Implement generic patches in Kustomization
Allow patching multiple resources instead of a single existing one as StrategicMerge & JSON6902 are forced to target existing named resources. Signed-off-by: Guillaume Le Biller <glebiller@Traveldoo.com>
This commit is contained in:
parent
30dd0c33b0
commit
b797eac907
|
@ -83,6 +83,10 @@ type KustomizationSpec struct {
|
||||||
// +optional
|
// +optional
|
||||||
HealthChecks []meta.NamespacedObjectKindReference `json:"healthChecks,omitempty"`
|
HealthChecks []meta.NamespacedObjectKindReference `json:"healthChecks,omitempty"`
|
||||||
|
|
||||||
|
// Patches (also called overlays), defined as inline YAML objects.
|
||||||
|
// +optional
|
||||||
|
Patches []kustomize.Patch `json:"patches,omitempty"`
|
||||||
|
|
||||||
// Strategic merge patches, defined as inline YAML objects.
|
// Strategic merge patches, defined as inline YAML objects.
|
||||||
// +optional
|
// +optional
|
||||||
PatchesStrategicMerge []apiextensionsv1.JSON `json:"patchesStrategicMerge,omitempty"`
|
PatchesStrategicMerge []apiextensionsv1.JSON `json:"patchesStrategicMerge,omitempty"`
|
||||||
|
|
|
@ -173,6 +173,11 @@ func (in *KustomizationSpec) DeepCopyInto(out *KustomizationSpec) {
|
||||||
*out = make([]meta.NamespacedObjectKindReference, len(*in))
|
*out = make([]meta.NamespacedObjectKindReference, len(*in))
|
||||||
copy(*out, *in)
|
copy(*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 {
|
if in.PatchesStrategicMerge != nil {
|
||||||
in, out := &in.PatchesStrategicMerge, &out.PatchesStrategicMerge
|
in, out := &in.PatchesStrategicMerge, &out.PatchesStrategicMerge
|
||||||
*out = make([]apiextensionsv1.JSON, len(*in))
|
*out = make([]apiextensionsv1.JSON, len(*in))
|
||||||
|
|
|
@ -142,6 +142,41 @@ spec:
|
||||||
- name
|
- name
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
patches:
|
||||||
|
description: Patches (also called overlays), defined as inline YAML objects.
|
||||||
|
items:
|
||||||
|
description: Patch contains either a StrategicMerge or a JSON6902 patch, either a file or inline, and the target the patch should be applied to.
|
||||||
|
properties:
|
||||||
|
patch:
|
||||||
|
description: Patch contains the JSON6902 patch document 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:
|
patchesJson6902:
|
||||||
description: JSON 6902 patches, defined as inline YAML objects.
|
description: JSON 6902 patches, defined as inline YAML objects.
|
||||||
items:
|
items:
|
||||||
|
|
|
@ -144,10 +144,17 @@ var _ = Describe("KustomizationReconciler", func() {
|
||||||
Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(Equal("ghcr.io/stefanprodan/podinfo:5.2.0"))
|
Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(Equal("ghcr.io/stefanprodan/podinfo:5.2.0"))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("strategic merge patches", func() {
|
It("patches as JSON", func() {
|
||||||
kustomization.Spec.PatchesStrategicMerge = []apiextensionsv1.JSON{
|
kustomization.Spec.Patches = []kustomize.Patch{
|
||||||
{
|
{
|
||||||
Raw: []byte(`{"kind":"Deployment","apiVersion":"apps/v1","metadata":{"name":"podinfo","labels":{"xxxx":"yyyy"}}}`),
|
Patch: `
|
||||||
|
- op: add
|
||||||
|
path: /metadata/labels/patch
|
||||||
|
value: inline-json
|
||||||
|
`,
|
||||||
|
Target: kustomize.Selector{
|
||||||
|
LabelSelector: "app=podinfo",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
Expect(k8sClient.Create(context.TODO(), kustomization)).To(Succeed())
|
Expect(k8sClient.Create(context.TODO(), kustomization)).To(Succeed())
|
||||||
|
@ -160,15 +167,59 @@ var _ = Describe("KustomizationReconciler", func() {
|
||||||
|
|
||||||
var deployment appsv1.Deployment
|
var deployment appsv1.Deployment
|
||||||
Expect(k8sClient.Get(context.TODO(), client.ObjectKey{Name: "podinfo", Namespace: namespace.Name}, &deployment)).To(Succeed())
|
Expect(k8sClient.Get(context.TODO(), client.ObjectKey{Name: "podinfo", Namespace: namespace.Name}, &deployment)).To(Succeed())
|
||||||
Expect(deployment.ObjectMeta.Labels["xxxx"]).To(Equal("yyyy"))
|
Expect(deployment.ObjectMeta.Labels["patch"]).To(Equal("inline-json"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("patches as YAML", func() {
|
||||||
|
kustomization.Spec.Patches = []kustomize.Patch{
|
||||||
|
{
|
||||||
|
Patch: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: podinfo
|
||||||
|
labels:
|
||||||
|
patch: inline-yaml
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Expect(k8sClient.Create(context.TODO(), kustomization)).To(Succeed())
|
||||||
|
|
||||||
|
Eventually(func() bool {
|
||||||
|
var obj kustomizev1.Kustomization
|
||||||
|
_ = k8sClient.Get(context.Background(), ObjectKey(kustomization), &obj)
|
||||||
|
return obj.Status.LastAppliedRevision == "main/"+artifactChecksum
|
||||||
|
}, timeout, time.Second).Should(BeTrue())
|
||||||
|
|
||||||
|
var deployment appsv1.Deployment
|
||||||
|
Expect(k8sClient.Get(context.TODO(), client.ObjectKey{Name: "podinfo", Namespace: namespace.Name}, &deployment)).To(Succeed())
|
||||||
|
Expect(deployment.ObjectMeta.Labels["patch"]).To(Equal("inline-yaml"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("strategic merge patches", func() {
|
||||||
|
kustomization.Spec.PatchesStrategicMerge = []apiextensionsv1.JSON{
|
||||||
|
{
|
||||||
|
Raw: []byte(`{"kind":"Deployment","apiVersion":"apps/v1","metadata":{"name":"podinfo","labels":{"patch":"strategic-merge"}}}`),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Expect(k8sClient.Create(context.TODO(), kustomization)).To(Succeed())
|
||||||
|
|
||||||
|
Eventually(func() bool {
|
||||||
|
var obj kustomizev1.Kustomization
|
||||||
|
_ = k8sClient.Get(context.Background(), ObjectKey(kustomization), &obj)
|
||||||
|
return obj.Status.LastAppliedRevision == "main/"+artifactChecksum
|
||||||
|
}, timeout, time.Second).Should(BeTrue())
|
||||||
|
|
||||||
|
var deployment appsv1.Deployment
|
||||||
|
Expect(k8sClient.Get(context.TODO(), client.ObjectKey{Name: "podinfo", Namespace: namespace.Name}, &deployment)).To(Succeed())
|
||||||
|
Expect(deployment.ObjectMeta.Labels["patch"]).To(Equal("strategic-merge"))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("JSON6902 patches", func() {
|
It("JSON6902 patches", func() {
|
||||||
kustomization.Spec.PatchesJSON6902 = []kustomize.JSON6902Patch{
|
kustomization.Spec.PatchesJSON6902 = []kustomize.JSON6902Patch{
|
||||||
{
|
{
|
||||||
|
|
||||||
Patch: []kustomize.JSON6902{
|
Patch: []kustomize.JSON6902{
|
||||||
{Op: "add", Path: "/metadata/labels/yyyy", Value: &apiextensionsv1.JSON{Raw: []byte(`"xxxx"`)}},
|
{Op: "add", Path: "/metadata/labels/patch", Value: &apiextensionsv1.JSON{Raw: []byte(`"json6902"`)}},
|
||||||
{Op: "replace", Path: "/spec/replicas", Value: &apiextensionsv1.JSON{Raw: []byte("2")}},
|
{Op: "replace", Path: "/spec/replicas", Value: &apiextensionsv1.JSON{Raw: []byte("2")}},
|
||||||
},
|
},
|
||||||
Target: kustomize.Selector{
|
Target: kustomize.Selector{
|
||||||
|
@ -189,7 +240,7 @@ var _ = Describe("KustomizationReconciler", func() {
|
||||||
|
|
||||||
var deployment appsv1.Deployment
|
var deployment appsv1.Deployment
|
||||||
Expect(k8sClient.Get(context.TODO(), client.ObjectKey{Name: "podinfo", Namespace: namespace.Name}, &deployment)).To(Succeed())
|
Expect(k8sClient.Get(context.TODO(), client.ObjectKey{Name: "podinfo", Namespace: namespace.Name}, &deployment)).To(Succeed())
|
||||||
Expect(deployment.ObjectMeta.Labels["yyyy"]).To(Equal("xxxx"))
|
Expect(deployment.ObjectMeta.Labels["patch"]).To(Equal("json6902"))
|
||||||
Expect(*deployment.Spec.Replicas).To(Equal(int32(2)))
|
Expect(*deployment.Spec.Replicas).To(Equal(int32(2)))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -104,6 +104,13 @@ func (kg *KustomizeGenerator) WriteFile(ctx context.Context, dirPath string) (st
|
||||||
kus.Namespace = kg.kustomization.Spec.TargetNamespace
|
kus.Namespace = kg.kustomization.Spec.TargetNamespace
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, m := range kg.kustomization.Spec.Patches {
|
||||||
|
kus.Patches = append(kus.Patches, kustypes.Patch{
|
||||||
|
Patch: m.Patch,
|
||||||
|
Target: adaptSelector(&m.Target),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
for _, m := range kg.kustomization.Spec.PatchesStrategicMerge {
|
for _, m := range kg.kustomization.Spec.PatchesStrategicMerge {
|
||||||
kus.PatchesStrategicMerge = append(kus.PatchesStrategicMerge, kustypes.PatchStrategicMerge(m.Raw))
|
kus.PatchesStrategicMerge = append(kus.PatchesStrategicMerge, kustypes.PatchStrategicMerge(m.Raw))
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,6 +198,20 @@ bool
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
|
<code>patches</code><br>
|
||||||
|
<em>
|
||||||
|
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/kustomize#Patch">
|
||||||
|
[]github.com/fluxcd/pkg/apis/kustomize.Patch
|
||||||
|
</a>
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<em>(Optional)</em>
|
||||||
|
<p>Patches (also called overlays), defined as inline YAML objects.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
<code>patchesStrategicMerge</code><br>
|
<code>patchesStrategicMerge</code><br>
|
||||||
<em>
|
<em>
|
||||||
<a href="https://pkg.go.dev/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1?tab=doc#JSON">
|
<a href="https://pkg.go.dev/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1?tab=doc#JSON">
|
||||||
|
@ -657,6 +671,20 @@ bool
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
|
<code>patches</code><br>
|
||||||
|
<em>
|
||||||
|
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/kustomize#Patch">
|
||||||
|
[]github.com/fluxcd/pkg/apis/kustomize.Patch
|
||||||
|
</a>
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<em>(Optional)</em>
|
||||||
|
<p>Patches (also called overlays), defined as inline YAML objects.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
<code>patchesStrategicMerge</code><br>
|
<code>patchesStrategicMerge</code><br>
|
||||||
<em>
|
<em>
|
||||||
<a href="https://pkg.go.dev/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1?tab=doc#JSON">
|
<a href="https://pkg.go.dev/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1?tab=doc#JSON">
|
||||||
|
|
|
@ -598,14 +598,15 @@ The Kustomization has a set of fields to extend and/or override the Kustomize
|
||||||
patches and namespace on all the Kubernetes objects reconciled by the resource,
|
patches and namespace on all the Kubernetes objects reconciled by the resource,
|
||||||
offering support for the following Kustomize directives:
|
offering support for the following Kustomize directives:
|
||||||
|
|
||||||
- [namespace](https://kubectl.docs.kubernetes.io/references/kustomize/namespace/)
|
- [namespace](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/namespace/)
|
||||||
|
- [patches](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patches/)
|
||||||
- [patchesStrategicMerge](https://kubectl.docs.kubernetes.io/references/kustomize/patchesstrategicmerge/)
|
- [patchesStrategicMerge](https://kubectl.docs.kubernetes.io/references/kustomize/patchesstrategicmerge/)
|
||||||
- [patchesJson6902](https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/)
|
- [patchesJson6902](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patchesjson6902/)
|
||||||
- [images](https://kubectl.docs.kubernetes.io/references/kustomize/images/)
|
- [images](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/images/)
|
||||||
|
|
||||||
### Target namespace
|
### Target namespace
|
||||||
|
|
||||||
To configure the [Kustomize `namespace`](https://kubectl.docs.kubernetes.io/references/kustomize/namespace/)
|
To configure the [Kustomize `namespace`](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/namespace/)
|
||||||
and overwrite the namespace of all the Kubernetes objects reconciled by the `Kustomization`,
|
and overwrite the namespace of all the Kubernetes objects reconciled by the `Kustomization`,
|
||||||
`spec.targetNamespace` can be defined:
|
`spec.targetNamespace` can be defined:
|
||||||
|
|
||||||
|
@ -622,9 +623,35 @@ spec:
|
||||||
|
|
||||||
The `targetNamespace` is expected to exist.
|
The `targetNamespace` is expected to exist.
|
||||||
|
|
||||||
|
### Patches
|
||||||
|
|
||||||
|
To add [Kustomize `patches` entries](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patches/)
|
||||||
|
to the configuration, and patch resources using either a [strategic merge](https://kubectl.docs.kubernetes.io/references/kustomize/glossary#patchstrategicmerge)
|
||||||
|
patch or a [JSON](https://kubectl.docs.kubernetes.io/references/kustomize/glossary#patchjson6902) patch,
|
||||||
|
`spec.patches` items must contain a `target` selector and a `patch` document.
|
||||||
|
The patch can target a single resource or multiple resources
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
metadata:
|
||||||
|
name: podinfo
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
# ...omitted for brevity
|
||||||
|
patches:
|
||||||
|
- patch: |-
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: not-used
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/part-of: test-app
|
||||||
|
```
|
||||||
|
|
||||||
### Strategic Merge patches
|
### Strategic Merge patches
|
||||||
|
|
||||||
To add [Kustomize `patchesStrategicMerge` entries](https://kubectl.docs.kubernetes.io/references/kustomize/patchesstrategicmerge/)
|
To add [Kustomize `patchesStrategicMerge` entries](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patchesstrategicmerge/)
|
||||||
to the configuration, `spec.patchesStrategicMerge` can be defined with a list
|
to the configuration, `spec.patchesStrategicMerge` can be defined with a list
|
||||||
of strategic merge patches in YAML format:
|
of strategic merge patches in YAML format:
|
||||||
|
|
||||||
|
@ -649,7 +676,7 @@ spec:
|
||||||
|
|
||||||
### JSON 6902 patches
|
### JSON 6902 patches
|
||||||
|
|
||||||
To add [Kustomize `patchesJson6902` entries](https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/)
|
To add [Kustomize `patchesJson6902` entries](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patchesjson6902/)
|
||||||
to the configuration, and patch resources using the [JSON 6902 standard](https://tools.ietf.org/html/rfc6902),
|
to the configuration, and patch resources using the [JSON 6902 standard](https://tools.ietf.org/html/rfc6902),
|
||||||
`spec.patchesJson6902`, the items must contain a `target` selector and JSON 6902
|
`spec.patchesJson6902`, the items must contain a `target` selector and JSON 6902
|
||||||
`patch` document:
|
`patch` document:
|
||||||
|
@ -675,7 +702,7 @@ spec:
|
||||||
|
|
||||||
### Images
|
### Images
|
||||||
|
|
||||||
To add [Kustomize `images` entries](https://kubectl.docs.kubernetes.io/references/kustomize/images/)
|
To add [Kustomize `images` entries](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/images/)
|
||||||
to the configuration, and overwrite the name, tag or digest of container images
|
to the configuration, and overwrite the name, tag or digest of container images
|
||||||
without creating patches, `spec.images` can be defined:
|
without creating patches, `spec.images` can be defined:
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue