Manage name changes (prefix/suffix) via YAML annotations rather than via in-memory-only fields.

This commit is contained in:
Natasha Sarkar
2021-01-11 13:06:21 -08:00
parent ea5d08bac5
commit bd4580d73a
34 changed files with 539 additions and 61 deletions

View File

@@ -28,6 +28,7 @@ func (p *HashTransformerPlugin) Transform(m resmap.ResMap) error {
if err != nil { if err != nil {
return err return err
} }
res.SetOriginalName(res.GetName(), false)
res.SetName(fmt.Sprintf("%s-%s", res.GetName(), h)) res.SetName(fmt.Sprintf("%s-%s", res.GetName(), h))
} }
} }

View File

@@ -34,6 +34,7 @@ func (p *NamespaceTransformerPlugin) Transform(m resmap.ResMap) error {
// Don't mutate empty objects? // Don't mutate empty objects?
continue continue
} }
r.SetOriginalNs(r.GetNamespace(), false)
err := r.ApplyFilter(namespace.Filter{ err := r.ApplyFilter(namespace.Filter{
Namespace: p.Namespace, Namespace: p.Namespace,
FsSlice: p.FieldSpecs, FsSlice: p.FieldSpecs,

View File

@@ -104,6 +104,7 @@ func (p *PatchTransformerPlugin) transformJson6902(m resmap.ResMap, patch jsonpa
return err return err
} }
for _, res := range resources { for _, res := range resources {
res.SetOriginalName(res.GetName(), false)
err = res.ApplyFilter(patchjson6902.Filter{ err = res.ApplyFilter(patchjson6902.Filter{
Patch: p.Patch, Patch: p.Patch,
}) })

View File

@@ -66,8 +66,12 @@ func (p *PrefixSuffixTransformerPlugin) Transform(m resmap.ResMap) error {
// this will add a prefix and a suffix // this will add a prefix and a suffix
// to the resource even if those are // to the resource even if those are
// empty // empty
r.AddNamePrefix(p.Prefix) r.AddNamePrefix(p.Prefix)
r.AddNameSuffix(p.Suffix) r.AddNameSuffix(p.Suffix)
if p.Prefix != "" || p.Suffix != "" {
r.SetOriginalName(r.GetName(), false)
}
} }
err := r.ApplyFilter(prefixsuffix.Filter{ err := r.ApplyFilter(prefixsuffix.Filter{
Prefix: p.Prefix, Prefix: p.Prefix,

View File

@@ -721,6 +721,7 @@ func TestNameReferenceNamespace(t *testing.T) {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
m.RemoveIdAnnotations()
if err = expected.ErrorIfNotEqualLists(m); err != nil { if err = expected.ErrorIfNotEqualLists(m); err != nil {
t.Fatalf("actual doesn't match expected: %v", err) t.Fatalf("actual doesn't match expected: %v", err)
} }
@@ -882,6 +883,7 @@ func TestNameReferenceClusterWide(t *testing.T) {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
m.RemoveIdAnnotations()
if err = expected.ErrorIfNotEqualLists(m); err != nil { if err = expected.ErrorIfNotEqualLists(m); err != nil {
t.Fatalf("actual doesn't match expected: %v", err) t.Fatalf("actual doesn't match expected: %v", err)
} }
@@ -1008,6 +1010,7 @@ func TestNameReferenceNamespaceTransformation(t *testing.T) {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
m.RemoveIdAnnotations()
if err = expected.ErrorIfNotEqualLists(m); err != nil { if err = expected.ErrorIfNotEqualLists(m); err != nil {
t.Fatalf("actual doesn't match expected: %v", err) t.Fatalf("actual doesn't match expected: %v", err)
} }
@@ -1044,6 +1047,7 @@ func TestNameReferenceCandidateSelection(t *testing.T) {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
m.RemoveIdAnnotations()
if err = expected.ErrorIfNotEqualLists(m); err != nil { if err = expected.ErrorIfNotEqualLists(m); err != nil {
t.Fatalf("actual doesn't match expected: %v", err) t.Fatalf("actual doesn't match expected: %v", err)
} }

View File

@@ -355,7 +355,8 @@ func TestResolveVarsWithNoambiguation(t *testing.T) {
// went through a prefix transformer. // went through a prefix transformer.
r := m.GetByIndex(1) r := m.GetByIndex(1)
r.AddNamePrefix("sub-") r.AddNamePrefix("sub-")
r.SetName("sub-backendOne") // original name remains "backendOne" r.SetName("sub-backendOne")
r.SetOriginalName("backendOne", true)
err = ra2.AppendAll(m) err = ra2.AppendAll(m)
if err != nil { if err != nil {

View File

@@ -45,6 +45,7 @@ s/$BAR/bar baz/g
"argsFromFile": "sed-input.txt", "argsFromFile": "sed-input.txt",
}) })
pluginConfig.RemoveIdAnnotations()
p := NewExecPlugin( p := NewExecPlugin(
pLdr.AbsolutePluginPath( pLdr.AbsolutePluginPath(
konfig.DisabledPluginConfig(), konfig.DisabledPluginConfig(),

View File

@@ -244,6 +244,7 @@ metadata:
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
} }
} }
assert.NoError(t, expected.RemoveIdAnnotations())
expYaml, err := expected.AsYaml() expYaml, err := expected.AsYaml()
assert.NoError(t, err) assert.NoError(t, err)
@@ -251,6 +252,7 @@ metadata:
assert.NoError(t, kt.Load()) assert.NoError(t, kt.Load())
actual, err := kt.MakeCustomizedResMap() actual, err := kt.MakeCustomizedResMap()
assert.NoError(t, err) assert.NoError(t, err)
assert.NoError(t, actual.RemoveIdAnnotations())
actYaml, err := actual.AsYaml() actYaml, err := actual.AsYaml()
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, expYaml, actYaml) assert.Equal(t, expYaml, actYaml)

View File

@@ -93,5 +93,9 @@ func (b *Kustomizer) Run(path string) (resmap.ResMap, error) {
} }
t.Transform(m) t.Transform(m)
} }
err = m.RemoveIdAnnotations()
if err != nil {
return nil, err
}
return m, nil return m, nil
} }

View File

@@ -80,7 +80,7 @@ data:
`) `)
m := th.Run("/app", th.MakeOptionsPluginsEnabled()) m := th.Run("/app", th.MakeOptionsPluginsEnabled())
th.AssertActualEqualsExpected(m, ` th.AssertActualEqualsExpectedNoIdAnnotations(m, `
apiVersion: v1 apiVersion: v1
data: data:
foo: foo foo: foo

View File

@@ -389,7 +389,6 @@ spec:
rm, err := rmF.ConflatePatches([]*resource.Resource{r1, r2}) rm, err := rmF.ConflatePatches([]*resource.Resource{r1, r2})
assert.NoError(t, err) assert.NoError(t, err)
yml, err = rm.AsYaml() yml, err = rm.AsYaml()
assert.NoError(t, err) assert.NoError(t, err)

View File

@@ -245,4 +245,6 @@ type ResMap interface {
// selected set of resources. // selected set of resources.
ApplySmPatch( ApplySmPatch(
selectedSet *resource.IdSet, patch *resource.Resource) error selectedSet *resource.IdSet, patch *resource.Resource) error
RemoveIdAnnotations() error
} }

View File

@@ -589,6 +589,7 @@ func (m *resWrangler) ApplySmPatch(
patchCopy.SetName(res.GetName()) patchCopy.SetName(res.GetName())
patchCopy.SetNamespace(res.GetNamespace()) patchCopy.SetNamespace(res.GetNamespace())
patchCopy.SetGvk(res.GetGvk()) patchCopy.SetGvk(res.GetGvk())
patchCopy.SetOriginalName(res.GetOriginalName(), true)
err := res.ApplySmPatch(patchCopy) err := res.ApplySmPatch(patchCopy)
if err != nil { if err != nil {
// Check for an error string from UnmarshalJSON that's indicative // Check for an error string from UnmarshalJSON that's indicative
@@ -619,3 +620,13 @@ func (m *resWrangler) ApplySmPatch(
m.AppendAll(newRm) m.AppendAll(newRm)
return nil return nil
} }
func (m *resWrangler) RemoveIdAnnotations() error {
for _, r := range m.Resources() {
err := r.RemoveIdAnnotations()
if err != nil {
return err
}
}
return nil
}

View File

@@ -745,7 +745,6 @@ rules:
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
rnodes, err := rm.ToRNodeSlice() rnodes, err := rm.ToRNodeSlice()
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
@@ -999,6 +998,7 @@ spec:
return return
} }
assert.False(t, tc.errorExpected) assert.False(t, tc.errorExpected)
assert.NoError(t, m.RemoveIdAnnotations())
yml, err := m.AsYaml() yml, err := m.AsYaml()
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, strings.Join(tc.expected, "---\n"), string(yml)) assert.Equal(t, strings.Join(tc.expected, "---\n"), string(yml))
@@ -1111,6 +1111,7 @@ $patch: delete
assert.NoError(t, err, name) assert.NoError(t, err, name)
assert.NoError(t, m.ApplySmPatch(idSet, p), name) assert.NoError(t, m.ApplySmPatch(idSet, p), name)
assert.Equal(t, tc.finalMapSize, m.Size(), name) assert.Equal(t, tc.finalMapSize, m.Size(), name)
assert.NoError(t, m.RemoveIdAnnotations())
yml, err := m.AsYaml() yml, err := m.AsYaml()
assert.NoError(t, err, name) assert.NoError(t, err, name)
assert.Equal(t, tc.expected, string(yml), name) assert.Equal(t, tc.expected, string(yml), name)

View File

@@ -35,17 +35,17 @@ func (rf *Factory) FromMap(m map[string]interface{}) *Resource {
// FromMapWithName returns a new instance with the given "original" name. // FromMapWithName returns a new instance with the given "original" name.
func (rf *Factory) FromMapWithName(n string, m map[string]interface{}) *Resource { func (rf *Factory) FromMapWithName(n string, m map[string]interface{}) *Resource {
return rf.makeOne(rf.kf.FromMap(m), nil).setOriginalName(n) return rf.makeOne(rf.kf.FromMap(m), nil).SetOriginalName(n, true)
} }
// FromMapWithNamespace returns a new instance with the given "original" namespace. // FromMapWithNamespace returns a new instance with the given "original" namespace.
func (rf *Factory) FromMapWithNamespace(n string, m map[string]interface{}) *Resource { func (rf *Factory) FromMapWithNamespace(n string, m map[string]interface{}) *Resource {
return rf.makeOne(rf.kf.FromMap(m), nil).setOriginalNs(n) return rf.makeOne(rf.kf.FromMap(m), nil).SetOriginalNs(n, true)
} }
// FromMapWithNamespaceAndName returns a new instance with the given "original" namespace. // FromMapWithNamespaceAndName returns a new instance with the given "original" namespace.
func (rf *Factory) FromMapWithNamespaceAndName(ns string, n string, m map[string]interface{}) *Resource { func (rf *Factory) FromMapWithNamespaceAndName(ns string, n string, m map[string]interface{}) *Resource {
return rf.makeOne(rf.kf.FromMap(m), nil).setOriginalNs(ns).setOriginalName(n) return rf.makeOne(rf.kf.FromMap(m), nil).SetOriginalNs(ns, true).SetOriginalName(n, true)
} }
// FromMapAndOption returns a new instance of Resource with given options. // FromMapAndOption returns a new instance of Resource with given options.
@@ -72,7 +72,7 @@ func (rf *Factory) makeOne(
kunStr: u, kunStr: u,
options: o, options: o,
} }
return r.setOriginalName(r.kunStr.GetName()).setOriginalNs(r.GetNamespace()) return r
} }
// SliceFromPatches returns a slice of resources given a patch path // SliceFromPatches returns a slice of resources given a patch path
@@ -157,7 +157,7 @@ func (rf *Factory) SliceFromBytesWithNames(names []string, in []byte) ([]*Resour
return nil, fmt.Errorf("number of names doesn't match number of resources") return nil, fmt.Errorf("number of names doesn't match number of resources")
} }
for i, res := range result { for i, res := range result {
res.originalName = names[i] res.SetOriginalName(names[i], true)
} }
return result, nil return result, nil
} }

View File

@@ -23,16 +23,19 @@ import (
// paired with metadata used by kustomize. // paired with metadata used by kustomize.
// For more history, see sigs.k8s.io/kustomize/api/ifc.Unstructured // For more history, see sigs.k8s.io/kustomize/api/ifc.Unstructured
type Resource struct { type Resource struct {
kunStr ifc.Kunstructured kunStr ifc.Kunstructured
originalName string options *types.GenArgs
originalNs string refBy []resid.ResId
options *types.GenArgs refVarNames []string
refBy []resid.ResId
refVarNames []string
namePrefixes []string
nameSuffixes []string
} }
const (
nameAnnotation = "config.kubernetes.io/originalName"
prefixAnnotation = "config.kubernetes.io/prefixes"
suffixAnnotation = "config.kubernetes.io/suffixes"
namespaceAnnotation = "config.kubernetes.io/originalNs"
)
func (r *Resource) ResetPrimaryData(incoming *Resource) { func (r *Resource) ResetPrimaryData(incoming *Resource) {
r.kunStr = incoming.Copy() r.kunStr = incoming.Copy()
} }
@@ -172,13 +175,9 @@ func (r *Resource) CopyMergeMetaDataFieldsFrom(other *Resource) {
} }
func (r *Resource) copyOtherFields(other *Resource) { func (r *Resource) copyOtherFields(other *Resource) {
r.originalName = other.originalName
r.originalNs = other.originalNs
r.options = other.options r.options = other.options
r.refBy = other.copyRefBy() r.refBy = other.copyRefBy()
r.refVarNames = copyStringSlice(other.refVarNames) r.refVarNames = copyStringSlice(other.refVarNames)
r.namePrefixes = copyStringSlice(other.namePrefixes)
r.nameSuffixes = copyStringSlice(other.nameSuffixes)
} }
func (r *Resource) MergeDataMapFrom(o *Resource) { func (r *Resource) MergeDataMapFrom(o *Resource) {
@@ -245,28 +244,48 @@ func copyStringSlice(s []string) []string {
// Implements ResCtx AddNamePrefix // Implements ResCtx AddNamePrefix
func (r *Resource) AddNamePrefix(p string) { func (r *Resource) AddNamePrefix(p string) {
r.namePrefixes = append(r.namePrefixes, p) annotations := r.GetAnnotations()
if annotations == nil {
annotations = make(map[string]string)
}
if _, ok := annotations[prefixAnnotation]; !ok {
annotations[prefixAnnotation] = p
} else {
annotations[prefixAnnotation] = annotations[prefixAnnotation] + "," + p
}
r.SetAnnotations(annotations)
} }
// Implements ResCtx AddNameSuffix // Implements ResCtx AddNameSuffix
func (r *Resource) AddNameSuffix(s string) { func (r *Resource) AddNameSuffix(s string) {
r.nameSuffixes = append(r.nameSuffixes, s) annotations := r.GetAnnotations()
if annotations == nil {
annotations = make(map[string]string)
}
if _, ok := annotations[suffixAnnotation]; !ok {
annotations[suffixAnnotation] = s
} else {
annotations[suffixAnnotation] = annotations[suffixAnnotation] + "," + s
}
r.SetAnnotations(annotations)
} }
// Implements ResCtx GetOutermostNamePrefix // Implements ResCtx GetOutermostNamePrefix
func (r *Resource) GetOutermostNamePrefix() string { func (r *Resource) GetOutermostNamePrefix() string {
if len(r.namePrefixes) == 0 { namePrefixes := r.GetNamePrefixes()
if len(namePrefixes) == 0 {
return "" return ""
} }
return r.namePrefixes[len(r.namePrefixes)-1] return namePrefixes[len(namePrefixes)-1]
} }
// Implements ResCtx GetOutermostNameSuffix // Implements ResCtx GetOutermostNameSuffix
func (r *Resource) GetOutermostNameSuffix() string { func (r *Resource) GetOutermostNameSuffix() string {
if len(r.nameSuffixes) == 0 { nameSuffixes := r.GetNameSuffixes()
if len(nameSuffixes) == 0 {
return "" return ""
} }
return r.nameSuffixes[len(r.nameSuffixes)-1] return nameSuffixes[len(nameSuffixes)-1]
} }
func sameEndingSubarray(a, b []string) bool { func sameEndingSubarray(a, b []string) bool {
@@ -291,12 +310,20 @@ func sameEndingSubarray(a, b []string) bool {
// Implements ResCtx GetNamePrefixes // Implements ResCtx GetNamePrefixes
func (r *Resource) GetNamePrefixes() []string { func (r *Resource) GetNamePrefixes() []string {
return r.namePrefixes annotations := r.GetAnnotations()
if _, ok := annotations[prefixAnnotation]; !ok {
return nil
}
return strings.Split(annotations[prefixAnnotation], ",")
} }
// Implements ResCtx GetNameSuffixes // Implements ResCtx GetNameSuffixes
func (r *Resource) GetNameSuffixes() []string { func (r *Resource) GetNameSuffixes() []string {
return r.nameSuffixes annotations := r.GetAnnotations()
if _, ok := annotations[suffixAnnotation]; !ok {
return nil
}
return strings.Split(annotations[suffixAnnotation], ",")
} }
// OutermostPrefixSuffixEquals returns true if both resources // OutermostPrefixSuffixEquals returns true if both resources
@@ -320,23 +347,96 @@ func (r *Resource) PrefixesSuffixesEquals(o ResCtx) bool {
return sameEndingSubarray(r.GetNamePrefixes(), o.GetNamePrefixes()) && sameEndingSubarray(r.GetNameSuffixes(), o.GetNameSuffixes()) return sameEndingSubarray(r.GetNamePrefixes(), o.GetNamePrefixes()) && sameEndingSubarray(r.GetNameSuffixes(), o.GetNameSuffixes())
} }
func (r *Resource) GetOriginalName() string { func (r *Resource) RemoveIdAnnotations() error {
return r.originalName annotations := r.GetAnnotations()
if annotations == nil {
annotations = make(map[string]string)
}
delete(annotations, nameAnnotation)
delete(annotations, prefixAnnotation)
delete(annotations, suffixAnnotation)
delete(annotations, namespaceAnnotation)
if len(annotations) == 0 {
json, err := r.MarshalJSON()
if err != nil {
return err
}
yml, err := yaml.JSONToYAML(json)
if err != nil {
return err
}
rnode, err := kyaml.Parse(string(yml))
if err != nil {
return err
}
err = rnode.SetAnnotations(nil)
if err != nil {
return err
}
b, err := rnode.MarshalJSON()
if err != nil {
return err
}
err = r.UnmarshalJSON(b)
if err != nil {
return err
}
return nil
}
r.SetAnnotations(annotations)
return nil
} }
// Making this public would be bad. func (r *Resource) GetOriginalName() string {
func (r *Resource) setOriginalName(n string) *Resource { annotations := r.GetAnnotations()
r.originalName = n if name, ok := annotations[nameAnnotation]; ok {
return name
}
return r.kunStr.GetName()
}
func (r *Resource) SetOriginalName(n string, overwrite bool) *Resource {
annotations := r.GetAnnotations()
if annotations == nil {
annotations = make(map[string]string)
}
if _, ok := annotations[nameAnnotation]; !ok || overwrite {
annotations[nameAnnotation] = n
}
r.kunStr.SetAnnotations(annotations)
return r return r
} }
func (r *Resource) GetOriginalNs() string { func (r *Resource) GetOriginalNs() string {
return r.originalNs annotations := r.GetAnnotations()
if ns, ok := annotations[namespaceAnnotation]; ok {
return ns
}
ns := r.GetNamespace()
if ns == "default" {
return ""
}
return ns
} }
// Making this public would be bad. func (r *Resource) SetOriginalNs(n string, overwrite bool) *Resource {
func (r *Resource) setOriginalNs(n string) *Resource { if n == "" {
r.originalNs = n n = "default"
}
annotations := r.GetAnnotations()
if annotations == nil {
annotations = make(map[string]string)
}
if _, ok := annotations[namespaceAnnotation]; !ok || overwrite {
annotations[namespaceAnnotation] = n
}
r.SetAnnotations(annotations)
return r return r
} }

View File

@@ -695,6 +695,325 @@ spec:
} }
} }
func TestSetOriginalNameAndNs(t *testing.T) {
input := `apiVersion: apps/v1
kind: Secret
metadata:
name: newName`
factory := provider.NewDefaultDepProvider().GetResourceFactory()
resources, err := factory.SliceFromBytes([]byte(input))
if err != nil {
t.Fatal(err)
}
res := resources[0]
res.SetOriginalName("oldName", false)
res.SetOriginalNs("default", false)
expected := `apiVersion: apps/v1
kind: Secret
metadata:
annotations:
config.kubernetes.io/originalName: oldName
config.kubernetes.io/originalNs: default
name: newName
`
bytes, err := res.AsYAML()
if err != nil {
t.Fatal(err)
}
assert.Equal(t, expected, string(bytes))
}
func TestGetOriginalName(t *testing.T) {
tests := []struct {
input string
expected string
}{
{
// no name annotation, return the name
input: `apiVersion: apps/v1
kind: Secret
metadata:
name: mySecret`,
expected: "mySecret",
},
{
// return name from name annotation
input: `apiVersion: apps/v1
kind: Secret
metadata:
annotations:
config.kubernetes.io/originalName: oldName
name: newName`,
expected: "oldName",
},
}
for _, test := range tests {
factory := provider.NewDefaultDepProvider().GetResourceFactory()
resources, err := factory.SliceFromBytes([]byte(test.input))
if err != nil {
t.Fatal(err)
}
assert.Equal(t, test.expected, resources[0].GetOriginalName())
}
}
func TestSetOriginalName(t *testing.T) {
tests := []struct {
input string
originalName string
overwrite bool
expected string
}{
{
// no original name set, overwrite is false
input: `apiVersion: apps/v1
kind: Secret
metadata:
name: newName`,
originalName: "oldName",
overwrite: false,
expected: `apiVersion: apps/v1
kind: Secret
metadata:
annotations:
config.kubernetes.io/originalName: oldName
name: newName
`,
},
{
// no original name set, overwrite is true
input: `apiVersion: apps/v1
kind: Secret
metadata:
name: newName`,
originalName: "oldName",
overwrite: true,
expected: `apiVersion: apps/v1
kind: Secret
metadata:
annotations:
config.kubernetes.io/originalName: oldName
name: newName
`,
},
{
// original name is set, overwrite is false, resource shouldn't change
input: `apiVersion: apps/v1
kind: Secret
metadata:
annotations:
config.kubernetes.io/originalName: oldName
name: newName`,
originalName: "newOriginalName",
overwrite: false,
expected: `apiVersion: apps/v1
kind: Secret
metadata:
annotations:
config.kubernetes.io/originalName: oldName
name: newName
`,
},
{
// original name is set, overwrite is true, resource should change
input: `apiVersion: apps/v1
kind: Secret
metadata:
annotations:
config.kubernetes.io/originalName: oldName
name: newName`,
originalName: "newOriginalName",
overwrite: true,
expected: `apiVersion: apps/v1
kind: Secret
metadata:
annotations:
config.kubernetes.io/originalName: newOriginalName
name: newName
`,
},
}
for _, test := range tests {
factory := provider.NewDefaultDepProvider().GetResourceFactory()
resources, err := factory.SliceFromBytes([]byte(test.input))
if err != nil {
t.Fatal(err)
}
res := resources[0]
res.SetOriginalName(test.originalName, test.overwrite)
bytes, err := res.AsYAML()
if err != nil {
t.Fatal(err)
}
assert.Equal(t, test.expected, string(bytes))
}
}
func TestGetOriginalNs(t *testing.T) {
tests := []struct {
input string
expected string
}{
{
// no namespace, return default
input: `apiVersion: apps/v1
kind: Secret
metadata:
name: mySecret`,
expected: "",
},
{
// return old namespace
input: `apiVersion: apps/v1
kind: Secret
metadata:
annotations:
config.kubernetes.io/originalNs: oldNamespace
name: mySecret
namespace: myNamespace`,
expected: "oldNamespace",
},
{
// return namespace
input: `apiVersion: apps/v1
kind: Secret
metadata:
name: mySecret
namespace: myNamespace`,
expected: "myNamespace",
},
}
for _, test := range tests {
factory := provider.NewDefaultDepProvider().GetResourceFactory()
resources, err := factory.SliceFromBytes([]byte(test.input))
if err != nil {
t.Fatal(err)
}
assert.Equal(t, test.expected, resources[0].GetOriginalNs())
}
}
func TestSetOriginalNs(t *testing.T) {
tests := []struct {
input string
originalNs string
overwrite bool
expected string
}{
{
// no original namespace set, overwrite is false
input: `apiVersion: apps/v1
kind: Secret
metadata:
name: newName
namespace: newNamespace`,
originalNs: "oldNamespace",
overwrite: false,
expected: `apiVersion: apps/v1
kind: Secret
metadata:
annotations:
config.kubernetes.io/originalNs: oldNamespace
name: newName
namespace: newNamespace
`,
},
{
// no original name set, overwrite is true
input: `apiVersion: apps/v1
kind: Secret
metadata:
name: newName
namespace: newNamespace`,
originalNs: "oldNamespace",
overwrite: true,
expected: `apiVersion: apps/v1
kind: Secret
metadata:
annotations:
config.kubernetes.io/originalNs: oldNamespace
name: newName
namespace: newNamespace
`,
},
{
// original name is set, overwrite is false, resource shouldn't change
input: `apiVersion: apps/v1
kind: Secret
metadata:
annotations:
config.kubernetes.io/originalNs: oldNamespace
name: newName
namespace: newNamespace`,
originalNs: "newOriginalNamespace",
overwrite: false,
expected: `apiVersion: apps/v1
kind: Secret
metadata:
annotations:
config.kubernetes.io/originalNs: oldNamespace
name: newName
namespace: newNamespace
`,
},
{
// original name is set, overwrite is true, resource should change
input: `apiVersion: apps/v1
kind: Secret
metadata:
annotations:
config.kubernetes.io/originalNs: oldNamespace
name: newName
namespace: newNamespace`,
originalNs: "newOriginalNamespace",
overwrite: true,
expected: `apiVersion: apps/v1
kind: Secret
metadata:
annotations:
config.kubernetes.io/originalNs: newOriginalNamespace
name: newName
namespace: newNamespace
`,
},
}
for _, test := range tests {
factory := provider.NewDefaultDepProvider().GetResourceFactory()
resources, err := factory.SliceFromBytes([]byte(test.input))
if err != nil {
t.Fatal(err)
}
res := resources[0]
res.SetOriginalNs(test.originalNs, test.overwrite)
bytes, err := res.AsYAML()
if err != nil {
t.Fatal(err)
}
assert.Equal(t, test.expected, string(bytes))
}
}
// baseResource produces a base object which used to test // baseResource produces a base object which used to test
// patch transformation // patch transformation
// Also the structure is matching the Deployment syntax // Also the structure is matching the Deployment syntax

View File

@@ -126,6 +126,14 @@ func (th Harness) AssertActualEqualsExpected(
th.AssertActualEqualsExpectedWithTweak(m, nil, expected) th.AssertActualEqualsExpectedWithTweak(m, nil, expected)
} }
func (th Harness) AssertActualEqualsExpectedNoIdAnnotations(m resmap.ResMap, expected string) {
err := m.RemoveIdAnnotations()
if err != nil {
th.t.Fatalf("Err: %v", err)
}
th.AssertActualEqualsExpectedWithTweak(m, nil, expected)
}
func (th Harness) AssertActualEqualsExpectedWithTweak( func (th Harness) AssertActualEqualsExpectedWithTweak(
m resmap.ResMap, tweaker func([]byte) []byte, expected string) { m resmap.ResMap, tweaker func([]byte) []byte, expected string) {
assertActualEqualsExpectedWithTweak(th, m, tweaker, expected) assertActualEqualsExpectedWithTweak(th, m, tweaker, expected)

View File

@@ -109,6 +109,7 @@ func (th *HarnessEnhanced) LoadAndRunGenerator(
if err != nil { if err != nil {
th.t.Fatalf("Err: %v", err) th.t.Fatalf("Err: %v", err)
} }
rm.RemoveIdAnnotations()
return rm return rm
} }
@@ -124,7 +125,7 @@ func (th *HarnessEnhanced) LoadAndRunTransformer(
func (th *HarnessEnhanced) RunTransformerAndCheckResult( func (th *HarnessEnhanced) RunTransformerAndCheckResult(
config, input, expected string) { config, input, expected string) {
resMap := th.LoadAndRunTransformer(config, input) resMap := th.LoadAndRunTransformer(config, input)
th.AssertActualEqualsExpected(resMap, expected) th.AssertActualEqualsExpectedNoIdAnnotations(resMap, expected)
} }
func (th *HarnessEnhanced) ErrorFromLoadAndRunTransformer( func (th *HarnessEnhanced) ErrorFromLoadAndRunTransformer(

View File

@@ -32,6 +32,7 @@ func (p *plugin) Transform(m resmap.ResMap) error {
if err != nil { if err != nil {
return err return err
} }
res.SetOriginalName(res.GetName(), false)
res.SetName(fmt.Sprintf("%s-%s", res.GetName(), h)) res.SetName(fmt.Sprintf("%s-%s", res.GetName(), h))
} }
} }

View File

@@ -53,7 +53,7 @@ spec:
image: nginx:1.7.9 image: nginx:1.7.9
`) `)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
metadata: metadata:

View File

@@ -52,7 +52,7 @@ spec:
name: init-alpine name: init-alpine
`) `)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: v1 apiVersion: v1
group: apps group: apps
kind: Deployment kind: Deployment
@@ -122,7 +122,7 @@ spec:
name: init-alpine name: init-alpine
`) `)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: v1 apiVersion: v1
group: apps group: apps
kind: Deployment kind: Deployment
@@ -194,7 +194,7 @@ spec:
name: init-alpine name: init-alpine
`) `)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: v1 apiVersion: v1
group: apps group: apps
kind: Deployment kind: Deployment
@@ -265,7 +265,7 @@ spec:
name: init-alpine name: init-alpine
`) `)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: v1 apiVersion: v1
group: apps group: apps
kind: Deployment kind: Deployment
@@ -337,7 +337,7 @@ spec:
name: init-alpine name: init-alpine
`) `)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: v1 apiVersion: v1
group: apps group: apps
kind: Deployment kind: Deployment
@@ -395,7 +395,7 @@ spec:
containers: containers:
initContainers: initContainers:
`) `)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: v1 apiVersion: v1
group: apps group: apps
kind: Deployment kind: Deployment
@@ -438,7 +438,7 @@ spec:
name: my-image name: my-image
`) `)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: v1 apiVersion: v1
group: apps group: apps
kind: Deployment kind: Deployment
@@ -480,7 +480,7 @@ spec:
name: my-image name: my-image
`) `)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: v1 apiVersion: v1
group: apps group: apps
kind: Deployment kind: Deployment

View File

@@ -65,7 +65,7 @@ spec:
image: nginx image: nginx
`) `)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:

View File

@@ -65,7 +65,7 @@ metadata:
name: apricot name: apricot
`) `)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:

View File

@@ -38,6 +38,7 @@ func (p *plugin) Transform(m resmap.ResMap) error {
// Don't mutate empty objects? // Don't mutate empty objects?
continue continue
} }
r.SetOriginalNs(r.GetNamespace(), false)
err := r.ApplyFilter(namespace.Filter{ err := r.ApplyFilter(namespace.Filter{
Namespace: p.Namespace, Namespace: p.Namespace,
FsSlice: p.FieldSpecs, FsSlice: p.FieldSpecs,

View File

@@ -603,7 +603,7 @@ spec:
B: Y B: Y
`) `)
assert.NoError(t, err) assert.NoError(t, err)
th.AssertActualEqualsExpected( th.AssertActualEqualsExpectedNoIdAnnotations(
resMap, resMap,
// In kyaml/yaml.merge2, the empty "B: " is dropped // In kyaml/yaml.merge2, the empty "B: " is dropped
// when patch1 and patch2 are merged, so the patch // when patch1 and patch2 are merged, so the patch
@@ -652,7 +652,7 @@ spec:
B: Y B: Y
`) `)
assert.NoError(t, err) assert.NoError(t, err)
th.AssertActualEqualsExpected( th.AssertActualEqualsExpectedNoIdAnnotations(
resMap, resMap,
// This time only patch2 was applied. Same answer on the kyaml // This time only patch2 was applied. Same answer on the kyaml
// path, but different answer on apimachinery path (B becomes "true"?) // path, but different answer on apimachinery path (B becomes "true"?)
@@ -1388,7 +1388,7 @@ paths:
- patch.yaml - patch.yaml
`, target) `, target)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
@@ -1430,7 +1430,7 @@ paths:
- patch.yaml - patch.yaml
`, target) `, target)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:

View File

@@ -108,6 +108,7 @@ func (p *plugin) transformJson6902(m resmap.ResMap, patch jsonpatch.Patch) error
return err return err
} }
for _, res := range resources { for _, res := range resources {
res.SetOriginalName(res.GetName(), false)
err = res.ApplyFilter(patchjson6902.Filter{ err = res.ApplyFilter(patchjson6902.Filter{
Patch: p.Patch, Patch: p.Patch,
}) })

View File

@@ -306,7 +306,7 @@ path: patch.yaml
target: target:
name: myDeploy name: myDeploy
`, someDeploymentResources) `, someDeploymentResources)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:

View File

@@ -6,7 +6,6 @@ package main
import ( import (
"errors" "errors"
"sigs.k8s.io/kustomize/api/filters/prefixsuffix" "sigs.k8s.io/kustomize/api/filters/prefixsuffix"
"sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resmap"
@@ -70,8 +69,12 @@ func (p *plugin) Transform(m resmap.ResMap) error {
// this will add a prefix and a suffix // this will add a prefix and a suffix
// to the resource even if those are // to the resource even if those are
// empty // empty
r.AddNamePrefix(p.Prefix) r.AddNamePrefix(p.Prefix)
r.AddNameSuffix(p.Suffix) r.AddNameSuffix(p.Suffix)
if p.Prefix != "" || p.Suffix != "" {
r.SetOriginalName(r.GetName(), false)
}
} }
err := r.ApplyFilter(prefixsuffix.Filter{ err := r.ApplyFilter(prefixsuffix.Filter{
Prefix: p.Prefix, Prefix: p.Prefix,

View File

@@ -62,6 +62,10 @@ metadata:
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:
annotations:
config.kubernetes.io/originalName: apple
config.kubernetes.io/prefixes: baked-
config.kubernetes.io/suffixes: -pie
name: baked-apple-pie name: baked-apple-pie
spec: spec:
ports: ports:
@@ -80,6 +84,10 @@ metadata:
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
metadata: metadata:
annotations:
config.kubernetes.io/originalName: cm
config.kubernetes.io/prefixes: baked-
config.kubernetes.io/suffixes: -pie
name: baked-cm-pie name: baked-cm-pie
`) `)
@@ -126,6 +134,10 @@ metadata:
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
annotations:
config.kubernetes.io/originalName: deployment
config.kubernetes.io/prefixes: test-
config.kubernetes.io/suffixes: null
name: test-deployment name: test-deployment
spec: spec:
template: template:

View File

@@ -91,7 +91,7 @@ spec:
app: app app: app
`) `)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: apps/v1 apiVersion: apps/v1
kind: Service kind: Service
metadata: metadata:
@@ -180,7 +180,7 @@ fieldSpecs:
- path: spec/replicas - path: spec/replicas
create: true create: true
kind: Deployment`, rm) kind: Deployment`, rm)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:

View File

@@ -26,7 +26,7 @@ metadata:
name: meatball name: meatball
`) `)
th.AssertActualEqualsExpected(m, ` th.AssertActualEqualsExpectedNoIdAnnotations(m, `
apiVersion: apps/v1 apiVersion: apps/v1
kind: MeatBall kind: MeatBall
metadata: metadata:

View File

@@ -36,7 +36,7 @@ fruit: $FRUIT
vegetable: $VEGGIE vegetable: $VEGGIE
`) `)
th.AssertActualEqualsExpected(rm, ` th.AssertActualEqualsExpectedNoIdAnnotations(rm, `
apiVersion: apps/v1 apiVersion: apps/v1
beans: two two two two beans: two two two two
fruit: orange fruit: orange

View File

@@ -27,7 +27,7 @@ metadata:
name: meatball name: meatball
`) `)
th.AssertActualEqualsExpected(m, ` th.AssertActualEqualsExpectedNoIdAnnotations(m, `
apiVersion: apps/v1 apiVersion: apps/v1
kind: MeatBall kind: MeatBall
metadata: metadata: