@@ -161,6 +161,9 @@ var _ = Context("creating resourceOverride with multiple jsonPatchOverrides to o
161161 Namespace : roNamespace ,
162162 },
163163 Spec : placementv1alpha1.ResourceOverrideSpec {
164+ Placement : & placementv1alpha1.PlacementRef {
165+ Name : crpName , // assigned CRP name
166+ },
164167 ResourceSelectors : configMapSelector (),
165168 Policy : & placementv1alpha1.OverridePolicy {
166169 OverrideRules : []placementv1alpha1.OverrideRule {
@@ -599,6 +602,9 @@ var _ = Context("creating resourceOverride with a templated rules with cluster n
599602 Namespace : roNamespace ,
600603 },
601604 Spec : placementv1alpha1.ResourceOverrideSpec {
605+ Placement : & placementv1alpha1.PlacementRef {
606+ Name : crpName , // assigned CRP name
607+ },
602608 ResourceSelectors : configMapSelector (),
603609 Policy : & placementv1alpha1.OverridePolicy {
604610 OverrideRules : []placementv1alpha1.OverrideRule {
@@ -693,6 +699,9 @@ var _ = Context("creating resourceOverride with delete configMap", Ordered, func
693699 Namespace : roNamespace ,
694700 },
695701 Spec : placementv1alpha1.ResourceOverrideSpec {
702+ Placement : & placementv1alpha1.PlacementRef {
703+ Name : crpName , // assigned CRP name
704+ },
696705 ResourceSelectors : configMapSelector (),
697706 Policy : & placementv1alpha1.OverridePolicy {
698707 OverrideRules : []placementv1alpha1.OverrideRule {
@@ -789,3 +798,128 @@ var _ = Context("creating resourceOverride with delete configMap", Ordered, func
789798 }, consistentlyDuration , consistentlyInterval ).Should (BeTrue (), "Failed to delete work resources on member cluster %s" , memberCluster .ClusterName )
790799 })
791800})
801+
802+ var _ = FContext ("creating resourceOverride with a templated rules with cluster label key replacement" , Ordered , func () {
803+ crpName := fmt .Sprintf (crpNameTemplate , GinkgoParallelProcess ())
804+ roName := fmt .Sprintf (roNameTemplate , GinkgoParallelProcess ())
805+ roNamespace := fmt .Sprintf (workNamespaceNameTemplate , GinkgoParallelProcess ())
806+
807+ BeforeAll (func () {
808+ By ("creating work resources" )
809+ createWorkResources ()
810+
811+ // Create the ro before crp so that the observed resource index is predictable.
812+ ro := & placementv1alpha1.ResourceOverride {
813+ ObjectMeta : metav1.ObjectMeta {
814+ Name : roName ,
815+ Namespace : roNamespace ,
816+ },
817+ Spec : placementv1alpha1.ResourceOverrideSpec {
818+ Placement : & placementv1alpha1.PlacementRef {
819+ Name : crpName , // assigned CRP name
820+ },
821+ ResourceSelectors : configMapSelector (),
822+ Policy : & placementv1alpha1.OverridePolicy {
823+ OverrideRules : []placementv1alpha1.OverrideRule {
824+ {
825+ ClusterSelector : & placementv1beta1.ClusterSelector {
826+ ClusterSelectorTerms : []placementv1beta1.ClusterSelectorTerm {
827+ {
828+ LabelSelector : & metav1.LabelSelector {
829+ MatchExpressions : []metav1.LabelSelectorRequirement {
830+ {
831+ Key : regionLabelName ,
832+ Operator : metav1 .LabelSelectorOpExists ,
833+ },
834+ },
835+ },
836+ },
837+ },
838+ },
839+ JSONPatchOverrides : []placementv1alpha1.JSONPatchOverride {
840+ {
841+ Operator : placementv1alpha1 .JSONPatchOverrideOpReplace ,
842+ Path : "/data/region" ,
843+ Value : apiextensionsv1.JSON {Raw : []byte (fmt .Sprintf (`"%s%s}"` , placementv1alpha1 .OverrideClusterLabelKeyVariablePrefix , regionLabelName ))},
844+ },
845+ },
846+ },
847+ },
848+ },
849+ },
850+ }
851+ By (fmt .Sprintf ("creating resourceOverride %s" , roName ))
852+ Expect (hubClient .Create (ctx , ro )).To (Succeed (), "Failed to create resourceOverride %s" , roName )
853+
854+ // Create the CRP.
855+ createCRP (crpName )
856+ })
857+
858+ AfterAll (func () {
859+ By (fmt .Sprintf ("deleting placement %s and related resources" , crpName ))
860+ ensureCRPAndRelatedResourcesDeleted (crpName , allMemberClusters )
861+
862+ By (fmt .Sprintf ("deleting resourceOverride %s" , roName ))
863+ cleanupResourceOverride (roName , roNamespace )
864+ })
865+
866+ It ("should update CRP status as expected" , func () {
867+ wantRONames := []placementv1beta1.NamespacedName {
868+ {Namespace : roNamespace , Name : fmt .Sprintf (placementv1alpha1 .OverrideSnapshotNameFmt , roName , 0 )},
869+ }
870+ crpStatusUpdatedActual := crpStatusWithOverrideUpdatedActual (workResourceIdentifiers (), allMemberClusterNames , "0" , nil , wantRONames )
871+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP %s status as expected" , crpName )
872+ })
873+
874+ It ("should replace the cluster label key in the configMap" , func () {
875+ cmName := fmt .Sprintf (appConfigMapNameTemplate , GinkgoParallelProcess ())
876+ cmNamespace := fmt .Sprintf (workNamespaceNameTemplate , GinkgoParallelProcess ())
877+ for _ , cluster := range allMemberClusters {
878+
879+ wantConfigMap := & corev1.ConfigMap {
880+ ObjectMeta : metav1.ObjectMeta {
881+ Name : cmName ,
882+ Namespace : cmNamespace ,
883+ },
884+ Data : map [string ]string {
885+ "region" : labelsByClusterName [cluster.ClusterName ][regionLabelName ],
886+ },
887+ }
888+ configMapActual := configMapPlacedOnClusterActual (cluster , wantConfigMap )
889+ Eventually (configMapActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update configmap %s data as expected" , cmName )
890+ }
891+ })
892+
893+ It ("should handle non-existent cluster label key gracefully" , func () {
894+ // Update the ResourceOverride to use a non-existent label key
895+ Eventually (func () error {
896+ ro := & placementv1alpha1.ResourceOverride {}
897+ if err := hubClient .Get (ctx , types.NamespacedName {Name : roName , Namespace : roNamespace }, ro ); err != nil {
898+ return err
899+ }
900+ ro .Spec .Policy .OverrideRules [0 ].JSONPatchOverrides [0 ].Value = apiextensionsv1.JSON {Raw : []byte (fmt .Sprintf (`"%snon-existent-label}"` , placementv1alpha1 .OverrideClusterLabelKeyVariablePrefix ))}
901+ return hubClient .Update (ctx , ro )
902+ }, eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update resourceOverride %s with non-existent label key" , roName )
903+
904+ // Verify CRP status reflects the error
905+ crpStatusUpdatedActual := crpStatusWithOverrideUpdatedFailedActual (workResourceIdentifiers (), allMemberClusterNames , "0" , nil , nil )
906+ Eventually (crpStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "CRP %s status should reflect the error due to non-existent label key" , crpName )
907+
908+ // Verify the configMap remains unchanged
909+ cmName := fmt .Sprintf (appConfigMapNameTemplate , GinkgoParallelProcess ())
910+ cmNamespace := fmt .Sprintf (workNamespaceNameTemplate , GinkgoParallelProcess ())
911+ for _ , cluster := range allMemberClusters {
912+ wantConfigMap := & corev1.ConfigMap {
913+ ObjectMeta : metav1.ObjectMeta {
914+ Name : cmName ,
915+ Namespace : cmNamespace ,
916+ },
917+ Data : map [string ]string {
918+ "region" : labelsByClusterName [cluster.ClusterName ][regionLabelName ],
919+ },
920+ }
921+ configMapActual := configMapPlacedOnClusterActual (cluster , wantConfigMap )
922+ Consistently (configMapActual , consistentlyDuration , consistentlyInterval ).Should (Succeed (), "ConfigMap %s should remain unchanged" , cmName )
923+ }
924+ })
925+ })
0 commit comments