From 67f53d2eff478e86ee285919bcb64e6e642c4a15 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Mon, 1 Jun 2015 16:58:19 -0700 Subject: [PATCH] Make kubectl work inside a container in k8s --- pkg/client/clientcmd/client_config.go | 30 +++++++++++++++++++ pkg/client/clientcmd/merged_client_builder.go | 5 ++++ pkg/kubectl/cmd/util/factory.go | 9 +++++- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/pkg/client/clientcmd/client_config.go b/pkg/client/clientcmd/client_config.go index 21cae3d25b3..8e0d39b91f6 100644 --- a/pkg/client/clientcmd/client_config.go +++ b/pkg/client/clientcmd/client_config.go @@ -17,6 +17,7 @@ limitations under the License. package clientcmd import ( + "fmt" "io" "os" @@ -284,3 +285,32 @@ func (config DirectClientConfig) getCluster() clientcmdapi.Cluster { return mergedClusterInfo } + +// inClusterClientConfig makes a config that will work from within a kubernetes cluster container environment. +type inClusterClientConfig struct{} + +func (inClusterClientConfig) RawConfig() (clientcmdapi.Config, error) { + return clientcmdapi.Config{}, fmt.Errorf("inCluster environment config doesn't support multiple clusters") +} + +func (inClusterClientConfig) ClientConfig() (*client.Config, error) { + return client.InClusterConfig() +} + +func (inClusterClientConfig) Namespace() (string, error) { + // TODO: generic way to figure out what namespace you are running in? + // This way assumes you've set the POD_NAMESPACE environment variable + // using the downward API. + if ns := os.Getenv("POD_NAMESPACE"); ns != "" { + return ns, nil + } + return "default", nil +} + +// Possible returns true if loading an inside-kubernetes-cluster is possible. +func (inClusterClientConfig) Possible() bool { + fi, err := os.Stat("/var/run/secrets/kubernetes.io/serviceaccount/token") + return os.Getenv("KUBERNETES_SERVICE_HOST") != "" && + os.Getenv("KUBERNETES_SERVICE_PORT") != "" && + err == nil && !fi.IsDir() +} diff --git a/pkg/client/clientcmd/merged_client_builder.go b/pkg/client/clientcmd/merged_client_builder.go index 49a3b73954f..b7f75b29bd3 100644 --- a/pkg/client/clientcmd/merged_client_builder.go +++ b/pkg/client/clientcmd/merged_client_builder.go @@ -45,6 +45,11 @@ func NewInteractiveDeferredLoadingClientConfig(loadingRules *ClientConfigLoading } func (config DeferredLoadingClientConfig) createClientConfig() (ClientConfig, error) { + // Are we running in a cluster? If so, use that. + icc := inClusterClientConfig{} + if icc.Possible() { + return icc, nil + } mergedConfig, err := config.loadingRules.Load() if err != nil { return nil, err diff --git a/pkg/kubectl/cmd/util/factory.go b/pkg/kubectl/cmd/util/factory.go index 9ccde2d9d2c..c598d21d241 100644 --- a/pkg/kubectl/cmd/util/factory.go +++ b/pkg/kubectl/cmd/util/factory.go @@ -290,7 +290,7 @@ func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { // 1. CommandLineLocation - this parsed from the command line, so it must be late bound. If you specify this, // then no other kubeconfig files are merged. This file must exist. // 2. If $KUBECONFIG is set, then it is treated as a list of files that should be merged. -// 3. HomeDirectoryLocation +// 3. HomeDirectoryLocation // Empty filenames are ignored. Files with non-deserializable content produced errors. // The first file to set a particular value or map key wins and the value or map key is never changed. // This means that the first file to set CurrentContext will have its context preserved. It also means @@ -316,6 +316,13 @@ func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { // 2. If the command line does not specify one, and the auth info has conflicting techniques, fail. // 3. If the command line specifies one and the auth info specifies another, honor the command line technique. // 2. Use default values and potentially prompt for auth information +// +// However, if it appears that we're running in a kubernetes cluster +// container environment, then run with the auth info kubernetes mounted for +// us. Specifically: +// The env vars KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT are +// set, and the file /var/run/secrets/kubernetes.io/serviceaccount/token +// exists and is not a directory. func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig { loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() flags.StringVar(&loadingRules.ExplicitPath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.")