sigs.k8s.io/cluster-api@v1.7.1/controlplane/kubeadm/internal/controllers/upgrade.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package controllers 18 19 import ( 20 "context" 21 22 "github.com/blang/semver/v4" 23 "github.com/pkg/errors" 24 ctrl "sigs.k8s.io/controller-runtime" 25 26 bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1" 27 controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1" 28 "sigs.k8s.io/cluster-api/controlplane/kubeadm/internal" 29 "sigs.k8s.io/cluster-api/util" 30 "sigs.k8s.io/cluster-api/util/collections" 31 "sigs.k8s.io/cluster-api/util/version" 32 ) 33 34 func (r *KubeadmControlPlaneReconciler) upgradeControlPlane( 35 ctx context.Context, 36 controlPlane *internal.ControlPlane, 37 machinesRequireUpgrade collections.Machines, 38 ) (ctrl.Result, error) { 39 logger := ctrl.LoggerFrom(ctx) 40 41 if controlPlane.KCP.Spec.RolloutStrategy == nil || controlPlane.KCP.Spec.RolloutStrategy.RollingUpdate == nil { 42 return ctrl.Result{}, errors.New("rolloutStrategy is not set") 43 } 44 45 // TODO: handle reconciliation of etcd members and kubeadm config in case they get out of sync with cluster 46 47 workloadCluster, err := controlPlane.GetWorkloadCluster(ctx) 48 if err != nil { 49 logger.Error(err, "failed to get remote client for workload cluster", "cluster key", util.ObjectKey(controlPlane.Cluster)) 50 return ctrl.Result{}, err 51 } 52 53 parsedVersion, err := semver.ParseTolerant(controlPlane.KCP.Spec.Version) 54 if err != nil { 55 return ctrl.Result{}, errors.Wrapf(err, "failed to parse kubernetes version %q", controlPlane.KCP.Spec.Version) 56 } 57 58 if err := workloadCluster.ReconcileKubeletRBACRole(ctx, parsedVersion); err != nil { 59 return ctrl.Result{}, errors.Wrap(err, "failed to reconcile the remote kubelet RBAC role") 60 } 61 62 if err := workloadCluster.ReconcileKubeletRBACBinding(ctx, parsedVersion); err != nil { 63 return ctrl.Result{}, errors.Wrap(err, "failed to reconcile the remote kubelet RBAC binding") 64 } 65 66 // Ensure kubeadm cluster role & bindings for v1.18+ 67 // as per https://github.com/kubernetes/kubernetes/commit/b117a928a6c3f650931bdac02a41fca6680548c4 68 if err := workloadCluster.AllowBootstrapTokensToGetNodes(ctx); err != nil { 69 return ctrl.Result{}, errors.Wrap(err, "failed to set role and role binding for kubeadm") 70 } 71 72 // Ensure kubeadm clusterRoleBinding for v1.29+ as per https://github.com/kubernetes/kubernetes/pull/121305 73 if err := workloadCluster.AllowClusterAdminPermissions(ctx, parsedVersion); err != nil { 74 return ctrl.Result{}, errors.Wrap(err, "failed to set cluster-admin ClusterRoleBinding for kubeadm") 75 } 76 77 kubeadmCMMutators := make([]func(*bootstrapv1.ClusterConfiguration), 0) 78 kubeadmCMMutators = append(kubeadmCMMutators, workloadCluster.UpdateKubernetesVersionInKubeadmConfigMap(parsedVersion)) 79 80 if controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration != nil { 81 // We intentionally only parse major/minor/patch so that the subsequent code 82 // also already applies to beta versions of new releases. 83 parsedVersionTolerant, err := version.ParseMajorMinorPatchTolerant(controlPlane.KCP.Spec.Version) 84 if err != nil { 85 return ctrl.Result{}, errors.Wrapf(err, "failed to parse kubernetes version %q", controlPlane.KCP.Spec.Version) 86 } 87 88 // Get the imageRepository or the correct value if nothing is set and a migration is necessary. 89 imageRepository := internal.ImageRepositoryFromClusterConfig(controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration, parsedVersionTolerant) 90 91 kubeadmCMMutators = append(kubeadmCMMutators, 92 workloadCluster.UpdateImageRepositoryInKubeadmConfigMap(imageRepository), 93 workloadCluster.UpdateFeatureGatesInKubeadmConfigMap(controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration.FeatureGates), 94 workloadCluster.UpdateAPIServerInKubeadmConfigMap(controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration.APIServer), 95 workloadCluster.UpdateControllerManagerInKubeadmConfigMap(controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration.ControllerManager), 96 workloadCluster.UpdateSchedulerInKubeadmConfigMap(controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration.Scheduler)) 97 98 // Etcd local and external are mutually exclusive and they cannot be switched, once set. 99 if controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration.Etcd.Local != nil { 100 kubeadmCMMutators = append(kubeadmCMMutators, 101 workloadCluster.UpdateEtcdLocalInKubeadmConfigMap(controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration.Etcd.Local)) 102 } else { 103 kubeadmCMMutators = append(kubeadmCMMutators, 104 workloadCluster.UpdateEtcdExternalInKubeadmConfigMap(controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration.Etcd.External)) 105 } 106 } 107 108 // collectively update Kubeadm config map 109 if err = workloadCluster.UpdateClusterConfiguration(ctx, parsedVersion, kubeadmCMMutators...); err != nil { 110 return ctrl.Result{}, err 111 } 112 113 if err := workloadCluster.UpdateKubeletConfigMap(ctx, parsedVersion); err != nil { 114 return ctrl.Result{}, errors.Wrap(err, "failed to upgrade kubelet config map") 115 } 116 117 switch controlPlane.KCP.Spec.RolloutStrategy.Type { 118 case controlplanev1.RollingUpdateStrategyType: 119 // RolloutStrategy is currently defaulted and validated to be RollingUpdate 120 // We can ignore MaxUnavailable because we are enforcing health checks before we get here. 121 maxNodes := *controlPlane.KCP.Spec.Replicas + int32(controlPlane.KCP.Spec.RolloutStrategy.RollingUpdate.MaxSurge.IntValue()) 122 if int32(controlPlane.Machines.Len()) < maxNodes { 123 // scaleUp ensures that we don't continue scaling up while waiting for Machines to have NodeRefs 124 return r.scaleUpControlPlane(ctx, controlPlane) 125 } 126 return r.scaleDownControlPlane(ctx, controlPlane, machinesRequireUpgrade) 127 default: 128 logger.Info("RolloutStrategy type is not set to RollingUpdateStrategyType, unable to determine the strategy for rolling out machines") 129 return ctrl.Result{}, nil 130 } 131 }