fixes e2e failure on gce with new .kubeconfig, kick travis

This commit is contained in:
deads2k 2015-01-08 08:40:02 -05:00
parent 005f2e1bda
commit 60a46e7d49
5 changed files with 239 additions and 49 deletions

View File

@ -71,48 +71,153 @@ func (config DirectClientConfig) ClientConfig() (*client.Config, error) {
configAuthInfo := config.getAuthInfo()
configClusterInfo := config.getCluster()
clientConfig := client.Config{}
clientConfig := &client.Config{}
clientConfig.Host = configClusterInfo.Server
clientConfig.Version = configClusterInfo.APIVersion
// only try to read the auth information if we are secure
if client.IsConfigTransportTLS(clientConfig) {
var authInfo *clientauth.Info
if client.IsConfigTransportTLS(*clientConfig) {
var err error
switch {
case len(configAuthInfo.AuthPath) > 0:
authInfo, err = NewDefaultAuthLoader().LoadAuth(configAuthInfo.AuthPath)
if err != nil {
return nil, err
}
case len(configAuthInfo.Token) > 0:
authInfo = &clientauth.Info{BearerToken: configAuthInfo.Token}
case len(configAuthInfo.ClientCertificate) > 0:
authInfo = &clientauth.Info{
CertFile: configAuthInfo.ClientCertificate,
KeyFile: configAuthInfo.ClientKey,
}
default:
authInfo = &clientauth.Info{}
}
if !authInfo.Complete() && (config.fallbackReader != nil) {
prompter := NewPromptingAuthLoader(config.fallbackReader)
authInfo = prompter.Prompt()
}
authInfo.Insecure = &configClusterInfo.InsecureSkipTLSVerify
clientConfig, err = authInfo.MergeWithConfig(clientConfig)
// mergo is a first write wins for map value and a last writing wins for interface values
userAuthPartialConfig, err := getUserIdentificationPartialConfig(configAuthInfo, config.fallbackReader)
if err != nil {
return nil, err
}
mergo.Merge(clientConfig, userAuthPartialConfig)
serverAuthPartialConfig, err := getServerIdentificationPartialConfig(configAuthInfo, configClusterInfo)
if err != nil {
return nil, err
}
mergo.Merge(clientConfig, serverAuthPartialConfig)
}
return &clientConfig, nil
return clientConfig, nil
}
// clientauth.Info object contain both user identification and server identification. We want different precedence orders for
// both, so we have to split the objects and merge them separately
// we want this order of precedence for the server identification
// 1. configClusterInfo (the final result of command line flags and merged .kubeconfig files)
// 2. configAuthInfo.auth-path (this file can contain information that conflicts with #1, and we want #1 to win the priority)
// 3. load the ~/.kubernetes_auth file as a default
func getServerIdentificationPartialConfig(configAuthInfo AuthInfo, configClusterInfo Cluster) (*client.Config, error) {
mergedConfig := &client.Config{}
defaultAuthPathInfo, err := NewDefaultAuthLoader().LoadAuth(os.Getenv("HOME") + "/.kubernetes_auth")
// if the error is anything besides a does not exist, then fail. Not existing is ok
if err != nil && !os.IsNotExist(err) {
return nil, err
}
if defaultAuthPathInfo != nil {
defaultAuthPathConfig := makeServerIdentificationConfig(*defaultAuthPathInfo)
mergo.Merge(mergedConfig, defaultAuthPathConfig)
}
if len(configAuthInfo.AuthPath) > 0 {
authPathInfo, err := NewDefaultAuthLoader().LoadAuth(configAuthInfo.AuthPath)
if err != nil {
return nil, err
}
authPathConfig := makeServerIdentificationConfig(*authPathInfo)
mergo.Merge(mergedConfig, authPathConfig)
}
// configClusterInfo holds the information identify the server provided by .kubeconfig
configClientConfig := &client.Config{}
configClientConfig.CAFile = configClusterInfo.CertificateAuthority
configClientConfig.Insecure = configClusterInfo.InsecureSkipTLSVerify
mergo.Merge(mergedConfig, configClientConfig)
return mergedConfig, nil
}
// clientauth.Info object contain both user identification and server identification. We want different precedence orders for
// both, so we have to split the objects and merge them separately
// we want this order of precedence for user identifcation
// 1. configAuthInfo minus auth-path (the final result of command line flags and merged .kubeconfig files)
// 2. configAuthInfo.auth-path (this file can contain information that conflicts with #1, and we want #1 to win the priority)
// 3. if there is not enough information to idenfity the user, load try the ~/.kubernetes_auth file
// 4. if there is not enough information to identify the user, prompt if possible
func getUserIdentificationPartialConfig(configAuthInfo AuthInfo, fallbackReader io.Reader) (*client.Config, error) {
mergedConfig := &client.Config{}
if len(configAuthInfo.AuthPath) > 0 {
authPathInfo, err := NewDefaultAuthLoader().LoadAuth(configAuthInfo.AuthPath)
if err != nil {
return nil, err
}
authPathConfig := makeUserIdentificationConfig(*authPathInfo)
mergo.Merge(mergedConfig, authPathConfig)
}
// blindly overwrite existing values based on precedence
if len(configAuthInfo.Token) > 0 {
mergedConfig.BearerToken = configAuthInfo.Token
}
if len(configAuthInfo.ClientCertificate) > 0 {
mergedConfig.CertFile = configAuthInfo.ClientCertificate
mergedConfig.KeyFile = configAuthInfo.ClientKey
}
// if there isn't sufficient information to authenticate the user to the server, merge in ~/.kubernetes_auth.
if !canIdentifyUser(*mergedConfig) {
defaultAuthPathInfo, err := NewDefaultAuthLoader().LoadAuth(os.Getenv("HOME") + "/.kubernetes_auth")
// if the error is anything besides a does not exist, then fail. Not existing is ok
if err != nil && !os.IsNotExist(err) {
return nil, err
}
if defaultAuthPathInfo != nil {
defaultAuthPathConfig := makeUserIdentificationConfig(*defaultAuthPathInfo)
previouslyMergedConfig := mergedConfig
mergedConfig = &client.Config{}
mergo.Merge(mergedConfig, defaultAuthPathConfig)
mergo.Merge(mergedConfig, previouslyMergedConfig)
}
}
// if there still isn't enough information to authenticate the user, try prompting
if !canIdentifyUser(*mergedConfig) && (fallbackReader != nil) {
prompter := NewPromptingAuthLoader(fallbackReader)
promptedAuthInfo := prompter.Prompt()
promptedConfig := makeUserIdentificationConfig(*promptedAuthInfo)
previouslyMergedConfig := mergedConfig
mergedConfig = &client.Config{}
mergo.Merge(mergedConfig, promptedConfig)
mergo.Merge(mergedConfig, previouslyMergedConfig)
}
return mergedConfig, nil
}
// makeUserIdentificationFieldsConfig returns a client.Config capable of being merged using mergo for only user identification information
func makeUserIdentificationConfig(info clientauth.Info) *client.Config {
config := &client.Config{}
config.Username = info.User
config.Password = info.Password
config.CertFile = info.CertFile
config.KeyFile = info.KeyFile
config.BearerToken = info.BearerToken
return config
}
// makeUserIdentificationFieldsConfig returns a client.Config capable of being merged using mergo for only server identification information
func makeServerIdentificationConfig(info clientauth.Info) client.Config {
config := client.Config{}
config.CAFile = info.CAFile
if info.Insecure != nil {
config.Insecure = *info.Insecure
}
return config
}
func canIdentifyUser(config client.Config) bool {
return len(config.Username) > 0 ||
len(config.CertFile) > 0 ||
len(config.BearerToken) > 0
}
// ConfirmUsable looks a particular context and determines if that particular part of the config is useable. There might still be errors in the config,

View File

@ -0,0 +1,92 @@
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package clientcmd
import (
"encoding/json"
"io/ioutil"
"os"
"testing"
"github.com/spf13/cobra"
"github.com/GoogleCloudPlatform/kubernetes/pkg/clientauth"
)
// Verifies that referencing an old .kubernetes_auth file respects all fields
func TestAuthPathUpdatesBothClusterAndUser(t *testing.T) {
authFile, _ := ioutil.TempFile("", "")
defer os.Remove(authFile.Name())
insecure := true
auth := &clientauth.Info{
User: "user",
Password: "password",
CAFile: "ca-file",
CertFile: "cert-file",
KeyFile: "key-file",
BearerToken: "bearer-token",
Insecure: &insecure,
}
err := testWriteAuthInfoFile(*auth, authFile.Name())
if err != nil {
t.Errorf("Unexpected error %v", err)
}
cmd := &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
},
}
clientConfig := testBindClientConfig(cmd)
cmd.ParseFlags([]string{"--server=https://localhost", "--auth-path=" + authFile.Name()})
config, err := clientConfig.ClientConfig()
if err != nil {
t.Errorf("Unexpected error %v", err)
}
matchStringArg(auth.User, config.Username, t)
matchStringArg(auth.Password, config.Password, t)
matchStringArg(auth.CAFile, config.CAFile, t)
matchStringArg(auth.CertFile, config.CertFile, t)
matchStringArg(auth.KeyFile, config.KeyFile, t)
matchStringArg(auth.BearerToken, config.BearerToken, t)
matchBoolArg(*auth.Insecure, config.Insecure, t)
}
func testWriteAuthInfoFile(auth clientauth.Info, filename string) error {
data, err := json.Marshal(auth)
if err != nil {
return err
}
err = ioutil.WriteFile(filename, data, 0600)
return err
}
func testBindClientConfig(cmd *cobra.Command) ClientConfig {
loadingRules := NewClientConfigLoadingRules()
loadingRules.EnvVarPath = ""
loadingRules.HomeDirectoryPath = ""
loadingRules.CurrentDirectoryPath = ""
cmd.PersistentFlags().StringVar(&loadingRules.CommandLinePath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.")
overrides := &ConfigOverrides{}
overrides.BindFlags(cmd.PersistentFlags(), RecommendedConfigOverrideFlags(""))
clientConfig := NewInteractiveDeferredLoadingClientConfig(loadingRules, overrides, os.Stdin)
return clientConfig
}

View File

@ -122,11 +122,13 @@ func validateClusterInfo(clusterName string, clusterInfo Cluster) []error {
func validateAuthInfo(authInfoName string, authInfo AuthInfo) []error {
validationErrors := make([]error, 0)
usingAuthPath := false
methods := make([]string, 0, 3)
if len(authInfo.Token) != 0 {
methods = append(methods, "token")
}
if len(authInfo.AuthPath) != 0 {
usingAuthPath = true
methods = append(methods, "authFile")
file, err := os.Open(authInfo.AuthPath)
@ -151,7 +153,8 @@ func validateAuthInfo(authInfoName string, authInfo AuthInfo) []error {
}
}
if (len(methods)) > 1 {
// authPath also provides information for the client to identify the server, so allow multiple auth methods in that case
if (len(methods) > 1) && (!usingAuthPath) {
validationErrors = append(validationErrors, fmt.Errorf("more than one authentication method found for %v. Found %v, only one is allowed", authInfoName, methods))
}

View File

@ -52,7 +52,7 @@ func TestConfirmUsableBadInfoButOkConfig(t *testing.T) {
badValidation := configValidationTest{
config: config,
expectedErrorSubstring: []string{"unable to read auth-path", "more than one authentication method", "unable to read certificate-authority"},
expectedErrorSubstring: []string{"unable to read auth-path", "unable to read certificate-authority"},
}
okTest := configValidationTest{
config: config,
@ -77,7 +77,7 @@ func TestConfirmUsableBadInfoConfig(t *testing.T) {
}
test := configValidationTest{
config: config,
expectedErrorSubstring: []string{"unable to read auth-path", "more than one authentication method", "unable to read certificate-authority"},
expectedErrorSubstring: []string{"unable to read auth-path", "unable to read certificate-authority"},
}
test.testConfirmUsable("first", t)
@ -216,20 +216,6 @@ func TestValidateEmptyAuthInfo(t *testing.T) {
test.testAuthInfo("error", t)
test.testConfig(t)
}
func TestValidateTooMayTechniquesAuthInfo(t *testing.T) {
config := NewConfig()
config.AuthInfos["error"] = AuthInfo{
AuthPath: "anything",
Token: "here",
}
test := configValidationTest{
config: config,
expectedErrorSubstring: []string{"more than one authentication method found"},
}
test.testAuthInfo("error", t)
test.testConfig(t)
}
func TestValidatePathNotFoundAuthInfo(t *testing.T) {
config := NewConfig()
config.AuthInfos["error"] = AuthInfo{

View File

@ -21,6 +21,7 @@ import (
"io"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
"github.com/spf13/cobra"
)
@ -68,8 +69,11 @@ $ cat frontend-v2.json | kubectl rollingupdate frontend-v1 -f -
err = CompareNamespaceFromFile(cmd, namespace)
checkErr(err)
client, err := f.ClientBuilder.Client()
config, err := f.ClientConfig.ClientConfig()
checkErr(err)
client, err := client.New(config)
checkErr(err)
obj, err := mapping.Codec.Decode(data)
checkErr(err)
newRc := obj.(*api.ReplicationController)