diff --git a/cmd/kubeadm/app/phases/addons/dns/dns.go b/cmd/kubeadm/app/phases/addons/dns/dns.go index 5e4355de025..179bc634ab0 100644 --- a/cmd/kubeadm/app/phases/addons/dns/dns.go +++ b/cmd/kubeadm/app/phases/addons/dns/dns.go @@ -273,12 +273,26 @@ func createCoreDNSAddon(deploymentBytes, serviceBytes, configBytes []byte, clien return errors.Wrap(err, "unable to fetch CoreDNS current installed version and ConfigMap.") } - var hasCoreDNSMigrationFailed bool - if IsCoreDNSConfigMapMigrationRequired(corefile) { + canMigrateCorefile, err := isCoreDNSVersionSupported(client) + if err != nil { + return err + } + + corefileMigrationRequired, err := isCoreDNSConfigMapMigrationRequired(corefile, currentInstalledCoreDNSVersion) + if err != nil { + return err + } + + if !canMigrateCorefile { + klog.Warningf("the CoreDNS Configuration will not be migrated due to unsupported version of CoreDNS. " + + "The existing CoreDNS Corefile configuration and deployment has been retained.") + } + + if corefileMigrationRequired && canMigrateCorefile { if err := migrateCoreDNSCorefile(client, coreDNSConfigMap, corefile, currentInstalledCoreDNSVersion); err != nil { // Errors in Corefile Migration is verified during preflight checks. This part will be executed when a user has chosen // to ignore preflight check errors. - hasCoreDNSMigrationFailed = true + canMigrateCorefile = false klog.Warningf("the CoreDNS Configuration was not migrated: %v. The existing CoreDNS Corefile configuration has been retained.", err) if err := apiclient.CreateOrRetainConfigMap(client, coreDNSConfigMap, kubeadmconstants.CoreDNSConfigMap); err != nil { return err @@ -326,7 +340,7 @@ func createCoreDNSAddon(deploymentBytes, serviceBytes, configBytes []byte, clien } // Create the deployment for CoreDNS or retain it in case the CoreDNS migration has failed during upgrade - if hasCoreDNSMigrationFailed { + if !canMigrateCorefile { if err := apiclient.CreateOrRetainDeployment(client, coreDNSDeployment, kubeadmconstants.CoreDNSDeploymentName); err != nil { return err } @@ -362,40 +376,57 @@ func createDNSService(dnsService *v1.Service, serviceBytes []byte, client client return nil } -// IsCoreDNSConfigMapMigrationRequired checks if a migration of the CoreDNS ConfigMap is required. -func IsCoreDNSConfigMapMigrationRequired(corefile string) bool { +// isCoreDNSConfigMapMigrationRequired checks if a migration of the CoreDNS ConfigMap is required. +func isCoreDNSConfigMapMigrationRequired(corefile, currentInstalledCoreDNSVersion string) (bool, error) { + var isMigrationRequired bool if corefile == "" || migration.Default("", corefile) { - return false + return isMigrationRequired, nil } - return true + deprecated, err := migration.Deprecated(currentInstalledCoreDNSVersion, kubeadmconstants.CoreDNSVersion, corefile) + if err != nil { + return isMigrationRequired, errors.Wrap(err, "unable to get list of changes to the configuration.") + } + + // Check if there are any plugins/options which needs to be removed or is a new default + for _, dep := range deprecated { + if dep.Severity == "removed" || dep.Severity == "newDefault" { + isMigrationRequired = true + } + } + + return isMigrationRequired, nil +} + +func isCoreDNSVersionSupported(client clientset.Interface) (bool, error) { + isValidVersion := true + coreDNSPodList, err := client.CoreV1().Pods(metav1.NamespaceSystem).List( + context.TODO(), + metav1.ListOptions{ + LabelSelector: "k8s-app=kube-dns", + }, + ) + if err != nil { + return false, errors.Wrap(err, "unable to list CoreDNS pods") + } + + for _, pod := range coreDNSPodList.Items { + imageID := strings.Split(pod.Status.ContainerStatuses[0].ImageID, ":") + if !migration.Released(imageID[2]) { + isValidVersion = false + } + } + + return isValidVersion, nil } func migrateCoreDNSCorefile(client clientset.Interface, cm *v1.ConfigMap, corefile, currentInstalledCoreDNSVersion string) error { - // Take a copy of the Corefile data as `Corefile-backup` and update the ConfigMap - // Also point the CoreDNS deployment to the `Corefile-backup` data. - - if _, err := client.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Update(context.TODO(), &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: kubeadmconstants.CoreDNSConfigMap, - Namespace: metav1.NamespaceSystem, - }, - Data: map[string]string{ - "Corefile": corefile, - "Corefile-backup": corefile, - }, - }, metav1.UpdateOptions{}); err != nil { - return errors.Wrap(err, "unable to update the CoreDNS ConfigMap with backup Corefile") - } - if err := patchCoreDNSDeployment(client, "Corefile-backup"); err != nil { - return err - } - // Since the current configuration present is not the default version, try and migrate it. updatedCorefile, err := migration.Migrate(currentInstalledCoreDNSVersion, kubeadmconstants.CoreDNSVersion, corefile, false) if err != nil { return errors.Wrap(err, "unable to migrate CoreDNS ConfigMap") } + // Take a copy of the existing Corefile data as `Corefile-backup` and update the ConfigMap if _, err := client.CoreV1().ConfigMaps(cm.ObjectMeta.Namespace).Update(context.TODO(), &v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: kubeadmconstants.CoreDNSConfigMap, @@ -408,6 +439,12 @@ func migrateCoreDNSCorefile(client clientset.Interface, cm *v1.ConfigMap, corefi }, metav1.UpdateOptions{}); err != nil { return errors.Wrap(err, "unable to update the CoreDNS ConfigMap") } + + // Point the CoreDNS deployment to the `Corefile-backup` data. + if err := setCorefile(client, "Corefile-backup"); err != nil { + return err + } + fmt.Println("[addons] Migrating CoreDNS Corefile") changes, err := migration.Deprecated(currentInstalledCoreDNSVersion, kubeadmconstants.CoreDNSVersion, corefile) if err != nil { @@ -445,12 +482,12 @@ func GetCoreDNSInfo(client clientset.Interface) (*v1.ConfigMap, string, string, return coreDNSConfigMap, corefile, currentCoreDNSversion, nil } -func patchCoreDNSDeployment(client clientset.Interface, coreDNSCorefileName string) error { +func setCorefile(client clientset.Interface, coreDNSCorefileName string) error { dnsDeployment, err := client.AppsV1().Deployments(metav1.NamespaceSystem).Get(context.TODO(), kubeadmconstants.CoreDNSDeploymentName, metav1.GetOptions{}) if err != nil { return err } - patch := fmt.Sprintf(`{"spec":{"template":{"spec":{"volumes":[{"name": "config-volume", "configMap":{"name": "coredns", "items":[{"key": "%s", "path": "%s"}]}}]}}}}`, coreDNSCorefileName, coreDNSCorefileName) + patch := fmt.Sprintf(`{"spec":{"template":{"spec":{"volumes":[{"name": "config-volume", "configMap":{"name": "coredns", "items":[{"key": "%s", "path": "Corefile"}]}}]}}}}`, coreDNSCorefileName) if _, err := client.AppsV1().Deployments(dnsDeployment.ObjectMeta.Namespace).Patch(context.TODO(), dnsDeployment.Name, types.StrategicMergePatchType, []byte(patch), metav1.PatchOptions{}); err != nil { return errors.Wrap(err, "unable to patch the CoreDNS deployment")