Skip to content

Commit 8c427a9

Browse files
refac(edge) use WaiterHelper for waiters (#6910)
* refac(edge) use WaiterHelper for waiters * fix(edge) use go 1.25 compatible error conversion * fix(edge) rename unused param to `_` * fix(edge) deprecate unused errors * fix(edge) write changelog, bump version
1 parent 8980283 commit 8c427a9

7 files changed

Lines changed: 161 additions & 137 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@
102102
- **Dependencies:** Bump STACKIT SDK core module to `v0.26.0`
103103
- [v0.10.0](services/edge/CHANGELOG.md#v0100)
104104
- Align package to latest API specification
105+
- [v0.11.0](services/edge/CHANGELOG.md#v0110)
106+
- **Improvement:** Use new `WaiterHandler` struct in the Edge WaitHandler
107+
- **Deprecation:** Deprecated `ErrInstanceCreationFailed` and `ErrInstanceIsBeingDeleted` in `wait` package
105108
- `git`:
106109
- [v0.11.2](services/git/CHANGELOG.md#v0112)
107110
- **Dependencies:** Bump STACKIT SDK core module from `v0.24.0` to `v0.24.1`

services/edge/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## v0.11.0
2+
- **Improvement:** Use new `WaiterHandler` struct in the Edge WaitHandler
3+
- **Deprecation:** Deprecated `ErrInstanceCreationFailed` and `ErrInstanceIsBeingDeleted` in `wait` package
4+
15
## v0.10.0
26
- Align package to latest API specification
37

services/edge/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v0.10.0
1+
v0.11.0

services/edge/v1beta1api/wait/wait.go

Lines changed: 78 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -22,38 +22,31 @@ const (
2222
)
2323

2424
var (
25-
ErrInstanceNotFound = errors.New("instance not found")
25+
ErrInstanceNotFound = errors.New("instance not found")
26+
// Deprecated: ErrInstanceStatusUndefined is no longer used and will be removed after 2026-11-07
2627
ErrInstanceStatusUndefined = errors.New("instance status undefined")
27-
ErrInstanceCreationFailed = errors.New("instance creation failed")
28-
ErrInstanceIsBeingDeleted = errors.New("instance is being deleted")
28+
// Deprecated: ErrInstanceCreationFailed is no longer used and will be removed after 2026-11-07
29+
ErrInstanceCreationFailed = errors.New("instance creation failed")
30+
// Deprecated: ErrInstanceIsBeingDeleted is no longer used and will be removed after 2026-11-07
31+
ErrInstanceIsBeingDeleted = errors.New("instance is being deleted")
2932
)
3033

3134
// createOrUpdateInstanceWaitHandler contains the shared logic for waiting on instance creation or updates.
3235
func createOrUpdateInstanceWaitHandler(ctx context.Context, getInstance func(ctx context.Context) (*edge.Instance, error)) *wait.AsyncActionHandler[edge.Instance] {
33-
handler := wait.New(func() (waitFinished bool, response *edge.Instance, err error) {
34-
instance, err := getInstance(ctx)
35-
if err != nil {
36-
return false, nil, err
37-
}
38-
39-
if instance == nil {
40-
return false, nil, ErrInstanceNotFound
41-
}
42-
43-
status := instance.Status
44-
switch status {
45-
case INSTANCESTATUS_ACTIVE:
46-
return true, instance, nil
47-
case INSTANCESTATUS_ERROR:
48-
return true, instance, ErrInstanceCreationFailed
49-
case INSTANCESTATUS_RECONCILING:
50-
return false, nil, nil
51-
case INSTANCESTATUS_DELETING:
52-
return true, instance, ErrInstanceIsBeingDeleted
53-
default:
54-
return false, nil, nil
55-
}
56-
})
36+
waitConfig := wait.WaiterHelper[edge.Instance, string]{
37+
FetchInstance: func() (*edge.Instance, error) {
38+
return getInstance(ctx)
39+
},
40+
GetState: func(e *edge.Instance) (string, error) {
41+
if e == nil {
42+
return "", ErrInstanceNotFound
43+
}
44+
return e.Status, nil
45+
},
46+
ActiveState: []string{INSTANCESTATUS_ACTIVE},
47+
ErrorState: []string{INSTANCESTATUS_ERROR, INSTANCESTATUS_DELETING},
48+
}
49+
handler := wait.New(waitConfig.Wait())
5750
handler.SetTimeout(timeoutMinutes * time.Minute)
5851
return handler
5952
}
@@ -74,17 +67,18 @@ func CreateOrUpdateInstanceByNameWaitHandler(ctx context.Context, a edge.Default
7467

7568
// deleteInstanceWaitHandler contains the shared logic for waiting on instance deletion.
7669
func deleteInstanceWaitHandler(ctx context.Context, getInstance func(ctx context.Context) (*edge.Instance, error)) *wait.AsyncActionHandler[edge.Instance] {
77-
handler := wait.New(func() (waitFinished bool, response *edge.Instance, err error) {
78-
_, err = getInstance(ctx)
79-
if err == nil {
80-
return false, nil, nil
81-
}
82-
var oapiErr *oapierror.GenericOpenAPIError
83-
if errors.As(err, &oapiErr) && oapiErr.StatusCode == http.StatusNotFound {
84-
return true, nil, nil
85-
}
86-
return false, nil, err
87-
})
70+
waitConfig := wait.WaiterHelper[edge.Instance, string]{
71+
FetchInstance: func() (*edge.Instance, error) {
72+
return getInstance(ctx)
73+
},
74+
GetState: func(e *edge.Instance) (string, error) {
75+
if e == nil {
76+
return "", ErrInstanceNotFound
77+
}
78+
return e.Status, nil
79+
},
80+
}
81+
handler := wait.New(waitConfig.Wait())
8882
handler.SetTimeout(timeoutMinutes * time.Minute)
8983
return handler
9084
}
@@ -105,21 +99,30 @@ func DeleteInstanceByNameWaitHandler(ctx context.Context, a edge.DefaultAPI, pro
10599

106100
// kubeconfigWaitHandlerHelper contains the shared logic for waiting for the instance to become ready before retrieving the kubeconfig.
107101
func kubeconfigWaitHandlerHelper(ctx context.Context, checkInstance func(ctx context.Context) error, getKubeconfig func(ctx context.Context) (*edge.Kubeconfig, error)) *wait.AsyncActionHandler[edge.Kubeconfig] {
108-
handler := wait.New(func() (waitFinished bool, response *edge.Kubeconfig, err error) {
109-
err = checkInstance(ctx)
110-
if err != nil {
111-
return false, nil, err
112-
}
113-
kubeconfig, err := getKubeconfig(ctx)
114-
var oapiErr *oapierror.GenericOpenAPIError
115-
if err != nil {
116-
if errors.As(err, &oapiErr) && oapiErr.StatusCode == http.StatusNotFound {
117-
return false, nil, nil
102+
waitConfig := wait.WaiterHelper[edge.Kubeconfig, string]{
103+
FetchInstance: func() (*edge.Kubeconfig, error) {
104+
err := checkInstance(ctx)
105+
if err != nil {
106+
return nil, err
118107
}
119-
return false, nil, err
120-
}
121-
return true, kubeconfig, nil
122-
})
108+
config, err := getKubeconfig(ctx)
109+
if err != nil {
110+
var apiErr *oapierror.GenericOpenAPIError
111+
if ok := errors.As(err, &apiErr); ok && apiErr.StatusCode == http.StatusNotFound {
112+
return nil, nil
113+
}
114+
}
115+
return config, err
116+
},
117+
GetState: func(e *edge.Kubeconfig) (string, error) {
118+
if e == nil {
119+
return "NOT_READY", nil
120+
}
121+
return "READY", nil
122+
},
123+
ActiveState: []string{"READY"},
124+
}
125+
handler := wait.New(waitConfig.Wait())
123126
handler.SetTimeout(timeoutMinutes * time.Minute)
124127
return handler
125128
}
@@ -158,21 +161,30 @@ func KubeconfigByInstanceNameWaitHandler(ctx context.Context, a edge.DefaultAPI,
158161

159162
// tokenWaitHandlerHelper contains the shared logic for waiting for the instance to become ready before retrieving the service token.
160163
func tokenWaitHandlerHelper(ctx context.Context, checkInstance func(ctx context.Context) error, getToken func(ctx context.Context) (*edge.Token, error)) *wait.AsyncActionHandler[edge.Token] {
161-
handler := wait.New(func() (waitFinished bool, response *edge.Token, err error) {
162-
err = checkInstance(ctx)
163-
if err != nil {
164-
return false, nil, err
165-
}
166-
token, err := getToken(ctx)
167-
var oapiErr *oapierror.GenericOpenAPIError
168-
if err != nil {
169-
if errors.As(err, &oapiErr) && oapiErr.StatusCode == http.StatusNotFound {
170-
return false, nil, nil
164+
waitConfig := wait.WaiterHelper[edge.Token, string]{
165+
FetchInstance: func() (*edge.Token, error) {
166+
err := checkInstance(ctx)
167+
if err != nil {
168+
return nil, err
171169
}
172-
return false, nil, err
173-
}
174-
return true, token, nil
175-
})
170+
token, err := getToken(ctx)
171+
if err != nil {
172+
var apiErr *oapierror.GenericOpenAPIError
173+
if ok := errors.As(err, &apiErr); ok && apiErr.StatusCode == http.StatusNotFound {
174+
return nil, nil
175+
}
176+
}
177+
return token, err
178+
},
179+
GetState: func(e *edge.Token) (string, error) {
180+
if e == nil {
181+
return "NOT_READY", nil
182+
}
183+
return "READY", nil
184+
},
185+
ActiveState: []string{"READY"},
186+
}
187+
handler := wait.New(waitConfig.Wait())
176188
handler.SetTimeout(timeoutMinutes * time.Minute)
177189
return handler
178190
}

services/edge/v1beta1api/wait/wait_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ var createOrUpdateInstanceTests = []struct {
129129
desc: "failed creation",
130130
shouldFail: false,
131131
instanceStatus: INSTANCESTATUS_ERROR,
132-
wantErr: errors.New("instance creation failed"),
132+
wantErr: errors.New("state is error"),
133133
},
134134
{
135135
desc: "API fails",

services/edge/wait/wait.go

Lines changed: 73 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ const timeoutMinutes time.Duration = 10
1717
var (
1818
ErrInstanceNotFound = errors.New("instance not found")
1919
ErrInstanceStatusUndefined = errors.New("instance status undefined")
20-
ErrInstanceCreationFailed = errors.New("instance creation failed")
21-
ErrInstanceIsBeingDeleted = errors.New("instance is being deleted")
20+
// Deprecated: ErrInstanceCreationFailed is no longer used and will be removed after 2026-11-07
21+
ErrInstanceCreationFailed = errors.New("instance creation failed")
22+
// Deprecated: ErrInstanceIsBeingDeleted is no longer used and will be removed after 2026-11-07
23+
ErrInstanceIsBeingDeleted = errors.New("instance is being deleted")
2224
)
2325

2426
// EdgeCloudApiClient is the interface for Edge Cloud API calls which require a waiter.
@@ -33,33 +35,20 @@ type EdgeCloudApiClient interface {
3335

3436
// createOrUpdateInstanceWaitHandler contains the shared logic for waiting on instance creation or updates.
3537
func createOrUpdateInstanceWaitHandler(ctx context.Context, getInstance func(ctx context.Context) (*edge.Instance, error)) *wait.AsyncActionHandler[edge.Instance] {
36-
handler := wait.New(func() (waitFinished bool, response *edge.Instance, err error) {
37-
instance, err := getInstance(ctx)
38-
if err != nil {
39-
return false, nil, err
40-
}
41-
42-
if instance == nil || instance.Status == nil {
43-
return false, nil, ErrInstanceNotFound
44-
}
45-
if instance == nil || instance.Status == nil {
46-
return false, nil, ErrInstanceStatusUndefined
47-
}
48-
49-
status := *instance.Status
50-
switch status {
51-
case edge.INSTANCESTATUS_ACTIVE:
52-
return true, instance, nil
53-
case edge.INSTANCESTATUS_ERROR:
54-
return true, instance, ErrInstanceCreationFailed
55-
case edge.INSTANCESTATUS_RECONCILING:
56-
return false, nil, nil
57-
case edge.INSTANCESTATUS_DELETING:
58-
return true, instance, ErrInstanceIsBeingDeleted
59-
default:
60-
return false, nil, nil
61-
}
62-
})
38+
waitConfig := wait.WaiterHelper[edge.Instance, edge.InstanceStatus]{
39+
FetchInstance: func() (*edge.Instance, error) {
40+
return getInstance(ctx)
41+
},
42+
GetState: func(instance *edge.Instance) (edge.InstanceStatus, error) {
43+
if instance == nil || instance.Status == nil {
44+
return "", ErrInstanceNotFound
45+
}
46+
return *instance.Status, nil
47+
},
48+
ActiveState: []edge.InstanceStatus{edge.INSTANCESTATUS_ACTIVE},
49+
ErrorState: []edge.InstanceStatus{edge.INSTANCESTATUS_ERROR, edge.INSTANCESTATUS_DELETING},
50+
}
51+
handler := wait.New(waitConfig.Wait())
6352
handler.SetTimeout(timeoutMinutes * time.Minute)
6453
return handler
6554
}
@@ -80,17 +69,15 @@ func CreateOrUpdateInstanceByNameWaitHandler(ctx context.Context, a EdgeCloudApi
8069

8170
// deleteInstanceWaitHandler contains the shared logic for waiting on instance deletion.
8271
func deleteInstanceWaitHandler(ctx context.Context, getInstance func(ctx context.Context) (*edge.Instance, error)) *wait.AsyncActionHandler[edge.Instance] {
83-
handler := wait.New(func() (waitFinished bool, response *edge.Instance, err error) {
84-
_, err = getInstance(ctx)
85-
if err == nil {
86-
return false, nil, nil
87-
}
88-
var oapiErr *oapierror.GenericOpenAPIError
89-
if errors.As(err, &oapiErr) && oapiErr.StatusCode == http.StatusNotFound {
90-
return true, nil, nil
91-
}
92-
return false, nil, err
93-
})
72+
waitConfig := wait.WaiterHelper[edge.Instance, edge.InstanceStatus]{
73+
FetchInstance: func() (*edge.Instance, error) {
74+
return getInstance(ctx)
75+
},
76+
GetState: func(_ *edge.Instance) (edge.InstanceStatus, error) {
77+
return "", nil
78+
},
79+
}
80+
handler := wait.New(waitConfig.Wait())
9481
handler.SetTimeout(timeoutMinutes * time.Minute)
9582
return handler
9683
}
@@ -111,21 +98,30 @@ func DeleteInstanceByNameWaitHandler(ctx context.Context, a EdgeCloudApiClient,
11198

11299
// kubeconfigWaitHandlerHelper contains the shared logic for waiting for the instance to become ready before retrieving the kubeconfig.
113100
func kubeconfigWaitHandlerHelper(ctx context.Context, checkInstance func(ctx context.Context) error, getKubeconfig func(ctx context.Context) (*edge.Kubeconfig, error)) *wait.AsyncActionHandler[edge.Kubeconfig] {
114-
handler := wait.New(func() (waitFinished bool, response *edge.Kubeconfig, err error) {
115-
err = checkInstance(ctx)
116-
if err != nil {
117-
return false, nil, err
118-
}
119-
kubeconfig, err := getKubeconfig(ctx)
120-
var oapiErr *oapierror.GenericOpenAPIError
121-
if err != nil {
122-
if errors.As(err, &oapiErr) && oapiErr.StatusCode == http.StatusNotFound {
123-
return false, nil, nil
101+
waitConfig := wait.WaiterHelper[edge.Kubeconfig, string]{
102+
FetchInstance: func() (*edge.Kubeconfig, error) {
103+
err := checkInstance(ctx)
104+
if err != nil {
105+
return nil, err
124106
}
125-
return false, nil, err
126-
}
127-
return true, kubeconfig, nil
128-
})
107+
config, err := getKubeconfig(ctx)
108+
if err != nil {
109+
var apiErr *oapierror.GenericOpenAPIError
110+
if ok := errors.As(err, &apiErr); ok && apiErr.StatusCode == http.StatusNotFound {
111+
return nil, nil
112+
}
113+
}
114+
return config, err
115+
},
116+
GetState: func(k *edge.Kubeconfig) (string, error) {
117+
if k == nil {
118+
return "NOT_READY", nil
119+
}
120+
return "READY", nil
121+
},
122+
ActiveState: []string{"READY"},
123+
}
124+
handler := wait.New(waitConfig.Wait())
129125
handler.SetTimeout(timeoutMinutes * time.Minute)
130126
return handler
131127
}
@@ -164,21 +160,30 @@ func KubeconfigByInstanceNameWaitHandler(ctx context.Context, a EdgeCloudApiClie
164160

165161
// tokenWaitHandlerHelper contains the shared logic for waiting for the instance to become ready before retrieving the service token.
166162
func tokenWaitHandlerHelper(ctx context.Context, checkInstance func(ctx context.Context) error, getToken func(ctx context.Context) (*edge.Token, error)) *wait.AsyncActionHandler[edge.Token] {
167-
handler := wait.New(func() (waitFinished bool, response *edge.Token, err error) {
168-
err = checkInstance(ctx)
169-
if err != nil {
170-
return false, nil, err
171-
}
172-
token, err := getToken(ctx)
173-
var oapiErr *oapierror.GenericOpenAPIError
174-
if err != nil {
175-
if errors.As(err, &oapiErr) && oapiErr.StatusCode == http.StatusNotFound {
176-
return false, nil, nil
163+
waitConfig := wait.WaiterHelper[edge.Token, string]{
164+
FetchInstance: func() (*edge.Token, error) {
165+
err := checkInstance(ctx)
166+
if err != nil {
167+
return nil, err
177168
}
178-
return false, nil, err
179-
}
180-
return true, token, nil
181-
})
169+
token, err := getToken(ctx)
170+
if err != nil {
171+
var apiErr *oapierror.GenericOpenAPIError
172+
if ok := errors.As(err, &apiErr); ok && apiErr.StatusCode == http.StatusNotFound {
173+
return nil, nil
174+
}
175+
}
176+
return token, err
177+
},
178+
GetState: func(t *edge.Token) (string, error) {
179+
if t == nil {
180+
return "NOT_READY", nil
181+
}
182+
return "READY", nil
183+
},
184+
ActiveState: []string{"READY"},
185+
}
186+
handler := wait.New(waitConfig.Wait())
182187
handler.SetTimeout(timeoutMinutes * time.Minute)
183188
return handler
184189
}

services/edge/wait/wait_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ var createOrUpdateInstanceTests = []struct {
173173
desc: "failed creation",
174174
shouldFail: false,
175175
instanceStatus: edge.INSTANCESTATUS_ERROR,
176-
wantErr: errors.New("instance creation failed"),
176+
wantErr: errors.New("state is error"),
177177
},
178178
{
179179
desc: "API fails",

0 commit comments

Comments
 (0)