@@ -44,6 +44,8 @@ const (
4444 policySnapshotIndex1st = "0"
4545 policySnapshotIndex2nd = "1"
4646 policySnapshotIndex3rd = "2"
47+
48+ testConfigMapDataValue = "new"
4749)
4850
4951// Note that this container will run in parallel with other containers.
@@ -86,7 +88,7 @@ var _ = Describe("test CRP rollout with staged update run", func() {
8688
8789 oldConfigMap = appConfigMap ()
8890 newConfigMap = appConfigMap ()
89- newConfigMap .Data ["data" ] = "new"
91+ newConfigMap .Data ["data" ] = testConfigMapDataValue
9092 })
9193
9294 AfterAll (func () {
@@ -149,7 +151,7 @@ var _ = Describe("test CRP rollout with staged update run", func() {
149151 })
150152
151153 It ("Should update the configmap successfully on hub but not change member clusters" , func () {
152- Eventually ( func () error { return hubClient . Update ( ctx , & newConfigMap ) }, eventuallyDuration , eventuallyInterval ). Should ( Succeed (), "Failed to update configmap on hub" )
154+ updateConfigMapSucceed ( & newConfigMap )
153155
154156 for _ , cluster := range allMemberClusters {
155157 configMapActual := configMapPlacedOnClusterActual (cluster , & oldConfigMap )
@@ -904,6 +906,241 @@ var _ = Describe("test CRP rollout with staged update run", func() {
904906
905907 It ("Should not rollout any resources to member clusters as it's reportDiff mode" , checkIfRemovedWorkResourcesFromAllMemberClustersConsistently )
906908 })
909+
910+ Context ("Test CRP rollout strategy transition from rollingUpdate to external" , Ordered , func () {
911+ var strategy * placementv1beta1.ClusterStagedUpdateStrategy
912+ updateRunName := fmt .Sprintf (updateRunNameWithSubIndexTemplate , GinkgoParallelProcess (), 0 )
913+ var oldConfigMap , newConfigMap corev1.ConfigMap
914+
915+ BeforeAll (func () {
916+ // Create a test namespace and a configMap inside it on the hub cluster.
917+ createWorkResources ()
918+
919+ // Create the CRP with rollingUpdate strategy initially.
920+ crp := & placementv1beta1.ClusterResourcePlacement {
921+ ObjectMeta : metav1.ObjectMeta {
922+ Name : crpName ,
923+ // Add a custom finalizer; this would allow us to better observe
924+ // the behavior of the controllers.
925+ Finalizers : []string {customDeletionBlockerFinalizer },
926+ },
927+ Spec : placementv1beta1.PlacementSpec {
928+ ResourceSelectors : workResourceSelector (),
929+ Strategy : placementv1beta1.RolloutStrategy {
930+ Type : placementv1beta1 .RollingUpdateRolloutStrategyType ,
931+ },
932+ },
933+ }
934+ Expect (hubClient .Create (ctx , crp )).To (Succeed (), "Failed to create CRP" )
935+
936+ // Create the clusterStagedUpdateStrategy for later use.
937+ strategy = createStagedUpdateStrategySucceed (strategyName )
938+
939+ oldConfigMap = appConfigMap ()
940+ newConfigMap = appConfigMap ()
941+ newConfigMap .Data ["data" ] = testConfigMapDataValue
942+ })
943+
944+ AfterAll (func () {
945+ // Remove the custom deletion blocker finalizer from the CRP.
946+ ensureCRPAndRelatedResourcesDeleted (crpName , allMemberClusters )
947+
948+ // Delete the clusterStagedUpdateRun.
949+ ensureUpdateRunDeletion (updateRunName )
950+
951+ // Delete the clusterStagedUpdateStrategy.
952+ ensureUpdateRunStrategyDeletion (strategyName )
953+ })
954+
955+ It ("Should rollout resources to all member clusters with rollingUpdate strategy" , func () {
956+ crpStatusUpdatedActual := crpStatusUpdatedActual (workResourceIdentifiers (), allMemberClusterNames , nil , resourceSnapshotIndex1st )
957+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP %s status as expected" , crpName )
958+ checkIfPlacedWorkResourcesOnMemberClustersInUpdateRun (allMemberClusters )
959+ })
960+
961+ It ("Update CRP to use external rollout strategy" , func () {
962+ Eventually (func () error {
963+ crp := & placementv1beta1.ClusterResourcePlacement {}
964+ if err := hubClient .Get (ctx , client.ObjectKey {Name : crpName }, crp ); err != nil {
965+ return fmt .Errorf ("failed to get the crp: %w" , err )
966+ }
967+ crp .Spec .Strategy = placementv1beta1.RolloutStrategy {
968+ Type : placementv1beta1 .ExternalRolloutStrategyType ,
969+ }
970+ return hubClient .Update (ctx , crp )
971+ }, eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP strategy to external rollout" )
972+ })
973+
974+ It ("Should update crp status to reflect external rollout strategy" , func () {
975+ crpStatusUpdatedActual := crpStatusWithExternalStrategyActual (workResourceIdentifiers (), resourceSnapshotIndex1st , true , allMemberClusterNames ,
976+ []string {resourceSnapshotIndex1st , resourceSnapshotIndex1st , resourceSnapshotIndex1st }, []bool {true , true , true }, nil , nil )
977+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP %s status for external strategy" , crpName )
978+ })
979+
980+ It ("Update the configmap on hub but should not rollout to member clusters" , func () {
981+ updateConfigMapSucceed (& newConfigMap )
982+
983+ // Verify old configmap is still on all member clusters
984+ for _ , cluster := range allMemberClusters {
985+ configMapActual := configMapPlacedOnClusterActual (cluster , & oldConfigMap )
986+ Consistently (configMapActual , consistentlyDuration , consistentlyInterval ).Should (Succeed (), "Failed to keep old configmap %s data on cluster %s" , oldConfigMap .Name , cluster .ClusterName )
987+ }
988+ })
989+
990+ It ("Should have the new resource snapshot but CRP status should remain completed with old snapshot" , func () {
991+ validateLatestResourceSnapshot (crpName , resourceSnapshotIndex2nd )
992+
993+ // CRP status should still show completed with old snapshot
994+ crpStatusUpdatedActual := crpStatusWithExternalStrategyActual (workResourceIdentifiers (), resourceSnapshotIndex1st , true , allMemberClusterNames ,
995+ []string {resourceSnapshotIndex1st , resourceSnapshotIndex1st , resourceSnapshotIndex1st }, []bool {true , true , true }, nil , nil )
996+ Consistently (crpStatusUpdatedActual , consistentlyDuration , consistentlyInterval ).Should (Succeed (), "Failed to keep CRP %s status as expected" , crpName )
997+ })
998+
999+ It ("Create a staged update run with new resourceSnapshotIndex and verify rollout happens" , func () {
1000+ createStagedUpdateRunSucceed (updateRunName , crpName , resourceSnapshotIndex2nd , strategyName )
1001+
1002+ // Verify rollout to canary cluster first
1003+ By ("Verify that the new configmap is updated on member-cluster-2 during canary stage" )
1004+ configMapActual := configMapPlacedOnClusterActual (allMemberClusters [1 ], & newConfigMap )
1005+ Eventually (configMapActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update to the new configmap %s on cluster %s" , newConfigMap .Name , allMemberClusterNames [1 ])
1006+
1007+ validateAndApproveClusterApprovalRequests (updateRunName , envCanary )
1008+
1009+ // Verify complete rollout
1010+ updateRunSucceededActual := updateRunStatusSucceededActual (updateRunName , policySnapshotIndex1st , len (allMemberClusters ), nil , & strategy .Spec , [][]string {{allMemberClusterNames [1 ]}, {allMemberClusterNames [0 ], allMemberClusterNames [2 ]}}, nil , nil , nil )
1011+ Eventually (updateRunSucceededActual , updateRunEventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to validate updateRun %s succeeded" , updateRunName )
1012+
1013+ // Verify new configmap is on all member clusters
1014+ for _ , cluster := range allMemberClusters {
1015+ configMapActual := configMapPlacedOnClusterActual (cluster , & newConfigMap )
1016+ Eventually (configMapActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update to the new configmap %s on cluster %s" , newConfigMap .Name , cluster .ClusterName )
1017+ }
1018+ })
1019+
1020+ It ("Should update crp status as completed with new snapshot" , func () {
1021+ crpStatusUpdatedActual := crpStatusWithExternalStrategyActual (workResourceIdentifiers (), resourceSnapshotIndex2nd , true , allMemberClusterNames ,
1022+ []string {resourceSnapshotIndex2nd , resourceSnapshotIndex2nd , resourceSnapshotIndex2nd }, []bool {true , true , true }, nil , nil )
1023+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP %s status as expected" , crpName )
1024+ })
1025+ })
1026+
1027+ Context ("Test CRP rollout strategy transition from external to rollingUpdate" , Ordered , func () {
1028+ var strategy * placementv1beta1.ClusterStagedUpdateStrategy
1029+ updateRunName := fmt .Sprintf (updateRunNameWithSubIndexTemplate , GinkgoParallelProcess (), 0 )
1030+ var oldConfigMap , newConfigMap corev1.ConfigMap
1031+
1032+ BeforeAll (func () {
1033+ // Create a test namespace and a configMap inside it on the hub cluster.
1034+ createWorkResources ()
1035+
1036+ // Create the CRP with external rollout strategy initially.
1037+ crp := & placementv1beta1.ClusterResourcePlacement {
1038+ ObjectMeta : metav1.ObjectMeta {
1039+ Name : crpName ,
1040+ // Add a custom finalizer; this would allow us to better observe
1041+ // the behavior of the controllers.
1042+ Finalizers : []string {customDeletionBlockerFinalizer },
1043+ },
1044+ Spec : placementv1beta1.PlacementSpec {
1045+ ResourceSelectors : workResourceSelector (),
1046+ Strategy : placementv1beta1.RolloutStrategy {
1047+ Type : placementv1beta1 .ExternalRolloutStrategyType ,
1048+ },
1049+ },
1050+ }
1051+ Expect (hubClient .Create (ctx , crp )).To (Succeed (), "Failed to create CRP" )
1052+
1053+ // Create the clusterStagedUpdateStrategy.
1054+ strategy = createStagedUpdateStrategySucceed (strategyName )
1055+
1056+ oldConfigMap = appConfigMap ()
1057+ newConfigMap = appConfigMap ()
1058+ newConfigMap .Data ["data" ] = testConfigMapDataValue
1059+ })
1060+
1061+ AfterAll (func () {
1062+ // Remove the custom deletion blocker finalizer from the CRP.
1063+ ensureCRPAndRelatedResourcesDeleted (crpName , allMemberClusters )
1064+
1065+ // Delete the clusterStagedUpdateRun.
1066+ ensureUpdateRunDeletion (updateRunName )
1067+
1068+ // Delete the clusterStagedUpdateStrategy.
1069+ ensureUpdateRunStrategyDeletion (strategyName )
1070+ })
1071+
1072+ It ("Should not rollout any resources to member clusters with external strategy" , checkIfRemovedWorkResourcesFromAllMemberClustersConsistently )
1073+
1074+ It ("Should have the latest resource snapshot" , func () {
1075+ validateLatestResourceSnapshot (crpName , resourceSnapshotIndex1st )
1076+ })
1077+
1078+ It ("Should update crp status as pending rollout" , func () {
1079+ crpStatusUpdatedActual := crpStatusWithExternalStrategyActual (nil , "" , false , allMemberClusterNames , []string {"" , "" , "" }, []bool {false , false , false }, nil , nil )
1080+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP %s status as expected" , crpName )
1081+ })
1082+
1083+ It ("Create updateRun and verify resources are rolled out" , func () {
1084+ createStagedUpdateRunSucceed (updateRunName , crpName , resourceSnapshotIndex1st , strategyName )
1085+
1086+ validateAndApproveClusterApprovalRequests (updateRunName , envCanary )
1087+
1088+ updateRunSucceededActual := updateRunStatusSucceededActual (updateRunName , policySnapshotIndex1st , len (allMemberClusters ), nil , & strategy .Spec , [][]string {{allMemberClusterNames [1 ]}, {allMemberClusterNames [0 ], allMemberClusterNames [2 ]}}, nil , nil , nil )
1089+ Eventually (updateRunSucceededActual , updateRunEventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to validate updateRun %s succeeded" , updateRunName )
1090+
1091+ checkIfPlacedWorkResourcesOnMemberClustersInUpdateRun (allMemberClusters )
1092+ })
1093+
1094+ It ("Should update crp status as completed" , func () {
1095+ crpStatusUpdatedActual := crpStatusWithExternalStrategyActual (workResourceIdentifiers (), resourceSnapshotIndex1st , true , allMemberClusterNames ,
1096+ []string {resourceSnapshotIndex1st , resourceSnapshotIndex1st , resourceSnapshotIndex1st }, []bool {true , true , true }, nil , nil )
1097+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP %s status as expected" , crpName )
1098+ })
1099+
1100+ It ("Update the configmap on hub but should not rollout to member clusters with external strategy" , func () {
1101+ updateConfigMapSucceed (& newConfigMap )
1102+
1103+ // Verify old configmap is still on all member clusters
1104+ for _ , cluster := range allMemberClusters {
1105+ configMapActual := configMapPlacedOnClusterActual (cluster , & oldConfigMap )
1106+ Consistently (configMapActual , consistentlyDuration , consistentlyInterval ).Should (Succeed (), "Failed to keep old configmap %s data on cluster %s" , oldConfigMap .Name , cluster .ClusterName )
1107+ }
1108+ })
1109+
1110+ It ("Should have new resource snapshot but CRP status should remain completed with old snapshot" , func () {
1111+ validateLatestResourceSnapshot (crpName , resourceSnapshotIndex2nd )
1112+
1113+ // CRP status should still show completed with old snapshot
1114+ crpStatusUpdatedActual := crpStatusWithExternalStrategyActual (workResourceIdentifiers (), resourceSnapshotIndex1st , true , allMemberClusterNames ,
1115+ []string {resourceSnapshotIndex1st , resourceSnapshotIndex1st , resourceSnapshotIndex1st }, []bool {true , true , true }, nil , nil )
1116+ Consistently (crpStatusUpdatedActual , consistentlyDuration , consistentlyInterval ).Should (Succeed (), "Failed to keep CRP %s status as expected" , crpName )
1117+ })
1118+
1119+ It ("Update CRP to use rollingUpdate strategy" , func () {
1120+ Eventually (func () error {
1121+ crp := & placementv1beta1.ClusterResourcePlacement {}
1122+ if err := hubClient .Get (ctx , client.ObjectKey {Name : crpName }, crp ); err != nil {
1123+ return fmt .Errorf ("failed to get the crp: %w" , err )
1124+ }
1125+ crp .Spec .Strategy = placementv1beta1.RolloutStrategy {
1126+ Type : placementv1beta1 .RollingUpdateRolloutStrategyType ,
1127+ }
1128+ return hubClient .Update (ctx , crp )
1129+ }, eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP strategy to rollingUpdate" )
1130+ })
1131+
1132+ It ("Should automatically rollout new resources to all member clusters with rollingUpdate strategy" , func () {
1133+ // Verify CRP status shows all clusters with new resource snapshot
1134+ crpStatusUpdatedActual := crpStatusUpdatedActual (workResourceIdentifiers (), allMemberClusterNames , nil , resourceSnapshotIndex2nd )
1135+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP %s status with rollingUpdate strategy" , crpName )
1136+
1137+ // Verify new configmap is on all member clusters
1138+ for _ , cluster := range allMemberClusters {
1139+ configMapActual := configMapPlacedOnClusterActual (cluster , & newConfigMap )
1140+ Eventually (configMapActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update to the new configmap %s on cluster %s" , newConfigMap .Name , cluster .ClusterName )
1141+ }
1142+ })
1143+ })
9071144})
9081145
9091146// Note that this container cannot run in parallel with other containers.
@@ -1098,7 +1335,7 @@ var _ = Describe("Test member cluster join and leave flow with updateRun", Order
10981335 })
10991336
11001337 It ("Should update the resources on hub cluster" , func () {
1101- Eventually ( func () error { return hubClient . Update ( ctx , & newConfigMap ) }, eventuallyDuration , eventuallyInterval ). Should ( Succeed (), "Failed to update configmap on hub" )
1338+ updateConfigMapSucceed ( & newConfigMap )
11021339 })
11031340
11041341 It ("Should have the latest resource snapshot with updated resources" , func () {
@@ -1336,3 +1573,11 @@ func validateAndApproveClusterApprovalRequests(updateRunName, stageName string)
13361573 return hubClient .Status ().Update (ctx , appReq )
13371574 }, updateRunEventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to get or approve approval request" )
13381575}
1576+
1577+ func updateConfigMapSucceed (newConfigMap * corev1.ConfigMap ) {
1578+ cm := & corev1.ConfigMap {}
1579+ key := client.ObjectKey {Namespace : newConfigMap .Namespace , Name : newConfigMap .Name }
1580+ Expect (hubClient .Get (ctx , key , cm )).To (Succeed (), "Failed to get configmap %s in namespace %s" , newConfigMap .Name , newConfigMap .Namespace )
1581+ cm .Data = newConfigMap .Data
1582+ Expect (hubClient .Update (ctx , cm )).To (Succeed (), "Failed to update configmap %s in namespace %s" , newConfigMap .Name , newConfigMap .Namespace )
1583+ }
0 commit comments