1/* 2Copyright 2019 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package defaulting 18 19import ( 20 "fmt" 21 22 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23) 24 25// AccessorFunc returns a node x in obj on a fixed (implicitly encoded) JSON path 26// if that path exists in obj (found==true). If it does not exist, found is false. 27// If on the path the type of a field is wrong, an error is returned. 28type AccessorFunc func(obj map[string]interface{}) (x interface{}, found bool, err error) 29 30// SurroundingObjectFunc is a surrounding object builder with a given x at a leaf. 31// Which leave is determined by the series of Index() and Child(k) calls. 32// It also returns the inverse of the builder, namely the accessor that extracts x 33// from the test object. 34// 35// With obj, acc, _ := someSurroundingObjectFunc(x) we get: 36// 37// acc(obj) == x 38// reflect.DeepEqual(acc(DeepCopy(obj), x) == x 39// 40// where x is the original instance for slices and maps. 41// 42// If after computation of acc the node holding x in obj is mutated (e.g. pruned), 43// the accessor will return that mutated node value (e.g. the pruned x). 44// 45// Example (ignoring the last two return values): 46// 47// NewRootObjectFunc()(x) == x 48// NewRootObjectFunc().Index()(x) == [x] 49// NewRootObjectFunc().Index().Child("foo") == [{"foo": x}] 50// NewRootObjectFunc().Index().Child("foo").Child("bar") == [{"foo": {"bar":x}}] 51// NewRootObjectFunc().Index().Child("foo").Child("bar").Index() == [{"foo": {"bar":[x]}}] 52// 53// and: 54// 55// NewRootObjectFunc(), then acc(x) == x 56// NewRootObjectFunc().Index(), then acc([x]) == x 57// NewRootObjectFunc().Index().Child("foo"), then acc([{"foo": x}]) == x 58// NewRootObjectFunc().Index().Child("foo").Child("bar"), then acc([{"foo": {"bar":x}}]) == x 59// NewRootObjectFunc().Index().Child("foo").Child("bar").Index(), then acc([{"foo": {"bar":[x]}}]) == x 60type SurroundingObjectFunc func(focus interface{}) (map[string]interface{}, AccessorFunc, error) 61 62// NewRootObjectFunc returns the identity function. The passed focus value 63// must be an object. 64func NewRootObjectFunc() SurroundingObjectFunc { 65 return func(x interface{}) (map[string]interface{}, AccessorFunc, error) { 66 obj, ok := x.(map[string]interface{}) 67 if !ok { 68 return nil, nil, fmt.Errorf("object root default value must be of object type") 69 } 70 return obj, func(root map[string]interface{}) (interface{}, bool, error) { 71 return root, true, nil 72 }, nil 73 } 74} 75 76// WithTypeMeta returns a closure with the TypeMeta fields set if they are defined. 77// This mutates f(x). 78func (f SurroundingObjectFunc) WithTypeMeta(meta metav1.TypeMeta) SurroundingObjectFunc { 79 return func(x interface{}) (map[string]interface{}, AccessorFunc, error) { 80 obj, acc, err := f(x) 81 if err != nil { 82 return nil, nil, err 83 } 84 if obj == nil { 85 obj = map[string]interface{}{} 86 } 87 if _, found := obj["kind"]; !found { 88 obj["kind"] = meta.Kind 89 } 90 if _, found := obj["apiVersion"]; !found { 91 obj["apiVersion"] = meta.APIVersion 92 } 93 return obj, acc, err 94 } 95} 96 97// Child returns a function x => f({k: x}) and the corresponding accessor. 98func (f SurroundingObjectFunc) Child(k string) SurroundingObjectFunc { 99 return func(x interface{}) (map[string]interface{}, AccessorFunc, error) { 100 obj, acc, err := f(map[string]interface{}{k: x}) 101 if err != nil { 102 return nil, nil, err 103 } 104 return obj, func(obj map[string]interface{}) (interface{}, bool, error) { 105 x, found, err := acc(obj) 106 if err != nil { 107 return nil, false, fmt.Errorf(".%s%v", k, err) 108 } 109 if !found { 110 return nil, false, nil 111 } 112 if x, ok := x.(map[string]interface{}); !ok { 113 return nil, false, fmt.Errorf(".%s must be of object type", k) 114 } else if v, found := x[k]; !found { 115 return nil, false, nil 116 } else { 117 return v, true, nil 118 } 119 }, err 120 } 121} 122 123// Index returns a function x => f([x]) and the corresponding accessor. 124func (f SurroundingObjectFunc) Index() SurroundingObjectFunc { 125 return func(focus interface{}) (map[string]interface{}, AccessorFunc, error) { 126 obj, acc, err := f([]interface{}{focus}) 127 if err != nil { 128 return nil, nil, err 129 } 130 return obj, func(obj map[string]interface{}) (interface{}, bool, error) { 131 x, found, err := acc(obj) 132 if err != nil { 133 return nil, false, fmt.Errorf("[]%v", err) 134 } 135 if !found { 136 return nil, false, nil 137 } 138 if x, ok := x.([]interface{}); !ok { 139 return nil, false, fmt.Errorf("[] must be of array type") 140 } else if len(x) == 0 { 141 return nil, false, nil 142 } else { 143 return x[0], true, nil 144 } 145 }, err 146 } 147} 148