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  }