Skip to content

Commit 27d087f

Browse files
Chained upgrades
1 parent 4429cb3 commit 27d087f

37 files changed

+4214
-880
lines changed

api/core/v1beta1/conversion.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ func (src *ClusterClass) ConvertTo(dstRaw conversion.Hub) error {
248248
dst.Status.Variables[i] = variable
249249
}
250250

251+
dst.Spec.KubernetesVersions = restored.Spec.KubernetesVersions
252+
251253
return nil
252254
}
253255

api/core/v1beta1/zz_generated.conversion.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/core/v1beta2/clusterclass_types.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,18 @@ type ClusterClassSpec struct {
135135
// +kubebuilder:validation:MinItems=1
136136
// +kubebuilder:validation:MaxItems=1000
137137
Patches []ClusterClassPatch `json:"patches,omitempty"`
138+
139+
// kubernetesVersions is the list of Kubernetes versions that can be
140+
// used for clusters using this ClusterClass.
141+
// The list of version must be ordered from the older to the newer version, and there should be
142+
// at least one version for every minor in between the first and the last version.
143+
// +optional
144+
// +listType=atomic
145+
// +kubebuilder:validation:MinItems=1
146+
// +kubebuilder:validation:MaxItems=100
147+
// +kubebuilder:validation:items:MinLength=1
148+
// +kubebuilder:validation:items:MaxLength=256
149+
KubernetesVersions []string `json:"kubernetesVersions,omitempty"`
138150
}
139151

140152
// InfrastructureClass defines the class for the infrastructure cluster.

api/core/v1beta2/common_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ const (
3636
// to track the name of the MachineDeployment topology it represents.
3737
ClusterTopologyMachineDeploymentNameLabel = "topology.cluster.x-k8s.io/deployment-name"
3838

39+
// ClusterTopologyControlPlaneUpgradeStepAnnotation tracks version current upgrade step.
40+
// NOTE: The annotation exists only during upgrades.
41+
ClusterTopologyControlPlaneUpgradeStepAnnotation = "topology.cluster.x-k8s.io/upgrade-step"
42+
3943
// ClusterTopologyHoldUpgradeSequenceAnnotation can be used to hold the entire MachineDeployment upgrade sequence.
4044
// If the annotation is set on a MachineDeployment topology in Cluster.spec.topology.workers, the Kubernetes upgrade
4145
// for this MachineDeployment topology and all subsequent ones is deferred.

api/core/v1beta2/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/core/v1beta2/zz_generated.openapi.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/cluster.x-k8s.io_clusterclasses.yaml

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

controlplane/kubeadm/internal/controllers/scale.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,16 @@ func (r *KubeadmControlPlaneReconciler) preflightChecks(ctx context.Context, con
185185

186186
if feature.Gates.Enabled(feature.ClusterTopology) {
187187
// Block when we expect an upgrade to be propagated for topology clusters.
188-
if controlPlane.Cluster.Spec.Topology.IsDefined() && controlPlane.Cluster.Spec.Topology.Version != controlPlane.KCP.Spec.Version {
188+
// NOTE: in case the cluster is performing an upgrade, allow creation of machines for the intermediate step.
189+
isUpgradeForVersion := false
190+
if versions, ok := controlPlane.Cluster.GetAnnotations()[clusterv1.ClusterTopologyControlPlaneUpgradeStepAnnotation]; ok {
191+
v := strings.Split(versions, ",")
192+
if len(v) > 0 {
193+
isUpgradeForVersion = strings.TrimSpace(v[0]) == controlPlane.KCP.Spec.Version
194+
}
195+
}
196+
197+
if controlPlane.Cluster.Spec.Topology.IsDefined() && controlPlane.Cluster.Spec.Topology.Version != controlPlane.KCP.Spec.Version && !isUpgradeForVersion {
189198
logger.Info(fmt.Sprintf("Waiting for a version upgrade to %s to be propagated from Cluster.spec.topology", controlPlane.Cluster.Spec.Topology.Version))
190199
controlPlane.PreflightCheckResults.TopologyVersionMismatch = true
191200
return ctrl.Result{RequeueAfter: preflightFailedRequeueAfter}, nil

controlplane/kubeadm/internal/controllers/scale_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,37 @@ func TestPreflightChecks(t *testing.T) {
562562
TopologyVersionMismatch: true,
563563
},
564564
},
565+
{
566+
name: "control plane with a pending upgrade, but not yet at the current step of the upgrade plan, should requeue",
567+
cluster: &clusterv1.Cluster{
568+
ObjectMeta: metav1.ObjectMeta{
569+
Annotations: map[string]string{
570+
clusterv1.ClusterTopologyControlPlaneUpgradeStepAnnotation: "v1.32.0",
571+
},
572+
},
573+
Spec: clusterv1.ClusterSpec{
574+
Topology: clusterv1.Topology{
575+
Version: "v1.33.0",
576+
},
577+
},
578+
},
579+
kcp: &controlplanev1.KubeadmControlPlane{
580+
Spec: controlplanev1.KubeadmControlPlaneSpec{
581+
Version: "v1.31.0",
582+
},
583+
},
584+
machines: []*clusterv1.Machine{
585+
{},
586+
},
587+
588+
expectResult: ctrl.Result{RequeueAfter: preflightFailedRequeueAfter},
589+
expectPreflight: internal.PreflightCheckResults{
590+
HasDeletingMachine: false,
591+
ControlPlaneComponentsNotHealthy: false,
592+
EtcdClusterNotHealthy: false,
593+
TopologyVersionMismatch: true,
594+
},
595+
},
565596
{
566597
name: "control plane with a deleting machine should requeue",
567598
kcp: &controlplanev1.KubeadmControlPlane{},
@@ -687,6 +718,55 @@ func TestPreflightChecks(t *testing.T) {
687718
TopologyVersionMismatch: false,
688719
},
689720
},
721+
{
722+
name: "control plane with a pending upgrade, but already at the current step of the upgrade plan, should pass",
723+
cluster: &clusterv1.Cluster{
724+
ObjectMeta: metav1.ObjectMeta{
725+
Annotations: map[string]string{
726+
clusterv1.ClusterTopologyControlPlaneUpgradeStepAnnotation: "v1.32.0",
727+
},
728+
},
729+
Spec: clusterv1.ClusterSpec{
730+
Topology: clusterv1.Topology{
731+
Version: "v1.33.0",
732+
},
733+
},
734+
},
735+
kcp: &controlplanev1.KubeadmControlPlane{
736+
Spec: controlplanev1.KubeadmControlPlaneSpec{
737+
Version: "v1.32.0",
738+
}, Status: controlplanev1.KubeadmControlPlaneStatus{
739+
Conditions: []metav1.Condition{
740+
{Type: controlplanev1.KubeadmControlPlaneControlPlaneComponentsHealthyCondition, Status: metav1.ConditionTrue},
741+
{Type: controlplanev1.KubeadmControlPlaneEtcdClusterHealthyCondition, Status: metav1.ConditionTrue},
742+
},
743+
},
744+
},
745+
machines: []*clusterv1.Machine{
746+
{
747+
Status: clusterv1.MachineStatus{
748+
NodeRef: clusterv1.MachineNodeReference{
749+
Name: "node-1",
750+
},
751+
Conditions: []metav1.Condition{
752+
{Type: controlplanev1.KubeadmControlPlaneMachineAPIServerPodHealthyCondition, Status: metav1.ConditionTrue},
753+
{Type: controlplanev1.KubeadmControlPlaneMachineControllerManagerPodHealthyCondition, Status: metav1.ConditionTrue},
754+
{Type: controlplanev1.KubeadmControlPlaneMachineSchedulerPodHealthyCondition, Status: metav1.ConditionTrue},
755+
{Type: controlplanev1.KubeadmControlPlaneMachineEtcdPodHealthyCondition, Status: metav1.ConditionTrue},
756+
{Type: controlplanev1.KubeadmControlPlaneMachineEtcdMemberHealthyCondition, Status: metav1.ConditionTrue},
757+
},
758+
},
759+
},
760+
},
761+
762+
expectResult: ctrl.Result{},
763+
expectPreflight: internal.PreflightCheckResults{
764+
HasDeletingMachine: false,
765+
ControlPlaneComponentsNotHealthy: false,
766+
EtcdClusterNotHealthy: false,
767+
TopologyVersionMismatch: false,
768+
},
769+
},
690770
}
691771

692772
for _, tt := range testCases {

0 commit comments

Comments
 (0)