@@ -419,43 +419,54 @@ const createCustomIngress = async (project, hostname, options) => {
419419
420420const createPersistentVolumeClaim = async ( project , options ) => {
421421 const namespace = this . _app . config . driver . options ?. projectNamespace || 'flowforge'
422- const pvc = JSON . parse ( JSON . stringify ( persistentVolumeClaimTemplate ) )
422+ const name = `${ project . id } -pvc`
423+ try {
424+ await this . _k8sApi . readNamespacedPersistentVolumeClaim ( { name, namespace } )
425+ // exists no need to recreate
426+ return undefined
427+ } catch ( err ) {
428+ if ( err . code === 404 || err . response ?. statusCode === 404 ) {
429+ const pvc = JSON . parse ( JSON . stringify ( persistentVolumeClaimTemplate ) )
423430
424- const drvOptions = this . _app . config . driver . options
425- const allowedAccessModes = new Set ( [ 'ReadWriteOnce' , 'ReadWriteMany' , 'ReadWriteOncePod' ] )
426- const configuredAccessMode = drvOptions ?. storage ?. accessMode
431+ const drvOptions = this . _app . config . driver . options
432+ const allowedAccessModes = new Set ( [ 'ReadWriteOnce' , 'ReadWriteMany' , 'ReadWriteOncePod' ] )
433+ const configuredAccessMode = drvOptions ?. storage ?. accessMode
427434
428- if ( configuredAccessMode !== undefined ) {
429- if ( ! allowedAccessModes . has ( configuredAccessMode ) ) {
430- throw new Error ( `Unsupported storage.accessMode '${ configuredAccessMode } '. Allowed values: ${ Array . from ( allowedAccessModes ) . join ( ', ' ) } ` )
431- }
432- pvc . spec . accessModes = [ configuredAccessMode ]
433- }
435+ if ( configuredAccessMode !== undefined ) {
436+ if ( ! allowedAccessModes . has ( configuredAccessMode ) ) {
437+ throw new Error ( `Unsupported storage.accessMode '${ configuredAccessMode } '. Allowed values: ${ Array . from ( allowedAccessModes ) . join ( ', ' ) } ` )
438+ }
439+ pvc . spec . accessModes = [ configuredAccessMode ]
440+ }
434441
435- if ( drvOptions ?. storage ?. storageClass ) {
436- pvc . spec . storageClassName = drvOptions . storage . storageClass
437- } else if ( drvOptions ?. storage ?. storageClassEFSTag ) {
438- pvc . spec . storageClassName = await awsEFS . lookupStorageClass ( drvOptions ?. storage ?. storageClassEFSTag )
439- }
442+ if ( drvOptions ?. storage ?. storageClass ) {
443+ pvc . spec . storageClassName = drvOptions . storage . storageClass
444+ } else if ( drvOptions ?. storage ?. storageClassEFSTag ) {
445+ pvc . spec . storageClassName = await awsEFS . lookupStorageClass ( drvOptions ?. storage ?. storageClassEFSTag )
446+ }
440447
441- if ( drvOptions ?. storage ?. size ) {
442- pvc . spec . resources . requests . storage = drvOptions . storage . size
443- }
448+ if ( drvOptions ?. storage ?. size ) {
449+ pvc . spec . resources . requests . storage = drvOptions . storage . size
450+ }
444451
445- pvc . metadata . namespace = namespace
446- pvc . metadata . name = `${ project . id } -pvc`
447- pvc . metadata . labels = {
448- 'ff-project-id' : project . id ,
449- 'ff-project-name' : project . safeName
450- }
451- if ( this . _app . config . driver . options ?. projectLabels ) {
452- pvc . metadata . labels = {
453- ...pvc . metadata . labels ,
454- ...this . _app . config . driver . options . projectLabels
452+ pvc . metadata . namespace = namespace
453+ pvc . metadata . name = name
454+ pvc . metadata . labels = {
455+ 'ff-project-id' : project . id ,
456+ 'ff-project-name' : project . safeName
457+ }
458+ if ( this . _app . config . driver . options ?. projectLabels ) {
459+ pvc . metadata . labels = {
460+ ...pvc . metadata . labels ,
461+ ...this . _app . config . driver . options . projectLabels
462+ }
463+ }
464+ console . error ( `PVC: ${ JSON . stringify ( pvc , null , 2 ) } ` )
465+ return pvc
466+ } else {
467+ throw err
455468 }
456469 }
457- console . error ( `PVC: ${ JSON . stringify ( pvc , null , 2 ) } ` )
458- return pvc
459470}
460471
461472const createProject = async ( project , options ) => {
@@ -468,17 +479,19 @@ const createProject = async (project, options) => {
468479 if ( this . _app . config . driver . options ?. storage ?. enabled ) {
469480 const localPVC = await createPersistentVolumeClaim ( project , options )
470481 // console.log(JSON.stringify(localPVC, null, 2))
471- try {
472- await this . _k8sApi . createNamespacedPersistentVolumeClaim ( { namespace, body : localPVC } )
473- } catch ( err ) {
474- console . error ( JSON . stringify ( err ) )
475- if ( err . code === 409 ) {
476- this . _app . log . warn ( `[k8s] PVC for instance ${ project . id } already exists, proceeding...` )
477- } else {
478- if ( project . state !== 'suspended' ) {
479- this . _app . log . error ( `[k8s] Instance ${ project . id } - error creating PVC: ${ err . toString ( ) } ${ err . code } ${ err . stack } ` )
480- // console.log(err)
481- throw err
482+ if ( localPVC !== undefined ) {
483+ try {
484+ await this . _k8sApi . createNamespacedPersistentVolumeClaim ( { namespace, body : localPVC } )
485+ } catch ( err ) {
486+ console . error ( JSON . stringify ( err ) )
487+ if ( err . code === 409 ) {
488+ this . _app . log . warn ( `[k8s] PVC for instance ${ project . id } already exists, proceeding...` )
489+ } else {
490+ if ( project . state !== 'suspended' ) {
491+ this . _app . log . error ( `[k8s] Instance ${ project . id } - error creating PVC: ${ err . toString ( ) } ${ err . code } ${ err . stack } ` )
492+ // console.log(err)
493+ throw err
494+ }
482495 }
483496 }
484497 }
@@ -735,8 +748,8 @@ const waitForInstanceRunning = async (endpoint) => {
735748// functions to wrap k8s api functions in retry logic
736749const retry = ( driver , api , func , args , delay , times ) => {
737750 return func . apply ( api , args ) . catch ( err => {
738- driver . _app . log . error ( `[k8s] API call to ${ func . name } failed. attempt=${ driver . _k8sRetries - times + 1 } /${ driver . _k8sRetries + 1 } statusCode=${ err . response ?. statusCode || 'N/A' } ${ err . toString ( ) } ` )
739- if ( times > 0 && err . response && err . response . statusCode === 429 ) {
751+ driver . _app . log . error ( `[k8s] API call to ${ func . name } failed. attempt=${ driver . _k8sRetries - times + 1 } /${ driver . _k8sRetries + 1 } statusCode=${ err . code || 'N/A' } ${ err . toString ( ) } ` )
752+ if ( times > 0 && err . code === 429 ) {
740753 return new Promise ( resolve => {
741754 setTimeout ( ( ) => { resolve ( retry ( driver , api , func , args , delay * 2 , times - 1 ) ) } , delay )
742755 } )
@@ -807,7 +820,8 @@ module.exports = {
807820 this . _k8sApi . deleteNamespacedPod ,
808821 this . _k8sApi . deleteNamespacedSecret ,
809822 this . _k8sApi . deleteNamespacedService ,
810- this . _k8sApi . deleteNamespacedPersistentVolumeClaim
823+ this . _k8sApi . deleteNamespacedPersistentVolumeClaim ,
824+ this . _k8sApi . readNamespacedPersistentVolumeClaim
811825 ] , this )
812826 wrapClient ( this . _k8sAppApi , [
813827 this . _k8sAppApi . createNamespacedDeployment ,
0 commit comments