Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@
- **Dependencies:** Bump STACKIT SDK core module from `v0.24.1` to `v0.25.0`
- [v1.12.2](services/loadbalancer/CHANGELOG.md#v1122)
- **Dependencies:** Bump STACKIT SDK core module to `v0.26.0`
- [v1.13.0](services/loadbalancer/CHANGELOG.md#v1130)
- **Improvement:** Use new WaiterHelper for LoadBalancer waiters
- **Breaking Change:** `v2api/wait/DeleteLoadBalancerWaitHandler` now returns a `LoadBalancer` instead of `struct{}`
- `logme`:
- [v0.27.3](services/logme/CHANGELOG.md#v0273)
- **Dependencies:** Bump STACKIT SDK core module from `v0.24.0` to `v0.24.1`
Expand Down
4 changes: 4 additions & 0 deletions services/loadbalancer/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## v1.13.0
- **Improvement:** Use new WaiterHelper for LoadBalancer waiters
- **Breaking Change:** `v2api/wait/DeleteLoadBalancerWaitHandler` now returns a `LoadBalancer` instead of `struct{}`

## v1.12.2
- **Dependencies:** Bump STACKIT SDK core module to `v0.26.0`

Expand Down
2 changes: 1 addition & 1 deletion services/loadbalancer/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.12.2
v1.13.0
79 changes: 31 additions & 48 deletions services/loadbalancer/v2api/wait/wait.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ package wait

import (
"context"
"errors"
"fmt"
"net/http"
"strings"
"time"

"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/core/wait"
loadbalancer "github.com/stackitcloud/stackit-sdk-go/services/loadbalancer/v2api"
)
Expand All @@ -23,58 +22,42 @@ const (

// CreateLoadBalancerWaitHandler will wait for load balancer creation
func CreateLoadBalancerWaitHandler(ctx context.Context, a loadbalancer.DefaultAPI, projectId, region, instanceName string) *wait.AsyncActionHandler[loadbalancer.LoadBalancer] {
handler := wait.New(func() (waitFinished bool, response *loadbalancer.LoadBalancer, err error) {
s, err := a.GetLoadBalancer(ctx, projectId, region, instanceName).Execute()
if err != nil {
return false, nil, err
}
if s == nil || s.Name == nil || *s.Name != instanceName || s.Status == nil {
return false, nil, nil
}

var errors []string
if len(s.Errors) > 0 {
for _, err := range s.Errors {
errors = append(errors, fmt.Sprintf("%s: %s", *err.Type, *err.Description))
waitConfig := wait.WaiterHelper[loadbalancer.LoadBalancer, string]{
FetchInstance: a.GetLoadBalancer(ctx, projectId, region, instanceName).Execute,
GetState: func(r *loadbalancer.LoadBalancer) (string, error) {
if r == nil || r.Status == nil {
return "", errors.New("response or status is nil")
}
return true, s, fmt.Errorf("create failed for instance with name %s, got status %s and errors: %s", instanceName, *s.Status, strings.Join(errors, ";"))
}

switch *s.Status {
case LOADBALANCERSTATUS_READY:
return true, s, nil
case LOADBALANCERSTATUS_UNSPECIFIED:
return false, nil, nil
case LOADBALANCERSTATUS_PENDING:
return false, nil, nil
case LOADBALANCERSTATUS_TERMINATING:
return true, s, fmt.Errorf("create failed for instance with name %s, got status %s", instanceName, LOADBALANCERSTATUS_TERMINATING)
case LOADBALANCERSTATUS_ERROR:
return true, s, fmt.Errorf("create failed for instance with name %s, got status %s", instanceName, LOADBALANCERSTATUS_ERROR)
default:
return true, s, fmt.Errorf("instance with name %s has unexpected status %s", instanceName, *s.Status)
}
})
var sb strings.Builder
if r.Errors != nil {
for _, err := range r.Errors {
sb.WriteString(fmt.Sprintf("%s: %s; ", *err.Type, *err.Description))
}
return "", fmt.Errorf("create failed for instance with name %s, got status %s and errors: %s", instanceName, *r.Status, sb.String())
}
return *r.Status, nil
},
ActiveState: []string{LOADBALANCERSTATUS_READY},
ErrorState: []string{LOADBALANCERSTATUS_TERMINATING, LOADBALANCERSTATUS_ERROR},
}
handler := wait.New(waitConfig.Wait())
handler.SetTimeout(45 * time.Minute)
return handler
}

// DeleteLoadBalancerWaitHandler will wait for load balancer deletion
func DeleteLoadBalancerWaitHandler(ctx context.Context, a loadbalancer.DefaultAPI, projectId, region, instanceId string) *wait.AsyncActionHandler[struct{}] {
handler := wait.New(func() (waitFinished bool, response *struct{}, err error) {
_, err = a.GetLoadBalancer(ctx, projectId, region, instanceId).Execute()
if err == nil {
return false, nil, nil
}
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
if !ok {
return false, nil, fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError")
}
if oapiErr.StatusCode != http.StatusNotFound {
return false, nil, err
}
return true, nil, nil
})
func DeleteLoadBalancerWaitHandler(ctx context.Context, a loadbalancer.DefaultAPI, projectId, region, instanceId string) *wait.AsyncActionHandler[loadbalancer.LoadBalancer] {
waitConfig := wait.WaiterHelper[loadbalancer.LoadBalancer, string]{
FetchInstance: a.GetLoadBalancer(ctx, projectId, region, instanceId).Execute,
GetState: func(l *loadbalancer.LoadBalancer) (string, error) {
if l == nil || l.Status == nil {
return "", errors.New("response or status is nil")
}
return *l.Status, nil
},
ErrorState: []string{LOADBALANCERSTATUS_ERROR},
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about DeleteHttpErrorStatusCodes: []int{http.StatusNotFound},

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WaiterHelper sets a default:

var defaultHttpErrorStatusCodes = []int{http.StatusForbidden, http.StatusNotFound, http.StatusGone}

Default includes some more statuses, thought these were ok

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, missed that. I had a look at other waiter implementations and saw that this was mentioned there 🙈

handler := wait.New(waitConfig.Wait())
handler.SetTimeout(15 * time.Minute)
return handler
}
Loading