From 588a21fe7543290b2712c2163277c790744d2b4e Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Mon, 11 May 2026 17:55:17 +0200 Subject: [PATCH 1/7] feat(sfs): refactored and tested sfs resource pool wait handler to use wait helper --- services/sfs/v1api/wait/wait.go | 89 +++++++++++++-------------------- 1 file changed, 35 insertions(+), 54 deletions(-) diff --git a/services/sfs/v1api/wait/wait.go b/services/sfs/v1api/wait/wait.go index d84569a4a..ba2f8a755 100644 --- a/services/sfs/v1api/wait/wait.go +++ b/services/sfs/v1api/wait/wait.go @@ -30,79 +30,60 @@ const ( ) func CreateResourcePoolWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, region, resourcePoolId string) *wait.AsyncActionHandler[sfs.GetResourcePoolResponse] { - handler := wait.New(func() (waitFinished bool, resourcePool *sfs.GetResourcePoolResponse, err error) { - resourcePool, err = api.GetResourcePool(ctx, projectId, region, resourcePoolId).Execute() - if err != nil { - return false, resourcePool, err - } - if resourcePool == nil || - resourcePool.ResourcePool == nil || - resourcePool.ResourcePool.Id == nil || - resourcePool.ResourcePool.State == nil { - return false, resourcePool, fmt.Errorf("create failed for resourcepool with id %s, the response is not valid (state missing)", resourcePoolId) - } - if *resourcePool.ResourcePool.Id == resourcePoolId { - switch *resourcePool.ResourcePool.State { - case ResourcePoolStateCreated: - return true, resourcePool, err - default: - return false, resourcePool, err - } - } + waitConfig := wait.WaiterHelper[sfs.GetResourcePoolResponse, string]{ + FetchInstance: api.GetResourcePool(ctx, projectId, region, resourcePoolId).Execute, + GetState: GetStateResourcePool, + ActiveState: []string{ResourcePoolStateCreated}, + ErrorState: []string{}, + } - return false, nil, nil - }) + handler := wait.New(waitConfig.Wait()) handler.SetTimeout(10 * time.Minute) return handler } func UpdateResourcePoolWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, region, resourcePoolId string) *wait.AsyncActionHandler[sfs.GetResourcePoolResponse] { - handler := wait.New(func() (waitFinished bool, resourcePool *sfs.GetResourcePoolResponse, err error) { - resourcePool, err = api.GetResourcePool(ctx, projectId, region, resourcePoolId).Execute() - if err != nil { - return false, resourcePool, err - } - if resourcePool == nil || - resourcePool.ResourcePool == nil || - resourcePool.ResourcePool.Id == nil || - resourcePool.ResourcePool.State == nil { - return false, resourcePool, fmt.Errorf("update failed for resourcepool with id %s, the response is not valid (state missing)", resourcePoolId) - } - if *resourcePool.ResourcePool.Id == resourcePoolId { - switch *resourcePool.ResourcePool.State { - case ResourcePoolStateCreated: - return true, resourcePool, err - default: - return false, resourcePool, err - } - } + waitConfig := wait.WaiterHelper[sfs.GetResourcePoolResponse, string]{ + FetchInstance: api.GetResourcePool(ctx, projectId, region, resourcePoolId).Execute, + GetState: GetStateResourcePool, + ActiveState: []string{ResourcePoolStateCreated}, + ErrorState: []string{}, + } - return false, nil, nil - }) + handler := wait.New(waitConfig.Wait()) handler.SetTimeout(10 * time.Minute) return handler } func DeleteResourcePoolWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, region, resourcePoolId string) *wait.AsyncActionHandler[sfs.GetResourcePoolResponse] { - handler := wait.New(func() (waitFinished bool, resourcePool *sfs.GetResourcePoolResponse, err error) { - resourcePool, err = api.GetResourcePool(ctx, projectId, region, resourcePoolId).Execute() - if err != nil { - var oapiError *oapierror.GenericOpenAPIError - if errors.As(err, &oapiError) { - if statusCode := oapiError.StatusCode; statusCode == http.StatusNotFound || statusCode == http.StatusGone { - return true, resourcePool, nil - } - } - } - return false, nil, nil - }) + waitConfig := wait.WaiterHelper[sfs.GetResourcePoolResponse, string]{ + FetchInstance: api.GetResourcePool(ctx, projectId, region, resourcePoolId).Execute, + GetState: GetStateResourcePool, + ActiveState: []string{}, + ErrorState: []string{}, + } + + handler := wait.New(waitConfig.Wait()) handler.SetTimeout(10 * time.Minute) return handler } +func GetStateResourcePool(response *sfs.GetResourcePoolResponse) (string, error) { + if response == nil { + return "", errors.New("empty response") + } + if response.ResourcePool == nil { + return "", errors.New("resource pool is nil") + } + if response.ResourcePool.State == nil { + return "", errors.New("resource pool state is nil") + } + return *response.ResourcePool.State, nil +} + func CreateShareWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, region, resourcePoolId, shareId string) *wait.AsyncActionHandler[sfs.GetShareResponse] { handler := wait.New(func() (waitFinished bool, share *sfs.GetShareResponse, err error) { share, err = api.GetShare(ctx, projectId, region, resourcePoolId, shareId).Execute() From 6afca3d1ada4a8bac88d05e0a63a3cff4217d1b8 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 13 May 2026 10:39:35 +0200 Subject: [PATCH 2/7] fix(sfs): refactored unit tests for timeout cases, changed expected value in error case to empty string to align to new waitHelper concept --- services/sfs/v1api/wait/wait_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/sfs/v1api/wait/wait_test.go b/services/sfs/v1api/wait/wait_test.go index 55a300c27..09973daae 100644 --- a/services/sfs/v1api/wait/wait_test.go +++ b/services/sfs/v1api/wait/wait_test.go @@ -125,7 +125,7 @@ func TestCreateResourcePoolWaitHandler(t *testing.T) { {ResourcePoolStateCreating, 0}, }, }, - ResourcePoolStateCreating, + "", true, }, } @@ -214,7 +214,7 @@ func TestUpdateResourcePoolWaitHandler(t *testing.T) { {ResourcePoolStateUpdating, 0}, }, }, - ResourcePoolStateUpdating, + "", true, }, } From 7535142402da910f2fd7c41449646c955d677452 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 13 May 2026 11:29:06 +0200 Subject: [PATCH 3/7] feat(sfs): refactored and tested sfs share wait handler to use wait helper --- services/sfs/v1api/wait/wait.go | 126 ++++++++++++--------------- services/sfs/v1api/wait/wait_test.go | 4 +- 2 files changed, 57 insertions(+), 73 deletions(-) diff --git a/services/sfs/v1api/wait/wait.go b/services/sfs/v1api/wait/wait.go index ba2f8a755..c6b783ae5 100644 --- a/services/sfs/v1api/wait/wait.go +++ b/services/sfs/v1api/wait/wait.go @@ -3,11 +3,8 @@ package wait import ( "context" "errors" - "fmt" - "net/http" "time" - "github.com/stackitcloud/stackit-sdk-go/core/oapierror" "github.com/stackitcloud/stackit-sdk-go/core/wait" sfs "github.com/stackitcloud/stackit-sdk-go/services/sfs/v1api" ) @@ -71,89 +68,76 @@ func DeleteResourcePoolWaitHandler(ctx context.Context, api sfs.DefaultAPI, proj return handler } -func GetStateResourcePool(response *sfs.GetResourcePoolResponse) (string, error) { - if response == nil { - return "", errors.New("empty response") - } - if response.ResourcePool == nil { - return "", errors.New("resource pool is nil") - } - if response.ResourcePool.State == nil { - return "", errors.New("resource pool state is nil") +func CreateShareWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, region, resourcePoolId, shareId string) *wait.AsyncActionHandler[sfs.GetShareResponse] { + waitConfig := wait.WaiterHelper[sfs.GetShareResponse, string]{ + FetchInstance: api.GetShare(ctx, projectId, region, resourcePoolId, shareId).Execute, + GetState: GetStateShare, + ActiveState: []string{ShareStateCreated}, + ErrorState: []string{}, } - return *response.ResourcePool.State, nil -} -func CreateShareWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, region, resourcePoolId, shareId string) *wait.AsyncActionHandler[sfs.GetShareResponse] { - handler := wait.New(func() (waitFinished bool, share *sfs.GetShareResponse, err error) { - share, err = api.GetShare(ctx, projectId, region, resourcePoolId, shareId).Execute() - if err != nil { - return false, share, err - } - if share == nil || - share.Share == nil || - share.Share.Id == nil || - share.Share.State == nil { - return false, share, fmt.Errorf("create failed for share with id %s %s, the response is not valid (state missing)", resourcePoolId, shareId) - } - if *share.Share.Id == shareId { - switch *share.Share.State { - case ShareStateCreated: - return true, share, err - default: - return false, share, err - } - } - - return false, nil, nil - }) + handler := wait.New(waitConfig.Wait()) handler.SetTimeout(10 * time.Minute) return handler } func UpdateShareWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, region, resourcePoolId, shareId string) *wait.AsyncActionHandler[sfs.GetShareResponse] { - handler := wait.New(func() (waitFinished bool, share *sfs.GetShareResponse, err error) { - share, err = api.GetShare(ctx, projectId, region, resourcePoolId, shareId).Execute() - if err != nil { - return false, share, err - } - if share == nil || - share.Share == nil || - share.Share.Id == nil || - share.Share.State == nil { - return false, share, fmt.Errorf("update failed for resourcepool with id %s, the response is not valid (state missing)", resourcePoolId) - } - if *share.Share.Id == shareId { - switch *share.Share.State { - case ResourcePoolStateCreated: - return true, share, err - default: - return false, share, err - } - } - - return false, nil, nil - }) + waitConfig := wait.WaiterHelper[sfs.GetShareResponse, string]{ + FetchInstance: api.GetShare(ctx, projectId, region, resourcePoolId, shareId).Execute, + GetState: GetStateShare, + ActiveState: []string{ShareStateCreated}, + ErrorState: []string{}, + } + + handler := wait.New(waitConfig.Wait()) handler.SetTimeout(10 * time.Minute) return handler } func DeleteShareWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, region, resourcePoolId, shareId string) *wait.AsyncActionHandler[sfs.GetShareResponse] { - handler := wait.New(func() (waitFinished bool, share *sfs.GetShareResponse, err error) { - share, err = api.GetShare(ctx, projectId, region, resourcePoolId, shareId).Execute() - if err != nil { - var oapiError *oapierror.GenericOpenAPIError - if errors.As(err, &oapiError) { - if statusCode := oapiError.StatusCode; statusCode == http.StatusNotFound || statusCode == http.StatusGone { - return true, share, nil - } - } - } - return false, nil, nil - }) + waitConfig := wait.WaiterHelper[sfs.GetShareResponse, string]{ + FetchInstance: api.GetShare(ctx, projectId, region, resourcePoolId, shareId).Execute, + GetState: GetStateShare, + ActiveState: []string{}, + ErrorState: []string{}, + } + + handler := wait.New(waitConfig.Wait()) handler.SetTimeout(10 * time.Minute) return handler } + +func GetStateResourcePool(response *sfs.GetResourcePoolResponse) (string, error) { + if response == nil { + return "", errors.New("empty response") + } + if response.ResourcePool == nil { + return "", errors.New("resource pool is nil") + } + if response.ResourcePool.Id == nil { + return "", errors.New("resource pool id is nil") + } + if response.ResourcePool.State == nil { + return "", errors.New("resource pool state is nil") + } + return *response.ResourcePool.State, nil +} + +func GetStateShare(response *sfs.GetShareResponse) (string, error) { + if response == nil { + return "", errors.New("empty response") + } + if response.Share == nil { + return "", errors.New("share is nil") + } + if response.Share.Id == nil { + return "", errors.New("share id is nil") + } + if response.Share.State == nil { + return "", errors.New("share state is nil") + } + return *response.Share.State, nil +} diff --git a/services/sfs/v1api/wait/wait_test.go b/services/sfs/v1api/wait/wait_test.go index 09973daae..9068528c8 100644 --- a/services/sfs/v1api/wait/wait_test.go +++ b/services/sfs/v1api/wait/wait_test.go @@ -378,7 +378,7 @@ func TestCreateShareWaitHandler(t *testing.T) { {ShareStateCreating, 0}, }, }, - ShareStateCreating, + "", true, }, } @@ -467,7 +467,7 @@ func TestUpdateShareWaitHandler(t *testing.T) { {ShareStateCreating, 0}, }, }, - ShareStateCreating, + "", true, }, } From 953f3ba2fb57c62e6125292cebaf86caf658b42c Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 13 May 2026 11:36:34 +0200 Subject: [PATCH 4/7] fix(sfs): made helper function package private --- services/sfs/v1api/wait/wait.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/services/sfs/v1api/wait/wait.go b/services/sfs/v1api/wait/wait.go index c6b783ae5..5a202ded4 100644 --- a/services/sfs/v1api/wait/wait.go +++ b/services/sfs/v1api/wait/wait.go @@ -29,7 +29,7 @@ const ( func CreateResourcePoolWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, region, resourcePoolId string) *wait.AsyncActionHandler[sfs.GetResourcePoolResponse] { waitConfig := wait.WaiterHelper[sfs.GetResourcePoolResponse, string]{ FetchInstance: api.GetResourcePool(ctx, projectId, region, resourcePoolId).Execute, - GetState: GetStateResourcePool, + GetState: getStateResourcePool, ActiveState: []string{ResourcePoolStateCreated}, ErrorState: []string{}, } @@ -43,7 +43,7 @@ func CreateResourcePoolWaitHandler(ctx context.Context, api sfs.DefaultAPI, proj func UpdateResourcePoolWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, region, resourcePoolId string) *wait.AsyncActionHandler[sfs.GetResourcePoolResponse] { waitConfig := wait.WaiterHelper[sfs.GetResourcePoolResponse, string]{ FetchInstance: api.GetResourcePool(ctx, projectId, region, resourcePoolId).Execute, - GetState: GetStateResourcePool, + GetState: getStateResourcePool, ActiveState: []string{ResourcePoolStateCreated}, ErrorState: []string{}, } @@ -57,7 +57,7 @@ func UpdateResourcePoolWaitHandler(ctx context.Context, api sfs.DefaultAPI, proj func DeleteResourcePoolWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, region, resourcePoolId string) *wait.AsyncActionHandler[sfs.GetResourcePoolResponse] { waitConfig := wait.WaiterHelper[sfs.GetResourcePoolResponse, string]{ FetchInstance: api.GetResourcePool(ctx, projectId, region, resourcePoolId).Execute, - GetState: GetStateResourcePool, + GetState: getStateResourcePool, ActiveState: []string{}, ErrorState: []string{}, } @@ -71,7 +71,7 @@ func DeleteResourcePoolWaitHandler(ctx context.Context, api sfs.DefaultAPI, proj func CreateShareWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, region, resourcePoolId, shareId string) *wait.AsyncActionHandler[sfs.GetShareResponse] { waitConfig := wait.WaiterHelper[sfs.GetShareResponse, string]{ FetchInstance: api.GetShare(ctx, projectId, region, resourcePoolId, shareId).Execute, - GetState: GetStateShare, + GetState: getStateShare, ActiveState: []string{ShareStateCreated}, ErrorState: []string{}, } @@ -85,7 +85,7 @@ func CreateShareWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, func UpdateShareWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, region, resourcePoolId, shareId string) *wait.AsyncActionHandler[sfs.GetShareResponse] { waitConfig := wait.WaiterHelper[sfs.GetShareResponse, string]{ FetchInstance: api.GetShare(ctx, projectId, region, resourcePoolId, shareId).Execute, - GetState: GetStateShare, + GetState: getStateShare, ActiveState: []string{ShareStateCreated}, ErrorState: []string{}, } @@ -99,7 +99,7 @@ func UpdateShareWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, func DeleteShareWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, region, resourcePoolId, shareId string) *wait.AsyncActionHandler[sfs.GetShareResponse] { waitConfig := wait.WaiterHelper[sfs.GetShareResponse, string]{ FetchInstance: api.GetShare(ctx, projectId, region, resourcePoolId, shareId).Execute, - GetState: GetStateShare, + GetState: getStateShare, ActiveState: []string{}, ErrorState: []string{}, } @@ -110,7 +110,7 @@ func DeleteShareWaitHandler(ctx context.Context, api sfs.DefaultAPI, projectId, return handler } -func GetStateResourcePool(response *sfs.GetResourcePoolResponse) (string, error) { +func getStateResourcePool(response *sfs.GetResourcePoolResponse) (string, error) { if response == nil { return "", errors.New("empty response") } @@ -126,7 +126,7 @@ func GetStateResourcePool(response *sfs.GetResourcePoolResponse) (string, error) return *response.ResourcePool.State, nil } -func GetStateShare(response *sfs.GetShareResponse) (string, error) { +func getStateShare(response *sfs.GetShareResponse) (string, error) { if response == nil { return "", errors.New("empty response") } From e545a8d7d2bd4633b02e6434098181a48dc07662 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 13 May 2026 12:49:03 +0200 Subject: [PATCH 5/7] feat(sfs): edit CHANGELOG.md --- CHANGELOG.md | 2 ++ services/sfs/CHANGELOG.md | 3 +++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e379bdaf4..91bdea1e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -398,6 +398,8 @@ - **Feature:** new field `SnapshotSchedules` in model `SnapshotPolicy` - **Feature:** new field `Interval` in model `SnapshotPolicySchedule` - **Feature:** new model `SnapshotPolicySnapshotPolicySchedule` + - [v0.11.0](services/sfs/CHANGELOG.md#v0100) + - - **Improvement:** Use new WaiterHelper for SFS waiters - [v0.10.0](services/sfs/CHANGELOG.md#v0100) - **Breaking change:** Change type from `*string` to `NullableString` of field `SnapshotPolicyId` in model `UpdateResourcePoolPayload` - `ske`: diff --git a/services/sfs/CHANGELOG.md b/services/sfs/CHANGELOG.md index 506bba85c..d60fed951 100644 --- a/services/sfs/CHANGELOG.md +++ b/services/sfs/CHANGELOG.md @@ -1,3 +1,6 @@ +## v0.11.0 +- **Improvement:** Use new WaiterHelper for SFS waiters + ## v0.10.0 - **Breaking change:** Change type from `*string` to `NullableString` of field `SnapshotPolicyId` in model `UpdateResourcePoolPayload` From 193c9fa507f0768256eae17a5f0b480b6cbed527 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 13 May 2026 13:01:13 +0200 Subject: [PATCH 6/7] feat(sfs): lift version after rebase --- services/sfs/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/sfs/VERSION b/services/sfs/VERSION index f78dc3652..e88c34ff0 100644 --- a/services/sfs/VERSION +++ b/services/sfs/VERSION @@ -1 +1 @@ -v0.10.0 \ No newline at end of file +v0.11.0 \ No newline at end of file From b264c3204b6206a015737d471956165973a3fc7f Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 13 May 2026 14:01:58 +0200 Subject: [PATCH 7/7] feat(sfs): corrected order in CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91bdea1e7..f29d5f14d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -398,10 +398,10 @@ - **Feature:** new field `SnapshotSchedules` in model `SnapshotPolicy` - **Feature:** new field `Interval` in model `SnapshotPolicySchedule` - **Feature:** new model `SnapshotPolicySnapshotPolicySchedule` - - [v0.11.0](services/sfs/CHANGELOG.md#v0100) - - - **Improvement:** Use new WaiterHelper for SFS waiters - [v0.10.0](services/sfs/CHANGELOG.md#v0100) - **Breaking change:** Change type from `*string` to `NullableString` of field `SnapshotPolicyId` in model `UpdateResourcePoolPayload` + - [v0.11.0](services/sfs/CHANGELOG.md#v0100) + - **Improvement:** Use new WaiterHelper for SFS waiters - `ske`: - [v1.11.2](services/ske/CHANGELOG.md#v1112) - **Dependencies:** Bump STACKIT SDK core module from `v0.24.0` to `v0.24.1`