switch kubeconfig types to internal map[string]*struct

This commit is contained in:
deads2k
2015-06-29 14:39:48 -04:00
parent 33278e7910
commit 55f574c267
17 changed files with 181 additions and 190 deletions

View File

@@ -34,11 +34,11 @@ import (
func newRedFederalCowHammerConfig() clientcmdapi.Config {
return clientcmdapi.Config{
AuthInfos: map[string]clientcmdapi.AuthInfo{
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"red-user": {Token: "red-token"}},
Clusters: map[string]clientcmdapi.Cluster{
Clusters: map[string]*clientcmdapi.Cluster{
"cow-cluster": {Server: "http://cow.org:8080"}},
Contexts: map[string]clientcmdapi.Context{
Contexts: map[string]*clientcmdapi.Context{
"federal-context": {AuthInfo: "red-user", Cluster: "cow-cluster"}},
CurrentContext: "federal-context",
}
@@ -108,10 +108,7 @@ func TestSetNonExistantContext(t *testing.T) {
func TestSetIntoExistingStruct(t *testing.T) {
expectedConfig := newRedFederalCowHammerConfig()
a := expectedConfig.AuthInfos["red-user"]
authInfo := &a
authInfo.Password = "new-path-value"
expectedConfig.AuthInfos["red-user"] = *authInfo
expectedConfig.AuthInfos["red-user"].Password = "new-path-value"
test := configCommandTest{
args: []string{"set", "users.red-user.password", "new-path-value"},
startingConfig: newRedFederalCowHammerConfig(),
@@ -123,10 +120,7 @@ func TestSetIntoExistingStruct(t *testing.T) {
func TestSetWithPathPrefixIntoExistingStruct(t *testing.T) {
expectedConfig := newRedFederalCowHammerConfig()
cc := expectedConfig.Clusters["cow-clusters"]
cinfo := &cc
cinfo.Server = "http://cow.org:8080/foo/baz"
expectedConfig.Clusters["cow-cluster"] = *cinfo
expectedConfig.Clusters["cow-cluster"].Server = "http://cow.org:8080/foo/baz"
test := configCommandTest{
args: []string{"set", "clusters.cow-cluster.server", "http://cow.org:8080/foo/baz"},
startingConfig: newRedFederalCowHammerConfig(),
@@ -164,7 +158,7 @@ func TestUnsetStruct(t *testing.T) {
func TestUnsetField(t *testing.T) {
expectedConfig := newRedFederalCowHammerConfig()
expectedConfig.AuthInfos["red-user"] = *clientcmdapi.NewAuthInfo()
expectedConfig.AuthInfos["red-user"] = clientcmdapi.NewAuthInfo()
test := configCommandTest{
args: []string{"unset", "users.red-user.token"},
startingConfig: newRedFederalCowHammerConfig(),
@@ -178,7 +172,7 @@ func TestSetIntoNewStruct(t *testing.T) {
expectedConfig := newRedFederalCowHammerConfig()
cluster := clientcmdapi.NewCluster()
cluster.Server = "new-server-value"
expectedConfig.Clusters["big-cluster"] = *cluster
expectedConfig.Clusters["big-cluster"] = cluster
test := configCommandTest{
args: []string{"set", "clusters.big-cluster.server", "new-server-value"},
startingConfig: newRedFederalCowHammerConfig(),
@@ -192,7 +186,7 @@ func TestSetBoolean(t *testing.T) {
expectedConfig := newRedFederalCowHammerConfig()
cluster := clientcmdapi.NewCluster()
cluster.InsecureSkipTLSVerify = true
expectedConfig.Clusters["big-cluster"] = *cluster
expectedConfig.Clusters["big-cluster"] = cluster
test := configCommandTest{
args: []string{"set", "clusters.big-cluster.insecure-skip-tls-verify", "true"},
startingConfig: newRedFederalCowHammerConfig(),
@@ -206,7 +200,7 @@ func TestSetIntoNewConfig(t *testing.T) {
expectedConfig := *clientcmdapi.NewConfig()
context := clientcmdapi.NewContext()
context.AuthInfo = "fake-user"
expectedConfig.Contexts["new-context"] = *context
expectedConfig.Contexts["new-context"] = context
test := configCommandTest{
args: []string{"set", "contexts.new-context.user", "fake-user"},
startingConfig: *clientcmdapi.NewConfig(),
@@ -218,7 +212,7 @@ func TestSetIntoNewConfig(t *testing.T) {
func TestNewEmptyAuth(t *testing.T) {
expectedConfig := *clientcmdapi.NewConfig()
expectedConfig.AuthInfos["the-user-name"] = *clientcmdapi.NewAuthInfo()
expectedConfig.AuthInfos["the-user-name"] = clientcmdapi.NewAuthInfo()
test := configCommandTest{
args: []string{"set-credentials", "the-user-name"},
startingConfig: *clientcmdapi.NewConfig(),
@@ -232,7 +226,7 @@ func TestAdditionalAuth(t *testing.T) {
expectedConfig := newRedFederalCowHammerConfig()
authInfo := clientcmdapi.NewAuthInfo()
authInfo.Token = "token"
expectedConfig.AuthInfos["another-user"] = *authInfo
expectedConfig.AuthInfos["another-user"] = authInfo
test := configCommandTest{
args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagBearerToken + "=token"},
startingConfig: newRedFederalCowHammerConfig(),
@@ -250,7 +244,7 @@ func TestEmbedClientCert(t *testing.T) {
expectedConfig := newRedFederalCowHammerConfig()
authInfo := clientcmdapi.NewAuthInfo()
authInfo.ClientCertificateData = fakeData
expectedConfig.AuthInfos["another-user"] = *authInfo
expectedConfig.AuthInfos["another-user"] = authInfo
test := configCommandTest{
args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagCertFile + "=" + fakeCertFile.Name(), "--" + clientcmd.FlagEmbedCerts + "=true"},
@@ -269,7 +263,7 @@ func TestEmbedClientKey(t *testing.T) {
expectedConfig := newRedFederalCowHammerConfig()
authInfo := clientcmdapi.NewAuthInfo()
authInfo.ClientKeyData = fakeData
expectedConfig.AuthInfos["another-user"] = *authInfo
expectedConfig.AuthInfos["another-user"] = authInfo
test := configCommandTest{
args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagKeyFile + "=" + fakeKeyFile.Name(), "--" + clientcmd.FlagEmbedCerts + "=true"},
@@ -296,7 +290,7 @@ func TestEmptyTokenAndCertAllowed(t *testing.T) {
expectedConfig := newRedFederalCowHammerConfig()
authInfo := clientcmdapi.NewAuthInfo()
authInfo.ClientCertificate = "cert-file"
expectedConfig.AuthInfos["another-user"] = *authInfo
expectedConfig.AuthInfos["another-user"] = authInfo
test := configCommandTest{
args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagCertFile + "=cert-file", "--" + clientcmd.FlagBearerToken + "="},
@@ -312,7 +306,7 @@ func TestTokenAndCertAllowed(t *testing.T) {
authInfo := clientcmdapi.NewAuthInfo()
authInfo.Token = "token"
authInfo.ClientCertificate = "cert-file"
expectedConfig.AuthInfos["another-user"] = *authInfo
expectedConfig.AuthInfos["another-user"] = authInfo
test := configCommandTest{
args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagCertFile + "=cert-file", "--" + clientcmd.FlagBearerToken + "=token"},
startingConfig: newRedFederalCowHammerConfig(),
@@ -343,10 +337,10 @@ func TestBasicClearsToken(t *testing.T) {
authInfoWithBasic.Password = "mypass"
startingConfig := newRedFederalCowHammerConfig()
startingConfig.AuthInfos["another-user"] = *authInfoWithToken
startingConfig.AuthInfos["another-user"] = authInfoWithToken
expectedConfig := newRedFederalCowHammerConfig()
expectedConfig.AuthInfos["another-user"] = *authInfoWithBasic
expectedConfig.AuthInfos["another-user"] = authInfoWithBasic
test := configCommandTest{
args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagUsername + "=myuser", "--" + clientcmd.FlagPassword + "=mypass"},
@@ -366,10 +360,10 @@ func TestTokenClearsBasic(t *testing.T) {
authInfoWithToken.Token = "token"
startingConfig := newRedFederalCowHammerConfig()
startingConfig.AuthInfos["another-user"] = *authInfoWithBasic
startingConfig.AuthInfos["another-user"] = authInfoWithBasic
expectedConfig := newRedFederalCowHammerConfig()
expectedConfig.AuthInfos["another-user"] = *authInfoWithToken
expectedConfig.AuthInfos["another-user"] = authInfoWithToken
test := configCommandTest{
args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagBearerToken + "=token"},
@@ -395,10 +389,10 @@ func TestTokenLeavesCert(t *testing.T) {
authInfoWithTokenAndCerts.ClientKeyData = []byte("keydata")
startingConfig := newRedFederalCowHammerConfig()
startingConfig.AuthInfos["another-user"] = *authInfoWithCerts
startingConfig.AuthInfos["another-user"] = authInfoWithCerts
expectedConfig := newRedFederalCowHammerConfig()
expectedConfig.AuthInfos["another-user"] = *authInfoWithTokenAndCerts
expectedConfig.AuthInfos["another-user"] = authInfoWithTokenAndCerts
test := configCommandTest{
args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagBearerToken + "=token"},
@@ -419,10 +413,10 @@ func TestCertLeavesToken(t *testing.T) {
authInfoWithTokenAndCerts.ClientKey = "key"
startingConfig := newRedFederalCowHammerConfig()
startingConfig.AuthInfos["another-user"] = *authInfoWithToken
startingConfig.AuthInfos["another-user"] = authInfoWithToken
expectedConfig := newRedFederalCowHammerConfig()
expectedConfig.AuthInfos["another-user"] = *authInfoWithTokenAndCerts
expectedConfig.AuthInfos["another-user"] = authInfoWithTokenAndCerts
test := configCommandTest{
args: []string{"set-credentials", "another-user", "--" + clientcmd.FlagCertFile + "=cert", "--" + clientcmd.FlagKeyFile + "=key"},
@@ -441,10 +435,10 @@ func TestCAClearsInsecure(t *testing.T) {
clusterInfoWithCA.CertificateAuthority = "cafile"
startingConfig := newRedFederalCowHammerConfig()
startingConfig.Clusters["another-cluster"] = *clusterInfoWithInsecure
startingConfig.Clusters["another-cluster"] = clusterInfoWithInsecure
expectedConfig := newRedFederalCowHammerConfig()
expectedConfig.Clusters["another-cluster"] = *clusterInfoWithCA
expectedConfig.Clusters["another-cluster"] = clusterInfoWithCA
test := configCommandTest{
args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagCAFile + "=cafile"},
@@ -463,10 +457,10 @@ func TestCAClearsCAData(t *testing.T) {
clusterInfoWithCA.CertificateAuthority = "cafile"
startingConfig := newRedFederalCowHammerConfig()
startingConfig.Clusters["another-cluster"] = *clusterInfoWithCAData
startingConfig.Clusters["another-cluster"] = clusterInfoWithCAData
expectedConfig := newRedFederalCowHammerConfig()
expectedConfig.Clusters["another-cluster"] = *clusterInfoWithCA
expectedConfig.Clusters["another-cluster"] = clusterInfoWithCA
test := configCommandTest{
args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagCAFile + "=cafile", "--" + clientcmd.FlagInsecure + "=false"},
@@ -486,10 +480,10 @@ func TestInsecureClearsCA(t *testing.T) {
clusterInfoWithCA.CertificateAuthorityData = []byte("cadata")
startingConfig := newRedFederalCowHammerConfig()
startingConfig.Clusters["another-cluster"] = *clusterInfoWithCA
startingConfig.Clusters["another-cluster"] = clusterInfoWithCA
expectedConfig := newRedFederalCowHammerConfig()
expectedConfig.Clusters["another-cluster"] = *clusterInfoWithInsecure
expectedConfig.Clusters["another-cluster"] = clusterInfoWithInsecure
test := configCommandTest{
args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagInsecure + "=true"},
@@ -513,10 +507,10 @@ func TestCADataClearsCA(t *testing.T) {
clusterInfoWithCA.CertificateAuthority = "cafile"
startingConfig := newRedFederalCowHammerConfig()
startingConfig.Clusters["another-cluster"] = *clusterInfoWithCA
startingConfig.Clusters["another-cluster"] = clusterInfoWithCA
expectedConfig := newRedFederalCowHammerConfig()
expectedConfig.Clusters["another-cluster"] = *clusterInfoWithCAData
expectedConfig.Clusters["another-cluster"] = clusterInfoWithCAData
test := configCommandTest{
args: []string{"set-cluster", "another-cluster", "--" + clientcmd.FlagCAFile + "=" + fakeCAFile.Name(), "--" + clientcmd.FlagEmbedCerts + "=true"},
@@ -566,7 +560,7 @@ func TestMergeExistingAuth(t *testing.T) {
func TestNewEmptyCluster(t *testing.T) {
expectedConfig := *clientcmdapi.NewConfig()
expectedConfig.Clusters["new-cluster"] = *clientcmdapi.NewCluster()
expectedConfig.Clusters["new-cluster"] = clientcmdapi.NewCluster()
test := configCommandTest{
args: []string{"set-cluster", "new-cluster"},
startingConfig: *clientcmdapi.NewConfig(),
@@ -578,7 +572,7 @@ func TestNewEmptyCluster(t *testing.T) {
func TestAdditionalCluster(t *testing.T) {
expectedConfig := newRedFederalCowHammerConfig()
cluster := *clientcmdapi.NewCluster()
cluster := clientcmdapi.NewCluster()
cluster.APIVersion = testapi.Version()
cluster.CertificateAuthority = "ca-location"
cluster.InsecureSkipTLSVerify = false
@@ -595,7 +589,7 @@ func TestAdditionalCluster(t *testing.T) {
func TestOverwriteExistingCluster(t *testing.T) {
expectedConfig := newRedFederalCowHammerConfig()
cluster := *clientcmdapi.NewCluster()
cluster := clientcmdapi.NewCluster()
cluster.Server = "serverlocation"
expectedConfig.Clusters["cow-cluster"] = cluster
@@ -610,7 +604,7 @@ func TestOverwriteExistingCluster(t *testing.T) {
func TestNewEmptyContext(t *testing.T) {
expectedConfig := *clientcmdapi.NewConfig()
expectedConfig.Contexts["new-context"] = *clientcmdapi.NewContext()
expectedConfig.Contexts["new-context"] = clientcmdapi.NewContext()
test := configCommandTest{
args: []string{"set-context", "new-context"},
startingConfig: *clientcmdapi.NewConfig(),
@@ -622,7 +616,7 @@ func TestNewEmptyContext(t *testing.T) {
func TestAdditionalContext(t *testing.T) {
expectedConfig := newRedFederalCowHammerConfig()
context := *clientcmdapi.NewContext()
context := clientcmdapi.NewContext()
context.Cluster = "some-cluster"
context.AuthInfo = "some-user"
context.Namespace = "different-namespace"
@@ -683,10 +677,13 @@ func TestToBool(t *testing.T) {
}
func testConfigCommand(args []string, startingConfig clientcmdapi.Config) (string, clientcmdapi.Config) {
func testConfigCommand(args []string, startingConfig clientcmdapi.Config, t *testing.T) (string, clientcmdapi.Config) {
fakeKubeFile, _ := ioutil.TempFile("", "")
defer os.Remove(fakeKubeFile.Name())
clientcmd.WriteToFile(startingConfig, fakeKubeFile.Name())
err := clientcmd.WriteToFile(startingConfig, fakeKubeFile.Name())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
argsToUse := make([]string, 0, 2+len(args))
argsToUse = append(argsToUse, "--kubeconfig="+fakeKubeFile.Name())
@@ -712,7 +709,7 @@ type configCommandTest struct {
}
func (test configCommandTest) run(t *testing.T) string {
out, actualConfig := testConfigCommand(test.args, test.startingConfig)
out, actualConfig := testConfigCommand(test.args, test.startingConfig, t)
testSetNilMapsToEmpties(reflect.ValueOf(&test.expectedConfig))
testSetNilMapsToEmpties(reflect.ValueOf(&actualConfig))
@@ -755,20 +752,7 @@ func testSetNilMapsToEmpties(curr reflect.Value) {
case reflect.Map:
for _, mapKey := range actualCurrValue.MapKeys() {
currMapValue := actualCurrValue.MapIndex(mapKey)
// our maps do not hold pointers to structs, they hold the structs themselves. This means that MapIndex returns the struct itself
// That in turn means that they have kinds of type.Struct, which is not a settable type. Because of this, we need to make new struct of that type
// copy all the data from the old value into the new value, then take the .addr of the new value to modify it in the next recursion.
// clear as mud
modifiableMapValue := reflect.New(currMapValue.Type()).Elem()
modifiableMapValue.Set(currMapValue)
if modifiableMapValue.Kind() == reflect.Struct {
modifiableMapValue = modifiableMapValue.Addr()
}
testSetNilMapsToEmpties(modifiableMapValue)
actualCurrValue.SetMapIndex(mapKey, reflect.Indirect(modifiableMapValue))
testSetNilMapsToEmpties(currMapValue)
}
case reflect.Struct:

View File

@@ -108,8 +108,12 @@ func (o createAuthInfoOptions) run() error {
return err
}
authInfo := o.modifyAuthInfo(config.AuthInfos[o.name])
config.AuthInfos[o.name] = authInfo
startingStanza, exists := config.AuthInfos[o.name]
if !exists {
startingStanza = clientcmdapi.NewAuthInfo()
}
authInfo := o.modifyAuthInfo(*startingStanza)
config.AuthInfos[o.name] = &authInfo
if err := ModifyConfig(o.configAccess, *config); err != nil {
return err

View File

@@ -94,8 +94,12 @@ func (o createClusterOptions) run() error {
return err
}
cluster := o.modifyCluster(config.Clusters[o.name])
config.Clusters[o.name] = cluster
startingStanza, exists := config.Clusters[o.name]
if !exists {
startingStanza = clientcmdapi.NewCluster()
}
cluster := o.modifyCluster(*startingStanza)
config.Clusters[o.name] = &cluster
if err := ModifyConfig(o.configAccess, *config); err != nil {
return err

View File

@@ -81,8 +81,12 @@ func (o createContextOptions) run() error {
return err
}
context := o.modifyContext(config.Contexts[o.name])
config.Contexts[o.name] = context
startingStanza, exists := config.Contexts[o.name]
if !exists {
startingStanza = clientcmdapi.NewContext()
}
context := o.modifyContext(*startingStanza)
config.Contexts[o.name] = &context
if err := ModifyConfig(o.configAccess, *config); err != nil {
return err

View File

@@ -50,7 +50,7 @@ func newNavigationSteps(path string) (*navigationSteps, error) {
// store them as a single step. In order to do that, we need to determine what set of tokens is a legal step AFTER the name of the map key
// This set of reflective code pulls the type of the map values, uses that type to look up the set of legal tags. Those legal tags are used to
// walk the list of remaining parts until we find a match to a legal tag or the end of the string. That name is used to burn all the used parts.
mapValueType := currType.Elem()
mapValueType := currType.Elem().Elem()
mapValueOptions, err := getPotentialTypeValues(mapValueType)
if err != nil {
return nil, err
@@ -120,6 +120,10 @@ func findNameStep(parts []string, typeOptions util.StringSet) string {
// getPotentialTypeValues takes a type and looks up the tags used to represent its fields when serialized.
func getPotentialTypeValues(typeValue reflect.Type) (map[string]reflect.Type, error) {
if typeValue.Kind() == reflect.Ptr {
typeValue = typeValue.Elem()
}
if typeValue.Kind() != reflect.Struct {
return nil, fmt.Errorf("%v is not of type struct", typeValue)
}

View File

@@ -36,7 +36,7 @@ func TestParseWithDots(t *testing.T) {
path: "clusters.my.dot.delimited.name.server",
expectedNavigationSteps: navigationSteps{
steps: []navigationStep{
{"clusters", reflect.TypeOf(make(map[string]clientcmdapi.Cluster))},
{"clusters", reflect.TypeOf(make(map[string]*clientcmdapi.Cluster))},
{"my.dot.delimited.name", reflect.TypeOf(clientcmdapi.Cluster{})},
{"server", reflect.TypeOf("")},
},
@@ -51,7 +51,7 @@ func TestParseWithDotsEndingWithName(t *testing.T) {
path: "contexts.10.12.12.12",
expectedNavigationSteps: navigationSteps{
steps: []navigationStep{
{"contexts", reflect.TypeOf(make(map[string]clientcmdapi.Context))},
{"contexts", reflect.TypeOf(make(map[string]*clientcmdapi.Context))},
{"10.12.12.12", reflect.TypeOf(clientcmdapi.Context{})},
},
},
@@ -91,5 +91,6 @@ func (test stepParserTest) run(t *testing.T) {
if !reflect.DeepEqual(test.expectedNavigationSteps, *actualSteps) {
t.Errorf("diff: %v", util.ObjectDiff(test.expectedNavigationSteps, *actualSteps))
t.Errorf("expected: %#v\n actual: %#v", test.expectedNavigationSteps, *actualSteps)
}
}

View File

@@ -139,26 +139,15 @@ func modifyConfig(curr reflect.Value, steps *navigationSteps, propertyValue stri
needToSetNewMapValue := currMapValue.Kind() == reflect.Invalid
if needToSetNewMapValue {
currMapValue = reflect.New(mapValueType).Elem()
currMapValue = reflect.New(mapValueType.Elem()).Elem().Addr()
actualCurrValue.SetMapIndex(mapKey, currMapValue)
}
// our maps do not hold pointers to structs, they hold the structs themselves. This means that MapIndex returns the struct itself
// That in turn means that they have kinds of type.Struct, which is not a settable type. Because of this, we need to make new struct of that type
// copy all the data from the old value into the new value, then take the .addr of the new value to modify it in the next recursion.
// clear as mud
modifiableMapValue := reflect.New(currMapValue.Type()).Elem()
modifiableMapValue.Set(currMapValue)
if modifiableMapValue.Kind() == reflect.Struct {
modifiableMapValue = modifiableMapValue.Addr()
}
err := modifyConfig(modifiableMapValue, steps, propertyValue, unset)
err := modifyConfig(currMapValue, steps, propertyValue, unset)
if err != nil {
return err
}
actualCurrValue.SetMapIndex(mapKey, reflect.Indirect(modifiableMapValue))
return nil
case reflect.String:
@@ -213,5 +202,6 @@ func modifyConfig(curr reflect.Value, steps *navigationSteps, propertyValue stri
}
return fmt.Errorf("Unrecognized type: %v", actualCurrValue)
panic(fmt.Errorf("Unrecognized type: %v", actualCurrValue))
return nil
}