Handle arb length paths in GetFieldName

This commit is contained in:
Jeffrey Regan
2018-06-08 15:07:57 -07:00
parent 7c4ca21578
commit de65503177
3 changed files with 46 additions and 39 deletions

View File

@@ -22,7 +22,6 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/golang/glog" "github.com/golang/glog"
@@ -316,10 +315,9 @@ func (a *applicationImpl) resolveRefVars(resources resmap.ResMap) (map[string]st
} }
for _, refvar := range vars { for _, refvar := range vars {
refGVKN := resource.NewResId(refvar.ObjRef.GroupVersionKind(), refvar.ObjRef.Name) id := resource.NewResId(refvar.ObjRef.GroupVersionKind(), refvar.ObjRef.Name)
if r, found := resources[refGVKN]; found { if r, found := resources[id]; found {
s, err := resource.GetFieldValue( s, err := r.GetFieldValue(refvar.FieldRef.FieldPath)
r.UnstructuredContent(), strings.Split(refvar.FieldRef.FieldPath, "."))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to resolve referred var: %+v", refvar) return nil, fmt.Errorf("failed to resolve referred var: %+v", refvar)
} }

View File

@@ -21,6 +21,8 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
@@ -49,6 +51,13 @@ func NewBehaviorlessResource(u *unstructured.Unstructured) *Resource {
return &Resource{Unstructured: *u, b: BehaviorUnspecified} return &Resource{Unstructured: *u, b: BehaviorUnspecified}
} }
// NewResource returns a new instance of Resource.
func NewResource(m map[string]interface{}) *Resource {
return &Resource{
Unstructured: unstructured.Unstructured{Object: m},
b: BehaviorUnspecified}
}
// Behavior returns the behavior for the resource. // Behavior returns the behavior for the resource.
func (r *Resource) Behavior() GenerationBehavior { func (r *Resource) Behavior() GenerationBehavior {
return r.b return r.b
@@ -94,21 +103,14 @@ func mergeStringMaps(maps ...map[string]string) map[string]string {
return result return result
} }
func newUnstructuredFromObject(in runtime.Object) (*unstructured.Unstructured, error) { func (r *Resource) GetFieldValue(fieldPath string) (string, error) {
marshaled, err := json.Marshal(in) return getFieldValue(r.UnstructuredContent(), strings.Split(fieldPath, "."))
if err != nil {
return nil, err
}
var out unstructured.Unstructured
err = out.UnmarshalJSON(marshaled)
return &out, err
} }
func GetFieldValue(m map[string]interface{}, pathToField []string) (string, error) { func getFieldValue(m map[string]interface{}, pathToField []string) (string, error) {
if len(pathToField) == 0 { if len(pathToField) == 0 {
return "", fmt.Errorf("Field not found") return "", fmt.Errorf("Field not found")
} }
if len(pathToField) == 1 { if len(pathToField) == 1 {
if v, found := m[pathToField[0]]; found { if v, found := m[pathToField[0]]; found {
if s, ok := v.(string); ok { if s, ok := v.(string); ok {
@@ -118,13 +120,10 @@ func GetFieldValue(m map[string]interface{}, pathToField []string) (string, erro
} }
return "", fmt.Errorf("field at given fieldpath does not exist") return "", fmt.Errorf("field at given fieldpath does not exist")
} }
v := m[pathToField[0]]
curr, rest := pathToField[0], pathToField[1]
v := m[curr]
switch typedV := v.(type) { switch typedV := v.(type) {
case map[string]interface{}: case map[string]interface{}:
return GetFieldValue(typedV, []string{rest}) return getFieldValue(typedV, pathToField[1:])
default: default:
return "", fmt.Errorf("%#v is not expected to be a primitive type", typedV) return "", fmt.Errorf("%#v is not expected to be a primitive type", typedV)
} }

View File

@@ -20,8 +20,8 @@ import (
"testing" "testing"
) )
func TestGetFieldAsString(t *testing.T) { func TestGetFieldValue(t *testing.T) {
m := map[string]interface{}{ res := NewResource(map[string]interface{}{
"Kind": "Service", "Kind": "Service",
"metadata": map[string]interface{}{ "metadata": map[string]interface{}{
"labels": map[string]string{ "labels": map[string]string{
@@ -29,37 +29,47 @@ func TestGetFieldAsString(t *testing.T) {
}, },
"name": "service-name", "name": "service-name",
}, },
} "spec": map[string]interface{}{
"ports": map[string]interface{}{
"port": "80",
},
},
})
tests := []struct { tests := []struct {
pathToField []string pathToField string
expectedName string expectedValue string
expectedError bool errorExpected bool
}{ }{
{ {
pathToField: []string{"Kind"}, pathToField: "Kind",
expectedName: "Service", expectedValue: "Service",
expectedError: false, errorExpected: false,
}, },
{ {
pathToField: []string{"metadata", "name"}, pathToField: "metadata.name",
expectedName: "service-name", expectedValue: "service-name",
expectedError: false, errorExpected: false,
}, },
{ {
pathToField: []string{"metadata", "non-existing-field"}, pathToField: "metadata.non-existing-field",
expectedName: "", expectedValue: "",
expectedError: true, errorExpected: true,
},
{
pathToField: "spec.ports.port",
expectedValue: "80",
errorExpected: false,
}, },
} }
for _, test := range tests { for _, test := range tests {
s, err := GetFieldValue(m, test.pathToField) s, err := res.GetFieldValue(test.pathToField)
if test.expectedError && err == nil { if test.errorExpected && err == nil {
t.Fatalf("should return error, but no error returned") t.Fatalf("should return error, but no error returned")
} else { } else {
if test.expectedName != s { if test.expectedValue != s {
t.Fatalf("Got:%s expected:%s", s, test.expectedName) t.Fatalf("Got:%s expected:%s", s, test.expectedValue)
} }
} }
} }