Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
20 changes: 20 additions & 0 deletions api/v1/kustomization_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,13 @@ type KustomizationSpec struct {
// +optional
Wait bool `json:"wait,omitempty"`

// BuildMetadata specifies which kustomize build metadata should be added
// to the built resources. The allowed values are 'originAnnotations' to
// annotate resources with their source origin, and 'transformerAnnotations'
// to annotate resources with the transformers that produced them.
// +optional
BuildMetadata []BuildMetadataOption `json:"buildMetadata,omitempty"`

// Components specifies relative paths to kustomize Components.
// +optional
Components []string `json:"components,omitempty"`
Expand All @@ -194,6 +201,19 @@ type KustomizationSpec struct {
HealthCheckExprs []kustomize.CustomHealthCheck `json:"healthCheckExprs,omitempty"`
}

// BuildMetadataOption defines the supported buildMetadata options.
// +kubebuilder:validation:Enum=originAnnotations;transformerAnnotations
type BuildMetadataOption string

const (
// BuildMetadataOriginAnnotations enables config.kubernetes.io/origin annotations
// that track which file and path each resource was loaded from.
BuildMetadataOriginAnnotations BuildMetadataOption = "originAnnotations"
// BuildMetadataTransformerAnnotations enables internal.config.kubernetes.io annotations
// that record which kustomize transformers modified each resource.
BuildMetadataTransformerAnnotations BuildMetadataOption = "transformerAnnotations"
)

// CommonMetadata defines the common labels and annotations.
type CommonMetadata struct {
// Annotations to be added to the object's metadata.
Expand Down
5 changes: 5 additions & 0 deletions api/v1/zz_generated.deepcopy.go

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

14 changes: 14 additions & 0 deletions config/crd/bases/kustomize.toolkit.fluxcd.io_kustomizations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,20 @@ spec:
KustomizationSpec defines the configuration to calculate the desired state
from a Source using Kustomize.
properties:
buildMetadata:
description: |-
BuildMetadata specifies which kustomize build metadata should be added
to the built resources. The allowed values are 'originAnnotations' to
annotate resources with their source origin, and 'transformerAnnotations'
to annotate resources with the transformers that produced them.
items:
description: BuildMetadataOption defines the supported buildMetadata
options.
enum:
- originAnnotations
- transformerAnnotations
type: string
type: array
commonMetadata:
description: |-
CommonMetadata specifies the common labels and annotations that are
Expand Down
41 changes: 41 additions & 0 deletions docs/api/v1/kustomize.md
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,23 @@ resources. When enabled, the HealthChecks are ignored. Defaults to false.</p>
</tr>
<tr>
<td>
<code>buildMetadata</code><br>
<em>
<a href="#kustomize.toolkit.fluxcd.io/v1.BuildMetadataOption">
[]BuildMetadataOption
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>BuildMetadata specifies which kustomize build metadata should be added
to the built resources. The allowed values are &lsquo;originAnnotations&rsquo; to
annotate resources with their source origin, and &lsquo;transformerAnnotations&rsquo;
to annotate resources with the transformers that produced them.</p>
</td>
</tr>
<tr>
<td>
<code>components</code><br>
<em>
[]string
Expand Down Expand Up @@ -444,6 +461,13 @@ KustomizationStatus
</table>
</div>
</div>
<h3 id="kustomize.toolkit.fluxcd.io/v1.BuildMetadataOption">BuildMetadataOption
(<code>string</code> alias)</h3>
<p>
(<em>Appears on:</em>
<a href="#kustomize.toolkit.fluxcd.io/v1.KustomizationSpec">KustomizationSpec</a>)
</p>
<p>BuildMetadataOption defines the supported buildMetadata options.</p>
<h3 id="kustomize.toolkit.fluxcd.io/v1.CommonMetadata">CommonMetadata
</h3>
<p>
Expand Down Expand Up @@ -1018,6 +1042,23 @@ resources. When enabled, the HealthChecks are ignored. Defaults to false.</p>
</tr>
<tr>
<td>
<code>buildMetadata</code><br>
<em>
<a href="#kustomize.toolkit.fluxcd.io/v1.BuildMetadataOption">
[]BuildMetadataOption
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>BuildMetadata specifies which kustomize build metadata should be added
to the built resources. The allowed values are &lsquo;originAnnotations&rsquo; to
annotate resources with their source origin, and &lsquo;transformerAnnotations&rsquo;
to annotate resources with the transformers that produced them.</p>
</td>
</tr>
<tr>
<td>
<code>components</code><br>
<em>
[]string
Expand Down
35 changes: 35 additions & 0 deletions docs/spec/v1/kustomizations.md
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,41 @@ spec:
digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
```

### Build metadata

`.spec.buildMetadata` is an optional list used to specify which
[Kustomize `buildMetadata`](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/buildmetadata/)
options should be added to the built resources. The allowed values are:

- `originAnnotations`: Adds `config.kubernetes.io/origin` annotations that
track which file and path each resource was loaded from.
- `transformerAnnotations`: Adds `internal.config.kubernetes.io` annotations
that record which kustomize transformers modified each resource.

```yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: podinfo
namespace: flux-system
spec:
# ...omitted for brevity
buildMetadata:
- originAnnotations
```

When `originAnnotations` is enabled, each resource gets an annotation like:

```yaml
metadata:
annotations:
config.kubernetes.io/origin: |
path: apps/deployment.yaml
```

This is useful for debugging, auditing, and tooling that needs to trace
resources back to their source files.

### Components

`.spec.components` is an optional list used to specify
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ require (
github.com/fluxcd/pkg/auth v0.40.0
github.com/fluxcd/pkg/cache v0.13.0
github.com/fluxcd/pkg/http/fetch v0.22.0
github.com/fluxcd/pkg/kustomize v1.28.0
github.com/fluxcd/pkg/kustomize v1.29.0
github.com/fluxcd/pkg/runtime v0.103.0
github.com/fluxcd/pkg/ssa v0.70.0
github.com/fluxcd/pkg/tar v0.17.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,8 @@ github.com/fluxcd/pkg/envsubst v1.5.0 h1:S07mo+MkGhptdHA4pRze5HPKlc8tHxKswNdcMZi
github.com/fluxcd/pkg/envsubst v1.5.0/go.mod h1:c3a8DYI855sZUubHFYQbjfjop6Wu4/zg1cLyf7SnCes=
github.com/fluxcd/pkg/http/fetch v0.22.0 h1:FT8CfstPE/e7+KRxNrx8ZJ1Uj5rkR5wXOtvQJurNQ0U=
github.com/fluxcd/pkg/http/fetch v0.22.0/go.mod h1:X+8wF3peP79TyyDSgCJiavz+fAcYaf7CRXSeu7ccsPA=
github.com/fluxcd/pkg/kustomize v1.28.0 h1:0RuFVczJRabbt8frHZ/ql8aqte6BOOKk274O09l6/hE=
github.com/fluxcd/pkg/kustomize v1.28.0/go.mod h1:cW08mnngSP8MJYb6mDmMvxH8YjNATdiML0udb37dk+M=
github.com/fluxcd/pkg/kustomize v1.29.0 h1:B/5hr9wX6INwaQAZ6BGKVNvZm++A6qjgorUfoaBAwPw=
github.com/fluxcd/pkg/kustomize v1.29.0/go.mod h1:cW08mnngSP8MJYb6mDmMvxH8YjNATdiML0udb37dk+M=
github.com/fluxcd/pkg/runtime v0.103.0 h1:J5y5GPhWdkyqIUBlaI1FP2N02TtZmsjbWhhZubuTSFk=
github.com/fluxcd/pkg/runtime v0.103.0/go.mod h1:mbo2f3azo3yVQgm7XZGxQB6/2zvzQ5Wgtd8TjRRwwAw=
github.com/fluxcd/pkg/sourceignore v0.17.0 h1:Z72nruRMhC15zIEpWoDrAcJcJ1El6QDnP/aRDfE4WOA=
Expand Down
101 changes: 101 additions & 0 deletions internal/controller/kustomization_transformer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -604,3 +604,104 @@ func checkSecret(list *corev1.SecretList, name string) bool {

return false
}

func TestKustomizationReconciler_BuildMetadata(t *testing.T) {
g := NewWithT(t)
id := "bm-" + randStringRunes(5)
revision := "v1.0.0"
resultK := &kustomizev1.Kustomization{}

err := createNamespace(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")

err = createKubeConfigSecret(id)
g.Expect(err).NotTo(HaveOccurred(), "failed to create kubeconfig secret")

manifests := func(name string) []testserver.File {
return []testserver.File{
{
Name: "config.yaml",
Body: fmt.Sprintf(`---
apiVersion: v1
kind: ConfigMap
metadata:
name: %[1]s
data:
key: val
`, name),
},
}
}

artifact, err := testServer.ArtifactFromFiles(manifests(id))
g.Expect(err).NotTo(HaveOccurred())

repositoryName := types.NamespacedName{
Name: fmt.Sprintf("bm-%s", randStringRunes(5)),
Namespace: id,
}

err = applyGitRepository(repositoryName, artifact, revision)
g.Expect(err).NotTo(HaveOccurred())

kustomizationKey := types.NamespacedName{
Name: fmt.Sprintf("bm-%s", randStringRunes(5)),
Namespace: id,
}
kustomization := &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: kustomizationKey.Name,
Namespace: kustomizationKey.Namespace,
},
Spec: kustomizev1.KustomizationSpec{
Interval: metav1.Duration{Duration: 2 * time.Minute},
Path: "./",
KubeConfig: &meta.KubeConfigReference{
SecretRef: &meta.SecretKeyReference{
Name: "kubeconfig",
},
},
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Name: repositoryName.Name,
Namespace: repositoryName.Namespace,
Kind: sourcev1.GitRepositoryKind,
},
Prune: true,
BuildMetadata: []kustomizev1.BuildMetadataOption{
kustomizev1.BuildMetadataOriginAnnotations,
},
TargetNamespace: id,
},
}

g.Expect(k8sClient.Create(context.Background(), kustomization)).To(Succeed())

t.Run("sets origin annotations", func(t *testing.T) {
g := NewWithT(t)
g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
return isReconcileSuccess(resultK)
}, timeout, time.Second).Should(BeTrue())
kstatusCheck.CheckErr(ctx, resultK)

var cm corev1.ConfigMap
g.Expect(k8sClient.Get(context.Background(), client.ObjectKey{Name: id, Namespace: id}, &cm)).To(Succeed())
g.Expect(cm.GetAnnotations()).To(HaveKey("config.kubernetes.io/origin"))
})

t.Run("removes origin annotations", func(t *testing.T) {
g := NewWithT(t)
resultK.Spec.BuildMetadata = nil
g.Expect(k8sClient.Update(context.Background(), resultK)).To(Succeed())

g.Eventually(func() bool {
_ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
return isReconcileSuccess(resultK)
}, timeout, time.Second).Should(BeTrue())
kstatusCheck.CheckErr(ctx, resultK)

var cm corev1.ConfigMap
g.Expect(k8sClient.Get(context.Background(), client.ObjectKey{Name: id, Namespace: id}, &cm)).To(Succeed())
g.Expect(cm.GetAnnotations()).ToNot(HaveKey("config.kubernetes.io/origin"))
})
}
Loading