From ce57a191db2f0a856ff6517b811814fa712d308b Mon Sep 17 00:00:00 2001 From: Alexander Dahmen Date: Fri, 4 Jul 2025 14:41:52 +0200 Subject: [PATCH] feat(ske): Region adjustment Signed-off-by: Alexander Dahmen --- go.mod | 2 +- go.sum | 4 +-- internal/cmd/ske/cluster/create/create.go | 8 ++--- .../cmd/ske/cluster/create/create_test.go | 8 +++-- internal/cmd/ske/cluster/delete/delete.go | 4 +-- .../cmd/ske/cluster/delete/delete_test.go | 8 +++-- internal/cmd/ske/cluster/describe/describe.go | 2 +- .../cmd/ske/cluster/describe/describe_test.go | 8 +++-- .../generate-payload/generate_payload.go | 4 +-- .../generate-payload/generate_payload_test.go | 12 +++++--- internal/cmd/ske/cluster/list/list.go | 4 +-- internal/cmd/ske/cluster/list/list_test.go | 10 +++++-- internal/cmd/ske/cluster/update/update.go | 6 ++-- .../cmd/ske/cluster/update/update_test.go | 8 +++-- .../complete-rotation/complete_rotation.go | 4 +-- .../complete_rotation_test.go | 8 +++-- .../start-rotation/start_rotation.go | 4 +-- .../start-rotation/start_rotation_test.go | 8 +++-- internal/cmd/ske/kubeconfig/create/create.go | 4 +-- .../cmd/ske/kubeconfig/create/create_test.go | 8 +++-- internal/cmd/ske/kubeconfig/login/login.go | 13 ++++++--- .../cmd/ske/kubeconfig/login/login_test.go | 5 +++- internal/cmd/ske/options/options.go | 6 ++-- internal/cmd/ske/options/options_test.go | 29 ++++++++++++------- internal/pkg/services/ske/client/client.go | 3 +- internal/pkg/services/ske/utils/utils.go | 12 ++++---- internal/pkg/services/ske/utils/utils_test.go | 10 ++++--- 27 files changed, 128 insertions(+), 74 deletions(-) diff --git a/go.mod b/go.mod index ed253d620..5f9d4f9db 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/stackitcloud/stackit-sdk-go/services/serverupdate v1.2.0 github.com/stackitcloud/stackit-sdk-go/services/serviceaccount v0.9.0 github.com/stackitcloud/stackit-sdk-go/services/serviceenablement v1.2.1 - github.com/stackitcloud/stackit-sdk-go/services/ske v0.27.0 + github.com/stackitcloud/stackit-sdk-go/services/ske v1.0.0 github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v1.3.0 github.com/zalando/go-keyring v0.2.6 golang.org/x/mod v0.25.0 diff --git a/go.sum b/go.sum index fc887f795..888db04e5 100644 --- a/go.sum +++ b/go.sum @@ -608,8 +608,8 @@ github.com/stackitcloud/stackit-sdk-go/services/serviceaccount v0.9.0 h1:2d28WFQ github.com/stackitcloud/stackit-sdk-go/services/serviceaccount v0.9.0/go.mod h1:t77MA8uyEU9KZd1On5JpnxI3xhVPKIS8WutStqvU8Cw= github.com/stackitcloud/stackit-sdk-go/services/serviceenablement v1.2.1 h1:h1TsWatlsexLeKdkb3L8chcxaXJOy/cLXctsRxhb4xg= github.com/stackitcloud/stackit-sdk-go/services/serviceenablement v1.2.1/go.mod h1:M4xZ2BnmROvLV2MrAP6A8o9BnyT0CkvpEcP8lBOfRs8= -github.com/stackitcloud/stackit-sdk-go/services/ske v0.27.0 h1:bwLmLXvtCl1XkPRP+YrXwfz+lBMaGWH/crlNbYtxeqE= -github.com/stackitcloud/stackit-sdk-go/services/ske v0.27.0/go.mod h1:V09NmPahuUiuZEogVPgxuVqqti0th5B7TVAjuiM09mE= +github.com/stackitcloud/stackit-sdk-go/services/ske v1.0.0 h1:PX8VTo2UhPd6BeEaCHFlpIkDbk9OFQEO6eJJ8JkxesA= +github.com/stackitcloud/stackit-sdk-go/services/ske v1.0.0/go.mod h1:V09NmPahuUiuZEogVPgxuVqqti0th5B7TVAjuiM09mE= github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v1.3.0 h1:pUl/981oAXPnZd7++69NfEWv6JwW9UpxER16XxQUdOk= github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v1.3.0/go.mod h1:S04/QsQrB2EgYGjl62BO+9QUswrlRBoBosigrhdmccM= github.com/stbenjam/no-sprintf-host-port v0.2.0 h1:i8pxvGrt1+4G0czLr/WnmyH7zbZ8Bg8etvARQ1rpyl4= diff --git a/internal/cmd/ske/cluster/create/create.go b/internal/cmd/ske/cluster/create/create.go index 3f7f9a802..557fb9a3a 100644 --- a/internal/cmd/ske/cluster/create/create.go +++ b/internal/cmd/ske/cluster/create/create.go @@ -108,7 +108,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } // Check if cluster exists - exists, err := skeUtils.ClusterExists(ctx, apiClient, model.ProjectId, model.ClusterName) + exists, err := skeUtils.ClusterExists(ctx, apiClient, model.ProjectId, model.Region, model.ClusterName) if err != nil { return err } @@ -118,7 +118,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { // Fill in default payload, if needed if model.Payload == nil { - defaultPayload, err := skeUtils.GetDefaultPayload(ctx, apiClient) + defaultPayload, err := skeUtils.GetDefaultPayload(ctx, apiClient, model.Region) if err != nil { return fmt.Errorf("get default payload: %w", err) } @@ -137,7 +137,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Creating cluster") - _, err = wait.CreateOrUpdateClusterWaitHandler(ctx, apiClient, model.ProjectId, name).WaitWithContext(ctx) + _, err = wait.CreateOrUpdateClusterWaitHandler(ctx, apiClient, model.ProjectId, model.Region, name).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for SKE cluster creation: %w", err) } @@ -192,7 +192,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *ske.APIClient) ske.ApiCreateOrUpdateClusterRequest { - req := apiClient.CreateOrUpdateCluster(ctx, model.ProjectId, model.ClusterName) + req := apiClient.CreateOrUpdateCluster(ctx, model.ProjectId, model.Region, model.ClusterName) req = req.CreateOrUpdateClusterPayload(*model.Payload) return req diff --git a/internal/cmd/ske/cluster/create/create_test.go b/internal/cmd/ske/cluster/create/create_test.go index f64a03eb1..8fba70614 100644 --- a/internal/cmd/ske/cluster/create/create_test.go +++ b/internal/cmd/ske/cluster/create/create_test.go @@ -26,6 +26,8 @@ var testClient = &ske.APIClient{} var testProjectId = uuid.NewString() var testClusterName = "cluster" +const testRegion = "eu01" + var testPayload = &ske.CreateOrUpdateClusterPayload{ Kubernetes: &ske.Kubernetes{ Version: utils.Ptr("1.25.15"), @@ -81,7 +83,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, payloadFlag: fmt.Sprintf(`{ "name": "cli-jp", "kubernetes": { @@ -128,6 +131,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, ClusterName: testClusterName, @@ -140,7 +144,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *ske.ApiCreateOrUpdateClusterRequest)) ske.ApiCreateOrUpdateClusterRequest { - request := testClient.CreateOrUpdateCluster(testCtx, testProjectId, fixtureInputModel().ClusterName) + request := testClient.CreateOrUpdateCluster(testCtx, testProjectId, testRegion, fixtureInputModel().ClusterName) request = request.CreateOrUpdateClusterPayload(*testPayload) for _, mod := range mods { mod(&request) diff --git a/internal/cmd/ske/cluster/delete/delete.go b/internal/cmd/ske/cluster/delete/delete.go index 8a6e5c9cc..b10871bfe 100644 --- a/internal/cmd/ske/cluster/delete/delete.go +++ b/internal/cmd/ske/cluster/delete/delete.go @@ -70,7 +70,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Deleting cluster") - _, err = wait.DeleteClusterWaitHandler(ctx, apiClient, model.ProjectId, model.ClusterName).WaitWithContext(ctx) + _, err = wait.DeleteClusterWaitHandler(ctx, apiClient, model.ProjectId, model.Region, model.ClusterName).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for SKE cluster deletion: %w", err) } @@ -114,6 +114,6 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *ske.APIClient) ske.ApiDeleteClusterRequest { - req := apiClient.DeleteCluster(ctx, model.ProjectId, model.ClusterName) + req := apiClient.DeleteCluster(ctx, model.ProjectId, model.Region, model.ClusterName) return req } diff --git a/internal/cmd/ske/cluster/delete/delete_test.go b/internal/cmd/ske/cluster/delete/delete_test.go index b51e559ad..2835c477b 100644 --- a/internal/cmd/ske/cluster/delete/delete_test.go +++ b/internal/cmd/ske/cluster/delete/delete_test.go @@ -23,6 +23,8 @@ var testClient = &ske.APIClient{} var testProjectId = uuid.NewString() var testClusterName = "cluster" +const testRegion = "eu01" + func fixtureArgValues(mods ...func(argValues []string)) []string { argValues := []string{ testClusterName, @@ -35,7 +37,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -47,6 +50,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, ClusterName: testClusterName, @@ -58,7 +62,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *ske.ApiDeleteClusterRequest)) ske.ApiDeleteClusterRequest { - request := testClient.DeleteCluster(testCtx, testProjectId, testClusterName) + request := testClient.DeleteCluster(testCtx, testProjectId, testRegion, testClusterName) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/ske/cluster/describe/describe.go b/internal/cmd/ske/cluster/describe/describe.go index 703ce9b0f..40bf4897f 100644 --- a/internal/cmd/ske/cluster/describe/describe.go +++ b/internal/cmd/ske/cluster/describe/describe.go @@ -93,7 +93,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *ske.APIClient) ske.ApiGetClusterRequest { - req := apiClient.GetCluster(ctx, model.ProjectId, model.ClusterName) + req := apiClient.GetCluster(ctx, model.ProjectId, model.Region, model.ClusterName) return req } diff --git a/internal/cmd/ske/cluster/describe/describe_test.go b/internal/cmd/ske/cluster/describe/describe_test.go index 13a1b9468..df33417ff 100644 --- a/internal/cmd/ske/cluster/describe/describe_test.go +++ b/internal/cmd/ske/cluster/describe/describe_test.go @@ -23,6 +23,8 @@ var testClient = &ske.APIClient{} var testProjectId = uuid.NewString() var testClusterName = "cluster" +const testRegion = "eu01" + func fixtureArgValues(mods ...func(argValues []string)) []string { argValues := []string{ testClusterName, @@ -35,7 +37,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -47,6 +50,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, ClusterName: testClusterName, @@ -58,7 +62,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *ske.ApiGetClusterRequest)) ske.ApiGetClusterRequest { - request := testClient.GetCluster(testCtx, testProjectId, testClusterName) + request := testClient.GetCluster(testCtx, testProjectId, testRegion, testClusterName) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/ske/cluster/generate-payload/generate_payload.go b/internal/cmd/ske/cluster/generate-payload/generate_payload.go index 14400f175..566e51f33 100644 --- a/internal/cmd/ske/cluster/generate-payload/generate_payload.go +++ b/internal/cmd/ske/cluster/generate-payload/generate_payload.go @@ -70,7 +70,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { var payload *ske.CreateOrUpdateClusterPayload if model.ClusterName == nil { - payload, err = skeUtils.GetDefaultPayload(ctx, apiClient) + payload, err = skeUtils.GetDefaultPayload(ctx, apiClient, model.Region) if err != nil { return err } @@ -130,7 +130,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { } func buildRequest(ctx context.Context, model *inputModel, apiClient *ske.APIClient) ske.ApiGetClusterRequest { - req := apiClient.GetCluster(ctx, model.ProjectId, *model.ClusterName) + req := apiClient.GetCluster(ctx, model.ProjectId, model.Region, *model.ClusterName) return req } diff --git a/internal/cmd/ske/cluster/generate-payload/generate_payload_test.go b/internal/cmd/ske/cluster/generate-payload/generate_payload_test.go index ac758cd1d..856db970d 100644 --- a/internal/cmd/ske/cluster/generate-payload/generate_payload_test.go +++ b/internal/cmd/ske/cluster/generate-payload/generate_payload_test.go @@ -28,11 +28,14 @@ const ( testFilePath = "example-file" ) +const testRegion = "eu01" + func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - clusterNameFlag: testClusterName, - filePathFlag: testFilePath, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + clusterNameFlag: testClusterName, + filePathFlag: testFilePath, } for _, mod := range mods { mod(flagValues) @@ -44,6 +47,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, ClusterName: utils.Ptr(testClusterName), @@ -56,7 +60,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *ske.ApiGetClusterRequest)) ske.ApiGetClusterRequest { - request := testClient.GetCluster(testCtx, testProjectId, testClusterName) + request := testClient.GetCluster(testCtx, testProjectId, testRegion, testClusterName) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/ske/cluster/list/list.go b/internal/cmd/ske/cluster/list/list.go index 6674be931..31b8f2b7b 100644 --- a/internal/cmd/ske/cluster/list/list.go +++ b/internal/cmd/ske/cluster/list/list.go @@ -144,7 +144,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { } func buildRequest(ctx context.Context, model *inputModel, apiClient *ske.APIClient) ske.ApiListClustersRequest { - req := apiClient.ListClusters(ctx, model.ProjectId) + req := apiClient.ListClusters(ctx, model.ProjectId, model.Region) return req } @@ -172,7 +172,7 @@ func outputResult(p *print.Printer, outputFormat string, clusters []ske.Cluster) for i := range clusters { c := clusters[i] monitoring := "Disabled" - if c.Extensions != nil && c.Extensions.Argus != nil && *c.Extensions.Argus.Enabled { + if c.Extensions != nil && c.Extensions.Observability != nil && *c.Extensions.Observability.Enabled { monitoring = "Enabled" } statusAggregated, kubernetesVersion := "", "" diff --git a/internal/cmd/ske/cluster/list/list_test.go b/internal/cmd/ske/cluster/list/list_test.go index c7eb8a01a..e3c1a063c 100644 --- a/internal/cmd/ske/cluster/list/list_test.go +++ b/internal/cmd/ske/cluster/list/list_test.go @@ -24,10 +24,13 @@ var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") var testClient = &ske.APIClient{} var testProjectId = uuid.NewString() +const testRegion = "eu01" + func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, - limitFlag: "10", + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, + limitFlag: "10", } for _, mod := range mods { mod(flagValues) @@ -39,6 +42,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, Limit: utils.Ptr(int64(10)), @@ -50,7 +54,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *ske.ApiListClustersRequest)) ske.ApiListClustersRequest { - request := testClient.ListClusters(testCtx, testProjectId) + request := testClient.ListClusters(testCtx, testProjectId, testRegion) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/ske/cluster/update/update.go b/internal/cmd/ske/cluster/update/update.go index 8ce6568e9..420c06349 100644 --- a/internal/cmd/ske/cluster/update/update.go +++ b/internal/cmd/ske/cluster/update/update.go @@ -79,7 +79,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } // Check if cluster exists - exists, err := skeUtils.ClusterExists(ctx, apiClient, model.ProjectId, model.ClusterName) + exists, err := skeUtils.ClusterExists(ctx, apiClient, model.ProjectId, model.Region, model.ClusterName) if err != nil { return err } @@ -99,7 +99,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Updating cluster") - _, err = wait.CreateOrUpdateClusterWaitHandler(ctx, apiClient, model.ProjectId, name).WaitWithContext(ctx) + _, err = wait.CreateOrUpdateClusterWaitHandler(ctx, apiClient, model.ProjectId, model.Region, name).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for SKE cluster update: %w", err) } @@ -154,7 +154,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *ske.APIClient) ske.ApiCreateOrUpdateClusterRequest { - req := apiClient.CreateOrUpdateCluster(ctx, model.ProjectId, model.ClusterName) + req := apiClient.CreateOrUpdateCluster(ctx, model.ProjectId, model.Region, model.ClusterName) req = req.CreateOrUpdateClusterPayload(model.Payload) return req diff --git a/internal/cmd/ske/cluster/update/update_test.go b/internal/cmd/ske/cluster/update/update_test.go index 8eab71453..dcf82f207 100644 --- a/internal/cmd/ske/cluster/update/update_test.go +++ b/internal/cmd/ske/cluster/update/update_test.go @@ -26,6 +26,8 @@ var testClient = &ske.APIClient{} var testProjectId = uuid.NewString() var testClusterName = "cluster" +const testRegion = "eu01" + var testPayload = ske.CreateOrUpdateClusterPayload{ Kubernetes: &ske.Kubernetes{ Version: utils.Ptr("1.25.15"), @@ -81,7 +83,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, payloadFlag: fmt.Sprintf(`{ "name": "cli-jp", "kubernetes": { @@ -128,6 +131,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, ClusterName: testClusterName, @@ -140,7 +144,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *ske.ApiCreateOrUpdateClusterRequest)) ske.ApiCreateOrUpdateClusterRequest { - request := testClient.CreateOrUpdateCluster(testCtx, testProjectId, fixtureInputModel().ClusterName) + request := testClient.CreateOrUpdateCluster(testCtx, testProjectId, testRegion, fixtureInputModel().ClusterName) request = request.CreateOrUpdateClusterPayload(testPayload) for _, mod := range mods { mod(&request) diff --git a/internal/cmd/ske/credentials/complete-rotation/complete_rotation.go b/internal/cmd/ske/credentials/complete-rotation/complete_rotation.go index 4b9dfa1d6..982e9267d 100644 --- a/internal/cmd/ske/credentials/complete-rotation/complete_rotation.go +++ b/internal/cmd/ske/credentials/complete-rotation/complete_rotation.go @@ -87,7 +87,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Completing credentials rotation") - _, err = wait.CompleteCredentialsRotationWaitHandler(ctx, apiClient, model.ProjectId, model.ClusterName).WaitWithContext(ctx) + _, err = wait.CompleteCredentialsRotationWaitHandler(ctx, apiClient, model.ProjectId, model.Region, model.ClusterName).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for completing SKE credentials rotation %w", err) } @@ -132,6 +132,6 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *ske.APIClient) ske.ApiCompleteCredentialsRotationRequest { - req := apiClient.CompleteCredentialsRotation(ctx, model.ProjectId, model.ClusterName) + req := apiClient.CompleteCredentialsRotation(ctx, model.ProjectId, model.Region, model.ClusterName) return req } diff --git a/internal/cmd/ske/credentials/complete-rotation/complete_rotation_test.go b/internal/cmd/ske/credentials/complete-rotation/complete_rotation_test.go index 35e773133..b8d40624c 100644 --- a/internal/cmd/ske/credentials/complete-rotation/complete_rotation_test.go +++ b/internal/cmd/ske/credentials/complete-rotation/complete_rotation_test.go @@ -23,6 +23,8 @@ var testClient = &ske.APIClient{} var testProjectId = uuid.NewString() var testClusterName = "cluster" +const testRegion = "eu01" + func fixtureArgValues(mods ...func(argValues []string)) []string { argValues := []string{ testClusterName, @@ -35,7 +37,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -47,6 +50,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, ClusterName: testClusterName, @@ -58,7 +62,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *ske.ApiCompleteCredentialsRotationRequest)) ske.ApiCompleteCredentialsRotationRequest { - request := testClient.CompleteCredentialsRotation(testCtx, testProjectId, testClusterName) + request := testClient.CompleteCredentialsRotation(testCtx, testProjectId, testRegion, testClusterName) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/ske/credentials/start-rotation/start_rotation.go b/internal/cmd/ske/credentials/start-rotation/start_rotation.go index 4e34c9ebe..a8314ad83 100644 --- a/internal/cmd/ske/credentials/start-rotation/start_rotation.go +++ b/internal/cmd/ske/credentials/start-rotation/start_rotation.go @@ -90,7 +90,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if !model.Async { s := spinner.New(params.Printer) s.Start("Starting credentials rotation") - _, err = wait.StartCredentialsRotationWaitHandler(ctx, apiClient, model.ProjectId, model.ClusterName).WaitWithContext(ctx) + _, err = wait.StartCredentialsRotationWaitHandler(ctx, apiClient, model.ProjectId, model.Region, model.ClusterName).WaitWithContext(ctx) if err != nil { return fmt.Errorf("wait for start SKE credentials rotation %w", err) } @@ -135,6 +135,6 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequest(ctx context.Context, model *inputModel, apiClient *ske.APIClient) ske.ApiStartCredentialsRotationRequest { - req := apiClient.StartCredentialsRotation(ctx, model.ProjectId, model.ClusterName) + req := apiClient.StartCredentialsRotation(ctx, model.ProjectId, model.Region, model.ClusterName) return req } diff --git a/internal/cmd/ske/credentials/start-rotation/start_rotation_test.go b/internal/cmd/ske/credentials/start-rotation/start_rotation_test.go index 29f2825ac..0e2f99fa3 100644 --- a/internal/cmd/ske/credentials/start-rotation/start_rotation_test.go +++ b/internal/cmd/ske/credentials/start-rotation/start_rotation_test.go @@ -23,6 +23,8 @@ var testClient = &ske.APIClient{} var testProjectId = uuid.NewString() var testClusterName = "cluster" +const testRegion = "eu01" + func fixtureArgValues(mods ...func(argValues []string)) []string { argValues := []string{ testClusterName, @@ -35,7 +37,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -47,6 +50,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, ClusterName: testClusterName, @@ -58,7 +62,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *ske.ApiStartCredentialsRotationRequest)) ske.ApiStartCredentialsRotationRequest { - request := testClient.StartCredentialsRotation(testCtx, testProjectId, testClusterName) + request := testClient.StartCredentialsRotation(testCtx, testProjectId, testRegion, testClusterName) for _, mod := range mods { mod(&request) } diff --git a/internal/cmd/ske/kubeconfig/create/create.go b/internal/cmd/ske/kubeconfig/create/create.go index c4565223c..fe2907958 100644 --- a/internal/cmd/ske/kubeconfig/create/create.go +++ b/internal/cmd/ske/kubeconfig/create/create.go @@ -228,7 +228,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu } func buildRequestCreate(ctx context.Context, model *inputModel, apiClient *ske.APIClient) (ske.ApiCreateKubeconfigRequest, error) { - req := apiClient.CreateKubeconfig(ctx, model.ProjectId, model.ClusterName) + req := apiClient.CreateKubeconfig(ctx, model.ProjectId, model.Region, model.ClusterName) payload := ske.CreateKubeconfigPayload{} @@ -240,7 +240,7 @@ func buildRequestCreate(ctx context.Context, model *inputModel, apiClient *ske.A } func buildRequestLogin(ctx context.Context, model *inputModel, apiClient *ske.APIClient) (ske.ApiGetLoginKubeconfigRequest, error) { - return apiClient.GetLoginKubeconfig(ctx, model.ProjectId, model.ClusterName), nil + return apiClient.GetLoginKubeconfig(ctx, model.ProjectId, model.Region, model.ClusterName), nil } func outputResult(p *print.Printer, outputFormat, clusterName, kubeconfigPath string, respKubeconfig *ske.Kubeconfig, respLogin *ske.LoginKubeconfig) error { diff --git a/internal/cmd/ske/kubeconfig/create/create_test.go b/internal/cmd/ske/kubeconfig/create/create_test.go index 558d273e5..513fae126 100644 --- a/internal/cmd/ske/kubeconfig/create/create_test.go +++ b/internal/cmd/ske/kubeconfig/create/create_test.go @@ -23,6 +23,8 @@ var testClient = &ske.APIClient{} var testProjectId = uuid.NewString() var testClusterName = "cluster" +const testRegion = "eu01" + func fixtureArgValues(mods ...func(argValues []string)) []string { argValues := []string{ testClusterName, @@ -35,7 +37,8 @@ func fixtureArgValues(mods ...func(argValues []string)) []string { func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - projectIdFlag: testProjectId, + globalflags.ProjectIdFlag: testProjectId, + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -47,6 +50,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ GlobalFlagModel: &globalflags.GlobalFlagModel{ ProjectId: testProjectId, + Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, ClusterName: testClusterName, @@ -58,7 +62,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *ske.ApiCreateKubeconfigRequest)) ske.ApiCreateKubeconfigRequest { - request := testClient.CreateKubeconfig(testCtx, testProjectId, testClusterName) + request := testClient.CreateKubeconfig(testCtx, testProjectId, testRegion, testClusterName) request = request.CreateKubeconfigPayload(ske.CreateKubeconfigPayload{}) for _, mod := range mods { mod(&request) diff --git a/internal/cmd/ske/kubeconfig/login/login.go b/internal/cmd/ske/kubeconfig/login/login.go index 058197418..3edc33b1f 100644 --- a/internal/cmd/ske/kubeconfig/login/login.go +++ b/internal/cmd/ske/kubeconfig/login/login.go @@ -14,6 +14,7 @@ import ( "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/cache" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "k8s.io/client-go/rest" "github.com/stackitcloud/stackit-cli/internal/pkg/args" @@ -55,7 +56,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { "$ kubectl cluster-info", "$ kubectl get pods"), ), - RunE: func(_ *cobra.Command, _ []string) error { + RunE: func(cmd *cobra.Command, _ []string) error { ctx := context.Background() if err := cache.Init(); err != nil { @@ -69,7 +70,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { "See `stackit ske kubeconfig login --help` for detailed usage instructions.") } - clusterConfig, err := parseClusterConfig() + clusterConfig, err := parseClusterConfig(params.Printer, cmd) if err != nil { return fmt.Errorf("parseClusterConfig: %w", err) } @@ -123,9 +124,10 @@ type clusterConfig struct { ClusterName string `json:"clusterName"` cacheKey string + Region string } -func parseClusterConfig() (*clusterConfig, error) { +func parseClusterConfig(p *print.Printer, cmd *cobra.Command) (*clusterConfig, error) { obj, _, err := exec.LoadExecCredentialFromEnv() if err != nil { return nil, fmt.Errorf("LoadExecCredentialFromEnv: %w", err) @@ -155,6 +157,9 @@ func parseClusterConfig() (*clusterConfig, error) { config.cacheKey = fmt.Sprintf("ske-login-%x", sha256.Sum256([]byte(execCredential.Spec.Cluster.Server))) + globalFlags := globalflags.Parse(p, cmd) + config.Region = globalFlags.Region + return config, nil } @@ -200,7 +205,7 @@ func GetAndOutputKubeconfig(ctx context.Context, p *print.Printer, apiClient *sk } func buildRequest(ctx context.Context, apiClient *ske.APIClient, clusterConfig *clusterConfig) ske.ApiCreateKubeconfigRequest { - req := apiClient.CreateKubeconfig(ctx, clusterConfig.STACKITProjectID, clusterConfig.ClusterName) + req := apiClient.CreateKubeconfig(ctx, clusterConfig.STACKITProjectID, clusterConfig.Region, clusterConfig.ClusterName) expirationSeconds := strconv.Itoa(expirationSeconds) return req.CreateKubeconfigPayload(ske.CreateKubeconfigPayload{ExpirationSeconds: &expirationSeconds}) diff --git a/internal/cmd/ske/kubeconfig/login/login_test.go b/internal/cmd/ske/kubeconfig/login/login_test.go index c6b94c9a9..ce22fbc1f 100644 --- a/internal/cmd/ske/kubeconfig/login/login_test.go +++ b/internal/cmd/ske/kubeconfig/login/login_test.go @@ -22,11 +22,14 @@ var testClient = &ske.APIClient{} var testProjectId = uuid.NewString() var testClusterName = "cluster" +const testRegion = "eu01" + func fixtureClusterConfig(mods ...func(clusterConfig *clusterConfig)) *clusterConfig { clusterConfig := &clusterConfig{ STACKITProjectID: testProjectId, ClusterName: testClusterName, cacheKey: "", + Region: testRegion, } for _, mod := range mods { mod(clusterConfig) @@ -35,7 +38,7 @@ func fixtureClusterConfig(mods ...func(clusterConfig *clusterConfig)) *clusterCo } func fixtureRequest(mods ...func(request *ske.ApiCreateKubeconfigRequest)) ske.ApiCreateKubeconfigRequest { - request := testClient.CreateKubeconfig(testCtx, testProjectId, testClusterName) + request := testClient.CreateKubeconfig(testCtx, testProjectId, testRegion, testClusterName) request = request.CreateKubeconfigPayload(ske.CreateKubeconfigPayload{}) for _, mod := range mods { mod(&request) diff --git a/internal/cmd/ske/options/options.go b/internal/cmd/ske/options/options.go index dbcfa7613..91564ceea 100644 --- a/internal/cmd/ske/options/options.go +++ b/internal/cmd/ske/options/options.go @@ -72,7 +72,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } // Call API - req := buildRequest(ctx, apiClient) + req := buildRequest(ctx, apiClient, model) resp, err := req.Execute() if err != nil { return fmt.Errorf("get SKE provider options: %w", err) @@ -131,8 +131,8 @@ func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { return &model, nil } -func buildRequest(ctx context.Context, apiClient *ske.APIClient) ske.ApiListProviderOptionsRequest { - req := apiClient.ListProviderOptions(ctx) +func buildRequest(ctx context.Context, apiClient *ske.APIClient, model *inputModel) ske.ApiListProviderOptionsRequest { + req := apiClient.ListProviderOptions(ctx, model.Region) return req } diff --git a/internal/cmd/ske/options/options_test.go b/internal/cmd/ske/options/options_test.go index b2181ef5b..d2317d1e5 100644 --- a/internal/cmd/ske/options/options_test.go +++ b/internal/cmd/ske/options/options_test.go @@ -18,6 +18,8 @@ type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") var testClient = &ske.APIClient{} +const testRegion = "eu01" + func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ availabilityZonesFlag: "false", @@ -25,6 +27,7 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st machineImagesFlag: "false", machineTypesFlag: "false", volumeTypesFlag: "false", + globalflags.RegionFlag: testRegion, } for _, mod := range mods { mod(flagValues) @@ -34,7 +37,7 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st func fixtureInputModelAllFalse(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{Verbosity: globalflags.VerbosityDefault}, + GlobalFlagModel: &globalflags.GlobalFlagModel{Region: testRegion, Verbosity: globalflags.VerbosityDefault}, AvailabilityZones: false, KubernetesVersions: false, MachineImages: false, @@ -49,7 +52,7 @@ func fixtureInputModelAllFalse(mods ...func(model *inputModel)) *inputModel { func fixtureInputModelAllTrue(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{Verbosity: globalflags.VerbosityDefault}, + GlobalFlagModel: &globalflags.GlobalFlagModel{Region: testRegion, Verbosity: globalflags.VerbosityDefault}, AvailabilityZones: true, KubernetesVersions: true, MachineImages: true, @@ -76,10 +79,12 @@ func TestParseInput(t *testing.T) { expectedModel: fixtureInputModelAllTrue(), }, { - description: "no values", - flagValues: map[string]string{}, - isValid: true, - expectedModel: fixtureInputModelAllTrue(), + description: "no values", + flagValues: map[string]string{}, + isValid: true, + expectedModel: fixtureInputModelAllTrue(func(model *inputModel) { + model.Region = "" + }), }, { description: "some values 1", @@ -90,6 +95,7 @@ func TestParseInput(t *testing.T) { isValid: true, expectedModel: fixtureInputModelAllFalse(func(model *inputModel) { model.AvailabilityZones = true + model.Region = "" }), }, { @@ -103,6 +109,7 @@ func TestParseInput(t *testing.T) { expectedModel: fixtureInputModelAllFalse(func(model *inputModel) { model.KubernetesVersions = true model.MachineTypes = true + model.Region = "" }), }, { @@ -111,8 +118,10 @@ func TestParseInput(t *testing.T) { kubernetesVersionsFlag: "false", machineTypesFlag: "false", }, - isValid: true, - expectedModel: fixtureInputModelAllTrue(), + isValid: true, + expectedModel: fixtureInputModelAllTrue(func(model *inputModel) { + model.Region = "" + }), }, } @@ -169,13 +178,13 @@ func TestBuildRequest(t *testing.T) { }{ { description: "base", - expectedRequest: testClient.ListProviderOptions(testCtx), + expectedRequest: testClient.ListProviderOptions(testCtx, testRegion), }, } for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - request := buildRequest(testCtx, testClient) + request := buildRequest(testCtx, testClient, fixtureInputModelAllTrue()) diff := cmp.Diff(request, tt.expectedRequest, cmp.AllowUnexported(tt.expectedRequest), diff --git a/internal/pkg/services/ske/client/client.go b/internal/pkg/services/ske/client/client.go index a361f73d2..1495ba7bf 100644 --- a/internal/pkg/services/ske/client/client.go +++ b/internal/pkg/services/ske/client/client.go @@ -27,8 +27,7 @@ func ConfigureClient(p *print.Printer, cliVersion string) (*ske.APIClient, error if customEndpoint != "" { cfgOptions = append(cfgOptions, sdkConfig.WithEndpoint(customEndpoint)) } else { - region := viper.GetString(config.RegionKey) - cfgOptions = append(cfgOptions, authCfgOption, sdkConfig.WithRegion(region)) + cfgOptions = append(cfgOptions, authCfgOption) } if p.IsVerbosityDebug() { diff --git a/internal/pkg/services/ske/utils/utils.go b/internal/pkg/services/ske/utils/utils.go index 283760f63..4c5604fc4 100644 --- a/internal/pkg/services/ske/utils/utils.go +++ b/internal/pkg/services/ske/utils/utils.go @@ -32,12 +32,12 @@ const ( ) type SKEClient interface { - ListClustersExecute(ctx context.Context, projectId string) (*ske.ListClustersResponse, error) - ListProviderOptionsExecute(ctx context.Context) (*ske.ProviderOptions, error) + ListClustersExecute(ctx context.Context, projectId, region string) (*ske.ListClustersResponse, error) + ListProviderOptionsExecute(ctx context.Context, region string) (*ske.ProviderOptions, error) } -func ClusterExists(ctx context.Context, apiClient SKEClient, projectId, clusterName string) (bool, error) { - clusters, err := apiClient.ListClustersExecute(ctx, projectId) +func ClusterExists(ctx context.Context, apiClient SKEClient, projectId, region, clusterName string) (bool, error) { + clusters, err := apiClient.ListClustersExecute(ctx, projectId, region) if err != nil { return false, fmt.Errorf("list SKE clusters: %w", err) } @@ -49,8 +49,8 @@ func ClusterExists(ctx context.Context, apiClient SKEClient, projectId, clusterN return false, nil } -func GetDefaultPayload(ctx context.Context, apiClient SKEClient) (*ske.CreateOrUpdateClusterPayload, error) { - resp, err := apiClient.ListProviderOptionsExecute(ctx) +func GetDefaultPayload(ctx context.Context, apiClient SKEClient, region string) (*ske.CreateOrUpdateClusterPayload, error) { + resp, err := apiClient.ListProviderOptionsExecute(ctx, region) if err != nil { return nil, fmt.Errorf("get SKE provider options: %w", err) } diff --git a/internal/pkg/services/ske/utils/utils_test.go b/internal/pkg/services/ske/utils/utils_test.go index 9c6c37ace..27b9b8d6a 100644 --- a/internal/pkg/services/ske/utils/utils_test.go +++ b/internal/pkg/services/ske/utils/utils_test.go @@ -70,14 +70,16 @@ type skeClientMocked struct { listProviderOptionsResp *ske.ProviderOptions } -func (m *skeClientMocked) ListClustersExecute(_ context.Context, _ string) (*ske.ListClustersResponse, error) { +const testRegion = "eu01" + +func (m *skeClientMocked) ListClustersExecute(_ context.Context, _, _ string) (*ske.ListClustersResponse, error) { if m.listClustersFails { return nil, fmt.Errorf("could not list clusters") } return m.listClustersResp, nil } -func (m *skeClientMocked) ListProviderOptionsExecute(_ context.Context) (*ske.ProviderOptions, error) { +func (m *skeClientMocked) ListProviderOptionsExecute(_ context.Context, _ string) (*ske.ProviderOptions, error) { if m.listProviderOptionsFails { return nil, fmt.Errorf("could not list provider options") } @@ -124,7 +126,7 @@ func TestClusterExists(t *testing.T) { listClustersResp: tt.getClustersResp, } - exists, err := ClusterExists(context.Background(), client, testProjectId, testClusterName) + exists, err := ClusterExists(context.Background(), client, testProjectId, testRegion, testClusterName) if tt.isValid && err != nil { t.Errorf("failed on valid input") @@ -400,7 +402,7 @@ func TestGetDefaultPayload(t *testing.T) { listProviderOptionsResp: tt.listProviderOptionsResp, } - output, err := GetDefaultPayload(context.Background(), client) + output, err := GetDefaultPayload(context.Background(), client, testRegion) if tt.isValid && err != nil { t.Errorf("failed on valid input")