Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 Set name of namespace in namespace decorator #440

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 23 additions & 28 deletions pkg/addon/templateagent/decorator.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ type namespaceDecorator struct {
installNamespace string
// paths is the paths of a resource kind that the decorator needs to set namespace field in it.
// if the returned object is a list, decorator will set namespace for each item.
paths map[string]string
paths map[string][]string
}

func newNamespaceDecorator(privateValues addonfactory.Values) *namespaceDecorator {
decorator := &namespaceDecorator{
paths: map[string]string{
"ClusterRoleBinding": "subjects",
"RoleBinding": "subjects",
paths: map[string][]string{
"ClusterRoleBinding": {"subjects", "namespace"},
"RoleBinding": {"subjects", "namespace"},
"Namespace": {"metadata", "name"},
},
}
namespace, ok := privateValues[InstallNamespacePrivateValueKey]
Expand All @@ -49,41 +50,35 @@ func (d *namespaceDecorator) decorate(obj *unstructured.Unstructured) (*unstruct
// being applied.
obj.SetNamespace(d.installNamespace)

path, ok := d.paths[obj.GetKind()]
paths, ok := d.paths[obj.GetKind()]
if !ok {
return obj, nil
}

field, found, err := unstructured.NestedFieldNoCopy(obj.Object, path)
if err != nil {
return obj, err
}
if !found {
return obj, fmt.Errorf("failed to find the path %s for kind %s", path, obj.GetKind())
}
err := setUnstructuredNestedField(obj.Object, d.installNamespace, paths)
return obj, err
}

// it cannot supported nested structure, only list or map.
switch f := field.(type) {
// search the object to set the val, if an array is found, find every item in the array.
func setUnstructuredNestedField(obj interface{}, val string, paths []string) error {
switch f := obj.(type) {
case []interface{}:
for _, item := range f {
if err := setNamespaceForObject(item, d.installNamespace); err != nil {
return obj, err
if err := setUnstructuredNestedField(item, val, paths); err != nil {
return err
}
}
case interface{}:
if err := setNamespaceForObject(f, d.installNamespace); err != nil {
return obj, err
case map[string]interface{}:
if len(paths) == 1 {
f[paths[0]] = val
return nil
}
field, ok := f[paths[0]]
if !ok {
return fmt.Errorf("failed to find field %s", paths[0])
}
return setUnstructuredNestedField(field, val, paths[1:])
}
return obj, nil
}

func setNamespaceForObject(obj interface{}, namespace string) error {
mapVal, ok := obj.(map[string]interface{})
if !ok {
return fmt.Errorf("obj %v is not a map, cannot set", obj)
}
mapVal["namespace"] = namespace
return nil
}

Expand Down
27 changes: 27 additions & 0 deletions pkg/addon/templateagent/decorator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package templateagent
import (
"testing"

corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
Expand Down Expand Up @@ -113,6 +114,32 @@ func TestNamespaceDecorator(t *testing.T) {
}
},
},
{
name: "namespace",
object: func() *unstructured.Unstructured {
ns := &corev1.Namespace{
TypeMeta: metav1.TypeMeta{
Kind: "Namespace",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
}
data, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(ns)
return &unstructured.Unstructured{Object: data}
}(),
namespace: "newns",
validateObject: func(t *testing.T, obj *unstructured.Unstructured) {
ns := &corev1.Namespace{}
err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, ns)
if err != nil {
t.Fatal(err)
}
if ns.Name != "newns" {
t.Errorf("name of namespace is not correct, got %v", ns.Name)
}
},
},
}

for _, tc := range tests {
Expand Down
Loading