k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/kubeadm/app/phases/kubeconfig/kubeconfig_test.go (about) 1 /* 2 Copyright 2018 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 kubeconfig 18 19 import ( 20 "bytes" 21 "context" 22 "crypto" 23 "crypto/x509" 24 "fmt" 25 "io" 26 "os" 27 "path/filepath" 28 "reflect" 29 "testing" 30 "time" 31 32 "github.com/lithammer/dedent" 33 "github.com/pkg/errors" 34 35 rbac "k8s.io/api/rbac/v1" 36 apierrors "k8s.io/apimachinery/pkg/api/errors" 37 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 38 "k8s.io/apimachinery/pkg/runtime" 39 "k8s.io/apimachinery/pkg/runtime/schema" 40 clientset "k8s.io/client-go/kubernetes" 41 clientsetfake "k8s.io/client-go/kubernetes/fake" 42 clientgotesting "k8s.io/client-go/testing" 43 "k8s.io/client-go/tools/clientcmd" 44 clientcmdapi "k8s.io/client-go/tools/clientcmd/api" 45 46 kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" 47 kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" 48 certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs" 49 kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" 50 certstestutil "k8s.io/kubernetes/cmd/kubeadm/app/util/certs" 51 "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil" 52 testutil "k8s.io/kubernetes/cmd/kubeadm/test" 53 kubeconfigtestutil "k8s.io/kubernetes/cmd/kubeadm/test/kubeconfig" 54 ) 55 56 func TestGetKubeConfigSpecsFailsIfCADoesntExists(t *testing.T) { 57 // Create temp folder for the test case (without a CA) 58 tmpdir := testutil.SetupTempDir(t) 59 defer os.RemoveAll(tmpdir) 60 61 // Creates an InitConfiguration pointing to the pkidir folder 62 cfg := &kubeadmapi.InitConfiguration{ 63 ClusterConfiguration: kubeadmapi.ClusterConfiguration{ 64 CertificatesDir: tmpdir, 65 }, 66 } 67 68 // Executes getKubeConfigSpecs 69 if _, err := getKubeConfigSpecs(cfg); err == nil { 70 t.Error("getKubeConfigSpecs didnt failed when expected") 71 } 72 } 73 74 func TestGetKubeConfigSpecs(t *testing.T) { 75 // Create temp folder for the test case 76 tmpdir := testutil.SetupTempDir(t) 77 defer os.RemoveAll(tmpdir) 78 79 // Adds a pki folder with a ca certs to the temp folder 80 pkidir := testutil.SetupPkiDirWithCertificateAuthority(t, tmpdir) 81 82 // Creates InitConfigurations pointing to the pkidir folder 83 cfgs := []*kubeadmapi.InitConfiguration{ 84 { 85 LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4", BindPort: 1234}, 86 ClusterConfiguration: kubeadmapi.ClusterConfiguration{ 87 CertificatesDir: pkidir, 88 }, 89 NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-node-name"}, 90 }, 91 { 92 LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4", BindPort: 1234}, 93 ClusterConfiguration: kubeadmapi.ClusterConfiguration{ 94 ControlPlaneEndpoint: "api.k8s.io", 95 CertificatesDir: pkidir, 96 }, 97 NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-node-name"}, 98 }, 99 { 100 LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4", BindPort: 1234}, 101 ClusterConfiguration: kubeadmapi.ClusterConfiguration{ 102 ControlPlaneEndpoint: "api.k8s.io:4321", 103 CertificatesDir: pkidir, 104 }, 105 NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-node-name"}, 106 }, 107 { 108 LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4", BindPort: 1234}, 109 ClusterConfiguration: kubeadmapi.ClusterConfiguration{ 110 ControlPlaneEndpoint: "api.k8s.io", 111 CertificatesDir: pkidir, 112 }, 113 NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-node-name"}, 114 }, 115 { 116 LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4", BindPort: 1234}, 117 ClusterConfiguration: kubeadmapi.ClusterConfiguration{ 118 ControlPlaneEndpoint: "api.k8s.io:4321", 119 CertificatesDir: pkidir, 120 }, 121 NodeRegistration: kubeadmapi.NodeRegistrationOptions{Name: "valid-node-name"}, 122 }, 123 } 124 125 for i, cfg := range cfgs { 126 var assertions = []struct { 127 kubeConfigFile string 128 clientName string 129 organizations []string 130 }{ 131 { 132 kubeConfigFile: kubeadmconstants.AdminKubeConfigFileName, 133 clientName: "kubernetes-admin", 134 organizations: []string{kubeadmconstants.ClusterAdminsGroupAndClusterRoleBinding}, 135 }, 136 { 137 kubeConfigFile: kubeadmconstants.SuperAdminKubeConfigFileName, 138 clientName: "kubernetes-super-admin", 139 organizations: []string{kubeadmconstants.SystemPrivilegedGroup}, 140 }, 141 { 142 kubeConfigFile: kubeadmconstants.KubeletKubeConfigFileName, 143 clientName: fmt.Sprintf("%s%s", kubeadmconstants.NodesUserPrefix, cfg.NodeRegistration.Name), 144 organizations: []string{kubeadmconstants.NodesGroup}, 145 }, 146 { 147 kubeConfigFile: kubeadmconstants.ControllerManagerKubeConfigFileName, 148 clientName: kubeadmconstants.ControllerManagerUser, 149 }, 150 { 151 kubeConfigFile: kubeadmconstants.SchedulerKubeConfigFileName, 152 clientName: kubeadmconstants.SchedulerUser, 153 }, 154 } 155 156 for _, assertion := range assertions { 157 t.Run(fmt.Sprintf("%d-%s", i, assertion.clientName), func(t *testing.T) { 158 // Executes getKubeConfigSpecs 159 specs, err := getKubeConfigSpecs(cfg) 160 if err != nil { 161 t.Fatal("getKubeConfigSpecs failed!") 162 } 163 164 var spec *kubeConfigSpec 165 var ok bool 166 167 // assert the spec for the kubeConfigFile exists 168 if spec, ok = specs[assertion.kubeConfigFile]; !ok { 169 t.Errorf("getKubeConfigSpecs didn't create spec for %s ", assertion.kubeConfigFile) 170 return 171 } 172 173 // Assert clientName 174 if spec.ClientName != assertion.clientName { 175 t.Errorf("getKubeConfigSpecs for %s clientName is %s, expected %s", assertion.kubeConfigFile, spec.ClientName, assertion.clientName) 176 } 177 178 // Assert Organizations 179 if spec.ClientCertAuth == nil || !reflect.DeepEqual(spec.ClientCertAuth.Organizations, assertion.organizations) { 180 t.Errorf("getKubeConfigSpecs for %s Organizations is %v, expected %v", assertion.kubeConfigFile, spec.ClientCertAuth.Organizations, assertion.organizations) 181 } 182 183 // Asserts InitConfiguration values injected into spec 184 controlPlaneEndpoint, err := kubeadmutil.GetControlPlaneEndpoint(cfg.ControlPlaneEndpoint, &cfg.LocalAPIEndpoint) 185 if err != nil { 186 t.Error(err) 187 } 188 localAPIEndpoint, err := kubeadmutil.GetLocalAPIEndpoint(&cfg.LocalAPIEndpoint) 189 if err != nil { 190 t.Error(err) 191 } 192 193 switch assertion.kubeConfigFile { 194 case kubeadmconstants.AdminKubeConfigFileName, kubeadmconstants.SuperAdminKubeConfigFileName, kubeadmconstants.KubeletKubeConfigFileName: 195 if spec.APIServer != controlPlaneEndpoint { 196 t.Errorf("expected getKubeConfigSpecs for %s to set cfg.APIServer to %s, got %s", 197 assertion.kubeConfigFile, controlPlaneEndpoint, spec.APIServer) 198 } 199 case kubeadmconstants.ControllerManagerKubeConfigFileName, kubeadmconstants.SchedulerKubeConfigFileName: 200 if spec.APIServer != localAPIEndpoint { 201 t.Errorf("expected getKubeConfigSpecs for %s to set cfg.APIServer to %s, got %s", 202 assertion.kubeConfigFile, localAPIEndpoint, spec.APIServer) 203 } 204 } 205 206 // Asserts CA certs and CA keys loaded into specs 207 if spec.CACert == nil { 208 t.Errorf("getKubeConfigSpecs didn't loaded CACert into spec for %s!", assertion.kubeConfigFile) 209 } 210 if spec.ClientCertAuth == nil || spec.ClientCertAuth.CAKey == nil { 211 t.Errorf("getKubeConfigSpecs didn't loaded CAKey into spec for %s!", assertion.kubeConfigFile) 212 } 213 }) 214 } 215 } 216 } 217 218 func TestBuildKubeConfigFromSpecWithClientAuth(t *testing.T) { 219 // Creates a CA 220 caCert, caKey := certstestutil.SetupCertificateAuthority(t) 221 222 notAfter, _ := time.Parse(time.RFC3339, "2026-01-02T15:04:05Z") 223 224 // Executes buildKubeConfigFromSpec passing a KubeConfigSpec with a ClientAuth 225 config := setupKubeConfigWithClientAuth(t, caCert, caKey, notAfter, "https://1.2.3.4:1234", "myClientName", "test-cluster", "myOrg1", "myOrg2") 226 227 // Asserts spec data are propagated to the kubeconfig 228 kubeconfigtestutil.AssertKubeConfigCurrentCluster(t, config, "https://1.2.3.4:1234", caCert) 229 kubeconfigtestutil.AssertKubeConfigCurrentAuthInfoWithClientCert(t, config, caCert, notAfter, "myClientName", "myOrg1", "myOrg2") 230 } 231 232 func TestBuildKubeConfigFromSpecWithTokenAuth(t *testing.T) { 233 // Creates a CA 234 caCert, _ := certstestutil.SetupCertificateAuthority(t) 235 236 // Executes buildKubeConfigFromSpec passing a KubeConfigSpec with a Token 237 config := setupKubeConfigWithTokenAuth(t, caCert, "https://1.2.3.4:1234", "myClientName", "123456", "test-cluster") 238 239 // Asserts spec data are propagated to the kubeconfig 240 kubeconfigtestutil.AssertKubeConfigCurrentCluster(t, config, "https://1.2.3.4:1234", caCert) 241 kubeconfigtestutil.AssertKubeConfigCurrentAuthInfoWithToken(t, config, "myClientName", "123456") 242 } 243 244 func TestCreateKubeConfigFileIfNotExists(t *testing.T) { 245 246 // Creates a CAs 247 caCert, caKey := certstestutil.SetupCertificateAuthority(t) 248 anotherCaCert, anotherCaKey := certstestutil.SetupCertificateAuthority(t) 249 250 notAfter, _ := time.Parse(time.RFC3339, "2026-01-02T15:04:05Z") 251 252 // build kubeconfigs (to be used to test kubeconfigs equality/not equality) 253 config := setupKubeConfigWithClientAuth(t, caCert, caKey, notAfter, "https://1.2.3.4:1234", "test-cluster", "myOrg1", "myOrg2") 254 configWithAnotherClusterCa := setupKubeConfigWithClientAuth(t, anotherCaCert, anotherCaKey, notAfter, "https://1.2.3.4:1234", "test-cluster", "myOrg1", "myOrg2") 255 configWithAnotherClusterAddress := setupKubeConfigWithClientAuth(t, caCert, caKey, notAfter, "https://3.4.5.6:3456", "myOrg1", "test-cluster", "myOrg2") 256 invalidConfig := setupKubeConfigWithClientAuth(t, caCert, caKey, notAfter, "https://1.2.3.4:1234", "test-cluster", "myOrg1", "myOrg2") 257 invalidConfig.CurrentContext = "invalid context" 258 259 var tests = []struct { 260 name string 261 existingKubeConfig *clientcmdapi.Config 262 kubeConfig *clientcmdapi.Config 263 expectedError bool 264 }{ 265 { // if there is no existing KubeConfig, creates the kubeconfig 266 name: "KubeConfig doesn't exist", 267 kubeConfig: config, 268 }, 269 { // if KubeConfig is invalid raise error 270 name: "KubeConfig is invalid", 271 existingKubeConfig: invalidConfig, 272 kubeConfig: invalidConfig, 273 expectedError: true, 274 }, 275 { // if KubeConfig is equal to the existingKubeConfig - refers to the same cluster -, use the existing (Test idempotency) 276 name: "KubeConfig refers to the same cluster", 277 existingKubeConfig: config, 278 kubeConfig: config, 279 }, 280 { // if KubeConfig is not equal to the existingKubeConfig - refers to the another cluster (a cluster with another Ca) -, raise error 281 name: "KubeConfig refers to the cluster with another CA", 282 existingKubeConfig: config, 283 kubeConfig: configWithAnotherClusterCa, 284 expectedError: true, 285 }, 286 { // if KubeConfig is not equal to the existingKubeConfig - tolerate custom server addresses 287 name: "KubeConfig referst to the cluster with another address", 288 existingKubeConfig: config, 289 kubeConfig: configWithAnotherClusterAddress, 290 }, 291 } 292 293 for _, test := range tests { 294 t.Run(test.name, func(t *testing.T) { 295 // Create temp folder for the test case 296 tmpdir := testutil.SetupTempDir(t) 297 defer os.RemoveAll(tmpdir) 298 299 // Writes the existing kubeconfig file to disk 300 if test.existingKubeConfig != nil { 301 if err := createKubeConfigFileIfNotExists(tmpdir, "test.conf", test.existingKubeConfig); err != nil { 302 t.Errorf("createKubeConfigFileIfNotExists failed") 303 } 304 } 305 306 // Writes the kubeconfig file to disk 307 err := createKubeConfigFileIfNotExists(tmpdir, "test.conf", test.kubeConfig) 308 if test.expectedError && err == nil { 309 t.Errorf("createKubeConfigFileIfNotExists didn't failed when expected to fail") 310 } 311 if !test.expectedError && err != nil { 312 t.Errorf("createKubeConfigFileIfNotExists failed") 313 } 314 315 // Assert that the created file is there 316 testutil.AssertFileExists(t, tmpdir, "test.conf") 317 }) 318 } 319 } 320 321 func TestCreateKubeconfigFilesAndWrappers(t *testing.T) { 322 var tests = []struct { 323 name string 324 createKubeConfigFunction func(outDir string, cfg *kubeadmapi.InitConfiguration) error 325 expectedFiles []string 326 expectedError bool 327 }{ 328 { // Test createKubeConfigFiles fails for unknown kubeconfig is requested 329 name: "createKubeConfigFiles", 330 createKubeConfigFunction: func(outDir string, cfg *kubeadmapi.InitConfiguration) error { 331 return createKubeConfigFiles(outDir, cfg, "unknown.conf") 332 }, 333 expectedError: true, 334 }, 335 { // Test CreateJoinControlPlaneKubeConfigFiles (wrapper to createKubeConfigFile) 336 name: "CreateJoinControlPlaneKubeConfigFiles", 337 createKubeConfigFunction: CreateJoinControlPlaneKubeConfigFiles, 338 expectedFiles: []string{ 339 kubeadmconstants.AdminKubeConfigFileName, 340 kubeadmconstants.ControllerManagerKubeConfigFileName, 341 kubeadmconstants.SchedulerKubeConfigFileName, 342 }, 343 }, 344 } 345 346 for _, test := range tests { 347 t.Run(test.name, func(t *testing.T) { 348 // Create temp folder for the test case 349 tmpdir := testutil.SetupTempDir(t) 350 defer os.RemoveAll(tmpdir) 351 352 // Adds a pki folder with a ca certs to the temp folder 353 pkidir := testutil.SetupPkiDirWithCertificateAuthority(t, tmpdir) 354 355 // Creates an InitConfiguration pointing to the pkidir folder 356 cfg := &kubeadmapi.InitConfiguration{ 357 LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4", BindPort: 1234}, 358 ClusterConfiguration: kubeadmapi.ClusterConfiguration{ 359 CertificatesDir: pkidir, 360 }, 361 } 362 363 // Execs the createKubeConfigFunction 364 err := test.createKubeConfigFunction(tmpdir, cfg) 365 if test.expectedError && err == nil { 366 t.Errorf("createKubeConfigFunction didn't failed when expected to fail") 367 return 368 } 369 if !test.expectedError && err != nil { 370 t.Errorf("createKubeConfigFunction failed") 371 return 372 } 373 374 // Assert expected files are there 375 testutil.AssertFileExists(t, tmpdir, test.expectedFiles...) 376 }) 377 } 378 } 379 380 func TestWriteKubeConfigFailsIfCADoesntExists(t *testing.T) { 381 // Temporary folders for the test case (without a CA) 382 tmpdir := testutil.SetupTempDir(t) 383 defer os.RemoveAll(tmpdir) 384 385 // Creates an InitConfiguration pointing to the tmpdir folder 386 cfg := &kubeadmapi.InitConfiguration{ 387 ClusterConfiguration: kubeadmapi.ClusterConfiguration{ 388 CertificatesDir: tmpdir, 389 }, 390 } 391 392 notAfter, _ := time.Parse(time.RFC3339, "2026-01-02T15:04:05Z") 393 394 var tests = []struct { 395 name string 396 writeKubeConfigFunction func(out io.Writer) error 397 }{ 398 { 399 name: "WriteKubeConfigWithClientCert", 400 writeKubeConfigFunction: func(out io.Writer) error { 401 return WriteKubeConfigWithClientCert(out, cfg, "myUser", []string{"myOrg"}, notAfter) 402 }, 403 }, 404 { 405 name: "WriteKubeConfigWithToken", 406 writeKubeConfigFunction: func(out io.Writer) error { 407 return WriteKubeConfigWithToken(out, cfg, "myUser", "12345", notAfter) 408 }, 409 }, 410 } 411 412 for _, test := range tests { 413 t.Run(test.name, func(t *testing.T) { 414 buf := new(bytes.Buffer) 415 416 // executes writeKubeConfigFunction 417 if err := test.writeKubeConfigFunction(buf); err == nil { 418 t.Error("writeKubeConfigFunction didnt failed when expected") 419 } 420 }) 421 } 422 } 423 424 func TestWriteKubeConfig(t *testing.T) { 425 // Temporary folders for the test case 426 tmpdir := testutil.SetupTempDir(t) 427 defer os.RemoveAll(tmpdir) 428 429 // Adds a pki folder with a ca cert to the temp folder 430 pkidir := testutil.SetupPkiDirWithCertificateAuthority(t, tmpdir) 431 432 // Retrieves ca cert for assertions 433 caCert, _, err := pkiutil.TryLoadCertAndKeyFromDisk(pkidir, kubeadmconstants.CACertAndKeyBaseName) 434 if err != nil { 435 t.Fatalf("couldn't retrieve ca cert: %v", err) 436 } 437 438 // Creates an InitConfiguration pointing to the pkidir folder 439 cfg := &kubeadmapi.InitConfiguration{ 440 LocalAPIEndpoint: kubeadmapi.APIEndpoint{AdvertiseAddress: "1.2.3.4", BindPort: 1234}, 441 ClusterConfiguration: kubeadmapi.ClusterConfiguration{ 442 CertificatesDir: pkidir, 443 CertificateValidityPeriod: &metav1.Duration{ 444 Duration: time.Hour * 10, 445 }, 446 }, 447 } 448 449 notAfter, _ := time.Parse(time.RFC3339, "2026-01-02T15:04:05Z") 450 451 var tests = []struct { 452 name string 453 writeKubeConfigFunction func(out io.Writer) error 454 withClientCert bool 455 withToken bool 456 }{ 457 { 458 name: "WriteKubeConfigWithClientCert", 459 writeKubeConfigFunction: func(out io.Writer) error { 460 return WriteKubeConfigWithClientCert(out, cfg, "myUser", []string{"myOrg"}, notAfter) 461 }, 462 withClientCert: true, 463 }, 464 { 465 name: "WriteKubeConfigWithToken", 466 writeKubeConfigFunction: func(out io.Writer) error { 467 return WriteKubeConfigWithToken(out, cfg, "myUser", "12345", notAfter) 468 }, 469 withToken: true, 470 }, 471 } 472 473 for _, test := range tests { 474 t.Run(test.name, func(t *testing.T) { 475 buf := new(bytes.Buffer) 476 477 // executes writeKubeConfigFunction 478 if err := test.writeKubeConfigFunction(buf); err != nil { 479 t.Error("writeKubeConfigFunction failed") 480 return 481 } 482 483 // reads kubeconfig written to stdout 484 config, err := clientcmd.Load(buf.Bytes()) 485 if err != nil { 486 t.Errorf("Couldn't read kubeconfig file from buffer: %v", err) 487 return 488 } 489 490 // checks that CLI flags are properly propagated 491 kubeconfigtestutil.AssertKubeConfigCurrentCluster(t, config, "https://1.2.3.4:1234", caCert) 492 493 if test.withClientCert { 494 // checks that kubeconfig files have expected client cert 495 kubeconfigtestutil.AssertKubeConfigCurrentAuthInfoWithClientCert(t, config, caCert, notAfter, "myUser", "myOrg") 496 } 497 498 if test.withToken { 499 // checks that kubeconfig files have expected token 500 kubeconfigtestutil.AssertKubeConfigCurrentAuthInfoWithToken(t, config, "myUser", "12345") 501 } 502 }) 503 } 504 } 505 506 func TestValidateKubeConfig(t *testing.T) { 507 caCert, caKey := certstestutil.SetupCertificateAuthority(t) 508 anotherCaCert, anotherCaKey := certstestutil.SetupCertificateAuthority(t) 509 510 notAfter, _ := time.Parse(time.RFC3339, "2026-01-02T15:04:05Z") 511 512 config := setupKubeConfigWithClientAuth(t, caCert, caKey, notAfter, "https://1.2.3.4:1234", "test-cluster", "myOrg1") 513 configWithAnotherClusterCa := setupKubeConfigWithClientAuth(t, anotherCaCert, anotherCaKey, notAfter, "https://1.2.3.4:1234", "test-cluster", "myOrg1") 514 configWithAnotherServerURL := setupKubeConfigWithClientAuth(t, caCert, caKey, notAfter, "https://4.3.2.1:4321", "test-cluster", "myOrg1") 515 516 configWithSameClusterCaByExternalFile := config.DeepCopy() 517 currentCtx, exists := configWithSameClusterCaByExternalFile.Contexts[configWithSameClusterCaByExternalFile.CurrentContext] 518 if !exists { 519 t.Fatal("failed to find CurrentContext in Contexts of the kubeconfig") 520 } 521 if configWithSameClusterCaByExternalFile.Clusters[currentCtx.Cluster] == nil { 522 t.Fatal("failed to find the given CurrentContext Cluster in Clusters of the kubeconfig") 523 } 524 tmpfile, err := os.CreateTemp("", "external-ca.crt") 525 if err != nil { 526 t.Fatal(err) 527 } 528 defer os.Remove(tmpfile.Name()) 529 if _, err := tmpfile.Write(pkiutil.EncodeCertPEM(caCert)); err != nil { 530 t.Fatal(err) 531 } 532 configWithSameClusterCaByExternalFile.Clusters[currentCtx.Cluster].CertificateAuthorityData = nil 533 configWithSameClusterCaByExternalFile.Clusters[currentCtx.Cluster].CertificateAuthority = tmpfile.Name() 534 535 // create a valid config but with whitespace around the CA PEM. 536 // validateKubeConfig() should tolerate that. 537 configWhitespace := config.DeepCopy() 538 configWhitespaceCtx := configWhitespace.Contexts[configWhitespace.CurrentContext] 539 configWhitespaceCA := string(configWhitespace.Clusters[configWhitespaceCtx.Cluster].CertificateAuthorityData) 540 configWhitespaceCA = "\n" + configWhitespaceCA + "\n" 541 configWhitespace.Clusters[configWhitespaceCtx.Cluster].CertificateAuthorityData = []byte(configWhitespaceCA) 542 543 tests := map[string]struct { 544 existingKubeConfig *clientcmdapi.Config 545 kubeConfig *clientcmdapi.Config 546 expectedError bool 547 }{ 548 "kubeconfig don't exist": { 549 kubeConfig: config, 550 expectedError: true, 551 }, 552 "kubeconfig exist and has invalid ca": { 553 existingKubeConfig: configWithAnotherClusterCa, 554 kubeConfig: config, 555 expectedError: true, 556 }, 557 "kubeconfig exist and has a different server url": { 558 existingKubeConfig: configWithAnotherServerURL, 559 kubeConfig: config, 560 }, 561 "kubeconfig exist and is valid": { 562 existingKubeConfig: config, 563 kubeConfig: config, 564 expectedError: false, 565 }, 566 "kubeconfig exist and is valid even if its CA contains whitespace": { 567 existingKubeConfig: configWhitespace, 568 kubeConfig: config, 569 expectedError: false, 570 }, 571 "kubeconfig exist and is valid even if its CA is provided as an external file": { 572 existingKubeConfig: configWithSameClusterCaByExternalFile, 573 kubeConfig: config, 574 expectedError: false, 575 }, 576 } 577 578 for name, test := range tests { 579 t.Run(name, func(t *testing.T) { 580 tmpdir := testutil.SetupTempDir(t) 581 defer os.RemoveAll(tmpdir) 582 583 if test.existingKubeConfig != nil { 584 if err := createKubeConfigFileIfNotExists(tmpdir, "test.conf", test.existingKubeConfig); err != nil { 585 t.Errorf("createKubeConfigFileIfNotExists failed") 586 } 587 } 588 589 err := validateKubeConfig(tmpdir, "test.conf", test.kubeConfig) 590 if (err != nil) != test.expectedError { 591 t.Fatalf(dedent.Dedent( 592 "validateKubeConfig failed\n%s\nexpected error: %t\n\tgot: %t\nerror: %v"), 593 name, 594 test.expectedError, 595 (err != nil), 596 err, 597 ) 598 } 599 }) 600 } 601 } 602 603 func TestValidateKubeconfigsForExternalCA(t *testing.T) { 604 tmpDir := testutil.SetupTempDir(t) 605 defer os.RemoveAll(tmpDir) 606 pkiDir := filepath.Join(tmpDir, "pki") 607 608 initConfig := &kubeadmapi.InitConfiguration{ 609 ClusterConfiguration: kubeadmapi.ClusterConfiguration{ 610 CertificatesDir: pkiDir, 611 }, 612 LocalAPIEndpoint: kubeadmapi.APIEndpoint{ 613 BindPort: 1234, 614 AdvertiseAddress: "1.2.3.4", 615 }, 616 } 617 618 // creates CA, write to pkiDir and remove ca.key to get into external CA condition 619 caCert, caKey := certstestutil.SetupCertificateAuthority(t) 620 if err := pkiutil.WriteCertAndKey(pkiDir, kubeadmconstants.CACertAndKeyBaseName, caCert, caKey); err != nil { 621 t.Fatalf("failure while saving CA certificate and key: %v", err) 622 } 623 if err := os.Remove(filepath.Join(pkiDir, kubeadmconstants.CAKeyName)); err != nil { 624 t.Fatalf("failure while deleting ca.key: %v", err) 625 } 626 627 notAfter, _ := time.Parse(time.RFC3339, "2026-01-02T15:04:05Z") 628 629 // create a valid config 630 config := setupKubeConfigWithClientAuth(t, caCert, caKey, notAfter, "https://1.2.3.4:1234", "test-cluster", "myOrg1") 631 632 // create a config with another CA 633 anotherCaCert, anotherCaKey := certstestutil.SetupCertificateAuthority(t) 634 configWithAnotherClusterCa := setupKubeConfigWithClientAuth(t, anotherCaCert, anotherCaKey, notAfter, "https://1.2.3.4:1234", "test-cluster", "myOrg1") 635 636 // create a config with another server URL 637 configWithAnotherServerURL := setupKubeConfigWithClientAuth(t, caCert, caKey, notAfter, "https://4.3.2.1:4321", "test-cluster", "myOrg1") 638 639 tests := map[string]struct { 640 filesToWrite map[string]*clientcmdapi.Config 641 initConfig *kubeadmapi.InitConfiguration 642 expectedError bool 643 }{ 644 "files don't exist": { 645 initConfig: initConfig, 646 expectedError: true, 647 }, 648 "some files don't exist": { 649 filesToWrite: map[string]*clientcmdapi.Config{ 650 kubeadmconstants.AdminKubeConfigFileName: config, 651 kubeadmconstants.SuperAdminKubeConfigFileName: config, 652 kubeadmconstants.KubeletKubeConfigFileName: config, 653 }, 654 initConfig: initConfig, 655 expectedError: true, 656 }, 657 "some files have invalid CA": { 658 filesToWrite: map[string]*clientcmdapi.Config{ 659 kubeadmconstants.AdminKubeConfigFileName: config, 660 kubeadmconstants.SuperAdminKubeConfigFileName: config, 661 kubeadmconstants.KubeletKubeConfigFileName: config, 662 kubeadmconstants.ControllerManagerKubeConfigFileName: configWithAnotherClusterCa, 663 kubeadmconstants.SchedulerKubeConfigFileName: config, 664 }, 665 initConfig: initConfig, 666 expectedError: true, 667 }, 668 "some files have a different Server URL": { 669 filesToWrite: map[string]*clientcmdapi.Config{ 670 kubeadmconstants.AdminKubeConfigFileName: config, 671 kubeadmconstants.SuperAdminKubeConfigFileName: config, 672 kubeadmconstants.KubeletKubeConfigFileName: config, 673 kubeadmconstants.ControllerManagerKubeConfigFileName: config, 674 kubeadmconstants.SchedulerKubeConfigFileName: configWithAnotherServerURL, 675 }, 676 initConfig: initConfig, 677 }, 678 "all files are valid": { 679 filesToWrite: map[string]*clientcmdapi.Config{ 680 kubeadmconstants.AdminKubeConfigFileName: config, 681 kubeadmconstants.SuperAdminKubeConfigFileName: config, 682 kubeadmconstants.KubeletKubeConfigFileName: config, 683 kubeadmconstants.ControllerManagerKubeConfigFileName: config, 684 kubeadmconstants.SchedulerKubeConfigFileName: config, 685 }, 686 initConfig: initConfig, 687 expectedError: false, 688 }, 689 } 690 691 for name, test := range tests { 692 t.Run(name, func(t *testing.T) { 693 tmpdir := testutil.SetupTempDir(t) 694 defer os.RemoveAll(tmpdir) 695 696 for name, config := range test.filesToWrite { 697 if err := createKubeConfigFileIfNotExists(tmpdir, name, config); err != nil { 698 t.Errorf("createKubeConfigFileIfNotExists failed: %v", err) 699 } 700 } 701 702 err := ValidateKubeconfigsForExternalCA(tmpdir, test.initConfig) 703 if (err != nil) != test.expectedError { 704 t.Fatalf(dedent.Dedent( 705 "ValidateKubeconfigsForExternalCA failed\n%s\nexpected error: %t\n\tgot: %t\nerror: %v"), 706 name, 707 test.expectedError, 708 (err != nil), 709 err, 710 ) 711 } 712 }) 713 } 714 } 715 716 // setupKubeConfigWithClientAuth is a test utility function that wraps buildKubeConfigFromSpec for building a KubeConfig object With ClientAuth 717 func setupKubeConfigWithClientAuth(t *testing.T, caCert *x509.Certificate, caKey crypto.Signer, notAfter time.Time, apiServer, clientName, clustername string, organizations ...string) *clientcmdapi.Config { 718 spec := &kubeConfigSpec{ 719 CACert: caCert, 720 APIServer: apiServer, 721 ClientName: clientName, 722 ClientCertAuth: &clientCertAuth{ 723 CAKey: caKey, 724 Organizations: organizations, 725 }, 726 ClientCertNotAfter: notAfter, 727 } 728 729 config, err := buildKubeConfigFromSpec(spec, clustername) 730 if err != nil { 731 t.Fatal("buildKubeConfigFromSpec failed!") 732 } 733 734 return config 735 } 736 737 // setupKubeConfigWithClientAuth is a test utility function that wraps buildKubeConfigFromSpec for building a KubeConfig object With Token 738 func setupKubeConfigWithTokenAuth(t *testing.T, caCert *x509.Certificate, apiServer, clientName, token, clustername string) *clientcmdapi.Config { 739 spec := &kubeConfigSpec{ 740 CACert: caCert, 741 APIServer: apiServer, 742 ClientName: clientName, 743 TokenAuth: &tokenAuth{ 744 Token: token, 745 }, 746 } 747 748 config, err := buildKubeConfigFromSpec(spec, clustername) 749 if err != nil { 750 t.Fatal("buildKubeConfigFromSpec failed!") 751 } 752 753 return config 754 } 755 756 func TestEnsureAdminClusterRoleBinding(t *testing.T) { 757 dir := testutil.SetupTempDir(t) 758 defer os.RemoveAll(dir) 759 760 cfg := testutil.GetDefaultInternalConfig(t) 761 cfg.CertificatesDir = dir 762 763 ca := certsphase.KubeadmCertRootCA() 764 _, _, err := ca.CreateAsCA(cfg) 765 if err != nil { 766 t.Fatal(err) 767 } 768 769 tests := []struct { 770 name string 771 expectedRBACError bool 772 expectedError bool 773 missingAdminConf bool 774 missingSuperAdminConf bool 775 }{ 776 { 777 name: "no errors", 778 }, 779 { 780 name: "expect RBAC error", 781 expectedRBACError: true, 782 expectedError: true, 783 }, 784 { 785 name: "admin.conf is missing", 786 missingAdminConf: true, 787 expectedError: true, 788 }, 789 { 790 name: "super-admin.conf is missing", 791 missingSuperAdminConf: true, 792 expectedError: false, // The file is optional. 793 }, 794 } 795 796 for _, tc := range tests { 797 t.Run(tc.name, func(t *testing.T) { 798 ensureRBACFunc := func(_ context.Context, adminClient clientset.Interface, superAdminClient clientset.Interface, 799 _ time.Duration, _ time.Duration) (clientset.Interface, error) { 800 801 if tc.expectedRBACError { 802 return nil, errors.New("ensureRBACFunc error") 803 } 804 return adminClient, nil 805 } 806 807 // Create the admin.conf and super-admin.conf so that EnsureAdminClusterRoleBinding 808 // can create clients from the files. 809 os.Remove(filepath.Join(dir, kubeadmconstants.AdminKubeConfigFileName)) 810 if !tc.missingAdminConf { 811 if err := CreateKubeConfigFile(kubeadmconstants.AdminKubeConfigFileName, dir, cfg); err != nil { 812 t.Fatal(err) 813 } 814 } 815 os.Remove(filepath.Join(dir, kubeadmconstants.SuperAdminKubeConfigFileName)) 816 if !tc.missingSuperAdminConf { 817 if err := CreateKubeConfigFile(kubeadmconstants.SuperAdminKubeConfigFileName, dir, cfg); err != nil { 818 t.Fatal(err) 819 } 820 } 821 822 client, err := EnsureAdminClusterRoleBinding(dir, ensureRBACFunc) 823 if (err != nil) != tc.expectedError { 824 t.Fatalf("expected error: %v, got: %v, error: %v", err != nil, tc.expectedError, err) 825 } 826 827 if err == nil && client == nil { 828 t.Fatal("got nil client") 829 } 830 }) 831 } 832 } 833 834 func TestEnsureAdminClusterRoleBindingImpl(t *testing.T) { 835 tests := []struct { 836 name string 837 setupAdminClient func(*clientsetfake.Clientset) 838 setupSuperAdminClient func(*clientsetfake.Clientset) 839 expectedError bool 840 }{ 841 { 842 name: "admin.conf: handle forbidden errors when the super-admin.conf client is nil", 843 setupAdminClient: func(client *clientsetfake.Clientset) { 844 client.PrependReactor("create", "clusterrolebindings", func(action clientgotesting.Action) (bool, runtime.Object, error) { 845 return true, nil, apierrors.NewForbidden( 846 schema.GroupResource{}, "name", errors.New("")) 847 }) 848 }, 849 expectedError: true, 850 }, 851 { 852 // A "create" call against a real server can return a forbidden error and a non-nil CRB 853 name: "admin.conf: handle forbidden error and returned CRBs, when the super-admin.conf client is nil", 854 setupAdminClient: func(client *clientsetfake.Clientset) { 855 client.PrependReactor("create", "clusterrolebindings", func(action clientgotesting.Action) (bool, runtime.Object, error) { 856 return true, &rbac.ClusterRoleBinding{}, apierrors.NewForbidden( 857 schema.GroupResource{}, "name", errors.New("")) 858 }) 859 }, 860 expectedError: true, 861 }, 862 { 863 name: "admin.conf: CRB already exists, use the admin.conf client", 864 setupAdminClient: func(client *clientsetfake.Clientset) { 865 client.PrependReactor("create", "clusterrolebindings", func(action clientgotesting.Action) (bool, runtime.Object, error) { 866 return true, nil, apierrors.NewAlreadyExists( 867 schema.GroupResource{}, "name") 868 }) 869 }, 870 setupSuperAdminClient: func(client *clientsetfake.Clientset) { 871 client.PrependReactor("create", "clusterrolebindings", func(action clientgotesting.Action) (bool, runtime.Object, error) { 872 return true, nil, apierrors.NewAlreadyExists( 873 schema.GroupResource{}, "name") 874 }) 875 }, 876 expectedError: false, 877 }, 878 { 879 name: "admin.conf: handle other errors, such as a server timeout", 880 setupAdminClient: func(client *clientsetfake.Clientset) { 881 client.PrependReactor("create", "clusterrolebindings", func(action clientgotesting.Action) (bool, runtime.Object, error) { 882 return true, nil, apierrors.NewServerTimeout( 883 schema.GroupResource{}, "create", 0) 884 }) 885 }, 886 expectedError: true, 887 }, 888 { 889 name: "admin.conf: CRB exists, return a client from admin.conf", 890 setupAdminClient: func(client *clientsetfake.Clientset) { 891 client.PrependReactor("create", "clusterrolebindings", func(action clientgotesting.Action) (bool, runtime.Object, error) { 892 return true, &rbac.ClusterRoleBinding{}, nil 893 }) 894 }, 895 expectedError: false, 896 }, 897 { 898 name: "super-admin.conf: error while creating CRB", 899 setupAdminClient: func(client *clientsetfake.Clientset) { 900 client.PrependReactor("create", "clusterrolebindings", func(action clientgotesting.Action) (bool, runtime.Object, error) { 901 return true, nil, apierrors.NewForbidden( 902 schema.GroupResource{}, "name", errors.New("")) 903 }) 904 }, 905 setupSuperAdminClient: func(client *clientsetfake.Clientset) { 906 client.PrependReactor("create", "clusterrolebindings", func(action clientgotesting.Action) (bool, runtime.Object, error) { 907 return true, nil, apierrors.NewServerTimeout( 908 schema.GroupResource{}, "create", 0) 909 }) 910 }, 911 expectedError: true, 912 }, 913 { 914 name: "super-admin.conf: admin.conf cannot create CRB, create CRB with super-admin.conf, return client from admin.conf", 915 setupAdminClient: func(client *clientsetfake.Clientset) { 916 client.PrependReactor("create", "clusterrolebindings", func(action clientgotesting.Action) (bool, runtime.Object, error) { 917 return true, nil, apierrors.NewForbidden( 918 schema.GroupResource{}, "name", errors.New("")) 919 }) 920 }, 921 setupSuperAdminClient: func(client *clientsetfake.Clientset) { 922 client.PrependReactor("create", "clusterrolebindings", func(action clientgotesting.Action) (bool, runtime.Object, error) { 923 return true, &rbac.ClusterRoleBinding{}, nil 924 }) 925 }, 926 expectedError: false, 927 }, 928 { 929 name: "super-admin.conf: admin.conf cannot create CRB, try to create CRB with super-admin.conf, encounter 'already exists' error", 930 setupAdminClient: func(client *clientsetfake.Clientset) { 931 client.PrependReactor("create", "clusterrolebindings", func(action clientgotesting.Action) (bool, runtime.Object, error) { 932 return true, nil, apierrors.NewForbidden( 933 schema.GroupResource{}, "name", errors.New("")) 934 }) 935 }, 936 setupSuperAdminClient: func(client *clientsetfake.Clientset) { 937 client.PrependReactor("create", "clusterrolebindings", func(action clientgotesting.Action) (bool, runtime.Object, error) { 938 return true, nil, apierrors.NewAlreadyExists( 939 schema.GroupResource{}, "name") 940 }) 941 }, 942 expectedError: false, 943 }, 944 } 945 946 for _, tc := range tests { 947 t.Run(tc.name, func(t *testing.T) { 948 adminClient := clientsetfake.NewSimpleClientset() 949 tc.setupAdminClient(adminClient) 950 951 var superAdminClient clientset.Interface // ensure superAdminClient is nil by default 952 if tc.setupSuperAdminClient != nil { 953 fakeSuperAdminClient := clientsetfake.NewSimpleClientset() 954 tc.setupSuperAdminClient(fakeSuperAdminClient) 955 superAdminClient = fakeSuperAdminClient 956 } 957 958 client, err := EnsureAdminClusterRoleBindingImpl( 959 context.Background(), adminClient, superAdminClient, 0, 0) 960 if (err != nil) != tc.expectedError { 961 t.Fatalf("expected error: %v, got %v, error: %v", tc.expectedError, err != nil, err) 962 } 963 964 if err == nil && client == nil { 965 t.Fatal("got nil client") 966 } 967 }) 968 } 969 } 970 971 func TestCreateKubeConfigAndCSR(t *testing.T) { 972 tmpDir := testutil.SetupTempDir(t) 973 testutil.SetupEmptyFiles(t, tmpDir, "testfile", "bar.csr", "bar.key") 974 defer func() { 975 if err := os.RemoveAll(tmpDir); err != nil { 976 t.Error(err) 977 } 978 }() 979 caCert, caKey := certstestutil.SetupCertificateAuthority(t) 980 981 type args struct { 982 kubeConfigDir string 983 kubeadmConfig *kubeadmapi.InitConfiguration 984 name string 985 spec *kubeConfigSpec 986 } 987 tests := []struct { 988 name string 989 args args 990 expectedError bool 991 }{ 992 { 993 name: "kubeadmConfig is nil", 994 args: args{ 995 kubeConfigDir: tmpDir, 996 kubeadmConfig: nil, 997 name: "foo", 998 spec: &kubeConfigSpec{ 999 CACert: caCert, 1000 APIServer: "10.0.0.1", 1001 ClientName: "foo", 1002 TokenAuth: &tokenAuth{Token: "test"}, 1003 ClientCertAuth: &clientCertAuth{CAKey: caKey}, 1004 }, 1005 }, 1006 expectedError: true, 1007 }, 1008 { 1009 name: "The kubeConfigDir is empty", 1010 args: args{ 1011 kubeConfigDir: "", 1012 kubeadmConfig: &kubeadmapi.InitConfiguration{}, 1013 name: "foo", 1014 spec: &kubeConfigSpec{ 1015 CACert: caCert, 1016 APIServer: "10.0.0.1", 1017 ClientName: "foo", 1018 TokenAuth: &tokenAuth{Token: "test"}, 1019 ClientCertAuth: &clientCertAuth{CAKey: caKey}, 1020 }, 1021 }, 1022 expectedError: true, 1023 }, 1024 { 1025 name: "The name is empty", 1026 args: args{ 1027 kubeConfigDir: tmpDir, 1028 kubeadmConfig: &kubeadmapi.InitConfiguration{}, 1029 name: "", 1030 spec: &kubeConfigSpec{ 1031 CACert: caCert, 1032 APIServer: "10.0.0.1", 1033 ClientName: "foo", 1034 TokenAuth: &tokenAuth{Token: "test"}, 1035 ClientCertAuth: &clientCertAuth{CAKey: caKey}, 1036 }, 1037 }, 1038 expectedError: true, 1039 }, 1040 { 1041 name: "The spec is empty", 1042 args: args{ 1043 kubeConfigDir: tmpDir, 1044 kubeadmConfig: &kubeadmapi.InitConfiguration{}, 1045 name: "foo", 1046 spec: nil, 1047 }, 1048 expectedError: true, 1049 }, 1050 { 1051 name: "The kubeconfig file already exists", 1052 args: args{ 1053 kubeConfigDir: tmpDir, 1054 kubeadmConfig: &kubeadmapi.InitConfiguration{}, 1055 name: "testfile", 1056 spec: &kubeConfigSpec{ 1057 CACert: caCert, 1058 APIServer: "10.0.0.1", 1059 ClientName: "foo", 1060 TokenAuth: &tokenAuth{Token: "test"}, 1061 ClientCertAuth: &clientCertAuth{CAKey: caKey}, 1062 }, 1063 }, 1064 expectedError: true, 1065 }, 1066 { 1067 name: "The CSR or key files already exists", 1068 args: args{ 1069 kubeConfigDir: tmpDir, 1070 kubeadmConfig: &kubeadmapi.InitConfiguration{}, 1071 name: "bar", 1072 spec: &kubeConfigSpec{ 1073 CACert: caCert, 1074 APIServer: "10.0.0.1", 1075 ClientName: "foo", 1076 TokenAuth: &tokenAuth{Token: "test"}, 1077 ClientCertAuth: &clientCertAuth{CAKey: caKey}, 1078 }, 1079 }, 1080 expectedError: true, 1081 }, 1082 { 1083 name: "configuration is valid, expect no errors", 1084 args: args{ 1085 kubeConfigDir: tmpDir, 1086 kubeadmConfig: &kubeadmapi.InitConfiguration{}, 1087 name: "test", 1088 spec: &kubeConfigSpec{ 1089 CACert: caCert, 1090 APIServer: "10.0.0.1", 1091 ClientName: "foo", 1092 TokenAuth: &tokenAuth{Token: "test"}, 1093 ClientCertAuth: &clientCertAuth{CAKey: caKey}, 1094 }, 1095 }, 1096 expectedError: false, 1097 }, 1098 } 1099 for _, tc := range tests { 1100 t.Run(tc.name, func(t *testing.T) { 1101 if err := createKubeConfigAndCSR(tc.args.kubeConfigDir, tc.args.kubeadmConfig, tc.args.name, tc.args.spec); (err != nil) != tc.expectedError { 1102 t.Errorf("createKubeConfigAndCSR() error = %v, wantErr %v", err, tc.expectedError) 1103 } 1104 }) 1105 } 1106 } 1107 1108 func TestCreateDefaultKubeConfigsAndCSRFiles(t *testing.T) { 1109 tmpDir := testutil.SetupTempDir(t) 1110 defer func() { 1111 if err := os.RemoveAll(tmpDir); err != nil { 1112 t.Error(err) 1113 } 1114 }() 1115 type args struct { 1116 kubeConfigDir string 1117 kubeadmConfig *kubeadmapi.InitConfiguration 1118 } 1119 tests := []struct { 1120 name string 1121 args args 1122 wantErr bool 1123 }{ 1124 { 1125 name: "kubeadmConfig is empty", 1126 args: args{ 1127 kubeConfigDir: tmpDir, 1128 kubeadmConfig: &kubeadmapi.InitConfiguration{}, 1129 }, 1130 wantErr: true, 1131 }, 1132 { 1133 name: "The APIEndpoint is invalid", 1134 args: args{ 1135 kubeConfigDir: tmpDir, 1136 kubeadmConfig: &kubeadmapi.InitConfiguration{ 1137 LocalAPIEndpoint: kubeadmapi.APIEndpoint{ 1138 AdvertiseAddress: "x.12.FOo.1", 1139 BindPort: 6443, 1140 }, 1141 }, 1142 }, 1143 wantErr: true, 1144 }, 1145 { 1146 name: "The APIEndpoint is valid", 1147 args: args{ 1148 kubeConfigDir: tmpDir, 1149 kubeadmConfig: &kubeadmapi.InitConfiguration{ 1150 LocalAPIEndpoint: kubeadmapi.APIEndpoint{ 1151 AdvertiseAddress: "127.0.0.1", 1152 BindPort: 6443, 1153 }, 1154 }, 1155 }, 1156 wantErr: false, 1157 }, 1158 } 1159 for _, tc := range tests { 1160 t.Run(tc.name, func(t *testing.T) { 1161 out := &bytes.Buffer{} 1162 if err := CreateDefaultKubeConfigsAndCSRFiles(out, tc.args.kubeConfigDir, tc.args.kubeadmConfig); (err != nil) != tc.wantErr { 1163 t.Errorf("CreateDefaultKubeConfigsAndCSRFiles() error = %v, wantErr %v", err, tc.wantErr) 1164 return 1165 } 1166 }) 1167 } 1168 }