Skip to content

Commit

Permalink
Improve NameReference Test cases
Browse files Browse the repository at this point in the history
- Add more NameReference Namespace tests
- Address issue when mixing empty/no namespace and default namespace.
- Address ClusterRoleBinding subjects field pointing at multiple namespaces.
  • Loading branch information
jbrette committed Jul 16, 2019
1 parent 7998ee7 commit c4d899f
Show file tree
Hide file tree
Showing 6 changed files with 417 additions and 47 deletions.
8 changes: 8 additions & 0 deletions pkg/resmaptest/rmbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ func (rm *rmBuilder) AddWithNs(ns string, m map[string]interface{}) *rmBuilder {
return rm
}

func (rm *rmBuilder) AddWithNsAndName(ns string, n string, m map[string]interface{}) *rmBuilder {
err := rm.m.Append(rm.rf.FromMapWithNamespaceAndName(ns, n, m))
if err != nil {
rm.t.Fatalf("test setup failure: %v", err)
}
return rm
}

func (rm *rmBuilder) ReplaceResource(m map[string]interface{}) *rmBuilder {
r := rm.rf.FromMap(m)
_, err := rm.m.Replace(r)
Expand Down
5 changes: 5 additions & 0 deletions pkg/resource/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ func (rf *Factory) FromMapWithNamespace(n string, m map[string]interface{}) *Res
return rf.makeOne(rf.kf.FromMap(m), nil).setOriginalNs(n)
}

// FromMapWithNamespaceAndName returns a new instance with the given "original" namespace.
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)
}

// FromMapAndOption returns a new instance of Resource with given options.
func (rf *Factory) FromMapAndOption(
m map[string]interface{}, args *types.GeneratorArgs, option *types.GeneratorOptions) *Resource {
Expand Down
2 changes: 1 addition & 1 deletion pkg/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func (r *Resource) GetOutermostNameSuffix() string {
}

func (r *Resource) InSameFuzzyNamespace(o *Resource) bool {
return r.GetNamespace() == o.GetNamespace() &&
return r.CurId().IsNsEquals(o.CurId()) &&
r.GetOutermostNamePrefix() == o.GetOutermostNamePrefix() &&
r.GetOutermostNameSuffix() == o.GetOutermostNameSuffix()
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/transformers/config/defaultconfig/namereference.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,10 @@ nameReference:
- kind: ServiceAccount
version: v1
fieldSpecs:
- path: subjects/name
- path: subjects
kind: RoleBinding
group: rbac.authorization.k8s.io
- path: subjects/name
- path: subjects
kind: ClusterRoleBinding
group: rbac.authorization.k8s.io
- path: spec/serviceAccountName
Expand Down
138 changes: 96 additions & 42 deletions pkg/transformers/namereference.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,77 @@ func (o *nameReferenceTransformer) Transform(m resmap.ResMap) error {
return nil
}

// utility function to replace a simple string by the new name
func (o *nameReferenceTransformer) mapSimpleNameField(
oldName string,
referrer *resource.Resource,
target gvk.Gvk,
referralCandidates resmap.ResMap,
referralCandidateSubset []*resource.Resource) (interface{}, error) {

for _, res := range referralCandidateSubset {
id := res.OrgId()
if id.IsSelected(&target) && res.GetOriginalName() == oldName {
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.Equals)
// If there's more than one match, there's no way
// to know which one to pick, so emit error.
if len(matches) > 1 {
return nil, fmt.Errorf(
"string case - multiple matches for %s:\n %v",
id, getIds(matches))
}
// In the resource, note that it is referenced
// by the referrer.
res.AppendRefBy(referrer.CurId())
// Return transformed name of the object,
// complete with prefixes, hashes, etc.
return res.GetName(), nil
}
}

return oldName, nil
}

// utility function to replace name field within a map[string]interface{}
// and leverage the namespace field.
func (o *nameReferenceTransformer) mapNameAndNsStruct(
inMap map[string]interface{},
referrer *resource.Resource,
target gvk.Gvk,
referralCandidates resmap.ResMap) (interface{}, error) {

// Example:
if _, ok := inMap["name"]; !ok {
return nil, fmt.Errorf(
"%#v is expected to contain a name field", inMap)
}
oldName, ok := inMap["name"].(string)
if !ok {
return nil, fmt.Errorf(
"%#v is expected to contain a name field of type string", oldName)
}

subset := referralCandidates.Resources()
if namespacevalue, ok := inMap["namespace"]; ok {
namespace := namespacevalue.(string)
bynamespace := referralCandidates.GroupedByNamespace()
if _, ok := bynamespace[namespace]; !ok {
return inMap, nil
}
subset = bynamespace[namespace]
}

newname, err := o.mapSimpleNameField(oldName, referrer, target,
referralCandidates, subset)
if err != nil {
return nil, err
}

inMap["name"] = newname
return inMap, nil

}

func (o *nameReferenceTransformer) getNewNameFunc(
referrer *resource.Resource,
target gvk.Gvk,
Expand All @@ -114,52 +185,35 @@ func (o *nameReferenceTransformer) getNewNameFunc(
switch in.(type) {
case string:
oldName, _ := in.(string)
for _, res := range referralCandidates.Resources() {
id := res.OrgId()
if id.IsSelected(&target) && res.GetOriginalName() == oldName {
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.Equals)
// If there's more than one match, there's no way
// to know which one to pick, so emit error.
if len(matches) > 1 {
return nil, fmt.Errorf(
"string case - multiple matches for %s:\n %v",
id, getIds(matches))
}
// In the resource, note that it is referenced
// by the referrer.
res.AppendRefBy(referrer.CurId())
// Return transformed name of the object,
// complete with prefixes, hashes, etc.
return res.GetName(), nil
}
}
return in, nil
return o.mapSimpleNameField(oldName, referrer, target,
referralCandidates, referralCandidates.Resources())
case []interface{}:
l, _ := in.([]interface{})
var names []string
for _, item := range l {
name, ok := item.(string)
if !ok {
return nil, fmt.Errorf(
"%#v is expected to be %T", item, name)
}
names = append(names, name)
}
for _, res := range referralCandidates.Resources() {
indexes := indexOf(res.GetOriginalName(), names)
id := res.OrgId()
if id.IsSelected(&target) && len(indexes) > 0 {
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.Equals)
if len(matches) > 1 {
return nil, fmt.Errorf(
"slice case - multiple matches for %s:\n %v",
id, getIds(matches))
for idx, item := range l {
switch item.(type) {
case string:
// Kind: Role/ClusterRole
// FieldSpec is rules.resourceNames
oldName, _ := item.(string)
newName, err := o.mapSimpleNameField(oldName, referrer, target,
referralCandidates, referralCandidates.Resources())
if err != nil {
return nil, err
}
for _, index := range indexes {
l[index] = res.GetName()
l[idx] = newName
case map[string]interface{}:
// Kind: RoleBinding/ClusterRoleBinding
// FieldSpec is subjects
oldMap, _ := item.(map[string]interface{})
newMap, err := o.mapNameAndNsStruct(oldMap, referrer, target,
referralCandidates)
if err != nil {
return nil, err
}
res.AppendRefBy(referrer.CurId())
return l, nil
l[idx] = newMap
default:
return nil, fmt.Errorf(
"%#v is expected to be either a []string or a []map[string]interface{}", in)
}
}
return in, nil
Expand Down

0 comments on commit c4d899f

Please sign in to comment.