Merge pull request #129006 from kokes/kubeadm_rereading_kubeconfigs

kubeadm: Do not read kubeconfig from disk repeatedly in the init phase
This commit is contained in:
Kubernetes Prow Robot 2024-12-12 05:28:38 +00:00 committed by GitHub
commit 1f415b4e13
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 50 additions and 35 deletions

View File

@ -28,6 +28,8 @@ import (
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/klog/v2" "k8s.io/klog/v2"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
@ -87,6 +89,7 @@ type initData struct {
cfg *kubeadmapi.InitConfiguration cfg *kubeadmapi.InitConfiguration
skipTokenPrint bool skipTokenPrint bool
dryRun bool dryRun bool
kubeconfig *clientcmdapi.Config
kubeconfigDir string kubeconfigDir string
kubeconfigPath string kubeconfigPath string
ignorePreflightErrors sets.Set[string] ignorePreflightErrors sets.Set[string]
@ -456,6 +459,21 @@ func (d *initData) CertificateDir() string {
return d.certificatesDir return d.certificatesDir
} }
// KubeConfig returns a kubeconfig after loading it from KubeConfigPath().
func (d *initData) KubeConfig() (*clientcmdapi.Config, error) {
if d.kubeconfig != nil {
return d.kubeconfig, nil
}
var err error
d.kubeconfig, err = clientcmd.LoadFromFile(d.KubeConfigPath())
if err != nil {
return nil, err
}
return d.kubeconfig, nil
}
// KubeConfigDir returns the path of the Kubernetes configuration folder or the temporary folder path in case of DryRun. // KubeConfigDir returns the path of the Kubernetes configuration folder or the temporary folder path in case of DryRun.
func (d *initData) KubeConfigDir() string { func (d *initData) KubeConfigDir() string {
if d.dryRun { if d.dryRun {
@ -536,7 +554,11 @@ func (d *initData) Client() (clientset.Interface, error) {
d.adminKubeConfigBootstrapped = true d.adminKubeConfigBootstrapped = true
} else { } else {
// Alternatively, just load the config pointed at the --kubeconfig path // Alternatively, just load the config pointed at the --kubeconfig path
d.client, err = kubeconfigutil.ClientSetFromFile(d.KubeConfigPath()) cfg, err := d.KubeConfig()
if err != nil {
return nil, err
}
d.client, err = kubeconfigutil.ToClientSet(cfg)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -72,6 +72,10 @@ func runBootstrapToken(c workflow.RunData) error {
if err != nil { if err != nil {
return err return err
} }
kubeconfig, err := data.KubeConfig()
if err != nil {
return err
}
if !data.SkipTokenPrint() { if !data.SkipTokenPrint() {
tokens := data.Tokens() tokens := data.Tokens()
@ -106,7 +110,7 @@ func runBootstrapToken(c workflow.RunData) error {
} }
// Create the cluster-info ConfigMap with the associated RBAC rules // Create the cluster-info ConfigMap with the associated RBAC rules
if err := clusterinfophase.CreateBootstrapConfigMapIfNotExists(client, data.KubeConfigPath()); err != nil { if err := clusterinfophase.CreateBootstrapConfigMapIfNotExists(client, kubeconfig); err != nil {
return errors.Wrap(err, "error creating bootstrap ConfigMap") return errors.Wrap(err, "error creating bootstrap ConfigMap")
} }
if err := clusterinfophase.CreateClusterInfoRBACRules(client); err != nil { if err := clusterinfophase.CreateClusterInfoRBACRules(client); err != nil {

View File

@ -22,6 +22,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
) )
@ -38,6 +39,7 @@ type InitData interface {
IgnorePreflightErrors() sets.Set[string] IgnorePreflightErrors() sets.Set[string]
CertificateWriteDir() string CertificateWriteDir() string
CertificateDir() string CertificateDir() string
KubeConfig() (*clientcmdapi.Config, error)
KubeConfigDir() string KubeConfigDir() string
KubeConfigPath() string KubeConfigPath() string
ManifestDir() string ManifestDir() string

View File

@ -22,6 +22,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
) )
@ -41,6 +42,7 @@ func (t *testInitData) SkipTokenPrint() bool { r
func (t *testInitData) IgnorePreflightErrors() sets.Set[string] { return nil } func (t *testInitData) IgnorePreflightErrors() sets.Set[string] { return nil }
func (t *testInitData) CertificateWriteDir() string { return "" } func (t *testInitData) CertificateWriteDir() string { return "" }
func (t *testInitData) CertificateDir() string { return "" } func (t *testInitData) CertificateDir() string { return "" }
func (t *testInitData) KubeConfig() (*clientcmdapi.Config, error) { return nil, nil }
func (t *testInitData) KubeConfigDir() string { return "" } func (t *testInitData) KubeConfigDir() string { return "" }
func (t *testInitData) KubeConfigPath() string { return "" } func (t *testInitData) KubeConfigPath() string { return "" }
func (t *testInitData) ManifestDir() string { return "" } func (t *testInitData) ManifestDir() string { return "" }

View File

@ -21,7 +21,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
rbac "k8s.io/api/rbac/v1" rbac "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authentication/user"
@ -40,19 +40,20 @@ const (
) )
// CreateBootstrapConfigMapIfNotExists creates the kube-public ConfigMap if it doesn't exist already // CreateBootstrapConfigMapIfNotExists creates the kube-public ConfigMap if it doesn't exist already
func CreateBootstrapConfigMapIfNotExists(client clientset.Interface, file string) error { func CreateBootstrapConfigMapIfNotExists(client clientset.Interface, kubeconfig *clientcmdapi.Config) error {
fmt.Printf("[bootstrap-token] Creating the %q ConfigMap in the %q namespace\n", bootstrapapi.ConfigMapClusterInfo, metav1.NamespacePublic) fmt.Printf("[bootstrap-token] Creating the %q ConfigMap in the %q namespace\n", bootstrapapi.ConfigMapClusterInfo, metav1.NamespacePublic)
klog.V(1).Infoln("[bootstrap-token] loading admin kubeconfig") // Clone the kubeconfig so that it's not mutated.
adminConfig, err := clientcmd.LoadFromFile(file) adminConfig := kubeconfig.DeepCopy()
if err != nil { if err := clientcmdapi.FlattenConfig(adminConfig); err != nil {
return errors.Wrap(err, "failed to load admin kubeconfig")
}
if err = clientcmdapi.FlattenConfig(adminConfig); err != nil {
return err return err
} }
if adminConfig.Contexts[adminConfig.CurrentContext] == nil {
return errors.New("invalid kubeconfig")
}
adminCluster := adminConfig.Contexts[adminConfig.CurrentContext].Cluster adminCluster := adminConfig.Contexts[adminConfig.CurrentContext].Cluster
// Copy the cluster from admin.conf to the bootstrap kubeconfig, contains the CA cert and the server URL // Copy the cluster from admin.conf to the bootstrap kubeconfig, contains the CA cert and the server URL
klog.V(1).Infoln("[bootstrap-token] copying the cluster from admin.conf to the bootstrap kubeconfig") klog.V(1).Infoln("[bootstrap-token] copying the cluster from admin.conf to the bootstrap kubeconfig")

View File

@ -17,8 +17,8 @@ limitations under the License.
package clusterinfo package clusterinfo
import ( import (
"bytes"
"context" "context"
"os"
"testing" "testing"
"text/template" "text/template"
"time" "time"
@ -31,6 +31,7 @@ import (
"k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authentication/user"
clientsetfake "k8s.io/client-go/kubernetes/fake" clientsetfake "k8s.io/client-go/kubernetes/fake"
core "k8s.io/client-go/testing" core "k8s.io/client-go/testing"
"k8s.io/client-go/tools/clientcmd"
bootstrapapi "k8s.io/cluster-bootstrap/token/api" bootstrapapi "k8s.io/cluster-bootstrap/token/api"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
@ -55,34 +56,24 @@ users:
func TestCreateBootstrapConfigMapIfNotExists(t *testing.T) { func TestCreateBootstrapConfigMapIfNotExists(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
fileExist bool
createErr error createErr error
expectErr bool expectErr bool
}{ }{
{ {
"successful case should have no error", "successful case should have no error",
true,
nil, nil,
false, false,
}, },
{ {
"if configmap already exists, return error", "if configmap already exists, return error",
true,
apierrors.NewAlreadyExists(schema.GroupResource{Resource: "configmaps"}, "test"), apierrors.NewAlreadyExists(schema.GroupResource{Resource: "configmaps"}, "test"),
true, true,
}, },
{ {
"unexpected error should be returned", "unexpected error should be returned",
true,
apierrors.NewUnauthorized("go away!"), apierrors.NewUnauthorized("go away!"),
true, true,
}, },
{
"if the file does not exist, return error",
false,
nil,
true,
},
} }
servers := []struct { servers := []struct {
@ -93,20 +84,12 @@ func TestCreateBootstrapConfigMapIfNotExists(t *testing.T) {
} }
for _, server := range servers { for _, server := range servers {
file, err := os.CreateTemp("", "") var buf bytes.Buffer
if err != nil {
t.Fatalf("could not create tempfile: %v", err)
}
defer os.Remove(file.Name())
if err := testConfigTempl.Execute(file, server); err != nil { if err := testConfigTempl.Execute(&buf, server); err != nil {
t.Fatalf("could not write to tempfile: %v", err) t.Fatalf("could not write to tempfile: %v", err)
} }
if err := file.Close(); err != nil {
t.Fatalf("could not close tempfile: %v", err)
}
// Override the default timeouts to be shorter // Override the default timeouts to be shorter
defaultTimeouts := kubeadmapi.GetActiveTimeouts() defaultTimeouts := kubeadmapi.GetActiveTimeouts()
defaultAPICallTimeout := defaultTimeouts.KubernetesAPICall defaultAPICallTimeout := defaultTimeouts.KubernetesAPICall
@ -124,11 +107,12 @@ func TestCreateBootstrapConfigMapIfNotExists(t *testing.T) {
}) })
} }
fileName := file.Name() kubeconfig, err := clientcmd.Load(buf.Bytes())
if !tc.fileExist { if err != nil {
fileName = "notexistfile" t.Fatal(err)
} }
err := CreateBootstrapConfigMapIfNotExists(client, fileName)
err = CreateBootstrapConfigMapIfNotExists(client, kubeconfig)
if tc.expectErr && err == nil { if tc.expectErr && err == nil {
t.Errorf("CreateBootstrapConfigMapIfNotExists(%s) wanted error, got nil", tc.name) t.Errorf("CreateBootstrapConfigMapIfNotExists(%s) wanted error, got nil", tc.name)
} else if !tc.expectErr && err != nil { } else if !tc.expectErr && err != nil {