From 17c8a6019f0b3b0f3f53c45d99d6d1d48b1e16d8 Mon Sep 17 00:00:00 2001 From: Kevin Gimbel Date: Mon, 21 Jul 2025 16:17:47 +0200 Subject: [PATCH 1/3] feat(ske): respect KUBECONFIG environment variable (#875) --- internal/pkg/services/ske/utils/utils.go | 6 ++- internal/pkg/services/ske/utils/utils_test.go | 39 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/internal/pkg/services/ske/utils/utils.go b/internal/pkg/services/ske/utils/utils.go index 4c5604fc4..605ca4158 100644 --- a/internal/pkg/services/ske/utils/utils.go +++ b/internal/pkg/services/ske/utils/utils.go @@ -284,8 +284,12 @@ func WriteConfigFile(configPath, data string) error { return nil } -// GetDefaultKubeconfigPath returns the default location for the kubeconfig file. +// GetDefaultKubeconfigPath returns the default location for the kubeconfig file or the value of KUBECONFIG if set. func GetDefaultKubeconfigPath() (string, error) { + if kubeconfigEnv := os.Getenv("KUBECONFIG"); kubeconfigEnv != "" { + return kubeconfigEnv, nil + } + userHome, err := os.UserHomeDir() if err != nil { return "", fmt.Errorf("get user home directory: %w", err) diff --git a/internal/pkg/services/ske/utils/utils_test.go b/internal/pkg/services/ske/utils/utils_test.go index 27b9b8d6a..201bce6b4 100644 --- a/internal/pkg/services/ske/utils/utils_test.go +++ b/internal/pkg/services/ske/utils/utils_test.go @@ -698,3 +698,42 @@ func TestGetDefaultKubeconfigPath(t *testing.T) { }) } } + +func TestGetDefaultKubeconfigPathWithEnvVar(t *testing.T) { + tests := []struct { + description string + kubeconfigEnvVar string + expected string + userHome string + }{ + { + description: "base", + kubeconfigEnvVar: "~/.kube/custom/config", + expected: "~/.kube/custom/config", + userHome: "/home/test-user", + }, + { + description: "return user home when environment var is empty", + kubeconfigEnvVar: "", + expected: "/home/test-user/.kube/config", + userHome: "/home/test-user", + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + // Setup environment variables + os.Setenv("KUBECONFIG", tt.kubeconfigEnvVar) + os.Setenv("HOME", tt.userHome) + + output, err := GetDefaultKubeconfigPath() + + if err != nil { + t.Errorf("failed on valid input") + } + if output != tt.expected { + t.Errorf("expected output to be %s, got %s", tt.expected, output) + } + }) + } +} From 8923ac079cab910ac685efa22de44a33d0f72af2 Mon Sep 17 00:00:00 2001 From: Kevin Gimbel Date: Wed, 30 Jul 2025 09:49:53 +0200 Subject: [PATCH 2/3] docs: document usage of KUBECONFIG env variable --- docs/stackit_ske_kubeconfig_create.md | 4 ++-- internal/cmd/ske/kubeconfig/create/create.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/stackit_ske_kubeconfig_create.md b/docs/stackit_ske_kubeconfig_create.md index d3d0e5622..823c19d72 100644 --- a/docs/stackit_ske_kubeconfig_create.md +++ b/docs/stackit_ske_kubeconfig_create.md @@ -7,7 +7,7 @@ Creates or update a kubeconfig for an SKE cluster Creates a kubeconfig for a STACKIT Kubernetes Engine (SKE) cluster, if the config exits in the kubeconfig file the information will be updated. By default, the kubeconfig information of the SKE cluster is merged into the default kubeconfig file of the current user. If the kubeconfig file doesn't exist, a new one will be created. -You can override this behavior by specifying a custom filepath with the --filepath flag. +You can override this behavior by specifying a custom filepath using the --filepath flag or by setting the KUBECONFIG env variable (fallback). An expiration time can be set for the kubeconfig. The expiration time is set in seconds(s), minutes(m), hours(h), days(d) or months(M). Default is 1h. @@ -47,7 +47,7 @@ stackit ske kubeconfig create CLUSTER_NAME [flags] ``` --disable-writing Disable the writing of kubeconfig. Set the output format to json or yaml using the --output-format flag to display the kubeconfig. -e, --expiration string Expiration time for the kubeconfig in seconds(s), minutes(m), hours(h), days(d) or months(M). Example: 30d. By default, expiration time is 1h - --filepath string Path to create the kubeconfig file. By default, the kubeconfig is created as 'config' in the .kube folder, in the user's home directory. + --filepath string Path to create the kubeconfig file. Will fall back to KUBECONFIG env variable if not set. In case both aren't set, the kubeconfig is created as file named 'config' in the .kube folder in the user's home directory. -h, --help Help for "stackit ske kubeconfig create" -l, --login Create a login kubeconfig that obtains valid credentials via the STACKIT CLI. This flag is mutually exclusive with the expiration flag. --overwrite Overwrite the kubeconfig file. diff --git a/internal/cmd/ske/kubeconfig/create/create.go b/internal/cmd/ske/kubeconfig/create/create.go index fe2907958..631f6c975 100644 --- a/internal/cmd/ske/kubeconfig/create/create.go +++ b/internal/cmd/ske/kubeconfig/create/create.go @@ -48,7 +48,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { Long: fmt.Sprintf("%s\n\n%s\n%s\n%s\n%s", "Creates a kubeconfig for a STACKIT Kubernetes Engine (SKE) cluster, if the config exits in the kubeconfig file the information will be updated.", "By default, the kubeconfig information of the SKE cluster is merged into the default kubeconfig file of the current user. If the kubeconfig file doesn't exist, a new one will be created.", - "You can override this behavior by specifying a custom filepath with the --filepath flag.\n", + "You can override this behavior by specifying a custom filepath using the --filepath flag or by setting the KUBECONFIG env variable (fallback).\n", "An expiration time can be set for the kubeconfig. The expiration time is set in seconds(s), minutes(m), hours(h), days(d) or months(M). Default is 1h.\n", "Note that the format is , e.g. 30d for 30 days and you can't combine units."), Args: args.SingleArg(clusterNameArg, nil), @@ -170,7 +170,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { func configureFlags(cmd *cobra.Command) { cmd.Flags().Bool(disableWritingFlag, false, fmt.Sprintf("Disable the writing of kubeconfig. Set the output format to json or yaml using the --%s flag to display the kubeconfig.", globalflags.OutputFormatFlag)) cmd.Flags().BoolP(loginFlag, "l", false, "Create a login kubeconfig that obtains valid credentials via the STACKIT CLI. This flag is mutually exclusive with the expiration flag.") - cmd.Flags().String(filepathFlag, "", "Path to create the kubeconfig file. By default, the kubeconfig is created as 'config' in the .kube folder, in the user's home directory.") + cmd.Flags().String(filepathFlag, "", "Path to create the kubeconfig file. Will fall back to KUBECONFIG env variable if not set. In case both aren't set, the kubeconfig is created as file named 'config' in the .kube folder in the user's home directory.") cmd.Flags().StringP(expirationFlag, "e", "", "Expiration time for the kubeconfig in seconds(s), minutes(m), hours(h), days(d) or months(M). Example: 30d. By default, expiration time is 1h") cmd.Flags().Bool(overwriteFlag, false, "Overwrite the kubeconfig file.") cmd.MarkFlagsMutuallyExclusive(loginFlag, expirationFlag) From e5f0bcaf2e4c8c25853337402a296255fd0b8b3d Mon Sep 17 00:00:00 2001 From: Kevin Gimbel Date: Wed, 30 Jul 2025 09:50:15 +0200 Subject: [PATCH 3/3] fix(test): check err returned by os.Setenv --- internal/pkg/services/ske/utils/utils_test.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/internal/pkg/services/ske/utils/utils_test.go b/internal/pkg/services/ske/utils/utils_test.go index 201bce6b4..917d590ae 100644 --- a/internal/pkg/services/ske/utils/utils_test.go +++ b/internal/pkg/services/ske/utils/utils_test.go @@ -723,8 +723,14 @@ func TestGetDefaultKubeconfigPathWithEnvVar(t *testing.T) { for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { // Setup environment variables - os.Setenv("KUBECONFIG", tt.kubeconfigEnvVar) - os.Setenv("HOME", tt.userHome) + err := os.Setenv("KUBECONFIG", tt.kubeconfigEnvVar) + if err != nil { + t.Errorf("could not set KUBECONFIG environment variable: %s", err) + } + err = os.Setenv("HOME", tt.userHome) + if err != nil { + t.Errorf("could not set HOME environment variable: %s", err) + } output, err := GetDefaultKubeconfigPath()