sigs.k8s.io/cluster-api@v1.6.3/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 controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1" 27 "sigs.k8s.io/cluster-api/controlplane/kubeadm/internal" 28 "sigs.k8s.io/cluster-api/util" 29 "sigs.k8s.io/cluster-api/util/collections" 30 "sigs.k8s.io/cluster-api/util/version" 31 ) 32 33 func (r *KubeadmControlPlaneReconciler) upgradeControlPlane( 34 ctx context.Context, 35 controlPlane *internal.ControlPlane, 36 machinesRequireUpgrade collections.Machines, 37 ) (ctrl.Result, error) { 38 logger := ctrl.LoggerFrom(ctx) 39 40 if controlPlane.KCP.Spec.RolloutStrategy == nil || controlPlane.KCP.Spec.RolloutStrategy.RollingUpdate == nil { 41 return ctrl.Result{}, errors.New("rolloutStrategy is not set") 42 } 43 44 // TODO: handle reconciliation of etcd members and kubeadm config in case they get out of sync with cluster 45 46 workloadCluster, err := controlPlane.GetWorkloadCluster(ctx) 47 if err != nil { 48 logger.Error(err, "failed to get remote client for workload cluster", "cluster key", util.ObjectKey(controlPlane.Cluster)) 49 return ctrl.Result{}, err 50 } 51 52 parsedVersion, err := semver.ParseTolerant(controlPlane.KCP.Spec.Version) 53 if err != nil { 54 return ctrl.Result{}, errors.Wrapf(err, "failed to parse kubernetes version %q", controlPlane.KCP.Spec.Version) 55 } 56 57 if err := workloadCluster.ReconcileKubeletRBACRole(ctx, parsedVersion); err != nil { 58 return ctrl.Result{}, errors.Wrap(err, "failed to reconcile the remote kubelet RBAC role") 59 } 60 61 if err := workloadCluster.ReconcileKubeletRBACBinding(ctx, parsedVersion); err != nil { 62 return ctrl.Result{}, errors.Wrap(err, "failed to reconcile the remote kubelet RBAC binding") 63 } 64 65 // Ensure kubeadm cluster role & bindings for v1.18+ 66 // as per https://github.com/kubernetes/kubernetes/commit/b117a928a6c3f650931bdac02a41fca6680548c4 67 if err := workloadCluster.AllowBootstrapTokensToGetNodes(ctx); err != nil { 68 return ctrl.Result{}, errors.Wrap(err, "failed to set role and role binding for kubeadm") 69 } 70 71 // Ensure kubeadm clusterRoleBinding for v1.29+ as per https://github.com/kubernetes/kubernetes/pull/121305 72 if err := workloadCluster.AllowClusterAdminPermissions(ctx, parsedVersion); err != nil { 73 return ctrl.Result{}, errors.Wrap(err, "failed to set cluster-admin ClusterRoleBinding for kubeadm") 74 } 75 76 if err := workloadCluster.UpdateKubernetesVersionInKubeadmConfigMap(ctx, parsedVersion); err != nil { 77 return ctrl.Result{}, errors.Wrap(err, "failed to update the kubernetes version in the kubeadm config map") 78 } 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 // Get the imageRepository or the correct value if nothing is set and a migration is necessary. 88 imageRepository := internal.ImageRepositoryFromClusterConfig(controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration, parsedVersionTolerant) 89 90 if err := workloadCluster.UpdateImageRepositoryInKubeadmConfigMap(ctx, imageRepository, parsedVersion); err != nil { 91 return ctrl.Result{}, errors.Wrap(err, "failed to update the image repository in the kubeadm config map") 92 } 93 } 94 95 if controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration != nil && controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration.Etcd.Local != nil { 96 meta := controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration.Etcd.Local.ImageMeta 97 if err := workloadCluster.UpdateEtcdVersionInKubeadmConfigMap(ctx, meta.ImageRepository, meta.ImageTag, parsedVersion); err != nil { 98 return ctrl.Result{}, errors.Wrap(err, "failed to update the etcd version in the kubeadm config map") 99 } 100 101 extraArgs := controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration.Etcd.Local.ExtraArgs 102 if err := workloadCluster.UpdateEtcdExtraArgsInKubeadmConfigMap(ctx, extraArgs, parsedVersion); err != nil { 103 return ctrl.Result{}, errors.Wrap(err, "failed to update the etcd extra args in the kubeadm config map") 104 } 105 } 106 107 if controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration != nil { 108 if err := workloadCluster.UpdateAPIServerInKubeadmConfigMap(ctx, controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration.APIServer, parsedVersion); err != nil { 109 return ctrl.Result{}, errors.Wrap(err, "failed to update api server in the kubeadm config map") 110 } 111 112 if err := workloadCluster.UpdateControllerManagerInKubeadmConfigMap(ctx, controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration.ControllerManager, parsedVersion); err != nil { 113 return ctrl.Result{}, errors.Wrap(err, "failed to update controller manager in the kubeadm config map") 114 } 115 116 if err := workloadCluster.UpdateSchedulerInKubeadmConfigMap(ctx, controlPlane.KCP.Spec.KubeadmConfigSpec.ClusterConfiguration.Scheduler, parsedVersion); err != nil { 117 return ctrl.Result{}, errors.Wrap(err, "failed to update scheduler in the kubeadm config map") 118 } 119 } 120 121 if err := workloadCluster.UpdateKubeletConfigMap(ctx, parsedVersion); err != nil { 122 return ctrl.Result{}, errors.Wrap(err, "failed to upgrade kubelet config map") 123 } 124 125 switch controlPlane.KCP.Spec.RolloutStrategy.Type { 126 case controlplanev1.RollingUpdateStrategyType: 127 // RolloutStrategy is currently defaulted and validated to be RollingUpdate 128 // We can ignore MaxUnavailable because we are enforcing health checks before we get here. 129 maxNodes := *controlPlane.KCP.Spec.Replicas + int32(controlPlane.KCP.Spec.RolloutStrategy.RollingUpdate.MaxSurge.IntValue()) 130 if int32(controlPlane.Machines.Len()) < maxNodes { 131 // scaleUp ensures that we don't continue scaling up while waiting for Machines to have NodeRefs 132 return r.scaleUpControlPlane(ctx, controlPlane) 133 } 134 return r.scaleDownControlPlane(ctx, controlPlane, machinesRequireUpgrade) 135 default: 136 logger.Info("RolloutStrategy type is not set to RollingUpdateStrategyType, unable to determine the strategy for rolling out machines") 137 return ctrl.Result{}, nil 138 } 139 }