@@ -267,6 +267,210 @@ var _ = Describe("test CRP rollout with staged update run", func() {
267267 })
268268 })
269269
270+ FContext ("Test resource rollout and rollback with staged update run without specifying resource snapshot index" , Ordered , func () {
271+ updateRunNames := []string {}
272+ var strategy * placementv1beta1.ClusterStagedUpdateStrategy
273+ var oldConfigMap , newConfigMap corev1.ConfigMap
274+
275+ BeforeAll (func () {
276+ // Create a test namespace and a configMap inside it on the hub cluster.
277+ createWorkResources ()
278+
279+ // Create the CRP with external rollout strategy.
280+ crp := & placementv1beta1.ClusterResourcePlacement {
281+ ObjectMeta : metav1.ObjectMeta {
282+ Name : crpName ,
283+ // Add a custom finalizer; this would allow us to better observe
284+ // the behavior of the controllers.
285+ Finalizers : []string {customDeletionBlockerFinalizer },
286+ },
287+ Spec : placementv1beta1.PlacementSpec {
288+ ResourceSelectors : workResourceSelector (),
289+ Strategy : placementv1beta1.RolloutStrategy {
290+ Type : placementv1beta1 .ExternalRolloutStrategyType ,
291+ },
292+ },
293+ }
294+ Expect (hubClient .Create (ctx , crp )).To (Succeed (), "Failed to create CRP" )
295+
296+ // Create the clusterStagedUpdateStrategy.
297+ strategy = createClusterStagedUpdateStrategySucceed (strategyName )
298+
299+ for i := 0 ; i < 3 ; i ++ {
300+ updateRunNames = append (updateRunNames , fmt .Sprintf (clusterStagedUpdateRunNameWithSubIndexTemplate , GinkgoParallelProcess (), i ))
301+ }
302+
303+ oldConfigMap = appConfigMap ()
304+ newConfigMap = appConfigMap ()
305+ newConfigMap .Data ["data" ] = testConfigMapDataValue
306+ })
307+
308+ AfterAll (func () {
309+ // Remove the custom deletion blocker finalizer from the CRP.
310+ ensureCRPAndRelatedResourcesDeleted (crpName , allMemberClusters )
311+
312+ // Remove all the clusterStagedUpdateRuns.
313+ for _ , name := range updateRunNames {
314+ ensureClusterStagedUpdateRunDeletion (name )
315+ }
316+
317+ // Delete the clusterStagedUpdateStrategy.
318+ ensureClusterUpdateRunStrategyDeletion (strategyName )
319+ })
320+
321+ It ("Should not rollout any resources to member clusters as there's no update run yet" , checkIfRemovedWorkResourcesFromAllMemberClustersConsistently )
322+
323+ It ("Should have the latest resource snapshot" , func () {
324+ validateLatestClusterResourceSnapshot (crpName , resourceSnapshotIndex1st )
325+ })
326+
327+ It ("Should successfully schedule the crp" , func () {
328+ validateLatestClusterSchedulingPolicySnapshot (crpName , policySnapshotIndex1st , 3 )
329+ })
330+
331+ It ("Should update crp status as pending rollout" , func () {
332+ crpStatusUpdatedActual := crpStatusWithExternalStrategyActual (nil , "" , false , allMemberClusterNames , []string {"" , "" , "" }, []bool {false , false , false }, nil , nil )
333+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP %s status as expected" , crpName )
334+ })
335+
336+ It ("Should create a cluster staged update run successfully" , func () {
337+ createClusterStagedUpdateRunSucceed (updateRunNames [0 ], crpName , "" , strategyName )
338+ })
339+
340+ It ("Should rollout resources to member-cluster-2 only and complete stage canary" , func () {
341+ checkIfPlacedWorkResourcesOnMemberClustersInUpdateRun ([]* framework.Cluster {allMemberClusters [1 ]})
342+ checkIfRemovedWorkResourcesFromMemberClustersConsistently ([]* framework.Cluster {allMemberClusters [0 ], allMemberClusters [2 ]})
343+
344+ By ("Validating crp status as member-cluster-2 updated" )
345+ crpStatusUpdatedActual := crpStatusWithExternalStrategyActual (nil , "" , false , allMemberClusterNames , []string {"" , resourceSnapshotIndex1st , "" }, []bool {false , true , false }, nil , nil )
346+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP %s status as expected" , crpName )
347+
348+ validateAndApproveClusterApprovalRequests (updateRunNames [0 ], envCanary )
349+ })
350+
351+ It ("Should rollout resources to member-cluster-1 first because of its name" , func () {
352+ checkIfPlacedWorkResourcesOnMemberClustersInUpdateRun ([]* framework.Cluster {allMemberClusters [0 ]})
353+ })
354+
355+ It ("Should rollout resources to all the members and complete the cluster staged update run successfully" , func () {
356+ csurSucceededActual := clusterStagedUpdateRunStatusSucceededActual (updateRunNames [0 ], policySnapshotIndex1st , len (allMemberClusters ), defaultApplyStrategy , & strategy .Spec , [][]string {{allMemberClusterNames [1 ]}, {allMemberClusterNames [0 ], allMemberClusterNames [2 ]}}, nil , nil , nil )
357+ Eventually (csurSucceededActual , updateRunEventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to validate updateRun %s succeeded" , updateRunNames [0 ])
358+ checkIfPlacedWorkResourcesOnMemberClustersInUpdateRun (allMemberClusters )
359+ })
360+
361+ It ("Should update crp status as completed" , func () {
362+ crpStatusUpdatedActual := crpStatusWithExternalStrategyActual (workResourceIdentifiers (), resourceSnapshotIndex1st , true , allMemberClusterNames ,
363+ []string {resourceSnapshotIndex1st , resourceSnapshotIndex1st , resourceSnapshotIndex1st }, []bool {true , true , true }, nil , nil )
364+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP %s status as expected" , crpName )
365+ })
366+
367+ It ("Should update the configmap successfully on hub but not change member clusters" , func () {
368+ updateConfigMapSucceed (& newConfigMap )
369+
370+ for _ , cluster := range allMemberClusters {
371+ configMapActual := configMapPlacedOnClusterActual (cluster , & oldConfigMap )
372+ Consistently (configMapActual , consistentlyDuration , consistentlyInterval ).Should (Succeed (), "Failed to keep configmap %s data as expected" , oldConfigMap .Name )
373+ }
374+ })
375+
376+ It ("Should not update crp status, should still be completed" , func () {
377+ crpStatusUpdatedActual := crpStatusWithExternalStrategyActual (workResourceIdentifiers (), resourceSnapshotIndex1st , true , allMemberClusterNames ,
378+ []string {resourceSnapshotIndex1st , resourceSnapshotIndex1st , resourceSnapshotIndex1st }, []bool {true , true , true }, nil , nil )
379+ Consistently (crpStatusUpdatedActual , consistentlyDuration , consistentlyInterval ).Should (Succeed (), "Failed to keep CRP %s status as expected" , crpName )
380+ })
381+
382+ It ("Should create a new latest resource snapshot" , func () {
383+ crsList := & placementv1beta1.ClusterResourceSnapshotList {}
384+ Eventually (func () error {
385+ if err := hubClient .List (ctx , crsList , client.MatchingLabels {placementv1beta1 .PlacementTrackingLabel : crpName , placementv1beta1 .IsLatestSnapshotLabel : "true" }); err != nil {
386+ return fmt .Errorf ("failed to list the resourcesnapshot: %w" , err )
387+ }
388+ if len (crsList .Items ) != 1 {
389+ return fmt .Errorf ("got %d latest resourcesnapshots, want 1" , len (crsList .Items ))
390+ }
391+ if crsList .Items [0 ].Labels [placementv1beta1 .ResourceIndexLabel ] != resourceSnapshotIndex2nd {
392+ return fmt .Errorf ("got resource snapshot index %s, want %s" , crsList .Items [0 ].Labels [placementv1beta1 .ResourceIndexLabel ], resourceSnapshotIndex2nd )
393+ }
394+ return nil
395+ }, eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed get the new latest resourcensnapshot" )
396+ })
397+
398+ It ("Should create a new cluster staged update run successfully" , func () {
399+ createClusterStagedUpdateRunSucceed (updateRunNames [1 ], crpName , resourceSnapshotIndex2nd , strategyName )
400+ })
401+
402+ It ("Should rollout resources to member-cluster-2 only and complete stage canary" , func () {
403+ By ("Verify that the new configmap is updated on member-cluster-2" )
404+ configMapActual := configMapPlacedOnClusterActual (allMemberClusters [1 ], & newConfigMap )
405+ Eventually (configMapActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update to the new configmap %s on cluster %s" , newConfigMap .Name , allMemberClusterNames [1 ])
406+ By ("Verify that the configmap is not updated on member-cluster-1 and member-cluster-3" )
407+ for _ , cluster := range []* framework.Cluster {allMemberClusters [0 ], allMemberClusters [2 ]} {
408+ configMapActual := configMapPlacedOnClusterActual (cluster , & oldConfigMap )
409+ Consistently (configMapActual , consistentlyDuration , consistentlyInterval ).Should (Succeed (), "Failed to keep configmap %s data as expected" , newConfigMap .Name )
410+ }
411+
412+ By ("Validating crp status as member-cluster-2 updated" )
413+ crpStatusUpdatedActual := crpStatusWithExternalStrategyActual (nil , "" , false , allMemberClusterNames ,
414+ []string {resourceSnapshotIndex1st , resourceSnapshotIndex2nd , resourceSnapshotIndex1st }, []bool {true , true , true }, nil , nil )
415+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP %s status as expected" , crpName )
416+
417+ validateAndApproveClusterApprovalRequests (updateRunNames [1 ], envCanary )
418+ })
419+
420+ It ("Should rollout resources to member-cluster-1 and member-cluster-3 too and complete the cluster staged update run successfully" , func () {
421+ csurSucceededActual := clusterStagedUpdateRunStatusSucceededActual (updateRunNames [1 ], policySnapshotIndex1st , len (allMemberClusters ), defaultApplyStrategy , & strategy .Spec , [][]string {{allMemberClusterNames [1 ]}, {allMemberClusterNames [0 ], allMemberClusterNames [2 ]}}, nil , nil , nil )
422+ Eventually (csurSucceededActual , updateRunEventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to validate updateRun %s succeeded" , updateRunNames [1 ])
423+ By ("Verify that new the configmap is updated on all member clusters" )
424+ for idx := range allMemberClusters {
425+ configMapActual := configMapPlacedOnClusterActual (allMemberClusters [idx ], & newConfigMap )
426+ Eventually (configMapActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update to the new configmap %s on cluster %s as expected" , newConfigMap .Name , allMemberClusterNames [idx ])
427+ }
428+ })
429+
430+ It ("Should update crp status as completed" , func () {
431+ crpStatusUpdatedActual := crpStatusWithExternalStrategyActual (workResourceIdentifiers (), resourceSnapshotIndex2nd , true , allMemberClusterNames ,
432+ []string {resourceSnapshotIndex2nd , resourceSnapshotIndex2nd , resourceSnapshotIndex2nd }, []bool {true , true , true }, nil , nil )
433+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP %s status as expected" , crpName )
434+ })
435+
436+ It ("Should create a new staged update run with old resourceSnapshotIndex successfully to rollback" , func () {
437+ createClusterStagedUpdateRunSucceed (updateRunNames [2 ], crpName , resourceSnapshotIndex1st , strategyName )
438+ })
439+
440+ It ("Should rollback resources to member-cluster-2 only and completes stage canary" , func () {
441+ By ("Verify that the configmap is rolled back on member-cluster-2" )
442+ configMapActual := configMapPlacedOnClusterActual (allMemberClusters [1 ], & oldConfigMap )
443+ Eventually (configMapActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to rollback the configmap change on cluster %s" , allMemberClusterNames [1 ])
444+ By ("Verify that the configmap is not rolled back on member-cluster-1 and member-cluster-3" )
445+ for _ , cluster := range []* framework.Cluster {allMemberClusters [0 ], allMemberClusters [2 ]} {
446+ configMapActual := configMapPlacedOnClusterActual (cluster , & newConfigMap )
447+ Consistently (configMapActual , consistentlyDuration , consistentlyInterval ).Should (Succeed (), "Failed to keep configmap %s data as expected" , newConfigMap .Name )
448+ }
449+
450+ By ("Validating crp status as member-cluster-2 updated" )
451+ crpStatusUpdatedActual := crpStatusWithExternalStrategyActual (nil , "" , false , allMemberClusterNames ,
452+ []string {resourceSnapshotIndex2nd , resourceSnapshotIndex1st , resourceSnapshotIndex2nd }, []bool {true , true , true }, nil , nil )
453+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP %s status as expected" , crpName )
454+
455+ validateAndApproveClusterApprovalRequests (updateRunNames [2 ], envCanary )
456+ })
457+
458+ It ("Should rollback resources to member-cluster-1 and member-cluster-3 too and complete the cluster staged update run successfully" , func () {
459+ csurSucceededActual := clusterStagedUpdateRunStatusSucceededActual (updateRunNames [2 ], policySnapshotIndex1st , len (allMemberClusters ), defaultApplyStrategy , & strategy .Spec , [][]string {{allMemberClusterNames [1 ]}, {allMemberClusterNames [0 ], allMemberClusterNames [2 ]}}, nil , nil , nil )
460+ Eventually (csurSucceededActual , updateRunEventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to validate updateRun %s succeeded" , updateRunNames [1 ])
461+ for idx := range allMemberClusters {
462+ configMapActual := configMapPlacedOnClusterActual (allMemberClusters [idx ], & oldConfigMap )
463+ Eventually (configMapActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to rollback the configmap %s data on cluster %s as expected" , oldConfigMap .Name , allMemberClusterNames [idx ])
464+ }
465+ })
466+
467+ It ("Should update crp status as completed" , func () {
468+ crpStatusUpdatedActual := crpStatusWithExternalStrategyActual (workResourceIdentifiers (), resourceSnapshotIndex1st , true , allMemberClusterNames ,
469+ []string {resourceSnapshotIndex1st , resourceSnapshotIndex1st , resourceSnapshotIndex1st }, []bool {true , true , true }, nil , nil )
470+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP %s status as expected" , crpName )
471+ })
472+ })
473+
270474 Context ("Test cluster scale out and shrink using pickFixed policy with staged update run" , Ordered , func () {
271475 var strategy * placementv1beta1.ClusterStagedUpdateStrategy
272476 updateRunNames := []string {}
0 commit comments