diff --git a/probe/kubernetes/client.go b/probe/kubernetes/client.go index c5112c991..b7193f5b7 100644 --- a/probe/kubernetes/client.go +++ b/probe/kubernetes/client.go @@ -12,6 +12,8 @@ import ( "k8s.io/kubernetes/pkg/client/cache" "k8s.io/kubernetes/pkg/client/restclient" "k8s.io/kubernetes/pkg/client/unversioned" + "k8s.io/kubernetes/pkg/client/unversioned/clientcmd" + clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" "k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/util/wait" @@ -62,35 +64,78 @@ func runReflectorUntil(r *cache.Reflector, resyncPeriod time.Duration, stopCh <- go wait.Until(loggingListAndWatch, resyncPeriod, stopCh) } +// ClientConfig establishes the configuration for the kubernetes client +type ClientConfig struct { + Interval time.Duration + CertificateAuthority string + ClientCertificate string + ClientKey string + Cluster string + Context string + Insecure bool + Kubeconfig string + Password string + Server string + Token string + User string + Username string +} + // NewClient returns a usable Client. Don't forget to Stop it. -func NewClient(addr string, resyncPeriod time.Duration) (Client, error) { - var config *restclient.Config - if addr != "" { - config = &restclient.Config{Host: addr} - } else { - // If no API server address was provided, assume we are running +func NewClient(config ClientConfig) (Client, error) { + var restConfig *restclient.Config + if config.Server == "" && config.Kubeconfig == "" { + // If no API server address or kubeconfig was provided, assume we are running // inside a pod. Try to connect to the API server through its // Service environment variables, using the default Service // Account Token. var err error - if config, err = restclient.InClusterConfig(); err != nil { + if restConfig, err = restclient.InClusterConfig(); err != nil { return nil, err } + } else { + var err error + restConfig, err = clientcmd.NewNonInteractiveDeferredLoadingClientConfig( + &clientcmd.ClientConfigLoadingRules{ExplicitPath: config.Kubeconfig}, + &clientcmd.ConfigOverrides{ + AuthInfo: clientcmdapi.AuthInfo{ + ClientCertificate: config.ClientCertificate, + ClientKey: config.ClientKey, + Token: config.Token, + Username: config.Username, + Password: config.Password, + }, + ClusterInfo: clientcmdapi.Cluster{ + Server: config.Server, + InsecureSkipTLSVerify: config.Insecure, + CertificateAuthority: config.CertificateAuthority, + }, + Context: clientcmdapi.Context{ + Cluster: config.Cluster, + AuthInfo: config.User, + }, + CurrentContext: config.Context, + }, + ).ClientConfig() + if err != nil { + return nil, err + } + } - c, err := unversioned.New(config) + c, err := unversioned.New(restConfig) if err != nil { return nil, err } - ec, err := unversioned.NewExtensions(config) + ec, err := unversioned.NewExtensions(restConfig) if err != nil { return nil, err } result := &client{ quit: make(chan struct{}), - resyncPeriod: resyncPeriod, + resyncPeriod: config.Interval, client: c, extensionsClient: ec, } diff --git a/prog/main.go b/prog/main.go index 9cc5c57d3..dc1a096c1 100644 --- a/prog/main.go +++ b/prog/main.go @@ -14,6 +14,7 @@ import ( "github.com/weaveworks/scope/app" "github.com/weaveworks/scope/common/xfer" + "github.com/weaveworks/scope/probe/kubernetes" "github.com/weaveworks/weave/common" ) @@ -86,9 +87,8 @@ type probeFlags struct { dockerInterval time.Duration dockerBridge string - kubernetesEnabled bool - kubernetesAPI string - kubernetesInterval time.Duration + kubernetesEnabled bool + kubernetesConfig kubernetes.ClientConfig weaveEnabled bool weaveAddr string @@ -200,8 +200,20 @@ func main() { // K8s flag.BoolVar(&flags.probe.kubernetesEnabled, "probe.kubernetes", false, "collect kubernetes-related attributes for containers, should only be enabled on the master node") - flag.StringVar(&flags.probe.kubernetesAPI, "probe.kubernetes.api", "", "Address of kubernetes master api") - flag.DurationVar(&flags.probe.kubernetesInterval, "probe.kubernetes.interval", 10*time.Second, "how often to do a full resync of the kubernetes data") + flag.DurationVar(&flags.probe.kubernetesConfig.Interval, "probe.kubernetes.interval", 10*time.Second, "how often to do a full resync of the kubernetes data") + flag.StringVar(&flags.probe.kubernetesConfig.Server, "probe.kubernetes.api", "", "The address and port of the Kubernetes API server (deprecated in favor of equivalent probe.kubernetes.server)") + flag.StringVar(&flags.probe.kubernetesConfig.CertificateAuthority, "probe.kubernetes.certificate-authority", "", "Path to a cert. file for the certificate authority") + flag.StringVar(&flags.probe.kubernetesConfig.ClientCertificate, "probe.kubernetes.client-certificate", "", "Path to a client certificate file for TLS") + flag.StringVar(&flags.probe.kubernetesConfig.ClientKey, "probe.kubernetes.client-key", "", "Path to a client key file for TLS") + flag.StringVar(&flags.probe.kubernetesConfig.Cluster, "probe.kubernetes.cluster", "", "The name of the kubeconfig cluster to use") + flag.StringVar(&flags.probe.kubernetesConfig.Context, "probe.kubernetes.context", "", "The name of the kubeconfig context to use") + flag.BoolVar(&flags.probe.kubernetesConfig.Insecure, "probe.kubernetes.insecure-skip-tls-verify", false, "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure") + flag.StringVar(&flags.probe.kubernetesConfig.Kubeconfig, "probe.kubernetes.kubecconfig", "", "Path to the kubeconfig file to use") + flag.StringVar(&flags.probe.kubernetesConfig.Password, "probe.kubernetes.password", "", "Password for basic authentication to the API server") + flag.StringVar(&flags.probe.kubernetesConfig.Server, "probe.kubernetes.server", "", "The address and port of the Kubernetes API server") + flag.StringVar(&flags.probe.kubernetesConfig.Token, "probe.kubernetes.token", "", "Bearer token for authentication to the API server") + flag.StringVar(&flags.probe.kubernetesConfig.User, "probe.kubernetes.user", "", "The name of the kubeconfig user to use") + flag.StringVar(&flags.probe.kubernetesConfig.Username, "probe.kubernetes.username", "", "Username for basic authentication to the API server") // Weave flag.StringVar(&flags.probe.weaveAddr, "probe.weave.addr", "127.0.0.1:6784", "IP address & port of the Weave router") diff --git a/prog/probe.go b/prog/probe.go index 01c030136..2cabc64aa 100644 --- a/prog/probe.go +++ b/prog/probe.go @@ -169,7 +169,7 @@ func probeMain(flags probeFlags) { } if flags.kubernetesEnabled { - if client, err := kubernetes.NewClient(flags.kubernetesAPI, flags.kubernetesInterval); err == nil { + if client, err := kubernetes.NewClient(flags.kubernetesConfig); err == nil { defer client.Stop() reporter := kubernetes.NewReporter(client, clients, probeID, hostID, p) defer reporter.Stop() @@ -177,7 +177,7 @@ func probeMain(flags probeFlags) { p.AddTagger(reporter) } else { log.Errorf("Kubernetes: failed to start client: %v", err) - log.Errorf("Kubernetes: make sure to run Scope inside a POD with a service account or provide a valid kubernetes.api url") + log.Errorf("Kubernetes: make sure to run Scope inside a POD with a service account or provide valid probe.kubernetes.* flags") } }