mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-10 08:20:59 +00:00
Preserve order when merging.
This commit is contained in:
@@ -42,18 +42,14 @@ func (ra *ResAccumulator) Vars() []types.Var {
|
|||||||
return ra.varSet.Set()
|
return ra.varSet.Set()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ra *ResAccumulator) MergeResourcesWithErrorOnIdCollision(
|
func (ra *ResAccumulator) AppendAll(
|
||||||
resources resmap.ResMap) (err error) {
|
resources resmap.ResMap) error {
|
||||||
ra.resMap, err = resmap.MergeWithErrorOnIdCollision(
|
return ra.resMap.AppendAll(resources)
|
||||||
resources, ra.resMap)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ra *ResAccumulator) MergeResourcesWithOverride(
|
func (ra *ResAccumulator) AbsorbAll(
|
||||||
resources resmap.ResMap) (err error) {
|
resources resmap.ResMap) error {
|
||||||
ra.resMap, err = resmap.MergeWithOverride(
|
return ra.resMap.AbsorbAll(resources)
|
||||||
ra.resMap, resources)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ra *ResAccumulator) MergeConfig(
|
func (ra *ResAccumulator) MergeConfig(
|
||||||
@@ -71,7 +67,7 @@ func (ra *ResAccumulator) MergeVars(incoming []types.Var) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ra *ResAccumulator) MergeAccumulator(other *ResAccumulator) (err error) {
|
func (ra *ResAccumulator) MergeAccumulator(other *ResAccumulator) (err error) {
|
||||||
err = ra.MergeResourcesWithErrorOnIdCollision(other.resMap)
|
err = ra.AppendAll(other.resMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ func makeResAccumulator() (*ResAccumulator, *resource.Factory, error) {
|
|||||||
}
|
}
|
||||||
rf := resource.NewFactory(
|
rf := resource.NewFactory(
|
||||||
kunstruct.NewKunstructuredFactoryImpl())
|
kunstruct.NewKunstructuredFactoryImpl())
|
||||||
err = ra.MergeResourcesWithErrorOnIdCollision(
|
err = ra.AppendAll(
|
||||||
resmap.FromMap(map[resid.ResId]*resource.Resource{
|
resmap.FromMap(map[resid.ResId]*resource.Resource{
|
||||||
resid.NewResId(
|
resid.NewResId(
|
||||||
gvk.Gvk{Group: "apps", Version: "v1", Kind: "Deployment"},
|
gvk.Gvk{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
@@ -188,7 +188,7 @@ func TestResolveVarsVarNeedsDisambiguation(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
err = ra.MergeResourcesWithErrorOnIdCollision(rm0)
|
err = ra.AppendAll(rm0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected err: %v", err)
|
t.Fatalf("unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ func (o *Options) emitResources(
|
|||||||
if o.outputPath != "" && fSys.IsDir(o.outputPath) {
|
if o.outputPath != "" && fSys.IsDir(o.outputPath) {
|
||||||
return writeIndividualFiles(fSys, o.outputPath, m)
|
return writeIndividualFiles(fSys, o.outputPath, m)
|
||||||
}
|
}
|
||||||
res, err := m.EncodeAsYaml()
|
res, err := m.AsYaml(resmap.LegacySort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ func (th *KustTestHarness) AssertActualEqualsExpected(
|
|||||||
if len(expected) > 0 && expected[0] == 10 {
|
if len(expected) > 0 && expected[0] == 10 {
|
||||||
expected = expected[1:]
|
expected = expected[1:]
|
||||||
}
|
}
|
||||||
actual, err := m.EncodeAsYaml()
|
actual, err := m.AsYaml(resmap.LegacySort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
th.t.Fatalf("Unexpected err: %v", err)
|
th.t.Fatalf("Unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ func (p *ExecPlugin) Transform(rm resmap.ResMap) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// encode the ResMap so it can be fed to the plugin
|
// encode the ResMap so it can be fed to the plugin
|
||||||
resources, err := inputRM.EncodeAsYaml()
|
resources, err := inputRM.AsYaml(resmap.Identity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,17 +84,34 @@ type ResMap interface {
|
|||||||
// Error on Id collision.
|
// Error on Id collision.
|
||||||
AppendWithId(resid.ResId, *resource.Resource) error
|
AppendWithId(resid.ResId, *resource.Resource) error
|
||||||
|
|
||||||
// AsMap returns ResId, *Resource pairs in
|
// AppendAll appends another ResMap to self,
|
||||||
// arbitrary order via a map.
|
// failing on any Id collision.
|
||||||
|
AppendAll(ResMap) error
|
||||||
|
|
||||||
|
// AbsorbAll appends, replaces or merges the contents
|
||||||
|
// of another ResMap into self,
|
||||||
|
// allowing and sometimes demanding ID collisions.
|
||||||
|
// A collision would be demanded, say, when a generated
|
||||||
|
// ConfigMap has the "replace" option in its generation
|
||||||
|
// instructions, meaning it _must_ replace
|
||||||
|
// something in the known set of resources.
|
||||||
|
// If a resource id for resource X is found to already
|
||||||
|
// be in self, then the behavior field for X must
|
||||||
|
// be BehaviorMerge or BehaviorReplace. If X is not in
|
||||||
|
// self, then its behavior _cannot_ be merge or replace.
|
||||||
|
AbsorbAll(ResMap) error
|
||||||
|
|
||||||
|
// AsMap returns (ResId, *Resource) pairs in
|
||||||
|
// arbitrary order via a generated map.
|
||||||
// The map is discardable, and edits to map structure
|
// The map is discardable, and edits to map structure
|
||||||
// have no impact on the ResMap.
|
// have no impact on the ResMap.
|
||||||
// The Ids are copies, but the resources are pointers,
|
// The Ids are copies, but the resources are pointers,
|
||||||
// so the resources themselves can be modified.
|
// so the resources themselves can be modified.
|
||||||
AsMap() map[resid.ResId]*resource.Resource
|
AsMap() map[resid.ResId]*resource.Resource
|
||||||
|
|
||||||
// EncodeAsYaml emits the resources as YAML in a byte slice.
|
// AsYaml returns the yaml form of resources, after twiddling.
|
||||||
// Resources are separated by `---`.
|
// Certainly nobody will abuse the twiddler.
|
||||||
EncodeAsYaml() ([]byte, error)
|
AsYaml(f ResTwiddler) ([]byte, error)
|
||||||
|
|
||||||
// Gets the resource with the given Id, else nil.
|
// Gets the resource with the given Id, else nil.
|
||||||
GetById(resid.ResId) *resource.Resource
|
GetById(resid.ResId) *resource.Resource
|
||||||
@@ -350,33 +367,42 @@ func (m *resWrangler) GetMatchingIds(matches IdMatcher) []resid.ResId {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeAsYaml implements ResMap.
|
// Identity returns Resources as is.
|
||||||
func (m *resWrangler) EncodeAsYaml() ([]byte, error) {
|
func Identity(m ResMap) []*resource.Resource {
|
||||||
// TODO: should be able to suppress this sort
|
return m.Resources()
|
||||||
// and rely on ordering as specified in the ResMap
|
}
|
||||||
// internal rList.
|
|
||||||
|
// LegacySort return Resources in a particular order.
|
||||||
|
func LegacySort(m ResMap) []*resource.Resource {
|
||||||
|
resources := make([]*resource.Resource, m.Size())
|
||||||
ids := m.AllIds()
|
ids := m.AllIds()
|
||||||
sort.Sort(IdSlice(ids))
|
sort.Sort(IdSlice(ids))
|
||||||
|
for i, id := range ids {
|
||||||
|
resources[i] = m.GetById(id)
|
||||||
|
}
|
||||||
|
return resources
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResTwiddler func(ResMap) []*resource.Resource
|
||||||
|
|
||||||
|
// AsYaml implements ResMap.
|
||||||
|
func (m *resWrangler) AsYaml(twiddle ResTwiddler) ([]byte, error) {
|
||||||
firstObj := true
|
firstObj := true
|
||||||
var b []byte
|
var b []byte
|
||||||
buf := bytes.NewBuffer(b)
|
buf := bytes.NewBuffer(b)
|
||||||
for _, id := range ids {
|
for _, res := range twiddle(m) {
|
||||||
obj := m.GetById(id)
|
out, err := yaml.Marshal(res.Map())
|
||||||
out, err := yaml.Marshal(obj.Map())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if firstObj {
|
if firstObj {
|
||||||
firstObj = false
|
firstObj = false
|
||||||
} else {
|
} else {
|
||||||
_, err = buf.WriteString("---\n")
|
if _, err = buf.WriteString("---\n"); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_, err = buf.Write(out)
|
if _, err = buf.Write(out); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -387,7 +413,7 @@ func (m *resWrangler) EncodeAsYaml() ([]byte, error) {
|
|||||||
func (m *resWrangler) ErrorIfNotEqual(other ResMap) error {
|
func (m *resWrangler) ErrorIfNotEqual(other ResMap) error {
|
||||||
m2, ok := other.(*resWrangler)
|
m2, ok := other.(*resWrangler)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Errorf("bad cast to resmapImpl"))
|
panic(fmt.Errorf("bad cast"))
|
||||||
}
|
}
|
||||||
if m.Size() != m2.Size() {
|
if m.Size() != m2.Size() {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
@@ -462,86 +488,93 @@ func (m *resWrangler) ResourcesThatCouldReference(inputId resid.ResId) ResMap {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// MergeWithErrorOnIdCollision combines multiple ResMap instances, failing on
|
// AppendAll implements ResMap.
|
||||||
// key collision and skipping nil maps.
|
func (m *resWrangler) AppendAll(other ResMap) error {
|
||||||
// If all of the maps are nil, an empty ResMap is returned.
|
if other == nil {
|
||||||
func MergeWithErrorOnIdCollision(maps ...ResMap) (ResMap, error) {
|
return nil
|
||||||
result := New()
|
}
|
||||||
for _, m := range maps {
|
w2, ok := other.(*resWrangler)
|
||||||
if m == nil {
|
if !ok {
|
||||||
continue
|
panic(fmt.Errorf("bad cast"))
|
||||||
|
}
|
||||||
|
for i, res := range w2.Resources() {
|
||||||
|
id, err := w2.idMappingToIndex(i)
|
||||||
|
if err != nil {
|
||||||
|
panic("map is unrecoverably corrupted; " + err.Error())
|
||||||
}
|
}
|
||||||
for id, res := range m.AsMap() {
|
err = m.AppendWithId(id, res)
|
||||||
err := result.AppendWithId(id, res)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MergeWithOverride combines multiple ResMap instances, allowing and sometimes
|
// AbsorbAll implements ResMap.
|
||||||
// demanding certain collisions and skipping nil maps.
|
func (m *resWrangler) AbsorbAll(other ResMap) error {
|
||||||
// A collision would be demanded, say, when a generated ConfigMap has the
|
if other == nil {
|
||||||
// "replace" option in its generation instructions, meaning it is supposed
|
return nil
|
||||||
// to replace something from the raw resources list.
|
|
||||||
// If all of the maps are nil, an empty ResMap is returned.
|
|
||||||
// When looping over the instances to combine them, if a resource id for
|
|
||||||
// resource X is found to be already in the combined map, then the behavior
|
|
||||||
// field for X must be BehaviorMerge or BehaviorReplace. If X is not in the
|
|
||||||
// map, then it's behavior cannot be merge or replace.
|
|
||||||
// nolint: gocyclo
|
|
||||||
func MergeWithOverride(maps ...ResMap) (ResMap, error) {
|
|
||||||
if len(maps) == 0 {
|
|
||||||
return New(), nil
|
|
||||||
}
|
}
|
||||||
result := maps[0]
|
w2, ok := other.(*resWrangler)
|
||||||
if result == nil {
|
if !ok {
|
||||||
result = New()
|
panic(fmt.Errorf("bad cast"))
|
||||||
}
|
}
|
||||||
for _, m := range maps[1:] {
|
for i, r := range w2.Resources() {
|
||||||
if m == nil {
|
id, err := w2.idMappingToIndex(i)
|
||||||
continue
|
if err != nil {
|
||||||
|
panic("map is unrecoverably corrupted; " + err.Error())
|
||||||
}
|
}
|
||||||
for id, r := range m.AsMap() {
|
err = m.appendReplaceOrMerge(id, r)
|
||||||
matchedId := result.GetMatchingIds(id.GvknEquals)
|
if err != nil {
|
||||||
if len(matchedId) == 1 {
|
return err
|
||||||
id = matchedId[0]
|
}
|
||||||
old := result.GetById(id)
|
}
|
||||||
if old == nil {
|
return nil
|
||||||
return nil, fmt.Errorf("id lookup failure")
|
}
|
||||||
}
|
|
||||||
switch r.Behavior() {
|
func (m *resWrangler) appendReplaceOrMerge(
|
||||||
case types.BehaviorReplace:
|
idForRes resid.ResId, res *resource.Resource) error {
|
||||||
r.Replace(old)
|
matchedId := m.GetMatchingIds(idForRes.GvknEquals)
|
||||||
err := result.ReplaceResource(id, r)
|
switch len(matchedId) {
|
||||||
if err != nil {
|
case 0:
|
||||||
return nil, err
|
switch res.Behavior() {
|
||||||
}
|
case types.BehaviorMerge, types.BehaviorReplace:
|
||||||
case types.BehaviorMerge:
|
return fmt.Errorf(
|
||||||
r.Merge(old)
|
"id %#v does not exist; cannot merge or replace", idForRes)
|
||||||
err := result.ReplaceResource(id, r)
|
default:
|
||||||
if err != nil {
|
// presumably types.BehaviorCreate
|
||||||
return nil, err
|
err := m.AppendWithId(idForRes, res)
|
||||||
}
|
if err != nil {
|
||||||
default:
|
return err
|
||||||
return nil, fmt.Errorf("id %#v exists; must merge or replace", id)
|
|
||||||
}
|
|
||||||
} else if len(matchedId) == 0 {
|
|
||||||
switch r.Behavior() {
|
|
||||||
case types.BehaviorMerge, types.BehaviorReplace:
|
|
||||||
return nil, fmt.Errorf("id %#v does not exist; cannot merge or replace", id)
|
|
||||||
default:
|
|
||||||
err := result.AppendWithId(id, r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil, fmt.Errorf("merge conflict, found multiple objects %v the Resmap %v can merge into", matchedId, id)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case 1:
|
||||||
|
mId := matchedId[0]
|
||||||
|
old := m.GetById(mId)
|
||||||
|
if old == nil {
|
||||||
|
return fmt.Errorf("id lookup failure")
|
||||||
|
}
|
||||||
|
switch res.Behavior() {
|
||||||
|
case types.BehaviorReplace:
|
||||||
|
res.Replace(old)
|
||||||
|
err := m.ReplaceResource(mId, res)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case types.BehaviorMerge:
|
||||||
|
res.Merge(old)
|
||||||
|
err := m.ReplaceResource(mId, res)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf(
|
||||||
|
"id %#v exists; must merge or replace", idForRes)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf(
|
||||||
|
"found multiple objects %v that could accept merge of %v",
|
||||||
|
matchedId, idForRes)
|
||||||
}
|
}
|
||||||
return result, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var deploy = gvk.Gvk{Group: "apps", Version: "v1", Kind: "Deployment"}
|
var deploy = gvk.Gvk{Group: "apps", Version: "v1", Kind: "Deployment"}
|
||||||
var statefulset = gvk.Gvk{Group: "apps", Version: "v1", Kind: "StatefulSet"}
|
|
||||||
var rf = resource.NewFactory(
|
var rf = resource.NewFactory(
|
||||||
kunstruct.NewKunstructuredFactoryImpl())
|
kunstruct.NewKunstructuredFactoryImpl())
|
||||||
var rmF = NewFactory(rf)
|
var rmF = NewFactory(rf)
|
||||||
@@ -161,25 +160,24 @@ kind: ConfigMap
|
|||||||
metadata:
|
metadata:
|
||||||
name: cm2
|
name: cm2
|
||||||
`)
|
`)
|
||||||
input := FromMap(map[resid.ResId]*resource.Resource{
|
input := New()
|
||||||
resid.NewResId(cmap, "cm1"): rf.FromMap(
|
input.Append(rf.FromMap(
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "ConfigMap",
|
"kind": "ConfigMap",
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": "cm1",
|
"name": "cm1",
|
||||||
},
|
},
|
||||||
}),
|
}))
|
||||||
resid.NewResId(cmap, "cm2"): rf.FromMap(
|
input.Append(rf.FromMap(
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "ConfigMap",
|
"kind": "ConfigMap",
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": "cm2",
|
"name": "cm2",
|
||||||
},
|
},
|
||||||
}),
|
}))
|
||||||
})
|
out, err := input.AsYaml(Identity)
|
||||||
out, err := input.EncodeAsYaml()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -581,172 +579,127 @@ func TestErrorIfNotEqual(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("%v should not equal %v %v", rm1, rm2, err)
|
t.Fatalf("%v should not equal %v %v", rm1, rm2, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMergeWithoutOverride(t *testing.T) {
|
func TestAppendAll(t *testing.T) {
|
||||||
input1 := FromMap(map[resid.ResId]*resource.Resource{
|
r1 := rf.FromMap(
|
||||||
resid.NewResId(deploy, "deploy1"): rf.FromMap(
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "apps/v1",
|
||||||
"apiVersion": "apps/v1",
|
"kind": "Deployment",
|
||||||
"kind": "Deployment",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "foo-deploy1",
|
||||||
"name": "foo-deploy1",
|
},
|
||||||
},
|
})
|
||||||
}),
|
input1 := rmF.FromResource(r1)
|
||||||
})
|
r2 := rf.FromMap(
|
||||||
input2 := FromMap(map[resid.ResId]*resource.Resource{
|
map[string]interface{}{
|
||||||
resid.NewResId(statefulset, "stateful1"): rf.FromMap(
|
"apiVersion": "apps/v1",
|
||||||
map[string]interface{}{
|
"kind": "StatefulSet",
|
||||||
"apiVersion": "apps/v1",
|
"metadata": map[string]interface{}{
|
||||||
"kind": "StatefulSet",
|
"name": "bar-stateful",
|
||||||
"metadata": map[string]interface{}{
|
},
|
||||||
"name": "bar-stateful",
|
})
|
||||||
},
|
input2 := rmF.FromResource(r2)
|
||||||
}),
|
|
||||||
})
|
expected := New()
|
||||||
input := []ResMap{input1, input2}
|
expected.Append(r1)
|
||||||
expected := FromMap(map[resid.ResId]*resource.Resource{
|
expected.Append(r2)
|
||||||
resid.NewResId(deploy, "deploy1"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
if err := input1.AppendAll(input2); err != nil {
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "foo-deploy1",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
resid.NewResId(statefulset, "stateful1"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "StatefulSet",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "bar-stateful",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
merged, err := MergeWithErrorOnIdCollision(input...)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
err = expected.ErrorIfNotEqual(merged)
|
if err := expected.ErrorIfNotEqual(input1); err != nil {
|
||||||
if err != nil {
|
input1.Debug("1")
|
||||||
t.Fatalf("%#v doesn't equal expected %#v", merged, expected)
|
expected.Debug("ex")
|
||||||
|
t.Fatalf("%#v doesn't equal expected %#v", input1, expected)
|
||||||
}
|
}
|
||||||
input3 := []ResMap{merged, nil}
|
if err := input1.AppendAll(nil); err != nil {
|
||||||
merged1, err := MergeWithErrorOnIdCollision(input3...)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
err = expected.ErrorIfNotEqual(merged1)
|
if err := expected.ErrorIfNotEqual(input1); err != nil {
|
||||||
if err != nil {
|
t.Fatalf("%#v doesn't equal expected %#v", input1, expected)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
input4 := []ResMap{nil, merged}
|
|
||||||
merged2, err := MergeWithErrorOnIdCollision(input4...)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
err = expected.ErrorIfNotEqual(merged2)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateMergeFixtures(b types.GenerationBehavior) []ResMap {
|
func makeMap1() ResMap {
|
||||||
input1 := FromMap(map[resid.ResId]*resource.Resource{
|
return rmF.FromResource(rf.FromMapAndOption(
|
||||||
resid.NewResId(cmap, "cmap"): rf.FromMapAndOption(
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "apps/v1",
|
||||||
"apiVersion": "apps/v1",
|
"kind": "ConfigMap",
|
||||||
"kind": "ConfigMap",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "cmap",
|
||||||
"name": "cmap",
|
},
|
||||||
},
|
"data": map[string]interface{}{
|
||||||
"data": map[string]interface{}{
|
"a": "x",
|
||||||
"a": "x",
|
"b": "y",
|
||||||
"b": "y",
|
},
|
||||||
},
|
}, &types.GeneratorArgs{
|
||||||
}, &types.GeneratorArgs{
|
Behavior: "create",
|
||||||
Behavior: "create",
|
}, nil))
|
||||||
}, nil),
|
|
||||||
})
|
|
||||||
input2 := FromMap(map[resid.ResId]*resource.Resource{
|
|
||||||
resid.NewResId(cmap, "cmap"): rf.FromMapAndOption(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "cmap",
|
|
||||||
},
|
|
||||||
"data": map[string]interface{}{
|
|
||||||
"a": "u",
|
|
||||||
"b": "v",
|
|
||||||
"c": "w",
|
|
||||||
},
|
|
||||||
}, &types.GeneratorArgs{
|
|
||||||
Behavior: b.String(),
|
|
||||||
}, nil),
|
|
||||||
})
|
|
||||||
return []ResMap{input1, input2}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMergeWithOverride(t *testing.T) {
|
func makeMap2(b types.GenerationBehavior) ResMap {
|
||||||
expected := FromMap(map[resid.ResId]*resource.Resource{
|
return rmF.FromResource(rf.FromMapAndOption(
|
||||||
resid.NewResId(cmap, "cmap"): rf.FromMapAndOption(
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "apps/v1",
|
||||||
"apiVersion": "apps/v1",
|
"kind": "ConfigMap",
|
||||||
"kind": "ConfigMap",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "cmap",
|
||||||
"annotations": map[string]interface{}{},
|
},
|
||||||
"labels": map[string]interface{}{},
|
"data": map[string]interface{}{
|
||||||
"name": "cmap",
|
"a": "u",
|
||||||
},
|
"b": "v",
|
||||||
"data": map[string]interface{}{
|
"c": "w",
|
||||||
"a": "u",
|
},
|
||||||
"b": "v",
|
}, &types.GeneratorArgs{
|
||||||
"c": "w",
|
Behavior: b.String(),
|
||||||
},
|
}, nil))
|
||||||
}, &types.GeneratorArgs{
|
}
|
||||||
Behavior: "create",
|
|
||||||
}, nil),
|
func TestAbsorbAll(t *testing.T) {
|
||||||
})
|
expected := rmF.FromResource(rf.FromMapAndOption(
|
||||||
merged, err := MergeWithOverride(generateMergeFixtures(types.BehaviorMerge)...)
|
map[string]interface{}{
|
||||||
if err != nil {
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"annotations": map[string]interface{}{},
|
||||||
|
"labels": map[string]interface{}{},
|
||||||
|
"name": "cmap",
|
||||||
|
},
|
||||||
|
"data": map[string]interface{}{
|
||||||
|
"a": "u",
|
||||||
|
"b": "v",
|
||||||
|
"c": "w",
|
||||||
|
},
|
||||||
|
}, &types.GeneratorArgs{
|
||||||
|
Behavior: "create",
|
||||||
|
}, nil))
|
||||||
|
w := makeMap1()
|
||||||
|
if err := w.AbsorbAll(makeMap2(types.BehaviorMerge)); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
err = expected.ErrorIfNotEqual(merged)
|
if err := expected.ErrorIfNotEqual(w); err != nil {
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
input3 := []ResMap{merged, nil}
|
w = makeMap1()
|
||||||
merged1, err := MergeWithOverride(input3...)
|
if err := w.AbsorbAll(nil); err != nil {
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
err = expected.ErrorIfNotEqual(merged1)
|
if err := w.ErrorIfNotEqual(makeMap1()); err != nil {
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
input4 := []ResMap{nil, merged}
|
w = makeMap1()
|
||||||
merged2, err := MergeWithOverride(input4...)
|
w2 := makeMap2(types.BehaviorReplace)
|
||||||
if err != nil {
|
if err := w.AbsorbAll(w2); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
err = expected.ErrorIfNotEqual(merged2)
|
if err := w2.ErrorIfNotEqual(w); err != nil {
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
inputs := generateMergeFixtures(types.BehaviorReplace)
|
w = makeMap1()
|
||||||
replaced, err := MergeWithOverride(inputs...)
|
w2 = makeMap2(types.BehaviorUnspecified)
|
||||||
if err != nil {
|
err := w.AbsorbAll(w2)
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
expectedReplaced := inputs[1]
|
|
||||||
err = expectedReplaced.ErrorIfNotEqual(replaced)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
_, err = MergeWithOverride(generateMergeFixtures(types.BehaviorUnspecified)...)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Merging with GenerationBehavior BehaviorUnspecified should return an error but does not")
|
t.Fatalf("expected error with unspecified behavior")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ func (kt *KustTarget) runGenerators(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// The legacy generators allow override.
|
// The legacy generators allow override.
|
||||||
err = ra.MergeResourcesWithOverride(resMap)
|
err = ra.AbsorbAll(resMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "merging from generator %v", g)
|
return errors.Wrapf(err, "merging from generator %v", g)
|
||||||
}
|
}
|
||||||
@@ -277,7 +277,7 @@ func (kt *KustTarget) runGenerators(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ra.MergeResourcesWithErrorOnIdCollision(resMap)
|
err = ra.AppendAll(resMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "merging from generator %v", g)
|
return errors.Wrapf(err, "merging from generator %v", g)
|
||||||
}
|
}
|
||||||
@@ -380,7 +380,7 @@ func (kt *KustTarget) accumulateFile(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "accumulating resources from '%s'", path)
|
return errors.Wrapf(err, "accumulating resources from '%s'", path)
|
||||||
}
|
}
|
||||||
err = ra.MergeResourcesWithErrorOnIdCollision(resources)
|
err = ra.AppendAll(resources)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "merging resources from '%s'", path)
|
return errors.Wrapf(err, "merging resources from '%s'", path)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/pkg/kusttest"
|
"sigs.k8s.io/kustomize/pkg/kusttest"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||||
"sigs.k8s.io/kustomize/plugin"
|
"sigs.k8s.io/kustomize/plugin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ kind: PrintWorkDir
|
|||||||
metadata:
|
metadata:
|
||||||
name: whatever
|
name: whatever
|
||||||
`)
|
`)
|
||||||
a, err := m.EncodeAsYaml()
|
a, err := m.AsYaml(resmap.Identity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user