Skip to content

Commit 781ff73

Browse files
authored
Merge pull request #12979 from sbueringer/pr-cluster-webhook-chained
🌱 Allow >1 minor version upgrades if generateUpgradePlan extension is defined
2 parents b0c656d + 5f07192 commit 781ff73

File tree

2 files changed

+45
-11
lines changed

2 files changed

+45
-11
lines changed

internal/webhooks/cluster.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -389,10 +389,17 @@ func (webhook *Cluster) validateTopology(ctx context.Context, oldCluster, newClu
389389
log.Info(warningMsg)
390390
allWarnings = append(allWarnings, warningMsg)
391391
} else {
392-
// TODO(chained-upgrade): handle properly when upgrade paths are called using a runtime extension.
393-
394-
// NOTE: We validate the version ceiling only if we can't validate the version against versions defined in the ClusterClass.
395-
shouldValidateVersionCeiling := len(clusterClass.Spec.KubernetesVersions) == 0
392+
// NOTE: Validate the version ceiling only if:
393+
// * there are no Kubernetes versions defined in the ClusterClass and
394+
// * there is no generateUpgradePlan extension defined in the ClusterClass
395+
//
396+
// If there are Kubernetes versions defined, we will instead validate that the Cluster.spec.topology.version
397+
// is one of these versions and then we can use the chained upgrade feature to upgrade to that version.
398+
// Note: The ClusterClass webhook ensures the KubernetesVersions in the ClusterClass don't have any gaps.
399+
//
400+
// If a generateUpgradePlan extension is defined, we assume that additionally a Cluster validating webhook is implemented
401+
// that validates Cluster.spec.topology.version in a way that matches with GenerateUpgradePlan responses.
402+
shouldValidateVersionCeiling := len(clusterClass.Spec.KubernetesVersions) == 0 && clusterClass.Spec.Upgrade.External.GenerateUpgradePlanExtension == ""
396403
if err := webhook.validateTopologyVersionUpdate(ctx, fldPath.Child("version"), newCluster.Spec.Topology.Version, inVersion, oldVersion, oldCluster, shouldValidateVersionCeiling); err != nil {
397404
allErrs = append(allErrs, err)
398405
}

internal/webhooks/cluster_test.go

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,13 +1676,14 @@ func TestClusterTopologyValidation(t *testing.T) {
16761676
utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.ClusterTopology, true)
16771677

16781678
tests := []struct {
1679-
name string
1680-
in *clusterv1.Cluster
1681-
old *clusterv1.Cluster
1682-
additionalObjects []client.Object
1683-
clusterClassVersions []string
1684-
expectErr bool
1685-
expectWarning bool
1679+
name string
1680+
in *clusterv1.Cluster
1681+
old *clusterv1.Cluster
1682+
additionalObjects []client.Object
1683+
clusterClassVersions []string
1684+
generateUpgradePlanExtension string
1685+
expectErr bool
1686+
expectWarning bool
16861687
}{
16871688
{
16881689
name: "should return error when topology does not have class",
@@ -1899,6 +1900,31 @@ func TestClusterTopologyValidation(t *testing.T) {
18991900
Build(),
19001901
},
19011902
},
1903+
{
1904+
name: "should allow upgrading >1 minor version when generateUpgradePlan extension is defined in CC",
1905+
old: builder.Cluster("fooboo", "cluster1").
1906+
WithControlPlane(builder.ControlPlane("fooboo", "cluster1-cp").Build()).
1907+
WithTopology(builder.ClusterTopology().
1908+
WithClass("foo").
1909+
WithVersion("v1.2.3").
1910+
Build()).
1911+
Build(),
1912+
in: builder.Cluster("fooboo", "cluster1").
1913+
WithControlPlane(builder.ControlPlane("fooboo", "cluster1-cp").Build()).
1914+
WithTopology(builder.ClusterTopology().
1915+
WithClass("foo").
1916+
WithVersion("v1.4.0").
1917+
Build()).
1918+
Build(),
1919+
generateUpgradePlanExtension: "foo",
1920+
additionalObjects: []client.Object{
1921+
// Note: CRD is needed to look up the apiVersion from contract labels.
1922+
builder.GenericControlPlaneCRD,
1923+
builder.ControlPlane("fooboo", "cluster1-cp").WithVersion("v1.2.3").
1924+
WithStatusFields(map[string]interface{}{"status.version": "v1.2.3"}).
1925+
Build(),
1926+
},
1927+
},
19021928
{
19031929
name: "should return error when duplicated MachineDeployments names exists in a Topology",
19041930
expectErr: true,
@@ -2246,6 +2272,7 @@ func TestClusterTopologyValidation(t *testing.T) {
22462272
if tt.clusterClassVersions != nil {
22472273
class.Spec.KubernetesVersions = tt.clusterClassVersions
22482274
}
2275+
class.Spec.Upgrade.External.GenerateUpgradePlanExtension = tt.generateUpgradePlanExtension
22492276

22502277
// Mark this condition to true so the webhook sees the ClusterClass as up to date.
22512278
conditions.Set(class, metav1.Condition{

0 commit comments

Comments
 (0)