WIP: Delete Volume when creation fails with status ERROR - #1452
Conversation
Signed-off-by: Niclas Schad <niclas.schad@stackit.cloud>
|
Skipping CI for Draft Pull Request. |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Signed-off-by: Niclas Schad <niclas.schad@stackit.cloud>
Signed-off-by: Niclas Schad <niclas.schad@stackit.cloud>
| if cs.Driver.deleteVolumesInErrorState { | ||
| cs.deleteVolumeInError(ctx, vol) | ||
| } |
There was a problem hiding this comment.
We also could say we just error here and only delete on the other place above.
There was a problem hiding this comment.
Yes that would be an option. I like it
Signed-off-by: Niclas Schad <niclas.schad@stackit.cloud>
stackit-ske-bot
left a comment
There was a problem hiding this comment.
SKE Code Review
Architectural Feedback
-
Simplify
WaitVolumeTargetStatusWithCustomBackoffSignature:
In pkg/stackit/client/iaas.go#L52,WaitVolumeTargetStatusWithCustomBackoffwas changed from acceptingvolumeID stringtovol **iaas.Volumeto allow mutating the pointer in-place for cleanup after creation. However, since the subsequent cleanup call afterWaitVolumeTargetStatusWithCustomBackoffwas removed in commit 87917aa, mutatingvolin-place is no longer needed in pkg/csi/blockstorage/controllerserver.go#L271.Passing a double pointer (
**iaas.Volume) across interface boundaries is unidiomatic in Go, introduces nil dereference risks (e.g.(*vol).GetId()), and forced modifications across multiple unit tests in pkg/csi/blockstorage/controllerserver_test.go and pkg/stackit/client/mock/iaas_mock.go. Reverting the interface method back tovolumeID stringsimplifies the API, avoids unnecessary mock changes, and keeps it consistent withWaitVolumeTargetStatus.
Findings & Feedback
- All findings and concrete recommendations have been provided as inline code suggestions above.
Verdict
Comment — The flag and cleanup logic for existing error-state volumes in CreateVolume are a great improvement. Please address the nil-safety items and consider reverting the double-pointer signature in WaitVolumeTargetStatusWithCustomBackoff.
| @@ -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 { | |||
There was a problem hiding this comment.
| if *vols[0].Status != stackitclient.VolumeAvailableStatus { | |
| if vols[0].GetStatus() != stackitclient.VolumeAvailableStatus { | |
| if cs.Driver.deleteVolumesInErrorState { | |
| cs.deleteVolumeInError(ctx, &vols[0]) | |
| } | |
| return nil, status.Errorf(codes.Internal, "Volume %s is not in available state", vols[0].GetId()) | |
| } |
Rationale: Use getter methods GetStatus() and GetId() (or status.Errorf) to safely prevent potential nil pointer dereferences when inspecting vols[0].
| 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) | ||
| return nil, status.Error(codes.Internal, fmt.Sprintf("CreateVolume Volume %s failed getting available in time: %v", *vol.Id, err)) |
There was a problem hiding this comment.
| return nil, status.Error(codes.Internal, fmt.Sprintf("CreateVolume Volume %s failed getting available in time: %v", *vol.Id, err)) | |
| return nil, status.Errorf(codes.Internal, "CreateVolume Volume %s failed getting available in time: %v", vol.GetId(), err) |
Rationale: Use vol.GetId() rather than direct pointer dereference *vol.Id to maintain nil-safety and consistency with line 278.
| } | ||
|
|
||
| func (cs *controllerServer) deleteVolumeInError(ctx context.Context, vol *iaas.Volume) { | ||
| cloud := cs.Instance |
There was a problem hiding this comment.
| cloud := cs.Instance | |
| func (cs *controllerServer) deleteVolumeInError(ctx context.Context, vol *iaas.Volume) { | |
| if vol == nil { | |
| return | |
| } | |
| cloud := cs.Instance |
Rationale: Add a defensive nil check on vol before accessing vol.GetStatus() and vol.GetId().
|
|
||
| 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() |
There was a problem hiding this comment.
| volID := (*vol).GetId() | |
| func (i *iaasClient) WaitVolumeTargetStatusWithCustomBackoff(ctx context.Context, vol **iaas.Volume, tStatus []string, backoff *wait.Backoff) error { | |
| if vol == nil || *vol == nil { | |
| return fmt.Errorf("volume pointer cannot be nil") | |
| } | |
| volID := (*vol).GetId() |
Rationale: Guard against nil pointer dereference if vol or *vol is nil, or consider reverting the method signature to accept volumeID string as noted in the architectural feedback.
Signed-off-by: Felix Breuer <f.breuer94@gmail.com>
How to categorize this PR?
/kind enhancement
What this PR does / why we need it:
The idea is to automatically delete the volume when status is
ERROR. We do this there is no left-over volumes even though the CreateVolume RPC failed.Which issue(s) this PR fixes:
Fixes #
Special notes for your reviewer:
Breaking changes: