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, errors.NewAggregate(errlist) }
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.Version(), 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 TestBasicAuthData(t *testing.T) { username := "******" password := "******" config := clientcmdapi.NewConfig() config.Clusters["clean"] = &clientcmdapi.Cluster{ Server: "https://localhost:8443", APIVersion: testapi.Default.Version(), } 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 TestValidateEmptyConfig(t *testing.T) { config := clientcmdapi.NewConfig() test := configValidationTest{ config: config, } test.testConfig(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 TestConfirmUsableMissingConfig(t *testing.T) { config := clientcmdapi.NewConfig() test := configValidationTest{ config: config, expectedErrorSubstring: []string{"context was not found for"}, } test.testConfirmUsable("not-here", t) }
func TestConfirmUsableEmptyConfig(t *testing.T) { config := clientcmdapi.NewConfig() test := configValidationTest{ config: config, expectedErrorSubstring: []string{"no context chosen"}, } test.testConfirmUsable("", t) }
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 TestValidateEmptyClusterInfo(t *testing.T) { config := clientcmdapi.NewConfig() config.Clusters["empty"] = &clientcmdapi.Cluster{} test := configValidationTest{ config: config, expectedErrorSubstring: []string{"no server found for"}, } 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 } if err := clientcmdlatest.Codec.DecodeInto(data, config); err != nil { return nil, err } return 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 := clientcmd.LoadFromFile(filename) if err != nil && !os.IsNotExist(err) { glog.FatalDepth(1, err) } if config == nil { return clientcmdapi.NewConfig() } return config }
func TestValidateCleanClusterInfo(t *testing.T) { config := clientcmdapi.NewConfig() config.Clusters["clean"] = &clientcmdapi.Cluster{ Server: "anything", } test := configValidationTest{ config: config, } test.testCluster("clean", t) test.testConfig(t) }
func TestValidateCleanTokenAuthInfo(t *testing.T) { config := clientcmdapi.NewConfig() config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ Token: "any-value", } test := configValidationTest{ config: config, } test.testAuthInfo("clean", t) test.testConfig(t) }
func TestValidateEmptyContext(t *testing.T) { config := clientcmdapi.NewConfig() config.CurrentContext = "anything" config.Contexts["anything"] = &clientcmdapi.Context{} test := configValidationTest{ config: config, expectedErrorSubstring: []string{"user was not specified for context \"anything\"", "cluster was not specified for context \"anything\""}, } test.testContext("anything", t) test.testConfig(t) }
func TestValidateMissingReferencesConfig(t *testing.T) { config := clientcmdapi.NewConfig() config.CurrentContext = "anything" config.Contexts["anything"] = &clientcmdapi.Context{Cluster: "missing", AuthInfo: "missing"} test := configValidationTest{ config: config, expectedErrorSubstring: []string{"user \"missing\" was not found for context \"anything\"", "cluster \"missing\" was not found for context \"anything\""}, } test.testContext("anything", t) test.testConfig(t) }
func TestIsContextNotFound(t *testing.T) { config := clientcmdapi.NewConfig() config.CurrentContext = "anything" err := Validate(*config) if !IsContextNotFound(err) { t.Errorf("Expected context not found, but got %v", err) } if !IsConfigurationInvalid(err) { t.Errorf("Expected configuration invalid, but got %v", err) } }
func TestValidateCertFilesNotFoundAuthInfo(t *testing.T) { config := clientcmdapi.NewConfig() config.AuthInfos["error"] = &clientcmdapi.AuthInfo{ ClientCertificate: "missing", ClientKey: "missing", } test := configValidationTest{ config: config, expectedErrorSubstring: []string{"unable to read client-cert", "unable to read client-key"}, } test.testAuthInfo("error", t) test.testConfig(t) }
func TestValidateMissingCAFileClusterInfo(t *testing.T) { config := clientcmdapi.NewConfig() config.Clusters["missing ca"] = &clientcmdapi.Cluster{ Server: "anything", CertificateAuthority: "missing", } test := configValidationTest{ config: config, expectedErrorSubstring: []string{"unable to read certificate-authority"}, } test.testCluster("missing ca", t) test.testConfig(t) }
func TestValidateMultipleMethodsAuthInfo(t *testing.T) { config := clientcmdapi.NewConfig() config.AuthInfos["error"] = &clientcmdapi.AuthInfo{ Token: "token", Username: "******", } test := configValidationTest{ config: config, expectedErrorSubstring: []string{"more than one authentication method", "token", "basicAuth"}, } test.testAuthInfo("error", t) test.testConfig(t) }
func (o *PathOptions) GetStartingConfig() (*clientcmdapi.Config, error) { // don't mutate the original loadingRules := *o.LoadingRules loadingRules.Precedence = o.GetLoadingPrecedence() clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(&loadingRules, &clientcmd.ConfigOverrides{}) rawConfig, err := clientConfig.RawConfig() if os.IsNotExist(err) { return clientcmdapi.NewConfig(), nil } if err != nil { return nil, err } return &rawConfig, nil }
func TestValidateCleanWithCAClusterInfo(t *testing.T) { tempFile, _ := ioutil.TempFile("", "") defer os.Remove(tempFile.Name()) config := clientcmdapi.NewConfig() config.Clusters["clean"] = &clientcmdapi.Cluster{ Server: "anything", CertificateAuthority: tempFile.Name(), } test := configValidationTest{ config: config, } test.testCluster("clean", t) test.testConfig(t) }
func TestValidateCleanCertFilesAuthInfo(t *testing.T) { tempFile, _ := ioutil.TempFile("", "") defer os.Remove(tempFile.Name()) config := clientcmdapi.NewConfig() config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ ClientCertificate: tempFile.Name(), ClientKey: tempFile.Name(), } test := configValidationTest{ config: config, } test.testAuthInfo("clean", t) test.testConfig(t) }
func TestKubectlValidation(t *testing.T) { testCases := []struct { data string err bool }{ {`{"apiVersion": "v1", "kind": "thisObjectShouldNotExistInAnyGroup"}`, true}, {`{"apiVersion": "invalidVersion", "kind": "Pod"}`, true}, {`{"apiVersion": "v1", "kind": "Pod"}`, false}, // The following test the experimental api. // TOOD: Replace with something more robust. These may move. {`{"apiVersion": "extensions/v1beta1", "kind": "Ingress"}`, false}, {`{"apiVersion": "extensions/v1beta1", "kind": "Job"}`, false}, {`{"apiVersion": "vNotAVersion", "kind": "Job"}`, true}, } components := framework.NewMasterComponents(&framework.Config{}) defer components.Stop(true, true) ctx := clientcmdapi.NewContext() cfg := clientcmdapi.NewConfig() cluster := clientcmdapi.NewCluster() cluster.Server = components.ApiServer.URL cluster.InsecureSkipTLSVerify = true overrides := clientcmd.ConfigOverrides{ ClusterInfo: *cluster, Context: *ctx, CurrentContext: "test", } cmdConfig := clientcmd.NewNonInteractiveClientConfig(*cfg, "test", &overrides) factory := util.NewFactory(cmdConfig) schema, err := factory.Validator(true, "") if err != nil { t.Errorf("failed to get validator: %v", err) return } for i, test := range testCases { err := schema.ValidateBytes([]byte(test.data)) if err == nil { if test.err { t.Errorf("case %d: expected error", i) } } else { if !test.err { t.Errorf("case %d: unexpected error: %v", i, err) } } } }
func TestValidateCertDataOverridesFiles(t *testing.T) { tempFile, _ := ioutil.TempFile("", "") defer os.Remove(tempFile.Name()) config := clientcmdapi.NewConfig() config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ ClientCertificate: tempFile.Name(), ClientCertificateData: []byte("certdata"), ClientKey: tempFile.Name(), ClientKeyData: []byte("keydata"), } test := configValidationTest{ config: config, expectedErrorSubstring: []string{"client-cert-data and client-cert are both specified", "client-key-data and client-key are both specified"}, } test.testAuthInfo("clean", t) test.testConfig(t) }
func TestConfirmUsableBadInfoConfig(t *testing.T) { config := clientcmdapi.NewConfig() config.Clusters["missing ca"] = &clientcmdapi.Cluster{ Server: "anything", CertificateAuthority: "missing", } config.AuthInfos["error"] = &clientcmdapi.AuthInfo{ Username: "******", Token: "here", } config.Contexts["first"] = &clientcmdapi.Context{ Cluster: "missing ca", AuthInfo: "error", } test := configValidationTest{ config: config, expectedErrorSubstring: []string{"unable to read certificate-authority"}, } test.testConfirmUsable("first", t) }
func createValidTestConfig() *clientcmdapi.Config { const ( server = "https://anything.com:8080" token = "the-token" ) config := clientcmdapi.NewConfig() config.Clusters["clean"] = &clientcmdapi.Cluster{ Server: server, APIVersion: testapi.Default.Version(), } config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ Token: token, } config.Contexts["clean"] = &clientcmdapi.Context{ Cluster: "clean", AuthInfo: "clean", } config.CurrentContext = "clean" return config }