diff --git a/tool/tsh/access_request.go b/tool/tsh/access_request.go index a7930159d90a1..d9084feb14571 100644 --- a/tool/tsh/access_request.go +++ b/tool/tsh/access_request.go @@ -385,7 +385,7 @@ func onRequestSearch(cf *CLIConf) error { // If KubeCluster not provided try to read it from kubeconfig. if cf.KubernetesCluster == "" { - cf.KubernetesCluster = selectedKubeCluster(tc.SiteName) + cf.KubernetesCluster = selectedKubeCluster(tc.SiteName, getKubeConfigPath(cf, "")) } if cf.ResourceKind == types.KindKubePod && cf.KubernetesCluster == "" { return trace.BadParameter("when searching for Pods, --kube-cluster cannot be empty") diff --git a/tool/tsh/kube.go b/tool/tsh/kube.go index 121e8db93730b..c2e35ab0b26ed 100644 --- a/tool/tsh/kube.go +++ b/tool/tsh/kube.go @@ -974,7 +974,7 @@ func (c *kubeLSCommand) run(cf *CLIConf) error { return trace.Wrap(err) } - selectedCluster := selectedKubeCluster(currentTeleportCluster) + selectedCluster := selectedKubeCluster(currentTeleportCluster, getKubeConfigPath(cf, "")) format := strings.ToLower(c.format) switch format { case teleport.Text, "": @@ -1121,8 +1121,9 @@ func serializeKubeListings(kubeListings []kubeListing, format string) (string, e return string(out), trace.Wrap(err) } -func selectedKubeCluster(currentTeleportCluster string) string { - kc, err := kubeconfig.Load("") +// selectedKubeCluster determines which kube cluster, if any, is selected. +func selectedKubeCluster(currentTeleportCluster string, kubeconfgPath string) string { + kc, err := kubeconfig.Load(kubeconfgPath) if err != nil { log.WithError(err).Warning("Failed parsing existing kubeconfig") return "" diff --git a/tool/tsh/kube_test.go b/tool/tsh/kube_test.go index 231107c0da5d5..8d812fbb40590 100644 --- a/tool/tsh/kube_test.go +++ b/tool/tsh/kube_test.go @@ -183,6 +183,11 @@ func (p *kubeTestPack) testListKube(t *testing.T) { tc.args..., ), setCopyStdout(captureStdout), + + // set a custom empty kube config for each test, as we do + // not want parallel (or even shuffled sequential) tests + // potentially racing on the same config + setKubeConfigPath(filepath.Join(t.TempDir(), "kubeconfig")), ) require.NoError(t, err) require.Contains(t, captureStdout.String(), tc.wantTable()) diff --git a/tool/tsh/tsh.go b/tool/tsh/tsh.go index 448fff8647fbd..63293e09be48a 100644 --- a/tool/tsh/tsh.go +++ b/tool/tsh/tsh.go @@ -609,7 +609,12 @@ func initLogger(cf *CLIConf) { } } -// Run executes TSH client. same as main() but easier to test +// Run executes TSH client. same as main() but easier to test. Note that this +// function modifies global state in `tsh` (e.g. the system logger), and WILL +// ALSO MODIFY EXTERNAL SHARED STATE in its default configuration (e.g. the +// $HOME/.tsh dir, $KUBECONFIG, etc). +// +// DO NOT RUN TESTS that call Run() in parallel (unless you taken precautions). func Run(ctx context.Context, args []string, opts ...cliOption) error { cf := CLIConf{ Context: ctx, @@ -4185,7 +4190,7 @@ func makeProfileInfo(p *client.ProfileStatus, env map[string]string, isActive bo Traits: p.Traits, Logins: logins, KubernetesEnabled: p.KubeEnabled, - KubernetesCluster: selectedKubeCluster(p.Cluster), + KubernetesCluster: selectedKubeCluster(p.Cluster, ""), KubernetesUsers: p.KubeUsers, KubernetesGroups: p.KubeGroups, Databases: p.DatabaseServices(), @@ -4652,7 +4657,7 @@ func onEnvironment(cf *CLIConf) error { fmt.Printf("unset %v\n", kubeClusterEnvVar) fmt.Printf("unset %v\n", teleport.EnvKubeConfig) case !cf.unsetEnvironment: - kubeName := selectedKubeCluster(profile.Cluster) + kubeName := selectedKubeCluster(profile.Cluster, "") fmt.Printf("export %v=%v\n", proxyEnvVar, profile.ProxyURL.Host) fmt.Printf("export %v=%v\n", clusterEnvVar, profile.Cluster) if kubeName != "" { @@ -4677,7 +4682,7 @@ func serializeEnvironment(profile *client.ProfileStatus, format string) (string, proxyEnvVar: profile.ProxyURL.Host, clusterEnvVar: profile.Cluster, } - kubeName := selectedKubeCluster(profile.Cluster) + kubeName := selectedKubeCluster(profile.Cluster, "") if kubeName != "" { env[kubeClusterEnvVar] = kubeName env[teleport.EnvKubeConfig] = profile.KubeConfigPath(kubeName)