Localize ConfigMapGenerator, SecretGenerator

This commit is contained in:
Anna Song
2023-01-24 17:10:20 -08:00
parent af3e8ee353
commit 142360b0ed
4 changed files with 230 additions and 78 deletions

View File

@@ -32,6 +32,22 @@ func (lbp *localizeBuiltinPlugins) Filter(plugins []*yaml.RNode) ([]*yaml.RNode,
for _, singlePlugin := range plugins { for _, singlePlugin := range plugins {
err := singlePlugin.PipeE(fsslice.Filter{ err := singlePlugin.PipeE(fsslice.Filter{
FsSlice: types.FsSlice{ FsSlice: types.FsSlice{
types.FieldSpec{
Gvk: resid.Gvk{Version: konfig.BuiltinPluginApiVersion, Kind: builtinhelpers.ConfigMapGenerator.String()},
Path: "env",
},
types.FieldSpec{
Gvk: resid.Gvk{Version: konfig.BuiltinPluginApiVersion, Kind: builtinhelpers.ConfigMapGenerator.String()},
Path: "envs",
},
types.FieldSpec{
Gvk: resid.Gvk{Version: konfig.BuiltinPluginApiVersion, Kind: builtinhelpers.SecretGenerator.String()},
Path: "env",
},
types.FieldSpec{
Gvk: resid.Gvk{Version: konfig.BuiltinPluginApiVersion, Kind: builtinhelpers.SecretGenerator.String()},
Path: "envs",
},
types.FieldSpec{ types.FieldSpec{
Gvk: resid.Gvk{Version: konfig.BuiltinPluginApiVersion, Kind: builtinhelpers.PatchTransformer.String()}, Gvk: resid.Gvk{Version: konfig.BuiltinPluginApiVersion, Kind: builtinhelpers.PatchTransformer.String()},
Path: "path", Path: "path",
@@ -47,20 +63,36 @@ func (lbp *localizeBuiltinPlugins) Filter(plugins []*yaml.RNode) ([]*yaml.RNode,
}, },
SetValue: func(node *yaml.RNode) error { SetValue: func(node *yaml.RNode) error {
lbp.locPathFn = lbp.lc.localizeFile lbp.locPathFn = lbp.lc.localizeFile
return lbp.localizeNode(node) return lbp.localizeAll(node)
}, },
}, fieldspec.Filter{ },
FieldSpec: types.FieldSpec{ fsslice.Filter{
Gvk: resid.Gvk{Version: konfig.BuiltinPluginApiVersion, Kind: builtinhelpers.PatchStrategicMergeTransformer.String()}, FsSlice: types.FsSlice{
Path: "paths", types.FieldSpec{
Gvk: resid.Gvk{Version: konfig.BuiltinPluginApiVersion, Kind: builtinhelpers.ConfigMapGenerator.String()},
Path: "files",
},
types.FieldSpec{
Gvk: resid.Gvk{Version: konfig.BuiltinPluginApiVersion, Kind: builtinhelpers.SecretGenerator.String()},
Path: "files",
},
},
SetValue: func(node *yaml.RNode) error {
lbp.locPathFn = lbp.lc.localizeFileSource
return lbp.localizeAll(node)
},
}, },
SetValue: func(node *yaml.RNode) error { fieldspec.Filter{
lbp.locPathFn = lbp.lc.localizeK8sResource FieldSpec: types.FieldSpec{
return errors.Wrap(node.VisitElements(lbp.localizeNode)) Gvk: resid.Gvk{Version: konfig.BuiltinPluginApiVersion, Kind: builtinhelpers.PatchStrategicMergeTransformer.String()},
}, Path: "paths",
}) },
// TODO(annasong): localize ConfigMapGenerator, SecretGenerator, SetValue: func(node *yaml.RNode) error {
// HelmChartInflationGenerator lbp.locPathFn = lbp.lc.localizeK8sResource
return lbp.localizeAll(node)
},
})
// TODO(annasong): localize HelmChartInflationGenerator
if err != nil { if err != nil {
return nil, errors.Wrap(err) return nil, errors.Wrap(err)
} }
@@ -68,14 +100,27 @@ func (lbp *localizeBuiltinPlugins) Filter(plugins []*yaml.RNode) ([]*yaml.RNode,
return plugins, nil return plugins, nil
} }
// localizeNode sets the scalar node to its value localized by locPathFn. // localizeAll sets each entry in node to its value localized by locPathFn.
func (lbp *localizeBuiltinPlugins) localizeNode(node *yaml.RNode) error { // Node is a sequence or scalar value.
func (lbp *localizeBuiltinPlugins) localizeAll(node *yaml.RNode) error {
// We rely on the build command to throw errors for nodes in
// built-in plugins that are sequences when expected to be scalar,
// and vice versa.
switch node.YNode().Kind {
case yaml.SequenceNode:
return errors.Wrap(node.VisitElements(lbp.localizeScalar))
case yaml.ScalarNode:
return lbp.localizeScalar(node)
default:
return errors.Errorf("expected sequence or scalar node")
}
}
// localizeScalar sets the scalar node to its value localized by locPathFn.
func (lbp *localizeBuiltinPlugins) localizeScalar(node *yaml.RNode) error {
localizedPath, err := lbp.locPathFn(node.YNode().Value) localizedPath, err := lbp.locPathFn(node.YNode().Value)
if err != nil { if err != nil {
return err return err
} }
if localizedPath != "" { return filtersutil.SetScalar(localizedPath)(node)
err = filtersutil.SetScalar(localizedPath)(node)
}
return err
} }

View File

@@ -193,9 +193,7 @@ func (lc *localizer) localizeNativeFields(kust *types.Kustomization) error {
if err != nil { if err != nil {
return errors.WrapPrefixf(err, "unable to localize patchesStrategicMerge entry") return errors.WrapPrefixf(err, "unable to localize patchesStrategicMerge entry")
} }
if locPath != "" { kust.PatchesStrategicMerge[i] = types.PatchStrategicMerge(locPath)
kust.PatchesStrategicMerge[i] = types.PatchStrategicMerge(locPath)
}
} }
for i, replacement := range kust.Replacements { for i, replacement := range kust.Replacements {
locPath, err := lc.localizeFile(replacement.Path) locPath, err := lc.localizeFile(replacement.Path)
@@ -222,18 +220,10 @@ func (lc *localizer) localizeGenerator(generator *types.GeneratorArgs) error {
} }
locFiles := make([]string, len(generator.FileSources)) locFiles := make([]string, len(generator.FileSources))
for i, file := range generator.FileSources { for i, file := range generator.FileSources {
k, f, err := generators.ParseFileSource(file) locFiles[i], err = lc.localizeFileSource(file)
if err != nil { if err != nil {
return errors.WrapPrefixf(err, "unable to parse generator files entry %q", file) return err
} }
newFile, err := lc.localizeFile(f)
if err != nil {
return errors.WrapPrefixf(err, "unable to localize generator files path in entry %q", file)
}
if f != file {
newFile = k + "=" + newFile
}
locFiles[i] = newFile
} }
generator.EnvSource = locEnvSrc generator.EnvSource = locEnvSrc
generator.EnvSources = locEnvs generator.EnvSources = locEnvs
@@ -241,6 +231,26 @@ func (lc *localizer) localizeGenerator(generator *types.GeneratorArgs) error {
return nil return nil
} }
// localizeFileSource returns the localized file source found in configMap and
// secretGenerators.
func (lc *localizer) localizeFileSource(source string) (string, error) {
key, file, err := generators.ParseFileSource(source)
if err != nil {
return "", errors.Wrap(err)
}
locFile, err := lc.localizeFile(file)
if err != nil {
return "", errors.WrapPrefixf(err, "invalid file source %q", source)
}
var locSource string
if source == file {
locSource = locFile
} else {
locSource = key + "=" + locFile
}
return locSource, nil
}
// localizeHelmInflationGenerator localizes helmChartInflationGenerator on kust. // localizeHelmInflationGenerator localizes helmChartInflationGenerator on kust.
// localizeHelmInflationGenerator localizes values files and copies local chart homes. // localizeHelmInflationGenerator localizes values files and copies local chart homes.
func (lc *localizer) localizeHelmInflationGenerator(kust *types.Kustomization) error { func (lc *localizer) localizeHelmInflationGenerator(kust *types.Kustomization) error {
@@ -559,10 +569,9 @@ func (lc *localizer) localizeBuiltinPlugins(kust *types.Kustomization) error {
return nil return nil
} }
// localizeK8sResource returns the localized file path if resourceEntry is a // localizeK8sResource returns the localized resourceEntry if it is a file
// file containing a kubernetes resource. // containing a kubernetes resource.
// localizeK8sResource returns the empty string if resourceEntry is an inline // localizeK8sResource returns resourceEntry if it is an inline resource.
// resource.
func (lc *localizer) localizeK8sResource(resourceEntry string) (string, error) { func (lc *localizer) localizeK8sResource(resourceEntry string) (string, error) {
_, isFile, err := lc.loadK8sResource(resourceEntry) _, isFile, err := lc.loadK8sResource(resourceEntry)
if err != nil { if err != nil {
@@ -571,7 +580,7 @@ func (lc *localizer) localizeK8sResource(resourceEntry string) (string, error) {
if isFile { if isFile {
return lc.localizeFile(resourceEntry) return lc.localizeFile(resourceEntry)
} }
return "", nil return resourceEntry, nil
} }
// loadK8sResource tries to load resourceEntry as a file path or inline // loadK8sResource tries to load resourceEntry as a file path or inline

View File

@@ -670,37 +670,61 @@ transformers:
checkFSys(t, expected, actual) checkFSys(t, expected, actual)
} }
func TestLocalizeGenerators(t *testing.T) { func TestLocalizeGeneratorsConfigMap(t *testing.T) {
kustAndPlugins := map[string]string{ files := map[string]string{
"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1 "kustomization.yaml": `generators:
generators: - configMapGenerator
- plugin.yaml
- |
apiVersion: builtin
behavior: create
kind: ConfigMapGenerator
literals:
- APPLE=orange
metadata:
name: another-map
---
apiVersion: builtin
kind: SecretGenerator
literals:
- APPLE=b3Jhbmdl
metadata:
name: secret
options:
disableNameSuffixHash: true
kind: Kustomization
`, `,
"plugin.yaml": `apiVersion: builtin "configMapGenerator": `apiVersion: builtin
behavior: create
env: one.env
envs:
- two.env
- three.env
files:
- four.properties
- key=five.properties
kind: ConfigMapGenerator kind: ConfigMapGenerator
metadata: metadata:
name: map name: custom-generator
options:
disableNameSuffix: true
`, `,
"one.env": "key1=value1",
"two.env": "key2=value2",
"three.env": "key3=value3",
"four.properties": "key4=value4",
"five.properties": "key5=value5",
} }
checkLocalizeInTargetSuccess(t, kustAndPlugins) checkLocalizeInTargetSuccess(t, files)
}
func TestLocalizeGeneratorsSecret(t *testing.T) {
files := map[string]string{
"kustomization.yaml": `generators:
- secretGenerator
`,
"secretGenerator": `apiVersion: builtin
env: one.env
envs:
- two.env
- three.env
files:
- four.properties
- key=five.properties
kind: SecretGenerator
literals:
- key6=value6
metadata:
name: custom-generator
`,
"one.env": "key1=value1",
"two.env": "key2=value2",
"three.env": "key3=value3",
"four.properties": "key4=value4",
"five.properties": "key5=value5",
}
checkLocalizeInTargetSuccess(t, files)
} }
func TestLocalizeTransformersPatch(t *testing.T) { func TestLocalizeTransformersPatch(t *testing.T) {
@@ -833,7 +857,23 @@ validators:
checkLocalizeInTargetSuccess(t, kustAndPlugin) checkLocalizeInTargetSuccess(t, kustAndPlugin)
} }
func TestLocalizeBuiltinPluginsNotResource(t *testing.T) { func TestLocalizeBuiltinPlugins_SequenceScalarEquivalence(t *testing.T) {
kustomization := map[string]string{
"kustomization.yaml": `transformers:
- |
apiVersion: builtin
kind: PatchTransformer
metadata:
name: path-should-be-scalar-but-accept-sequence
path:
- patchSM.yaml
`,
"patchSM.yaml": podConfiguration,
}
checkLocalizeInTargetSuccess(t, kustomization)
}
func TestLocalizeBuiltinPlugins_NotResource(t *testing.T) {
type testCase struct { type testCase struct {
name string name string
files map[string]string files map[string]string
@@ -895,24 +935,52 @@ when parsing as filepath received error: %s`, test.errPrefix, test.inlineErrMsg,
} }
} }
func TestLocalizeBuiltinPluginsFileError(t *testing.T) { func TestLocalizeBuiltinPlugins_Errors(t *testing.T) {
kustAndPatches := map[string]string{ for name, test := range map[string]struct {
"kustomization.yaml": `transformers: files map[string]string
- patch.yaml fieldSpecErr string
locErr string
}{
"file_dne": {
files: map[string]string{
"kustomization.yaml": `transformers:
- |
apiVersion: builtin
kind: PatchTransformer
metadata:
name: file-does-not-exist
path: patchSM.yaml
`, `,
"patch.yaml": `apiVersion: builtin },
kind: PatchTransformer fieldSpecErr: "considering field 'path' of object PatchTransformer.builtin.[noGrp]/file-does-not-exist.[noNs]",
metadata: locErr: "invalid file reference: '/a/patchSM.yaml' doesn't exist",
name: my-patch },
path: patchSM.yaml "not_sequence_or_scalar": {
files: map[string]string{
"kustomization.yaml": `transformers:
- |
apiVersion: builtin
kind: PatchTransformer
metadata:
name: path-node-has-wrong-kind
path:
mappingNode: patchSM.yaml
`, `,
"patchSM.yaml": podConfiguration,
},
fieldSpecErr: "considering field 'path' of object PatchTransformer.builtin.[noGrp]/path-node-has-wrong-kind.[noNs]",
locErr: "expected sequence or scalar node",
},
} {
t.Run(name, func(t *testing.T) {
expected, actual := makeFileSystems(t, "/a", test.files)
err := Run("/a", "", "/dst", actual)
const errPrefix = `unable to localize target "/a"`
require.EqualError(t, err, fmt.Sprintf(
"%s: %s: %s", errPrefix, test.fieldSpecErr, test.locErr))
checkFSys(t, expected, actual)
})
} }
_, actual := makeFileSystems(t, "/a", kustAndPatches)
err := Run("/a", "", "/dst", actual)
require.EqualError(t, err, "unable to localize target \"/a\": "+
"considering field 'path' of object PatchTransformer.builtin.[noGrp]/my-patch.[noNs]: "+
"invalid file reference: '/a/patchSM.yaml' doesn't exist")
} }
func TestLocalizeDirInTarget(t *testing.T) { func TestLocalizeDirInTarget(t *testing.T) {

View File

@@ -646,3 +646,33 @@ func TestHelmHomeEscapesScope(t *testing.T) {
require.NoError(t, fsExpected.Mkdir(filepath.Join(dst, "home"))) require.NoError(t, fsExpected.Mkdir(filepath.Join(dst, "home")))
CheckFs(t, dst, fsExpected, fsActual) CheckFs(t, dst, fsExpected, fsActual)
} }
func TestSymlinkedFileSource(t *testing.T) {
// target (and scope)
// - kustomization
// - file
// - link to file
fsExpected, fsActual, target := PrepareFs(t, nil, map[string]string{
"kustomization.yaml": `configMapGenerator:
- files:
- filename-used-as-key-in-configMap
`,
"different-key": "properties",
})
link(t, target, map[string]string{
"filename-used-as-key-in-configMap": "different-key",
})
dst := target.Join("dst")
err := localizer.Run(fsActual, target.String(), "", dst)
require.NoError(t, err)
SetupDir(t, fsExpected, dst, map[string]string{
"kustomization.yaml": `configMapGenerator:
- files:
- different-key
`,
"different-key": "properties",
})
CheckFs(t, dst, fsExpected, fsActual)
}