Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for in-line generic patches to Flux Kustomization API #364

Merged
merged 2 commits into from
Jun 14, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions api/v1beta1/kustomization_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ type KustomizationSpec struct {
// +optional
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.
// +optional
PatchesStrategicMerge []apiextensionsv1.JSON `json:"patchesStrategicMerge,omitempty"`
Expand Down
5 changes: 5 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions config/crd/bases/kustomize.toolkit.fluxcd.io_kustomizations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,41 @@ spec:
- name
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:
description: JSON 6902 patches, defined as inline YAML objects.
items:
Expand Down
61 changes: 56 additions & 5 deletions controllers/kustomization_controller_patch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,62 @@ var _ = Describe("KustomizationReconciler", func() {
Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(Equal("ghcr.io/stefanprodan/podinfo:5.2.0"))
})

It("patches as JSON", func() {
kustomization.Spec.Patches = []kustomize.Patch{
{
Patch: `
- op: add
path: /metadata/labels/patch
value: inline-json
`,
Target: kustomize.Selector{
LabelSelector: "app=podinfo",
},
},
}
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-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":{"xxxx":"yyyy"}}}`),
Raw: []byte(`{"kind":"Deployment","apiVersion":"apps/v1","metadata":{"name":"podinfo","labels":{"patch":"strategic-merge"}}}`),
},
}
Expect(k8sClient.Create(context.TODO(), kustomization)).To(Succeed())
Expand All @@ -160,15 +212,14 @@ var _ = Describe("KustomizationReconciler", func() {

var deployment appsv1.Deployment
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("strategic-merge"))
})

It("JSON6902 patches", func() {
kustomization.Spec.PatchesJSON6902 = []kustomize.JSON6902Patch{
{

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")}},
},
Target: kustomize.Selector{
Expand All @@ -189,7 +240,7 @@ var _ = Describe("KustomizationReconciler", func() {

var deployment appsv1.Deployment
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)))
})
})
Expand Down
7 changes: 7 additions & 0 deletions controllers/kustomization_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ func (kg *KustomizeGenerator) WriteFile(ctx context.Context, dirPath string) (st
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 {
kus.PatchesStrategicMerge = append(kus.PatchesStrategicMerge, kustypes.PatchStrategicMerge(m.Raw))
}
Expand Down
28 changes: 28 additions & 0 deletions docs/api/kustomize.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,20 @@ bool
</tr>
<tr>
<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>
<em>
<a href="https://pkg.go.dev/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1?tab=doc#JSON">
Expand Down Expand Up @@ -657,6 +671,20 @@ bool
</tr>
<tr>
<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>
<em>
<a href="https://pkg.go.dev/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1?tab=doc#JSON">
Expand Down
41 changes: 34 additions & 7 deletions docs/spec/v1beta1/kustomization.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
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/)
- [patchesJson6902](https://kubectl.docs.kubernetes.io/references/kustomize/patchesjson6902/)
- [images](https://kubectl.docs.kubernetes.io/references/kustomize/images/)
- [patchesJson6902](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patchesjson6902/)
- [images](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/images/)

### 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`,
`spec.targetNamespace` can be defined:

Expand All @@ -622,9 +623,35 @@ spec:

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

items must contain a target but in the blow example there is no target specified

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the catch :)

In the original Kustomize resource, it's possible to apply a strategic merge patch (not JSON6902) without specifying the target.
I decided to force the target to be present in the Flux implementation for simplicity. Maybe that is something could be added in the future.

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

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
of strategic merge patches in YAML format:

Expand All @@ -649,7 +676,7 @@ spec:

### 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),
`spec.patchesJson6902`, the items must contain a `target` selector and JSON 6902
`patch` document:
Expand All @@ -675,7 +702,7 @@ spec:

### 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
without creating patches, `spec.images` can be defined:

Expand Down