@@ -185,7 +185,7 @@ func applyOverrideRules(resource *placementv1beta1.ResourceContent, cluster *clu
185185 return nil
186186 }
187187 // Apply JSONPatchOverrides by default
188- if err : = applyJSONPatchOverride (resource , cluster , rule .JSONPatchOverrides ); err != nil {
188+ if err = applyJSONPatchOverride (resource , cluster , rule .JSONPatchOverrides ); err != nil {
189189 klog .ErrorS (err , "Failed to apply JSON patch override" )
190190 return controller .NewUserError (err )
191191 }
@@ -195,16 +195,24 @@ func applyOverrideRules(resource *placementv1beta1.ResourceContent, cluster *clu
195195
196196// applyJSONPatchOverride applies a JSON patch on the selected resources following [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902).
197197func applyJSONPatchOverride (resourceContent * placementv1beta1.ResourceContent , cluster * clusterv1beta1.MemberCluster , overrides []placementv1alpha1.JSONPatchOverride ) error {
198+ var err error
198199 if len (overrides ) == 0 { // do nothing
199200 return nil
200201 }
201202 // go through the JSON patch overrides to replace the built-in variables before json Marshal
202203 // as it may contain the built-in variables that cannot be marshaled directly
203204 for i := range overrides {
204- // find and replace a few special built-in variables
205- // replace the built-in variable with the actual cluster name
206- processedJSONStr := []byte (strings .ReplaceAll (string (overrides [i ].Value .Raw ), placementv1alpha1 .OverrideClusterNameVariable , cluster .Name ))
207- overrides [i ].Value .Raw = processedJSONStr
205+ // Process the JSON string to replace variables
206+ jsonStr := string (overrides [i ].Value .Raw )
207+ // Replace the built-in ${MEMBER-CLUSTER-NAME} variable with the actual cluster name
208+ jsonStr = strings .ReplaceAll (jsonStr , placementv1alpha1 .OverrideClusterNameVariable , cluster .Name )
209+ // Replace label key variables with actual label values
210+ jsonStr , err = replaceClusterLabelKeyVariables (jsonStr , cluster )
211+ if err != nil {
212+ klog .ErrorS (err , "Failed to replace cluster label key variables in JSON patch override" )
213+ return err
214+ }
215+ overrides [i ].Value .Raw = []byte (jsonStr )
208216 }
209217
210218 jsonPatchBytes , err := json .Marshal (overrides )
@@ -227,3 +235,38 @@ func applyJSONPatchOverride(resourceContent *placementv1beta1.ResourceContent, c
227235 resourceContent .Raw = patchedObjectJSONBytes
228236 return nil
229237}
238+
239+ // replaceClusterLabelKeyVariables finds all occurrences of the OverrideClusterLabelKeyVariablePrefix pattern
240+ // (e.g. ${MEMBER-CLUSTER-LABEL-KEY-region}) in the input string and replaces them with
241+ // the corresponding label values from the cluster.
242+ // If a label with the specified key doesn't exist, it returns an error.
243+ func replaceClusterLabelKeyVariables (input string , cluster * clusterv1beta1.MemberCluster ) (string , error ) {
244+ prefixLen := len (placementv1alpha1 .OverrideClusterLabelKeyVariablePrefix )
245+ result := input
246+
247+ for {
248+ startIdx := strings .Index (result , placementv1alpha1 .OverrideClusterLabelKeyVariablePrefix )
249+ if startIdx == - 1 {
250+ break
251+ }
252+ // extract the key value user wants to replace
253+ endIdx := strings .Index (result [startIdx + prefixLen :], "}" )
254+ if endIdx == - 1 {
255+ klog .V (2 ).InfoS ("malformed key ${MEMBER-CLUSTER-LABEL-KEY without the closing `}`" , "input" , input )
256+ return "" , fmt .Errorf ("input %s is missing the closing bracket `}`" , input )
257+ }
258+ endIdx += startIdx + prefixLen
259+ // extract the key name
260+ keyName := result [startIdx + prefixLen : endIdx ]
261+ // check if the key exists in the cluster labels
262+ labelValue , exists := cluster .ObjectMeta .Labels [keyName ]
263+ if ! exists {
264+ klog .V (2 ).InfoS ("Label key not found on cluster" , "key" , keyName , "cluster" , cluster .Name )
265+ return "" , fmt .Errorf ("label key %s not found on cluster %s" , keyName , cluster .Name )
266+ }
267+ // replace this instance of the variable with the actual label value
268+ fullVariable := result [startIdx : endIdx + 1 ]
269+ result = strings .Replace (result , fullVariable , labelValue , 1 )
270+ }
271+ return result , nil
272+ }
0 commit comments