Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
74 changes: 74 additions & 0 deletions services/serviceenablement/wait/wait.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
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)
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)
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)
}
},
)
}
}