From e51b55b45110d7276cbe65ce789c37e2515880a4 Mon Sep 17 00:00:00 2001 From: Christian Schlotter Date: Fri, 28 Jun 2024 13:31:26 +0200 Subject: [PATCH] kubeadm: feature gate ControlPlaneKubeletLocalMode on upgrade --- .../cmd/phases/upgrade/node/controlplane.go | 7 +++ cmd/kubeadm/app/phases/upgrade/postupgrade.go | 58 +++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/cmd/kubeadm/app/cmd/phases/upgrade/node/controlplane.go b/cmd/kubeadm/app/cmd/phases/upgrade/node/controlplane.go index cbdca3ec1c6..330d89b9823 100644 --- a/cmd/kubeadm/app/cmd/phases/upgrade/node/controlplane.go +++ b/cmd/kubeadm/app/cmd/phases/upgrade/node/controlplane.go @@ -24,6 +24,7 @@ import ( "k8s.io/kubernetes/cmd/kubeadm/app/cmd/options" "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow" + "k8s.io/kubernetes/cmd/kubeadm/app/features" "k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade" "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" ) @@ -82,6 +83,12 @@ func runControlPlane() func(c workflow.RunData) error { return errors.Wrap(err, "failed to perform addons upgrade") } + if features.Enabled(cfg.FeatureGates, features.ControlPlaneKubeletLocalMode) { + if err := upgrade.UpdateKubeletLocalMode(cfg, dryRun); err != nil { + return errors.Wrap(err, "failed to update kubelet local mode") + } + } + fmt.Println("[upgrade] The control plane instance for this node was successfully updated!") return nil diff --git a/cmd/kubeadm/app/phases/upgrade/postupgrade.go b/cmd/kubeadm/app/phases/upgrade/postupgrade.go index 02e7bcca618..b7d15f41b93 100644 --- a/cmd/kubeadm/app/phases/upgrade/postupgrade.go +++ b/cmd/kubeadm/app/phases/upgrade/postupgrade.go @@ -31,10 +31,12 @@ import ( errorsutil "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" clientset "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" "k8s.io/klog/v2" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" + "k8s.io/kubernetes/cmd/kubeadm/app/features" "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns" "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy" "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/clusterinfo" @@ -109,6 +111,12 @@ func PerformPostUpgradeTasks(client clientset.Interface, cfg *kubeadmapi.InitCon errs = append(errs, err) } + if features.Enabled(cfg.FeatureGates, features.ControlPlaneKubeletLocalMode) { + if err := UpdateKubeletLocalMode(cfg, dryRun); err != nil { + return errors.Wrap(err, "failed to update kubelet local mode") + } + } + return errorsutil.NewAggregate(errs) } @@ -281,3 +289,53 @@ func GetKubeletDir(dryRun bool) (string, error) { } return kubeadmconstants.KubeletRunDirectory, nil } + +func UpdateKubeletLocalMode(cfg *kubeadmapi.InitConfiguration, dryRun bool) error { + // TODO(chrischdi): how to get the correct dir? kubeadm init has a flag to change the location + dir := kubeadmconstants.KubernetesDir + + kubeletKubeConfigFilePath := filepath.Join(dir, kubeadmconstants.KubeletKubeConfigFileName) + + if _, err := os.Stat(kubeletKubeConfigFilePath); err != nil { + if os.IsNotExist(err) { + // TODO(chrischdi): should we print a warning or even return the error? + return nil + } + return err + } + + config, err := clientcmd.LoadFromFile(kubeletKubeConfigFilePath) + if err != nil { + return err + } + + configContext, ok := config.Contexts[config.CurrentContext] + if !ok { + return errors.Errorf("cannot find cluster for active context in kubeconfig %q", kubeletKubeConfigFilePath) + } + + localAPIEndpoint, err := kubeadmutil.GetLocalAPIEndpoint(&cfg.LocalAPIEndpoint) + if err != nil { + return err + } + + // Skip changing kubeconfig file if LocalAPIEndpoint is already set. + if config.Clusters[configContext.Cluster].Server == localAPIEndpoint { + return nil + } + + if dryRun { + fmt.Printf("[dryrun] Would change the server url from %q to %q in %s and try to restart kubelet\n", localAPIEndpoint, config.Clusters[configContext.Cluster].Server, kubeletKubeConfigFilePath) + return nil + } + + config.Clusters[configContext.Cluster].Server = localAPIEndpoint + + if err := clientcmd.WriteToFile(*config, kubeletKubeConfigFilePath); err != nil { + return err + } + + kubeletphase.TryRestartKubelet() + + return nil +}