From 0aaa47808c9bc88e55cb05b84f538ee3a2eda691 Mon Sep 17 00:00:00 2001 From: Atanas Dinov Date: Mon, 22 Jul 2024 11:58:34 +0300 Subject: [PATCH] Support control plane only clusters (#14) * Support control plane only clusters Signed-off-by: Atanas Dinov * Drop unnecessary reconciliations Signed-off-by: Atanas Dinov --------- Signed-off-by: Atanas Dinov --- internal/controller/reconcile_kubernetes.go | 45 +++++++++++-------- internal/controller/upgradeplan_controller.go | 18 ++++++-- internal/upgrade/base.go | 2 +- internal/upgrade/kubernetes.go | 6 +-- 4 files changed, 44 insertions(+), 27 deletions(-) diff --git a/internal/controller/reconcile_kubernetes.go b/internal/controller/reconcile_kubernetes.go index 613f274..0629d80 100644 --- a/internal/controller/reconcile_kubernetes.go +++ b/internal/controller/reconcile_kubernetes.go @@ -8,7 +8,6 @@ import ( "github.com/suse-edge/upgrade-controller/internal/upgrade" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" ctrl "sigs.k8s.io/controller-runtime" @@ -22,16 +21,7 @@ func (r *UpgradePlanReconciler) reconcileKubernetes(ctx context.Context, upgrade return ctrl.Result{}, err } - return r.createPlan(ctx, upgradePlan, controlPlanePlan) - } - - workerPlan := upgrade.KubernetesWorkerPlan(kubernetesVersion) - if err := r.Get(ctx, client.ObjectKeyFromObject(workerPlan), workerPlan); err != nil { - if !errors.IsNotFound(err) { - return ctrl.Result{}, err - } - - return r.createPlan(ctx, upgradePlan, workerPlan) + return ctrl.Result{}, r.createPlan(ctx, upgradePlan, controlPlanePlan) } nodeList := &corev1.NodeList{} @@ -45,10 +35,20 @@ func (r *UpgradePlanReconciler) reconcileKubernetes(ctx context.Context, upgrade } if !isKubernetesUpgraded(nodeList, selector, kubernetesVersion) { - condition := metav1.Condition{Type: lifecyclev1alpha1.KubernetesUpgradedCondition, Status: metav1.ConditionFalse, Reason: lifecyclev1alpha1.UpgradeInProgress, Message: "Control plane nodes are being upgraded"} - meta.SetStatusCondition(&upgradePlan.Status.Conditions, condition) - + setInProgressCondition(upgradePlan, lifecyclev1alpha1.KubernetesUpgradedCondition, "Control plane nodes are being upgraded") return ctrl.Result{}, nil + } else if controlPlaneOnlyCluster(nodeList) { + setSuccessfulCondition(upgradePlan, lifecyclev1alpha1.KubernetesUpgradedCondition, "All cluster nodes are upgraded") + return ctrl.Result{Requeue: true}, nil + } + + workerPlan := upgrade.KubernetesWorkerPlan(kubernetesVersion) + if err = r.Get(ctx, client.ObjectKeyFromObject(workerPlan), workerPlan); err != nil { + if !errors.IsNotFound(err) { + return ctrl.Result{}, err + } + + return ctrl.Result{}, r.createPlan(ctx, upgradePlan, workerPlan) } selector, err = metav1.LabelSelectorAsSelector(workerPlan.Spec.NodeSelector) @@ -57,14 +57,11 @@ func (r *UpgradePlanReconciler) reconcileKubernetes(ctx context.Context, upgrade } if !isKubernetesUpgraded(nodeList, selector, kubernetesVersion) { - condition := metav1.Condition{Type: lifecyclev1alpha1.KubernetesUpgradedCondition, Status: metav1.ConditionFalse, Reason: lifecyclev1alpha1.UpgradeInProgress, Message: "Worker nodes are being upgraded"} - meta.SetStatusCondition(&upgradePlan.Status.Conditions, condition) + setInProgressCondition(upgradePlan, lifecyclev1alpha1.KubernetesUpgradedCondition, "Worker nodes are being upgraded") return ctrl.Result{}, nil } - condition := metav1.Condition{Type: lifecyclev1alpha1.KubernetesUpgradedCondition, Status: metav1.ConditionTrue, Reason: lifecyclev1alpha1.UpgradeSucceeded, Message: "All cluster nodes are upgraded"} - meta.SetStatusCondition(&upgradePlan.Status.Conditions, condition) - + setSuccessfulCondition(upgradePlan, lifecyclev1alpha1.KubernetesUpgradedCondition, "All cluster nodes are upgraded") return ctrl.Result{Requeue: true}, nil } @@ -93,3 +90,13 @@ func isKubernetesUpgraded(nodeList *corev1.NodeList, selector labels.Selector, k return true } + +func controlPlaneOnlyCluster(nodeList *corev1.NodeList) bool { + for _, node := range nodeList.Items { + if node.Labels[upgrade.ControlPlaneLabel] != "true" { + return false + } + } + + return true +} diff --git a/internal/controller/upgradeplan_controller.go b/internal/controller/upgradeplan_controller.go index 7c4b5c6..c0e20f3 100644 --- a/internal/controller/upgradeplan_controller.go +++ b/internal/controller/upgradeplan_controller.go @@ -103,18 +103,28 @@ func (r *UpgradePlanReconciler) recordCreatedPlan(upgradePlan *lifecyclev1alpha1 r.Recorder.Eventf(upgradePlan, corev1.EventTypeNormal, "PlanCreated", "Upgrade plan created: %s/%s", namespace, name) } -func (r *UpgradePlanReconciler) createPlan(ctx context.Context, upgradePlan *lifecyclev1alpha1.UpgradePlan, plan *upgradecattlev1.Plan) (ctrl.Result, error) { +func (r *UpgradePlanReconciler) createPlan(ctx context.Context, upgradePlan *lifecyclev1alpha1.UpgradePlan, plan *upgradecattlev1.Plan) error { if err := ctrl.SetControllerReference(upgradePlan, plan, r.Scheme); err != nil { - return ctrl.Result{}, fmt.Errorf("setting controller reference: %w", err) + return fmt.Errorf("setting controller reference: %w", err) } if err := r.Create(ctx, plan); err != nil { - return ctrl.Result{}, fmt.Errorf("creating upgrade plan: %w", err) + return fmt.Errorf("creating upgrade plan: %w", err) } r.recordCreatedPlan(upgradePlan, plan.Name, plan.Namespace) - return ctrl.Result{Requeue: true}, nil + return nil +} + +func setInProgressCondition(plan *lifecyclev1alpha1.UpgradePlan, conditionType, message string) { + condition := metav1.Condition{Type: conditionType, Status: metav1.ConditionFalse, Reason: lifecyclev1alpha1.UpgradeInProgress, Message: message} + meta.SetStatusCondition(&plan.Status.Conditions, condition) +} + +func setSuccessfulCondition(plan *lifecyclev1alpha1.UpgradePlan, conditionType, message string) { + condition := metav1.Condition{Type: conditionType, Status: metav1.ConditionTrue, Reason: lifecyclev1alpha1.UpgradeSucceeded, Message: message} + meta.SetStatusCondition(&plan.Status.Conditions, condition) } // SetupWithManager sets up the controller with the Manager. diff --git a/internal/upgrade/base.go b/internal/upgrade/base.go index d709017..321cee0 100644 --- a/internal/upgrade/base.go +++ b/internal/upgrade/base.go @@ -8,7 +8,7 @@ import ( const ( upgradeNamespace = "cattle-system" - controlPlaneLabel = "node-role.kubernetes.io/control-plane" + ControlPlaneLabel = "node-role.kubernetes.io/control-plane" ) func baseUpgradePlan(name string) *upgradecattlev1.Plan { diff --git a/internal/upgrade/kubernetes.go b/internal/upgrade/kubernetes.go index 0759875..fc9315f 100644 --- a/internal/upgrade/kubernetes.go +++ b/internal/upgrade/kubernetes.go @@ -30,7 +30,7 @@ func KubernetesControlPlanePlan(version string) *upgradecattlev1.Plan { controlPlanePlan.Spec.NodeSelector = &metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ { - Key: controlPlaneLabel, + Key: ControlPlaneLabel, Operator: "In", Values: []string{ "true", @@ -52,7 +52,7 @@ func KubernetesControlPlanePlan(version string) *upgradecattlev1.Plan { Effect: "NoExecute", }, { - Key: controlPlaneLabel, + Key: ControlPlaneLabel, Operator: "Equal", Value: "", Effect: "NoSchedule", @@ -80,7 +80,7 @@ func KubernetesWorkerPlan(version string) *upgradecattlev1.Plan { workerPlan.Spec.NodeSelector = &metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ { - Key: controlPlaneLabel, + Key: ControlPlaneLabel, Operator: "NotIn", Values: []string{ "true",