sigs.k8s.io/cluster-api@v1.6.3/cmd/clusterctl/client/cluster/proxy_test.go (about) 1 /* 2 Copyright 2020 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 cluster 18 19 import ( 20 "fmt" 21 "os" 22 "path/filepath" 23 "testing" 24 "time" 25 26 . "github.com/onsi/gomega" 27 28 "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test" 29 "sigs.k8s.io/cluster-api/version" 30 ) 31 32 var _ Proxy = &test.FakeProxy{} 33 34 func TestProxyGetConfig(t *testing.T) { 35 t.Run("GetConfig", func(t *testing.T) { 36 tests := []struct { 37 name string 38 context string 39 kubeconfigContents string 40 expectedHost string 41 expectErr bool 42 }{ 43 { 44 name: "defaults to the currentContext if none is specified", 45 kubeconfigContents: kubeconfig("management", "default"), 46 expectedHost: "https://management-server:1234", 47 expectErr: false, 48 }, 49 { 50 name: "returns host of cluster associated with the specified context even if currentContext is different", 51 kubeconfigContents: kubeconfig("management", "default"), 52 context: "workload", 53 expectedHost: "https://kind-server:38790", 54 expectErr: false, 55 }, 56 { 57 name: "returns error if cannot load the kubeconfig file", 58 expectErr: true, 59 kubeconfigContents: "bad contents", 60 }, 61 } 62 63 for _, tt := range tests { 64 t.Run(tt.name, func(t *testing.T) { 65 g := NewWithT(t) 66 dir, err := os.MkdirTemp("", "clusterctl") 67 g.Expect(err).ToNot(HaveOccurred()) 68 defer os.RemoveAll(dir) 69 configFile := filepath.Join(dir, ".test-kubeconfig.yaml") 70 g.Expect(os.WriteFile(configFile, []byte(tt.kubeconfigContents), 0600)).To(Succeed()) 71 72 proxy := newProxy(Kubeconfig{Path: configFile, Context: tt.context}) 73 conf, err := proxy.GetConfig() 74 if tt.expectErr { 75 g.Expect(err).To(HaveOccurred()) 76 return 77 } 78 g.Expect(err).ToNot(HaveOccurred()) 79 g.Expect(conf).ToNot(BeNil()) 80 // asserting on the host of the cluster associated with the 81 // context 82 g.Expect(conf.Host).To(Equal(tt.expectedHost)) 83 g.Expect(conf.UserAgent).To(Equal(fmt.Sprintf("clusterctl/%s (%s)", version.Get().GitVersion, version.Get().Platform))) 84 g.Expect(conf.QPS).To(BeEquivalentTo(20)) 85 g.Expect(conf.Burst).To(BeEquivalentTo(100)) 86 g.Expect(conf.Timeout.String()).To(Equal("30s")) 87 }) 88 } 89 }) 90 91 t.Run("configure timeout", func(t *testing.T) { 92 g := NewWithT(t) 93 dir, err := os.MkdirTemp("", "clusterctl") 94 g.Expect(err).ToNot(HaveOccurred()) 95 defer os.RemoveAll(dir) 96 configFile := filepath.Join(dir, ".test-kubeconfig.yaml") 97 g.Expect(os.WriteFile(configFile, []byte(kubeconfig("management", "default")), 0600)).To(Succeed()) 98 99 proxy := newProxy(Kubeconfig{Path: configFile, Context: "management"}, InjectProxyTimeout(23*time.Second)) 100 conf, err := proxy.GetConfig() 101 g.Expect(err).ToNot(HaveOccurred()) 102 g.Expect(conf.Timeout.String()).To(Equal("23s")) 103 }) 104 } 105 106 // These tests are emulating the files passed in via KUBECONFIG env var by 107 // injecting the file paths into the ClientConfigLoadingRules.Precedence 108 // chain. 109 func TestKUBECONFIGEnvVar(t *testing.T) { 110 t.Run("CurrentNamespace", func(t *testing.T) { 111 // KUBECONFIG can specify multiple config files. We should be able to 112 // get the correct namespace for the context by parsing through all 113 // kubeconfig files 114 var ( 115 context = "workload" 116 kubeconfigContents = kubeconfig("does-not-exist", "some-ns") 117 ) 118 119 g := NewWithT(t) 120 dir, err := os.MkdirTemp("", "clusterctl") 121 g.Expect(err).ToNot(HaveOccurred()) 122 defer os.RemoveAll(dir) 123 configFile := filepath.Join(dir, ".test-kubeconfig.yaml") 124 g.Expect(os.WriteFile(configFile, []byte(kubeconfigContents), 0600)).To(Succeed()) 125 126 proxy := newProxy( 127 // dont't give an explicit path but rather define the file in the 128 // configLoadingRules precedence chain. 129 Kubeconfig{Path: "", Context: context}, 130 InjectKubeconfigPaths([]string{configFile}), 131 ) 132 actualNS, err := proxy.CurrentNamespace() 133 g.Expect(err).ToNot(HaveOccurred()) 134 g.Expect(actualNS).To(Equal("some-ns")) 135 }) 136 137 t.Run("GetConfig", func(t *testing.T) { 138 // KUBECONFIG can specify multiple config files. We should be able to 139 // get the valid cluster context by parsing all the kubeconfig files. 140 var ( 141 context = "workload" 142 // TODO: If we change current context to "do-not-exist", we get an 143 // error. See https://github.com/kubernetes/client-go/issues/797 144 kubeconfigContents = kubeconfig("management", "default") 145 expectedHost = "https://kind-server:38790" 146 ) 147 g := NewWithT(t) 148 dir, err := os.MkdirTemp("", "clusterctl") 149 g.Expect(err).ToNot(HaveOccurred()) 150 defer os.RemoveAll(dir) 151 configFile := filepath.Join(dir, ".test-kubeconfig.yaml") 152 g.Expect(os.WriteFile(configFile, []byte(kubeconfigContents), 0600)).To(Succeed()) 153 154 proxy := newProxy( 155 // dont't give an explicit path but rather define the file in the 156 // configLoadingRules precedence chain. 157 Kubeconfig{Path: "", Context: context}, 158 InjectKubeconfigPaths([]string{configFile}), 159 ) 160 conf, err := proxy.GetConfig() 161 g.Expect(err).ToNot(HaveOccurred()) 162 g.Expect(conf).ToNot(BeNil()) 163 // asserting on the host of the cluster associated with the 164 // context 165 g.Expect(conf.Host).To(Equal(expectedHost)) 166 }) 167 } 168 169 func TestProxyCurrentNamespace(t *testing.T) { 170 tests := []struct { 171 name string 172 kubeconfigPath string 173 kubeconfigContents string 174 kubeconfigContext string 175 expectErr bool 176 expectedNamespace string 177 }{ 178 { 179 name: "return error for invalid kubeconfig path", 180 kubeconfigPath: "do-not-exist", 181 expectErr: true, 182 }, 183 { 184 name: "return error for bad kubeconfig contents", 185 kubeconfigContents: "management", 186 expectErr: true, 187 }, 188 { 189 name: "return default namespace if unspecified", 190 kubeconfigContents: kubeconfig("workload", ""), 191 expectErr: false, 192 expectedNamespace: "default", 193 }, 194 { 195 name: "return error when current-context is empty", 196 kubeconfigContents: kubeconfig("", ""), 197 expectErr: true, 198 }, 199 { 200 name: "return error when current-context is incorrect or does not exist", 201 kubeconfigContents: kubeconfig("does-not-exist", ""), 202 expectErr: true, 203 }, 204 { 205 name: "return specified namespace for the current context", 206 kubeconfigContents: kubeconfig("workload", "mykindns"), 207 expectErr: false, 208 expectedNamespace: "mykindns", 209 }, 210 { 211 name: "return the namespace of the specified context which is different from current context", 212 kubeconfigContents: kubeconfig("management", "workload-ns"), 213 expectErr: false, 214 kubeconfigContext: "workload", 215 expectedNamespace: "workload-ns", 216 }, 217 } 218 for _, tt := range tests { 219 t.Run(tt.name, func(t *testing.T) { 220 g := NewWithT(t) 221 var configFile string 222 if tt.kubeconfigPath != "" { 223 configFile = tt.kubeconfigPath 224 } else { 225 dir, err := os.MkdirTemp("", "clusterctl") 226 g.Expect(err).ToNot(HaveOccurred()) 227 defer os.RemoveAll(dir) 228 configFile = filepath.Join(dir, ".test-kubeconfig.yaml") 229 g.Expect(os.WriteFile(configFile, []byte(tt.kubeconfigContents), 0600)).To(Succeed()) 230 } 231 232 proxy := newProxy(Kubeconfig{Path: configFile, Context: tt.kubeconfigContext}) 233 ns, err := proxy.CurrentNamespace() 234 if tt.expectErr { 235 g.Expect(err).To(HaveOccurred()) 236 return 237 } 238 g.Expect(err).ToNot(HaveOccurred()) 239 g.Expect(ns).To(Equal(tt.expectedNamespace)) 240 }) 241 } 242 } 243 244 func kubeconfig(currentContext, namespace string) string { 245 return fmt.Sprintf(`--- 246 apiVersion: v1 247 clusters: 248 - cluster: 249 insecure-skip-tls-verify: true 250 server: https://management-server:1234 251 name: management 252 - cluster: 253 insecure-skip-tls-verify: true 254 server: https://kind-server:38790 255 name: workload 256 contexts: 257 - context: 258 cluster: management 259 user: management 260 namespace: management-ns 261 name: management 262 - context: 263 cluster: workload 264 user: workload 265 namespace: %s 266 name: workload 267 current-context: %s 268 kind: Config 269 preferences: {} 270 users: 271 - name: management 272 user: 273 client-certificate-data: c3R1ZmYK 274 client-key-data: c3R1ZmYK 275 - name: workload 276 user: 277 client-certificate-data: c3R1ZmYK 278 client-key-data: c3R1ZmYK 279 `, namespace, currentContext) 280 }