diff --git a/api/v2beta1/helmrelease_types.go b/api/v2beta1/helmrelease_types.go index 05b7cf1..dac448d 100644 --- a/api/v2beta1/helmrelease_types.go +++ b/api/v2beta1/helmrelease_types.go @@ -35,6 +35,11 @@ const HelmReleaseFinalizer = "finalizers.fluxcd.io" // Kustomize Helm PostRenderer specification. type Kustomize struct { + // Strategic merge and JSON patches, defined as inline YAML objects, + // capable of targeting objects based on kind, label and annotation selectors. + // +optional + Patches []kustomize.Patch `json:"patches,omitempty"` + // Strategic merge patches, defined as inline YAML objects. // +optional PatchesStrategicMerge []apiextensionsv1.JSON `json:"patchesStrategicMerge,omitempty"` diff --git a/api/v2beta1/zz_generated.deepcopy.go b/api/v2beta1/zz_generated.deepcopy.go index 03a7fd7..857b7a8 100644 --- a/api/v2beta1/zz_generated.deepcopy.go +++ b/api/v2beta1/zz_generated.deepcopy.go @@ -316,6 +316,11 @@ func (in *KubeConfig) DeepCopy() *KubeConfig { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Kustomize) DeepCopyInto(out *Kustomize) { *out = *in + if in.Patches != nil { + in, out := &in.Patches, &out.Patches + *out = make([]kustomize.Patch, len(*in)) + copy(*out, *in) + } if in.PatchesStrategicMerge != nil { in, out := &in.PatchesStrategicMerge, &out.PatchesStrategicMerge *out = make([]v1.JSON, len(*in)) diff --git a/config/crd/bases/helm.toolkit.fluxcd.io_helmreleases.yaml b/config/crd/bases/helm.toolkit.fluxcd.io_helmreleases.yaml index d298229..a3f9412 100644 --- a/config/crd/bases/helm.toolkit.fluxcd.io_helmreleases.yaml +++ b/config/crd/bases/helm.toolkit.fluxcd.io_helmreleases.yaml @@ -299,6 +299,61 @@ spec: - name type: object type: array + patches: + description: Strategic merge and JSON patches, defined as + inline YAML objects, capable of targeting objects based + on kind, label and annotation selectors. + items: + description: Patch contains an inline StrategicMerge or + JSON6902 patch, and the target the patch should be applied + to. + properties: + patch: + description: Patch contains an inline StrategicMerge + patch or an inline JSON6902 patch with an array + of operation objects. + type: string + target: + description: Target points to the resources that the + patch document should be applied to. + properties: + annotationSelector: + description: AnnotationSelector is a string that + follows the label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: Group is the API group to select + resources from. Together with Version and Kind + it is capable of unambiguously identifying and/or + selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: Kind of the API Group to select resources + from. Together with Group and Version it is + capable of unambiguously identifying and/or + selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: LabelSelector is a string that follows + the label selection expression https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: Version of the API Group to select + resources from. Together with Group and Kind + it is capable of unambiguously identifying and/or + selecting resources. https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + type: object + type: array patchesJson6902: description: JSON 6902 patches, defined as inline YAML objects. items: diff --git a/docs/api/helmrelease.md b/docs/api/helmrelease.md index f4ee502..e12c0e1 100644 --- a/docs/api/helmrelease.md +++ b/docs/api/helmrelease.md @@ -1427,6 +1427,21 @@ the HelmRelease.

+patches
+ + +[]github.com/fluxcd/pkg/apis/kustomize.Patch + + + + +(Optional) +

Strategic merge and JSON patches, defined as inline YAML objects, +capable of targeting objects based on kind, label and annotation selectors.

+ + + + patchesStrategicMerge
diff --git a/docs/spec/v2beta1/helmreleases.md b/docs/spec/v2beta1/helmreleases.md index fda125b..3904e1d 100644 --- a/docs/spec/v2beta1/helmreleases.md +++ b/docs/spec/v2beta1/helmreleases.md @@ -1149,6 +1149,7 @@ HelmRelease resources has a built-in [Kustomize](https://kubectl.docs.kubernetes compatible [Post Renderer](https://helm.sh/docs/topics/advanced/#post-rendering), which provides the following Kustomize directives: +- [patches](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patches/) - [patchesStrategicMerge](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patchesstrategicmerge/) - [patchesJson6902](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patchesjson6902/) - [images](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/images/) diff --git a/internal/runner/post_renderer_kustomize.go b/internal/runner/post_renderer_kustomize.go index a4ca4d0..a640e72 100644 --- a/internal/runner/post_renderer_kustomize.go +++ b/internal/runner/post_renderer_kustomize.go @@ -105,6 +105,14 @@ func (k *postRendererKustomize) Run(renderedManifests *bytes.Buffer) (modifiedMa return nil, err } + // Add patches. + for _, m := range k.spec.Patches { + cfg.Patches = append(cfg.Patches, kustypes.Patch{ + Patch: m.Patch, + Target: adaptSelector(&m.Target), + }) + } + // Add strategic merge patches. for _, m := range k.spec.PatchesStrategicMerge { cfg.PatchesStrategicMerge = append(cfg.PatchesStrategicMerge, kustypes.PatchStrategicMerge(m.Raw)) diff --git a/internal/runner/post_renderer_kustomize_test.go b/internal/runner/post_renderer_kustomize_test.go index 4602edb..31f322e 100644 --- a/internal/runner/post_renderer_kustomize_test.go +++ b/internal/runner/post_renderer_kustomize_test.go @@ -63,6 +63,7 @@ func Test_postRendererKustomize_Run(t *testing.T) { tests := []struct { name string renderedManifests string + patches string patchesStrategicMerge string patchesJson6902 string images string @@ -146,6 +147,42 @@ spec: `, expectManifests: `apiVersion: v1 kind: Pod +metadata: + annotations: + d: "42" + e: "42" + name: json6902 +`, + }, + { + name: "targeted json 6902", + renderedManifests: json6902Mock, + patches: ` +- target: + version: v1 + kind: Pod + name: json6902 + patch: | + - op: test + path: /metadata/annotations/c + value: foo + - op: remove + path: /metadata/annotations/c + - op: add + path: /metadata/annotations/c + value: [ "foo", "bar" ] + - op: replace + path: /metadata/annotations/c + value: 42 + - op: move + from: /metadata/annotations/c + path: /metadata/annotations/d + - op: copy + from: /metadata/annotations/d + path: /metadata/annotations/e +`, + expectManifests: `apiVersion: v1 +kind: Pod metadata: annotations: d: "42" @@ -170,6 +207,39 @@ metadata: `, expectManifests: `apiVersion: apps/v1 kind: Deployment +metadata: + name: nginx +spec: + template: + spec: + containers: + - image: nignx:latest + name: nginx +`, + }, + { + name: "targeted strategic merge test", + renderedManifests: strategicMergeMock, + patches: ` +- target: + group: apps + version: v1 + kind: Deployment + name: nginx + patch: | + apiVersion: apps/v1 + kind: Deployment + metadata: + name: nginx + spec: + template: + spec: + containers: + - name: nginx + image: nignx:latest +`, + expectManifests: `apiVersion: apps/v1 +kind: Deployment metadata: name: nginx spec: @@ -183,7 +253,11 @@ spec: } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - spec, err := mockKustomize(tt.patchesStrategicMerge, tt.patchesJson6902, tt.images) + spec, err := mockKustomize(tt.patches, tt.patchesStrategicMerge, tt.patchesJson6902, tt.images) + if err != nil { + t.Errorf("Run() mockKustomize returned %v", err) + return + } k := &postRendererKustomize{ spec: spec, } @@ -199,7 +273,11 @@ spec: } } -func mockKustomize(patchesStrategicMerge, patchesJson6902, images string) (*v2.Kustomize, error) { +func mockKustomize(patches, patchesStrategicMerge, patchesJson6902, images string) (*v2.Kustomize, error) { + var targeted []kustomize.Patch + if err := yaml.Unmarshal([]byte(patches), &targeted); err != nil { + return nil, err + } b, err := yaml.YAMLToJSON([]byte(patchesStrategicMerge)) if err != nil { return nil, err @@ -217,6 +295,7 @@ func mockKustomize(patchesStrategicMerge, patchesJson6902, images string) (*v2.K return nil, err } return &v2.Kustomize{ + Patches: targeted, PatchesStrategicMerge: strategicMerge, PatchesJSON6902: json6902, Images: imgs,