@@ -462,6 +462,11 @@ func GetSecurityGroups(is *InstanceService, sg_param []openstackconfigv1.Securit
462462// If ServerGroupName is nonempty and no server group exists with that name,
463463// then InstanceCreate creates a server group with that name.
464464func (is * InstanceService ) InstanceCreate (clusterName string , name string , clusterSpec * openstackconfigv1.OpenstackClusterProviderSpec , config * openstackconfigv1.OpenstackProviderSpec , cmd string , keyName string , configClient configclient.ConfigV1Interface ) (instance * Instance , err error ) {
465+ // server is nil until creation is successful in Nova. This variable is
466+ // used to trigger cleanup functions in early returns in case
467+ // associated resources were created.
468+ var server * servers.Server
469+
465470 if config == nil {
466471 return nil , fmt .Errorf ("create Options need be specified to create instace" )
467472 }
@@ -475,8 +480,6 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, clust
475480 }
476481 }
477482
478- var cleanupOperationsInCaseOfServerCreationFailure []func () error
479-
480483 // Set default Tags
481484 machineTags := []string {
482485 "cluster-api-provider-openstack" ,
@@ -713,7 +716,7 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, clust
713716 volumeName := name
714717
715718 // if source type is "image" then we have to create a volume from the image first
716- klog .Infof ("Creating bootable volume with name %q from image %v ." , volumeName , config .RootVolume .SourceUUID )
719+ klog .Infof ("Creating bootable volume with name %q from image %q ." , volumeName , config .RootVolume .SourceUUID )
717720
718721 // Deleting any volumes with the same name, as they may
719722 // be leftovers from a previous failed try.
@@ -750,21 +753,23 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, clust
750753 if err != nil {
751754 return nil , fmt .Errorf ("Create bootable volume err: %v" , err )
752755 }
753-
754- cleanupOperationsInCaseOfServerCreationFailure = append (cleanupOperationsInCaseOfServerCreationFailure , func () error {
755- return volumes .Delete (is .volumeClient , volume .ID , nil ).ExtractErr ()
756- })
757756 volumeID = volume .ID
758757
759- err = volumes .WaitForStatus (is .volumeClient , volumeID , "available" , 300 )
760- if err != nil {
761- klog .Infof ("Bootable volume %v creation failed. Removing..." , volumeID )
762- err = volumes .Delete (is .volumeClient , volumeID , volumes.DeleteOpts {}).ExtractErr ()
763- if err != nil {
764- return nil , fmt .Errorf ("Bootable volume deletion err: %v" , err )
758+ defer func () {
759+ // If the server is created in Nova, the lifetime of the associated volume will be
760+ // bound to it. This deferred cleanup function tackles the case where a volume was created
761+ // but never attached to a server. In that case, the volume must be removed manually.
762+ if server == nil {
763+ if err := volumes .Delete (is .volumeClient , volumeID , nil ).ExtractErr (); err != nil {
764+ klog .Infof ("Failed to delete stale volume %q" , volumeID )
765+ } else {
766+ klog .Infof ("Deleted stale volume %q" , volumeID )
767+ }
765768 }
769+ }()
766770
767- return nil , fmt .Errorf ("Bootable volume %v is not available err: %v" , volumeID , err )
771+ if err := volumes .WaitForStatus (is .volumeClient , volumeID , "available" , 300 ); err != nil {
772+ return nil , fmt .Errorf ("bootable volume is not available: %v" , err )
768773 }
769774
770775 klog .Infof ("Bootable volume %v was created successfully." , volumeID )
@@ -839,16 +844,13 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, clust
839844 }
840845 }
841846
842- server , err : = servers .Create (is .computeClient , keypairs.CreateOptsExt {
847+ server , err = servers .Create (is .computeClient , keypairs.CreateOptsExt {
843848 CreateOptsBuilder : serverCreateOpts ,
844849 KeyName : keyName ,
845850 }).Extract ()
846851 if err != nil {
847- for _ , cleanup := range cleanupOperationsInCaseOfServerCreationFailure {
848- if e := cleanup (); e != nil {
849- err = fmt .Errorf ("%w. Additionally: %v" , err , e )
850- }
851- }
852+ // setting the server variable to nil to signal cleanup functions that server creation was not successful.
853+ server = nil
852854 return nil , err
853855 }
854856
0 commit comments