diff --git a/controlplane/kubeadm/controllers/kubeadm_control_plane_controller.go b/controlplane/kubeadm/controllers/kubeadm_control_plane_controller.go index 05f70d96d9e5..0780360ef70f 100644 --- a/controlplane/kubeadm/controllers/kubeadm_control_plane_controller.go +++ b/controlplane/kubeadm/controllers/kubeadm_control_plane_controller.go @@ -352,6 +352,13 @@ func (r *KubeadmControlPlaneReconciler) upgradeControlPlane(ctx context.Context, return ctrl.Result{}, errors.Wrap(err, "failed to update the kubernetes version in the kubeadm config map") } + if kcp.Spec.KubeadmConfigSpec.ClusterConfiguration.Etcd.Local != nil { + meta := kcp.Spec.KubeadmConfigSpec.ClusterConfiguration.Etcd.Local.ImageMeta + if err := workloadCluster.UpdateEtcdVersionInKubeadmConfigMap(ctx, meta.ImageRepository, meta.ImageTag); err != nil { + return ctrl.Result{}, errors.Wrap(err, "failed to update the etcd version in the kubeadm config map") + } + } + if err := workloadCluster.UpdateKubeletConfigMap(ctx, parsedVersion); err != nil { return ctrl.Result{}, errors.Wrap(err, "failed to upgrade kubelet config map") } diff --git a/controlplane/kubeadm/internal/kubeadm_config_map.go b/controlplane/kubeadm/internal/kubeadm_config_map.go index f362547768e5..78678f2d60c0 100644 --- a/controlplane/kubeadm/internal/kubeadm_config_map.go +++ b/controlplane/kubeadm/internal/kubeadm_config_map.go @@ -82,6 +82,34 @@ func (k *kubeadmConfig) UpdateKubernetesVersion(version string) error { return nil } +// UpdateEtcdMeta sets the local etcd's configuration's image repository and image tag +func (k *kubeadmConfig) UpdateEtcdMeta(imageRepository, imageTag string) error { + data, ok := k.ConfigMap.Data[clusterConfigurationKey] + if !ok { + return errors.Errorf("could not find key %q in kubeadm config", clusterConfigurationKey) + } + configuration, err := yamlToUnstructured([]byte(data)) + if err != nil { + return errors.Wrap(err, "unable to convert YAML to unstructured") + } + if imageRepository != "" { + if err := unstructured.SetNestedField(configuration.UnstructuredContent(), imageRepository, "etcd", "local", "imageRepository"); err != nil { + return errors.Wrap(err, "unable to update image repository on kubeadm configmap") + } + } + if imageTag != "" { + if err := unstructured.SetNestedField(configuration.UnstructuredContent(), imageTag, "etcd", "local", "imageTag"); err != nil { + return errors.Wrap(err, "unable to update image repository on kubeadm configmap") + } + } + updated, err := yaml.Marshal(configuration) + if err != nil { + return errors.Wrap(err, "error encoding kubeadm cluster configuration object") + } + k.ConfigMap.Data[clusterConfigurationKey] = string(updated) + return nil +} + // yamlToUnstructured looks inside a config map for a specific key and extracts the embedded YAML into an // *unstructured.Unstructured. func yamlToUnstructured(rawYAML []byte) (*unstructured.Unstructured, error) { diff --git a/controlplane/kubeadm/internal/workload_cluster.go b/controlplane/kubeadm/internal/workload_cluster.go index 9860ffe930f1..9d91c112033d 100644 --- a/controlplane/kubeadm/internal/workload_cluster.go +++ b/controlplane/kubeadm/internal/workload_cluster.go @@ -62,6 +62,7 @@ type WorkloadCluster interface { ReconcileKubeletRBACBinding(ctx context.Context, version semver.Version) error ReconcileKubeletRBACRole(ctx context.Context, version semver.Version) error UpdateKubernetesVersionInKubeadmConfigMap(ctx context.Context, version string) error + UpdateEtcdVersionInKubeadmConfigMap(ctx context.Context, imageRepository, imageTag string) error UpdateKubeletConfigMap(ctx context.Context, version semver.Version) error RemoveEtcdMemberForMachine(ctx context.Context, machine *clusterv1.Machine) error RemoveMachineFromKubeadmConfigMap(ctx context.Context, machine *clusterv1.Machine) error @@ -257,6 +258,23 @@ func (w *Workload) EtcdIsHealthy(ctx context.Context) (HealthCheckResult, error) return response, nil } +// UpdateEtcdVersionInKubeadmConfigMap sets the imageRepository or the imageTag or both in the kubeadm config map. +func (w *Workload) UpdateEtcdVersionInKubeadmConfigMap(ctx context.Context, imageRepository, imageTag string) error { + configMapKey := ctrlclient.ObjectKey{Name: "kubeadm-config", Namespace: metav1.NamespaceSystem} + kubeadmConfigMap, err := w.getConfigMap(ctx, configMapKey) + if err != nil { + return err + } + config := &kubeadmConfig{ConfigMap: kubeadmConfigMap} + if err := config.UpdateEtcdMeta(imageRepository, imageTag); err != nil { + return err + } + if err := w.Client.Update(ctx, config.ConfigMap); err != nil { + return errors.Wrap(err, "error updating kubeadm ConfigMap") + } + return nil +} + // UpdateKubernetesVersionInKubeadmConfigMap updates the kubernetes version in the kubeadm config map. func (w *Workload) UpdateKubernetesVersionInKubeadmConfigMap(ctx context.Context, version string) error { configMapKey := ctrlclient.ObjectKey{Name: "kubeadm-config", Namespace: metav1.NamespaceSystem}