Skip to content

Commit 6c8df70

Browse files
authored
refac(ske): Use new WaitHelper for waiters (#7725)
STACKITSDK-393 Signed-off-by: Alexander Dahmen <alexander.dahmen@inovex.de>
1 parent ad799be commit 6c8df70

6 files changed

Lines changed: 122 additions & 93 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,10 @@
549549
- **Feature:** Introduce enums for various attributes
550550
- [v1.17.0](services/ske/CHANGELOG.md#v1170)
551551
- **Feature:** New field `ServiceAccountIssuer` for `ClusterStatus` model struct
552+
- [v1.18.0](services/ske/CHANGELOG.md#v1180)
553+
- `v2api`:
554+
- **Improvement:** Use new WaiterHelper for ske waiters
555+
- **Deprecation:** `CreateOrUpdateClusterWaitHandler` will be removed after 2026-12-08. Use the `CreateClusterWaitHandler` or `UpdateClusterWaitHandler` instead.
552556
- `sqlserverflex`:
553557
- [v1.6.3](services/sqlserverflex/CHANGELOG.md#v163)
554558
- **Dependencies:** Bump STACKIT SDK core module from `v0.24.0` to `v0.24.1`

examples/ske/ske.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func main() {
8484
}
8585

8686
// Wait for cluster creation to complete
87-
_, err = wait.CreateOrUpdateClusterWaitHandler(context.Background(), skeClient.DefaultAPI, projectId, region, clusterName).WaitWithContext(context.Background())
87+
_, err = wait.CreateClusterWaitHandler(context.Background(), skeClient.DefaultAPI, projectId, region, clusterName).WaitWithContext(context.Background())
8888
if err != nil {
8989
fmt.Fprintf(os.Stderr, "Error when calling `CreateOrUpdateCluster`: %v\n", err)
9090
} else {

services/ske/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## v1.18.0
2+
- **Improvement:** Use new WaiterHelper for ske waiters
3+
- **Deprecation:** `CreateOrUpdateClusterWaitHandler` will be removed after 2026-12-08. Use the `CreateClusterWaitHandler` or `UpdateClusterWaitHandler` instead.
4+
15
## v1.17.0
26
- **Feature:** New field `ServiceAccountIssuer` for `ClusterStatus` model struct
37

services/ske/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v1.17.0
1+
v1.18.0

services/ske/v2api/wait/wait.go

Lines changed: 67 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package wait
22

33
import (
44
"context"
5-
"fmt"
5+
"errors"
66
"time"
77

88
"github.com/stackitcloud/stackit-sdk-go/core/wait"
@@ -31,7 +31,17 @@ const (
3131
RUNTIMEERRORCODE_OBSERVABILITY_INSTANCE_NOT_FOUND = ske.RUNTIMEERRORCODE_SKE_OBSERVABILITY_INSTANCE_NOT_FOUND
3232
)
3333

34-
// CreateOrUpdateClusterWaitHandler will wait for cluster creation or update
34+
// CreateClusterWaitHandler will wait for cluster creation
35+
func CreateClusterWaitHandler(ctx context.Context, a ske.DefaultAPI, projectId, region, name string) *wait.AsyncActionHandler[ske.Cluster] {
36+
return CreateOrUpdateClusterWaitHandler(ctx, a, projectId, region, name)
37+
}
38+
39+
// UpdateClusterWaitHandler will wait for cluster update
40+
func UpdateClusterWaitHandler(ctx context.Context, a ske.DefaultAPI, projectId, region, name string) *wait.AsyncActionHandler[ske.Cluster] {
41+
return CreateOrUpdateClusterWaitHandler(ctx, a, projectId, region, name)
42+
}
43+
44+
// Deprecated: Will be removed after 2026-12-08. Use the CreateClusterWaitHandler or UpdateClusterWaitHandler instead.
3545
func CreateOrUpdateClusterWaitHandler(ctx context.Context, a ske.DefaultAPI, projectId, region, name string) *wait.AsyncActionHandler[ske.Cluster] {
3646
handler := wait.New(func() (waitFinished bool, response *ske.Cluster, err error) {
3747
s, err := a.GetCluster(ctx, projectId, region, name).Execute()
@@ -151,72 +161,73 @@ func TriggerClusterWakeupWaitHandler(ctx context.Context, a ske.DefaultAPI, proj
151161

152162
// RotateCredentialsWaitHandler will wait for credentials rotation
153163
func RotateCredentialsWaitHandler(ctx context.Context, a ske.DefaultAPI, projectId, region, clusterName string) *wait.AsyncActionHandler[ske.Cluster] {
154-
handler := wait.New(func() (waitFinished bool, response *ske.Cluster, err error) {
155-
s, err := a.GetCluster(ctx, projectId, region, clusterName).Execute()
156-
if err != nil {
157-
return false, nil, err
158-
}
159-
state := *s.Status.Aggregated
160-
161-
if state == ske.CLUSTERSTATUSSTATE_STATE_HEALTHY || state == ske.CLUSTERSTATUSSTATE_STATE_HIBERNATED {
162-
return true, s, nil
163-
}
164-
165-
if state == ske.CLUSTERSTATUSSTATE_STATE_RECONCILING {
166-
return false, nil, nil
167-
}
168-
169-
return true, s, fmt.Errorf("unexpected state %s while waiting for cluster reconciliation", state)
170-
})
171-
164+
waitConfig := wait.WaiterHelper[ske.Cluster, ske.ClusterStatusState]{
165+
FetchInstance: a.GetCluster(ctx, projectId, region, clusterName).Execute,
166+
GetState: func(s *ske.Cluster) (ske.ClusterStatusState, error) {
167+
if s == nil || s.Status == nil || s.Status.Aggregated == nil {
168+
return "", errors.New("empty response or status")
169+
}
170+
return *s.Status.Aggregated, nil
171+
},
172+
ActiveState: []ske.ClusterStatusState{
173+
ske.CLUSTERSTATUSSTATE_STATE_HEALTHY,
174+
ske.CLUSTERSTATUSSTATE_STATE_HIBERNATED,
175+
},
176+
ErrorState: []ske.ClusterStatusState{
177+
ske.CLUSTERSTATUSSTATE_STATE_UNHEALTHY,
178+
ske.CLUSTERSTATUSSTATE_STATE_DELETING,
179+
ske.CLUSTERSTATUSSTATE_STATE_HIBERNATING,
180+
ske.CLUSTERSTATUSSTATE_STATE_WAKINGUP,
181+
},
182+
}
183+
184+
handler := wait.New(waitConfig.Wait())
172185
handler.SetTimeout(10 * time.Minute)
173186
return handler
174187
}
175188

176189
// StartCredentialsRotationWaitHandler will wait for credentials rotation
177190
func StartCredentialsRotationWaitHandler(ctx context.Context, a ske.DefaultAPI, projectId, region, clusterName string) *wait.AsyncActionHandler[ske.Cluster] {
178-
handler := wait.New(func() (waitFinished bool, response *ske.Cluster, err error) {
179-
s, err := a.GetCluster(ctx, projectId, region, clusterName).Execute()
180-
if err != nil {
181-
return false, nil, err
182-
}
183-
state := *s.Status.CredentialsRotation.Phase
184-
185-
if state == ske.CREDENTIALSROTATIONSTATEPHASE_PREPARED {
186-
return true, s, nil
187-
}
188-
189-
if state == ske.CREDENTIALSROTATIONSTATEPHASE_PREPARING {
190-
return false, nil, nil
191-
}
192-
193-
return true, s, fmt.Errorf("unexpected status %s while waiting for cluster credentials rotation to be prepared", state)
194-
})
195-
191+
waitConfig := wait.WaiterHelper[ske.Cluster, ske.CredentialsRotationStatePhase]{
192+
FetchInstance: a.GetCluster(ctx, projectId, region, clusterName).Execute,
193+
GetState: func(s *ske.Cluster) (ske.CredentialsRotationStatePhase, error) {
194+
if s == nil || s.Status == nil || s.Status.CredentialsRotation == nil || s.Status.CredentialsRotation.Phase == nil {
195+
return "", errors.New("empty response or credentials rotation phase")
196+
}
197+
return *s.Status.CredentialsRotation.Phase, nil
198+
},
199+
ActiveState: []ske.CredentialsRotationStatePhase{ske.CREDENTIALSROTATIONSTATEPHASE_PREPARED},
200+
ErrorState: []ske.CredentialsRotationStatePhase{
201+
ske.CREDENTIALSROTATIONSTATEPHASE_NEVER,
202+
ske.CREDENTIALSROTATIONSTATEPHASE_COMPLETING,
203+
ske.CREDENTIALSROTATIONSTATEPHASE_COMPLETED,
204+
},
205+
}
206+
207+
handler := wait.New(waitConfig.Wait())
196208
handler.SetTimeout(45 * time.Minute)
197209
return handler
198210
}
199211

200212
// CompleteCredentialsRotationWaitHandler will wait for credentials rotation
201213
func CompleteCredentialsRotationWaitHandler(ctx context.Context, a ske.DefaultAPI, projectId, region, clusterName string) *wait.AsyncActionHandler[ske.Cluster] {
202-
handler := wait.New(func() (waitFinished bool, response *ske.Cluster, err error) {
203-
s, err := a.GetCluster(ctx, projectId, region, clusterName).Execute()
204-
if err != nil {
205-
return false, nil, err
206-
}
207-
state := *s.Status.CredentialsRotation.Phase
208-
209-
if state == ske.CREDENTIALSROTATIONSTATEPHASE_COMPLETED {
210-
return true, s, nil
211-
}
212-
213-
if state == ske.CREDENTIALSROTATIONSTATEPHASE_COMPLETING {
214-
return false, nil, nil
215-
}
216-
217-
return true, s, fmt.Errorf("unexpected status %s while waiting for cluster credentials rotation to be completed", state)
218-
})
219-
214+
waitConfig := wait.WaiterHelper[ske.Cluster, ske.CredentialsRotationStatePhase]{
215+
FetchInstance: a.GetCluster(ctx, projectId, region, clusterName).Execute,
216+
GetState: func(s *ske.Cluster) (ske.CredentialsRotationStatePhase, error) {
217+
if s == nil || s.Status == nil || s.Status.CredentialsRotation == nil || s.Status.CredentialsRotation.Phase == nil {
218+
return "", errors.New("empty response or credentials rotation phase")
219+
}
220+
return *s.Status.CredentialsRotation.Phase, nil
221+
},
222+
ActiveState: []ske.CredentialsRotationStatePhase{ske.CREDENTIALSROTATIONSTATEPHASE_COMPLETED},
223+
ErrorState: []ske.CredentialsRotationStatePhase{
224+
ske.CREDENTIALSROTATIONSTATEPHASE_NEVER,
225+
ske.CREDENTIALSROTATIONSTATEPHASE_PREPARING,
226+
ske.CREDENTIALSROTATIONSTATEPHASE_PREPARED,
227+
},
228+
}
229+
230+
handler := wait.New(waitConfig.Wait())
220231
handler.SetTimeout(45 * time.Minute)
221232
return handler
222233
}

services/ske/v2api/wait/wait_test.go

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package wait
22

33
import (
44
"context"
5+
"fmt"
56
"net/http"
67
"testing"
78
"testing/synctest"
@@ -11,6 +12,7 @@ import (
1112

1213
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
1314
"github.com/stackitcloud/stackit-sdk-go/core/utils"
15+
"github.com/stackitcloud/stackit-sdk-go/core/wait"
1416
ske "github.com/stackitcloud/stackit-sdk-go/services/ske/v2api"
1517
)
1618

@@ -84,7 +86,7 @@ func TestCreateOrUpdateClusterWaitHandler(t *testing.T) {
8486
wantResp bool
8587
}{
8688
{
87-
desc: "create_succeeded",
89+
desc: "succeeded",
8890
getFails: false,
8991
resourceState: ske.CLUSTERSTATUSSTATE_STATE_HEALTHY,
9092
wantErr: false,
@@ -119,48 +121,56 @@ func TestCreateOrUpdateClusterWaitHandler(t *testing.T) {
119121
wantResp: false,
120122
},
121123
}
122-
for _, tt := range tests {
123-
t.Run(tt.desc, func(t *testing.T) {
124-
synctest.Test(t, func(t *testing.T) {
125-
name := "cluster"
126124

127-
apiClient := newAPIMock(mockSettings{
128-
getFails: tt.getFails,
129-
name: name,
130-
resourceState: tt.resourceState,
131-
invalidArgusInstance: tt.invalidArgusInstance,
132-
})
125+
handlers := map[string]func(context.Context, ske.DefaultAPI, string, string, string) *wait.AsyncActionHandler[ske.Cluster]{
126+
"common logic": CreateOrUpdateClusterWaitHandler,
127+
"create": CreateClusterWaitHandler,
128+
"update": UpdateClusterWaitHandler,
129+
}
133130

134-
var wantRes *ske.Cluster
135-
rs := ske.ClusterStatusState(tt.resourceState)
136-
if tt.wantResp {
137-
wantRes = &ske.Cluster{
138-
Name: &name,
139-
Status: &ske.ClusterStatus{
140-
Aggregated: &rs,
141-
},
142-
}
131+
for handlerDesc, handlerFn := range handlers {
132+
for _, tt := range tests {
133+
t.Run(fmt.Sprintf("%s - %s", handlerDesc, tt.desc), func(t *testing.T) {
134+
synctest.Test(t, func(t *testing.T) {
135+
name := "cluster"
136+
137+
apiClient := newAPIMock(mockSettings{
138+
getFails: tt.getFails,
139+
name: name,
140+
resourceState: tt.resourceState,
141+
invalidArgusInstance: tt.invalidArgusInstance,
142+
})
143+
144+
var wantRes *ske.Cluster
145+
rs := ske.ClusterStatusState(tt.resourceState)
146+
if tt.wantResp {
147+
wantRes = &ske.Cluster{
148+
Name: &name,
149+
Status: &ske.ClusterStatus{
150+
Aggregated: &rs,
151+
},
152+
}
143153

144-
if tt.invalidArgusInstance {
145-
wantRes.Status.Error = &ske.RuntimeError{
146-
Code: utils.Ptr(ske.RUNTIMEERRORCODE_SKE_OBSERVABILITY_INSTANCE_NOT_FOUND),
147-
Message: utils.Ptr("invalid argus instance"),
154+
if tt.invalidArgusInstance {
155+
wantRes.Status.Error = &ske.RuntimeError{
156+
Code: utils.Ptr(ske.RUNTIMEERRORCODE_SKE_OBSERVABILITY_INSTANCE_NOT_FOUND),
157+
Message: utils.Ptr("invalid argus instance"),
158+
}
148159
}
149160
}
150-
}
151-
152-
handler := CreateOrUpdateClusterWaitHandler(context.Background(), apiClient, "", testRegion, name)
153161

154-
gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background())
162+
handler := handlerFn(context.Background(), apiClient, "", testRegion, name)
163+
gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background())
155164

156-
if (err != nil) != tt.wantErr {
157-
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
158-
}
159-
if !cmp.Equal(gotRes, wantRes) {
160-
t.Fatalf("handler gotRes = %+v, want %+v", gotRes, wantRes)
161-
}
165+
if (err != nil) != tt.wantErr {
166+
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
167+
}
168+
if !cmp.Equal(gotRes, wantRes) {
169+
t.Fatalf("handler gotRes = %+v, want %+v", gotRes, wantRes)
170+
}
171+
})
162172
})
163-
})
173+
}
164174
}
165175
}
166176

0 commit comments

Comments
 (0)