func TestNewEmptyContext(t *testing.T) { expectedConfig := *clientcmdapi.NewConfig() expectedConfig.Contexts["new-context"] = clientcmdapi.NewContext() test := configCommandTest{ args: []string{"set-context", "new-context"}, startingConfig: *clientcmdapi.NewConfig(), expectedConfig: expectedConfig, } test.run(t) }
func TestNewEmptyAuth(t *testing.T) { expectedConfig := *clientcmdapi.NewConfig() expectedConfig.AuthInfos["the-user-name"] = clientcmdapi.NewAuthInfo() test := configCommandTest{ args: []string{"set-credentials", "the-user-name"}, startingConfig: *clientcmdapi.NewConfig(), expectedConfig: expectedConfig, } test.run(t) }
func TestSetIntoNewConfig(t *testing.T) { expectedConfig := *clientcmdapi.NewConfig() context := clientcmdapi.NewContext() context.AuthInfo = "fake-user" expectedConfig.Contexts["new-context"] = context test := configCommandTest{ args: []string{"set", "contexts.new-context.user", "fake-user"}, startingConfig: *clientcmdapi.NewConfig(), expectedConfig: expectedConfig, } test.run(t) }
// Load starts by running the MigrationRules and then // takes the loading rules and returns a Config object based on following rules. // if the ExplicitPath, return the unmerged explicit file // Otherwise, return a merged config based on the Precedence slice // A missing ExplicitPath file produces an error. Empty filenames or other missing files are ignored. // Read errors or files with non-deserializable content produce errors. // The first file to set a particular map key wins and map key's value is never changed. // BUT, if you set a struct value that is NOT contained inside of map, the value WILL be changed. // This results in some odd looking logic to merge in one direction, merge in the other, and then merge the two. // It also means that if two files specify a "red-user", only values from the first file's red-user are used. Even // non-conflicting entries from the second file's "red-user" are discarded. // Relative paths inside of the .kubeconfig files are resolved against the .kubeconfig file's parent folder // and only absolute file paths are returned. func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) { if err := rules.Migrate(); err != nil { return nil, err } errlist := []error{} kubeConfigFiles := []string{} // Make sure a file we were explicitly told to use exists if len(rules.ExplicitPath) > 0 { if _, err := os.Stat(rules.ExplicitPath); os.IsNotExist(err) { return nil, err } kubeConfigFiles = append(kubeConfigFiles, rules.ExplicitPath) } else { kubeConfigFiles = append(kubeConfigFiles, rules.Precedence...) } // first merge all of our maps mapConfig := clientcmdapi.NewConfig() for _, file := range kubeConfigFiles { if err := mergeConfigWithFile(mapConfig, file); err != nil { errlist = append(errlist, err) } } // merge all of the struct values in the reverse order so that priority is given correctly // errors are not added to the list the second time nonMapConfig := clientcmdapi.NewConfig() for i := len(kubeConfigFiles) - 1; i >= 0; i-- { file := kubeConfigFiles[i] mergeConfigWithFile(nonMapConfig, file) } // since values are overwritten, but maps values are not, we can merge the non-map config on top of the map config and // get the values we expect. config := clientcmdapi.NewConfig() mergo.Merge(config, mapConfig) mergo.Merge(config, nonMapConfig) if rules.ResolvePaths() { if err := ResolveLocalPaths(config); err != nil { errlist = append(errlist, err) } } return config, utilerrors.NewAggregate(errlist) }
func TestBasicTokenFile(t *testing.T) { token := "exampletoken" f, err := ioutil.TempFile("", "tokenfile") if err != nil { t.Errorf("Unexpected error: %v", err) return } defer os.Remove(f.Name()) if err := ioutil.WriteFile(f.Name(), []byte(token), 0644); err != nil { t.Errorf("Unexpected error: %v", err) return } config := clientcmdapi.NewConfig() config.Clusters["clean"] = &clientcmdapi.Cluster{ Server: "https://localhost:8443", } config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ TokenFile: f.Name(), } config.Contexts["clean"] = &clientcmdapi.Context{ Cluster: "clean", AuthInfo: "clean", } config.CurrentContext = "clean" clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{}, nil) clientConfig, err := clientBuilder.ClientConfig() if err != nil { t.Fatalf("Unexpected error: %v", err) } matchStringArg(token, clientConfig.BearerToken, t) }
// ReadConfigOrNew retrieves Kubernetes client configuration from a file. // If no files exists, an empty configuration is returned. func ReadConfigOrNew(filename string) (*api.Config, error) { data, err := ioutil.ReadFile(filename) if os.IsNotExist(err) { return api.NewConfig(), nil } else if err != nil { return nil, errors.Wrapf(err, "Error reading file", filename) } // decode config, empty if no bytes config, err := decode(data) if err != nil { return nil, errors.Errorf("could not read config: %v", err) } // initialize nil maps if config.AuthInfos == nil { config.AuthInfos = map[string]*api.AuthInfo{} } if config.Clusters == nil { config.Clusters = map[string]*api.Cluster{} } if config.Contexts == nil { config.Contexts = map[string]*api.Context{} } return config, nil }
func TestBasicAuthData(t *testing.T) { username := "******" password := "******" config := clientcmdapi.NewConfig() config.Clusters["clean"] = &clientcmdapi.Cluster{ Server: "https://localhost:8443", APIVersion: testapi.Default.GroupVersion().String(), } config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ Username: username, Password: password, } config.Contexts["clean"] = &clientcmdapi.Context{ Cluster: "clean", AuthInfo: "clean", } config.CurrentContext = "clean" clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{}) clientConfig, err := clientBuilder.ClientConfig() if err != nil { t.Fatalf("Unexpected error: %v", err) } // Make sure basic auth data gets into config matchStringArg(username, clientConfig.Username, t) matchStringArg(password, clientConfig.Password, t) }
func (k8scc *K8sClientConfig) UnversionedClient() *unversioned.Client { config := clientcmdapi.NewConfig() config.Clusters[k8scc.ClusterID] = &clientcmdapi.Cluster{ InsecureSkipTLSVerify: k8scc.InsecureSkipTLSVerify, Server: k8scc.Server, CertificateAuthority: k8scc.CertificateAuthority, CertificateAuthorityData: k8scc.CertificateAuthorityData, } config.AuthInfos[k8scc.ClusterID] = &clientcmdapi.AuthInfo{ ClientCertificate: k8scc.ClientCertificate, ClientKey: k8scc.ClientKey, ClientCertificateData: k8scc.ClientCertificateData, ClientKeyData: k8scc.ClientKeyData, } config.Contexts[k8scc.ClusterID] = &clientcmdapi.Context{ Cluster: k8scc.ClusterID, AuthInfo: k8scc.ClusterID, } config.CurrentContext = k8scc.ClusterID clientBuilder := clientcmd.NewNonInteractiveClientConfig(*config, k8scc.ClusterID, &clientcmd.ConfigOverrides{}) clientConfig, err := clientBuilder.ClientConfig() if err != nil { log.Fatalf("Unexpected error: %v", err) } client, err := unversioned.New(clientConfig) if err != nil { log.Fatalf("Unexpected error: %v", err) } return client }
func TestCertificateData(t *testing.T) { caData := []byte("ca-data") certData := []byte("cert-data") keyData := []byte("key-data") config := clientcmdapi.NewConfig() config.Clusters["clean"] = &clientcmdapi.Cluster{ Server: "https://localhost:8443", APIVersion: testapi.Default.GroupVersion().String(), CertificateAuthorityData: caData, } config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ ClientCertificateData: certData, ClientKeyData: keyData, } config.Contexts["clean"] = &clientcmdapi.Context{ Cluster: "clean", AuthInfo: "clean", } config.CurrentContext = "clean" clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{}) clientConfig, err := clientBuilder.ClientConfig() if err != nil { t.Fatalf("Unexpected error: %v", err) } // Make sure cert data gets into config (will override file paths) matchByteArg(caData, clientConfig.TLSClientConfig.CAData, t) matchByteArg(certData, clientConfig.TLSClientConfig.CertData, t) matchByteArg(keyData, clientConfig.TLSClientConfig.KeyData, t) }
func TestNewConfig(t *testing.T) { dir, err := ioutil.TempDir("", ".kube") if err != nil { t.Fatal(err) } defer os.RemoveAll(dir) // setup minikube config expected := api.NewConfig() minikubeConfig(expected) // write actual filename := filepath.Join(dir, "config") err = WriteConfig(expected, filename) if err != nil { t.Fatal(err) } actual, err := ReadConfigOrNew(filename) if err != nil { t.Fatal(err) } if !configEquals(actual, expected) { t.Fatal("configs did not match") } }
// Login logs into the specified server using given credentials and CA file func Login(username, password, server, configDir string, f *clientcmd.Factory, c *cobra.Command, out io.Writer) error { existingConfig, err := f.OpenShiftClientConfig.RawConfig() if err != nil { if !os.IsNotExist(err) { return err } existingConfig = *(kclientcmdapi.NewConfig()) } adminConfig, err := kclientcmd.LoadFromFile(filepath.Join(configDir, "master", "admin.kubeconfig")) if err != nil { return err } for k := range adminConfig.AuthInfos { adminConfig.AuthInfos[k].LocationOfOrigin = "" } newConfig, err := config.MergeConfig(existingConfig, *adminConfig) if err != nil { return err } output := ioutil.Discard if glog.V(1) { output = out } opts := &cmd.LoginOptions{ Server: server, Username: username, Password: password, Out: output, StartingKubeConfig: newConfig, PathOptions: config.NewPathOptions(c), } return cmd.RunLogin(nil, opts) }
func TestValidateEmptyConfig(t *testing.T) { config := clientcmdapi.NewConfig() test := configValidationTest{ config: config, } test.testConfig(t) }
func TestCurrentContextWithUnsetContext(t *testing.T) { test := currentContextTest{ startingConfig: *clientcmdapi.NewConfig(), expectedError: "current-context is not set", } test.run(t) }
func TestNewFactoryNoFlagBindings(t *testing.T) { clientConfig := clientcmd.NewDefaultClientConfig(*clientcmdapi.NewConfig(), &clientcmd.ConfigOverrides{}) factory := NewFactory(clientConfig) if factory.flags.HasFlags() { t.Errorf("Expected zero flags, but got %v", factory.flags) } }
func (o *LoginOptions) Complete(f *osclientcmd.Factory, cmd *cobra.Command, args []string) error { kubeconfig, err := f.OpenShiftClientConfig.RawConfig() o.StartingKubeConfig = &kubeconfig if err != nil { if !os.IsNotExist(err) { return err } // build a valid object to use if we failed on a non-existent file o.StartingKubeConfig = kclientcmdapi.NewConfig() } addr := flagtypes.Addr{Value: "localhost:8443", DefaultScheme: "https", DefaultPort: 8443, AllowPrefix: true}.Default() if serverFlag := kcmdutil.GetFlagString(cmd, "server"); len(serverFlag) > 0 { if err := addr.Set(serverFlag); err != nil { return err } o.Server = addr.String() } else if len(args) == 1 { if err := addr.Set(args[0]); err != nil { return err } o.Server = addr.String() } else if len(o.Server) == 0 { if defaultContext, defaultContextExists := o.StartingKubeConfig.Contexts[o.StartingKubeConfig.CurrentContext]; defaultContextExists { if cluster, exists := o.StartingKubeConfig.Clusters[defaultContext.Cluster]; exists { o.Server = cluster.Server } } } o.CertFile = kcmdutil.GetFlagString(cmd, "client-certificate") o.KeyFile = kcmdutil.GetFlagString(cmd, "client-key") o.APIVersion = kcmdutil.GetFlagString(cmd, "api-version") // if the API version isn't explicitly passed, use the API version from the default context (same rules as the server above) if len(o.APIVersion) == 0 { if defaultContext, defaultContextExists := o.StartingKubeConfig.Contexts[o.StartingKubeConfig.CurrentContext]; defaultContextExists { if cluster, exists := o.StartingKubeConfig.Clusters[defaultContext.Cluster]; exists { o.APIVersion = cluster.APIVersion } } } o.CAFile = kcmdutil.GetFlagString(cmd, "certificate-authority") o.InsecureTLS = kcmdutil.GetFlagBool(cmd, "insecure-skip-tls-verify") o.Token = kcmdutil.GetFlagString(cmd, "token") o.DefaultNamespace, _, _ = f.OpenShiftClientConfig.Namespace() o.PathOptions = config.NewPathOptions(cmd) return nil }
func TestConfirmUsableEmptyConfig(t *testing.T) { config := clientcmdapi.NewConfig() test := configValidationTest{ config: config, expectedErrorSubstring: []string{"no context chosen"}, } test.testConfirmUsable("", t) }
func TestConfirmUsableMissingConfig(t *testing.T) { config := clientcmdapi.NewConfig() test := configValidationTest{ config: config, expectedErrorSubstring: []string{"context was not found for"}, } test.testConfirmUsable("not-here", t) }
func TestValidateEmptyConfig(t *testing.T) { config := clientcmdapi.NewConfig() test := configValidationTest{ config: config, expectedErrorSubstring: []string{"invalid configuration: no configuration has been provided"}, } test.testConfig(t) }
func TestConfirmUsableMissingConfig(t *testing.T) { config := clientcmdapi.NewConfig() test := configValidationTest{ config: config, expectedErrorSubstring: []string{"invalid configuration: no configuration has been provided"}, } test.testConfirmUsable("not-here", t) }
func TestGetContextsAllNone(t *testing.T) { test := getContextsTest{ startingConfig: *clientcmdapi.NewConfig(), names: []string{}, noHeader: true, nameOnly: false, expectedOut: "", } test.run(t) }
// getConfigFromFile tries to read a kubeconfig file and if it can't, returns an error. One exception, missing files result in empty configs, not an error. func getConfigFromFile(filename string) (*clientcmdapi.Config, error) { config, err := LoadFromFile(filename) if err != nil && !os.IsNotExist(err) { return nil, err } if config == nil { config = clientcmdapi.NewConfig() } return config, nil }
func CreateBasicClientConfig(clusterName string, serverURL string, caCert []byte) *clientcmdapi.Config { cluster := clientcmdapi.NewCluster() cluster.Server = serverURL cluster.CertificateAuthorityData = caCert config := clientcmdapi.NewConfig() config.Clusters[clusterName] = cluster return config }
func TestValidateMissingCurrentContextConfig(t *testing.T) { config := clientcmdapi.NewConfig() config.CurrentContext = "anything" test := configValidationTest{ config: config, expectedErrorSubstring: []string{"context was not found for specified "}, } test.testConfig(t) }
func TestValidateEmptyAuthInfo(t *testing.T) { config := clientcmdapi.NewConfig() config.AuthInfos["error"] = &clientcmdapi.AuthInfo{} test := configValidationTest{ config: config, } test.testAuthInfo("error", t) test.testConfig(t) }
func TestIsEmptyConfig(t *testing.T) { config := clientcmdapi.NewConfig() err := Validate(*config) if !IsEmptyConfig(err) { t.Errorf("Expected context not found, but got %v", err) } if !IsConfigurationInvalid(err) { t.Errorf("Expected configuration invalid, but got %v", err) } }
func TestValidateEmptyClusterInfo(t *testing.T) { config := clientcmdapi.NewConfig() config.Clusters["empty"] = &clientcmdapi.Cluster{} test := configValidationTest{ config: config, expectedErrorSubstring: []string{"cluster has no server defined"}, } test.testCluster("empty", t) test.testConfig(t) }
// Load takes a byte slice and deserializes the contents into Config object. // Encapsulates deserialization without assuming the source is a file. func Load(data []byte) (*clientcmdapi.Config, error) { config := clientcmdapi.NewConfig() // if there's no data in a file, return the default object instead of failing (DecodeInto reject empty input) if len(data) == 0 { return config, nil } decoded, _, err := clientcmdlatest.Codec.Decode(data, &unversioned.GroupVersionKind{Version: clientcmdlatest.Version, Kind: "Config"}, config) if err != nil { return nil, err } return decoded.(*clientcmdapi.Config), nil }
// GetConfigFromFileOrDie tries to read a kubeconfig file and if it can't, it calls exit. One exception, missing files result in empty configs, not an exit func GetConfigFromFileOrDie(filename string) *clientcmdapi.Config { config, err := LoadFromFile(filename) if err != nil && !os.IsNotExist(err) { glog.FatalDepth(1, err) } if config == nil { return clientcmdapi.NewConfig() } return config }
// GetStartingConfig implements ConfigAccess func (rules *ClientConfigLoadingRules) GetStartingConfig() (*clientcmdapi.Config, error) { clientConfig := NewNonInteractiveDeferredLoadingClientConfig(rules, &ConfigOverrides{}) rawConfig, err := clientConfig.RawConfig() if os.IsNotExist(err) { return clientcmdapi.NewConfig(), nil } if err != nil { return nil, err } return &rawConfig, nil }
// Load takes a byte slice and deserializes the contents into Config object. // Encapsulates deserialization without assuming the source is a file. func Load(data []byte) (*clientcmdapi.Config, error) { config := clientcmdapi.NewConfig() // if there's no data in a file, return the default object instead of failing (DecodeInto reject empty input) if len(data) == 0 { return config, nil } if err := clientcmdlatest.Codec.DecodeInto(data, config); err != nil { return nil, err } return config, nil }