Skip to content

Commit

Permalink
move main client configuration to pkg/client/config
Browse files Browse the repository at this point in the history
  • Loading branch information
juanvallejo committed Nov 30, 2017
1 parent 41e9a84 commit 14a5503
Show file tree
Hide file tree
Showing 14 changed files with 294 additions and 81 deletions.
231 changes: 218 additions & 13 deletions pkg/client/cmd/clientcmd.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,229 @@
package clientconfig
package cmd

import (
"k8s.io/kubernetes/pkg/api"
"fmt"
"io/ioutil"
"os"
"strings"

"github.com/golang/glog"
"github.com/spf13/cobra"
"github.com/spf13/pflag"

restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
kclientcmd "k8s.io/client-go/tools/clientcmd"
kclientcmdapi "k8s.io/client-go/tools/clientcmd/api"

kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"

"github.com/openshift/origin/pkg/client/config"
"github.com/openshift/origin/pkg/cmd/flagtypes"
"github.com/openshift/origin/pkg/cmd/util"
)

func EnvVars(host string, caData []byte, insecure bool, bearerTokenFile string) []api.EnvVar {
envvars := []api.EnvVar{
{Name: "KUBERNETES_MASTER", Value: host},
{Name: "OPENSHIFT_MASTER", Value: host},
const ConfigSyntax = " --master=<addr>"

// Config contains all the necessary bits for client configuration
type Config struct {
// MasterAddr is the address the master can be reached on (host, host:port, or URL).
MasterAddr flagtypes.Addr
// KubernetesAddr is the address of the Kubernetes server (host, host:port, or URL).
// If omitted defaults to the master.
KubernetesAddr flagtypes.Addr
// CommonConfig is the shared base config for both the OpenShift config and Kubernetes config
CommonConfig restclient.Config
// Namespace is the namespace to act in
Namespace string

// If set, allow kubeconfig file loading
FromFile bool
// If true, no environment is loaded (for testing, primarily)
SkipEnv bool
clientConfig clientcmd.ClientConfig
}

// NewConfig returns a new configuration
func NewConfig() *Config {
return &Config{
MasterAddr: flagtypes.Addr{Value: "localhost:8080", DefaultScheme: "http", DefaultPort: 8080, AllowPrefix: true}.Default(),
KubernetesAddr: flagtypes.Addr{Value: "localhost:8080", DefaultScheme: "http", DefaultPort: 8080}.Default(),
CommonConfig: restclient.Config{},
}
}

// Bind binds configuration values to the passed flagset
func (cfg *Config) Bind(flags *pflag.FlagSet) {
flags.Var(&cfg.MasterAddr, "master", "The address the master can be reached on (host, host:port, or URL).")
flags.Var(&cfg.KubernetesAddr, "kubernetes", "The address of the Kubernetes server (host, host:port, or URL). If omitted defaults to the master.")

if cfg.FromFile {
cfg.clientConfig = DefaultClientConfig(flags)
} else {
BindClientConfigSecurityFlags(&cfg.CommonConfig, flags)
}
}

// BindToFile is used when this config will not be bound to flags, but should load the config file
// from disk if available.
func (cfg *Config) BindToFile() *Config {
cfg.clientConfig = DefaultClientConfig(pflag.NewFlagSet("empty", pflag.ContinueOnError))
return cfg
}

// OpenShiftConfig returns the OpenShift configuration
func (cfg *Config) OpenShiftConfig() *restclient.Config {
err := cfg.bindEnv()
if err != nil {
glog.Error(err)
}

osConfig := cfg.CommonConfig
if len(osConfig.Host) == 0 || cfg.MasterAddr.Provided {
osConfig.Host = cfg.MasterAddr.String()
}

return &osConfig
}

// Clients returns an OpenShift and a Kubernetes client from a given configuration
func (cfg *Config) Clients() (kclientset.Interface, error) {
cfg.bindEnv()

kubeClientset, err := kclientset.NewForConfig(cfg.KubeConfig())
if err != nil {
return nil, fmt.Errorf("Unable to configure Kubernetes client: %v", err)
}

return kubeClientset, nil
}

// BindClientConfigSecurityFlags adds flags for the supplied client config
func BindClientConfigSecurityFlags(config *restclient.Config, flags *pflag.FlagSet) {
flags.BoolVar(&config.Insecure, "insecure-skip-tls-verify", config.Insecure, "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.")
flags.StringVar(&config.CertFile, "client-certificate", config.CertFile, "Path to a client certificate file for TLS.")
flags.StringVar(&config.KeyFile, "client-key", config.KeyFile, "Path to a client key file for TLS.")
flags.StringVar(&config.CAFile, "certificate-authority", config.CAFile, "Path to a cert. file for the certificate authority")
flags.StringVar(&config.BearerToken, "token", config.BearerToken, "If present, the bearer token for this request.")
}

// KubeConfig returns the Kubernetes configuration
func (cfg *Config) KubeConfig() *restclient.Config {
err := cfg.bindEnv()
if err != nil {
glog.Error(err)
}

kaddr := cfg.KubernetesAddr
if !kaddr.Provided {
kaddr = cfg.MasterAddr
}

kConfig := cfg.CommonConfig
kConfig.Host = kaddr.URL.String()

return &kConfig
}

func (cfg *Config) bindEnv() error {
// bypass loading from env
if cfg.SkipEnv {
return nil
}
var err error

// callers may not use the config file if they have specified a master directly, for backwards
// compatibility with components that used to use env, switch to service account token, and have
// config defined in env.
_, masterSet := util.GetEnv("OPENSHIFT_MASTER")
specifiedMaster := masterSet || cfg.MasterAddr.Provided

if cfg.clientConfig != nil && !specifiedMaster {
clientConfig, err := cfg.clientConfig.ClientConfig()
if err != nil {
return err
}
cfg.CommonConfig = *clientConfig
cfg.Namespace, _, err = cfg.clientConfig.Namespace()
if err != nil {
return err
}

if !cfg.MasterAddr.Provided {
cfg.MasterAddr.Set(cfg.CommonConfig.Host)
}
if !cfg.KubernetesAddr.Provided {
cfg.KubernetesAddr.Set(cfg.CommonConfig.Host)
}
return nil
}

// Legacy path - preserve env vars set on pods that previously were honored.
if value, ok := util.GetEnv("KUBERNETES_MASTER"); ok && !cfg.KubernetesAddr.Provided {
cfg.KubernetesAddr.Set(value)
}
if value, ok := util.GetEnv("OPENSHIFT_MASTER"); ok && !cfg.MasterAddr.Provided {
cfg.MasterAddr.Set(value)
}
if value, ok := util.GetEnv("BEARER_TOKEN"); ok && len(cfg.CommonConfig.BearerToken) == 0 {
cfg.CommonConfig.BearerToken = value
}
if value, ok := util.GetEnv("BEARER_TOKEN_FILE"); ok && len(cfg.CommonConfig.BearerToken) == 0 {
if tokenData, tokenErr := ioutil.ReadFile(value); tokenErr == nil {
cfg.CommonConfig.BearerToken = strings.TrimSpace(string(tokenData))
if len(cfg.CommonConfig.BearerToken) == 0 {
err = fmt.Errorf("BEARER_TOKEN_FILE %q was empty", value)
}
} else {
err = fmt.Errorf("Error reading BEARER_TOKEN_FILE %q: %v", value, tokenErr)
}
}

if value, ok := util.GetEnv("OPENSHIFT_CA_FILE"); ok && len(cfg.CommonConfig.CAFile) == 0 {
cfg.CommonConfig.CAFile = value
} else if value, ok := util.GetEnv("OPENSHIFT_CA_DATA"); ok && len(cfg.CommonConfig.CAData) == 0 {
cfg.CommonConfig.CAData = []byte(value)
}

if value, ok := util.GetEnv("OPENSHIFT_CERT_FILE"); ok && len(cfg.CommonConfig.CertFile) == 0 {
cfg.CommonConfig.CertFile = value
} else if value, ok := util.GetEnv("OPENSHIFT_CERT_DATA"); ok && len(cfg.CommonConfig.CertData) == 0 {
cfg.CommonConfig.CertData = []byte(value)
}

if len(bearerTokenFile) > 0 {
envvars = append(envvars, api.EnvVar{Name: "BEARER_TOKEN_FILE", Value: bearerTokenFile})
if value, ok := util.GetEnv("OPENSHIFT_KEY_FILE"); ok && len(cfg.CommonConfig.KeyFile) == 0 {
cfg.CommonConfig.KeyFile = value
} else if value, ok := util.GetEnv("OPENSHIFT_KEY_DATA"); ok && len(cfg.CommonConfig.KeyData) == 0 {
cfg.CommonConfig.KeyData = []byte(value)
}

if len(caData) > 0 {
envvars = append(envvars, api.EnvVar{Name: "OPENSHIFT_CA_DATA", Value: string(caData)})
} else if insecure {
envvars = append(envvars, api.EnvVar{Name: "OPENSHIFT_INSECURE", Value: "true"})
if value, ok := util.GetEnv("OPENSHIFT_INSECURE"); ok && len(value) != 0 {
cfg.CommonConfig.Insecure = value == "true"
}

return envvars
return err
}

func DefaultClientConfig(flags *pflag.FlagSet) kclientcmd.ClientConfig {
loadingRules := config.NewOpenShiftClientConfigLoadingRules()
flags.StringVar(&loadingRules.ExplicitPath, config.OpenShiftConfigFlagName, "", "Path to the config file to use for CLI requests.")
cobra.MarkFlagFilename(flags, config.OpenShiftConfigFlagName)

// set our explicit defaults
defaultOverrides := &kclientcmd.ConfigOverrides{ClusterDefaults: kclientcmdapi.Cluster{Server: os.Getenv("KUBERNETES_MASTER")}}
loadingRules.DefaultClientConfig = kclientcmd.NewDefaultClientConfig(kclientcmdapi.Config{}, defaultOverrides)

overrides := &kclientcmd.ConfigOverrides{ClusterDefaults: defaultOverrides.ClusterDefaults}
overrideFlags := kclientcmd.RecommendedConfigOverrideFlags("")
overrideFlags.ContextOverrideFlags.Namespace.ShortName = "n"
overrideFlags.AuthOverrideFlags.Username.LongName = ""
overrideFlags.AuthOverrideFlags.Password.LongName = ""
kclientcmd.BindOverrideFlags(overrides, flags, overrideFlags)
cobra.MarkFlagFilename(flags, overrideFlags.AuthOverrideFlags.ClientCertificate.LongName)
cobra.MarkFlagFilename(flags, overrideFlags.AuthOverrideFlags.ClientKey.LongName)
cobra.MarkFlagFilename(flags, overrideFlags.ClusterOverrideFlags.CertificateAuthority.LongName)

clientConfig := kclientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides)

return clientConfig
}
55 changes: 55 additions & 0 deletions pkg/client/config/loader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package config

import (
"os"
"path"
"path/filepath"
"runtime"

"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
)

const (
OpenShiftConfigPathEnvVar = "KUBECONFIG"
OpenShiftConfigFlagName = "config"
OpenShiftConfigHomeDir = ".kube"
OpenShiftConfigHomeFileName = "config"
OpenShiftConfigHomeDirFileName = OpenShiftConfigHomeDir + "/" + OpenShiftConfigHomeFileName
)

var RecommendedHomeFile = path.Join(homedir.HomeDir(), OpenShiftConfigHomeDirFileName)

// currentMigrationRules returns a map that holds the history of recommended home directories used in previous versions.
// Any future changes to RecommendedHomeFile and related are expected to add a migration rule here, in order to make
// sure existing config files are migrated to their new locations properly.
func CurrentMigrationRules() map[string]string {
oldRecommendedHomeFile := path.Join(homedir.HomeDir(), ".kube/.config")
oldRecommendedWindowsHomeFile := path.Join(os.Getenv("HOME"), OpenShiftConfigHomeDirFileName)

migrationRules := map[string]string{}
migrationRules[RecommendedHomeFile] = oldRecommendedHomeFile
if runtime.GOOS == "windows" {
migrationRules[RecommendedHomeFile] = oldRecommendedWindowsHomeFile
}
return migrationRules
}

// NewOpenShiftClientConfigLoadingRules returns file priority loading rules for OpenShift.
// 1. --config value
// 2. if KUBECONFIG env var has a value, use it. Otherwise, ~/.kube/config file
func NewOpenShiftClientConfigLoadingRules() *clientcmd.ClientConfigLoadingRules {
chain := []string{}

envVarFile := os.Getenv(OpenShiftConfigPathEnvVar)
if len(envVarFile) != 0 {
chain = append(chain, filepath.SplitList(envVarFile)...)
} else {
chain = append(chain, RecommendedHomeFile)
}

return &clientcmd.ClientConfigLoadingRules{
Precedence: chain,
MigrationRules: CurrentMigrationRules(),
}
}
1 change: 1 addition & 0 deletions pkg/cmd/infra/router/f5.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"

clientcmd "github.com/openshift/origin/pkg/client/cmd"
"github.com/openshift/origin/pkg/cmd/util"
cmdversion "github.com/openshift/origin/pkg/cmd/version"
"github.com/openshift/origin/pkg/oc/cli/util/clientcmd"
Expand Down
1 change: 1 addition & 0 deletions pkg/cmd/infra/router/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"

clientcmd "github.com/openshift/origin/pkg/client/cmd"
"github.com/openshift/origin/pkg/cmd/server/crypto"
"github.com/openshift/origin/pkg/cmd/util"
cmdversion "github.com/openshift/origin/pkg/cmd/version"
Expand Down
2 changes: 1 addition & 1 deletion pkg/oc/admin/diagnostics/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (

clientcmdapi "k8s.io/client-go/tools/clientcmd/api"

"github.com/openshift/origin/pkg/client/config"
clientdiagnostics "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/client"
"github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types"
"github.com/openshift/origin/pkg/oc/cli/config"
)

// determine if we even have a client config
Expand Down
2 changes: 1 addition & 1 deletion pkg/oc/admin/diagnostics/diagnostics.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ import (
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"

"github.com/openshift/origin/pkg/client/config"
"github.com/openshift/origin/pkg/cmd/flagtypes"
"github.com/openshift/origin/pkg/cmd/util/variable"
"github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/log"
netutil "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/networkpod/util"
"github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types"
"github.com/openshift/origin/pkg/oc/admin/diagnostics/options"
"github.com/openshift/origin/pkg/oc/cli/config"
osclientcmd "github.com/openshift/origin/pkg/oc/cli/util/clientcmd"
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import (
flag "github.com/spf13/pflag"
"k8s.io/client-go/tools/clientcmd"

"github.com/openshift/origin/pkg/client/config"
"github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types"
"github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/util"
"github.com/openshift/origin/pkg/oc/cli/config"
)

// ConfigLoading is a little special in that it is run separately as a precondition
Expand Down
2 changes: 1 addition & 1 deletion pkg/oc/admin/diagnostics/diagnostics/network/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ import (
kclientcmd "k8s.io/client-go/tools/clientcmd"
kapi "k8s.io/kubernetes/pkg/api"

"github.com/openshift/origin/pkg/client/config"
"github.com/openshift/origin/pkg/network"
networkapi "github.com/openshift/origin/pkg/network/apis/network"
"github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/networkpod/util"
diagutil "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/util"
"github.com/openshift/origin/pkg/oc/cli/config"
)

func (d *NetworkDiagnostic) TestSetup() error {
Expand Down
1 change: 1 addition & 0 deletions pkg/oc/admin/diagnostics/diagnostics/pod/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
knet "k8s.io/apimachinery/pkg/util/net"
restclient "k8s.io/client-go/rest"

clientcmd "github.com/openshift/origin/pkg/client/cmd"
"github.com/openshift/origin/pkg/cmd/flagtypes"
"github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types"
"github.com/openshift/origin/pkg/oc/cli/util/clientcmd"
Expand Down
4 changes: 2 additions & 2 deletions pkg/oc/bootstrap/docker/openshift/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
kapi "k8s.io/kubernetes/pkg/api"

defaultsapi "github.com/openshift/origin/pkg/build/controller/build/defaults/api"
clientconfig "github.com/openshift/origin/pkg/client/config"
"github.com/openshift/origin/pkg/cmd/server/admin"
configapi "github.com/openshift/origin/pkg/cmd/server/api"
_ "github.com/openshift/origin/pkg/cmd/server/api/install"
Expand All @@ -31,7 +32,6 @@ import (
dockerexec "github.com/openshift/origin/pkg/oc/bootstrap/docker/exec"
"github.com/openshift/origin/pkg/oc/bootstrap/docker/host"
"github.com/openshift/origin/pkg/oc/bootstrap/docker/run"
cliconfig "github.com/openshift/origin/pkg/oc/cli/config"
kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
)

Expand Down Expand Up @@ -74,7 +74,7 @@ var (
DefaultPorts = append(BasePorts, DefaultDNSPort)
PortsWithAlternateDNS = append(BasePorts, AlternateDNSPort)
AllPorts = append(append(RouterPorts, DefaultPorts...), AlternateDNSPort)
SocatPidFile = filepath.Join(homedir.HomeDir(), cliconfig.OpenShiftConfigHomeDir, "socat-8443.pid")
SocatPidFile = filepath.Join(homedir.HomeDir(), clientconfig.OpenShiftConfigHomeDir, "socat-8443.pid")
defaultCertHosts = []string{
"127.0.0.1",
"172.30.0.1",
Expand Down
Loading

0 comments on commit 14a5503

Please sign in to comment.