diff --git a/tools/clientcmd/api/v1/conversion.go b/tools/clientcmd/api/v1/conversion.go index b47bfbca..2d7142e6 100644 --- a/tools/clientcmd/api/v1/conversion.go +++ b/tools/clientcmd/api/v1/conversion.go @@ -17,6 +17,7 @@ limitations under the License. package v1 import ( + "fmt" "sort" "k8s.io/apimachinery/pkg/conversion" @@ -105,7 +106,11 @@ func addConversionFuncs(scheme *runtime.Scheme) error { if err := s.Convert(&curr.Cluster, newCluster, 0); err != nil { return err } - (*out)[curr.Name] = newCluster + if (*out)[curr.Name] == nil { + (*out)[curr.Name] = newCluster + } else { + return fmt.Errorf("error converting *[]NamedCluster into *map[string]*api.Cluster: duplicate name \"%v\" in list: %v", curr.Name, *in) + } } return nil @@ -136,7 +141,11 @@ func addConversionFuncs(scheme *runtime.Scheme) error { if err := s.Convert(&curr.AuthInfo, newAuthInfo, 0); err != nil { return err } - (*out)[curr.Name] = newAuthInfo + if (*out)[curr.Name] == nil { + (*out)[curr.Name] = newAuthInfo + } else { + return fmt.Errorf("error converting *[]NamedAuthInfo into *map[string]*api.AuthInfo: duplicate name \"%v\" in list: %v", curr.Name, *in) + } } return nil @@ -167,7 +176,11 @@ func addConversionFuncs(scheme *runtime.Scheme) error { if err := s.Convert(&curr.Context, newContext, 0); err != nil { return err } - (*out)[curr.Name] = newContext + if (*out)[curr.Name] == nil { + (*out)[curr.Name] = newContext + } else { + return fmt.Errorf("error converting *[]NamedContext into *map[string]*api.Context: duplicate name \"%v\" in list: %v", curr.Name, *in) + } } return nil @@ -198,7 +211,11 @@ func addConversionFuncs(scheme *runtime.Scheme) error { if err := s.Convert(&curr.Extension, &newExtension, 0); err != nil { return err } - (*out)[curr.Name] = newExtension + if (*out)[curr.Name] == nil { + (*out)[curr.Name] = newExtension + } else { + return fmt.Errorf("error converting *[]NamedExtension into *map[string]runtime.Object: duplicate name \"%v\" in list: %v", curr.Name, *in) + } } return nil diff --git a/tools/clientcmd/loader_test.go b/tools/clientcmd/loader_test.go index 09d0753b..86eccac4 100644 --- a/tools/clientcmd/loader_test.go +++ b/tools/clientcmd/loader_test.go @@ -201,6 +201,174 @@ func TestLoadingEmptyMaps(t *testing.T) { } } +func TestDuplicateClusterName(t *testing.T) { + configFile, _ := ioutil.TempFile("", "") + defer os.Remove(configFile.Name()) + + err := ioutil.WriteFile(configFile.Name(), []byte(` +kind: Config +apiVersion: v1 +clusters: +- cluster: + api-version: v1 + server: https://kubernetes.default.svc:443 + certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + name: kubeconfig-cluster +- cluster: + api-version: v2 + server: https://test.example.server:443 + certificate-authority: /var/run/secrets/test.example.io/serviceaccount/ca.crt + name: kubeconfig-cluster +contexts: +- context: + cluster: kubeconfig-cluster + namespace: default + user: kubeconfig-user + name: kubeconfig-context +current-context: kubeconfig-context +users: +- name: kubeconfig-user + user: + tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token +`), os.FileMode(0755)) + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + _, err = LoadFromFile(configFile.Name()) + if err == nil || !strings.Contains(err.Error(), + "error converting *[]NamedCluster into *map[string]*api.Cluster: duplicate name \"kubeconfig-cluster\" in list") { + t.Error("Expected error in loading duplicate cluster name, got none") + } +} + +func TestDuplicateContextName(t *testing.T) { + configFile, _ := ioutil.TempFile("", "") + defer os.Remove(configFile.Name()) + + err := ioutil.WriteFile(configFile.Name(), []byte(` +kind: Config +apiVersion: v1 +clusters: +- cluster: + api-version: v1 + server: https://kubernetes.default.svc:443 + certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + name: kubeconfig-cluster +contexts: +- context: + cluster: kubeconfig-cluster + namespace: default + user: kubeconfig-user + name: kubeconfig-context +- context: + cluster: test-example-cluster + namespace: test-example + user: test-example-user + name: kubeconfig-context +current-context: kubeconfig-context +users: +- name: kubeconfig-user + user: + tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token +`), os.FileMode(0755)) + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + _, err = LoadFromFile(configFile.Name()) + if err == nil || !strings.Contains(err.Error(), + "error converting *[]NamedContext into *map[string]*api.Context: duplicate name \"kubeconfig-context\" in list") { + t.Error("Expected error in loading duplicate context name, got none") + } +} + +func TestDuplicateUserName(t *testing.T) { + configFile, _ := ioutil.TempFile("", "") + defer os.Remove(configFile.Name()) + + err := ioutil.WriteFile(configFile.Name(), []byte(` +kind: Config +apiVersion: v1 +clusters: +- cluster: + api-version: v1 + server: https://kubernetes.default.svc:443 + certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + name: kubeconfig-cluster +contexts: +- context: + cluster: kubeconfig-cluster + namespace: default + user: kubeconfig-user + name: kubeconfig-context +current-context: kubeconfig-context +users: +- name: kubeconfig-user + user: + tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token +- name: kubeconfig-user + user: + tokenFile: /var/run/secrets/test.example.com/serviceaccount/token +`), os.FileMode(0755)) + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + _, err = LoadFromFile(configFile.Name()) + if err == nil || !strings.Contains(err.Error(), + "error converting *[]NamedAuthInfo into *map[string]*api.AuthInfo: duplicate name \"kubeconfig-user\" in list") { + t.Error("Expected error in loading duplicate user name, got none") + } +} + +func TestDuplicateExtensionName(t *testing.T) { + configFile, _ := ioutil.TempFile("", "") + defer os.Remove(configFile.Name()) + + err := ioutil.WriteFile(configFile.Name(), []byte(` +kind: Config +apiVersion: v1 +clusters: +- cluster: + api-version: v1 + server: https://kubernetes.default.svc:443 + certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + name: kubeconfig-cluster +contexts: +- context: + cluster: kubeconfig-cluster + namespace: default + user: kubeconfig-user + name: kubeconfig-context +current-context: kubeconfig-context +users: +- name: kubeconfig-user + user: + tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token +extensions: +- extension: + bytes: test + name: test-extension +- extension: + bytes: some-example + name: test-extension +`), os.FileMode(0755)) + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + _, err = LoadFromFile(configFile.Name()) + if err == nil || !strings.Contains(err.Error(), + "error converting *[]NamedExtension into *map[string]runtime.Object: duplicate name \"test-extension\" in list") { + t.Error("Expected error in loading duplicate extension name, got none") + } +} + func TestResolveRelativePaths(t *testing.T) { pathResolutionConfig1 := clientcmdapi.Config{ AuthInfos: map[string]*clientcmdapi.AuthInfo{