...

Source file src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/defaulting/surroundingobject.go

Documentation: k8s.io/apiextensions-apiserver/pkg/apiserver/schema/defaulting

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package defaulting
    18  
    19  import (
    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.
    28  type 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
    60  type 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.
    64  func 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).
    78  func (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.
    98  func (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.
   124  func (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  

View as plain text