From 5dd7c5cd4673ed3dd4435cc994cd593918fdcdc8 Mon Sep 17 00:00:00 2001 From: Guang Jiong Lou <7991675+27149chen@users.noreply.github.com> Date: Thu, 31 Aug 2023 13:06:59 +0800 Subject: [PATCH] add label selector in Resource Modifiers (#6704) * add label selector in resource modifier Signed-off-by: lou * add ut Signed-off-by: lou * update after review Signed-off-by: lou * update after review Signed-off-by: lou --------- Signed-off-by: lou --- changelogs/unreleased/6704-27149chen | 3 + .../json-substitution-action-design.md | 8 +- .../resourcemodifiers/resource_modifiers.go | 58 ++++--- .../resource_modifiers_test.go | 147 ++++++++++++++++-- .../resource_modifiers_validator.go | 7 +- .../resource_modifiers_validator_test.go | 10 +- pkg/controller/restore_controller_test.go | 6 +- .../docs/main/restore-resource-modifiers.md | 13 +- .../docs/v1.12/restore-resource-modifiers.md | 21 +-- .../resourcemodifiers/resource_modifiers.go | 2 +- 10 files changed, 204 insertions(+), 71 deletions(-) create mode 100644 changelogs/unreleased/6704-27149chen diff --git a/changelogs/unreleased/6704-27149chen b/changelogs/unreleased/6704-27149chen new file mode 100644 index 000000000..62a9084cb --- /dev/null +++ b/changelogs/unreleased/6704-27149chen @@ -0,0 +1,3 @@ +This pr made some improvements in Resource Modifiers: +1. add label selector +2. change the field name from groupKind to groupResource diff --git a/design/Implemented/json-substitution-action-design.md b/design/Implemented/json-substitution-action-design.md index 3d5b0eb28..595fcd3a7 100644 --- a/design/Implemented/json-substitution-action-design.md +++ b/design/Implemented/json-substitution-action-design.md @@ -26,7 +26,7 @@ Currently velero supports substituting certain values in the K8s resources durin ## Goals -- Allow the user to specify a GroupKind, Name(optional), JSON patch for modification. +- Allow the user to specify a GroupResource, Name(optional), JSON patch for modification. - Allow the user to specify multiple JSON patch. ## Non Goals @@ -74,7 +74,7 @@ velero restore create --from-backup backup-1 --resource-modifier-configmap resou ### Resource Modifier ConfigMap Structure - User first needs to provide details on which resources the JSON Substitutions need to be applied. - - For this the user will provide 4 inputs - Namespaces(for NS Scoped resources), GroupKind (kind.group format similar to includeResources field in velero) and Name Regex(optional). + - For this the user will provide 4 inputs - Namespaces(for NS Scoped resources), GroupResource (resource.group format similar to includeResources field in velero) and Name Regex(optional). - If the user does not provide the Name, the JSON Substitutions will be applied to all the resources of the given Group and Kind under the given namespaces. - Further the use will specify the JSON Patch using the structure of kubectl's "JSON Patch" based inputs. @@ -83,7 +83,7 @@ velero restore create --from-backup backup-1 --resource-modifier-configmap resou version: v1 resourceModifierRules: - conditions: - groupKind: persistentvolumeclaims + groupResource: persistentvolumeclaims resourceNameRegex: "mysql.*" namespaces: - bar @@ -119,7 +119,7 @@ kubectl create cm --from-file -n velero version: v1 resourceModifierRules: - conditions: - groupKind: persistentvolumeclaims.storage.k8s.io + groupResource: persistentvolumeclaims.storage.k8s.io resourceNameRegex: ".*" namespaces: - bar diff --git a/internal/resourcemodifiers/resource_modifiers.go b/internal/resourcemodifiers/resource_modifiers.go index a4d24012f..ef8194522 100644 --- a/internal/resourcemodifiers/resource_modifiers.go +++ b/internal/resourcemodifiers/resource_modifiers.go @@ -2,7 +2,6 @@ package resourcemodifiers import ( "fmt" - "io" "regexp" "strconv" "strings" @@ -10,9 +9,11 @@ import ( jsonpatch "github.com/evanphx/json-patch" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "gopkg.in/yaml.v3" v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/labels" + "sigs.k8s.io/yaml" "github.com/vmware-tanzu/velero/pkg/util/collections" ) @@ -23,26 +24,27 @@ const ( ) type JSONPatch struct { - Operation string `yaml:"operation"` - From string `yaml:"from,omitempty"` - Path string `yaml:"path"` - Value string `yaml:"value,omitempty"` + Operation string `json:"operation"` + From string `json:"from,omitempty"` + Path string `json:"path"` + Value string `json:"value,omitempty"` } type Conditions struct { - Namespaces []string `yaml:"namespaces,omitempty"` - GroupKind string `yaml:"groupKind"` - ResourceNameRegex string `yaml:"resourceNameRegex"` + Namespaces []string `json:"namespaces,omitempty"` + GroupResource string `json:"groupResource"` + ResourceNameRegex string `json:"resourceNameRegex,omitempty"` + LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"` } type ResourceModifierRule struct { - Conditions Conditions `yaml:"conditions"` - Patches []JSONPatch `yaml:"patches"` + Conditions Conditions `json:"conditions"` + Patches []JSONPatch `json:"patches"` } type ResourceModifiers struct { - Version string `yaml:"version"` - ResourceModifierRules []ResourceModifierRule `yaml:"resourceModifierRules"` + Version string `json:"version"` + ResourceModifierRules []ResourceModifierRule `json:"resourceModifierRules"` } func GetResourceModifiersFromConfig(cm *v1.ConfigMap) (*ResourceModifiers, error) { @@ -58,7 +60,7 @@ func GetResourceModifiersFromConfig(cm *v1.ConfigMap) (*ResourceModifiers, error yamlData = v } - resModifiers, err := unmarshalResourceModifiers(&yamlData) + resModifiers, err := unmarshalResourceModifiers([]byte(yamlData)) if err != nil { return nil, errors.WithStack(err) } @@ -83,9 +85,11 @@ func (r *ResourceModifierRule) Apply(obj *unstructured.Unstructured, groupResour if !namespaceInclusion.ShouldInclude(obj.GetNamespace()) { return nil } - if !strings.EqualFold(groupResource, r.Conditions.GroupKind) { + + if r.Conditions.GroupResource != groupResource { return nil } + if r.Conditions.ResourceNameRegex != "" { match, err := regexp.MatchString(r.Conditions.ResourceNameRegex, obj.GetName()) if err != nil { @@ -95,6 +99,17 @@ func (r *ResourceModifierRule) Apply(obj *unstructured.Unstructured, groupResour return nil } } + + if r.Conditions.LabelSelector != nil { + selector, err := metav1.LabelSelectorAsSelector(r.Conditions.LabelSelector) + if err != nil { + return errors.Errorf("error in creating label selector %s", err.Error()) + } + if !selector.Matches(labels.Set(obj.GetLabels())) { + return nil + } + } + patches, err := r.PatchArrayToByteArray() if err != nil { return err @@ -107,7 +122,7 @@ func (r *ResourceModifierRule) Apply(obj *unstructured.Unstructured, groupResour return nil } -// convert all JsonPatch to string array with the format of jsonpatch.Patch and then convert it to byte array +// PatchArrayToByteArray converts all JsonPatch to string array with the format of jsonpatch.Patch and then convert it to byte array func (r *ResourceModifierRule) PatchArrayToByteArray() ([]byte, error) { var patches []string for _, patch := range r.Patches { @@ -148,22 +163,15 @@ func ApplyPatch(patch []byte, obj *unstructured.Unstructured, log logrus.FieldLo return nil } -func unmarshalResourceModifiers(yamlData *string) (*ResourceModifiers, error) { +func unmarshalResourceModifiers(yamlData []byte) (*ResourceModifiers, error) { resModifiers := &ResourceModifiers{} - err := decodeStruct(strings.NewReader(*yamlData), resModifiers) + err := yaml.UnmarshalStrict(yamlData, resModifiers) if err != nil { return nil, fmt.Errorf("failed to decode yaml data into resource modifiers %v", err) } return resModifiers, nil } -// decodeStruct restrict validate the keys in decoded mappings to exist as fields in the struct being decoded into -func decodeStruct(r io.Reader, s interface{}) error { - dec := yaml.NewDecoder(r) - dec.KnownFields(true) - return dec.Decode(s) -} - func addQuotes(value string) bool { if value == "" { return true diff --git a/internal/resourcemodifiers/resource_modifiers_test.go b/internal/resourcemodifiers/resource_modifiers_test.go index 911425f38..c2150bbc8 100644 --- a/internal/resourcemodifiers/resource_modifiers_test.go +++ b/internal/resourcemodifiers/resource_modifiers_test.go @@ -18,7 +18,7 @@ func TestGetResourceModifiersFromConfig(t *testing.T) { Namespace: "test-namespace", }, Data: map[string]string{ - "sub.yml": "version: v1\nresourceModifierRules:\n- conditions:\n groupKind: persistentvolumeclaims\n resourceNameRegex: \".*\"\n namespaces:\n - bar\n - foo\n patches:\n - operation: replace\n path: \"/spec/storageClassName\"\n value: \"premium\"\n - operation: remove\n path: \"/metadata/labels/test\"\n\n\n", + "sub.yml": "version: v1\nresourceModifierRules:\n- conditions:\n groupResource: persistentvolumeclaims\n resourceNameRegex: \".*\"\n namespaces:\n - bar\n - foo\n patches:\n - operation: replace\n path: \"/spec/storageClassName\"\n value: \"premium\"\n - operation: remove\n path: \"/metadata/labels/test\"\n\n\n", }, } @@ -27,7 +27,7 @@ func TestGetResourceModifiersFromConfig(t *testing.T) { ResourceModifierRules: []ResourceModifierRule{ { Conditions: Conditions{ - GroupKind: "persistentvolumeclaims", + GroupResource: "persistentvolumeclaims", ResourceNameRegex: ".*", Namespaces: []string{"bar", "foo"}, }, @@ -51,7 +51,7 @@ func TestGetResourceModifiersFromConfig(t *testing.T) { Namespace: "test-namespace", }, Data: map[string]string{ - "sub.yml": "version: v1\nresourceModifierRules:\n- conditions:\n groupKind: deployments.apps\n resourceNameRegex: \"^test-.*$\"\n namespaces:\n - bar\n - foo\n patches:\n - operation: add\n path: \"/spec/template/spec/containers/0\"\n value: \"{\\\"name\\\": \\\"nginx\\\", \\\"image\\\": \\\"nginx:1.14.2\\\", \\\"ports\\\": [{\\\"containerPort\\\": 80}]}\"\n - operation: copy\n from: \"/spec/template/spec/containers/0\"\n path: \"/spec/template/spec/containers/1\"\n\n\n", + "sub.yml": "version: v1\nresourceModifierRules:\n- conditions:\n groupResource: deployments.apps\n resourceNameRegex: \"^test-.*$\"\n namespaces:\n - bar\n - foo\n patches:\n - operation: add\n path: \"/spec/template/spec/containers/0\"\n value: \"{\\\"name\\\": \\\"nginx\\\", \\\"image\\\": \\\"nginx:1.14.2\\\", \\\"ports\\\": [{\\\"containerPort\\\": 80}]}\"\n - operation: copy\n from: \"/spec/template/spec/containers/0\"\n path: \"/spec/template/spec/containers/1\"\n\n\n", }, } @@ -60,7 +60,7 @@ func TestGetResourceModifiersFromConfig(t *testing.T) { ResourceModifierRules: []ResourceModifierRule{ { Conditions: Conditions{ - GroupKind: "deployments.apps", + GroupResource: "deployments.apps", ResourceNameRegex: "^test-.*$", Namespaces: []string{"bar", "foo"}, }, @@ -86,7 +86,33 @@ func TestGetResourceModifiersFromConfig(t *testing.T) { Namespace: "test-namespace", }, Data: map[string]string{ - "sub.yml": "version1: v1\nresourceModifierRules:\n- conditions:\n groupKind: deployments.apps\n resourceNameRegex: \"^test-.*$\"\n namespaces:\n - bar\n - foo\n patches:\n - operation: add\n path: \"/spec/template/spec/containers/0\"\n value: \"{\\\"name\\\": \\\"nginx\\\", \\\"image\\\": \\\"nginx:1.14.2\\\", \\\"ports\\\": [{\\\"containerPort\\\": 80}]}\"\n - operation: copy\n from: \"/spec/template/spec/containers/0\"\n path: \"/spec/template/spec/containers/1\"\n\n\n", + "sub.yml": "version1: v1\nresourceModifierRules:\n- conditions:\n groupResource: deployments.apps\n resourceNameRegex: \"^test-.*$\"\n namespaces:\n - bar\n - foo\n patches:\n - operation: add\n path: \"/spec/template/spec/containers/0\"\n value: \"{\\\"name\\\": \\\"nginx\\\", \\\"image\\\": \\\"nginx:1.14.2\\\", \\\"ports\\\": [{\\\"containerPort\\\": 80}]}\"\n - operation: copy\n from: \"/spec/template/spec/containers/0\"\n path: \"/spec/template/spec/containers/1\"\n\n\n", + }, + } + + cm4 := &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-configmap", + Namespace: "test-namespace", + }, + Data: map[string]string{ + "sub.yml": "version: v1\nresourceModifierRules:\n- conditions:\n groupResource: deployments.apps\n labelSelector:\n matchLabels:\n a: b\n", + }, + } + + rules4 := &ResourceModifiers{ + Version: "v1", + ResourceModifierRules: []ResourceModifierRule{ + { + Conditions: Conditions{ + GroupResource: "deployments.apps", + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "a": "b", + }, + }, + }, + }, }, } @@ -123,6 +149,14 @@ func TestGetResourceModifiersFromConfig(t *testing.T) { want: nil, wantErr: true, }, + { + name: "match labels", + args: args{ + cm: cm4, + }, + want: rules4, + wantErr: false, + }, { name: "nil configmap", args: args{ @@ -183,6 +217,9 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) { "metadata": map[string]interface{}{ "name": "test-deployment", "namespace": "foo", + "labels": map[string]interface{}{ + "app": "nginx", + }, }, "spec": map[string]interface{}{ "replicas": int64(1), @@ -211,6 +248,9 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) { "metadata": map[string]interface{}{ "name": "test-deployment", "namespace": "foo", + "labels": map[string]interface{}{ + "app": "nginx", + }, }, "spec": map[string]interface{}{ "replicas": int64(2), @@ -239,6 +279,9 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) { "metadata": map[string]interface{}{ "name": "test-deployment", "namespace": "foo", + "labels": map[string]interface{}{ + "app": "nginx", + }, }, "spec": map[string]interface{}{ "replicas": int64(1), @@ -287,7 +330,7 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) { ResourceModifierRules: []ResourceModifierRule{ { Conditions: Conditions{ - GroupKind: "persistentvolumeclaims", + GroupResource: "persistentvolumeclaims", ResourceNameRegex: "[a-z", Namespaces: []string{"foo"}, }, @@ -320,7 +363,7 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) { ResourceModifierRules: []ResourceModifierRule{ { Conditions: Conditions{ - GroupKind: "persistentvolumeclaims", + GroupResource: "persistentvolumeclaims", ResourceNameRegex: ".*", Namespaces: []string{"foo"}, }, @@ -353,7 +396,7 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) { ResourceModifierRules: []ResourceModifierRule{ { Conditions: Conditions{ - GroupKind: "deployments.apps", + GroupResource: "deployments.apps", ResourceNameRegex: "^test-.*$", Namespaces: []string{"foo"}, }, @@ -386,7 +429,7 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) { ResourceModifierRules: []ResourceModifierRule{ { Conditions: Conditions{ - GroupKind: "deployments.apps", + GroupResource: "deployments.apps", ResourceNameRegex: "^test-.*$", Namespaces: []string{"foo"}, }, @@ -419,8 +462,8 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) { ResourceModifierRules: []ResourceModifierRule{ { Conditions: Conditions{ - GroupKind: "deployments.apps", - Namespaces: []string{"foo"}, + GroupResource: "deployments.apps", + Namespaces: []string{"foo"}, }, Patches: []JSONPatch{ { @@ -451,7 +494,7 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) { ResourceModifierRules: []ResourceModifierRule{ { Conditions: Conditions{ - GroupKind: "deployments.apps", + GroupResource: "deployments.apps", }, Patches: []JSONPatch{ { @@ -482,7 +525,7 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) { ResourceModifierRules: []ResourceModifierRule{ { Conditions: Conditions{ - GroupKind: "deployments.apps", + GroupResource: "deployments.apps", ResourceNameRegex: ".*", Namespaces: []string{"bar"}, }, @@ -515,7 +558,7 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) { ResourceModifierRules: []ResourceModifierRule{ { Conditions: Conditions{ - GroupKind: "deployments.apps", + GroupResource: "deployments.apps", ResourceNameRegex: "^test-.*$", Namespaces: []string{"foo"}, }, @@ -543,7 +586,7 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) { ResourceModifierRules: []ResourceModifierRule{ { Conditions: Conditions{ - GroupKind: "deployments.apps", + GroupResource: "deployments.apps", ResourceNameRegex: "^test-.*$", Namespaces: []string{"foo"}, }, @@ -579,6 +622,80 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) { wantErr: false, wantObj: deployNginxMysql.DeepCopy(), }, + { + name: "nginx deployment: match label selector", + fields: fields{ + Version: "v1", + ResourceModifierRules: []ResourceModifierRule{ + { + Conditions: Conditions{ + GroupResource: "deployments.apps", + Namespaces: []string{"foo"}, + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "nginx", + }, + }, + }, + Patches: []JSONPatch{ + { + Operation: "test", + Path: "/spec/replicas", + Value: "1", + }, + { + Operation: "replace", + Path: "/spec/replicas", + Value: "2", + }, + }, + }, + }, + }, + args: args{ + obj: deployNginxOneReplica.DeepCopy(), + groupResource: "deployments.apps", + }, + wantErr: false, + wantObj: deployNginxTwoReplica.DeepCopy(), + }, + { + name: "nginx deployment: mismatch label selector", + fields: fields{ + Version: "v1", + ResourceModifierRules: []ResourceModifierRule{ + { + Conditions: Conditions{ + GroupResource: "deployments.apps", + Namespaces: []string{"foo"}, + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "nginx-mismatch", + }, + }, + }, + Patches: []JSONPatch{ + { + Operation: "test", + Path: "/spec/replicas", + Value: "1", + }, + { + Operation: "replace", + Path: "/spec/replicas", + Value: "2", + }, + }, + }, + }, + }, + args: args{ + obj: deployNginxOneReplica.DeepCopy(), + groupResource: "deployments.apps", + }, + wantErr: false, + wantObj: deployNginxOneReplica.DeepCopy(), + }, } for _, tt := range tests { diff --git a/internal/resourcemodifiers/resource_modifiers_validator.go b/internal/resourcemodifiers/resource_modifiers_validator.go index 623989e23..24fe0dbb2 100644 --- a/internal/resourcemodifiers/resource_modifiers_validator.go +++ b/internal/resourcemodifiers/resource_modifiers_validator.go @@ -1,9 +1,8 @@ package resourcemodifiers import ( - "strings" - "fmt" + "strings" ) func (r *ResourceModifierRule) Validate() error { @@ -48,8 +47,8 @@ func (p *JSONPatch) Validate() error { } func (c *Conditions) Validate() error { - if c.GroupKind == "" { - return fmt.Errorf("groupkind cannot be empty") + if c.GroupResource == "" { + return fmt.Errorf("groupkResource cannot be empty") } return nil } diff --git a/internal/resourcemodifiers/resource_modifiers_validator_test.go b/internal/resourcemodifiers/resource_modifiers_validator_test.go index ed640b1ff..a46c46530 100644 --- a/internal/resourcemodifiers/resource_modifiers_validator_test.go +++ b/internal/resourcemodifiers/resource_modifiers_validator_test.go @@ -21,7 +21,7 @@ func TestResourceModifiers_Validate(t *testing.T) { ResourceModifierRules: []ResourceModifierRule{ { Conditions: Conditions{ - GroupKind: "persistentvolumeclaims", + GroupResource: "persistentvolumeclaims", ResourceNameRegex: ".*", Namespaces: []string{"bar", "foo"}, }, @@ -44,7 +44,7 @@ func TestResourceModifiers_Validate(t *testing.T) { ResourceModifierRules: []ResourceModifierRule{ { Conditions: Conditions{ - GroupKind: "persistentvolumeclaims", + GroupResource: "persistentvolumeclaims", ResourceNameRegex: ".*", Namespaces: []string{"bar", "foo"}, }, @@ -75,7 +75,7 @@ func TestResourceModifiers_Validate(t *testing.T) { ResourceModifierRules: []ResourceModifierRule{ { Conditions: Conditions{ - GroupKind: "persistentvolumeclaims", + GroupResource: "persistentvolumeclaims", ResourceNameRegex: ".*", Namespaces: []string{"bar", "foo"}, }, @@ -92,13 +92,13 @@ func TestResourceModifiers_Validate(t *testing.T) { wantErr: true, }, { - name: "Condition has empty GroupKind", + name: "Condition has empty GroupResource", fields: fields{ Version: "v1", ResourceModifierRules: []ResourceModifierRule{ { Conditions: Conditions{ - GroupKind: "", + GroupResource: "", ResourceNameRegex: ".*", Namespaces: []string{"bar", "foo"}, }, diff --git a/pkg/controller/restore_controller_test.go b/pkg/controller/restore_controller_test.go index 009bccbb5..c63918e20 100644 --- a/pkg/controller/restore_controller_test.go +++ b/pkg/controller/restore_controller_test.go @@ -760,7 +760,7 @@ func TestValidateAndCompleteWithResourceModifierSpecified(t *testing.T) { Namespace: velerov1api.DefaultNamespace, }, Data: map[string]string{ - "sub.yml": "version: v1\nresourceModifierRules:\n- conditions:\n groupKind: persistentvolumeclaims\n resourceNameRegex: \".*\"\n namespaces:\n - bar\n - foo\n patches:\n - operation: replace\n path: \"/spec/storageClassName\"\n value: \"premium\"\n - operation: remove\n path: \"/metadata/labels/test\"\n\n\n", + "sub.yml": "version: v1\nresourceModifierRules:\n- conditions:\n groupResource: persistentvolumeclaims\n resourceNameRegex: \".*\"\n namespaces:\n - bar\n - foo\n patches:\n - operation: replace\n path: \"/spec/storageClassName\"\n value: \"premium\"\n - operation: remove\n path: \"/metadata/labels/test\"\n\n\n", }, } require.NoError(t, r.kbClient.Create(context.Background(), cm1)) @@ -788,7 +788,7 @@ func TestValidateAndCompleteWithResourceModifierSpecified(t *testing.T) { Namespace: velerov1api.DefaultNamespace, }, Data: map[string]string{ - "sub.yml": "version1: v1\nresourceModifierRules:\n- conditions:\n groupKind: persistentvolumeclaims\n resourceNameRegex: \".*\"\n namespaces:\n - bar\n - foo\n patches:\n - operation: replace\n path: \"/spec/storageClassName\"\n value: \"premium\"\n - operation: remove\n path: \"/metadata/labels/test\"\n\n\n", + "sub.yml": "version1: v1\nresourceModifierRules:\n- conditions:\n groupResource: persistentvolumeclaims\n resourceNameRegex: \".*\"\n namespaces:\n - bar\n - foo\n patches:\n - operation: replace\n path: \"/spec/storageClassName\"\n value: \"premium\"\n - operation: remove\n path: \"/metadata/labels/test\"\n\n\n", }, } require.NoError(t, r.kbClient.Create(context.Background(), invalidVersionCm)) @@ -816,7 +816,7 @@ func TestValidateAndCompleteWithResourceModifierSpecified(t *testing.T) { Namespace: velerov1api.DefaultNamespace, }, Data: map[string]string{ - "sub.yml": "version: v1\nresourceModifierRules:\n- conditions:\n groupKind: persistentvolumeclaims\n resourceNameRegex: \".*\"\n namespaces:\n - bar\n - foo\n patches:\n - operation: invalid\n path: \"/spec/storageClassName\"\n value: \"premium\"\n - operation: remove\n path: \"/metadata/labels/test\"\n\n\n", + "sub.yml": "version: v1\nresourceModifierRules:\n- conditions:\n groupResource: persistentvolumeclaims\n resourceNameRegex: \".*\"\n namespaces:\n - bar\n - foo\n patches:\n - operation: invalid\n path: \"/spec/storageClassName\"\n value: \"premium\"\n - operation: remove\n path: \"/metadata/labels/test\"\n\n\n", }, } require.NoError(t, r.kbClient.Create(context.Background(), invalidOperatorCm)) diff --git a/site/content/docs/main/restore-resource-modifiers.md b/site/content/docs/main/restore-resource-modifiers.md index 7e0e87f6d..18ff1e028 100644 --- a/site/content/docs/main/restore-resource-modifiers.md +++ b/site/content/docs/main/restore-resource-modifiers.md @@ -29,11 +29,14 @@ Below is the two-step of using resource modifiers to modify the resources during version: v1 resourceModifierRules: - conditions: - groupKind: persistentvolumeclaims + groupResource: persistentvolumeclaims resourceNameRegex: "^mysql.*$" namespaces: - bar - foo + labelSelector: + matchLabels: + foo: bar patches: - operation: replace path: "/spec/storageClassName" @@ -42,9 +45,9 @@ resourceModifierRules: path: "/metadata/labels/test" ``` -- The above configmap will apply the JSON Patch to all the PVCs in the namespaces bar and foo with name starting with mysql. The JSON Patch will replace the storageClassName with "premium" and remove the label "test" from the PVCs. +- The above configmap will apply the JSON Patch to all the PVCs in the namespaces bar and foo with name starting with mysql and match label `foo: bar`. The JSON Patch will replace the storageClassName with "premium" and remove the label "test" from the PVCs. - You can specify multiple JSON Patches for a particular resource. The patches will be applied in the order specified in the configmap. A subsequent patch is applied in order and if multiple patches are specified for the same path, the last patch will override the previous patches. -- You can can specify multiple resourceModifierRules in the configmap. The rules will be applied in the order specified in the configmap. +- You can specify multiple resourceModifierRules in the configmap. The rules will be applied in the order specified in the configmap. ### Operations supported by the JSON Patch RFC: - add @@ -61,7 +64,7 @@ resourceModifierRules: version: v1 resourceModifierRules: - conditions: - groupKind: persistentvolumeclaims + groupResource: persistentvolumeclaims resourceNameRegex: ".*" namespaces: - bar @@ -80,7 +83,7 @@ resourceModifierRules: version: v1 resourceModifierRules: - conditions: - groupKind: deployments.apps + groupResource: deployments.apps resourceNameRegex: "^test-.*$" namespaces: - bar diff --git a/site/content/docs/v1.12/restore-resource-modifiers.md b/site/content/docs/v1.12/restore-resource-modifiers.md index 7e0e87f6d..4e40d34e6 100644 --- a/site/content/docs/v1.12/restore-resource-modifiers.md +++ b/site/content/docs/v1.12/restore-resource-modifiers.md @@ -29,11 +29,14 @@ Below is the two-step of using resource modifiers to modify the resources during version: v1 resourceModifierRules: - conditions: - groupKind: persistentvolumeclaims - resourceNameRegex: "^mysql.*$" - namespaces: - - bar - - foo + groupResource: persistentvolumeclaims + resourceNameRegex: "^mysql.*$" + namespaces: + - bar + - foo + labelSelector: + matchLabels: + foo: bar patches: - operation: replace path: "/spec/storageClassName" @@ -42,9 +45,9 @@ resourceModifierRules: path: "/metadata/labels/test" ``` -- The above configmap will apply the JSON Patch to all the PVCs in the namespaces bar and foo with name starting with mysql. The JSON Patch will replace the storageClassName with "premium" and remove the label "test" from the PVCs. +- The above configmap will apply the JSON Patch to all the PVCs in the namespaces bar and foo with name starting with mysql and match label `foo: bar`. The JSON Patch will replace the storageClassName with "premium" and remove the label "test" from the PVCs. - You can specify multiple JSON Patches for a particular resource. The patches will be applied in the order specified in the configmap. A subsequent patch is applied in order and if multiple patches are specified for the same path, the last patch will override the previous patches. -- You can can specify multiple resourceModifierRules in the configmap. The rules will be applied in the order specified in the configmap. +- You can specify multiple resourceModifierRules in the configmap. The rules will be applied in the order specified in the configmap. ### Operations supported by the JSON Patch RFC: - add @@ -61,7 +64,7 @@ resourceModifierRules: version: v1 resourceModifierRules: - conditions: - groupKind: persistentvolumeclaims + groupResource: persistentvolumeclaims resourceNameRegex: ".*" namespaces: - bar @@ -80,7 +83,7 @@ resourceModifierRules: version: v1 resourceModifierRules: - conditions: - groupKind: deployments.apps + groupResource: deployments.apps resourceNameRegex: "^test-.*$" namespaces: - bar diff --git a/test/e2e/resourcemodifiers/resource_modifiers.go b/test/e2e/resourcemodifiers/resource_modifiers.go index 4df389132..e32ce4d97 100644 --- a/test/e2e/resourcemodifiers/resource_modifiers.go +++ b/test/e2e/resourcemodifiers/resource_modifiers.go @@ -36,7 +36,7 @@ var yamlData = ` version: v1 resourceModifierRules: - conditions: - groupKind: deployments.apps + groupResource: deployments.apps resourceNameRegex: "resource-modifiers-.*" patches: - operation: add