Localize PatchTransformer, PatchJson6902Transformer (#4920)

* Localize patches, patchesJson6902 custom transformers

* Improve readability
This commit is contained in:
Anna Song
2022-12-16 12:52:17 -05:00
committed by GitHub
parent ef60d5f9bb
commit a1bfab382a
3 changed files with 237 additions and 90 deletions

View File

@@ -4,35 +4,51 @@
package localizer
import (
"sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
"sigs.k8s.io/kustomize/api/konfig"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/resid"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// localizeBuiltinGenerators localizes built-in generators with file paths.
// localizeBuiltinPlugins localizes built-in plugins with file paths.
// Note that this excludes helm, which needs a repo.
type localizeBuiltinGenerators struct {
type localizeBuiltinPlugins struct {
lc *localizer
}
var _ kio.Filter = &localizeBuiltinGenerators{}
var _ kio.Filter = &localizeBuiltinPlugins{}
// Filter localizes the built-in generators with file paths. Filter returns an error if
// generators contains a resource that is not a built-in generator, cannot contain a file path,
// needs more than a file path like helm, or is not localizable.
// TODO(annasong): implement
func (lbg *localizeBuiltinGenerators) Filter(generators []*yaml.RNode) ([]*yaml.RNode, error) {
return generators, nil
// Filter localizes the built-in plugins with file paths.
func (lbp *localizeBuiltinPlugins) Filter(plugins []*yaml.RNode) ([]*yaml.RNode, error) {
localizedPlugins, err := kio.FilterAll(fsslice.Filter{
FsSlice: types.FsSlice{
types.FieldSpec{
Gvk: resid.Gvk{Version: konfig.BuiltinPluginApiVersion, Kind: builtinhelpers.PatchTransformer.String()},
Path: "path",
},
types.FieldSpec{
Gvk: resid.Gvk{Version: konfig.BuiltinPluginApiVersion, Kind: builtinhelpers.PatchJson6902Transformer.String()},
Path: "path",
},
},
SetValue: lbp.localizeNode,
}).Filter(plugins)
// TODO(annasong): localize ReplacementTransformer, PatchStrategicMergeTransformer, ConfigMapGenerator, SecretGenerator
return localizedPlugins, errors.Wrap(err)
}
// localizeBuiltinTransformers localizes built-in transformers with file paths.
type localizeBuiltinTransformers struct {
}
var _ kio.Filter = &localizeBuiltinTransformers{}
// Filter localizes the built-in transformers with file paths. Filter returns an error if
// transformers contains a resource that is not a built-in transformer, cannot contain a file path,
// or is not localizable.
// TODO(annasong): implement
func (lbt *localizeBuiltinTransformers) Filter(transformers []*yaml.RNode) ([]*yaml.RNode, error) {
return transformers, nil
// localizeNode sets the scalar node to its value localized as a file path.
func (lbp *localizeBuiltinPlugins) localizeNode(node *yaml.RNode) error {
localizedPath, err := lbp.lc.localizeFile(node.YNode().Value)
if err != nil {
return errors.WrapPrefixf(err, "unable to localize built-in plugin path")
}
return filtersutil.SetScalar(localizedPath)(node)
}

View File

@@ -16,7 +16,6 @@ import (
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/filesys"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/yaml"
)
@@ -224,7 +223,11 @@ func (lc *localizer) localizeFile(path string) (string, error) {
if err != nil {
return "", errors.Wrap(err)
}
return lc.localizeFileWithContent(path, content)
}
// localizeFileWithContent writes content to the localized file path and returns the localized path.
func (lc *localizer) localizeFileWithContent(path string, content []byte) (string, error) {
var locPath string
if loader.IsRemoteFile(path) {
// TODO(annasong): You need to check if you can add a localize directory here to store
@@ -243,10 +246,10 @@ func (lc *localizer) localizeFile(path string) (string, error) {
locPath = cleanFilePath(lc.fSys, lc.root, path)
}
absPath := filepath.Join(lc.dst, locPath)
if err = lc.fSys.MkdirAll(filepath.Dir(absPath)); err != nil {
if err := lc.fSys.MkdirAll(filepath.Dir(absPath)); err != nil {
return "", errors.WrapPrefixf(err, "unable to create directories to localize file %q", path)
}
if err = lc.fSys.WriteFile(absPath, content); err != nil {
if err := lc.fSys.WriteFile(absPath, content); err != nil {
return "", errors.WrapPrefixf(err, "unable to localize file %q", path)
}
return locPath, nil
@@ -297,29 +300,17 @@ func (lc *localizer) localizeDir(path string) (string, error) {
//
// Note that the localization in this function has not been implemented yet.
func (lc *localizer) localizeBuiltinPlugins(kust *types.Kustomization) error {
for fieldName, plugins := range map[string]struct {
entries []string
localizer kio.Filter
}{
"generators": {
kust.Generators,
&localizeBuiltinGenerators{},
},
"transformers": {
kust.Transformers,
&localizeBuiltinTransformers{},
},
"validators": {
kust.Validators,
&localizeBuiltinTransformers{},
},
for fieldName, entries := range map[string][]string{
"generators": kust.Generators,
"transformers": kust.Transformers,
"validators": kust.Validators,
} {
for i, entry := range plugins.entries {
for i, entry := range entries {
rm, isPath, err := lc.loadResource(entry)
if err != nil {
return errors.WrapPrefixf(err, "unable to load %s entry", fieldName)
}
err = rm.ApplyFilter(plugins.localizer)
err = rm.ApplyFilter(&localizeBuiltinPlugins{lc})
if err != nil {
return errors.Wrap(err)
}
@@ -327,14 +318,16 @@ func (lc *localizer) localizeBuiltinPlugins(kust *types.Kustomization) error {
if err != nil {
return errors.WrapPrefixf(err, "unable to serialize localized %s entry %q", fieldName, entry)
}
var newEntry string
var localizedEntry string
if isPath {
// TODO(annasong): write localizedPlugin to dst
newEntry = entry
localizedEntry, err = lc.localizeFileWithContent(entry, localizedPlugin)
if err != nil {
return errors.WrapPrefixf(err, "unable to localize %s entry", fieldName)
}
} else {
newEntry = string(localizedPlugin)
localizedEntry = string(localizedPlugin)
}
plugins.entries[i] = newEntry
entries[i] = localizedEntry
}
}
return nil

View File

@@ -95,11 +95,9 @@ func reportFSysDiff(t *testing.T, fSysExpected filesys.FileSystem, fSysActual fi
err = fSysExpected.Walk("/", func(path string, info fs.FileInfo, err error) error {
require.NoError(t, err)
visited[path] = struct{}{}
if _, exists := visited[path]; !exists {
t.Errorf("expected path %q not found", path)
}
_, exists := visited[path]
assert.Truef(t, exists, "expected path %q not found", path)
return nil
})
require.NoError(t, err)
@@ -531,6 +529,96 @@ patches:
checkFSys(t, expected, actual)
}
func TestLocalizePluginsInlineAndFile(t *testing.T) {
kustAndPlugins := map[string]string{
"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
transformers:
- |
apiVersion: builtin
kind: PatchTransformer
metadata:
name: inline
path: patchSM-one.yaml
- patch.yaml
`,
"patch.yaml": `apiVersion: builtin
kind: PatchTransformer
metadata:
name: file
path: patchSM-two.yaml
`,
"patchSM-one.yaml": podConfiguration,
"patchSM-two.yaml": podConfiguration,
}
expected, actual := makeFileSystems(t, "/a", kustAndPlugins)
err := Run("/a", "", "/dst", actual)
require.NoError(t, err)
addFiles(t, expected, "/dst", kustAndPlugins)
checkFSys(t, expected, actual)
}
func TestLocalizeMultiplePluginsInEntry(t *testing.T) {
kustAndPlugins := map[string]string{
"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
transformers:
- |
apiVersion: builtin
kind: PatchTransformer
metadata:
name: one
path: patchSM-one.yaml
---
apiVersion: builtin
kind: PatchTransformer
metadata:
name: two
path: patchSM-two.yaml
`,
"patchSM-one.yaml": podConfiguration,
"patchSM-two.yaml": podConfiguration,
}
expected, actual := makeFileSystems(t, "/a", kustAndPlugins)
err := Run("/a", "", "/dst", actual)
require.NoError(t, err)
addFiles(t, expected, "/dst", kustAndPlugins)
checkFSys(t, expected, actual)
}
func TestLocalizeCleanedPathInPath(t *testing.T) {
const patchf = `apiVersion: builtin
kind: PatchTransformer
metadata:
name: cleaned-path
path: %s
`
kustAndPlugins := map[string]string{
"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
transformers:
- patch.yaml
`,
"patch.yaml": fmt.Sprintf(patchf, "../a/patchSM.yaml"),
"patchSM.yaml": podConfiguration,
}
expected, actual := makeFileSystems(t, "/a", kustAndPlugins)
err := Run("/a", "", "/dst", actual)
require.NoError(t, err)
addFiles(t, expected, "/dst", map[string]string{
"kustomization.yaml": kustAndPlugins["kustomization.yaml"],
"patch.yaml": fmt.Sprintf(patchf, "patchSM.yaml"),
"patchSM.yaml": kustAndPlugins["patchSM.yaml"],
})
checkFSys(t, expected, actual)
}
func TestLocalizeGenerators(t *testing.T) {
kustAndPlugins := map[string]string{
"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
@@ -566,47 +654,101 @@ metadata:
err := Run("/a", "", "/alpha/dst", actual)
require.NoError(t, err)
addFiles(t, expected, "/alpha/dst", map[string]string{
"kustomization.yaml": kustAndPlugins["kustomization.yaml"],
})
addFiles(t, expected, "/alpha/dst", kustAndPlugins)
checkFSys(t, expected, actual)
}
func TestLocalizeTransformers(t *testing.T) {
kustAndPlugins := map[string]string{
func TestLocalizeTransformersPatch(t *testing.T) {
kustAndPatches := map[string]string{
"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
transformers:
- |
apiVersion: builtin
jsonOp: '[{"op": "add", "path": "/spec/template/spec/dnsPolicy", "value": "ClusterFirst"}]'
kind: PatchJson6902Transformer
kind: PatchTransformer
metadata:
name: patch6902
name: no-path
patch: '[{"op": "add", "path": "/path", "value": "value"}]'
target:
name: deployment
---
apiVersion: builtin
kind: ReplacementTransformer
metadata:
name: replacement
replacements:
- source:
fieldPath: spec.template.spec.containers.0.image
kind: Deployment
targets:
- fieldPaths:
- spec.template.spec.containers.1.image
select:
kind: Deployment
- plugin.yaml
name: pod
- patch.yaml
`,
"plugin.yaml": `apiVersion: builtin
kind: PatchStrategicMergeTransformer
"patch.yaml": `apiVersion: builtin
kind: PatchTransformer
metadata:
name: patchSM
paths:
- pod.yaml
name: path
path: patchSM.yaml
`,
"patchSM.yaml": podConfiguration,
}
expected, actual := makeFileSystems(t, "/a", kustAndPatches)
err := Run("/a", "", "/dst", actual)
require.NoError(t, err)
addFiles(t, expected, "/dst", kustAndPatches)
checkFSys(t, expected, actual)
}
func TestLocalizeTransformersPatchJson(t *testing.T) {
kustAndPatches := map[string]string{
"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
transformers:
- patch.yaml
`,
"patch.yaml": `apiVersion: builtin
kind: PatchJson6902Transformer
metadata:
name: path
path: nested-patch.yaml
target:
name: pod
namespace: test
---
apiVersion: builtin
jsonOp: |-
op: replace
path: /path
value: new value
kind: PatchJson6902Transformer
metadata:
name: patch6902
target:
name: deployment
`,
"nested-patch.yaml": ` [
{"op": "copy", "from": "/existing/path", "path": "/another/path"},
]
`,
}
expected, actual := makeFileSystems(t, "/a", kustAndPatches)
err := Run("/a", "", "/dst", actual)
require.NoError(t, err)
addFiles(t, expected, "/dst", kustAndPatches)
checkFSys(t, expected, actual)
}
func TestLocalizePluginsNoPaths(t *testing.T) {
kustAndPlugins := map[string]string{
"kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
transformers:
- |
apiVersion: different
kind: MyTransformer
metadata:
name: still-copied
path: /nothing/special
- prefix.yaml
`,
"prefix.yaml": `apiVersion: builtin
kind: PrefixTransformer
metadata:
name: other-built-ins-still-copied
prefix: copy
`,
}
expected, actual := makeFileSystems(t, "/a", kustAndPlugins)
@@ -614,9 +756,7 @@ paths:
err := Run("/a", "", "/dst", actual)
require.NoError(t, err)
addFiles(t, expected, "/dst", map[string]string{
"kustomization.yaml": kustAndPlugins["kustomization.yaml"],
})
addFiles(t, expected, "/dst", kustAndPlugins)
checkFSys(t, expected, actual)
}
@@ -632,13 +772,13 @@ validators:
name: replacement
replacements:
- source:
fieldPath: data.[field=value]
group: apps
fieldPath: metadata.name
kind: ConfigMap
targets:
- fieldPaths:
- spec.*
- metadata.name
select:
kind: Pod
kind: ConfigMap
- replacement.yaml
`,
"replacement.yaml": `apiVersion: builtin
@@ -662,9 +802,7 @@ replacements:
err := Run("/", "", "/dst", actual)
require.NoError(t, err)
addFiles(t, expected, "/dst", map[string]string{
"kustomization.yaml": kustAndPlugin["kustomization.yaml"],
})
addFiles(t, expected, "/dst", kustAndPlugin)
checkFSys(t, expected, actual)
}