Refactored resource to store all previous names and namespaces

This commit is contained in:
Natasha Sarkar
2021-02-01 14:50:20 -08:00
parent 6246262965
commit f71854a0c8
23 changed files with 376 additions and 442 deletions

View File

@@ -47,7 +47,7 @@ func (m *merginator) ConflatePatches(in []*resource.Resource) (ResMap, error) {
func (m *merginator) appendIfNoMatch(index int) (*resource.Resource, error) {
candidate := m.incoming[index]
matchedResources := m.result.GetMatchingResourcesByOriginalId(
matchedResources := m.result.GetMatchingResourcesByAnyId(
candidate.OrgId().Equals)
if len(matchedResources) == 0 {
m.result.Append(candidate)

View File

@@ -142,24 +142,18 @@ type ResMap interface {
// who's CurId is matched by the argument.
GetMatchingResourcesByCurrentId(matches IdMatcher) []*resource.Resource
// GetMatchingResourcesByOriginalId returns the resources
// who's OriginalId is matched by the argument.
GetMatchingResourcesByOriginalId(matches IdMatcher) []*resource.Resource
// GetMatchingResourcesByAnyId returns the resources
// who's current or previous IDs is matched by the argument.
GetMatchingResourcesByAnyId(matches IdMatcher) []*resource.Resource
// GetByCurrentId is shorthand for calling
// GetMatchingResourcesByCurrentId with a matcher requiring
// an exact match, returning an error on multiple or no matches.
GetByCurrentId(resid.ResId) (*resource.Resource, error)
// GetByOriginalId is shorthand for calling
// GetMatchingResourcesByOriginalId with a matcher requiring
// GetByPreviousId is shorthand for calling
// GetMatchingResourcesByAnyId with a matcher requiring
// an exact match, returning an error on multiple or no matches.
GetByOriginalId(resid.ResId) (*resource.Resource, error)
// GetById is a helper function which first
// attempts GetByOriginalId, then GetByCurrentId,
// returning an error if both fail to find a single
// match.
GetById(resid.ResId) (*resource.Resource, error)
// GroupedByCurrentNamespace returns a map of namespace

View File

@@ -155,8 +155,7 @@ func (m *resWrangler) GetIndexOfCurrentId(id resid.ResId) (int, error) {
type IdFromResource func(r *resource.Resource) resid.ResId
func GetOriginalId(r *resource.Resource) resid.ResId { return r.OrgId() }
func GetCurrentId(r *resource.Resource) resid.ResId { return r.CurId() }
func GetCurrentId(r *resource.Resource) resid.ResId { return r.CurId() }
// GetMatchingResourcesByCurrentId implements ResMap.
func (m *resWrangler) GetMatchingResourcesByCurrentId(
@@ -164,10 +163,21 @@ func (m *resWrangler) GetMatchingResourcesByCurrentId(
return m.filteredById(matches, GetCurrentId)
}
// GetMatchingResourcesByOriginalId implements ResMap.
func (m *resWrangler) GetMatchingResourcesByOriginalId(
// GetMatchingResourcesByAnyId implements ResMap.
func (m *resWrangler) GetMatchingResourcesByAnyId(
matches IdMatcher) []*resource.Resource {
return m.filteredById(matches, GetOriginalId)
var result []*resource.Resource
for _, r := range m.rList {
prevIds := r.PrevIds()
prevIds = append(prevIds, r.CurId())
for _, prevId := range prevIds {
if matches(prevId) {
result = append(result, r)
break
}
}
}
return result
}
func (m *resWrangler) filteredById(
@@ -187,26 +197,16 @@ func (m *resWrangler) GetByCurrentId(
return demandOneMatch(m.GetMatchingResourcesByCurrentId, id, "Current")
}
// GetByOriginalId implements ResMap.
func (m *resWrangler) GetByOriginalId(
id resid.ResId) (*resource.Resource, error) {
return demandOneMatch(m.GetMatchingResourcesByOriginalId, id, "Original")
}
// GetById implements ResMap.
func (m *resWrangler) GetById(
id resid.ResId) (*resource.Resource, error) {
match, err1 := m.GetByOriginalId(id)
if err1 == nil {
return match, nil
r, err := demandOneMatch(m.GetMatchingResourcesByAnyId, id, "Id")
if err != nil {
return nil, fmt.Errorf(
"%s; failed to find unique target for patch %s",
err.Error(), id.GvknString())
}
match, err2 := m.GetByCurrentId(id)
if err2 == nil {
return match, nil
}
return nil, fmt.Errorf(
"%s; %s; failed to find unique target for patch %s",
err1.Error(), err2.Error(), id.GvknString())
return r, nil
}
type resFinder func(IdMatcher) []*resource.Resource
@@ -465,10 +465,7 @@ func (m *resWrangler) AbsorbAll(other ResMap) error {
func (m *resWrangler) appendReplaceOrMerge(res *resource.Resource) error {
id := res.CurId()
matches := m.GetMatchingResourcesByOriginalId(id.Equals)
if len(matches) == 0 {
matches = m.GetMatchingResourcesByCurrentId(id.Equals)
}
matches := m.GetMatchingResourcesByAnyId(id.Equals)
switch len(matches) {
case 0:
switch res.Behavior() {
@@ -593,10 +590,8 @@ func (m *resWrangler) ApplySmPatch(
continue
}
patchCopy := patch.DeepCopy()
patchCopy.SetName(res.GetName())
patchCopy.SetNamespace(res.GetNamespace())
patchCopy.CopyMergeMetaDataFieldsFrom(patch)
patchCopy.SetGvk(res.GetGvk())
patchCopy.SetOriginalName(res.GetOriginalName(), true)
err := res.ApplySmPatch(patchCopy)
if err != nil {
// Check for an error string from UnmarshalJSON that's indicative

View File

@@ -331,6 +331,134 @@ func TestGetMatchingResourcesByCurrentId(t *testing.T) {
}
}
func TestGetMatchingResourcesByPreviousId(t *testing.T) {
r1 := rf.FromMap(
map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "new-alice",
"annotations": map[string]interface{}{
"config.kubernetes.io/originalName": "alice",
"config.kubernetes.io/originalNs": "default",
},
},
})
r2 := rf.FromMap(
map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "new-bob",
"annotations": map[string]interface{}{
"config.kubernetes.io/originalName": "bob,bob2",
"config.kubernetes.io/originalNs": "default,default",
},
},
})
r3 := rf.FromMap(
map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "new-bob",
"namespace": "new-happy",
"annotations": map[string]interface{}{
"config.kubernetes.io/originalName": "bob",
"config.kubernetes.io/originalNs": "happy",
},
},
})
r4 := rf.FromMap(
map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "charlie",
"namespace": "happy",
"annotations": map[string]interface{}{
"config.kubernetes.io/originalName": "charlie",
"config.kubernetes.io/originalNs": "default",
},
},
})
r5 := rf.FromMap(
map[string]interface{}{
"apiVersion": "v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "charlie",
"namespace": "happy",
},
})
m := resmaptest_test.NewRmBuilder(t, rf).
AddR(r1).AddR(r2).AddR(r3).AddR(r4).AddR(r5).ResMap()
// nolint:goconst
tests := []struct {
name string
matcher IdMatcher
count int
}{
{
"match everything",
func(resid.ResId) bool { return true },
5,
},
{
"match nothing",
func(resid.ResId) bool { return false },
0,
},
{
"name is alice",
func(x resid.ResId) bool { return x.Name == "alice" },
1,
},
{
"name is charlie",
func(x resid.ResId) bool { return x.Name == "charlie" },
2,
},
{
"name is bob",
func(x resid.ResId) bool { return x.Name == "bob" },
2,
},
{
"happy namespace",
func(x resid.ResId) bool {
return x.Namespace == "happy"
},
3,
},
{
"happy deployment",
func(x resid.ResId) bool {
return x.Namespace == "happy" &&
x.Gvk.Kind == "Deployment"
},
1,
},
{
"happy ConfigMap",
func(x resid.ResId) bool {
return x.Namespace == "happy" &&
x.Gvk.Kind == "ConfigMap"
},
2,
},
}
for _, tst := range tests {
result := m.GetMatchingResourcesByAnyId(tst.matcher)
if len(result) != tst.count {
t.Fatalf("test '%s'; actual: %d, expected: %d",
tst.name, len(result), tst.count)
}
}
}
func TestSubsetThatCouldBeReferencedByResource(t *testing.T) {
r1 := rf.FromMap(
map[string]interface{}{