mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
Localize helm fields (#4978)
* Localize helm fields * Address readability feedback * Handle edge cases * Improve readability Split copyChartHome and use existence to prevent repeated copying.
This commit is contained in:
@@ -83,7 +83,7 @@ func (p *HelmChartInflationGeneratorPlugin) validateArgs() (err error) {
|
||||
// the loader root (unless root restrictions are
|
||||
// disabled, in which case this can be an absolute path).
|
||||
if p.ChartHome == "" {
|
||||
p.ChartHome = "charts"
|
||||
p.ChartHome = types.HelmDefaultHome
|
||||
}
|
||||
|
||||
// The ValuesFile may be consulted by the plugin, so it must
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
package localizer
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
@@ -119,11 +121,11 @@ func (lc *localizer) load() (*types.Kustomization, string, error) {
|
||||
// built-in understanding of. This excludes helm-related fields, such as `helmGlobals` and `helmCharts`.
|
||||
func (lc *localizer) localizeNativeFields(kust *types.Kustomization) error {
|
||||
if path, exists := kust.OpenAPI["path"]; exists {
|
||||
newPath, err := lc.localizeFile(path)
|
||||
locPath, err := lc.localizeFile(path)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "unable to localize openapi path")
|
||||
}
|
||||
kust.OpenAPI["path"] = newPath
|
||||
kust.OpenAPI["path"] = locPath
|
||||
}
|
||||
|
||||
for fieldName, field := range map[string]struct {
|
||||
@@ -134,11 +136,11 @@ func (lc *localizer) localizeNativeFields(kust *types.Kustomization) error {
|
||||
// Allow use of deprecated field
|
||||
//nolint:staticcheck
|
||||
kust.Bases,
|
||||
lc.localizeDir,
|
||||
lc.localizeRoot,
|
||||
},
|
||||
"components": {
|
||||
kust.Components,
|
||||
lc.localizeDir,
|
||||
lc.localizeRoot,
|
||||
},
|
||||
"configurations": {
|
||||
kust.Configurations,
|
||||
@@ -172,6 +174,12 @@ func (lc *localizer) localizeNativeFields(kust *types.Kustomization) error {
|
||||
return errors.WrapPrefixf(err, "unable to localize secretGenerator")
|
||||
}
|
||||
}
|
||||
if err := lc.localizeHelmInflationGenerator(kust); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := lc.localizeHelmCharts(kust); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := lc.localizePatches(kust.Patches); err != nil {
|
||||
return errors.WrapPrefixf(err, "unable to localize patches")
|
||||
}
|
||||
@@ -181,34 +189,29 @@ func (lc *localizer) localizeNativeFields(kust *types.Kustomization) error {
|
||||
}
|
||||
//nolint:staticcheck
|
||||
for i, patch := range kust.PatchesStrategicMerge {
|
||||
localizedPath, err := lc.localizeK8sResource(string(patch))
|
||||
locPath, err := lc.localizeK8sResource(string(patch))
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "unable to localize patchesStrategicMerge entry")
|
||||
}
|
||||
if localizedPath != "" {
|
||||
kust.PatchesStrategicMerge[i] = types.PatchStrategicMerge(localizedPath)
|
||||
if locPath != "" {
|
||||
kust.PatchesStrategicMerge[i] = types.PatchStrategicMerge(locPath)
|
||||
}
|
||||
}
|
||||
for i, replacement := range kust.Replacements {
|
||||
if replacement.Path != "" {
|
||||
newPath, err := lc.localizeFile(replacement.Path)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "unable to localize replacements entry")
|
||||
}
|
||||
kust.Replacements[i].Path = newPath
|
||||
locPath, err := lc.localizeFile(replacement.Path)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "unable to localize replacements entry")
|
||||
}
|
||||
kust.Replacements[i].Path = locPath
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// localizeGenerator localizes the file paths on generator.
|
||||
func (lc *localizer) localizeGenerator(generator *types.GeneratorArgs) (err error) {
|
||||
var locEnvSrc string
|
||||
if generator.EnvSource != "" {
|
||||
locEnvSrc, err = lc.localizeFile(generator.EnvSource)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "unable to localize generator env file")
|
||||
}
|
||||
func (lc *localizer) localizeGenerator(generator *types.GeneratorArgs) error {
|
||||
locEnvSrc, err := lc.localizeFile(generator.EnvSource)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "unable to localize generator env file")
|
||||
}
|
||||
locEnvs := make([]string, len(generator.EnvSources))
|
||||
for i, env := range generator.EnvSources {
|
||||
@@ -238,16 +241,58 @@ func (lc *localizer) localizeGenerator(generator *types.GeneratorArgs) (err erro
|
||||
return nil
|
||||
}
|
||||
|
||||
// localizeHelmInflationGenerator localizes helmChartInflationGenerator on kust.
|
||||
// localizeHelmInflationGenerator localizes values files and copies local chart homes.
|
||||
func (lc *localizer) localizeHelmInflationGenerator(kust *types.Kustomization) error {
|
||||
for i, chart := range kust.HelmChartInflationGenerator {
|
||||
locFile, err := lc.localizeFile(chart.Values)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "unable to localize helmChartInflationGenerator entry %d values", i)
|
||||
}
|
||||
kust.HelmChartInflationGenerator[i].Values = locFile
|
||||
|
||||
locDir, err := lc.copyChartHomeEntry(chart.ChartHome)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "unable to copy helmChartInflationGenerator entry %d", i)
|
||||
}
|
||||
kust.HelmChartInflationGenerator[i].ChartHome = locDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// localizeHelmCharts localizes helmCharts and helmGlobals on kust.
|
||||
// localizeHelmCharts localizes values files and copies a local chart home.
|
||||
func (lc *localizer) localizeHelmCharts(kust *types.Kustomization) error {
|
||||
for i, chart := range kust.HelmCharts {
|
||||
locFile, err := lc.localizeFile(chart.ValuesFile)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "unable to localize helmCharts entry %d valuesFile", i)
|
||||
}
|
||||
kust.HelmCharts[i].ValuesFile = locFile
|
||||
}
|
||||
if kust.HelmGlobals != nil {
|
||||
locDir, err := lc.copyChartHomeEntry(kust.HelmGlobals.ChartHome)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "unable to copy helmGlobals")
|
||||
}
|
||||
kust.HelmGlobals.ChartHome = locDir
|
||||
} else if len(kust.HelmCharts) > 0 {
|
||||
_, err := lc.copyChartHomeEntry("")
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "unable to copy default chart home")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// localizePatches localizes the file paths on patches if they are non-empty
|
||||
func (lc *localizer) localizePatches(patches []types.Patch) error {
|
||||
for i := range patches {
|
||||
if patches[i].Path != "" {
|
||||
newPath, err := lc.localizeFile(patches[i].Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
patches[i].Path = newPath
|
||||
locPath, err := lc.localizeFile(patches[i].Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
patches[i].Path = locPath
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -272,7 +317,7 @@ func (lc *localizer) localizeResource(path string) (string, error) {
|
||||
}
|
||||
if fileErr != nil {
|
||||
var rootErr error
|
||||
locPath, rootErr = lc.localizeDir(path)
|
||||
locPath, rootErr = lc.localizeRoot(path)
|
||||
if rootErr != nil {
|
||||
err := PathLocalizeError{
|
||||
Path: path,
|
||||
@@ -285,8 +330,13 @@ func (lc *localizer) localizeResource(path string) (string, error) {
|
||||
return locPath, nil
|
||||
}
|
||||
|
||||
// localizeFile localizes file path and returns the localized path
|
||||
// localizeFile localizes file path if set and returns the localized path
|
||||
func (lc *localizer) localizeFile(path string) (string, error) {
|
||||
// Some localizable fields can be empty, for example, replacements.path.
|
||||
// We rely on the build command to throw errors for the ones that cannot.
|
||||
if path == "" {
|
||||
return "", nil
|
||||
}
|
||||
content, err := lc.ldr.Load(path)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err)
|
||||
@@ -324,8 +374,11 @@ func (lc *localizer) localizeFileWithContent(path string, content []byte) (strin
|
||||
return locPath, nil
|
||||
}
|
||||
|
||||
// localizeDir localizes root path and returns the localized path
|
||||
func (lc *localizer) localizeDir(path string) (string, error) {
|
||||
// localizeRoot localizes root path if set and returns the localized path
|
||||
func (lc *localizer) localizeRoot(path string) (string, error) {
|
||||
if path == "" {
|
||||
return "", nil
|
||||
}
|
||||
ldr, err := lc.ldr.New(path)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err)
|
||||
@@ -368,6 +421,106 @@ func (lc *localizer) localizeDir(path string) (string, error) {
|
||||
return locPath, nil
|
||||
}
|
||||
|
||||
// copyChartHomeEntry copies the helm chart home entry to lc dst
|
||||
// at the same location relative to the root and returns said relative path.
|
||||
// If entry is empty, copyChartHomeEntry returns the empty string.
|
||||
// If entry does not exist, copyChartHome returns entry.
|
||||
//
|
||||
// copyChartHomeEntry copies the default home to the same location at dst,
|
||||
// without following symlinks. An empty entry also indicates the default home.
|
||||
func (lc *localizer) copyChartHomeEntry(entry string) (string, error) {
|
||||
path := entry
|
||||
if entry == "" {
|
||||
path = types.HelmDefaultHome
|
||||
}
|
||||
if filepath.IsAbs(path) {
|
||||
return "", errors.Errorf("absolute path %q not handled in alpha", path)
|
||||
}
|
||||
isDefault := lc.root.Join(path) == lc.root.Join(types.HelmDefaultHome)
|
||||
locPath, err := lc.copyChartHome(path, !isDefault)
|
||||
if err != nil {
|
||||
return "", errors.WrapPrefixf(err, "unable to copy home %q", entry)
|
||||
}
|
||||
if entry == "" {
|
||||
return "", nil
|
||||
}
|
||||
return locPath, nil
|
||||
}
|
||||
|
||||
// copyChartHome copies path relative to lc root to dst and returns the
|
||||
// copied location relative to dst. If clean is true, copyChartHome uses path's
|
||||
// delinked location as the copy destination.
|
||||
//
|
||||
// If path does not exist, copyChartHome returns path.
|
||||
func (lc *localizer) copyChartHome(path string, clean bool) (string, error) {
|
||||
path, err := filepath.Rel(lc.root.String(), lc.root.Join(path))
|
||||
if err != nil {
|
||||
return "", errors.WrapPrefixf(err, "no path to chart home %q", path)
|
||||
}
|
||||
// Chart home may serve as untar destination.
|
||||
// Note that we don't check if path is in scope.
|
||||
if !lc.fSys.Exists(lc.root.Join(path)) {
|
||||
return path, nil
|
||||
}
|
||||
// Perform localize directory checks.
|
||||
ldr, err := lc.ldr.New(path)
|
||||
if err != nil {
|
||||
return "", errors.WrapPrefixf(err, "invalid chart home")
|
||||
}
|
||||
cleaned, err := filesys.ConfirmDir(lc.fSys, ldr.Root())
|
||||
if err != nil {
|
||||
log.Panicf("unable to confirm validated directory %q: %s", ldr.Root(), err)
|
||||
}
|
||||
toDst := path
|
||||
if clean {
|
||||
toDst, err = filepath.Rel(lc.root.String(), cleaned.String())
|
||||
if err != nil {
|
||||
log.Panicf("no path between scoped directories %q and %q: %s", lc.root, cleaned, err)
|
||||
}
|
||||
}
|
||||
// Note this check does not guarantee that we copied the entire directory.
|
||||
if dst := filepath.Join(lc.dst, toDst); !lc.fSys.Exists(dst) {
|
||||
err = lc.copyDir(cleaned, filepath.Join(lc.dst, toDst))
|
||||
if err != nil {
|
||||
return "", errors.WrapPrefixf(err, "unable to copy chart home %q", path)
|
||||
}
|
||||
}
|
||||
return toDst, nil
|
||||
}
|
||||
|
||||
// copyDir copies src to dst. copyDir does not follow symlinks.
|
||||
func (lc *localizer) copyDir(src filesys.ConfirmedDir, dst string) error {
|
||||
err := lc.fSys.Walk(src.String(),
|
||||
func(path string, info fs.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pathToCreate, err := filepath.Rel(src.String(), path)
|
||||
if err != nil {
|
||||
log.Panicf("no path from %q to child file %q: %s", src, path, err)
|
||||
}
|
||||
pathInDst := filepath.Join(dst, pathToCreate)
|
||||
if info.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||
return nil
|
||||
}
|
||||
if info.IsDir() {
|
||||
err = lc.fSys.MkdirAll(pathInDst)
|
||||
} else {
|
||||
var content []byte
|
||||
content, err = lc.fSys.ReadFile(path)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
err = lc.fSys.WriteFile(pathInDst, content)
|
||||
}
|
||||
return errors.Wrap(err)
|
||||
})
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "unable to copy directory %q", src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// localizeBuiltinPlugins localizes built-in plugins on kust that can contain file paths. The built-in plugins
|
||||
// can be inline or in a file. This excludes the HelmChartInflationGenerator.
|
||||
//
|
||||
|
||||
@@ -72,6 +72,10 @@ replacements:
|
||||
delimiter: '='
|
||||
index: 0
|
||||
`
|
||||
|
||||
valuesFile = `minecraftServer:
|
||||
difficulty: peaceful
|
||||
`
|
||||
)
|
||||
|
||||
func makeMemoryFs(t *testing.T) filesys.FileSystem {
|
||||
@@ -208,10 +212,11 @@ patches:
|
||||
func TestLoadKustomizationName(t *testing.T) {
|
||||
kustomization := map[string]string{
|
||||
"Kustomization": `apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
commonLabels:
|
||||
label-one: value-one
|
||||
label-two: value-two
|
||||
kind: Kustomization
|
||||
labels:
|
||||
- pairs:
|
||||
label-one: value-one
|
||||
label-two: value-two
|
||||
`,
|
||||
}
|
||||
checkLocalizeInTargetSuccess(t, kustomization)
|
||||
@@ -235,14 +240,9 @@ func TestLoadGVKNN(t *testing.T) {
|
||||
|
||||
func TestLoadLegacyFields(t *testing.T) {
|
||||
kustomization := map[string]string{
|
||||
// TODO(annasong): Adjust test once localize handles helm.
|
||||
"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
helmChartInflationGenerator:
|
||||
- chartName: minecraft
|
||||
chartRepoUrl: https://kubernetes-charts.storage.googleapis.com
|
||||
chartVersion: v1.2.0
|
||||
releaseName: test
|
||||
values: values.yaml
|
||||
commonLabels:
|
||||
app: bingo
|
||||
imageTags:
|
||||
- name: postgres
|
||||
newName: my-registry/my-postgres
|
||||
@@ -587,7 +587,7 @@ patches:
|
||||
expected, actual := makeFileSystems(t, "/a/b", kustAndPatch)
|
||||
|
||||
err := Run("/a/b", "", "/dst", actual)
|
||||
require.Error(t, err)
|
||||
require.EqualError(t, err, `unable to localize target "/a/b": unable to localize patches: invalid file reference: '/a/b/name-DNE.yaml' doesn't exist`)
|
||||
|
||||
checkFSys(t, expected, actual)
|
||||
}
|
||||
@@ -1124,3 +1124,310 @@ resources:
|
||||
|
||||
checkFSys(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestLocalizeHelmChartInflationGenerator(t *testing.T) {
|
||||
helmKust := map[string]string{
|
||||
"kustomization.yaml": `helmChartInflationGenerator:
|
||||
- chartName: nothing-to-localize
|
||||
chartRepoUrl: https://itzg.github.io/warcraft-server-charts
|
||||
releaseName: moria
|
||||
- chartName: localize-values
|
||||
values: minecraftValues.yaml
|
||||
valuesLocal:
|
||||
minecraftServer:
|
||||
eula: true
|
||||
valuesMerge: replace
|
||||
- chartHome: home
|
||||
chartName: copy-chartHome
|
||||
`,
|
||||
"minecraftValues.yaml": valuesFile,
|
||||
"charts/localize-values/values.yaml": valuesFile,
|
||||
"home/copy-chartHome/values.yaml": valuesFile,
|
||||
}
|
||||
checkLocalizeInTargetSuccess(t, helmKust)
|
||||
}
|
||||
|
||||
func TestLocalizeHelmCharts(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
files map[string]string
|
||||
}{
|
||||
{
|
||||
name: "charts_only",
|
||||
files: map[string]string{
|
||||
"kustomization.yaml": `helmCharts:
|
||||
- name: nothing-to-localize
|
||||
repo: https://helm.releases.hashicorp.com
|
||||
version: 1.0.0
|
||||
- includeCRDs: true
|
||||
name: localize-valuesFile
|
||||
valuesFile: file
|
||||
`,
|
||||
"file": valuesFile,
|
||||
"charts/nothing-to-localize/values.yaml": valuesFile,
|
||||
"charts/localize-valuesFile/values.yaml": valuesFile,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "charts_globals_no_home",
|
||||
files: map[string]string{
|
||||
"kustomization.yaml": `helmCharts:
|
||||
- name: default
|
||||
helmGlobals:
|
||||
configHome: .
|
||||
`,
|
||||
"charts/default/values.yaml": valuesFile,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "home_only",
|
||||
files: map[string]string{
|
||||
"kustomization.yaml": `helmGlobals:
|
||||
chartHome: home
|
||||
`,
|
||||
"home/name/values.yaml": valuesFile,
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
checkLocalizeInTargetSuccess(t, test.files)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizeHelmChartsNoDefault(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"kustomization.yaml": `helmGlobals:
|
||||
chartHome: home
|
||||
`,
|
||||
"home/name/values.yaml": valuesFile,
|
||||
"charts/name/values.yaml": valuesFile,
|
||||
}
|
||||
expected, actual := makeFileSystems(t, "/a", files)
|
||||
|
||||
err := Run("/a", "", "/dst", actual)
|
||||
require.NoError(t, err)
|
||||
|
||||
addFiles(t, expected, "/dst", map[string]string{
|
||||
"kustomization.yaml": files["kustomization.yaml"],
|
||||
"home/name/values.yaml": valuesFile,
|
||||
})
|
||||
checkFSys(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestCopyChartHomeSimple(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
files map[string]string
|
||||
}{
|
||||
{
|
||||
name: "does_not_exist",
|
||||
files: map[string]string{
|
||||
"kustomization.yaml": `helmGlobals:
|
||||
chartHome: untar-dir
|
||||
`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "chart_home_structure",
|
||||
files: map[string]string{
|
||||
"kustomization.yaml": `helmGlobals:
|
||||
chartHome: home
|
||||
`,
|
||||
"home/minecraft-3.1.3.tgz": "blah",
|
||||
"home/terraform-1.0.0.tgz": "la",
|
||||
"home/minecraft/Chart.yaml": `annotations:
|
||||
artifacthub.io/links: |
|
||||
- name: source
|
||||
url: https://minecraft.net/
|
||||
`,
|
||||
"home/terraform/Chart.yaml": `description: Minecraft server
|
||||
`,
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
checkLocalizeInTargetSuccess(t, test.files)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyChartHomeChanges(t *testing.T) {
|
||||
for name, test := range map[string]struct {
|
||||
files map[string]string
|
||||
copiedFiles map[string]string
|
||||
}{
|
||||
"clean_does_not_exist": {
|
||||
files: map[string]string{
|
||||
"kustomization.yaml": `helmGlobals:
|
||||
chartHome: ../b/home
|
||||
`,
|
||||
},
|
||||
copiedFiles: map[string]string{
|
||||
"kustomization.yaml": `helmGlobals:
|
||||
chartHome: home
|
||||
`,
|
||||
},
|
||||
},
|
||||
"clean_default": {
|
||||
files: map[string]string{
|
||||
"kustomization.yaml": `helmGlobals:
|
||||
chartHome: ../b/charts
|
||||
`,
|
||||
"charts/name/values.yaml": valuesFile,
|
||||
},
|
||||
copiedFiles: map[string]string{
|
||||
"kustomization.yaml": `helmGlobals:
|
||||
chartHome: charts
|
||||
`,
|
||||
"charts/name/values.yaml": valuesFile,
|
||||
},
|
||||
},
|
||||
"not_copied": {
|
||||
files: map[string]string{
|
||||
"kustomization.yaml": `helmCharts:
|
||||
- name: name
|
||||
valuesFile: home/name/values.yaml
|
||||
helmGlobals:
|
||||
chartHome: home
|
||||
`,
|
||||
"home/name/values.yaml": valuesFile,
|
||||
"home/name/many-other-files": "other contents",
|
||||
},
|
||||
copiedFiles: map[string]string{
|
||||
"kustomization.yaml": `helmCharts:
|
||||
- name: name
|
||||
valuesFile: home/name/values.yaml
|
||||
helmGlobals:
|
||||
chartHome: home
|
||||
`,
|
||||
"home/name/values.yaml": valuesFile,
|
||||
},
|
||||
},
|
||||
"does_not_exist_exits_scope": {
|
||||
files: map[string]string{
|
||||
"kustomization.yaml": `helmGlobals:
|
||||
chartHome: ../home
|
||||
`,
|
||||
"../../home/will-exist-at-dst/values.yaml": valuesFile,
|
||||
},
|
||||
copiedFiles: map[string]string{
|
||||
"kustomization.yaml": `helmGlobals:
|
||||
chartHome: ../home
|
||||
`,
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
expected, actual := makeFileSystems(t, "/a/b", test.files)
|
||||
|
||||
err := Run("/a/b", "/a/b", "/dst", actual)
|
||||
require.NoError(t, err)
|
||||
|
||||
addFiles(t, expected, "/dst", test.copiedFiles)
|
||||
checkFSys(t, expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyChartHomeEmpty(t *testing.T) {
|
||||
kustomization := map[string]string{
|
||||
"kustomization.yaml": `helmGlobals:
|
||||
chartHome: home
|
||||
`,
|
||||
}
|
||||
expected, actual := makeFileSystems(t, "/a", kustomization)
|
||||
require.NoError(t, actual.Mkdir("/a/home"))
|
||||
require.NoError(t, expected.Mkdir("/a/home"))
|
||||
|
||||
err := Run("/a", "", "/dst", actual)
|
||||
require.NoError(t, err)
|
||||
|
||||
addFiles(t, expected, "/dst", kustomization)
|
||||
require.NoError(t, expected.Mkdir("/dst/home"))
|
||||
checkFSys(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestCopyChartHomeError(t *testing.T) {
|
||||
for name, test := range map[string]struct {
|
||||
err string
|
||||
files map[string]string
|
||||
}{
|
||||
"absolute": {
|
||||
err: `unable to copy helmGlobals: absolute path "/a/b/home" not handled in alpha`,
|
||||
files: map[string]string{
|
||||
"a/b/kustomization.yaml": `helmGlobals:
|
||||
chartHome: /a/b/home
|
||||
`,
|
||||
"a/b/home/name/values.yaml": valuesFile,
|
||||
},
|
||||
},
|
||||
"file": {
|
||||
err: `unable to copy helmGlobals: unable to copy home "home": invalid chart home: invalid root reference: must build at directory: '/a/b/home': file is not directory`,
|
||||
files: map[string]string{
|
||||
"a/b/kustomization.yaml": `helmGlobals:
|
||||
chartHome: home
|
||||
`,
|
||||
"a/b/home": valuesFile,
|
||||
},
|
||||
},
|
||||
"scope": {
|
||||
err: `unable to copy helmGlobals: unable to copy home "../../alpha/home": invalid chart home: root "/alpha/home" outside localize scope "/a"`,
|
||||
files: map[string]string{
|
||||
"a/b/kustomization.yaml": `helmGlobals:
|
||||
chartHome: ../../alpha/home
|
||||
`,
|
||||
"alpha/home/values.yaml": valuesFile,
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
expected, actual := makeFileSystems(t, "/", test.files)
|
||||
|
||||
err := Run("/a/b", "/a", "/dst", actual)
|
||||
const prefix = `unable to localize target "/a/b"`
|
||||
require.EqualError(t, err, fmt.Sprintf("%s: %s", prefix, test.err))
|
||||
|
||||
checkFSys(t, expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizeEmpty(t *testing.T) {
|
||||
for name, kustomization := range map[string]string{
|
||||
"file": `configurations:
|
||||
- ""
|
||||
`,
|
||||
"root": `bases:
|
||||
- ""
|
||||
`,
|
||||
"resource": `resources:
|
||||
- ""
|
||||
`,
|
||||
"generator_file_src": `configMapGenerator:
|
||||
- files:
|
||||
- ""
|
||||
`,
|
||||
"patchesStrategicMerge": `patchesStrategicMerge:
|
||||
- ""
|
||||
`,
|
||||
"custom_transformers": `transformers:
|
||||
- ""
|
||||
`,
|
||||
"custom_transformer_field": `transformers:
|
||||
- |
|
||||
apiVersion: builtin
|
||||
kind: PatchStrategicMergeTransformer
|
||||
metadata:
|
||||
name: empty
|
||||
paths:
|
||||
- ""
|
||||
`,
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
checkLocalizeInTargetSuccess(t, map[string]string{
|
||||
"kustomization.yaml": kustomization,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +199,10 @@ spec:
|
||||
maxReplicas: 10`
|
||||
|
||||
urlQuery = "?submodules=0&ref=kustomize/v4.5.7&timeout=300"
|
||||
|
||||
valuesFile = `minecraftServer:
|
||||
difficulty: peaceful
|
||||
`
|
||||
)
|
||||
|
||||
func link(t *testing.T, testDir filesys.ConfirmedDir, links map[string]string) {
|
||||
@@ -267,7 +271,7 @@ func TestWorkingDir(t *testing.T) {
|
||||
CheckFs(t, wd.String(), fsExpected, fsActual)
|
||||
}
|
||||
|
||||
func TestSymlinks(t *testing.T) {
|
||||
func TestLoaderSymlinks(t *testing.T) {
|
||||
// test directory
|
||||
// - link to target
|
||||
// - link to base
|
||||
@@ -500,3 +504,144 @@ func TestExistingCacheDir(t *testing.T) {
|
||||
SetupDir(t, fsExpected, testDir.String(), file)
|
||||
CheckFs(t, testDir.String(), fsExpected, fsActual)
|
||||
}
|
||||
|
||||
func TestHelmNestedHome(t *testing.T) {
|
||||
files := map[string]string{
|
||||
"kustomization.yaml": fmt.Sprintf(`helmGlobals:
|
||||
chartHome: %s
|
||||
`, filepath.Join("nested", "dirs", "home")),
|
||||
filepath.Join("nested", "dirs", "home", "name", "values.yaml"): `
|
||||
minecraftServer:
|
||||
difficulty: peaceful
|
||||
`,
|
||||
}
|
||||
fsExpected, fsActual, testDir := PrepareFs(t, []string{
|
||||
filepath.Join("nested", "dirs", "home", "name"),
|
||||
}, files)
|
||||
|
||||
dst := testDir.Join("dst")
|
||||
err := localizer.Run(fsActual, testDir.String(), "", dst)
|
||||
require.NoError(t, err)
|
||||
|
||||
SetupDir(t, fsExpected, dst, files)
|
||||
CheckFs(t, dst, fsExpected, fsActual)
|
||||
}
|
||||
|
||||
func TestHelmLinkedHome(t *testing.T) {
|
||||
// scope
|
||||
// - target
|
||||
// - kustomization
|
||||
// - myValues.yaml
|
||||
// - link to home
|
||||
// - home
|
||||
// - name
|
||||
// - values.yaml
|
||||
fsExpected, fsActual, scope := PrepareFs(t, []string{
|
||||
"target",
|
||||
filepath.Join("home", "name"),
|
||||
},
|
||||
map[string]string{
|
||||
filepath.Join("target", "Kustomization"): `helmCharts:
|
||||
- name: name
|
||||
valuesFile: myValues.yaml
|
||||
helmGlobals:
|
||||
chartHome: home-link
|
||||
`,
|
||||
filepath.Join("target", "myValues.yaml"): valuesFile,
|
||||
filepath.Join("home", "name", "values.yaml"): valuesFile,
|
||||
})
|
||||
link(t, scope, map[string]string{
|
||||
filepath.Join("target", "home-link"): "home",
|
||||
})
|
||||
|
||||
dst := scope.Join("dst")
|
||||
err := localizer.Run(fsActual, scope.Join("target"), scope.String(), dst)
|
||||
require.NoError(t, err)
|
||||
|
||||
SetupDir(t, fsExpected, dst, map[string]string{
|
||||
filepath.Join("target", "Kustomization"): fmt.Sprintf(`helmCharts:
|
||||
- name: name
|
||||
valuesFile: myValues.yaml
|
||||
helmGlobals:
|
||||
chartHome: %s
|
||||
`, filepath.Join("..", "home")),
|
||||
filepath.Join("target", "myValues.yaml"): valuesFile,
|
||||
filepath.Join("home", "name", "values.yaml"): valuesFile,
|
||||
})
|
||||
CheckFs(t, dst, fsExpected, fsActual)
|
||||
}
|
||||
|
||||
func TestHelmLinkedDefaultHome(t *testing.T) {
|
||||
// target
|
||||
// - kustomization
|
||||
// - link to home (named charts)
|
||||
// - home
|
||||
// - name
|
||||
// - values.yaml
|
||||
fsExpected, fsActual, target := PrepareFs(t, []string{
|
||||
filepath.Join("home", "default"),
|
||||
filepath.Join("home", "same"),
|
||||
}, map[string]string{
|
||||
"kustomization.yaml": fmt.Sprintf(`helmCharts:
|
||||
- name: default
|
||||
helmChartInflationGenerator:
|
||||
- chartHome: %s
|
||||
chartName: same
|
||||
`, filepath.Join("home", "..", "charts")),
|
||||
filepath.Join("home", "default", "values.yaml"): valuesFile,
|
||||
filepath.Join("home", "same", "values.yaml"): valuesFile,
|
||||
})
|
||||
link(t, target, map[string]string{"charts": "home"})
|
||||
|
||||
dst := target.Join("dst")
|
||||
err := localizer.Run(fsActual, target.String(), "", dst)
|
||||
require.NoError(t, err)
|
||||
|
||||
SetupDir(t, fsExpected, dst, map[string]string{
|
||||
"kustomization.yaml": `helmChartInflationGenerator:
|
||||
- chartHome: charts
|
||||
chartName: same
|
||||
helmCharts:
|
||||
- name: default
|
||||
`,
|
||||
filepath.Join("charts", "default", "values.yaml"): valuesFile,
|
||||
filepath.Join("charts", "same", "values.yaml"): valuesFile,
|
||||
})
|
||||
CheckFs(t, dst, fsExpected, fsActual)
|
||||
}
|
||||
|
||||
func TestHelmHomeEscapesScope(t *testing.T) {
|
||||
// test directory
|
||||
// - dir
|
||||
// - file
|
||||
// - target (and scope)
|
||||
// - kustomization
|
||||
// - home
|
||||
// - link to dir
|
||||
// - link to file
|
||||
fsExpected, fsActual, testDir := PrepareFs(t, []string{
|
||||
"dir",
|
||||
filepath.Join("target", "home"),
|
||||
}, map[string]string{
|
||||
"file": valuesFile,
|
||||
filepath.Join("target", "kustomization.yaml"): `helmGlobals:
|
||||
chartHome: home
|
||||
`,
|
||||
})
|
||||
link(t, testDir, map[string]string{
|
||||
filepath.Join("target", "home", "dir-link"): "dir",
|
||||
filepath.Join("target", "home", "file-link"): "file",
|
||||
})
|
||||
|
||||
dst := testDir.Join("dst")
|
||||
err := localizer.Run(fsActual, testDir.Join("target"), "", dst)
|
||||
require.NoError(t, err)
|
||||
|
||||
SetupDir(t, fsExpected, dst, map[string]string{
|
||||
"kustomization.yaml": `helmGlobals:
|
||||
chartHome: home
|
||||
`,
|
||||
})
|
||||
require.NoError(t, fsExpected.Mkdir(filepath.Join(dst, "home")))
|
||||
CheckFs(t, dst, fsExpected, fsActual)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
package types
|
||||
|
||||
const HelmDefaultHome = "charts"
|
||||
|
||||
type HelmGlobals struct {
|
||||
// ChartHome is a file path, relative to the kustomization root,
|
||||
// to a directory containing a subdirectory for each chart to be
|
||||
|
||||
@@ -89,7 +89,7 @@ func (p *plugin) validateArgs() (err error) {
|
||||
// the loader root (unless root restrictions are
|
||||
// disabled, in which case this can be an absolute path).
|
||||
if p.ChartHome == "" {
|
||||
p.ChartHome = "charts"
|
||||
p.ChartHome = types.HelmDefaultHome
|
||||
}
|
||||
|
||||
// The ValuesFile may be consulted by the plugin, so it must
|
||||
|
||||
Reference in New Issue
Block a user