From 81e2384474a7961a04d4563fb3e7a33f007b19e0 Mon Sep 17 00:00:00 2001 From: Aparna Singh Date: Mon, 20 May 2024 13:43:19 +0530 Subject: [PATCH] Adding wait for volume create when volume already exists in ANF driver --- storage_drivers/azure/azure_anf.go | 13 +++++ storage_drivers/azure/azure_anf_test.go | 68 +++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/storage_drivers/azure/azure_anf.go b/storage_drivers/azure/azure_anf.go index 0d394bbdd..89ce6ae3a 100644 --- a/storage_drivers/azure/azure_anf.go +++ b/storage_drivers/azure/azure_anf.go @@ -771,6 +771,12 @@ func (d *NASStorageDriver) Create( "state": extantVolume.ProvisioningState, }).Warning("Volume already exists.") + // Volume here is likely in terminal state. Get the exact error message why is it so. + if err = d.waitForVolumeCreate(ctx, extantVolume, api.Create); err != nil { + return err + } + + // No specific error is returned, so return a generic volume exists error return drivers.NewVolumeExistsError(name) } @@ -1085,6 +1091,13 @@ func (d *NASStorageDriver) CreateClone( return errors.VolumeCreatingError( fmt.Sprintf("volume state is still %s, not %s", api.StateCreating, api.StateAvailable)) } + + // Volume here is likely in terminal state. Get the exact error message why is it so. + if err = d.waitForVolumeCreate(ctx, extantVolume, api.Create); err != nil { + return err + } + + // No specific error is returned, so return a generic volume exists error return drivers.NewVolumeExistsError(name) } diff --git a/storage_drivers/azure/azure_anf_test.go b/storage_drivers/azure/azure_anf_test.go index 2754c7081..fece096d5 100644 --- a/storage_drivers/azure/azure_anf_test.go +++ b/storage_drivers/azure/azure_anf_test.go @@ -2262,6 +2262,37 @@ func TestCreate_VolumeExistsCreating(t *testing.T) { assert.Equal(t, "", volConfig.InternalID, "internal ID set on volConfig") } +func TestCreate_VolumeExistsResourceExhaustedError(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.Config.BackendName = "anf" + driver.Config.ServiceLevel = api.ServiceLevelUltra + + driver.populateConfigurationDefaults(ctx, &driver.Config) + driver.initializeStoragePools(ctx) + driver.initializeTelemetry(ctx, BackendUUID) + + storagePool := driver.pools["anf_pool"] + + volConfig, _, _, _, filesystem := getStructsForCreateNFSVolume(ctx, driver, storagePool) + filesystem.ProvisioningState = api.StateError + cpLowSpaceError := errors.ResourceExhaustedError( + errors.New("PoolSizeTooSmall: Unable to complete the operation. " + + "The capacity pool size of 4398046511104 bytes is too small for the " + + "combined volume size of 6597069766656 bytes of the capacity pool.")) + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().VolumeExists(ctx, volConfig).Return(true, filesystem, nil).Times(1) + mockAPI.EXPECT().WaitForVolumeState(ctx, filesystem, api.StateAvailable, []string{api.StateError}, + driver.volumeCreateTimeout, api.Create).Return(api.StateError, cpLowSpaceError).Times(1) + mockAPI.EXPECT().DeleteVolume(ctx, filesystem).Return(nil).Times(1) + + result := driver.Create(ctx, volConfig, storagePool, nil) + + assert.Error(t, result, "create did not fail") + assert.IsType(t, errors.ResourceExhaustedError(errors.New("")), result, "not ResourceExhaustedError") + assert.Equal(t, "", volConfig.InternalID, "internal ID set on volConfig") +} + func TestCreate_VolumeExists(t *testing.T) { mockAPI, driver := newMockANFDriver(t) driver.Config.BackendName = "anf" @@ -2278,6 +2309,8 @@ func TestCreate_VolumeExists(t *testing.T) { mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) mockAPI.EXPECT().VolumeExists(ctx, volConfig).Return(true, filesystem, nil).Times(1) + mockAPI.EXPECT().WaitForVolumeState(ctx, filesystem, api.StateAvailable, []string{api.StateError}, + driver.volumeCreateTimeout, api.Create).Return(api.StateAvailable, nil).Times(1) result := driver.Create(ctx, volConfig, storagePool, nil) @@ -3811,6 +3844,39 @@ func TestCreateClone_VolumeExistsCreating(t *testing.T) { assert.Equal(t, "", cloneVolConfig.InternalID, "internal ID set on volConfig") } +func TestCreateClone_VolumeExistsResourceExhaustedError(t *testing.T) { + mockAPI, driver := newMockANFDriver(t) + driver.Config.BackendName = "anf" + driver.Config.ServiceLevel = api.ServiceLevelUltra + + driver.populateConfigurationDefaults(ctx, &driver.Config) + driver.initializeStoragePools(ctx) + driver.initializeTelemetry(ctx, BackendUUID) + + storagePool := driver.pools["anf_pool"] + + sourceVolConfig, cloneVolConfig, _, sourceFilesystem, cloneFilesystem, _ := getStructsForCreateClone(ctx, driver, + storagePool) + cloneFilesystem.ProvisioningState = api.StateError + cpLowSpaceError := errors.ResourceExhaustedError( + errors.New("PoolSizeTooSmall: Unable to complete the operation. " + + "The capacity pool size of 4398046511104 bytes is too small for the " + + "combined volume size of 6597069766656 bytes of the capacity pool.")) + + mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) + mockAPI.EXPECT().Volume(ctx, sourceVolConfig).Return(sourceFilesystem, nil).Times(1) + mockAPI.EXPECT().VolumeExistsByID(ctx, cloneFilesystem.ID).Return(true, cloneFilesystem, nil).Times(1) + mockAPI.EXPECT().WaitForVolumeState(ctx, cloneFilesystem, api.StateAvailable, []string{api.StateError}, + driver.volumeCreateTimeout, api.Create).Return(api.StateError, cpLowSpaceError).Times(1) + mockAPI.EXPECT().DeleteVolume(ctx, cloneFilesystem).Return(nil).Times(1) + + result := driver.CreateClone(ctx, sourceVolConfig, cloneVolConfig, nil) + + assert.Error(t, result, "expected error") + assert.IsType(t, errors.ResourceExhaustedError(errors.New("")), result, "not ResourceExhaustedError") + assert.Equal(t, "", cloneVolConfig.InternalID, "internal ID set on volConfig") +} + func TestCreateClone_VolumeExists(t *testing.T) { mockAPI, driver := newMockANFDriver(t) driver.Config.BackendName = "anf" @@ -3829,6 +3895,8 @@ func TestCreateClone_VolumeExists(t *testing.T) { mockAPI.EXPECT().RefreshAzureResources(ctx).Return(nil).Times(1) mockAPI.EXPECT().Volume(ctx, sourceVolConfig).Return(sourceFilesystem, nil).Times(1) mockAPI.EXPECT().VolumeExistsByID(ctx, cloneFilesystem.ID).Return(true, cloneFilesystem, nil).Times(1) + mockAPI.EXPECT().WaitForVolumeState(ctx, cloneFilesystem, api.StateAvailable, []string{api.StateError}, + driver.volumeCreateTimeout, api.Create).Return(api.StateAvailable, nil).Times(1) result := driver.CreateClone(ctx, sourceVolConfig, cloneVolConfig, nil)