@@ -620,6 +620,123 @@ var _ = Describe("validating CRP when resources exists", Ordered, func() {
620620 })
621621})
622622
623+ var _ = Describe ("SSA" , Ordered , func () {
624+ Context ("use server-side apply to place resources (with changes)" , func () {
625+ crpName := fmt .Sprintf (crpNameTemplate , GinkgoParallelProcess ())
626+ nsName := fmt .Sprintf (workNamespaceNameTemplate , GinkgoParallelProcess ())
627+ cmName := fmt .Sprintf (appConfigMapNameTemplate , GinkgoParallelProcess ())
628+
629+ // The key here should match the one used in the default config map.
630+ cmDataKey := "data"
631+ cmDataVal1 := "foobar"
632+
633+ BeforeAll (func () {
634+ // Create the resources on the hub cluster.
635+ createWorkResources ()
636+
637+ // Create the CRP.
638+ crp := & placementv1beta1.ClusterResourcePlacement {
639+ ObjectMeta : metav1.ObjectMeta {
640+ Name : crpName ,
641+ // Add a custom finalizer; this would allow us to better observe
642+ // the behavior of the controllers.
643+ Finalizers : []string {customDeletionBlockerFinalizer },
644+ },
645+ Spec : placementv1beta1.ClusterResourcePlacementSpec {
646+ ResourceSelectors : workResourceSelector (),
647+ Policy : & placementv1beta1.PlacementPolicy {
648+ PlacementType : placementv1beta1 .PickAllPlacementType ,
649+ },
650+ Strategy : placementv1beta1.RolloutStrategy {
651+ Type : placementv1beta1 .RollingUpdateRolloutStrategyType ,
652+ RollingUpdate : & placementv1beta1.RollingUpdateConfig {
653+ MaxUnavailable : ptr .To (intstr .FromInt (1 )),
654+ MaxSurge : ptr .To (intstr .FromInt (1 )),
655+ UnavailablePeriodSeconds : ptr .To (2 ),
656+ },
657+ ApplyStrategy : & placementv1beta1.ApplyStrategy {
658+ Type : placementv1beta1 .ApplyStrategyTypeServerSideApply ,
659+ },
660+ },
661+ },
662+ }
663+ Expect (hubClient .Create (ctx , crp )).To (Succeed ())
664+ })
665+
666+ It ("should update CRP status as expected" , func () {
667+ crpStatusUpdatedActual := crpStatusUpdatedActual (workResourceIdentifiers (), allMemberClusterNames , nil , "0" )
668+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP status as expected" )
669+ })
670+
671+ It ("should place the resources on all member clusters" , checkIfPlacedWorkResourcesOnAllMemberClusters )
672+
673+ It ("can update the manifests" , func () {
674+ Eventually (func () error {
675+ cm := & corev1.ConfigMap {}
676+ if err := hubClient .Get (ctx , client.ObjectKey {Name : cmName , Namespace : nsName }, cm ); err != nil {
677+ return fmt .Errorf ("failed to get configmap: %w" , err )
678+ }
679+
680+ if cm .Data == nil {
681+ cm .Data = make (map [string ]string )
682+ }
683+ cm .Data [cmDataKey ] = cmDataVal1
684+
685+ if err := hubClient .Update (ctx , cm ); err != nil {
686+ return fmt .Errorf ("failed to update configmap: %w" , err )
687+ }
688+ return nil
689+ }, eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update the manifests" )
690+ })
691+
692+ It ("should update CRP status as expected" , func () {
693+ crpStatusUpdatedActual := crpStatusUpdatedActual (workResourceIdentifiers (), allMemberClusterNames , nil , "1" )
694+ // Longer timeout is used to allow full rollouts.
695+ Eventually (crpStatusUpdatedActual , workloadEventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP status as expected" )
696+ })
697+
698+ It ("should refresh the resources on all member clusters" , func () {
699+ for idx := range allMemberClusters {
700+ memberClient := allMemberClusters [idx ].KubeClient
701+
702+ Eventually (func () error {
703+ cm := & corev1.ConfigMap {}
704+ if err := memberClient .Get (ctx , client.ObjectKey {Name : cmName , Namespace : nsName }, cm ); err != nil {
705+ return fmt .Errorf ("failed to get configmap: %w" , err )
706+ }
707+
708+ // To keep things simple, here the config map for comparison is
709+ // rebuilt from the retrieved data.
710+ rebuiltCM := & corev1.ConfigMap {
711+ ObjectMeta : metav1.ObjectMeta {
712+ Name : cm .Name ,
713+ Namespace : cm .Namespace ,
714+ },
715+ Data : cm .Data ,
716+ }
717+ wantCM := & corev1.ConfigMap {
718+ ObjectMeta : metav1.ObjectMeta {
719+ Name : cmName ,
720+ Namespace : nsName ,
721+ },
722+ Data : map [string ]string {
723+ cmDataKey : cmDataVal1 ,
724+ },
725+ }
726+ if diff := cmp .Diff (rebuiltCM , wantCM ); diff != "" {
727+ return fmt .Errorf ("configMap diff (-got, +want):\n %s" , diff )
728+ }
729+ return nil
730+ }, eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to refresh the resources on %s" , allMemberClusters [idx ].ClusterName )
731+ }
732+ })
733+
734+ AfterAll (func () {
735+ ensureCRPAndRelatedResourcesDeleted (crpName , allMemberClusters )
736+ })
737+ })
738+ })
739+
623740var _ = Describe ("switching apply strategies" , func () {
624741 Context ("switch from client-side apply to report diff" , Ordered , func () {
625742 crpName := fmt .Sprintf (crpNameTemplate , GinkgoParallelProcess ())
0 commit comments