Skip to content

Commit 6907e22

Browse files
Add volume attachment waiters
1 parent ceb84e7 commit 6907e22

File tree

2 files changed

+191
-0
lines changed

2 files changed

+191
-0
lines changed

services/iaasalpha/wait/wait.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type APIClientInterface interface {
3434
GetVolumeExecute(ctx context.Context, projectId string, volumeId string) (*iaasalpha.Volume, error)
3535
GetServerExecute(ctx context.Context, projectId string, serverId string) (*iaasalpha.Server, error)
3636
GetProjectRequestExecute(ctx context.Context, projectId string, requestId string) (*iaasalpha.Request, error)
37+
GetAttachedVolumeExecute(ctx context.Context, projectId string, serverId string, volumeId string) (*iaasalpha.VolumeAttachment, error)
3738
}
3839

3940
// CreateVolumeWaitHandler will wait for volume creation
@@ -234,3 +235,56 @@ func ProjectRequestWaitHandler(ctx context.Context, a APIClientInterface, projec
234235
handler.SetTimeout(20 * time.Minute)
235236
return handler
236237
}
238+
239+
// AddVolumeToServerWaitHandler will wait for a volume to be attached to a server
240+
func AddVolumeToServerWaitHandler(ctx context.Context, a APIClientInterface, projectId, serverId, volumeId string) *wait.AsyncActionHandler[iaasalpha.VolumeAttachment] {
241+
handler := wait.New(func() (waitFinished bool, response *iaasalpha.VolumeAttachment, err error) {
242+
volumeAttachment, err := a.GetAttachedVolumeExecute(ctx, projectId, serverId, volumeId)
243+
if err == nil {
244+
if volumeAttachment != nil {
245+
if volumeAttachment.VolumeId == nil {
246+
return false, volumeAttachment, fmt.Errorf("attachment failed for server with id %s and volume with id %s, the response is not valid: the volume id is missing", serverId, volumeId)
247+
}
248+
if *volumeAttachment.VolumeId == volumeId {
249+
return true, volumeAttachment, nil
250+
}
251+
}
252+
return false, nil, nil
253+
}
254+
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
255+
if !ok {
256+
return false, volumeAttachment, fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError: %w", err)
257+
}
258+
if oapiErr.StatusCode != http.StatusNotFound {
259+
return false, volumeAttachment, err
260+
}
261+
return false, nil, nil
262+
})
263+
handler.SetTimeout(10 * time.Minute)
264+
return handler
265+
}
266+
267+
// RemoveVolumeFromServerWaitHandler will wait for a volume to be attached to a server
268+
func RemoveVolumeFromServerWaitHandler(ctx context.Context, a APIClientInterface, projectId, serverId, volumeId string) *wait.AsyncActionHandler[iaasalpha.VolumeAttachment] {
269+
handler := wait.New(func() (waitFinished bool, response *iaasalpha.VolumeAttachment, err error) {
270+
volumeAttachment, err := a.GetAttachedVolumeExecute(ctx, projectId, serverId, volumeId)
271+
if err == nil {
272+
if volumeAttachment != nil {
273+
if volumeAttachment.VolumeId == nil {
274+
return false, volumeAttachment, fmt.Errorf("remove volume failed for server with id %s and volume with id %s, the response is not valid: the volume id is missing", serverId, volumeId)
275+
}
276+
}
277+
return false, nil, nil
278+
}
279+
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
280+
if !ok {
281+
return false, volumeAttachment, fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError: %w", err)
282+
}
283+
if oapiErr.StatusCode != http.StatusNotFound {
284+
return false, volumeAttachment, err
285+
}
286+
return true, nil, nil
287+
})
288+
handler.SetTimeout(10 * time.Minute)
289+
return handler
290+
}

services/iaasalpha/wait/wait_test.go

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ type apiClientMocked struct {
1515
getVolumeFails bool
1616
getServerFails bool
1717
getProjectRequestFails bool
18+
getAttachedVolumeFails bool
1819
isDeleted bool
20+
isAttached bool
1921
resourceState string
2022
requestAction string
2123
returnResizing bool
@@ -81,6 +83,25 @@ func (a *apiClientMocked) GetProjectRequestExecute(_ context.Context, _, _ strin
8183
}, nil
8284
}
8385

86+
func (a *apiClientMocked) GetAttachedVolumeExecute(_ context.Context, _, _, _ string) (*iaasalpha.VolumeAttachment, error) {
87+
if a.getAttachedVolumeFails {
88+
return nil, &oapierror.GenericOpenAPIError{
89+
StatusCode: 500,
90+
}
91+
}
92+
93+
if !a.isAttached {
94+
return nil, &oapierror.GenericOpenAPIError{
95+
StatusCode: 404,
96+
}
97+
}
98+
99+
return &iaasalpha.VolumeAttachment{
100+
ServerId: utils.Ptr("sid"),
101+
VolumeId: utils.Ptr("vid"),
102+
}, nil
103+
}
104+
84105
func TestCreateVolumeWaitHandler(t *testing.T) {
85106
tests := []struct {
86107
desc string
@@ -507,3 +528,119 @@ func TestProjectRequestWaitHandler(t *testing.T) {
507528
})
508529
}
509530
}
531+
532+
func TestAddVolumeToServerWaitHandler(t *testing.T) {
533+
tests := []struct {
534+
desc string
535+
getFails bool
536+
isAttached bool
537+
wantErr bool
538+
wantResp bool
539+
}{
540+
{
541+
desc: "attachment_succeeded",
542+
getFails: false,
543+
isAttached: true,
544+
wantErr: false,
545+
wantResp: true,
546+
},
547+
{
548+
desc: "get_fails",
549+
getFails: true,
550+
wantErr: true,
551+
wantResp: false,
552+
},
553+
{
554+
desc: "timeout",
555+
getFails: false,
556+
isAttached: false,
557+
wantErr: true,
558+
wantResp: false,
559+
},
560+
}
561+
for _, tt := range tests {
562+
t.Run(tt.desc, func(t *testing.T) {
563+
apiClient := &apiClientMocked{
564+
getAttachedVolumeFails: tt.getFails,
565+
isAttached: tt.isAttached,
566+
}
567+
568+
var wantRes *iaasalpha.VolumeAttachment
569+
if tt.wantResp {
570+
wantRes = &iaasalpha.VolumeAttachment{
571+
ServerId: utils.Ptr("sid"),
572+
VolumeId: utils.Ptr("vid"),
573+
}
574+
}
575+
576+
handler := AddVolumeToServerWaitHandler(context.Background(), apiClient, "pid", "sid", "vid")
577+
578+
gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background())
579+
580+
if (err != nil) != tt.wantErr {
581+
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
582+
}
583+
if !cmp.Equal(gotRes, wantRes) {
584+
t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes)
585+
}
586+
})
587+
}
588+
}
589+
590+
func TestRemoveVolumeFromServerWaitHandler(t *testing.T) {
591+
tests := []struct {
592+
desc string
593+
getFails bool
594+
isAttached bool
595+
wantErr bool
596+
wantResp bool
597+
}{
598+
{
599+
desc: "removal_succeeded",
600+
getFails: false,
601+
isAttached: false,
602+
wantErr: false,
603+
wantResp: false,
604+
},
605+
{
606+
desc: "get_fails",
607+
getFails: true,
608+
wantErr: true,
609+
wantResp: false,
610+
},
611+
{
612+
desc: "timeout",
613+
getFails: false,
614+
isAttached: true,
615+
wantErr: true,
616+
wantResp: false,
617+
},
618+
}
619+
for _, tt := range tests {
620+
t.Run(tt.desc, func(t *testing.T) {
621+
apiClient := &apiClientMocked{
622+
getAttachedVolumeFails: tt.getFails,
623+
isAttached: tt.isAttached,
624+
}
625+
626+
var wantRes *iaasalpha.VolumeAttachment
627+
if tt.wantResp {
628+
wantRes = &iaasalpha.VolumeAttachment{
629+
ServerId: utils.Ptr("sid"),
630+
VolumeId: utils.Ptr("vid"),
631+
}
632+
}
633+
634+
handler := RemoveVolumeFromServerWaitHandler(context.Background(), apiClient, "pid", "sid", "vid")
635+
636+
gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background())
637+
638+
if (err != nil) != tt.wantErr {
639+
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
640+
}
641+
if !cmp.Equal(gotRes, wantRes) {
642+
t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes)
643+
}
644+
})
645+
}
646+
}

0 commit comments

Comments
 (0)