sigs.k8s.io/controller-runtime@v0.18.2/pkg/client/config/config_test.go (about) 1 /* 2 Copyright 2019 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package config 18 19 import ( 20 "os" 21 "path/filepath" 22 "strings" 23 24 . "github.com/onsi/ginkgo/v2" 25 . "github.com/onsi/gomega" 26 "k8s.io/client-go/rest" 27 "k8s.io/client-go/tools/clientcmd" 28 ) 29 30 type testCase struct { 31 text string 32 context string 33 kubeconfigFlag string 34 kubeconfigEnv []string 35 wantHost string 36 } 37 38 var _ = Describe("Config", func() { 39 40 var dir string 41 42 origRecommendedHomeFile := clientcmd.RecommendedHomeFile 43 44 BeforeEach(func() { 45 // create temporary directory for test case 46 var err error 47 dir, err = os.MkdirTemp("", "cr-test") 48 Expect(err).NotTo(HaveOccurred()) 49 50 // override $HOME/.kube/config 51 clientcmd.RecommendedHomeFile = filepath.Join(dir, ".kubeconfig") 52 }) 53 54 AfterEach(func() { 55 os.Unsetenv(clientcmd.RecommendedConfigPathEnvVar) 56 kubeconfig = "" 57 clientcmd.RecommendedHomeFile = origRecommendedHomeFile 58 59 err := os.RemoveAll(dir) 60 Expect(err).NotTo(HaveOccurred()) 61 }) 62 63 Describe("GetConfigWithContext", func() { 64 defineTests := func(testCases []testCase) { 65 for _, testCase := range testCases { 66 tc := testCase 67 It(tc.text, func() { 68 // set global and environment configs 69 setConfigs(tc, dir) 70 71 // run the test 72 cfg, err := GetConfigWithContext(tc.context) 73 Expect(err).NotTo(HaveOccurred()) 74 Expect(cfg.Host).To(Equal(tc.wantHost)) 75 }) 76 } 77 } 78 79 Context("when kubeconfig files don't exist", func() { 80 It("should fail", func() { 81 err := os.Unsetenv(clientcmd.RecommendedConfigPathEnvVar) 82 Expect(err).NotTo(HaveOccurred()) 83 84 cfg, err := GetConfigWithContext("") 85 Expect(cfg).To(BeNil()) 86 Expect(err).To(HaveOccurred()) 87 }) 88 }) 89 90 Context("when in-cluster", func() { 91 kubeconfigFiles := map[string]string{ 92 "kubeconfig-multi-context": genKubeconfig("from-multi-env-1", "from-multi-env-2"), 93 ".kubeconfig": genKubeconfig("from-home"), 94 } 95 BeforeEach(func() { 96 err := createFiles(kubeconfigFiles, dir) 97 Expect(err).NotTo(HaveOccurred()) 98 99 // override in-cluster config loader 100 loadInClusterConfig = func() (*rest.Config, error) { 101 return &rest.Config{Host: "from-in-cluster"}, nil 102 } 103 }) 104 AfterEach(func() { loadInClusterConfig = rest.InClusterConfig }) 105 106 testCases := []testCase{ 107 { 108 text: "should prefer the envvar over the in-cluster config", 109 kubeconfigEnv: []string{"kubeconfig-multi-context"}, 110 wantHost: "from-multi-env-1", 111 }, 112 { 113 text: "should prefer in-cluster over the recommended home file", 114 wantHost: "from-in-cluster", 115 }, 116 } 117 defineTests(testCases) 118 }) 119 120 Context("when outside the cluster", func() { 121 kubeconfigFiles := map[string]string{ 122 "kubeconfig-flag": genKubeconfig("from-flag"), 123 "kubeconfig-multi-context": genKubeconfig("from-multi-env-1", "from-multi-env-2"), 124 "kubeconfig-env-1": genKubeconfig("from-env-1"), 125 "kubeconfig-env-2": genKubeconfig("from-env-2"), 126 ".kubeconfig": genKubeconfig("from-home"), 127 } 128 BeforeEach(func() { 129 err := createFiles(kubeconfigFiles, dir) 130 Expect(err).NotTo(HaveOccurred()) 131 }) 132 testCases := []testCase{ 133 { 134 text: "should use the --kubeconfig flag", 135 kubeconfigFlag: "kubeconfig-flag", 136 wantHost: "from-flag", 137 }, 138 { 139 text: "should use the envvar", 140 kubeconfigEnv: []string{"kubeconfig-multi-context"}, 141 wantHost: "from-multi-env-1", 142 }, 143 { 144 text: "should use the recommended home file", 145 wantHost: "from-home", 146 }, 147 { 148 text: "should prefer the flag over the envvar", 149 kubeconfigFlag: "kubeconfig-flag", 150 kubeconfigEnv: []string{"kubeconfig-multi-context"}, 151 wantHost: "from-flag", 152 }, 153 { 154 text: "should prefer the envvar over the recommended home file", 155 kubeconfigEnv: []string{"kubeconfig-multi-context"}, 156 wantHost: "from-multi-env-1", 157 }, 158 { 159 text: "should allow overriding the context", 160 context: "from-multi-env-2", 161 kubeconfigEnv: []string{"kubeconfig-multi-context"}, 162 wantHost: "from-multi-env-2", 163 }, 164 { 165 text: "should support a multi-value envvar", 166 context: "from-env-2", 167 kubeconfigEnv: []string{"kubeconfig-env-1", "kubeconfig-env-2"}, 168 wantHost: "from-env-2", 169 }, 170 } 171 defineTests(testCases) 172 }) 173 }) 174 }) 175 176 func setConfigs(tc testCase, dir string) { 177 // Set kubeconfig flag value 178 if len(tc.kubeconfigFlag) > 0 { 179 kubeconfig = filepath.Join(dir, tc.kubeconfigFlag) 180 } 181 182 // Set KUBECONFIG env value 183 if len(tc.kubeconfigEnv) > 0 { 184 kubeconfigEnvPaths := []string{} 185 for _, k := range tc.kubeconfigEnv { 186 kubeconfigEnvPaths = append(kubeconfigEnvPaths, filepath.Join(dir, k)) 187 } 188 os.Setenv(clientcmd.RecommendedConfigPathEnvVar, strings.Join(kubeconfigEnvPaths, ":")) 189 } 190 } 191 192 func createFiles(files map[string]string, dir string) error { 193 for path, data := range files { 194 if err := os.WriteFile(filepath.Join(dir, path), []byte(data), 0644); err != nil { //nolint:gosec 195 return err 196 } 197 } 198 return nil 199 } 200 201 func genKubeconfig(contexts ...string) string { 202 var sb strings.Builder 203 sb.WriteString(`--- 204 apiVersion: v1 205 kind: Config 206 clusters: 207 `) 208 for _, ctx := range contexts { 209 sb.WriteString(`- cluster: 210 server: ` + ctx + ` 211 name: ` + ctx + ` 212 `) 213 } 214 sb.WriteString("contexts:\n") 215 for _, ctx := range contexts { 216 sb.WriteString(`- context: 217 cluster: ` + ctx + ` 218 user: ` + ctx + ` 219 name: ` + ctx + ` 220 `) 221 } 222 223 sb.WriteString("users:\n") 224 for _, ctx := range contexts { 225 sb.WriteString(`- name: ` + ctx + ` 226 `) 227 } 228 sb.WriteString("preferences: {}\n") 229 if len(contexts) > 0 { 230 sb.WriteString("current-context: " + contexts[0] + "\n") 231 } 232 233 return sb.String() 234 }