kustomize: ignore Components directories missing a kustomization file

The `ignoreMissingComponents` switch for Kustomize Applications
currently consider a Component specified in the Application spec as
present if the directory exists, which is not enough for kustomize
itself, which needs a not empty kustomization.yml file (with 3 filenames
accepted)

There is however some use cases where the directory exists, but not the
components: for instance, when using ApplicationSets, another file in
the directory can control the generation of an Application, even if it
does not need modification with a Component.

Check that the kustomization file exists to make that workflow possible.

We don't check that the file is valid, though, as:
1. This amount to reimplementing kustomize validation
2. Silently skipping an invalid file is more surprising than just
   skipping an absent one.

Signed-off-by: Max Gautier <mg@max.gautier.name>
This commit is contained in:
Max Gautier 2026-02-23 16:58:06 +01:00
parent 5e974b03d3
commit fe8a70cbb5
No known key found for this signature in database
4 changed files with 37 additions and 8 deletions

View file

@ -133,7 +133,7 @@ spec:
## Components
Kustomize [components](https://github.com/kubernetes-sigs/kustomize/blob/master/examples/components.md) encapsulate both resources and patches together. They provide a powerful way to modularize and reuse configuration in Kubernetes applications.
If Kustomize is passed a non-existing component directory, it will error out. Missing component directories can be ignored (meaning, not passed to Kustomize) using `ignoreMissingComponents`. This can be particularly helpful to implement a [default/override pattern].
If Kustomize is passed a non-existing component directory, it will error out. Missing or invalid (missing a Kustomization file) component directories can be ignored (meaning, not passed to Kustomize) using `ignoreMissingComponents`. This can be particularly helpful to implement a [default/override pattern].
Outside of Argo CD, to utilize components, you must add the following to the `kustomization.yaml` that the Application references. For example:
```yaml

View file

@ -351,17 +351,24 @@ func (k *kustomize) Build(opts *v1alpha1.ApplicationSourceKustomize, kustomizeOp
return nil, nil, nil, fmt.Errorf("failed to open the repo folder: %w", err)
}
kustomizationFileValidNames := []string{"kustomization.yaml", "kustomization.yml", "Kustomization"}
component:
for _, c := range opts.Components {
resolvedPath, err := filepath.Rel(k.repoRoot, filepath.Join(k.path, c))
componentDir, err := filepath.Rel(k.repoRoot, filepath.Join(k.path, c))
if err != nil {
return nil, nil, nil, fmt.Errorf("kustomize components path failed: %w", err)
}
_, err = root.Stat(resolvedPath)
if err != nil {
log.Debugf("%s component directory does not exist", resolvedPath)
continue
for _, kustomizationFile := range kustomizationFileValidNames {
kustomization, err := root.Stat(filepath.Join(componentDir, kustomizationFile))
if err == nil && kustomization.Mode().IsRegular() {
foundComponents = append(foundComponents, c)
log.Infof("Adding component '%s' to kustomization.yaml", c)
break component
}
}
foundComponents = append(foundComponents, c)
log.Infof("Ignoring component '%s': directory does not exist or unable to find one of %s",
componentDir,
strings.Join(kustomizationFileValidNames, ", "))
}
}

View file

@ -495,13 +495,29 @@ func TestKustomizeBuildComponents(t *testing.T) {
}
_, _, _, err = kustomize.Build(&kustomizeSource, nil, nil, nil)
require.Error(t, err)
kustomizeSource = v1alpha1.ApplicationSourceKustomize{
Components: []string{"./components", "./components_no_kustomization"},
IgnoreMissingComponents: false,
}
_, _, _, err = kustomize.Build(&kustomizeSource, nil, nil, nil)
require.Error(t, err)
// `kustomize edit add component` works if the directory exists even if there is no kustomization.yaml inside,
// but then `kustomize build` fails
// Reset the kustomize app so we don't let components_no_kustomization in the kustomization.yaml
appPath, err = testDataDir(t, kustomization6)
require.NoError(t, err)
kustomize = NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "", "", "")
kustomizeSource = v1alpha1.ApplicationSourceKustomize{
Components: []string{"./components", "./missing-components"},
Components: []string{"./components", "./missing-components", "./components_no_kustomization"},
IgnoreMissingComponents: true,
}
objs, _, _, err := kustomize.Build(&kustomizeSource, nil, nil, nil)
require.NoError(t, err)
for _, o := range objs {
assert.NotEqual(t, "notproduced", o.GetName())
}
obj := objs[0]
assert.Equal(t, "nginx-deployment", obj.GetName())
assert.Equal(t, map[string]string{

View file

@ -0,0 +1,6 @@
kind: ConfigMap
apiVersion: v1
metadata:
name: notproduced
data:
somekey: somevalue