From 71b0721e6eb2ec425bfb0a5e7da4029c50f8d8d3 Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Tue, 4 Aug 2026 12:20:54 +0200 Subject: [PATCH 1/8] WIP: Delete Volume when creation fails with status ERROR Signed-off-by: Niclas Schad --- pkg/csi/blockstorage/controllerserver.go | 17 +++++++++++++++-- pkg/stackit/client/iaas.go | 21 ++++++++++++++------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/pkg/csi/blockstorage/controllerserver.go b/pkg/csi/blockstorage/controllerserver.go index 367d8340..e975a6c5 100644 --- a/pkg/csi/blockstorage/controllerserver.go +++ b/pkg/csi/blockstorage/controllerserver.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "strconv" + "strings" "time" "github.com/container-storage-interface/spec/lib/go/csi" @@ -265,14 +266,26 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol targetStatus := []string{stackitclient.VolumeAvailableStatus} // Recheck after: 0s (immediate), 20s, 45.6s, 78.36s, 120.31s - err = cloud.WaitVolumeTargetStatusWithCustomBackoff(ctx, *vol.Id, targetStatus, + err = cloud.WaitVolumeTargetStatusWithCustomBackoff(ctx, &vol, targetStatus, &wait.Backoff{ Duration: 20 * time.Second, Steps: 5, Factor: 1.28, }) if err != nil { - klog.Errorf("Failed to WaitVolumeTargetStatus of volume %s: %v", *vol.Id, err) + klog.Errorf("Failed to WaitVolumeTargetStatus of volume %s: %v", vol.GetId(), err) + + if err != nil { + klog.Errorf("Failed to fetch volume %s status during cleanup check: %v", vol.GetId(), err) + } else if strings.ToUpper(vol.GetStatus()) == stackitclient.VolumeErrorStatus { + klog.Warningf("Volume %s entered ERROR status, attempting cleanup deletion...", vol.GetId()) + if deleteErr := cloud.DeleteVolume(ctx, vol.GetId()); deleteErr != nil { + klog.Errorf("Failed to delete erroneous volume %s: %v", vol.GetId(), deleteErr) + } else { + klog.Infof("Successfully deleted erroneous volume %s", vol.GetId()) + } + } + return nil, status.Error(codes.Internal, fmt.Sprintf("CreateVolume Volume %s failed getting available in time: %v", *vol.Id, err)) } diff --git a/pkg/stackit/client/iaas.go b/pkg/stackit/client/iaas.go index 56ed1588..0da8fc84 100644 --- a/pkg/stackit/client/iaas.go +++ b/pkg/stackit/client/iaas.go @@ -49,12 +49,13 @@ type IaaSClient interface { WaitVolumeTargetStatus(ctx context.Context, volumeID string, tStatus []string) error WaitDiskAttached(ctx context.Context, instanceID, volumeID string) error WaitDiskDetached(ctx context.Context, instanceID, volumeID string) error - WaitVolumeTargetStatusWithCustomBackoff(ctx context.Context, volumeID string, tStatus []string, backoff *wait.Backoff) error + WaitVolumeTargetStatusWithCustomBackoff(ctx context.Context, vol **iaas.Volume, tStatus []string, backoff *wait.Backoff) error } const ( VolumeAvailableStatus = "AVAILABLE" VolumeAttachedStatus = "ATTACHED" + VolumeErrorStatus = "ERROR" operationFinishInitDelay = 1 * time.Second operationFinishFactor = 1.1 operationFinishSteps = 10 @@ -542,25 +543,31 @@ func (i *iaasClient) DetachVolume(ctx context.Context, serverID, volumeID string return nil } -func (i *iaasClient) WaitVolumeTargetStatusWithCustomBackoff(ctx context.Context, volumeID string, tStatus []string, backoff *wait.Backoff) error { +func (i *iaasClient) WaitVolumeTargetStatusWithCustomBackoff(ctx context.Context, vol **iaas.Volume, tStatus []string, backoff *wait.Backoff) error { + volID := (*vol).GetId() + waitErr := wait.ExponentialBackoff(*backoff, func() (bool, error) { - vol, err := i.GetVolume(ctx, volumeID) + updatedVol, err := i.GetVolume(ctx, volID) if err != nil { return false, err } - if slices.Contains(tStatus, *vol.Status) { + + // Update vol so we can skip having another request + *vol = updatedVol + + if slices.Contains(tStatus, updatedVol.GetStatus()) { return true, nil } for _, eState := range volumeErrorStates { - if *vol.Status == eState { - return false, fmt.Errorf("volume is in error state: %s", *vol.Status) + if updatedVol.GetStatus() == eState { + return false, fmt.Errorf("volume is in error state: %s", updatedVol.GetStatus()) } } return false, nil }) if wait.Interrupted(waitErr) { - waitErr = fmt.Errorf("timeout on waiting for volume %s status to be in %v", volumeID, tStatus) + waitErr = fmt.Errorf("timeout on waiting for volume %s status to be in %v", volID, tStatus) } return waitErr From e5c57faff601dd4d3f4ea040d592033f8fe45435 Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Tue, 4 Aug 2026 13:33:40 +0200 Subject: [PATCH 2/8] cleanup if logic Signed-off-by: Niclas Schad --- pkg/csi/blockstorage/controllerserver.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pkg/csi/blockstorage/controllerserver.go b/pkg/csi/blockstorage/controllerserver.go index e975a6c5..47593f87 100644 --- a/pkg/csi/blockstorage/controllerserver.go +++ b/pkg/csi/blockstorage/controllerserver.go @@ -274,10 +274,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol }) if err != nil { klog.Errorf("Failed to WaitVolumeTargetStatus of volume %s: %v", vol.GetId(), err) - - if err != nil { - klog.Errorf("Failed to fetch volume %s status during cleanup check: %v", vol.GetId(), err) - } else if strings.ToUpper(vol.GetStatus()) == stackitclient.VolumeErrorStatus { + if strings.ToUpper(vol.GetStatus()) == stackitclient.VolumeErrorStatus { klog.Warningf("Volume %s entered ERROR status, attempting cleanup deletion...", vol.GetId()) if deleteErr := cloud.DeleteVolume(ctx, vol.GetId()); deleteErr != nil { klog.Errorf("Failed to delete erroneous volume %s: %v", vol.GetId(), deleteErr) @@ -285,7 +282,6 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol klog.Infof("Successfully deleted erroneous volume %s", vol.GetId()) } } - return nil, status.Error(codes.Internal, fmt.Sprintf("CreateVolume Volume %s failed getting available in time: %v", *vol.Id, err)) } From 447c883aa8ef40add3a4c22629247a2e783c2f50 Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Tue, 4 Aug 2026 13:50:39 +0200 Subject: [PATCH 3/8] move deleteVolumesInErrorState behind CLI flag Signed-off-by: Niclas Schad --- cmd/stackit-csi-plugin/main.go | 22 ++++++++++++-------- pkg/csi/blockstorage/controllerserver.go | 22 ++++++++++++-------- pkg/csi/blockstorage/driver.go | 26 +++++++++++++++--------- 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/cmd/stackit-csi-plugin/main.go b/cmd/stackit-csi-plugin/main.go index 302aee97..534a5583 100644 --- a/cmd/stackit-csi-plugin/main.go +++ b/cmd/stackit-csi-plugin/main.go @@ -23,14 +23,15 @@ import ( ) var ( - endpoint string - cloudConfig string - cluster string - metricsAddress string - provideControllerService bool - provideNodeService bool - legacyStorageMode bool - legacyVolumeCreation bool + endpoint string + cloudConfig string + cluster string + metricsAddress string + provideControllerService bool + provideNodeService bool + legacyStorageMode bool + legacyVolumeCreation bool + deleteVolumesInErrorState bool ) func main() { @@ -85,6 +86,7 @@ func main() { cmd.PersistentFlags().BoolVar(&legacyStorageMode, "legacy-storage-mode", false, "Configures the CSI to listen to the legacy storage driverName cinder.csi.openstack.org instead") cmd.PersistentFlags().BoolVar(&legacyVolumeCreation, "legacy-volume-creation", true, "Enable or disable support for creating volumes with the old driverName (cinder.csi.openstack.org)") + cmd.PersistentFlags().BoolVar(&deleteVolumesInErrorState, "delete-volumes-in-error", false, "Delete volumes in error state when creating") stackitclient.AddExtraFlags(pflag.CommandLine) @@ -117,6 +119,10 @@ func handle(ctx context.Context) { driverOpts.BlockVolumeCreation = true } + if deleteVolumesInErrorState { + driverOpts.DeleteVolumesInErrorState = true + } + d := blockstorage.NewDriver(driverOpts) if provideControllerService { diff --git a/pkg/csi/blockstorage/controllerserver.go b/pkg/csi/blockstorage/controllerserver.go index 47593f87..fa668905 100644 --- a/pkg/csi/blockstorage/controllerserver.go +++ b/pkg/csi/blockstorage/controllerserver.go @@ -21,7 +21,6 @@ import ( "errors" "fmt" "strconv" - "strings" "time" "github.com/container-storage-interface/spec/lib/go/csi" @@ -274,13 +273,8 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol }) if err != nil { klog.Errorf("Failed to WaitVolumeTargetStatus of volume %s: %v", vol.GetId(), err) - if strings.ToUpper(vol.GetStatus()) == stackitclient.VolumeErrorStatus { - klog.Warningf("Volume %s entered ERROR status, attempting cleanup deletion...", vol.GetId()) - if deleteErr := cloud.DeleteVolume(ctx, vol.GetId()); deleteErr != nil { - klog.Errorf("Failed to delete erroneous volume %s: %v", vol.GetId(), deleteErr) - } else { - klog.Infof("Successfully deleted erroneous volume %s", vol.GetId()) - } + if cs.Driver.deleteVolumesInErrorState { + cs.deleteVolumeInError(ctx, vol) } return nil, status.Error(codes.Internal, fmt.Sprintf("CreateVolume Volume %s failed getting available in time: %v", *vol.Id, err)) } @@ -290,6 +284,18 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol return cs.getCreateVolumeResponse(vol), nil } +func (cs *controllerServer) deleteVolumeInError(ctx context.Context, vol *iaas.Volume) { + cloud := cs.Instance + if vol.GetStatus() == stackitclient.VolumeErrorStatus { + klog.Warningf("Volume %s entered ERROR status, attempting cleanup deletion...", vol.GetId()) + if deleteErr := cloud.DeleteVolume(ctx, vol.GetId()); deleteErr != nil { + klog.Errorf("Failed to delete erroneous volume %s: %v", vol.GetId(), deleteErr) + } else { + klog.Infof("Successfully deleted erroneous volume %s", vol.GetId()) + } + } +} + func setVolumeEncryptionParameters(opts *iaas.CreateVolumePayload, volParams *stackitParameterConfig) error { err := validateEncryptionConfig(volParams) if err != nil { diff --git a/pkg/csi/blockstorage/driver.go b/pkg/csi/blockstorage/driver.go index 60e3b6f9..41948708 100644 --- a/pkg/csi/blockstorage/driver.go +++ b/pkg/csi/blockstorage/driver.go @@ -31,12 +31,13 @@ var ( ) type Driver struct { - name string - fqVersion string // Fully qualified version in format {Version}@{CPO version} - endpoint string - clusterID string - legacyDriver bool - blockVolumeCreation bool + name string + fqVersion string // Fully qualified version in format {Version}@{CPO version} + endpoint string + clusterID string + legacyDriver bool + blockVolumeCreation bool + deleteVolumesInErrorState bool ids *identityServer cs *controllerServer @@ -51,10 +52,11 @@ type Driver struct { } type DriverOpts struct { - ClusterID string - Endpoint string - LegacyDriverName bool - BlockVolumeCreation bool + ClusterID string + Endpoint string + LegacyDriverName bool + BlockVolumeCreation bool + DeleteVolumesInErrorState bool PVCLister corev1.PersistentVolumeClaimLister } @@ -73,6 +75,10 @@ func NewDriver(o *DriverOpts) *Driver { d.legacyDriver = true } + if o.DeleteVolumesInErrorState { + d.deleteVolumesInErrorState = true + } + if o.BlockVolumeCreation { d.blockVolumeCreation = true } From 41378a32f93555d38af3a119b9f5f6015f644bb0 Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Wed, 5 Aug 2026 14:24:24 +0200 Subject: [PATCH 4/8] fix tests Signed-off-by: Niclas Schad --- pkg/csi/blockstorage/controllerserver.go | 3 + pkg/csi/blockstorage/controllerserver_test.go | 95 ++++++++++--------- pkg/stackit/client/mock/iaas_mock.go | 12 +-- 3 files changed, 59 insertions(+), 51 deletions(-) diff --git a/pkg/csi/blockstorage/controllerserver.go b/pkg/csi/blockstorage/controllerserver.go index fa668905..2065ca52 100644 --- a/pkg/csi/blockstorage/controllerserver.go +++ b/pkg/csi/blockstorage/controllerserver.go @@ -137,6 +137,9 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol return nil, status.Error(codes.AlreadyExists, "Volume Already exists with same name and different capacity") } if *vols[0].Status != stackitclient.VolumeAvailableStatus { + if cs.Driver.deleteVolumesInErrorState { + cs.deleteVolumeInError(ctx, &vols[0]) + } return nil, status.Error(codes.Internal, fmt.Sprintf("Volume %s is not in available state", *vols[0].Id)) } klog.V(4).Infof("Volume %s already exists in Availability Zone: %s of size %d GiB", *vols[0].Id, vols[0].AvailabilityZone, *vols[0].Size) diff --git a/pkg/csi/blockstorage/controllerserver_test.go b/pkg/csi/blockstorage/controllerserver_test.go index c4f91be9..edcde647 100644 --- a/pkg/csi/blockstorage/controllerserver_test.go +++ b/pkg/csi/blockstorage/controllerserver_test.go @@ -67,13 +67,15 @@ var _ = Describe("ControllerServer test", Ordered, func() { iaasClient.EXPECT().GetVolumesByName(gomock.Any(), "new volume").Return([]iaas.Volume{}, nil) - iaasClient.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(&iaas.Volume{ + vol := &iaas.Volume{ Id: new("volume-id"), Name: new("new volume"), AvailabilityZone: "eu01", Size: new(int64(20)), - }, nil) - iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), "volume-id", gomock.Any(), gomock.Any()).Return(nil) + } + + iaasClient.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(vol, nil) + iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), &vol, gomock.Any(), gomock.Any()).Return(nil) resp, err := fakeCs.CreateVolume(context.Background(), req) Expect(err).ToNot(HaveOccurred()) @@ -122,13 +124,15 @@ var _ = Describe("ControllerServer test", Ordered, func() { iaasClient.EXPECT().GetVolumesByName(gomock.Any(), "volume name").Return([]iaas.Volume{}, nil) - iaasClient.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(&iaas.Volume{ + vol := &iaas.Volume{ Id: new("volume-id"), Name: new("volume name"), AvailabilityZone: "zone-from-parameters", Size: new(int64(20)), - }, nil) - iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), "volume-id", gomock.Any(), gomock.Any()).Return(nil) + } + + iaasClient.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(vol, nil) + iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), &vol, gomock.Any(), gomock.Any()).Return(nil) _, err := fakeCs.CreateVolume(context.Background(), req) Expect(err).ToNot(HaveOccurred()) @@ -150,13 +154,15 @@ var _ = Describe("ControllerServer test", Ordered, func() { iaasClient.EXPECT().GetVolumesByName(gomock.Any(), "volume name").Return([]iaas.Volume{}, nil) - iaasClient.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(&iaas.Volume{ + vol := &iaas.Volume{ Id: new("volume-id"), Name: new("volume name"), AvailabilityZone: "zone-from-accessibility-reqs", Size: new(int64(20)), - }, nil) - iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), "volume-id", gomock.Any(), gomock.Any()).Return(nil) + } + + iaasClient.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(vol, nil) + iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), &vol, gomock.Any(), gomock.Any()).Return(nil) _, err := fakeCs.CreateVolume(context.Background(), req) Expect(err).ToNot(HaveOccurred()) @@ -303,24 +309,23 @@ var _ = Describe("ControllerServer test", Ordered, func() { VolumeId: "snapshot-volume-id", AvailabilityZone: new("eu01"), }, nil) + + vol := &iaas.Volume{ + Id: new("volume-id"), + Name: new("new volume"), + AvailabilityZone: "eu01", + Size: new(int64(20)), + } + iaasClient.EXPECT(). CreateVolume(gomock.Any(), gomock.Any()). DoAndReturn(func(_ context.Context, opts iaas.CreateVolumePayload) (*iaas.Volume, error) { Expect(opts.Source.Id).To(Equal("snapshot-id")) Expect(opts.Source.Type).To(Equal("snapshot")) - volumeID := "volume-id" - name := "new volume" - size := int64(20) - - return &iaas.Volume{ - Id: &volumeID, - Name: &name, - AvailabilityZone: "eu01", - Size: &size, - }, nil + return vol, nil }) - iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), "volume-id", gomock.Any(), gomock.Any()).Return(nil) + iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), &vol, gomock.Any(), gomock.Any()).Return(nil) _, err := fakeCs.CreateVolume(context.Background(), req) Expect(err).ToNot(HaveOccurred()) @@ -379,24 +384,23 @@ var _ = Describe("ControllerServer test", Ordered, func() { Status: new("AVAILABLE"), AvailabilityZone: new("eu01"), }, nil) + + vol := &iaas.Volume{ + Id: new("volume-id"), + Name: new("new volume"), + AvailabilityZone: "eu01", + Size: new(int64(20)), + } + iaasClient.EXPECT(). CreateVolume(gomock.Any(), gomock.Any()). DoAndReturn(func(_ context.Context, opts iaas.CreateVolumePayload) (*iaas.Volume, error) { Expect(opts.Source.Id).To(Equal("snapshot-id")) Expect(opts.Source.Type).To(Equal("backup")) - volumeID := "volume-id" - name := "new volume" - size := int64(20) - - return &iaas.Volume{ - Id: &volumeID, - Name: &name, - AvailabilityZone: "eu01", - Size: &size, - }, nil + return vol, nil }) - iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), "volume-id", gomock.Any(), gomock.Any()).Return(nil) + iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), &vol, gomock.Any(), gomock.Any()).Return(nil) _, err := fakeCs.CreateVolume(context.Background(), req) Expect(err).ToNot(HaveOccurred()) @@ -490,24 +494,23 @@ var _ = Describe("ControllerServer test", Ordered, func() { Status: new("AVAILABLE"), AvailabilityZone: "eu01", }, nil) + + vol := &iaas.Volume{ + Id: new("volume-id"), + Name: new("new volume"), + AvailabilityZone: "eu01", + Size: new(int64(20)), + } + iaasClient.EXPECT(). CreateVolume(gomock.Any(), gomock.Any()). DoAndReturn(func(_ context.Context, opts iaas.CreateVolumePayload) (*iaas.Volume, error) { Expect(opts.Source.Id).To(Equal("volume-source-id")) Expect(opts.Source.Type).To(Equal("volume")) - name := "new volume" - volumeID := "volume-id" - size := int64(20) - - return &iaas.Volume{ - Id: &volumeID, - Name: &name, - AvailabilityZone: "eu01", - Size: &size, - }, nil + return vol, nil }) - iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), "volume-id", gomock.Any(), gomock.Any()).Return(nil) + iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), &vol, gomock.Any(), gomock.Any()).Return(nil) _, err := fakeCs.CreateVolume(context.Background(), req) Expect(err).ToNot(HaveOccurred()) @@ -578,13 +581,15 @@ var _ = Describe("ControllerServer test", Ordered, func() { iaasClient.EXPECT().GetVolumesByName(gomock.Any(), "new volume").Return([]iaas.Volume{}, nil) - iaasClient.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(&iaas.Volume{ + vol := &iaas.Volume{ Id: new("volume-id"), Name: new("new volume"), AvailabilityZone: "eu01", Size: new(int64(20)), - }, nil) - iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), "volume-id", gomock.Any(), gomock.Any()). + } + + iaasClient.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(vol, nil) + iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), &vol, gomock.Any(), gomock.Any()). Return(fmt.Errorf("injected error")) _, err := fakeCs.CreateVolume(context.Background(), req) diff --git a/pkg/stackit/client/mock/iaas_mock.go b/pkg/stackit/client/mock/iaas_mock.go index a538deb4..8e25dc83 100644 --- a/pkg/stackit/client/mock/iaas_mock.go +++ b/pkg/stackit/client/mock/iaas_mock.go @@ -973,17 +973,17 @@ func (c *MockIaaSClientWaitVolumeTargetStatusCall) DoAndReturn(f func(context.Co } // WaitVolumeTargetStatusWithCustomBackoff mocks base method. -func (m *MockIaaSClient) WaitVolumeTargetStatusWithCustomBackoff(ctx context.Context, volumeID string, tStatus []string, backoff *wait.Backoff) error { +func (m *MockIaaSClient) WaitVolumeTargetStatusWithCustomBackoff(ctx context.Context, vol **v2api.Volume, tStatus []string, backoff *wait.Backoff) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WaitVolumeTargetStatusWithCustomBackoff", ctx, volumeID, tStatus, backoff) + ret := m.ctrl.Call(m, "WaitVolumeTargetStatusWithCustomBackoff", ctx, vol, tStatus, backoff) ret0, _ := ret[0].(error) return ret0 } // WaitVolumeTargetStatusWithCustomBackoff indicates an expected call of WaitVolumeTargetStatusWithCustomBackoff. -func (mr *MockIaaSClientMockRecorder) WaitVolumeTargetStatusWithCustomBackoff(ctx, volumeID, tStatus, backoff any) *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall { +func (mr *MockIaaSClientMockRecorder) WaitVolumeTargetStatusWithCustomBackoff(ctx, vol, tStatus, backoff any) *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitVolumeTargetStatusWithCustomBackoff", reflect.TypeOf((*MockIaaSClient)(nil).WaitVolumeTargetStatusWithCustomBackoff), ctx, volumeID, tStatus, backoff) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitVolumeTargetStatusWithCustomBackoff", reflect.TypeOf((*MockIaaSClient)(nil).WaitVolumeTargetStatusWithCustomBackoff), ctx, vol, tStatus, backoff) return &MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall{Call: call} } @@ -999,13 +999,13 @@ func (c *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall) Return(arg0 } // Do rewrite *gomock.Call.Do -func (c *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall) Do(f func(context.Context, string, []string, *wait.Backoff) error) *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall { +func (c *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall) Do(f func(context.Context, **v2api.Volume, []string, *wait.Backoff) error) *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall) DoAndReturn(f func(context.Context, string, []string, *wait.Backoff) error) *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall { +func (c *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall) DoAndReturn(f func(context.Context, **v2api.Volume, []string, *wait.Backoff) error) *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall { c.Call = c.Call.DoAndReturn(f) return c } From 87917aa586f3ab9ebfa9435c8123bc9bcdaa24db Mon Sep 17 00:00:00 2001 From: Niclas Schad Date: Mon, 24 Aug 2026 10:26:34 +0200 Subject: [PATCH 5/8] only DELETE() in the above case, when vol not available Signed-off-by: Niclas Schad --- pkg/csi/blockstorage/controllerserver.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkg/csi/blockstorage/controllerserver.go b/pkg/csi/blockstorage/controllerserver.go index 2065ca52..daf82fd1 100644 --- a/pkg/csi/blockstorage/controllerserver.go +++ b/pkg/csi/blockstorage/controllerserver.go @@ -276,9 +276,6 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol }) if err != nil { klog.Errorf("Failed to WaitVolumeTargetStatus of volume %s: %v", vol.GetId(), err) - if cs.Driver.deleteVolumesInErrorState { - cs.deleteVolumeInError(ctx, vol) - } return nil, status.Error(codes.Internal, fmt.Sprintf("CreateVolume Volume %s failed getting available in time: %v", *vol.Id, err)) } From f05b4fced167f5b313ea2ad288d89a4315288cb5 Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Mon, 31 Aug 2026 17:16:17 +0200 Subject: [PATCH 6/8] add test for delete volume in error state Signed-off-by: Felix Breuer --- pkg/csi/blockstorage/controllerserver_test.go | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/pkg/csi/blockstorage/controllerserver_test.go b/pkg/csi/blockstorage/controllerserver_test.go index edcde647..39b91fd3 100644 --- a/pkg/csi/blockstorage/controllerserver_test.go +++ b/pkg/csi/blockstorage/controllerserver_test.go @@ -252,6 +252,31 @@ var _ = Describe("ControllerServer test", Ordered, func() { Expect(err.Error()).To(ContainSubstring("is not in available state")) }) + It("should delete an existing volume in error state when cleanup is enabled", func() { + req := &csi.CreateVolumeRequest{ + Name: "new volume", + VolumeCapabilities: stdVolCaps, + CapacityRange: stdCapRange, + } + fakeCs.Driver.deleteVolumesInErrorState = true + + iaasClient.EXPECT().GetVolumesByName(gomock.Any(), "new volume").Return([]iaas.Volume{ + { + Id: new("existing-error-volume-id"), + Name: new("new volume"), + Size: new(int64(20)), + Status: new(stackitclient.VolumeErrorStatus), + AvailabilityZone: "eu01", + }, + }, nil) + iaasClient.EXPECT().DeleteVolume(gomock.Any(), "existing-error-volume-id").Return(nil) + + _, err := fakeCs.CreateVolume(context.Background(), req) + Expect(err).To(HaveOccurred()) + Expect(status.Code(err)).To(Equal(codes.Internal)) + Expect(err.Error()).To(ContainSubstring("is not in available state")) + }) + It("should fail if more than one volume with the same name are available", func() { req := &csi.CreateVolumeRequest{ Name: "new volume", From 4762ba6d9174cd27355915bd7029d84fd762aec6 Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Tue, 15 Sep 2026 15:56:51 +0200 Subject: [PATCH 7/8] implement feedback --- pkg/csi/blockstorage/controllerserver.go | 42 +++++++++++++++--------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/pkg/csi/blockstorage/controllerserver.go b/pkg/csi/blockstorage/controllerserver.go index daf82fd1..93698177 100644 --- a/pkg/csi/blockstorage/controllerserver.go +++ b/pkg/csi/blockstorage/controllerserver.go @@ -132,21 +132,24 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol return nil, status.Errorf(codes.Internal, "Failed to get volumes: %v", err) } + if len(vols) > 1 { + klog.V(3).Infof("found multiple existing volumes with selected name (%s) during create", volName) + return nil, status.Error(codes.Internal, "Multiple volumes reported by Cinder with same name") + } + if len(vols) == 1 { - if volSizeGB != *vols[0].Size { + volume := vols[0] + if volSizeGB != volume.GetSize() { return nil, status.Error(codes.AlreadyExists, "Volume Already exists with same name and different capacity") } - if *vols[0].Status != stackitclient.VolumeAvailableStatus { + if volume.GetStatus() != stackitclient.VolumeAvailableStatus { if cs.Driver.deleteVolumesInErrorState { - cs.deleteVolumeInError(ctx, &vols[0]) + cs.deleteVolumeInError(ctx, &volume) } - return nil, status.Error(codes.Internal, fmt.Sprintf("Volume %s is not in available state", *vols[0].Id)) + return nil, status.Errorf(codes.Internal, "Volume %s is not in available state", volume.GetId()) } - klog.V(4).Infof("Volume %s already exists in Availability Zone: %s of size %d GiB", *vols[0].Id, vols[0].AvailabilityZone, *vols[0].Size) - return cs.getCreateVolumeResponse(&vols[0]), nil - } else if len(vols) > 1 { - klog.V(3).Infof("found multiple existing volumes with selected name (%s) during create", volName) - return nil, status.Error(codes.Internal, "Multiple volumes reported by Cinder with same name") + klog.V(4).Infof("Volume %s already exists in Availability Zone: %s of size %d GiB", volume.GetId(), volume.GetAvailabilityZone(), volume.GetSize()) + return cs.getCreateVolumeResponse(&volume), nil } // Volume Create @@ -285,15 +288,22 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol } func (cs *controllerServer) deleteVolumeInError(ctx context.Context, vol *iaas.Volume) { + if vol == nil { + return + } + + if vol.GetStatus() != stackitclient.VolumeErrorStatus { + return + } + cloud := cs.Instance - if vol.GetStatus() == stackitclient.VolumeErrorStatus { - klog.Warningf("Volume %s entered ERROR status, attempting cleanup deletion...", vol.GetId()) - if deleteErr := cloud.DeleteVolume(ctx, vol.GetId()); deleteErr != nil { - klog.Errorf("Failed to delete erroneous volume %s: %v", vol.GetId(), deleteErr) - } else { - klog.Infof("Successfully deleted erroneous volume %s", vol.GetId()) - } + klog.Warningf("Volume %s entered ERROR status, attempting cleanup deletion...", vol.GetId()) + if deleteErr := cloud.DeleteVolume(ctx, vol.GetId()); deleteErr != nil { + klog.Errorf("Failed to delete erroneous volume %s: %v", vol.GetId(), deleteErr) + return } + + klog.Infof("Successfully deleted erroneous volume %s", vol.GetId()) } func setVolumeEncryptionParameters(opts *iaas.CreateVolumePayload, volParams *stackitParameterConfig) error { From af6637dc9c185f06aa52a2b7c0ea23ee6f6bada9 Mon Sep 17 00:00:00 2001 From: Felix Breuer Date: Tue, 15 Sep 2026 16:28:15 +0200 Subject: [PATCH 8/8] refactor wait for volume --- pkg/csi/blockstorage/controllerserver.go | 9 ++-- pkg/csi/blockstorage/controllerserver_test.go | 16 +++--- pkg/csi/blockstorage/sanity_test.go | 2 +- pkg/stackit/client/iaas.go | 52 ++++++------------- pkg/stackit/client/iaas_test.go | 15 ++++++ pkg/stackit/client/mock/iaas_mock.go | 21 ++++---- 6 files changed, 57 insertions(+), 58 deletions(-) diff --git a/pkg/csi/blockstorage/controllerserver.go b/pkg/csi/blockstorage/controllerserver.go index 93698177..41a32605 100644 --- a/pkg/csi/blockstorage/controllerserver.go +++ b/pkg/csi/blockstorage/controllerserver.go @@ -271,12 +271,15 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol targetStatus := []string{stackitclient.VolumeAvailableStatus} // Recheck after: 0s (immediate), 20s, 45.6s, 78.36s, 120.31s - err = cloud.WaitVolumeTargetStatusWithCustomBackoff(ctx, &vol, targetStatus, - &wait.Backoff{ + updatedVol, err := cloud.WaitVolumeTargetStatusWithCustomBackoff(ctx, vol.GetId(), targetStatus, + wait.Backoff{ Duration: 20 * time.Second, Steps: 5, Factor: 1.28, }) + if updatedVol != nil { + vol = updatedVol + } if err != nil { klog.Errorf("Failed to WaitVolumeTargetStatus of volume %s: %v", vol.GetId(), err) return nil, status.Error(codes.Internal, fmt.Sprintf("CreateVolume Volume %s failed getting available in time: %v", *vol.Id, err)) @@ -302,7 +305,7 @@ func (cs *controllerServer) deleteVolumeInError(ctx context.Context, vol *iaas.V klog.Errorf("Failed to delete erroneous volume %s: %v", vol.GetId(), deleteErr) return } - + klog.Infof("Successfully deleted erroneous volume %s", vol.GetId()) } diff --git a/pkg/csi/blockstorage/controllerserver_test.go b/pkg/csi/blockstorage/controllerserver_test.go index 39b91fd3..b6e10039 100644 --- a/pkg/csi/blockstorage/controllerserver_test.go +++ b/pkg/csi/blockstorage/controllerserver_test.go @@ -75,7 +75,7 @@ var _ = Describe("ControllerServer test", Ordered, func() { } iaasClient.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(vol, nil) - iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), &vol, gomock.Any(), gomock.Any()).Return(nil) + iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), vol.GetId(), gomock.Any(), gomock.Any()).Return(vol, nil) resp, err := fakeCs.CreateVolume(context.Background(), req) Expect(err).ToNot(HaveOccurred()) @@ -132,7 +132,7 @@ var _ = Describe("ControllerServer test", Ordered, func() { } iaasClient.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(vol, nil) - iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), &vol, gomock.Any(), gomock.Any()).Return(nil) + iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), vol.GetId(), gomock.Any(), gomock.Any()).Return(vol, nil) _, err := fakeCs.CreateVolume(context.Background(), req) Expect(err).ToNot(HaveOccurred()) @@ -162,7 +162,7 @@ var _ = Describe("ControllerServer test", Ordered, func() { } iaasClient.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(vol, nil) - iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), &vol, gomock.Any(), gomock.Any()).Return(nil) + iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), vol.GetId(), gomock.Any(), gomock.Any()).Return(vol, nil) _, err := fakeCs.CreateVolume(context.Background(), req) Expect(err).ToNot(HaveOccurred()) @@ -350,7 +350,7 @@ var _ = Describe("ControllerServer test", Ordered, func() { return vol, nil }) - iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), &vol, gomock.Any(), gomock.Any()).Return(nil) + iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), vol.GetId(), gomock.Any(), gomock.Any()).Return(vol, nil) _, err := fakeCs.CreateVolume(context.Background(), req) Expect(err).ToNot(HaveOccurred()) @@ -425,7 +425,7 @@ var _ = Describe("ControllerServer test", Ordered, func() { return vol, nil }) - iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), &vol, gomock.Any(), gomock.Any()).Return(nil) + iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), vol.GetId(), gomock.Any(), gomock.Any()).Return(vol, nil) _, err := fakeCs.CreateVolume(context.Background(), req) Expect(err).ToNot(HaveOccurred()) @@ -535,7 +535,7 @@ var _ = Describe("ControllerServer test", Ordered, func() { return vol, nil }) - iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), &vol, gomock.Any(), gomock.Any()).Return(nil) + iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), vol.GetId(), gomock.Any(), gomock.Any()).Return(vol, nil) _, err := fakeCs.CreateVolume(context.Background(), req) Expect(err).ToNot(HaveOccurred()) @@ -614,8 +614,8 @@ var _ = Describe("ControllerServer test", Ordered, func() { } iaasClient.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(vol, nil) - iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), &vol, gomock.Any(), gomock.Any()). - Return(fmt.Errorf("injected error")) + iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff(gomock.Any(), vol.GetId(), gomock.Any(), gomock.Any()). + Return(nil, fmt.Errorf("injected error")) _, err := fakeCs.CreateVolume(context.Background(), req) Expect(err).To(HaveOccurred()) diff --git a/pkg/csi/blockstorage/sanity_test.go b/pkg/csi/blockstorage/sanity_test.go index 38fcad39..01462ec4 100644 --- a/pkg/csi/blockstorage/sanity_test.go +++ b/pkg/csi/blockstorage/sanity_test.go @@ -142,7 +142,7 @@ var _ = Describe("CSI sanity test", Ordered, func() { iaasClient.EXPECT().WaitVolumeTargetStatusWithCustomBackoff( gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), - ).Return(nil).AnyTimes() + ).Return(nil, nil).AnyTimes() iaasClient.EXPECT().ExpandVolume( gomock.Any(), // context diff --git a/pkg/stackit/client/iaas.go b/pkg/stackit/client/iaas.go index 0da8fc84..ab27ea52 100644 --- a/pkg/stackit/client/iaas.go +++ b/pkg/stackit/client/iaas.go @@ -49,7 +49,7 @@ type IaaSClient interface { WaitVolumeTargetStatus(ctx context.Context, volumeID string, tStatus []string) error WaitDiskAttached(ctx context.Context, instanceID, volumeID string) error WaitDiskDetached(ctx context.Context, instanceID, volumeID string) error - WaitVolumeTargetStatusWithCustomBackoff(ctx context.Context, vol **iaas.Volume, tStatus []string, backoff *wait.Backoff) error + WaitVolumeTargetStatusWithCustomBackoff(ctx context.Context, volumeID string, tStatus []string, backoff wait.Backoff) (*iaas.Volume, error) } const ( @@ -441,17 +441,27 @@ func (i *iaasClient) WaitVolumeTargetStatus(ctx context.Context, volumeID string Steps: operationFinishSteps, } + _, err := i.WaitVolumeTargetStatusWithCustomBackoff(ctx, volumeID, tStatus, backoff) + return err +} + +func (i *iaasClient) WaitVolumeTargetStatusWithCustomBackoff(ctx context.Context, volumeID string, tStatus []string, backoff wait.Backoff) (*iaas.Volume, error) { + var lastVolume *iaas.Volume + waitErr := wait.ExponentialBackoff(backoff, func() (bool, error) { - vol, err := i.GetVolume(ctx, volumeID) + volume, err := i.GetVolume(ctx, volumeID) if err != nil { return false, err } - if slices.Contains(tStatus, *vol.Status) { + + lastVolume = volume + + if slices.Contains(tStatus, volume.GetStatus()) { return true, nil } for _, eState := range volumeErrorStates { - if *vol.Status == eState { - return false, fmt.Errorf("volume is in Error State : %s", ptr.Deref(vol.Status, "")) + if volume.GetStatus() == eState { + return false, fmt.Errorf("volume is in Error State : %s", ptr.Deref(volume.Status, "")) } } return false, nil @@ -461,7 +471,7 @@ func (i *iaasClient) WaitVolumeTargetStatus(ctx context.Context, volumeID string waitErr = fmt.Errorf("timeout on waiting for volume %s status to be in %v", volumeID, tStatus) } - return waitErr + return lastVolume, waitErr } func (i *iaasClient) WaitDiskAttached(ctx context.Context, instanceID, volumeID string) error { @@ -543,36 +553,6 @@ func (i *iaasClient) DetachVolume(ctx context.Context, serverID, volumeID string return nil } -func (i *iaasClient) WaitVolumeTargetStatusWithCustomBackoff(ctx context.Context, vol **iaas.Volume, tStatus []string, backoff *wait.Backoff) error { - volID := (*vol).GetId() - - waitErr := wait.ExponentialBackoff(*backoff, func() (bool, error) { - updatedVol, err := i.GetVolume(ctx, volID) - if err != nil { - return false, err - } - - // Update vol so we can skip having another request - *vol = updatedVol - - if slices.Contains(tStatus, updatedVol.GetStatus()) { - return true, nil - } - for _, eState := range volumeErrorStates { - if updatedVol.GetStatus() == eState { - return false, fmt.Errorf("volume is in error state: %s", updatedVol.GetStatus()) - } - } - return false, nil - }) - - if wait.Interrupted(waitErr) { - waitErr = fmt.Errorf("timeout on waiting for volume %s status to be in %v", volID, tStatus) - } - - return waitErr -} - // diskIsAttached queries if a volume is attached to a compute instance func (i *iaasClient) diskIsAttached(ctx context.Context, instanceID, volumeID string) (bool, error) { volume, err := i.GetVolume(ctx, volumeID) diff --git a/pkg/stackit/client/iaas_test.go b/pkg/stackit/client/iaas_test.go index 172b15d6..ceca1794 100644 --- a/pkg/stackit/client/iaas_test.go +++ b/pkg/stackit/client/iaas_test.go @@ -10,6 +10,7 @@ import ( oapiError "github.com/stackitcloud/stackit-sdk-go/core/oapierror" iaas "github.com/stackitcloud/stackit-sdk-go/services/iaas/v2api" "go.uber.org/mock/gomock" + "k8s.io/apimachinery/pkg/util/wait" mock "github.com/stackitcloud/cloud-provider-stackit/pkg/mock/iaas" ) @@ -593,6 +594,20 @@ var _ = Describe("Volume", func() { Expect(err).ToNot(HaveOccurred()) }) + It("WaitVolumeTargetStatusWithCustomBackoff returns the refreshed volume", func() { + mockIaaSClient.EXPECT(). + GetVolume(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + Return(iaas.ApiGetVolumeRequest{ApiService: mockIaaSClient}) + updatedVolume := &iaas.Volume{Id: new(volumeID), Status: new("available")} + mockIaaSClient.EXPECT().GetVolumeExecute(gomock.Any()).Return(updatedVolume, nil) + + volume, err := client.WaitVolumeTargetStatusWithCustomBackoff( + context.Background(), volumeID, []string{"available"}, wait.Backoff{Steps: 1}, + ) + Expect(err).ToNot(HaveOccurred()) + Expect(volume).To(BeIdenticalTo(updatedVolume)) + }) + It("WaitDiskAttached returns error on timeout", func() { mockIaaSClient.EXPECT(). GetVolume(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). diff --git a/pkg/stackit/client/mock/iaas_mock.go b/pkg/stackit/client/mock/iaas_mock.go index 8e25dc83..db849244 100644 --- a/pkg/stackit/client/mock/iaas_mock.go +++ b/pkg/stackit/client/mock/iaas_mock.go @@ -973,17 +973,18 @@ func (c *MockIaaSClientWaitVolumeTargetStatusCall) DoAndReturn(f func(context.Co } // WaitVolumeTargetStatusWithCustomBackoff mocks base method. -func (m *MockIaaSClient) WaitVolumeTargetStatusWithCustomBackoff(ctx context.Context, vol **v2api.Volume, tStatus []string, backoff *wait.Backoff) error { +func (m *MockIaaSClient) WaitVolumeTargetStatusWithCustomBackoff(ctx context.Context, volumeID string, tStatus []string, backoff wait.Backoff) (*v2api.Volume, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WaitVolumeTargetStatusWithCustomBackoff", ctx, vol, tStatus, backoff) - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "WaitVolumeTargetStatusWithCustomBackoff", ctx, volumeID, tStatus, backoff) + ret0, _ := ret[0].(*v2api.Volume) + ret1, _ := ret[1].(error) + return ret0, ret1 } // WaitVolumeTargetStatusWithCustomBackoff indicates an expected call of WaitVolumeTargetStatusWithCustomBackoff. -func (mr *MockIaaSClientMockRecorder) WaitVolumeTargetStatusWithCustomBackoff(ctx, vol, tStatus, backoff any) *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall { +func (mr *MockIaaSClientMockRecorder) WaitVolumeTargetStatusWithCustomBackoff(ctx, volumeID, tStatus, backoff any) *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitVolumeTargetStatusWithCustomBackoff", reflect.TypeOf((*MockIaaSClient)(nil).WaitVolumeTargetStatusWithCustomBackoff), ctx, vol, tStatus, backoff) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitVolumeTargetStatusWithCustomBackoff", reflect.TypeOf((*MockIaaSClient)(nil).WaitVolumeTargetStatusWithCustomBackoff), ctx, volumeID, tStatus, backoff) return &MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall{Call: call} } @@ -993,19 +994,19 @@ type MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall struct { } // Return rewrite *gomock.Call.Return -func (c *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall) Return(arg0 error) *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall { - c.Call = c.Call.Return(arg0) +func (c *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall) Return(arg0 *v2api.Volume, arg1 error) *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall { + c.Call = c.Call.Return(arg0, arg1) return c } // Do rewrite *gomock.Call.Do -func (c *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall) Do(f func(context.Context, **v2api.Volume, []string, *wait.Backoff) error) *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall { +func (c *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall) Do(f func(context.Context, string, []string, wait.Backoff) (*v2api.Volume, error)) *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall) DoAndReturn(f func(context.Context, **v2api.Volume, []string, *wait.Backoff) error) *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall { +func (c *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall) DoAndReturn(f func(context.Context, string, []string, wait.Backoff) (*v2api.Volume, error)) *MockIaaSClientWaitVolumeTargetStatusWithCustomBackoffCall { c.Call = c.Call.DoAndReturn(f) return c }