Skip to content

Commit 42bd7c7

Browse files
Bug 1943378: Fix InstanceCreate volume cleanup
Using the deferred function, this solution triggers the cleanup of the unused root volume in all failure cases of InstanceCreate.
1 parent 0ff90e6 commit 42bd7c7

File tree

1 file changed

+22
-20
lines changed

1 file changed

+22
-20
lines changed

pkg/cloud/openstack/clients/machineservice.go

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
464464
func (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

Comments
 (0)