Skip to content

Commit cc9d571

Browse files
committed
feat: support single-node cluster node upgrades
Single-node clusters cannot survive node drains, so the node-upgrade plans need to be loosened. Signed-off-by: Zespre Chang <[email protected]>
1 parent 2ff4037 commit cc9d571

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

config/rbac/role.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ kind: ClusterRole
44
metadata:
55
name: manager-role
66
rules:
7+
- apiGroups:
8+
- ""
9+
resources:
10+
- nodes
11+
verbs:
12+
- get
13+
- list
14+
- watch
715
- apiGroups:
816
- management.harvesterhci.io
917
resources:

internal/controller/upgradeplan_controller.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
corev1 "k8s.io/api/core/v1"
3333
apierrors "k8s.io/apimachinery/pkg/api/errors"
3434
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35+
"k8s.io/apimachinery/pkg/labels"
3536
"k8s.io/apimachinery/pkg/runtime"
3637
"k8s.io/apimachinery/pkg/types"
3738
"k8s.io/utils/ptr"
@@ -122,6 +123,7 @@ type UpgradePlanReconciler struct {
122123
// +kubebuilder:rbac:groups=management.harvesterhci.io,resources=upgradeplans/status,verbs=get;update;patch
123124
// +kubebuilder:rbac:groups=management.harvesterhci.io,resources=upgradeplans/finalizers,verbs=update
124125
// +kubebuilder:rbac:groups=batch,namespace=harvester-system,resources=jobs,verbs=get;list;watch;create;update
126+
// +kubebuilder:rbac:groups=core,resources=nodes,verbs=get;list;watch
125127
// +kubebuilder:rbac:groups=upgrade.cattle.io,namespace=cattle-system,resources=plans,verbs=get;list;watch;create;update
126128

127129
// Reconcile is part of the main kubernetes reconciliation loop which aims to
@@ -347,6 +349,18 @@ func (r *UpgradePlanReconciler) finalize(ctx context.Context, upgradePlan *manag
347349
return ctrl.Result{}, nil
348350
}
349351

352+
func (r *UpgradePlanReconciler) isSingleNodeCluster(ctx context.Context) (bool, error) {
353+
var nodeList corev1.NodeList
354+
if err := r.List(ctx, &nodeList, &client.ListOptions{
355+
LabelSelector: labels.SelectorFromSet(labels.Set{
356+
harvesterManagedLabel: "true",
357+
}),
358+
}); err != nil {
359+
return false, err
360+
}
361+
return len(nodeList.Items) == 1, nil
362+
}
363+
350364
func (r *UpgradePlanReconciler) getOrCreatePlanForImagePreload(
351365
ctx context.Context,
352366
up *managementv1beta1.UpgradePlan,
@@ -387,10 +401,14 @@ func (r *UpgradePlanReconciler) getOrCreatePlanForNodeUpgrade(
387401
Namespace: cattleSystemNamespace,
388402
Name: fmt.Sprintf("%s-%s", up.Name, nodeComponent),
389403
}
404+
single, err := r.isSingleNodeCluster(ctx)
405+
if err != nil {
406+
return nil, err
407+
}
390408
return getOrCreate(
391409
ctx, r.Client, r.Scheme, nn,
392410
func() *upgradev1.Plan { return &upgradev1.Plan{} },
393-
func() *upgradev1.Plan { return constructPlanForNodeUpgrade(up) },
411+
func() *upgradev1.Plan { return constructPlanForNodeUpgrade(up, !single) },
394412
up,
395413
)
396414
}
@@ -628,7 +646,7 @@ func constructPlanForImagePreload(upgradePlan *managementv1beta1.UpgradePlan) *u
628646
return constructPlan(upgradePlan.Name, prepareComponent, 1, selector, false, container, version)
629647
}
630648

631-
func constructPlanForNodeUpgrade(upgradePlan *managementv1beta1.UpgradePlan) *upgradev1.Plan {
649+
func constructPlanForNodeUpgrade(upgradePlan *managementv1beta1.UpgradePlan, maintenance bool) *upgradev1.Plan {
632650
selector := &metav1.LabelSelector{
633651
MatchExpressions: []metav1.LabelSelectorRequirement{
634652
{
@@ -645,7 +663,7 @@ func constructPlanForNodeUpgrade(upgradePlan *managementv1beta1.UpgradePlan) *up
645663
}
646664
version := getKubernetesVersion(upgradePlan)
647665

648-
return constructPlan(upgradePlan.Name, nodeComponent, 1, selector, true, container, version)
666+
return constructPlan(upgradePlan.Name, nodeComponent, 1, selector, maintenance, container, version)
649667
}
650668

651669
func isJobFinished(job *batchv1.Job) (finished, success bool) {

0 commit comments

Comments
 (0)