예제 #1
0
func TestBasicAuthData(t *testing.T) {
	username := "******"
	password := "******"

	config := clientcmdapi.NewConfig()
	config.Clusters["clean"] = &clientcmdapi.Cluster{
		Server: "https://localhost:8443",
	}
	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{}, nil)

	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)
}
예제 #2
0
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",
		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{}, nil)

	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)
}
예제 #3
0
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)
}
예제 #4
0
func TestValidateEmptyConfig(t *testing.T) {
	config := clientcmdapi.NewConfig()
	test := configValidationTest{
		config:                 config,
		expectedErrorSubstring: []string{"invalid configuration: no configuration has been provided"},
	}

	test.testConfig(t)
}
예제 #5
0
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)
}
예제 #6
0
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)
}
예제 #7
0
// 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
}
예제 #8
0
func TestValidateEmptyAuthInfo(t *testing.T) {
	config := clientcmdapi.NewConfig()
	config.AuthInfos["error"] = &clientcmdapi.AuthInfo{}
	test := configValidationTest{
		config: config,
	}

	test.testAuthInfo("error", t)
	test.testConfig(t)
}
예제 #9
0
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)
	}
}
예제 #10
0
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)
}
예제 #11
0
// 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
}
예제 #12
0
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)
}
예제 #13
0
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)
	}
}
예제 #14
0
// 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
}
예제 #15
0
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)
}
예제 #16
0
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)
}
예제 #17
0
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)
}
예제 #18
0
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)
}
예제 #19
0
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)
}
예제 #20
0
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)
}
예제 #21
0
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)
}
예제 #22
0
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)
}
예제 #23
0
func (o *PathOptions) GetStartingConfig() (*clientcmdapi.Config, error) {
	// don't mutate the original
	loadingRules := *o.LoadingRules
	loadingRules.Precedence = o.GetLoadingPrecedence()

	clientConfig := NewNonInteractiveDeferredLoadingClientConfig(&loadingRules, &ConfigOverrides{})
	rawConfig, err := clientConfig.RawConfig()
	if os.IsNotExist(err) {
		return clientcmdapi.NewConfig(), nil
	}
	if err != nil {
		return nil, err
	}

	return &rawConfig, nil
}
예제 #24
0
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)
}
예제 #25
0
func createValidTestConfig() *clientcmdapi.Config {
	const (
		server = "https://anything.com:8080"
		token  = "the-token"
	)

	config := clientcmdapi.NewConfig()
	config.Clusters["clean"] = &clientcmdapi.Cluster{
		Server: server,
	}
	config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
		Token: token,
	}
	config.Contexts["clean"] = &clientcmdapi.Context{
		Cluster:  "clean",
		AuthInfo: "clean",
	}
	config.CurrentContext = "clean"

	return config
}
예제 #26
0
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)
}
예제 #27
0
	"k8s.io/client-go/1.4/pkg/api"
	"k8s.io/client-go/1.4/rest"
	clientauth "k8s.io/client-go/1.4/tools/auth"
	clientcmdapi "k8s.io/client-go/1.4/tools/clientcmd/api"
)

var (
	// DefaultCluster is the cluster config used when no other config is specified
	// TODO: eventually apiserver should start on 443 and be secure by default
	DefaultCluster = clientcmdapi.Cluster{Server: "http://localhost:8080"}

	// EnvVarCluster allows overriding the DefaultCluster using an envvar for the server name
	EnvVarCluster = clientcmdapi.Cluster{Server: os.Getenv("KUBERNETES_MASTER")}

	DefaultClientConfig = DirectClientConfig{*clientcmdapi.NewConfig(), "", &ConfigOverrides{}, nil, NewDefaultClientConfigLoadingRules()}
)

// ClientConfig is used to make it easy to get an api server client
type ClientConfig interface {
	// RawConfig returns the merged result of all overrides
	RawConfig() (clientcmdapi.Config, error)
	// ClientConfig returns a complete client config
	ClientConfig() (*rest.Config, error)
	// Namespace returns the namespace resulting from the merged
	// result of all overrides and a boolean indicating if it was
	// overridden
	Namespace() (string, bool, error)
	// ConfigAccess returns the rules for loading/persisting the config.
	ConfigAccess() ConfigAccess
}
예제 #28
0
	"github.com/golang/glog"
	"github.com/imdario/mergo"

	"k8s.io/client-go/1.4/pkg/api"
	"k8s.io/client-go/1.4/rest"
	clientauth "k8s.io/client-go/1.4/tools/auth"
	clientcmdapi "k8s.io/client-go/1.4/tools/clientcmd/api"
)

var (
	// ClusterDefaults has the same behavior as the old EnvVar and DefaultCluster fields
	// DEPRECATED will be replaced
	ClusterDefaults = clientcmdapi.Cluster{Server: getDefaultServer()}
	// DefaultClientConfig represents the legacy behavior of this package for defaulting
	// DEPRECATED will be replace
	DefaultClientConfig = DirectClientConfig{*clientcmdapi.NewConfig(), "", &ConfigOverrides{
		ClusterDefaults: ClusterDefaults,
	}, nil, NewDefaultClientConfigLoadingRules()}
)

// getDefaultServer returns a default setting for DefaultClientConfig
// DEPRECATED
func getDefaultServer() string {
	if server := os.Getenv("KUBERNETES_MASTER"); len(server) > 0 {
		return server
	}
	return "http://localhost:8080"
}

// ClientConfig is used to make it easy to get an api server client
type ClientConfig interface {
func TestInClusterConfig(t *testing.T) {
	default1 := &DirectClientConfig{
		config:      *createValidTestConfig(),
		contextName: "clean",
		overrides:   &ConfigOverrides{},
	}
	invalidDefaultConfig := clientcmdapi.NewConfig()
	invalidDefaultConfig.Clusters["clean"] = &clientcmdapi.Cluster{
		Server: "http://localhost:8080",
	}
	invalidDefaultConfig.Contexts["other"] = &clientcmdapi.Context{
		Cluster: "clean",
	}
	invalidDefaultConfig.CurrentContext = "clean"

	defaultInvalid := &DirectClientConfig{
		config:    *invalidDefaultConfig,
		overrides: &ConfigOverrides{},
	}
	if _, err := defaultInvalid.ClientConfig(); err == nil || !IsConfigurationInvalid(err) {
		t.Fatal(err)
	}
	config1, err := default1.ClientConfig()
	if err != nil {
		t.Fatal(err)
	}
	config2 := &rest.Config{Host: "config2"}
	err1 := fmt.Errorf("unique error")

	testCases := map[string]struct {
		clientConfig  *testClientConfig
		icc           *testICC
		defaultConfig *DirectClientConfig

		checkedICC bool
		result     *rest.Config
		err        error
	}{
		"in-cluster checked on other error": {
			clientConfig: &testClientConfig{err: ErrEmptyConfig},
			icc:          &testICC{},

			checkedICC: true,
			result:     nil,
			err:        ErrEmptyConfig,
		},

		"in-cluster not checked on non-empty error": {
			clientConfig: &testClientConfig{err: ErrEmptyCluster},
			icc:          &testICC{},

			checkedICC: false,
			result:     nil,
			err:        ErrEmptyCluster,
		},

		"in-cluster checked when config is default": {
			defaultConfig: default1,
			clientConfig:  &testClientConfig{config: config1},
			icc:           &testICC{},

			checkedICC: true,
			result:     config1,
			err:        nil,
		},

		"in-cluster not checked when default config is invalid": {
			defaultConfig: defaultInvalid,
			clientConfig:  &testClientConfig{config: config1},
			icc:           &testICC{},

			checkedICC: false,
			result:     config1,
			err:        nil,
		},

		"in-cluster not checked when config is not equal to default": {
			defaultConfig: default1,
			clientConfig:  &testClientConfig{config: config2},
			icc:           &testICC{},

			checkedICC: false,
			result:     config2,
			err:        nil,
		},

		"in-cluster checked when config is not equal to default and error is empty": {
			clientConfig: &testClientConfig{config: config2, err: ErrEmptyConfig},
			icc:          &testICC{},

			checkedICC: true,
			result:     config2,
			err:        ErrEmptyConfig,
		},

		"in-cluster error returned when config is empty": {
			clientConfig: &testClientConfig{err: ErrEmptyConfig},
			icc: &testICC{
				possible: true,
				testClientConfig: testClientConfig{
					err: err1,
				},
			},

			checkedICC: true,
			result:     nil,
			err:        err1,
		},

		"in-cluster config returned when config is empty": {
			clientConfig: &testClientConfig{err: ErrEmptyConfig},
			icc: &testICC{
				possible: true,
				testClientConfig: testClientConfig{
					config: config2,
				},
			},

			checkedICC: true,
			result:     config2,
			err:        nil,
		},

		"in-cluster not checked when standard default is invalid": {
			defaultConfig: &DefaultClientConfig,
			clientConfig:  &testClientConfig{config: config2},
			icc:           &testICC{},

			checkedICC: false,
			result:     config2,
			err:        nil,
		},
	}

	for name, test := range testCases {
		c := &DeferredLoadingClientConfig{icc: test.icc}
		c.loader = &ClientConfigLoadingRules{DefaultClientConfig: test.defaultConfig}
		c.clientConfig = test.clientConfig

		cfg, err := c.ClientConfig()
		if test.icc.called != test.checkedICC {
			t.Errorf("%s: unexpected in-cluster-config call %t", name, test.icc.called)
		}
		if err != test.err || cfg != test.result {
			t.Errorf("%s: unexpected result: %v %#v", name, err, cfg)
		}
	}
}
예제 #30
0
// 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...)
	}

	kubeconfigs := []*clientcmdapi.Config{}
	// read and cache the config files so that we only look at them once
	for _, filename := range kubeConfigFiles {
		if len(filename) == 0 {
			// no work to do
			continue
		}

		config, err := LoadFromFile(filename)
		if os.IsNotExist(err) {
			// skip missing files
			continue
		}
		if err != nil {
			errlist = append(errlist, fmt.Errorf("Error loading config file \"%s\": %v", filename, err))
			continue
		}

		kubeconfigs = append(kubeconfigs, config)
	}

	// first merge all of our maps
	mapConfig := clientcmdapi.NewConfig()
	for _, kubeconfig := range kubeconfigs {
		mergo.Merge(mapConfig, kubeconfig)
	}

	// 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(kubeconfigs) - 1; i >= 0; i-- {
		kubeconfig := kubeconfigs[i]
		mergo.Merge(nonMapConfig, kubeconfig)
	}

	// 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)
}