From 9b604242c68cc6b03064987b78641c276477c890 Mon Sep 17 00:00:00 2001 From: nikhiljindal Date: Mon, 23 May 2016 20:20:27 -0700 Subject: [PATCH] Updating the federation cluster controller to use secretRef to contact the server --- .../cluster/cluster_client.go | 35 ++++++++++++++++-- .../unversioned/clientcmd/client_config.go | 9 +++++ pkg/client/unversioned/clientcmd/loader.go | 37 +++++++++++++++++++ .../clientcmd/merged_client_builder.go | 20 +++++----- 4 files changed, 87 insertions(+), 14 deletions(-) diff --git a/federation/pkg/federation-controller/cluster/cluster_client.go b/federation/pkg/federation-controller/cluster/cluster_client.go index 0864718b772..0b8fdd4ebcd 100644 --- a/federation/pkg/federation-controller/cluster/cluster_client.go +++ b/federation/pkg/federation-controller/cluster/cluster_client.go @@ -17,7 +17,9 @@ limitations under the License. package cluster import ( + "fmt" "net" + "os" "strings" federation_v1alpha1 "k8s.io/kubernetes/federation/apis/federation/v1alpha1" @@ -25,14 +27,17 @@ import ( "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/client/restclient" "k8s.io/kubernetes/pkg/client/typed/discovery" + client "k8s.io/kubernetes/pkg/client/unversioned" "k8s.io/kubernetes/pkg/client/unversioned/clientcmd" + clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" utilnet "k8s.io/kubernetes/pkg/util/net" ) const ( - UserAgentName = "Cluster-Controller" - KubeAPIQPS = 20.0 - KubeAPIBurst = 30 + UserAgentName = "Cluster-Controller" + KubeAPIQPS = 20.0 + KubeAPIBurst = 30 + KubeconfigSecretDataKey = "kubeconfig" ) type ClusterClient struct { @@ -59,7 +64,29 @@ func NewClusterClientSet(c *federation_v1alpha1.Cluster) (*ClusterClient, error) } var clusterClientSet = ClusterClient{} if serverAddress != "" { - clusterConfig, err := clientcmd.BuildConfigFromFlags(serverAddress, "") + // Get a client to talk to the k8s apiserver, to fetch secrets from it. + client, err := client.NewInCluster() + if err != nil { + return nil, fmt.Errorf("error in creating in-cluster client: %s", err) + } + kubeconfigGetter := func() (*clientcmdapi.Config, error) { + // Get the namespace this is running in from the env variable. + namespace := os.Getenv("POD_NAMESPACE") + if namespace == "" { + return nil, fmt.Errorf("unexpected: POD_NAMESPACE env var returned empty string") + } + secret, err := client.Secrets(namespace).Get(c.Spec.SecretRef.Name) + if err != nil { + return nil, fmt.Errorf("error in fetching secret: %s", err) + } + data, ok := secret.Data[KubeconfigSecretDataKey] + if !ok { + return nil, fmt.Errorf("secret does not have data with key: %s", KubeconfigSecretDataKey) + } + return clientcmd.Load(data) + } + + clusterConfig, err := clientcmd.BuildConfigFromKubeconfigGetter(serverAddress, kubeconfigGetter) if err != nil { return nil, err } diff --git a/pkg/client/unversioned/clientcmd/client_config.go b/pkg/client/unversioned/clientcmd/client_config.go index c030ec1bd66..40ccdb64eb0 100644 --- a/pkg/client/unversioned/clientcmd/client_config.go +++ b/pkg/client/unversioned/clientcmd/client_config.go @@ -399,3 +399,12 @@ func BuildConfigFromFlags(masterUrl, kubeconfigPath string) (*restclient.Config, &ClientConfigLoadingRules{ExplicitPath: kubeconfigPath}, &ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterUrl}}).ClientConfig() } + +// BuildConfigFromKubeconfigGetter is a helper function that builds configs from a master +// url and a kubeconfigGetter. +func BuildConfigFromKubeconfigGetter(masterUrl string, kubeconfigGetter KubeconfigGetter) (*restclient.Config, error) { + cc := NewNonInteractiveDeferredLoadingClientConfig( + &ClientConfigGetter{kubeconfigGetter: kubeconfigGetter}, + &ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterUrl}}) + return cc.ClientConfig() +} diff --git a/pkg/client/unversioned/clientcmd/loader.go b/pkg/client/unversioned/clientcmd/loader.go index 1742d60a4a3..f0c9c547a1d 100644 --- a/pkg/client/unversioned/clientcmd/loader.go +++ b/pkg/client/unversioned/clientcmd/loader.go @@ -63,6 +63,40 @@ func currentMigrationRules() map[string]string { return migrationRules } +type ClientConfigLoader interface { + ConfigAccess + Load() (*clientcmdapi.Config, error) +} + +type KubeconfigGetter func() (*clientcmdapi.Config, error) + +type ClientConfigGetter struct { + kubeconfigGetter KubeconfigGetter +} + +// ClientConfigGetter implements the ClientConfigLoader interface. +var _ ClientConfigLoader = &ClientConfigGetter{} + +func (g *ClientConfigGetter) Load() (*clientcmdapi.Config, error) { + return g.kubeconfigGetter() +} + +func (g *ClientConfigGetter) GetLoadingPrecedence() []string { + return nil +} +func (g *ClientConfigGetter) GetStartingConfig() (*clientcmdapi.Config, error) { + return nil, nil +} +func (g *ClientConfigGetter) GetDefaultFilename() string { + return "" +} +func (g *ClientConfigGetter) IsExplicitFile() bool { + return false +} +func (g *ClientConfigGetter) GetExplicitFile() string { + return "" +} + // ClientConfigLoadingRules is an ExplicitPath and string slice of specific locations that are used for merging together a Config // Callers can put the chain together however they want, but we'd recommend: // EnvVarPathFiles if set (a list of files if set) OR the HomeDirectoryPath @@ -80,6 +114,9 @@ type ClientConfigLoadingRules struct { DoNotResolvePaths bool } +// ClientConfigLoadingRules implements the ClientConfigLoader interface. +var _ ClientConfigLoader = &ClientConfigLoadingRules{} + // NewDefaultClientConfigLoadingRules returns a ClientConfigLoadingRules object with default fields filled in. You are not required to // use this constructor func NewDefaultClientConfigLoadingRules() *ClientConfigLoadingRules { diff --git a/pkg/client/unversioned/clientcmd/merged_client_builder.go b/pkg/client/unversioned/clientcmd/merged_client_builder.go index 57fb2e20f39..52c1493d056 100644 --- a/pkg/client/unversioned/clientcmd/merged_client_builder.go +++ b/pkg/client/unversioned/clientcmd/merged_client_builder.go @@ -27,13 +27,13 @@ import ( clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" ) -// DeferredLoadingClientConfig is a ClientConfig interface that is backed by a set of loading rules +// DeferredLoadingClientConfig is a ClientConfig interface that is backed by a client config loader. // It is used in cases where the loading rules may change after you've instantiated them and you want to be sure that // the most recent rules are used. This is useful in cases where you bind flags to loading rule parameters before // the parse happens and you want your calling code to be ignorant of how the values are being mutated to avoid // passing extraneous information down a call stack type DeferredLoadingClientConfig struct { - loadingRules *ClientConfigLoadingRules + loader ClientConfigLoader overrides *ConfigOverrides fallbackReader io.Reader @@ -42,13 +42,13 @@ type DeferredLoadingClientConfig struct { } // NewNonInteractiveDeferredLoadingClientConfig creates a ConfigClientClientConfig using the passed context name -func NewNonInteractiveDeferredLoadingClientConfig(loadingRules *ClientConfigLoadingRules, overrides *ConfigOverrides) ClientConfig { - return &DeferredLoadingClientConfig{loadingRules: loadingRules, overrides: overrides} +func NewNonInteractiveDeferredLoadingClientConfig(loader ClientConfigLoader, overrides *ConfigOverrides) ClientConfig { + return &DeferredLoadingClientConfig{loader: loader, overrides: overrides} } // NewInteractiveDeferredLoadingClientConfig creates a ConfigClientClientConfig using the passed context name and the fallback auth reader -func NewInteractiveDeferredLoadingClientConfig(loadingRules *ClientConfigLoadingRules, overrides *ConfigOverrides, fallbackReader io.Reader) ClientConfig { - return &DeferredLoadingClientConfig{loadingRules: loadingRules, overrides: overrides, fallbackReader: fallbackReader} +func NewInteractiveDeferredLoadingClientConfig(loader ClientConfigLoader, overrides *ConfigOverrides, fallbackReader io.Reader) ClientConfig { + return &DeferredLoadingClientConfig{loader: loader, overrides: overrides, fallbackReader: fallbackReader} } func (config *DeferredLoadingClientConfig) createClientConfig() (ClientConfig, error) { @@ -57,16 +57,16 @@ func (config *DeferredLoadingClientConfig) createClientConfig() (ClientConfig, e defer config.loadingLock.Unlock() if config.clientConfig == nil { - mergedConfig, err := config.loadingRules.Load() + mergedConfig, err := config.loader.Load() if err != nil { return nil, err } var mergedClientConfig ClientConfig if config.fallbackReader != nil { - mergedClientConfig = NewInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.fallbackReader, config.loadingRules) + mergedClientConfig = NewInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.fallbackReader, config.loader) } else { - mergedClientConfig = NewNonInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.loadingRules) + mergedClientConfig = NewNonInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.loader) } config.clientConfig = mergedClientConfig @@ -118,5 +118,5 @@ func (config *DeferredLoadingClientConfig) Namespace() (string, bool, error) { // ConfigAccess implements ClientConfig func (config *DeferredLoadingClientConfig) ConfigAccess() ConfigAccess { - return config.loadingRules + return config.loader }