From 9cd73104237ab1d35a51c0b4bb0fad1e1a6f04a0 Mon Sep 17 00:00:00 2001 From: Kristian Klausen Date: Fri, 28 Oct 2022 14:14:57 +0200 Subject: [PATCH] Add support for Kustomize components Fix #753 Signed-off-by: Kristian Klausen --- api/v1beta2/kustomization_types.go | 4 ++ api/v1beta2/zz_generated.deepcopy.go | 5 ++ ...mize.toolkit.fluxcd.io_kustomizations.yaml | 6 +++ docs/spec/v1beta2/kustomization.md | 26 ++++++++++ internal/generator/generator.go | 25 ++++++++++ internal/generator/generator_test.go | 49 +++++++++++++++++++ .../components/components/kustomization.yaml | 7 +++ .../zero-components/kustomization.yaml | 5 ++ 8 files changed, 127 insertions(+) create mode 100644 internal/generator/testdata/components/components/kustomization.yaml create mode 100644 internal/generator/testdata/components/zero-components/kustomization.yaml diff --git a/api/v1beta2/kustomization_types.go b/api/v1beta2/kustomization_types.go index 09a5739b..6b307ff8 100644 --- a/api/v1beta2/kustomization_types.go +++ b/api/v1beta2/kustomization_types.go @@ -153,6 +153,10 @@ type KustomizationSpec struct { // +kubebuilder:validation:Enum=none;client;server // +optional Validation string `json:"validation,omitempty"` + + // Components specifies relative paths to specifications of other Components + // +optional + Components []string `json:"components,omitempty"` } // Decryption defines how decryption is handled for Kubernetes manifests. diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go index 93ab196c..0ef46eab 100644 --- a/api/v1beta2/zz_generated.deepcopy.go +++ b/api/v1beta2/zz_generated.deepcopy.go @@ -187,6 +187,11 @@ func (in *KustomizationSpec) DeepCopyInto(out *KustomizationSpec) { *out = new(v1.Duration) **out = **in } + if in.Components != nil { + in, out := &in.Components, &out.Components + *out = make([]string, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KustomizationSpec. diff --git a/config/crd/bases/kustomize.toolkit.fluxcd.io_kustomizations.yaml b/config/crd/bases/kustomize.toolkit.fluxcd.io_kustomizations.yaml index 0b4cc2a0..13a3cc30 100644 --- a/config/crd/bases/kustomize.toolkit.fluxcd.io_kustomizations.yaml +++ b/config/crd/bases/kustomize.toolkit.fluxcd.io_kustomizations.yaml @@ -585,6 +585,12 @@ spec: description: KustomizationSpec defines the configuration to calculate the desired state from a Source using Kustomize. properties: + components: + description: Components specifies relative paths to specifications + of other Components + items: + type: string + type: array decryption: description: Decrypt Kubernetes secrets before applying them on the cluster. diff --git a/docs/spec/v1beta2/kustomization.md b/docs/spec/v1beta2/kustomization.md index f45e5edc..23ec2853 100644 --- a/docs/spec/v1beta2/kustomization.md +++ b/docs/spec/v1beta2/kustomization.md @@ -556,6 +556,7 @@ offering support for the following Kustomize directives: - [namespace](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/namespace/) - [patches](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patches/) - [images](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/images/) +- [components](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/components/) ### Target namespace @@ -654,6 +655,31 @@ spec: digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3 ``` +### Components + +To add [Kustomize `components` entries](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/components/) +to the configuration, and use reusable pieces of configuration logic that can +be included from multiple overlays, `spec.components` can be defined: + +```yaml +apiVersion: kustomize.toolkit.fluxcd.io/v1beta2 +kind: Kustomization +metadata: + name: podinfo + namespace: flux-system +spec: + # ...omitted for brevity + components: + - ingress + - tls +``` + +**Note:** The component paths must be local and relative. + +**Warning:** Components are a alpha feature in Kustomize and are therefore +considered experimental in Flux. No guarantees are provided and the feature may +be modified in backwards incompatible ways or removed without warning. + ## Variable substitution With `spec.postBuild.substitute` you can provide a map of key/value pairs holding the diff --git a/internal/generator/generator.go b/internal/generator/generator.go index cb7ed971..6db21d1f 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -79,6 +79,13 @@ func (kg *KustomizeGenerator) WriteFile(dirPath string) (string, error) { }) } + for _, m := range kg.kustomization.Spec.Components { + if !isLocalRelativePath(m) { + return "", fmt.Errorf("component path '%s' must be local and relative", m) + } + kus.Components = append(kus.Components, m) + } + for _, m := range kg.kustomization.Spec.PatchesStrategicMerge { kus.PatchesStrategicMerge = append(kus.PatchesStrategicMerge, kustypes.PatchStrategicMerge(m.Raw)) } @@ -234,3 +241,21 @@ func adaptSelector(selector *kustomize.Selector) (output *kustypes.Selector) { } return } + +func isLocalRelativePath(path string) bool { + // From: https://github.com/kubernetes-sigs/kustomize/blob/84bd402cc0662c5df3f109c4f80c22611243c5f9/api/internal/git/repospec.go#L231-L239 + // with "file://" removed/ + for _, p := range []string{ + // Order matters here. + "git::", "gh:", "ssh://", "https://", "http://", + "git@", "github.com:", "github.com/"} { + if len(p) < len(path) && strings.ToLower(path[:len(p)]) == p { + return false + } + } + + if filepath.IsAbs(path) || filepath.IsAbs(strings.TrimPrefix(strings.ToLower(path), "file://")) { + return false + } + return true +} diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go index 13a0fc24..787f319f 100644 --- a/internal/generator/generator_test.go +++ b/internal/generator/generator_test.go @@ -93,3 +93,52 @@ func TestGenerator_WriteFile(t *testing.T) { }) } } + +func TestGenerator_Components(t *testing.T) { + tests := []struct { + name string + dir string + fluxComponents []string + expectedComponents []string + }{ + { + name: "test kustomization.yaml with components and Flux Kustomization without components", + dir: "components", + fluxComponents: []string{}, + expectedComponents: []string{"componentA"}, + }, + { + name: "test kustomization.yaml without components and Flux Kustomization with components", + dir: "zero-components", + fluxComponents: []string{"componentB", "componentC"}, + expectedComponents: []string{"componentB", "componentC"}, + }, + { + name: "test kustomization.yaml with components and Flux Kustomization with components", + dir: "components", + fluxComponents: []string{"componentB", "componentC"}, + expectedComponents: []string{"componentA", "componentB", "componentC"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + tmpDir := t.TempDir() + g.Expect(copy.Copy("./testdata/components", tmpDir)).To(Succeed()) + ks := v1beta2.Kustomization{ + Spec: v1beta2.KustomizationSpec{ + Components: tt.fluxComponents, + }, + } + kfile, err := NewGenerator(filepath.Join(tmpDir, tt.dir), &ks).WriteFile(filepath.Join(tmpDir, tt.dir)) + g.Expect(err).ToNot(HaveOccurred()) + + kfileYAML, err := os.ReadFile(kfile) + g.Expect(err).ToNot(HaveOccurred()) + var k kustypes.Kustomization + g.Expect(k.Unmarshal(kfileYAML)).To(Succeed()) + g.Expect(k.Components).Should(Equal(tt.expectedComponents)) + }) + } +} diff --git a/internal/generator/testdata/components/components/kustomization.yaml b/internal/generator/testdata/components/components/kustomization.yaml new file mode 100644 index 00000000..a85800f5 --- /dev/null +++ b/internal/generator/testdata/components/components/kustomization.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - configmap.yaml +components: + - componentA diff --git a/internal/generator/testdata/components/zero-components/kustomization.yaml b/internal/generator/testdata/components/zero-components/kustomization.yaml new file mode 100644 index 00000000..bbfab0ea --- /dev/null +++ b/internal/generator/testdata/components/zero-components/kustomization.yaml @@ -0,0 +1,5 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - configmap.yaml