Skip to content

Commit f06f3ef

Browse files
committed
update to disallow update once external strategy type
Signed-off-by: Britania Rodriguez Reyes <[email protected]>
1 parent 6f3e972 commit f06f3ef

File tree

7 files changed

+20
-313
lines changed

7 files changed

+20
-313
lines changed

apis/placement/v1beta1/clusterresourceplacement_types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,9 +524,9 @@ const (
524524
type RolloutStrategy struct {
525525
// Type of rollout. The only supported types are "RollingUpdate" and "External".
526526
// Default is "RollingUpdate".
527-
// +kubebuilder:validation:Optional
528527
// +kubebuilder:default=RollingUpdate
529528
// +kubebuilder:validation:Enum=RollingUpdate;External
529+
// +kubebuilder:validation:XValidation:rule="!(self != 'External' && oldSelf == 'External')",message="cannot change rollout strategy type from 'External' to other types"
530530
Type RolloutStrategyType `json:"type,omitempty"`
531531

532532
// Rolling update config params. Present only if RolloutStrategyType = RollingUpdate.

config/crd/bases/placement.kubernetes-fleet.io_clusterresourceplacements.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2482,6 +2482,10 @@ spec:
24822482
- RollingUpdate
24832483
- External
24842484
type: string
2485+
x-kubernetes-validations:
2486+
- message: cannot change rollout strategy type from 'External'
2487+
to other types
2488+
rule: '!(self != ''External'' && oldSelf == ''External'')'
24852489
type: object
24862490
required:
24872491
- resourceSelectors

config/crd/bases/placement.kubernetes-fleet.io_resourceplacements.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,10 @@ spec:
992992
- RollingUpdate
993993
- External
994994
type: string
995+
x-kubernetes-validations:
996+
- message: cannot change rollout strategy type from 'External'
997+
to other types
998+
rule: '!(self != ''External'' && oldSelf == ''External'')'
995999
type: object
9961000
required:
9971001
- resourceSelectors

pkg/controllers/rollout/controller_integration_test.go

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,76 +1013,6 @@ var _ = Describe("Test the rollout Controller", func() {
10131013
}
10141014
})
10151015

1016-
It("Should rollout all the selected bindings when strategy type is changed from External to RollingUpdate", func() {
1017-
By("Creating CRP with External strategy")
1018-
var targetCluster int32 = 10
1019-
rolloutCRP = clusterResourcePlacementForTest(testCRPName,
1020-
createPlacementPolicyForTest(placementv1beta1.PickNPlacementType, targetCluster),
1021-
createPlacementRolloutStrategyForTest(placementv1beta1.ExternalRolloutStrategyType, nil, nil))
1022-
Expect(k8sClient.Create(ctx, rolloutCRP)).Should(Succeed())
1023-
1024-
By("Creating the latest master resource snapshot")
1025-
masterSnapshot := generateClusterResourceSnapshot(rolloutCRP.Name, 0, true)
1026-
Expect(k8sClient.Create(ctx, masterSnapshot)).Should(Succeed())
1027-
By(fmt.Sprintf("master resource snapshot %s created", masterSnapshot.Name))
1028-
1029-
By("Creating scheduled bindings for master snapshot on target clusters")
1030-
clusters := make([]string, targetCluster)
1031-
for i := 0; i < int(targetCluster); i++ {
1032-
clusters[i] = "cluster-" + utils.RandStr()
1033-
binding := generateClusterResourceBinding(placementv1beta1.BindingStateScheduled, masterSnapshot.Name, clusters[i])
1034-
Expect(k8sClient.Create(ctx, binding)).Should(Succeed())
1035-
By(fmt.Sprintf("resource binding %s created", binding.Name))
1036-
bindings = append(bindings, binding)
1037-
}
1038-
1039-
By("Checking bindings are not rolled out consistently")
1040-
verifyBindingsNotRolledOutConsistently(controller.ConvertCRBArrayToBindingObjs(bindings))
1041-
1042-
By("Updating CRP rollout strategy type to RollingUpdate")
1043-
rolloutCRP.Spec.Strategy.Type = placementv1beta1.RollingUpdateRolloutStrategyType
1044-
rolloutCRP.Spec.Strategy.RollingUpdate = generateDefaultRollingUpdateConfig()
1045-
Expect(k8sClient.Update(ctx, rolloutCRP)).Should(Succeed(), "Failed to update CRP")
1046-
1047-
By("Verifying that rollout is unblocked")
1048-
verifyBindingsRolledOut(controller.ConvertCRBArrayToBindingObjs(bindings), masterSnapshot, timeout)
1049-
})
1050-
1051-
It("Should rollout all the selected bindings when strategy type is changed from External to empty", func() {
1052-
By("Creating CRP with External strategy")
1053-
var targetCluster int32 = 10
1054-
rolloutCRP = clusterResourcePlacementForTest(testCRPName,
1055-
createPlacementPolicyForTest(placementv1beta1.PickNPlacementType, targetCluster),
1056-
createPlacementRolloutStrategyForTest(placementv1beta1.ExternalRolloutStrategyType, nil, nil))
1057-
Expect(k8sClient.Create(ctx, rolloutCRP)).Should(Succeed())
1058-
1059-
By("Creating the latest master resource snapshot")
1060-
masterSnapshot := generateClusterResourceSnapshot(rolloutCRP.Name, 0, true)
1061-
Expect(k8sClient.Create(ctx, masterSnapshot)).Should(Succeed())
1062-
By(fmt.Sprintf("master resource snapshot %s created", masterSnapshot.Name))
1063-
1064-
By("Creating scheduled bindings for master snapshot on target clusters")
1065-
clusters := make([]string, targetCluster)
1066-
for i := 0; i < int(targetCluster); i++ {
1067-
clusters[i] = "cluster-" + utils.RandStr()
1068-
binding := generateClusterResourceBinding(placementv1beta1.BindingStateScheduled, masterSnapshot.Name, clusters[i])
1069-
Expect(k8sClient.Create(ctx, binding)).Should(Succeed())
1070-
By(fmt.Sprintf("resource binding %s created", binding.Name))
1071-
bindings = append(bindings, binding)
1072-
}
1073-
1074-
By("Checking bindings are not rolled out consistently")
1075-
verifyBindingsNotRolledOutConsistently(controller.ConvertCRBArrayToBindingObjs(bindings))
1076-
1077-
By("Updating CRP rollout strategy type to empty")
1078-
rolloutCRP.Spec.Strategy.Type = ""
1079-
rolloutCRP.Spec.Strategy.RollingUpdate = nil
1080-
Expect(k8sClient.Update(ctx, rolloutCRP)).Should(Succeed(), "Failed to update CRP")
1081-
1082-
By("Verifying that rollout is unblocked")
1083-
verifyBindingsRolledOut(controller.ConvertCRBArrayToBindingObjs(bindings), masterSnapshot, timeout)
1084-
})
1085-
10861016
It("Should not rollout anymore if the rollout strategy type is changed from RollingUpdate to External", func() {
10871017
By("Creating CRP with RollingUpdate strategy")
10881018
var targetCluster int32 = 10

test/apis/placement/v1beta1/api_validation_integration_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ var _ = Describe("Test placement v1beta1 API validation", func() {
142142
PlacementType: placementv1beta1.PickFixedPlacementType,
143143
ClusterNames: []string{"cluster1", "cluster2"},
144144
},
145+
Strategy: placementv1beta1.RolloutStrategy{
146+
Type: placementv1beta1.ExternalRolloutStrategyType,
147+
},
145148
},
146149
}
147150
Expect(hubClient.Create(ctx, &crp)).Should(Succeed())
@@ -166,6 +169,14 @@ var _ = Describe("Test placement v1beta1 API validation", func() {
166169
Expect(errors.As(err, &statusErr)).To(BeTrue(), fmt.Sprintf("Update CRP call produced error %s. Error type wanted is %s.", reflect.TypeOf(err), reflect.TypeOf(&k8sErrors.StatusError{})))
167170
Expect(statusErr.ErrStatus.Message).Should(MatchRegexp("placement type is immutable"))
168171
})
172+
173+
It("should deny update of RolloutStrategy type when External", func() {
174+
crp.Spec.Strategy.Type = placementv1beta1.RollingUpdateRolloutStrategyType
175+
err := hubClient.Update(ctx, &crp)
176+
var statusErr *k8sErrors.StatusError
177+
Expect(errors.As(err, &statusErr)).To(BeTrue(), fmt.Sprintf("Update CRP call produced error %s. Error type wanted is %s.", reflect.TypeOf(err), reflect.TypeOf(&k8sErrors.StatusError{})))
178+
Expect(statusErr.ErrStatus.Message).Should(MatchRegexp("cannot change rollout strategy type from 'External' to other types"))
179+
})
169180
})
170181

171182
Context("Test ClusterResourcePlacement StatusReportingScope validation - create, allow cases", func() {

test/e2e/cluster_staged_updaterun_test.go

Lines changed: 0 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,128 +1366,6 @@ var _ = Describe("test CRP rollout with staged update run", func() {
13661366
})
13671367
})
13681368

1369-
Context("Test CRP rollout strategy transition from external to rollingUpdate", Ordered, func() {
1370-
var strategy *placementv1beta1.ClusterStagedUpdateStrategy
1371-
updateRunName := fmt.Sprintf(clusterStagedUpdateRunNameWithSubIndexTemplate, GinkgoParallelProcess(), 0)
1372-
var oldConfigMap, newConfigMap corev1.ConfigMap
1373-
1374-
BeforeAll(func() {
1375-
// Create a test namespace and a configMap inside it on the hub cluster.
1376-
createWorkResources()
1377-
1378-
// Create the CRP with external rollout strategy initially.
1379-
crp := &placementv1beta1.ClusterResourcePlacement{
1380-
ObjectMeta: metav1.ObjectMeta{
1381-
Name: crpName,
1382-
// Add a custom finalizer; this would allow us to better observe
1383-
// the behavior of the controllers.
1384-
Finalizers: []string{customDeletionBlockerFinalizer},
1385-
},
1386-
Spec: placementv1beta1.PlacementSpec{
1387-
ResourceSelectors: workResourceSelector(),
1388-
Strategy: placementv1beta1.RolloutStrategy{
1389-
Type: placementv1beta1.ExternalRolloutStrategyType,
1390-
},
1391-
},
1392-
}
1393-
Expect(hubClient.Create(ctx, crp)).To(Succeed(), "Failed to create CRP")
1394-
1395-
// Create the clusterStagedUpdateStrategy.
1396-
strategy = createClusterStagedUpdateStrategySucceed(strategyName)
1397-
1398-
oldConfigMap = appConfigMap()
1399-
newConfigMap = appConfigMap()
1400-
newConfigMap.Data["data"] = testConfigMapDataValue
1401-
})
1402-
1403-
AfterAll(func() {
1404-
// Remove the custom deletion blocker finalizer from the CRP.
1405-
ensureCRPAndRelatedResourcesDeleted(crpName, allMemberClusters)
1406-
1407-
// Delete the clusterStagedUpdateRun.
1408-
ensureClusterStagedUpdateRunDeletion(updateRunName)
1409-
1410-
// Delete the clusterStagedUpdateStrategy.
1411-
ensureClusterUpdateRunStrategyDeletion(strategyName)
1412-
})
1413-
1414-
It("Should not rollout any resources to member clusters with external strategy", checkIfRemovedWorkResourcesFromAllMemberClustersConsistently)
1415-
1416-
It("Should have the latest resource snapshot", func() {
1417-
validateLatestClusterResourceSnapshot(crpName, resourceSnapshotIndex1st)
1418-
})
1419-
1420-
It("Should update crp status as pending rollout", func() {
1421-
crpStatusUpdatedActual := crpStatusWithExternalStrategyActual(nil, "", false, allMemberClusterNames, []string{"", "", ""}, []bool{false, false, false}, nil, nil)
1422-
Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName)
1423-
})
1424-
1425-
It("Create updateRun and verify resources are rolled out", func() {
1426-
createClusterStagedUpdateRunSucceed(updateRunName, crpName, resourceSnapshotIndex1st, strategyName, placementv1beta1.StateRun)
1427-
1428-
// Approval for AfterStageTasks of canary stage
1429-
validateAndApproveClusterApprovalRequests(updateRunName, envCanary, placementv1beta1.AfterStageApprovalTaskNameFmt, placementv1beta1.AfterStageTaskLabelValue)
1430-
1431-
// Approval for BeforeStageTasks of prod stage
1432-
validateAndApproveClusterApprovalRequests(updateRunName, envProd, placementv1beta1.BeforeStageApprovalTaskNameFmt, placementv1beta1.BeforeStageTaskLabelValue)
1433-
1434-
csurSucceededActual := clusterStagedUpdateRunStatusSucceededActual(updateRunName, resourceSnapshotIndex1st, policySnapshotIndex1st, len(allMemberClusters), defaultApplyStrategy, &strategy.Spec, [][]string{{allMemberClusterNames[1]}, {allMemberClusterNames[0], allMemberClusterNames[2]}}, nil, nil, nil, true)
1435-
Eventually(csurSucceededActual, updateRunEventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to validate updateRun %s succeeded", updateRunName)
1436-
1437-
checkIfPlacedWorkResourcesOnMemberClustersInUpdateRun(allMemberClusters)
1438-
})
1439-
1440-
It("Should update crp status as completed", func() {
1441-
crpStatusUpdatedActual := crpStatusWithExternalStrategyActual(workResourceIdentifiers(), resourceSnapshotIndex1st, true, allMemberClusterNames,
1442-
[]string{resourceSnapshotIndex1st, resourceSnapshotIndex1st, resourceSnapshotIndex1st}, []bool{true, true, true}, nil, nil)
1443-
Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status as expected", crpName)
1444-
})
1445-
1446-
It("Update the configmap on hub but should not rollout to member clusters with external strategy", func() {
1447-
updateConfigMapSucceed(&newConfigMap)
1448-
1449-
// Verify old configmap is still on all member clusters
1450-
for _, cluster := range allMemberClusters {
1451-
configMapActual := configMapPlacedOnClusterActual(cluster, &oldConfigMap)
1452-
Consistently(configMapActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to keep old configmap %s data on cluster %s", oldConfigMap.Name, cluster.ClusterName)
1453-
}
1454-
})
1455-
1456-
It("Should have new resource snapshot but CRP status should remain completed with old snapshot", func() {
1457-
validateLatestClusterResourceSnapshot(crpName, resourceSnapshotIndex2nd)
1458-
1459-
// CRP status should still show completed with old snapshot
1460-
crpStatusUpdatedActual := crpStatusWithExternalStrategyActual(workResourceIdentifiers(), resourceSnapshotIndex1st, true, allMemberClusterNames,
1461-
[]string{resourceSnapshotIndex1st, resourceSnapshotIndex1st, resourceSnapshotIndex1st}, []bool{true, true, true}, nil, nil)
1462-
Consistently(crpStatusUpdatedActual, consistentlyDuration, consistentlyInterval).Should(Succeed(), "Failed to keep CRP %s status as expected", crpName)
1463-
})
1464-
1465-
It("Update CRP to use rollingUpdate strategy", func() {
1466-
Eventually(func() error {
1467-
crp := &placementv1beta1.ClusterResourcePlacement{}
1468-
if err := hubClient.Get(ctx, client.ObjectKey{Name: crpName}, crp); err != nil {
1469-
return fmt.Errorf("failed to get the crp: %w", err)
1470-
}
1471-
crp.Spec.Strategy = placementv1beta1.RolloutStrategy{
1472-
Type: placementv1beta1.RollingUpdateRolloutStrategyType,
1473-
}
1474-
return hubClient.Update(ctx, crp)
1475-
}, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP strategy to rollingUpdate")
1476-
})
1477-
1478-
It("Should automatically rollout new resources to all member clusters with rollingUpdate strategy", func() {
1479-
// Verify CRP status shows all clusters with new resource snapshot
1480-
crpStatusUpdatedActual := crpStatusUpdatedActual(workResourceIdentifiers(), allMemberClusterNames, nil, resourceSnapshotIndex2nd)
1481-
Eventually(crpStatusUpdatedActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update CRP %s status with rollingUpdate strategy", crpName)
1482-
1483-
// Verify new configmap is on all member clusters
1484-
for _, cluster := range allMemberClusters {
1485-
configMapActual := configMapPlacedOnClusterActual(cluster, &newConfigMap)
1486-
Eventually(configMapActual, eventuallyDuration, eventuallyInterval).Should(Succeed(), "Failed to update to the new configmap %s on cluster %s", newConfigMap.Name, cluster.ClusterName)
1487-
}
1488-
})
1489-
})
1490-
14911369
Context("Test parallel cluster updates with maxConcurrency set to 3", Ordered, func() {
14921370
var strategy *placementv1beta1.ClusterStagedUpdateStrategy
14931371
updateRunName := fmt.Sprintf(clusterStagedUpdateRunNameWithSubIndexTemplate, GinkgoParallelProcess(), 0)

0 commit comments

Comments
 (0)