Skip to content
Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
- **Feature:** Add new field `AllowSystemComponents` to the `Nodepool` model that configures wether system components are allowed to run on the node pool.
- `loadbalancer`: [v0.XX.X](services/loadbalancer/CHANGELOG.md#v0xxx-2024-xx-xx)
- **Improvement:** Improve default error messages.
- `serviceenablement`: [v0.2.0](services/serviceenablement/CHANGELOG.md#v020-2024-07-12)
- **Feature**: New waiters `EnableServiceWaitHandler` and `DisableServiceWaitHandler` for async operations `EnableService` and `DisableService`, respectively.

## Release (2024-07-01)

Expand Down
4 changes: 4 additions & 0 deletions services/serviceenablement/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## v0.2.0 (2024-07-12)

- **Feature**: New waiters `EnableServiceWaitHandler` and `DisableServiceWaitHandler` for async operations `EnableService` and `DisableService`, respectively.

## v0.1.0 (2024-05-17)

- **New**: STACKIT Service Enablement module can be used to enable services
5 changes: 4 additions & 1 deletion services/serviceenablement/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ module github.com/stackitcloud/stackit-sdk-go/services/serviceenablement

go 1.18

require github.com/stackitcloud/stackit-sdk-go/core v0.12.0
require (
github.com/google/go-cmp v0.6.0
github.com/stackitcloud/stackit-sdk-go/core v0.12.0
)

require (
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
Expand Down
1 change: 1 addition & 0 deletions services/serviceenablement/go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/stackitcloud/stackit-sdk-go/core v0.12.0 h1:auIzUUNRuydKOScvpICP4MifGgvOajiDQd+ncGmBL0U=
Expand Down
75 changes: 75 additions & 0 deletions services/serviceenablement/wait/wait.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package wait

import (
"context"
"fmt"
"time"

"github.com/stackitcloud/stackit-sdk-go/core/wait"
"github.com/stackitcloud/stackit-sdk-go/services/serviceenablement"
)

const (
ServiceStateEnabled = "ENABLED"
ServiceStateEnabling = "ENABLING"
ServiceStateDisabled = "DISABLED"
ServiceStateDisabling = "DISABLING"
)

// Interface needed for tests
type APIClientInstanceInterface interface {
GetServiceStatusExecute(ctx context.Context, projectId, serviceId string) (*serviceenablement.ServiceStatus, error)
}

func EnableServiceWaitHandler(ctx context.Context, a APIClientInstanceInterface, projectId, serviceId string) *wait.AsyncActionHandler[serviceenablement.ServiceStatus] {
handler := wait.New(func() (waitFinished bool, response *serviceenablement.ServiceStatus, err error) {
s, err := a.GetServiceStatusExecute(ctx, projectId, serviceId)
if err != nil {
return false, nil, err
}
if s == nil || s.State == nil {
return false, nil, nil
}
switch *s.State {
default:
return true, s, fmt.Errorf("service with id %s has unexpected state %s", serviceId, *s.State)
case ServiceStateEnabled:
return true, s, nil
case ServiceStateEnabling:
return false, nil, nil
case ServiceStateDisabled:
return true, s, fmt.Errorf("enabling failed for service with id %s", serviceId)
case ServiceStateDisabling:
return true, s, fmt.Errorf("service with id %s is in state %s", serviceId, *s.State)
}
})

handler.SetTimeout(45 * time.Minute).SetSleepBeforeWait(15 * time.Second)
return handler
}

func DisableServiceWaitHandler(ctx context.Context, a APIClientInstanceInterface, projectId, serviceId string) *wait.AsyncActionHandler[serviceenablement.ServiceStatus] {
handler := wait.New(func() (waitFinished bool, response *serviceenablement.ServiceStatus, err error) {
s, err := a.GetServiceStatusExecute(ctx, projectId, serviceId)
if err != nil {
return false, nil, err
}
if s == nil || s.State == nil {
return false, nil, nil
}
switch *s.State {
default:
return true, s, fmt.Errorf("service with id %s has unexpected state %s", serviceId, *s.State)
case ServiceStateDisabled:
return true, s, nil
case ServiceStateDisabling:
return false, nil, nil
case ServiceStateEnabled:
return true, s, fmt.Errorf("disabling failed for service with id %s", serviceId)
case ServiceStateEnabling:
return true, s, fmt.Errorf("service with id %s is in state %s", serviceId, *s.State)
}
})
handler.SetTimeout(45 * time.Minute).SetSleepBeforeWait(15 * time.Second)
return handler
}
195 changes: 195 additions & 0 deletions services/serviceenablement/wait/wait_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package wait

import (
"context"
"testing"
"time"

"github.com/google/go-cmp/cmp"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/serviceenablement"
)

// Used for testing service operations
type apiClientServiceMocked struct {
serviceId string
serviceState string
getServiceFails bool
}

func (a *apiClientServiceMocked) GetServiceStatusExecute(_ context.Context, _, _ string) (*serviceenablement.ServiceStatus, error) {
if a.getServiceFails {
return nil, &oapierror.GenericOpenAPIError{
StatusCode: 500,
}
}

return &serviceenablement.ServiceStatus{
ServiceId: &a.serviceId,
State: &a.serviceState,
}, nil
}

func TestEnableServiceWaitHandler(t *testing.T) {
tests := []struct {
desc string
getServiceFails bool
serviceState string
wantErr bool
wantResp bool
}{
{
desc: "enable_succeeded",
getServiceFails: false,
serviceState: ServiceStateEnabled,
wantErr: false,
wantResp: true,
},
{
desc: "enable_failed",
getServiceFails: false,
serviceState: ServiceStateDisabled,
wantErr: true,
wantResp: false,
},
{
desc: "enable_failed_2",
getServiceFails: false,
serviceState: ServiceStateDisabling,
wantErr: true,
wantResp: false,
},
{
desc: "timeout",
getServiceFails: false,
serviceState: ServiceStateEnabling,
wantErr: true,
wantResp: false,
},
{
desc: "get_service_fails",
getServiceFails: true,
serviceState: ServiceStateEnabling,
wantErr: true,
wantResp: false,
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
serviceId := "serviceId"

apiClient := &apiClientServiceMocked{
serviceId: serviceId,
serviceState: tt.serviceState,
getServiceFails: tt.getServiceFails,
}

var wantRes *serviceenablement.ServiceStatus
if tt.wantResp {
wantRes = &serviceenablement.ServiceStatus{
ServiceId: &serviceId,
State: &tt.serviceState,
}
}

ctx := context.Background()

handler := EnableServiceWaitHandler(ctx, apiClient, "projectId", serviceId)

gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(ctx)

if err != nil {
if !tt.wantErr {
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
}
return
}
if !cmp.Equal(gotRes, wantRes) {
t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes)
}
},
)
}
}

func TestDisableServiceWaitHandler(t *testing.T) {
tests := []struct {
desc string
getServiceFails bool
serviceState string
wantErr bool
wantResp bool
}{
{
desc: "disable_succeeded",
getServiceFails: false,
serviceState: ServiceStateDisabled,
wantErr: false,
wantResp: true,
},
{
desc: "disable_failed",
getServiceFails: false,
serviceState: ServiceStateEnabled,
wantErr: true,
wantResp: false,
},
{
desc: "disable_failed_2",
getServiceFails: false,
serviceState: ServiceStateEnabling,
wantErr: true,
wantResp: false,
},
{
desc: "timeout",
getServiceFails: false,
serviceState: ServiceStateDisabling,
wantErr: true,
wantResp: false,
},
{
desc: "get_service_fails",
getServiceFails: true,
serviceState: ServiceStateDisabling,
wantErr: true,
wantResp: false,
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
serviceId := "serviceId"

apiClient := &apiClientServiceMocked{
serviceId: serviceId,
serviceState: tt.serviceState,
getServiceFails: tt.getServiceFails,
}

var wantRes *serviceenablement.ServiceStatus
if tt.wantResp {
wantRes = &serviceenablement.ServiceStatus{
ServiceId: &serviceId,
State: &tt.serviceState,
}
}

ctx := context.Background()

handler := DisableServiceWaitHandler(ctx, apiClient, "projectId", serviceId)

gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(ctx)

if err != nil {
if !tt.wantErr {
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
}
return
}
if !cmp.Equal(gotRes, wantRes) {
t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes)
}
},
)
}
}