Unstructured cleanups

This commit is contained in:
Mikhail Mazurskiy 2017-11-19 19:12:26 +11:00
parent d52d160239
commit 160cf97fa4
No known key found for this signature in database
GPG Key ID: 93551ECC96E2F568
2 changed files with 42 additions and 65 deletions

View File

@ -138,11 +138,10 @@ func NestedSlice(obj map[string]interface{}, fields ...string) ([]interface{}, b
// NestedStringMap returns a copy of map[string]string value of a nested field. // NestedStringMap returns a copy of map[string]string value of a nested field.
// Returns false if value is not found, is not a map[string]interface{} or contains non-string values in the map. // Returns false if value is not found, is not a map[string]interface{} or contains non-string values in the map.
func NestedStringMap(obj map[string]interface{}, fields ...string) (map[string]string, bool) { func NestedStringMap(obj map[string]interface{}, fields ...string) (map[string]string, bool) {
val, ok := nestedFieldNoCopy(obj, fields...) m, ok := nestedMapNoCopy(obj, fields...)
if !ok { if !ok {
return nil, false return nil, false
} }
if m, ok := val.(map[string]interface{}); ok {
strMap := make(map[string]string, len(m)) strMap := make(map[string]string, len(m))
for k, v := range m { for k, v := range m {
if str, ok := v.(string); ok { if str, ok := v.(string); ok {
@ -153,20 +152,26 @@ func NestedStringMap(obj map[string]interface{}, fields ...string) (map[string]s
} }
return strMap, true return strMap, true
} }
return nil, false
}
// NestedMap returns a deep copy of map[string]interface{} value of a nested field. // NestedMap returns a deep copy of map[string]interface{} value of a nested field.
// Returns false if value is not found or is not a map[string]interface{}. // Returns false if value is not found or is not a map[string]interface{}.
func NestedMap(obj map[string]interface{}, fields ...string) (map[string]interface{}, bool) { func NestedMap(obj map[string]interface{}, fields ...string) (map[string]interface{}, bool) {
m, ok := nestedMapNoCopy(obj, fields...)
if !ok {
return nil, false
}
return runtime.DeepCopyJSON(m), true
}
// nestedMapNoCopy returns a map[string]interface{} value of a nested field.
// Returns false if value is not found or is not a map[string]interface{}.
func nestedMapNoCopy(obj map[string]interface{}, fields ...string) (map[string]interface{}, bool) {
val, ok := nestedFieldNoCopy(obj, fields...) val, ok := nestedFieldNoCopy(obj, fields...)
if !ok { if !ok {
return nil, false return nil, false
} }
if m, ok := val.(map[string]interface{}); ok { m, ok := val.(map[string]interface{})
return runtime.DeepCopyJSON(m), true return m, ok
}
return nil, false
} }
// SetNestedField sets the value of a nested field to a deep copy of the value provided. // SetNestedField sets the value of a nested field to a deep copy of the value provided.
@ -268,25 +273,6 @@ func extractOwnerReference(v map[string]interface{}) metav1.OwnerReference {
} }
} }
func setOwnerReference(src metav1.OwnerReference) map[string]interface{} {
ret := map[string]interface{}{
"kind": src.Kind,
"name": src.Name,
"apiVersion": src.APIVersion,
"uid": string(src.UID),
}
// json.Unmarshal() extracts boolean json fields as bool, not as *bool and hence extractOwnerReference()
// expects bool or a missing field, not *bool. So if pointer is nil, fields are omitted from the ret object.
// If pointer is non-nil, they are set to the referenced value.
if src.Controller != nil {
ret["controller"] = *src.Controller
}
if src.BlockOwnerDeletion != nil {
ret["blockOwnerDeletion"] = *src.BlockOwnerDeletion
}
return ret
}
// UnstructuredJSONScheme is capable of converting JSON data into the Unstructured // UnstructuredJSONScheme is capable of converting JSON data into the Unstructured
// type, which can be used for generic access to objects without a predefined scheme. // type, which can be used for generic access to objects without a predefined scheme.
// TODO: move into serializer/json. // TODO: move into serializer/json.
@ -444,7 +430,7 @@ func (UnstructuredObjectConverter) Convert(in, out, context interface{}) error {
// maybe deep copy the map? It is documented in the // maybe deep copy the map? It is documented in the
// ObjectConverter interface that this function is not // ObjectConverter interface that this function is not
// guaranteeed to not mutate the input. Or maybe set the input // guaranteed to not mutate the input. Or maybe set the input
// object to nil. // object to nil.
unstructOut.Object = unstructIn.Object unstructOut.Object = unstructIn.Object
return nil return nil

View File

@ -18,6 +18,7 @@ package unstructured
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -50,29 +51,27 @@ var _ runtime.Unstructured = &Unstructured{}
func (obj *Unstructured) GetObjectKind() schema.ObjectKind { return obj } func (obj *Unstructured) GetObjectKind() schema.ObjectKind { return obj }
func (obj *Unstructured) IsList() bool { func (obj *Unstructured) IsList() bool {
if obj.Object != nil { field, ok := obj.Object["items"]
_, ok := obj.Object["items"] if !ok {
return ok
}
return false return false
} }
_, ok = field.([]interface{})
return ok
}
func (obj *Unstructured) EachListItem(fn func(runtime.Object) error) error { func (obj *Unstructured) EachListItem(fn func(runtime.Object) error) error {
if obj.Object == nil {
return fmt.Errorf("content is not a list")
}
field, ok := obj.Object["items"] field, ok := obj.Object["items"]
if !ok { if !ok {
return fmt.Errorf("content is not a list") return errors.New("content is not a list")
} }
items, ok := field.([]interface{}) items, ok := field.([]interface{})
if !ok { if !ok {
return nil return fmt.Errorf("content is not a list: %T", field)
} }
for _, item := range items { for _, item := range items {
child, ok := item.(map[string]interface{}) child, ok := item.(map[string]interface{})
if !ok { if !ok {
return fmt.Errorf("items member is not an object") return fmt.Errorf("items member is not an object: %T", child)
} }
if err := fn(&Unstructured{Object: child}); err != nil { if err := fn(&Unstructured{Object: child}); err != nil {
return err return err
@ -162,7 +161,12 @@ func (u *Unstructured) GetOwnerReferences() []metav1.OwnerReference {
func (u *Unstructured) SetOwnerReferences(references []metav1.OwnerReference) { func (u *Unstructured) SetOwnerReferences(references []metav1.OwnerReference) {
newReferences := make([]interface{}, 0, len(references)) newReferences := make([]interface{}, 0, len(references))
for _, reference := range references { for _, reference := range references {
newReferences = append(newReferences, setOwnerReference(reference)) out, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&reference)
if err != nil {
utilruntime.HandleError(fmt.Errorf("unable to convert Owner Reference: %v", err))
continue
}
newReferences = append(newReferences, out)
} }
u.setNestedField(newReferences, "metadata", "ownerReferences") u.setNestedField(newReferences, "metadata", "ownerReferences")
} }
@ -301,10 +305,7 @@ func (u *Unstructured) SetDeletionGracePeriodSeconds(deletionGracePeriodSeconds
} }
func (u *Unstructured) GetLabels() map[string]string { func (u *Unstructured) GetLabels() map[string]string {
m, ok := NestedStringMap(u.Object, "metadata", "labels") m, _ := NestedStringMap(u.Object, "metadata", "labels")
if !ok {
return nil
}
return m return m
} }
@ -313,10 +314,7 @@ func (u *Unstructured) SetLabels(labels map[string]string) {
} }
func (u *Unstructured) GetAnnotations() map[string]string { func (u *Unstructured) GetAnnotations() map[string]string {
m, ok := NestedStringMap(u.Object, "metadata", "annotations") m, _ := NestedStringMap(u.Object, "metadata", "annotations")
if !ok {
return nil
}
return m return m
} }
@ -339,18 +337,14 @@ func (u *Unstructured) GroupVersionKind() schema.GroupVersionKind {
} }
func (u *Unstructured) GetInitializers() *metav1.Initializers { func (u *Unstructured) GetInitializers() *metav1.Initializers {
field, ok := nestedFieldNoCopy(u.Object, "metadata", "initializers") m, ok := nestedMapNoCopy(u.Object, "metadata", "initializers")
if !ok { if !ok {
return nil return nil
} }
obj, ok := field.(map[string]interface{})
if !ok {
// expected map[string]interface{}, got something else
return nil
}
out := &metav1.Initializers{} out := &metav1.Initializers{}
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj, out); err != nil { if err := runtime.DefaultUnstructuredConverter.FromUnstructured(m, out); err != nil {
utilruntime.HandleError(fmt.Errorf("unable to retrieve initializers for object: %v", err)) utilruntime.HandleError(fmt.Errorf("unable to retrieve initializers for object: %v", err))
return nil
} }
return out return out
} }
@ -368,10 +362,7 @@ func (u *Unstructured) SetInitializers(initializers *metav1.Initializers) {
} }
func (u *Unstructured) GetFinalizers() []string { func (u *Unstructured) GetFinalizers() []string {
val, ok := NestedStringSlice(u.Object, "metadata", "finalizers") val, _ := NestedStringSlice(u.Object, "metadata", "finalizers")
if !ok {
return nil
}
return val return val
} }