From 6c44ba77e3867d85bc0c6d8136ec8e890abc8fdd Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Sat, 17 Jul 2021 15:49:44 +0200 Subject: [PATCH] Bug 1943378: Eliminate instanceCreate volume leak InstanceCreate is a method that creates a server. If the server is set to boot from volume, and an image ID is passed, the method creates the root volume prior to creating the server. The root volume is set to be destroyed when the associated server is destroyed. However, if the server fails to create (for example, because of quota issues), the volume is never associated to a server and the automatic deletion is never triggered. At every round of retry, a new volume will be created, possibly until volume quota is reached (or server creation is successful). This results in a leakage of unused volumes. With this patch, a newly created root volume is explicitly deleted as soon as the server creation call fails. Note that this patch leaves unmodified the lifespan of a volume associated to a server, regardless if the server ever reaches an ACTIVE state. Co-Authored-By: Matthew Booth --- pkg/cloud/openstack/clients/machineservice.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pkg/cloud/openstack/clients/machineservice.go b/pkg/cloud/openstack/clients/machineservice.go index d0c05a78f2..b68e566734 100644 --- a/pkg/cloud/openstack/clients/machineservice.go +++ b/pkg/cloud/openstack/clients/machineservice.go @@ -475,6 +475,8 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, clust } } + var cleanupOperationsInCaseOfServerCreationFailure []func() error + // Set default Tags machineTags := []string{ "cluster-api-provider-openstack", @@ -730,6 +732,9 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, clust return nil, fmt.Errorf("Create bootable volume err: %v", err) } + cleanupOperationsInCaseOfServerCreationFailure = append(cleanupOperationsInCaseOfServerCreationFailure, func() error { + return volumes.Delete(is.volumeClient, volume.ID, nil).ExtractErr() + }) volumeID = volume.ID err = volumes.WaitForStatus(is.volumeClient, volumeID, "available", 300) @@ -820,7 +825,12 @@ func (is *InstanceService) InstanceCreate(clusterName string, name string, clust KeyName: keyName, }).Extract() if err != nil { - return nil, fmt.Errorf("Create new server err: %v", err) + for _, cleanup := range cleanupOperationsInCaseOfServerCreationFailure { + if e := cleanup(); e != nil { + err = fmt.Errorf("%w. Additionally: %v", err, e) + } + } + return nil, err } is.computeClient.Microversion = ""