...

Source file src/k8s.io/apimachinery/pkg/runtime/helper.go

Documentation: k8s.io/apimachinery/pkg/runtime

     1  /*
     2  Copyright 2014 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 runtime
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"reflect"
    23  
    24  	"k8s.io/apimachinery/pkg/conversion"
    25  	"k8s.io/apimachinery/pkg/runtime/schema"
    26  	"k8s.io/apimachinery/pkg/util/errors"
    27  )
    28  
    29  // unsafeObjectConvertor implements ObjectConvertor using the unsafe conversion path.
    30  type unsafeObjectConvertor struct {
    31  	*Scheme
    32  }
    33  
    34  var _ ObjectConvertor = unsafeObjectConvertor{}
    35  
    36  // ConvertToVersion converts in to the provided outVersion without copying the input first, which
    37  // is only safe if the output object is not mutated or reused.
    38  func (c unsafeObjectConvertor) ConvertToVersion(in Object, outVersion GroupVersioner) (Object, error) {
    39  	return c.Scheme.UnsafeConvertToVersion(in, outVersion)
    40  }
    41  
    42  // UnsafeObjectConvertor performs object conversion without copying the object structure,
    43  // for use when the converted object will not be reused or mutated. Primarily for use within
    44  // versioned codecs, which use the external object for serialization but do not return it.
    45  func UnsafeObjectConvertor(scheme *Scheme) ObjectConvertor {
    46  	return unsafeObjectConvertor{scheme}
    47  }
    48  
    49  // SetField puts the value of src, into fieldName, which must be a member of v.
    50  // The value of src must be assignable to the field.
    51  func SetField(src interface{}, v reflect.Value, fieldName string) error {
    52  	field := v.FieldByName(fieldName)
    53  	if !field.IsValid() {
    54  		return fmt.Errorf("couldn't find %v field in %T", fieldName, v.Interface())
    55  	}
    56  	srcValue := reflect.ValueOf(src)
    57  	if srcValue.Type().AssignableTo(field.Type()) {
    58  		field.Set(srcValue)
    59  		return nil
    60  	}
    61  	if srcValue.Type().ConvertibleTo(field.Type()) {
    62  		field.Set(srcValue.Convert(field.Type()))
    63  		return nil
    64  	}
    65  	return fmt.Errorf("couldn't assign/convert %v to %v", srcValue.Type(), field.Type())
    66  }
    67  
    68  // Field puts the value of fieldName, which must be a member of v, into dest,
    69  // which must be a variable to which this field's value can be assigned.
    70  func Field(v reflect.Value, fieldName string, dest interface{}) error {
    71  	field := v.FieldByName(fieldName)
    72  	if !field.IsValid() {
    73  		return fmt.Errorf("couldn't find %v field in %T", fieldName, v.Interface())
    74  	}
    75  	destValue, err := conversion.EnforcePtr(dest)
    76  	if err != nil {
    77  		return err
    78  	}
    79  	if field.Type().AssignableTo(destValue.Type()) {
    80  		destValue.Set(field)
    81  		return nil
    82  	}
    83  	if field.Type().ConvertibleTo(destValue.Type()) {
    84  		destValue.Set(field.Convert(destValue.Type()))
    85  		return nil
    86  	}
    87  	return fmt.Errorf("couldn't assign/convert %v to %v", field.Type(), destValue.Type())
    88  }
    89  
    90  // FieldPtr puts the address of fieldName, which must be a member of v,
    91  // into dest, which must be an address of a variable to which this field's
    92  // address can be assigned.
    93  func FieldPtr(v reflect.Value, fieldName string, dest interface{}) error {
    94  	field := v.FieldByName(fieldName)
    95  	if !field.IsValid() {
    96  		return fmt.Errorf("couldn't find %v field in %T", fieldName, v.Interface())
    97  	}
    98  	v, err := conversion.EnforcePtr(dest)
    99  	if err != nil {
   100  		return err
   101  	}
   102  	field = field.Addr()
   103  	if field.Type().AssignableTo(v.Type()) {
   104  		v.Set(field)
   105  		return nil
   106  	}
   107  	if field.Type().ConvertibleTo(v.Type()) {
   108  		v.Set(field.Convert(v.Type()))
   109  		return nil
   110  	}
   111  	return fmt.Errorf("couldn't assign/convert %v to %v", field.Type(), v.Type())
   112  }
   113  
   114  // EncodeList ensures that each object in an array is converted to a Unknown{} in serialized form.
   115  // TODO: accept a content type.
   116  func EncodeList(e Encoder, objects []Object) error {
   117  	var errs []error
   118  	for i := range objects {
   119  		data, err := Encode(e, objects[i])
   120  		if err != nil {
   121  			errs = append(errs, err)
   122  			continue
   123  		}
   124  		// TODO: Set ContentEncoding and ContentType.
   125  		objects[i] = &Unknown{Raw: data}
   126  	}
   127  	return errors.NewAggregate(errs)
   128  }
   129  
   130  func decodeListItem(obj *Unknown, decoders []Decoder) (Object, error) {
   131  	for _, decoder := range decoders {
   132  		// TODO: Decode based on ContentType.
   133  		obj, err := Decode(decoder, obj.Raw)
   134  		if err != nil {
   135  			if IsNotRegisteredError(err) {
   136  				continue
   137  			}
   138  			return nil, err
   139  		}
   140  		return obj, nil
   141  	}
   142  	// could not decode, so leave the object as Unknown, but give the decoders the
   143  	// chance to set Unknown.TypeMeta if it is available.
   144  	for _, decoder := range decoders {
   145  		if err := DecodeInto(decoder, obj.Raw, obj); err == nil {
   146  			return obj, nil
   147  		}
   148  	}
   149  	return obj, nil
   150  }
   151  
   152  // DecodeList alters the list in place, attempting to decode any objects found in
   153  // the list that have the Unknown type. Any errors that occur are returned
   154  // after the entire list is processed. Decoders are tried in order.
   155  func DecodeList(objects []Object, decoders ...Decoder) []error {
   156  	errs := []error(nil)
   157  	for i, obj := range objects {
   158  		switch t := obj.(type) {
   159  		case *Unknown:
   160  			decoded, err := decodeListItem(t, decoders)
   161  			if err != nil {
   162  				errs = append(errs, err)
   163  				break
   164  			}
   165  			objects[i] = decoded
   166  		}
   167  	}
   168  	return errs
   169  }
   170  
   171  // MultiObjectTyper returns the types of objects across multiple schemes in order.
   172  type MultiObjectTyper []ObjectTyper
   173  
   174  var _ ObjectTyper = MultiObjectTyper{}
   175  
   176  func (m MultiObjectTyper) ObjectKinds(obj Object) (gvks []schema.GroupVersionKind, unversionedType bool, err error) {
   177  	for _, t := range m {
   178  		gvks, unversionedType, err = t.ObjectKinds(obj)
   179  		if err == nil {
   180  			return
   181  		}
   182  	}
   183  	return
   184  }
   185  
   186  func (m MultiObjectTyper) Recognizes(gvk schema.GroupVersionKind) bool {
   187  	for _, t := range m {
   188  		if t.Recognizes(gvk) {
   189  			return true
   190  		}
   191  	}
   192  	return false
   193  }
   194  
   195  // SetZeroValue would set the object of objPtr to zero value of its type.
   196  func SetZeroValue(objPtr Object) error {
   197  	v, err := conversion.EnforcePtr(objPtr)
   198  	if err != nil {
   199  		return err
   200  	}
   201  	v.Set(reflect.Zero(v.Type()))
   202  	return nil
   203  }
   204  
   205  // DefaultFramer is valid for any stream that can read objects serially without
   206  // any separation in the stream.
   207  var DefaultFramer = defaultFramer{}
   208  
   209  type defaultFramer struct{}
   210  
   211  func (defaultFramer) NewFrameReader(r io.ReadCloser) io.ReadCloser { return r }
   212  func (defaultFramer) NewFrameWriter(w io.Writer) io.Writer         { return w }
   213  
   214  // WithVersionEncoder serializes an object and ensures the GVK is set.
   215  type WithVersionEncoder struct {
   216  	Version GroupVersioner
   217  	Encoder
   218  	ObjectTyper
   219  }
   220  
   221  // Encode does not do conversion. It sets the gvk during serialization.
   222  func (e WithVersionEncoder) Encode(obj Object, stream io.Writer) error {
   223  	gvks, _, err := e.ObjectTyper.ObjectKinds(obj)
   224  	if err != nil {
   225  		if IsNotRegisteredError(err) {
   226  			return e.Encoder.Encode(obj, stream)
   227  		}
   228  		return err
   229  	}
   230  	kind := obj.GetObjectKind()
   231  	oldGVK := kind.GroupVersionKind()
   232  	gvk := gvks[0]
   233  	if e.Version != nil {
   234  		preferredGVK, ok := e.Version.KindForGroupVersionKinds(gvks)
   235  		if ok {
   236  			gvk = preferredGVK
   237  		}
   238  	}
   239  
   240  	// The gvk only needs to be set if not already as desired.
   241  	if gvk != oldGVK {
   242  		kind.SetGroupVersionKind(gvk)
   243  		defer kind.SetGroupVersionKind(oldGVK)
   244  	}
   245  
   246  	return e.Encoder.Encode(obj, stream)
   247  }
   248  
   249  // WithoutVersionDecoder clears the group version kind of a deserialized object.
   250  type WithoutVersionDecoder struct {
   251  	Decoder
   252  }
   253  
   254  // Decode does not do conversion. It removes the gvk during deserialization.
   255  func (d WithoutVersionDecoder) Decode(data []byte, defaults *schema.GroupVersionKind, into Object) (Object, *schema.GroupVersionKind, error) {
   256  	obj, gvk, err := d.Decoder.Decode(data, defaults, into)
   257  	if obj != nil {
   258  		kind := obj.GetObjectKind()
   259  		// clearing the gvk is just a convention of a codec
   260  		kind.SetGroupVersionKind(schema.GroupVersionKind{})
   261  	}
   262  	return obj, gvk, err
   263  }
   264  
   265  type encoderWithAllocator struct {
   266  	encoder      EncoderWithAllocator
   267  	memAllocator MemoryAllocator
   268  }
   269  
   270  // NewEncoderWithAllocator returns a new encoder
   271  func NewEncoderWithAllocator(e EncoderWithAllocator, a MemoryAllocator) Encoder {
   272  	return &encoderWithAllocator{
   273  		encoder:      e,
   274  		memAllocator: a,
   275  	}
   276  }
   277  
   278  // Encode writes the provided object to the nested writer
   279  func (e *encoderWithAllocator) Encode(obj Object, w io.Writer) error {
   280  	return e.encoder.EncodeWithAllocator(obj, w, e.memAllocator)
   281  }
   282  
   283  // Identifier returns identifier of this encoder.
   284  func (e *encoderWithAllocator) Identifier() Identifier {
   285  	return e.encoder.Identifier()
   286  }
   287  

View as plain text