diff --git a/examples/ske/ske.go b/examples/ske/ske.go index 67e010c4c..081fa92f1 100644 --- a/examples/ske/ske.go +++ b/examples/ske/ske.go @@ -8,6 +8,7 @@ import ( "github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/utils" "github.com/stackitcloud/stackit-sdk-go/services/ske" + "github.com/stackitcloud/stackit-sdk-go/services/ske/wait" ) func main() { @@ -80,6 +81,46 @@ func main() { if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `CreateCluster`: %v\n", err) } else { - fmt.Printf("Created cluster with cluster name \"%s\".\n", *createClusterResp.Name) + fmt.Printf("Triggered creation of cluster with name \"%s\".\n", *createClusterResp.Name) + } + + // Wait for cluster creation to complete + _, err = wait.CreateOrUpdateClusterWaitHandler(context.Background(), skeClient, projectId, clusterName).WaitWithContext(context.Background()) + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `CreateOrUpdateCluster`: %v\n", err) + } else { + fmt.Printf("Cluster created.\n") + } + + // Start cluster credential rotation + _, err = skeClient.StartCredentialsRotationExecute(context.Background(), projectId, clusterName) + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `StartCredentialsRotation`: %v\n", err) + } else { + fmt.Printf("Triggered start of cluster credentials rotation.\n") + } + + // Wait for cluster credential rotation to be prepared + _, err = wait.StartCredentialsRotationWaitHandler(context.Background(), skeClient, projectId, clusterName).WaitWithContext(context.Background()) + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `StartRotateCredentials`: %v\n", err) + } else { + fmt.Printf("Cluster credentials ready to rotate.\n") + } + + // Complete cluster credential rotation + _, err = skeClient.CompleteCredentialsRotationExecute(context.Background(), projectId, clusterName) + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `CompleteCredentialsRotation`: %v\n", err) + } else { + fmt.Printf("Triggered completion of cluster credentials rotation.\n") + } + + // Wait for cluster credential rotation to be completed + _, err = wait.CompleteCredentialsRotationWaitHandler(context.Background(), skeClient, projectId, clusterName).WaitWithContext(context.Background()) + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `CompleteRotateCredentials`: %v\n", err) + } else { + fmt.Printf("Completed cluster credentials rotation.\n") } } diff --git a/services/ske/CHANGELOG.md b/services/ske/CHANGELOG.md index 478cbe64d..acc628ec3 100644 --- a/services/ske/CHANGELOG.md +++ b/services/ske/CHANGELOG.md @@ -1,3 +1,7 @@ +## v0.11.0 (2024-03-28) + +- **Feature**: Waiters for async operation `StartCredentialsRotationWaitHandler` and `CompleteCredentialsRotationWaitHandler` + ## v0.10.1 (2024-02-28) - Update `core` to [`v0.10.0`](../../core/CHANGELOG.md#v0100-2024-02-27) diff --git a/services/ske/wait/wait.go b/services/ske/wait/wait.go index 77f8331d4..8ec9529a1 100644 --- a/services/ske/wait/wait.go +++ b/services/ske/wait/wait.go @@ -12,14 +12,18 @@ import ( ) const ( - StateHealthy = "STATE_HEALTHY" - StateHibernated = "STATE_HIBERNATED" - StateFailed = "STATE_FAILED" - StateDeleting = "STATE_DELETING" - StateCreated = "STATE_CREATED" - StateUnhealthy = "STATE_UNHEALTHY" - StateReconciling = "STATE_RECONCILING" - InvalidArgusInstanceErrorCode = "SKE_ARGUS_INSTANCE_NOT_FOUND" + StateHealthy = "STATE_HEALTHY" + StateHibernated = "STATE_HIBERNATED" + StateFailed = "STATE_FAILED" + StateDeleting = "STATE_DELETING" + StateCreated = "STATE_CREATED" + StateUnhealthy = "STATE_UNHEALTHY" + StateReconciling = "STATE_RECONCILING" + CredentialsRotationStatePreparing = "PREPARING" + CredentialsRotationStatePrepared = "PREPARED" + CredentialsRotationStateCompleting = "COMPLETING" + CredentialsRotationStateCompleted = "COMPLETED" + InvalidArgusInstanceErrorCode = "SKE_ARGUS_INSTANCE_NOT_FOUND" ) type APIClientProjectInterface interface { @@ -148,3 +152,51 @@ func RotateCredentialsWaitHandler(ctx context.Context, a APIClientClusterInterfa handler.SetTimeout(10 * time.Minute) return handler } + +// StartCredentialsRotationWaitHandler will wait for credentials rotation +func StartCredentialsRotationWaitHandler(ctx context.Context, a APIClientClusterInterface, projectId, clusterName string) *wait.AsyncActionHandler[ske.Cluster] { + handler := wait.New(func() (waitFinished bool, response *ske.Cluster, err error) { + s, err := a.GetClusterExecute(ctx, projectId, clusterName) + if err != nil { + return false, nil, err + } + state := *s.Status.CredentialsRotation.Phase + + if state == CredentialsRotationStatePrepared { + return true, s, nil + } + + if state == CredentialsRotationStatePreparing { + return false, nil, nil + } + + return true, s, fmt.Errorf("unexpected status %s while waiting for cluster credentials rotation to be prepared", state) + }) + + handler.SetTimeout(45 * time.Minute) + return handler +} + +// CompleteCredentialsRotationWaitHandler will wait for credentials rotation +func CompleteCredentialsRotationWaitHandler(ctx context.Context, a APIClientClusterInterface, projectId, clusterName string) *wait.AsyncActionHandler[ske.Cluster] { + handler := wait.New(func() (waitFinished bool, response *ske.Cluster, err error) { + s, err := a.GetClusterExecute(ctx, projectId, clusterName) + if err != nil { + return false, nil, err + } + state := *s.Status.CredentialsRotation.Phase + + if state == CredentialsRotationStateCompleted { + return true, s, nil + } + + if state == CredentialsRotationStateCompleting { + return false, nil, nil + } + + return true, s, fmt.Errorf("unexpected status %s while waiting for cluster credentials rotation to be completed", state) + }) + + handler.SetTimeout(45 * time.Minute) + return handler +}