From 63b5650885acf6c2f4e68c8140ade2964bc2c6cb Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Mon, 17 Apr 2017 14:25:34 -0400 Subject: [PATCH] Explicit namespace from kubeconfig should override in-cluster config --- .../tools/clientcmd/merged_client_builder.go | 21 ++++++- test/e2e/kubectl.go | 58 +++++++++++++++---- 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/staging/src/k8s.io/client-go/tools/clientcmd/merged_client_builder.go b/staging/src/k8s.io/client-go/tools/clientcmd/merged_client_builder.go index 92c1a5a0061..f3eb6a40a47 100644 --- a/staging/src/k8s.io/client-go/tools/clientcmd/merged_client_builder.go +++ b/staging/src/k8s.io/client-go/tools/clientcmd/merged_client_builder.go @@ -22,6 +22,7 @@ import ( "github.com/golang/glog" + "k8s.io/client-go/pkg/api" restclient "k8s.io/client-go/rest" clientcmdapi "k8s.io/client-go/tools/clientcmd/api" ) @@ -134,12 +135,26 @@ func (config *DeferredLoadingClientConfig) Namespace() (string, bool, error) { return "", false, err } - ns, ok, err := mergedKubeConfig.Namespace() + ns, overridden, err := mergedKubeConfig.Namespace() // if we get an error and it is not empty config, or if the merged config defined an explicit namespace, or // if in-cluster config is not possible, return immediately - if (err != nil && !IsEmptyConfig(err)) || ok || !config.icc.Possible() { + if (err != nil && !IsEmptyConfig(err)) || overridden || !config.icc.Possible() { // return on any error except empty config - return ns, ok, err + return ns, overridden, err + } + + if len(ns) > 0 { + // if we got a non-default namespace from the kubeconfig, use it + if ns != api.NamespaceDefault { + return ns, false, nil + } + + // if we got a default namespace, determine whether it was explicit or implicit + if raw, err := mergedKubeConfig.RawConfig(); err == nil { + if context := raw.Contexts[raw.CurrentContext]; context != nil && len(context.Namespace) > 0 { + return ns, false, nil + } + } } glog.V(4).Infof("Using in-cluster namespace") diff --git a/test/e2e/kubectl.go b/test/e2e/kubectl.go index 4cac24deffa..f0ae3f33aa4 100644 --- a/test/e2e/kubectl.go +++ b/test/e2e/kubectl.go @@ -582,7 +582,7 @@ var _ = framework.KubeDescribe("Kubectl client", func() { It("should handle in-cluster config", func() { By("adding rbac permissions") - // grant the view permission widely to allow inspection of the `invalid` namespace. + // grant the view permission widely to allow inspection of the `invalid` namespace and the default namespace framework.BindClusterRole(f.ClientSet.Rbac(), "view", f.Namespace.Name, rbacv1beta1.Subject{Kind: rbacv1beta1.ServiceAccountKind, Namespace: f.Namespace.Name, Name: "default"}) @@ -608,11 +608,41 @@ var _ = framework.KubeDescribe("Kubectl client", func() { framework.Logf("copying %s to the %s pod", kubectlPath, simplePodName) framework.RunKubectlOrDie("cp", kubectlPath, ns+"/"+simplePodName+":/tmp/") + // Build a kubeconfig file that will make use of the injected ca and token, + // but point at the DNS host and the default namespace + tmpDir, err := ioutil.TempDir("", "icc-override") + overrideKubeconfigName := "icc-override.kubeconfig" + framework.ExpectNoError(err) + defer func() { os.Remove(tmpDir) }() + framework.ExpectNoError(ioutil.WriteFile(filepath.Join(tmpDir, overrideKubeconfigName), []byte(` +kind: Config +apiVersion: v1 +clusters: +- cluster: + api-version: v1 + server: https://kubernetes.default.svc:443 + certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + name: kubeconfig-cluster +contexts: +- context: + cluster: kubeconfig-cluster + namespace: default + user: kubeconfig-user + name: kubeconfig-context +current-context: kubeconfig-context +users: +- name: kubeconfig-user + user: + tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token +`), os.FileMode(0755))) + framework.Logf("copying override kubeconfig to the %s pod", simplePodName) + framework.RunKubectlOrDie("cp", filepath.Join(tmpDir, overrideKubeconfigName), ns+"/"+simplePodName+":/tmp/"+overrideKubeconfigName) + By("getting pods with in-cluster configs") - execOutput := framework.RunHostCmdOrDie(ns, simplePodName, "/tmp/kubectl get pods") - if matched, err := regexp.MatchString("nginx +1/1 +Running", execOutput); err != nil || !matched { - framework.Failf("Unexpected kubectl exec output: ", execOutput) - } + execOutput := framework.RunHostCmdOrDie(ns, simplePodName, "/tmp/kubectl get pods --v=7 2>&1") + Expect(execOutput).To(MatchRegexp("nginx +1/1 +Running")) + Expect(execOutput).To(ContainSubstring("Using in-cluster namespace")) + Expect(execOutput).To(ContainSubstring("Using in-cluster configuration")) By("trying to use kubectl with invalid token") _, err = framework.RunHostCmd(ns, simplePodName, "/tmp/kubectl get pods --token=invalid --v=7 2>&1") @@ -631,13 +661,17 @@ var _ = framework.KubeDescribe("Kubectl client", func() { Expect(err).To(ContainSubstring("GET http://invalid/api")) By("trying to use kubectl with invalid namespace") - output, _ := framework.RunHostCmd(ns, simplePodName, "/tmp/kubectl get pods --namespace=invalid --v=6 2>&1") - Expect(output).To(ContainSubstring("No resources found")) - Expect(output).ToNot(ContainSubstring("Using in-cluster namespace")) - Expect(output).To(ContainSubstring("Using in-cluster configuration")) - if matched, _ := regexp.MatchString(fmt.Sprintf("GET http[s]?://%s:%s/api/v1/namespaces/invalid/pods", inClusterHost, inClusterPort), output); !matched { - framework.Failf("Unexpected kubectl exec output: ", output) - } + execOutput = framework.RunHostCmdOrDie(ns, simplePodName, "/tmp/kubectl get pods --namespace=invalid --v=6 2>&1") + Expect(execOutput).To(ContainSubstring("No resources found")) + Expect(execOutput).ToNot(ContainSubstring("Using in-cluster namespace")) + Expect(execOutput).To(ContainSubstring("Using in-cluster configuration")) + Expect(execOutput).To(MatchRegexp(fmt.Sprintf("GET http[s]?://%s:%s/api/v1/namespaces/invalid/pods", inClusterHost, inClusterPort))) + + By("trying to use kubectl with kubeconfig") + execOutput = framework.RunHostCmdOrDie(ns, simplePodName, "/tmp/kubectl get pods --kubeconfig=/tmp/"+overrideKubeconfigName+" --v=6 2>&1") + Expect(execOutput).ToNot(ContainSubstring("Using in-cluster namespace")) + Expect(execOutput).ToNot(ContainSubstring("Using in-cluster configuration")) + Expect(execOutput).To(ContainSubstring("GET https://kubernetes.default.svc:443/api/v1/namespaces/default/pods")) }) })