mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
Localize PatchTransformer, PatchJson6902Transformer (#4920)
* Localize patches, patchesJson6902 custom transformers * Improve readability
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user