summaryrefslogtreecommitdiff
path: root/vendor/k8s.io/apimachinery/pkg/conversion
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/k8s.io/apimachinery/pkg/conversion')
-rw-r--r--vendor/k8s.io/apimachinery/pkg/conversion/cloner.go249
-rw-r--r--vendor/k8s.io/apimachinery/pkg/conversion/converter.go898
-rw-r--r--vendor/k8s.io/apimachinery/pkg/conversion/deep_equal.go36
-rw-r--r--vendor/k8s.io/apimachinery/pkg/conversion/doc.go24
-rw-r--r--vendor/k8s.io/apimachinery/pkg/conversion/helper.go39
-rw-r--r--vendor/k8s.io/apimachinery/pkg/conversion/queryparams/convert.go188
-rw-r--r--vendor/k8s.io/apimachinery/pkg/conversion/queryparams/doc.go19
-rw-r--r--vendor/k8s.io/apimachinery/pkg/conversion/unstructured/converter.go690
-rw-r--r--vendor/k8s.io/apimachinery/pkg/conversion/unstructured/doc.go19
9 files changed, 2162 insertions, 0 deletions
diff --git a/vendor/k8s.io/apimachinery/pkg/conversion/cloner.go b/vendor/k8s.io/apimachinery/pkg/conversion/cloner.go
new file mode 100644
index 000000000..c5dec1f31
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/conversion/cloner.go
@@ -0,0 +1,249 @@
+/*
+Copyright 2014 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package conversion
+
+import (
+ "fmt"
+ "reflect"
+)
+
+// Cloner knows how to copy one type to another.
+type Cloner struct {
+ // Map from the type to a function which can do the deep copy.
+ deepCopyFuncs map[reflect.Type]reflect.Value
+ generatedDeepCopyFuncs map[reflect.Type]func(in interface{}, out interface{}, c *Cloner) error
+}
+
+// NewCloner creates a new Cloner object.
+func NewCloner() *Cloner {
+ c := &Cloner{
+ deepCopyFuncs: map[reflect.Type]reflect.Value{},
+ generatedDeepCopyFuncs: map[reflect.Type]func(in interface{}, out interface{}, c *Cloner) error{},
+ }
+ if err := c.RegisterDeepCopyFunc(byteSliceDeepCopy); err != nil {
+ // If one of the deep-copy functions is malformed, detect it immediately.
+ panic(err)
+ }
+ return c
+}
+
+// Prevent recursing into every byte...
+func byteSliceDeepCopy(in *[]byte, out *[]byte, c *Cloner) error {
+ if *in != nil {
+ *out = make([]byte, len(*in))
+ copy(*out, *in)
+ } else {
+ *out = nil
+ }
+ return nil
+}
+
+// Verifies whether a deep-copy function has a correct signature.
+func verifyDeepCopyFunctionSignature(ft reflect.Type) error {
+ if ft.Kind() != reflect.Func {
+ return fmt.Errorf("expected func, got: %v", ft)
+ }
+ if ft.NumIn() != 3 {
+ return fmt.Errorf("expected three 'in' params, got %v", ft)
+ }
+ if ft.NumOut() != 1 {
+ return fmt.Errorf("expected one 'out' param, got %v", ft)
+ }
+ if ft.In(0).Kind() != reflect.Ptr {
+ return fmt.Errorf("expected pointer arg for 'in' param 0, got: %v", ft)
+ }
+ if ft.In(1) != ft.In(0) {
+ return fmt.Errorf("expected 'in' param 0 the same as param 1, got: %v", ft)
+ }
+ var forClonerType Cloner
+ if expected := reflect.TypeOf(&forClonerType); ft.In(2) != expected {
+ return fmt.Errorf("expected '%v' arg for 'in' param 2, got: '%v'", expected, ft.In(2))
+ }
+ var forErrorType error
+ // This convolution is necessary, otherwise TypeOf picks up on the fact
+ // that forErrorType is nil
+ errorType := reflect.TypeOf(&forErrorType).Elem()
+ if ft.Out(0) != errorType {
+ return fmt.Errorf("expected error return, got: %v", ft)
+ }
+ return nil
+}
+
+// RegisterGeneratedDeepCopyFunc registers a copying func with the Cloner.
+// deepCopyFunc must take three parameters: a type input, a pointer to a
+// type output, and a pointer to Cloner. It should return an error.
+//
+// Example:
+// c.RegisterGeneratedDeepCopyFunc(
+// func(in Pod, out *Pod, c *Cloner) error {
+// // deep copy logic...
+// return nil
+// })
+func (c *Cloner) RegisterDeepCopyFunc(deepCopyFunc interface{}) error {
+ fv := reflect.ValueOf(deepCopyFunc)
+ ft := fv.Type()
+ if err := verifyDeepCopyFunctionSignature(ft); err != nil {
+ return err
+ }
+ c.deepCopyFuncs[ft.In(0)] = fv
+ return nil
+}
+
+// GeneratedDeepCopyFunc bundles an untyped generated deep-copy function of a type
+// with a reflection type object used as a key to lookup the deep-copy function.
+type GeneratedDeepCopyFunc struct {
+ Fn func(in interface{}, out interface{}, c *Cloner) error
+ InType reflect.Type
+}
+
+// Similar to RegisterDeepCopyFunc, but registers deep copy function that were
+// automatically generated.
+func (c *Cloner) RegisterGeneratedDeepCopyFunc(fn GeneratedDeepCopyFunc) error {
+ c.generatedDeepCopyFuncs[fn.InType] = fn.Fn
+ return nil
+}
+
+// DeepCopy will perform a deep copy of a given object.
+func (c *Cloner) DeepCopy(in interface{}) (interface{}, error) {
+ // Can be invalid if we run DeepCopy(X) where X is a nil interface type.
+ // For example, we get an invalid value when someone tries to deep-copy
+ // a nil labels.Selector.
+ // This does not occur if X is nil and is a pointer to a concrete type.
+ if in == nil {
+ return nil, nil
+ }
+ inValue := reflect.ValueOf(in)
+ outValue, err := c.deepCopy(inValue)
+ if err != nil {
+ return nil, err
+ }
+ return outValue.Interface(), nil
+}
+
+func (c *Cloner) deepCopy(src reflect.Value) (reflect.Value, error) {
+ inType := src.Type()
+
+ switch src.Kind() {
+ case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
+ if src.IsNil() {
+ return src, nil
+ }
+ }
+
+ if fv, ok := c.deepCopyFuncs[inType]; ok {
+ return c.customDeepCopy(src, fv)
+ }
+ if fv, ok := c.generatedDeepCopyFuncs[inType]; ok {
+ var outValue reflect.Value
+ outValue = reflect.New(inType.Elem())
+ err := fv(src.Interface(), outValue.Interface(), c)
+ return outValue, err
+ }
+ return c.defaultDeepCopy(src)
+}
+
+func (c *Cloner) customDeepCopy(src, fv reflect.Value) (reflect.Value, error) {
+ outValue := reflect.New(src.Type().Elem())
+ args := []reflect.Value{src, outValue, reflect.ValueOf(c)}
+ result := fv.Call(args)[0].Interface()
+ // This convolution is necessary because nil interfaces won't convert
+ // to error.
+ if result == nil {
+ return outValue, nil
+ }
+ return outValue, result.(error)
+}
+
+func (c *Cloner) defaultDeepCopy(src reflect.Value) (reflect.Value, error) {
+ switch src.Kind() {
+ case reflect.Chan, reflect.Func, reflect.UnsafePointer, reflect.Uintptr:
+ return src, fmt.Errorf("cannot deep copy kind: %s", src.Kind())
+ case reflect.Array:
+ dst := reflect.New(src.Type())
+ for i := 0; i < src.Len(); i++ {
+ copyVal, err := c.deepCopy(src.Index(i))
+ if err != nil {
+ return src, err
+ }
+ dst.Elem().Index(i).Set(copyVal)
+ }
+ return dst.Elem(), nil
+ case reflect.Interface:
+ if src.IsNil() {
+ return src, nil
+ }
+ return c.deepCopy(src.Elem())
+ case reflect.Map:
+ if src.IsNil() {
+ return src, nil
+ }
+ dst := reflect.MakeMap(src.Type())
+ for _, k := range src.MapKeys() {
+ copyVal, err := c.deepCopy(src.MapIndex(k))
+ if err != nil {
+ return src, err
+ }
+ dst.SetMapIndex(k, copyVal)
+ }
+ return dst, nil
+ case reflect.Ptr:
+ if src.IsNil() {
+ return src, nil
+ }
+ dst := reflect.New(src.Type().Elem())
+ copyVal, err := c.deepCopy(src.Elem())
+ if err != nil {
+ return src, err
+ }
+ dst.Elem().Set(copyVal)
+ return dst, nil
+ case reflect.Slice:
+ if src.IsNil() {
+ return src, nil
+ }
+ dst := reflect.MakeSlice(src.Type(), 0, src.Len())
+ for i := 0; i < src.Len(); i++ {
+ copyVal, err := c.deepCopy(src.Index(i))
+ if err != nil {
+ return src, err
+ }
+ dst = reflect.Append(dst, copyVal)
+ }
+ return dst, nil
+ case reflect.Struct:
+ dst := reflect.New(src.Type())
+ for i := 0; i < src.NumField(); i++ {
+ if !dst.Elem().Field(i).CanSet() {
+ // Can't set private fields. At this point, the
+ // best we can do is a shallow copy. For
+ // example, time.Time is a value type with
+ // private members that can be shallow copied.
+ return src, nil
+ }
+ copyVal, err := c.deepCopy(src.Field(i))
+ if err != nil {
+ return src, err
+ }
+ dst.Elem().Field(i).Set(copyVal)
+ }
+ return dst.Elem(), nil
+
+ default:
+ // Value types like numbers, booleans, and strings.
+ return src, nil
+ }
+}
diff --git a/vendor/k8s.io/apimachinery/pkg/conversion/converter.go b/vendor/k8s.io/apimachinery/pkg/conversion/converter.go
new file mode 100644
index 000000000..7854c207c
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/conversion/converter.go
@@ -0,0 +1,898 @@
+/*
+Copyright 2014 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package conversion
+
+import (
+ "fmt"
+ "reflect"
+)
+
+type typePair struct {
+ source reflect.Type
+ dest reflect.Type
+}
+
+type typeNamePair struct {
+ fieldType reflect.Type
+ fieldName string
+}
+
+// DebugLogger allows you to get debugging messages if necessary.
+type DebugLogger interface {
+ Logf(format string, args ...interface{})
+}
+
+type NameFunc func(t reflect.Type) string
+
+var DefaultNameFunc = func(t reflect.Type) string { return t.Name() }
+
+type GenericConversionFunc func(a, b interface{}, scope Scope) (bool, error)
+
+// Converter knows how to convert one type to another.
+type Converter struct {
+ // Map from the conversion pair to a function which can
+ // do the conversion.
+ conversionFuncs ConversionFuncs
+ generatedConversionFuncs ConversionFuncs
+
+ // genericConversions are called during normal conversion to offer a "fast-path"
+ // that avoids all reflection. These methods are not called outside of the .Convert()
+ // method.
+ genericConversions []GenericConversionFunc
+
+ // Set of conversions that should be treated as a no-op
+ ignoredConversions map[typePair]struct{}
+
+ // This is a map from a source field type and name, to a list of destination
+ // field type and name.
+ structFieldDests map[typeNamePair][]typeNamePair
+
+ // Allows for the opposite lookup of structFieldDests. So that SourceFromDest
+ // copy flag also works. So this is a map of destination field name, to potential
+ // source field name and type to look for.
+ structFieldSources map[typeNamePair][]typeNamePair
+
+ // Map from an input type to a function which can apply a key name mapping
+ inputFieldMappingFuncs map[reflect.Type]FieldMappingFunc
+
+ // Map from an input type to a set of default conversion flags.
+ inputDefaultFlags map[reflect.Type]FieldMatchingFlags
+
+ // If non-nil, will be called to print helpful debugging info. Quite verbose.
+ Debug DebugLogger
+
+ // nameFunc is called to retrieve the name of a type; this name is used for the
+ // purpose of deciding whether two types match or not (i.e., will we attempt to
+ // do a conversion). The default returns the go type name.
+ nameFunc func(t reflect.Type) string
+}
+
+// NewConverter creates a new Converter object.
+func NewConverter(nameFn NameFunc) *Converter {
+ c := &Converter{
+ conversionFuncs: NewConversionFuncs(),
+ generatedConversionFuncs: NewConversionFuncs(),
+ ignoredConversions: make(map[typePair]struct{}),
+ nameFunc: nameFn,
+ structFieldDests: make(map[typeNamePair][]typeNamePair),
+ structFieldSources: make(map[typeNamePair][]typeNamePair),
+
+ inputFieldMappingFuncs: make(map[reflect.Type]FieldMappingFunc),
+ inputDefaultFlags: make(map[reflect.Type]FieldMatchingFlags),
+ }
+ c.RegisterConversionFunc(Convert_Slice_byte_To_Slice_byte)
+ return c
+}
+
+// AddGenericConversionFunc adds a function that accepts the ConversionFunc call pattern
+// (for two conversion types) to the converter. These functions are checked first during
+// a normal conversion, but are otherwise not called. Use AddConversionFuncs when registering
+// typed conversions.
+func (c *Converter) AddGenericConversionFunc(fn GenericConversionFunc) {
+ c.genericConversions = append(c.genericConversions, fn)
+}
+
+// WithConversions returns a Converter that is a copy of c but with the additional
+// fns merged on top.
+func (c *Converter) WithConversions(fns ConversionFuncs) *Converter {
+ copied := *c
+ copied.conversionFuncs = c.conversionFuncs.Merge(fns)
+ return &copied
+}
+
+// DefaultMeta returns the conversion FieldMappingFunc and meta for a given type.
+func (c *Converter) DefaultMeta(t reflect.Type) (FieldMatchingFlags, *Meta) {
+ return c.inputDefaultFlags[t], &Meta{
+ KeyNameMapping: c.inputFieldMappingFuncs[t],
+ }
+}
+
+// Convert_Slice_byte_To_Slice_byte prevents recursing into every byte
+func Convert_Slice_byte_To_Slice_byte(in *[]byte, out *[]byte, s Scope) error {
+ if *in == nil {
+ *out = nil
+ return nil
+ }
+ *out = make([]byte, len(*in))
+ copy(*out, *in)
+ return nil
+}
+
+// Scope is passed to conversion funcs to allow them to continue an ongoing conversion.
+// If multiple converters exist in the system, Scope will allow you to use the correct one
+// from a conversion function--that is, the one your conversion function was called by.
+type Scope interface {
+ // Call Convert to convert sub-objects. Note that if you call it with your own exact
+ // parameters, you'll run out of stack space before anything useful happens.
+ Convert(src, dest interface{}, flags FieldMatchingFlags) error
+
+ // DefaultConvert performs the default conversion, without calling a conversion func
+ // on the current stack frame. This makes it safe to call from a conversion func.
+ DefaultConvert(src, dest interface{}, flags FieldMatchingFlags) error
+
+ // SrcTags and DestTags contain the struct tags that src and dest had, respectively.
+ // If the enclosing object was not a struct, then these will contain no tags, of course.
+ SrcTag() reflect.StructTag
+ DestTag() reflect.StructTag
+
+ // Flags returns the flags with which the conversion was started.
+ Flags() FieldMatchingFlags
+
+ // Meta returns any information originally passed to Convert.
+ Meta() *Meta
+}
+
+// FieldMappingFunc can convert an input field value into different values, depending on
+// the value of the source or destination struct tags.
+type FieldMappingFunc func(key string, sourceTag, destTag reflect.StructTag) (source string, dest string)
+
+func NewConversionFuncs() ConversionFuncs {
+ return ConversionFuncs{fns: make(map[typePair]reflect.Value)}
+}
+
+type ConversionFuncs struct {
+ fns map[typePair]reflect.Value
+}
+
+// Add adds the provided conversion functions to the lookup table - they must have the signature
+// `func(type1, type2, Scope) error`. Functions are added in the order passed and will override
+// previously registered pairs.
+func (c ConversionFuncs) Add(fns ...interface{}) error {
+ for _, fn := range fns {
+ fv := reflect.ValueOf(fn)
+ ft := fv.Type()
+ if err := verifyConversionFunctionSignature(ft); err != nil {
+ return err
+ }
+ c.fns[typePair{ft.In(0).Elem(), ft.In(1).Elem()}] = fv
+ }
+ return nil
+}
+
+// Merge returns a new ConversionFuncs that contains all conversions from
+// both other and c, with other conversions taking precedence.
+func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs {
+ merged := NewConversionFuncs()
+ for k, v := range c.fns {
+ merged.fns[k] = v
+ }
+ for k, v := range other.fns {
+ merged.fns[k] = v
+ }
+ return merged
+}
+
+// Meta is supplied by Scheme, when it calls Convert.
+type Meta struct {
+ // KeyNameMapping is an optional function which may map the listed key (field name)
+ // into a source and destination value.
+ KeyNameMapping FieldMappingFunc
+ // Context is an optional field that callers may use to pass info to conversion functions.
+ Context interface{}
+}
+
+// scope contains information about an ongoing conversion.
+type scope struct {
+ converter *Converter
+ meta *Meta
+ flags FieldMatchingFlags
+
+ // srcStack & destStack are separate because they may not have a 1:1
+ // relationship.
+ srcStack scopeStack
+ destStack scopeStack
+}
+
+type scopeStackElem struct {
+ tag reflect.StructTag
+ value reflect.Value
+ key string
+}
+
+type scopeStack []scopeStackElem
+
+func (s *scopeStack) pop() {
+ n := len(*s)
+ *s = (*s)[:n-1]
+}
+
+func (s *scopeStack) push(e scopeStackElem) {
+ *s = append(*s, e)
+}
+
+func (s *scopeStack) top() *scopeStackElem {
+ return &(*s)[len(*s)-1]
+}
+
+func (s scopeStack) describe() string {
+ desc := ""
+ if len(s) > 1 {
+ desc = "(" + s[1].value.Type().String() + ")"
+ }
+ for i, v := range s {
+ if i < 2 {
+ // First layer on stack is not real; second is handled specially above.
+ continue
+ }
+ if v.key == "" {
+ desc += fmt.Sprintf(".%v", v.value.Type())
+ } else {
+ desc += fmt.Sprintf(".%v", v.key)
+ }
+ }
+ return desc
+}
+
+// Formats src & dest as indices for printing.
+func (s *scope) setIndices(src, dest int) {
+ s.srcStack.top().key = fmt.Sprintf("[%v]", src)
+ s.destStack.top().key = fmt.Sprintf("[%v]", dest)
+}
+
+// Formats src & dest as map keys for printing.
+func (s *scope) setKeys(src, dest interface{}) {
+ s.srcStack.top().key = fmt.Sprintf(`["%v"]`, src)
+ s.destStack.top().key = fmt.Sprintf(`["%v"]`, dest)
+}
+
+// Convert continues a conversion.
+func (s *scope) Convert(src, dest interface{}, flags FieldMatchingFlags) error {
+ return s.converter.Convert(src, dest, flags, s.meta)
+}
+
+// DefaultConvert continues a conversion, performing a default conversion (no conversion func)
+// for the current stack frame.
+func (s *scope) DefaultConvert(src, dest interface{}, flags FieldMatchingFlags) error {
+ return s.converter.DefaultConvert(src, dest, flags, s.meta)
+}
+
+// SrcTag returns the tag of the struct containing the current source item, if any.
+func (s *scope) SrcTag() reflect.StructTag {
+ return s.srcStack.top().tag
+}
+
+// DestTag returns the tag of the struct containing the current dest item, if any.
+func (s *scope) DestTag() reflect.StructTag {
+ return s.destStack.top().tag
+}
+
+// Flags returns the flags with which the current conversion was started.
+func (s *scope) Flags() FieldMatchingFlags {
+ return s.flags
+}
+
+// Meta returns the meta object that was originally passed to Convert.
+func (s *scope) Meta() *Meta {
+ return s.meta
+}
+
+// describe prints the path to get to the current (source, dest) values.
+func (s *scope) describe() (src, dest string) {
+ return s.srcStack.describe(), s.destStack.describe()
+}
+
+// error makes an error that includes information about where we were in the objects
+// we were asked to convert.
+func (s *scope) errorf(message string, args ...interface{}) error {
+ srcPath, destPath := s.describe()
+ where := fmt.Sprintf("converting %v to %v: ", srcPath, destPath)
+ return fmt.Errorf(where+message, args...)
+}
+
+// Verifies whether a conversion function has a correct signature.
+func verifyConversionFunctionSignature(ft reflect.Type) error {
+ if ft.Kind() != reflect.Func {
+ return fmt.Errorf("expected func, got: %v", ft)
+ }
+ if ft.NumIn() != 3 {
+ return fmt.Errorf("expected three 'in' params, got: %v", ft)
+ }
+ if ft.NumOut() != 1 {
+ return fmt.Errorf("expected one 'out' param, got: %v", ft)
+ }
+ if ft.In(0).Kind() != reflect.Ptr {
+ return fmt.Errorf("expected pointer arg for 'in' param 0, got: %v", ft)
+ }
+ if ft.In(1).Kind() != reflect.Ptr {
+ return fmt.Errorf("expected pointer arg for 'in' param 1, got: %v", ft)
+ }
+ scopeType := Scope(nil)
+ if e, a := reflect.TypeOf(&scopeType).Elem(), ft.In(2); e != a {
+ return fmt.Errorf("expected '%v' arg for 'in' param 2, got '%v' (%v)", e, a, ft)
+ }
+ var forErrorType error
+ // This convolution is necessary, otherwise TypeOf picks up on the fact
+ // that forErrorType is nil.
+ errorType := reflect.TypeOf(&forErrorType).Elem()
+ if ft.Out(0) != errorType {
+ return fmt.Errorf("expected error return, got: %v", ft)
+ }
+ return nil
+}
+
+// RegisterConversionFunc registers a conversion func with the
+// Converter. conversionFunc must take three parameters: a pointer to the input
+// type, a pointer to the output type, and a conversion.Scope (which should be
+// used if recursive conversion calls are desired). It must return an error.
+//
+// Example:
+// c.RegisterConversionFunc(
+// func(in *Pod, out *v1.Pod, s Scope) error {
+// // conversion logic...
+// return nil
+// })
+func (c *Converter) RegisterConversionFunc(conversionFunc interface{}) error {
+ return c.conversionFuncs.Add(conversionFunc)
+}
+
+// Similar to RegisterConversionFunc, but registers conversion function that were
+// automatically generated.
+func (c *Converter) RegisterGeneratedConversionFunc(conversionFunc interface{}) error {
+ return c.generatedConversionFuncs.Add(conversionFunc)
+}
+
+// RegisterIgnoredConversion registers a "no-op" for conversion, where any requested
+// conversion between from and to is ignored.
+func (c *Converter) RegisterIgnoredConversion(from, to interface{}) error {
+ typeFrom := reflect.TypeOf(from)
+ typeTo := reflect.TypeOf(to)
+ if reflect.TypeOf(from).Kind() != reflect.Ptr {
+ return fmt.Errorf("expected pointer arg for 'from' param 0, got: %v", typeFrom)
+ }
+ if typeTo.Kind() != reflect.Ptr {
+ return fmt.Errorf("expected pointer arg for 'to' param 1, got: %v", typeTo)
+ }
+ c.ignoredConversions[typePair{typeFrom.Elem(), typeTo.Elem()}] = struct{}{}
+ return nil
+}
+
+// IsConversionIgnored returns true if the specified objects should be dropped during
+// conversion.
+func (c *Converter) IsConversionIgnored(inType, outType reflect.Type) bool {
+ _, found := c.ignoredConversions[typePair{inType, outType}]
+ return found
+}
+
+func (c *Converter) HasConversionFunc(inType, outType reflect.Type) bool {
+ _, found := c.conversionFuncs.fns[typePair{inType, outType}]
+ return found
+}
+
+func (c *Converter) ConversionFuncValue(inType, outType reflect.Type) (reflect.Value, bool) {
+ value, found := c.conversionFuncs.fns[typePair{inType, outType}]
+ return value, found
+}
+
+// SetStructFieldCopy registers a correspondence. Whenever a struct field is encountered
+// which has a type and name matching srcFieldType and srcFieldName, it wil be copied
+// into the field in the destination struct matching destFieldType & Name, if such a
+// field exists.
+// May be called multiple times, even for the same source field & type--all applicable
+// copies will be performed.
+func (c *Converter) SetStructFieldCopy(srcFieldType interface{}, srcFieldName string, destFieldType interface{}, destFieldName string) error {
+ st := reflect.TypeOf(srcFieldType)
+ dt := reflect.TypeOf(destFieldType)
+ srcKey := typeNamePair{st, srcFieldName}
+ destKey := typeNamePair{dt, destFieldName}
+ c.structFieldDests[srcKey] = append(c.structFieldDests[srcKey], destKey)
+ c.structFieldSources[destKey] = append(c.structFieldSources[destKey], srcKey)
+ return nil
+}
+
+// RegisterInputDefaults registers a field name mapping function, used when converting
+// from maps to structs. Inputs to the conversion methods are checked for this type and a mapping
+// applied automatically if the input matches in. A set of default flags for the input conversion
+// may also be provided, which will be used when no explicit flags are requested.
+func (c *Converter) RegisterInputDefaults(in interface{}, fn FieldMappingFunc, defaultFlags FieldMatchingFlags) error {
+ fv := reflect.ValueOf(in)
+ ft := fv.Type()
+ if ft.Kind() != reflect.Ptr {
+ return fmt.Errorf("expected pointer 'in' argument, got: %v", ft)
+ }
+ c.inputFieldMappingFuncs[ft] = fn
+ c.inputDefaultFlags[ft] = defaultFlags
+ return nil
+}
+
+// FieldMatchingFlags contains a list of ways in which struct fields could be
+// copied. These constants may be | combined.
+type FieldMatchingFlags int
+
+const (
+ // Loop through destination fields, search for matching source
+ // field to copy it from. Source fields with no corresponding
+ // destination field will be ignored. If SourceToDest is
+ // specified, this flag is ignored. If neither is specified,
+ // or no flags are passed, this flag is the default.
+ DestFromSource FieldMatchingFlags = 0
+ // Loop through source fields, search for matching dest field
+ // to copy it into. Destination fields with no corresponding
+ // source field will be ignored.
+ SourceToDest FieldMatchingFlags = 1 << iota
+ // Don't treat it as an error if the corresponding source or
+ // dest field can't be found.
+ IgnoreMissingFields
+ // Don't require type names to match.
+ AllowDifferentFieldTypeNames
+)
+
+// IsSet returns true if the given flag or combination of flags is set.
+func (f FieldMatchingFlags) IsSet(flag FieldMatchingFlags) bool {
+ if flag == DestFromSource {
+ // The bit logic doesn't work on the default value.
+ return f&SourceToDest != SourceToDest
+ }
+ return f&flag == flag
+}
+
+// Convert will translate src to dest if it knows how. Both must be pointers.
+// If no conversion func is registered and the default copying mechanism
+// doesn't work on this type pair, an error will be returned.
+// Read the comments on the various FieldMatchingFlags constants to understand
+// what the 'flags' parameter does.
+// 'meta' is given to allow you to pass information to conversion functions,
+// it is not used by Convert() other than storing it in the scope.
+// Not safe for objects with cyclic references!
+func (c *Converter) Convert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta) error {
+ if len(c.genericConversions) > 0 {
+ // TODO: avoid scope allocation
+ s := &scope{converter: c, flags: flags, meta: meta}
+ for _, fn := range c.genericConversions {
+ if ok, err := fn(src, dest, s); ok {
+ return err
+ }
+ }
+ }
+ return c.doConversion(src, dest, flags, meta, c.convert)
+}
+
+// DefaultConvert will translate src to dest if it knows how. Both must be pointers.
+// No conversion func is used. If the default copying mechanism
+// doesn't work on this type pair, an error will be returned.
+// Read the comments on the various FieldMatchingFlags constants to understand
+// what the 'flags' parameter does.
+// 'meta' is given to allow you to pass information to conversion functions,
+// it is not used by DefaultConvert() other than storing it in the scope.
+// Not safe for objects with cyclic references!
+func (c *Converter) DefaultConvert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta) error {
+ return c.doConversion(src, dest, flags, meta, c.defaultConvert)
+}
+
+type conversionFunc func(sv, dv reflect.Value, scope *scope) error
+
+func (c *Converter) doConversion(src, dest interface{}, flags FieldMatchingFlags, meta *Meta, f conversionFunc) error {
+ dv, err := EnforcePtr(dest)
+ if err != nil {
+ return err
+ }
+ if !dv.CanAddr() && !dv.CanSet() {
+ return fmt.Errorf("can't write to dest")
+ }
+ sv, err := EnforcePtr(src)
+ if err != nil {
+ return err
+ }
+ s := &scope{
+ converter: c,
+ flags: flags,
+ meta: meta,
+ }
+ // Leave something on the stack, so that calls to struct tag getters never fail.
+ s.srcStack.push(scopeStackElem{})
+ s.destStack.push(scopeStackElem{})
+ return f(sv, dv, s)
+}
+
+// callCustom calls 'custom' with sv & dv. custom must be a conversion function.
+func (c *Converter) callCustom(sv, dv, custom reflect.Value, scope *scope) error {
+ if !sv.CanAddr() {
+ sv2 := reflect.New(sv.Type())
+ sv2.Elem().Set(sv)
+ sv = sv2
+ } else {
+ sv = sv.Addr()
+ }
+ if !dv.CanAddr() {
+ if !dv.CanSet() {
+ return scope.errorf("can't addr or set dest.")
+ }
+ dvOrig := dv
+ dv := reflect.New(dvOrig.Type())
+ defer func() { dvOrig.Set(dv) }()
+ } else {
+ dv = dv.Addr()
+ }
+ args := []reflect.Value{sv, dv, reflect.ValueOf(scope)}
+ ret := custom.Call(args)[0].Interface()
+ // This convolution is necessary because nil interfaces won't convert
+ // to errors.
+ if ret == nil {
+ return nil
+ }
+ return ret.(error)
+}
+
+// convert recursively copies sv into dv, calling an appropriate conversion function if
+// one is registered.
+func (c *Converter) convert(sv, dv reflect.Value, scope *scope) error {
+ dt, st := dv.Type(), sv.Type()
+ pair := typePair{st, dt}
+
+ // ignore conversions of this type
+ if _, ok := c.ignoredConversions[pair]; ok {
+ if c.Debug != nil {
+ c.Debug.Logf("Ignoring conversion of '%v' to '%v'", st, dt)
+ }
+ return nil
+ }
+
+ // Convert sv to dv.
+ if fv, ok := c.conversionFuncs.fns[pair]; ok {
+ if c.Debug != nil {
+ c.Debug.Logf("Calling custom conversion of '%v' to '%v'", st, dt)
+ }
+ return c.callCustom(sv, dv, fv, scope)
+ }
+ if fv, ok := c.generatedConversionFuncs.fns[pair]; ok {
+ if c.Debug != nil {
+ c.Debug.Logf("Calling generated conversion of '%v' to '%v'", st, dt)
+ }
+ return c.callCustom(sv, dv, fv, scope)
+ }
+
+ return c.defaultConvert(sv, dv, scope)
+}
+
+// defaultConvert recursively copies sv into dv. no conversion function is called
+// for the current stack frame (but conversion functions may be called for nested objects)
+func (c *Converter) defaultConvert(sv, dv reflect.Value, scope *scope) error {
+ dt, st := dv.Type(), sv.Type()
+
+ if !dv.CanSet() {
+ return scope.errorf("Cannot set dest. (Tried to deep copy something with unexported fields?)")
+ }
+
+ if !scope.flags.IsSet(AllowDifferentFieldTypeNames) && c.nameFunc(dt) != c.nameFunc(st) {
+ return scope.errorf(
+ "type names don't match (%v, %v), and no conversion 'func (%v, %v) error' registered.",
+ c.nameFunc(st), c.nameFunc(dt), st, dt)
+ }
+
+ switch st.Kind() {
+ case reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct:
+ // Don't copy these via assignment/conversion!
+ default:
+ // This should handle all simple types.
+ if st.AssignableTo(dt) {
+ dv.Set(sv)
+ return nil
+ }
+ if st.ConvertibleTo(dt) {
+ dv.Set(sv.Convert(dt))
+ return nil
+ }
+ }
+
+ if c.Debug != nil {
+ c.Debug.Logf("Trying to convert '%v' to '%v'", st, dt)
+ }
+
+ scope.srcStack.push(scopeStackElem{value: sv})
+ scope.destStack.push(scopeStackElem{value: dv})
+ defer scope.srcStack.pop()
+ defer scope.destStack.pop()
+
+ switch dv.Kind() {
+ case reflect.Struct:
+ return c.convertKV(toKVValue(sv), toKVValue(dv), scope)
+ case reflect.Slice:
+ if sv.IsNil() {
+ // Don't make a zero-length slice.
+ dv.Set(reflect.Zero(dt))
+ return nil
+ }
+ dv.Set(reflect.MakeSlice(dt, sv.Len(), sv.Cap()))
+ for i := 0; i < sv.Len(); i++ {
+ scope.setIndices(i, i)
+ if err := c.convert(sv.Index(i), dv.Index(i), scope); err != nil {
+ return err
+ }
+ }
+ case reflect.Ptr:
+ if sv.IsNil() {
+ // Don't copy a nil ptr!
+ dv.Set(reflect.Zero(dt))
+ return nil
+ }
+ dv.Set(reflect.New(dt.Elem()))
+ switch st.Kind() {
+ case reflect.Ptr, reflect.Interface:
+ return c.convert(sv.Elem(), dv.Elem(), scope)
+ default:
+ return c.convert(sv, dv.Elem(), scope)
+ }
+ case reflect.Map:
+ if sv.IsNil() {
+ // Don't copy a nil ptr!
+ dv.Set(reflect.Zero(dt))
+ return nil
+ }
+ dv.Set(reflect.MakeMap(dt))
+ for _, sk := range sv.MapKeys() {
+ dk := reflect.New(dt.Key()).Elem()
+ if err := c.convert(sk, dk, scope); err != nil {
+ return err
+ }
+ dkv := reflect.New(dt.Elem()).Elem()
+ scope.setKeys(sk.Interface(), dk.Interface())
+ // TODO: sv.MapIndex(sk) may return a value with CanAddr() == false,
+ // because a map[string]struct{} does not allow a pointer reference.
+ // Calling a custom conversion function defined for the map value
+ // will panic. Example is PodInfo map[string]ContainerStatus.
+ if err := c.convert(sv.MapIndex(sk), dkv, scope); err != nil {
+ return err
+ }
+ dv.SetMapIndex(dk, dkv)
+ }
+ case reflect.Interface:
+ if sv.IsNil() {
+ // Don't copy a nil interface!
+ dv.Set(reflect.Zero(dt))
+ return nil
+ }
+ tmpdv := reflect.New(sv.Elem().Type()).Elem()
+ if err := c.convert(sv.Elem(), tmpdv, scope); err != nil {
+ return err
+ }
+ dv.Set(reflect.ValueOf(tmpdv.Interface()))
+ return nil
+ default:
+ return scope.errorf("couldn't copy '%v' into '%v'; didn't understand types", st, dt)
+ }
+ return nil
+}
+
+var stringType = reflect.TypeOf("")
+
+func toKVValue(v reflect.Value) kvValue {
+ switch v.Kind() {
+ case reflect.Struct:
+ return structAdaptor(v)
+ case reflect.Map:
+ if v.Type().Key().AssignableTo(stringType) {
+ return stringMapAdaptor(v)
+ }
+ }
+
+ return nil
+}
+
+// kvValue lets us write the same conversion logic to work with both maps
+// and structs. Only maps with string keys make sense for this.
+type kvValue interface {
+ // returns all keys, as a []string.
+ keys() []string
+ // Will just return "" for maps.
+ tagOf(key string) reflect.StructTag
+ // Will return the zero Value if the key doesn't exist.
+ value(key string) reflect.Value
+ // Maps require explicit setting-- will do nothing for structs.
+ // Returns false on failure.
+ confirmSet(key string, v reflect.Value) bool
+}
+
+type stringMapAdaptor reflect.Value
+
+func (a stringMapAdaptor) len() int {
+ return reflect.Value(a).Len()
+}
+
+func (a stringMapAdaptor) keys() []string {
+ v := reflect.Value(a)
+ keys := make([]string, v.Len())
+ for i, v := range v.MapKeys() {
+ if v.IsNil() {
+ continue
+ }
+ switch t := v.Interface().(type) {
+ case string:
+ keys[i] = t
+ }
+ }
+ return keys
+}
+
+func (a stringMapAdaptor) tagOf(key string) reflect.StructTag {
+ return ""
+}
+
+func (a stringMapAdaptor) value(key string) reflect.Value {
+ return reflect.Value(a).MapIndex(reflect.ValueOf(key))
+}
+
+func (a stringMapAdaptor) confirmSet(key string, v reflect.Value) bool {
+ return true
+}
+
+type structAdaptor reflect.Value
+
+func (a structAdaptor) len() int {
+ v := reflect.Value(a)
+ return v.Type().NumField()
+}
+
+func (a structAdaptor) keys() []string {
+ v := reflect.Value(a)
+ t := v.Type()
+ keys := make([]string, t.NumField())
+ for i := range keys {
+ keys[i] = t.Field(i).Name
+ }
+ return keys
+}
+
+func (a structAdaptor) tagOf(key string) reflect.StructTag {
+ v := reflect.Value(a)
+ field, ok := v.Type().FieldByName(key)
+ if ok {
+ return field.Tag
+ }
+ return ""
+}
+
+func (a structAdaptor) value(key string) reflect.Value {
+ v := reflect.Value(a)
+ return v.FieldByName(key)
+}
+
+func (a structAdaptor) confirmSet(key string, v reflect.Value) bool {
+ return true
+}
+
+// convertKV can convert things that consist of key/value pairs, like structs
+// and some maps.
+func (c *Converter) convertKV(skv, dkv kvValue, scope *scope) error {
+ if skv == nil || dkv == nil {
+ // TODO: add keys to stack to support really understandable error messages.
+ return fmt.Errorf("Unable to convert %#v to %#v", skv, dkv)
+ }
+
+ lister := dkv
+ if scope.flags.IsSet(SourceToDest) {
+ lister = skv
+ }
+
+ var mapping FieldMappingFunc
+ if scope.meta != nil && scope.meta.KeyNameMapping != nil {
+ mapping = scope.meta.KeyNameMapping
+ }
+
+ for _, key := range lister.keys() {
+ if found, err := c.checkField(key, skv, dkv, scope); found {
+ if err != nil {
+ return err
+ }
+ continue
+ }
+ stag := skv.tagOf(key)
+ dtag := dkv.tagOf(key)
+ skey := key
+ dkey := key
+ if mapping != nil {
+ skey, dkey = scope.meta.KeyNameMapping(key, stag, dtag)
+ }
+
+ df := dkv.value(dkey)
+ sf := skv.value(skey)
+ if !df.IsValid() || !sf.IsValid() {
+ switch {
+ case scope.flags.IsSet(IgnoreMissingFields):
+ // No error.
+ case scope.flags.IsSet(SourceToDest):
+ return scope.errorf("%v not present in dest", dkey)
+ default:
+ return scope.errorf("%v not present in src", skey)
+ }
+ continue
+ }
+ scope.srcStack.top().key = skey
+ scope.srcStack.top().tag = stag
+ scope.destStack.top().key = dkey
+ scope.destStack.top().tag = dtag
+ if err := c.convert(sf, df, scope); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// checkField returns true if the field name matches any of the struct
+// field copying rules. The error should be ignored if it returns false.
+func (c *Converter) checkField(fieldName string, skv, dkv kvValue, scope *scope) (bool, error) {
+ replacementMade := false
+ if scope.flags.IsSet(DestFromSource) {
+ df := dkv.value(fieldName)
+ if !df.IsValid() {
+ return false, nil
+ }
+ destKey := typeNamePair{df.Type(), fieldName}
+ // Check each of the potential source (type, name) pairs to see if they're
+ // present in sv.
+ for _, potentialSourceKey := range c.structFieldSources[destKey] {
+ sf := skv.value(potentialSourceKey.fieldName)
+ if !sf.IsValid() {
+ continue
+ }
+ if sf.Type() == potentialSourceKey.fieldType {
+ // Both the source's name and type matched, so copy.
+ scope.srcStack.top().key = potentialSourceKey.fieldName
+ scope.destStack.top().key = fieldName
+ if err := c.convert(sf, df, scope); err != nil {
+ return true, err
+ }
+ dkv.confirmSet(fieldName, df)
+ replacementMade = true
+ }
+ }
+ return replacementMade, nil
+ }
+
+ sf := skv.value(fieldName)
+ if !sf.IsValid() {
+ return false, nil
+ }
+ srcKey := typeNamePair{sf.Type(), fieldName}
+ // Check each of the potential dest (type, name) pairs to see if they're
+ // present in dv.
+ for _, potentialDestKey := range c.structFieldDests[srcKey] {
+ df := dkv.value(potentialDestKey.fieldName)
+ if !df.IsValid() {
+ continue
+ }
+ if df.Type() == potentialDestKey.fieldType {
+ // Both the dest's name and type matched, so copy.
+ scope.srcStack.top().key = fieldName
+ scope.destStack.top().key = potentialDestKey.fieldName
+ if err := c.convert(sf, df, scope); err != nil {
+ return true, err
+ }
+ dkv.confirmSet(potentialDestKey.fieldName, df)
+ replacementMade = true
+ }
+ }
+ return replacementMade, nil
+}
diff --git a/vendor/k8s.io/apimachinery/pkg/conversion/deep_equal.go b/vendor/k8s.io/apimachinery/pkg/conversion/deep_equal.go
new file mode 100644
index 000000000..f21abe1e5
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/conversion/deep_equal.go
@@ -0,0 +1,36 @@
+/*
+Copyright 2015 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package conversion
+
+import (
+ "k8s.io/apimachinery/third_party/forked/golang/reflect"
+)
+
+// The code for this type must be located in third_party, since it forks from
+// go std lib. But for convenience, we expose the type here, too.
+type Equalities struct {
+ reflect.Equalities
+}
+
+// For convenience, panics on errors
+func EqualitiesOrDie(funcs ...interface{}) Equalities {
+ e := Equalities{reflect.Equalities{}}
+ if err := e.AddFuncs(funcs...); err != nil {
+ panic(err)
+ }
+ return e
+}
diff --git a/vendor/k8s.io/apimachinery/pkg/conversion/doc.go b/vendor/k8s.io/apimachinery/pkg/conversion/doc.go
new file mode 100644
index 000000000..7415d8164
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/conversion/doc.go
@@ -0,0 +1,24 @@
+/*
+Copyright 2014 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package conversion provides go object versioning.
+//
+// Specifically, conversion provides a way for you to define multiple versions
+// of the same object. You may write functions which implement conversion logic,
+// but for the fields which did not change, copying is automated. This makes it
+// easy to modify the structures you use in memory without affecting the format
+// you store on disk or respond to in your external API calls.
+package conversion // import "k8s.io/apimachinery/pkg/conversion"
diff --git a/vendor/k8s.io/apimachinery/pkg/conversion/helper.go b/vendor/k8s.io/apimachinery/pkg/conversion/helper.go
new file mode 100644
index 000000000..4ebc1ebc5
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/conversion/helper.go
@@ -0,0 +1,39 @@
+/*
+Copyright 2014 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package conversion
+
+import (
+ "fmt"
+ "reflect"
+)
+
+// EnforcePtr ensures that obj is a pointer of some sort. Returns a reflect.Value
+// of the dereferenced pointer, ensuring that it is settable/addressable.
+// Returns an error if this is not possible.
+func EnforcePtr(obj interface{}) (reflect.Value, error) {
+ v := reflect.ValueOf(obj)
+ if v.Kind() != reflect.Ptr {
+ if v.Kind() == reflect.Invalid {
+ return reflect.Value{}, fmt.Errorf("expected pointer, but got invalid kind")
+ }
+ return reflect.Value{}, fmt.Errorf("expected pointer, but got %v type", v.Type())
+ }
+ if v.IsNil() {
+ return reflect.Value{}, fmt.Errorf("expected pointer, but got nil")
+ }
+ return v.Elem(), nil
+}
diff --git a/vendor/k8s.io/apimachinery/pkg/conversion/queryparams/convert.go b/vendor/k8s.io/apimachinery/pkg/conversion/queryparams/convert.go
new file mode 100644
index 000000000..30f717b2c
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/conversion/queryparams/convert.go
@@ -0,0 +1,188 @@
+/*
+Copyright 2014 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package queryparams
+
+import (
+ "fmt"
+ "net/url"
+ "reflect"
+ "strings"
+)
+
+// Marshaler converts an object to a query parameter string representation
+type Marshaler interface {
+ MarshalQueryParameter() (string, error)
+}
+
+// Unmarshaler converts a string representation to an object
+type Unmarshaler interface {
+ UnmarshalQueryParameter(string) error
+}
+
+func jsonTag(field reflect.StructField) (string, bool) {
+ structTag := field.Tag.Get("json")
+ if len(structTag) == 0 {
+ return "", false
+ }
+ parts := strings.Split(structTag, ",")
+ tag := parts[0]
+ if tag == "-" {
+ tag = ""
+ }
+ omitempty := false
+ parts = parts[1:]
+ for _, part := range parts {
+ if part == "omitempty" {
+ omitempty = true
+ break
+ }
+ }
+ return tag, omitempty
+}
+
+func formatValue(value interface{}) string {
+ return fmt.Sprintf("%v", value)
+}
+
+func isPointerKind(kind reflect.Kind) bool {
+ return kind == reflect.Ptr
+}
+
+func isStructKind(kind reflect.Kind) bool {
+ return kind == reflect.Struct
+}
+
+func isValueKind(kind reflect.Kind) bool {
+ switch kind {
+ case reflect.String, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16,
+ reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8,
+ reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32,
+ reflect.Float64, reflect.Complex64, reflect.Complex128:
+ return true
+ default:
+ return false
+ }
+}
+
+func zeroValue(value reflect.Value) bool {
+ return reflect.DeepEqual(reflect.Zero(value.Type()).Interface(), value.Interface())
+}
+
+func customMarshalValue(value reflect.Value) (reflect.Value, bool) {
+ // Return unless we implement a custom query marshaler
+ if !value.CanInterface() {
+ return reflect.Value{}, false
+ }
+
+ marshaler, ok := value.Interface().(Marshaler)
+ if !ok {
+ return reflect.Value{}, false
+ }
+
+ // Don't invoke functions on nil pointers
+ // If the type implements MarshalQueryParameter, AND the tag is not omitempty, AND the value is a nil pointer, "" seems like a reasonable response
+ if isPointerKind(value.Kind()) && zeroValue(value) {
+ return reflect.ValueOf(""), true
+ }
+
+ // Get the custom marshalled value
+ v, err := marshaler.MarshalQueryParameter()
+ if err != nil {
+ return reflect.Value{}, false
+ }
+ return reflect.ValueOf(v), true
+}
+
+func addParam(values url.Values, tag string, omitempty bool, value reflect.Value) {
+ if omitempty && zeroValue(value) {
+ return
+ }
+ val := ""
+ iValue := fmt.Sprintf("%v", value.Interface())
+
+ if iValue != "<nil>" {
+ val = iValue
+ }
+ values.Add(tag, val)
+}
+
+func addListOfParams(values url.Values, tag string, omitempty bool, list reflect.Value) {
+ for i := 0; i < list.Len(); i++ {
+ addParam(values, tag, omitempty, list.Index(i))
+ }
+}
+
+// Convert takes an object and converts it to a url.Values object using JSON tags as
+// parameter names. Only top-level simple values, arrays, and slices are serialized.
+// Embedded structs, maps, etc. will not be serialized.
+func Convert(obj interface{}) (url.Values, error) {
+ result := url.Values{}
+ if obj == nil {
+ return result, nil
+ }
+ var sv reflect.Value
+ switch reflect.TypeOf(obj).Kind() {
+ case reflect.Ptr, reflect.Interface:
+ sv = reflect.ValueOf(obj).Elem()
+ default:
+ return nil, fmt.Errorf("expecting a pointer or interface")
+ }
+ st := sv.Type()
+ if !isStructKind(st.Kind()) {
+ return nil, fmt.Errorf("expecting a pointer to a struct")
+ }
+
+ // Check all object fields
+ convertStruct(result, st, sv)
+
+ return result, nil
+}
+
+func convertStruct(result url.Values, st reflect.Type, sv reflect.Value) {
+ for i := 0; i < st.NumField(); i++ {
+ field := sv.Field(i)
+ tag, omitempty := jsonTag(st.Field(i))
+ if len(tag) == 0 {
+ continue
+ }
+ ft := field.Type()
+
+ kind := ft.Kind()
+ if isPointerKind(kind) {
+ ft = ft.Elem()
+ kind = ft.Kind()
+ if !field.IsNil() {
+ field = reflect.Indirect(field)
+ }
+ }
+
+ switch {
+ case isValueKind(kind):
+ addParam(result, tag, omitempty, field)
+ case kind == reflect.Array || kind == reflect.Slice:
+ if isValueKind(ft.Elem().Kind()) {
+ addListOfParams(result, tag, omitempty, field)
+ }
+ case isStructKind(kind) && !(zeroValue(field) && omitempty):
+ if marshalValue, ok := customMarshalValue(field); ok {
+ addParam(result, tag, omitempty, marshalValue)
+ } else {
+ convertStruct(result, ft, field)
+ }
+ }
+ }
+}
diff --git a/vendor/k8s.io/apimachinery/pkg/conversion/queryparams/doc.go b/vendor/k8s.io/apimachinery/pkg/conversion/queryparams/doc.go
new file mode 100644
index 000000000..7b763de6f
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/conversion/queryparams/doc.go
@@ -0,0 +1,19 @@
+/*
+Copyright 2014 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package queryparams provides conversion from versioned
+// runtime objects to URL query values
+package queryparams // import "k8s.io/apimachinery/pkg/conversion/queryparams"
diff --git a/vendor/k8s.io/apimachinery/pkg/conversion/unstructured/converter.go b/vendor/k8s.io/apimachinery/pkg/conversion/unstructured/converter.go
new file mode 100644
index 000000000..cf84a6198
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/conversion/unstructured/converter.go
@@ -0,0 +1,690 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package unstructured
+
+import (
+ "bytes"
+ encodingjson "encoding/json"
+ "fmt"
+ "math"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+ "sync/atomic"
+
+ apiequality "k8s.io/apimachinery/pkg/api/equality"
+ "k8s.io/apimachinery/pkg/util/diff"
+ "k8s.io/apimachinery/pkg/util/json"
+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+
+ "github.com/golang/glog"
+)
+
+// Converter is an interface for converting between interface{}
+// and map[string]interface representation.
+type Converter interface {
+ ToUnstructured(obj interface{}, u *map[string]interface{}) error
+ FromUnstructured(u map[string]interface{}, obj interface{}) error
+}
+
+type structField struct {
+ structType reflect.Type
+ field int
+}
+
+type fieldInfo struct {
+ name string
+ nameValue reflect.Value
+ omitempty bool
+}
+
+type fieldsCacheMap map[structField]*fieldInfo
+
+type fieldsCache struct {
+ sync.Mutex
+ value atomic.Value
+}
+
+func newFieldsCache() *fieldsCache {
+ cache := &fieldsCache{}
+ cache.value.Store(make(fieldsCacheMap))
+ return cache
+}
+
+var (
+ marshalerType = reflect.TypeOf(new(encodingjson.Marshaler)).Elem()
+ unmarshalerType = reflect.TypeOf(new(encodingjson.Unmarshaler)).Elem()
+ mapStringInterfaceType = reflect.TypeOf(map[string]interface{}{})
+ stringType = reflect.TypeOf(string(""))
+ int64Type = reflect.TypeOf(int64(0))
+ uint64Type = reflect.TypeOf(uint64(0))
+ float64Type = reflect.TypeOf(float64(0))
+ boolType = reflect.TypeOf(bool(false))
+ fieldCache = newFieldsCache()
+ DefaultConverter = NewConverter(parseBool(os.Getenv("KUBE_PATCH_CONVERSION_DETECTOR")))
+)
+
+func parseBool(key string) bool {
+ if len(key) == 0 {
+ return false
+ }
+ value, err := strconv.ParseBool(key)
+ if err != nil {
+ utilruntime.HandleError(fmt.Errorf("Couldn't parse '%s' as bool for unstructured mismatch detection", key))
+ }
+ return value
+}
+
+// ConverterImpl knows how to convert between interface{} and
+// Unstructured in both ways.
+type converterImpl struct {
+ // If true, we will be additionally running conversion via json
+ // to ensure that the result is true.
+ // This is supposed to be set only in tests.
+ mismatchDetection bool
+}
+
+func NewConverter(mismatchDetection bool) Converter {
+ return &converterImpl{
+ mismatchDetection: mismatchDetection,
+ }
+}
+
+func (c *converterImpl) FromUnstructured(u map[string]interface{}, obj interface{}) error {
+ t := reflect.TypeOf(obj)
+ value := reflect.ValueOf(obj)
+ if t.Kind() != reflect.Ptr || value.IsNil() {
+ return fmt.Errorf("FromUnstructured requires a non-nil pointer to an object, got %v", t)
+ }
+ err := fromUnstructured(reflect.ValueOf(u), value.Elem())
+ if c.mismatchDetection {
+ newObj := reflect.New(t.Elem()).Interface()
+ newErr := fromUnstructuredViaJSON(u, newObj)
+ if (err != nil) != (newErr != nil) {
+ glog.Fatalf("FromUnstructured unexpected error for %v: error: %v", u, err)
+ }
+ if err == nil && !apiequality.Semantic.DeepEqual(obj, newObj) {
+ glog.Fatalf("FromUnstructured mismatch for %#v, diff: %v", obj, diff.ObjectReflectDiff(obj, newObj))
+ }
+ }
+ return err
+}
+
+func fromUnstructuredViaJSON(u map[string]interface{}, obj interface{}) error {
+ data, err := json.Marshal(u)
+ if err != nil {
+ return err
+ }
+ return json.Unmarshal(data, obj)
+}
+
+func fromUnstructured(sv, dv reflect.Value) error {
+ sv = unwrapInterface(sv)
+ if !sv.IsValid() {
+ dv.Set(reflect.Zero(dv.Type()))
+ return nil
+ }
+ st, dt := sv.Type(), dv.Type()
+
+ switch dt.Kind() {
+ case reflect.Map, reflect.Slice, reflect.Ptr, reflect.Struct, reflect.Interface:
+ // Those require non-trivial conversion.
+ default:
+ // This should handle all simple types.
+ if st.AssignableTo(dt) {
+ dv.Set(sv)
+ return nil
+ }
+ // We cannot simply use "ConvertibleTo", as JSON doesn't support conversions
+ // between those four groups: bools, integers, floats and string. We need to
+ // do the same.
+ if st.ConvertibleTo(dt) {
+ switch st.Kind() {
+ case reflect.String:
+ switch dt.Kind() {
+ case reflect.String:
+ dv.Set(sv.Convert(dt))
+ return nil
+ }
+ case reflect.Bool:
+ switch dt.Kind() {
+ case reflect.Bool:
+ dv.Set(sv.Convert(dt))
+ return nil
+ }
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ switch dt.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ dv.Set(sv.Convert(dt))
+ return nil
+ }
+ case reflect.Float32, reflect.Float64:
+ switch dt.Kind() {
+ case reflect.Float32, reflect.Float64:
+ dv.Set(sv.Convert(dt))
+ return nil
+ }
+ if sv.Float() == math.Trunc(sv.Float()) {
+ dv.Set(sv.Convert(dt))
+ return nil
+ }
+ }
+ return fmt.Errorf("cannot convert %s to %s", st.String(), dt.String())
+ }
+ }
+
+ // Check if the object has a custom JSON marshaller/unmarshaller.
+ if reflect.PtrTo(dt).Implements(unmarshalerType) {
+ data, err := json.Marshal(sv.Interface())
+ if err != nil {
+ return fmt.Errorf("error encoding %s to json: %v", st.String(), err)
+ }
+ unmarshaler := dv.Addr().Interface().(encodingjson.Unmarshaler)
+ return unmarshaler.UnmarshalJSON(data)
+ }
+
+ switch dt.Kind() {
+ case reflect.Map:
+ return mapFromUnstructured(sv, dv)
+ case reflect.Slice:
+ return sliceFromUnstructured(sv, dv)
+ case reflect.Ptr:
+ return pointerFromUnstructured(sv, dv)
+ case reflect.Struct:
+ return structFromUnstructured(sv, dv)
+ case reflect.Interface:
+ return interfaceFromUnstructured(sv, dv)
+ default:
+ return fmt.Errorf("unrecognized type: %v", dt.Kind())
+ }
+}
+
+func fieldInfoFromField(structType reflect.Type, field int) *fieldInfo {
+ fieldCacheMap := fieldCache.value.Load().(fieldsCacheMap)
+ if info, ok := fieldCacheMap[structField{structType, field}]; ok {
+ return info
+ }
+
+ // Cache miss - we need to compute the field name.
+ info := &fieldInfo{}
+ typeField := structType.Field(field)
+ jsonTag := typeField.Tag.Get("json")
+ if len(jsonTag) == 0 {
+ // Make the first character lowercase.
+ if typeField.Name == "" {
+ info.name = typeField.Name
+ } else {
+ info.name = strings.ToLower(typeField.Name[:1]) + typeField.Name[1:]
+ }
+ } else {
+ items := strings.Split(jsonTag, ",")
+ info.name = items[0]
+ for i := range items {
+ if items[i] == "omitempty" {
+ info.omitempty = true
+ }
+ }
+ }
+ info.nameValue = reflect.ValueOf(info.name)
+
+ fieldCache.Lock()
+ defer fieldCache.Unlock()
+ fieldCacheMap = fieldCache.value.Load().(fieldsCacheMap)
+ newFieldCacheMap := make(fieldsCacheMap)
+ for k, v := range fieldCacheMap {
+ newFieldCacheMap[k] = v
+ }
+ newFieldCacheMap[structField{structType, field}] = info
+ fieldCache.value.Store(newFieldCacheMap)
+ return info
+}
+
+func unwrapInterface(v reflect.Value) reflect.Value {
+ for v.Kind() == reflect.Interface {
+ v = v.Elem()
+ }
+ return v
+}
+
+func mapFromUnstructured(sv, dv reflect.Value) error {
+ st, dt := sv.Type(), dv.Type()
+ if st.Kind() != reflect.Map {
+ return fmt.Errorf("cannot restore map from %v", st.Kind())
+ }
+
+ if !st.Key().AssignableTo(dt.Key()) && !st.Key().ConvertibleTo(dt.Key()) {
+ return fmt.Errorf("cannot copy map with non-assignable keys: %v %v", st.Key(), dt.Key())
+ }
+
+ if sv.IsNil() {
+ dv.Set(reflect.Zero(dt))
+ return nil
+ }
+ dv.Set(reflect.MakeMap(dt))
+ for _, key := range sv.MapKeys() {
+ value := reflect.New(dt.Elem()).Elem()
+ if val := unwrapInterface(sv.MapIndex(key)); val.IsValid() {
+ if err := fromUnstructured(val, value); err != nil {
+ return err
+ }
+ } else {
+ value.Set(reflect.Zero(dt.Elem()))
+ }
+ if st.Key().AssignableTo(dt.Key()) {
+ dv.SetMapIndex(key, value)
+ } else {
+ dv.SetMapIndex(key.Convert(dt.Key()), value)
+ }
+ }
+ return nil
+}
+
+func sliceFromUnstructured(sv, dv reflect.Value) error {
+ st, dt := sv.Type(), dv.Type()
+ if st.Kind() == reflect.String && dt.Elem().Kind() == reflect.Uint8 {
+ // We store original []byte representation as string.
+ // This conversion is allowed, but we need to be careful about
+ // marshaling data appropriately.
+ if len(sv.Interface().(string)) > 0 {
+ marshalled, err := json.Marshal(sv.Interface())
+ if err != nil {
+ return fmt.Errorf("error encoding %s to json: %v", st, err)
+ }
+ // TODO: Is this Unmarshal needed?
+ var data []byte
+ err = json.Unmarshal(marshalled, &data)
+ if err != nil {
+ return fmt.Errorf("error decoding from json: %v", err)
+ }
+ dv.SetBytes(data)
+ } else {
+ dv.Set(reflect.Zero(dt))
+ }
+ return nil
+ }
+ if st.Kind() != reflect.Slice {
+ return fmt.Errorf("cannot restore slice from %v", st.Kind())
+ }
+
+ if sv.IsNil() {
+ dv.Set(reflect.Zero(dt))
+ return nil
+ }
+ dv.Set(reflect.MakeSlice(dt, sv.Len(), sv.Cap()))
+ for i := 0; i < sv.Len(); i++ {
+ if err := fromUnstructured(sv.Index(i), dv.Index(i)); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func pointerFromUnstructured(sv, dv reflect.Value) error {
+ st, dt := sv.Type(), dv.Type()
+
+ if st.Kind() == reflect.Ptr && sv.IsNil() {
+ dv.Set(reflect.Zero(dt))
+ return nil
+ }
+ dv.Set(reflect.New(dt.Elem()))
+ switch st.Kind() {
+ case reflect.Ptr, reflect.Interface:
+ return fromUnstructured(sv.Elem(), dv.Elem())
+ default:
+ return fromUnstructured(sv, dv.Elem())
+ }
+}
+
+func structFromUnstructured(sv, dv reflect.Value) error {
+ st, dt := sv.Type(), dv.Type()
+ if st.Kind() != reflect.Map {
+ return fmt.Errorf("cannot restore struct from: %v", st.Kind())
+ }
+
+ for i := 0; i < dt.NumField(); i++ {
+ fieldInfo := fieldInfoFromField(dt, i)
+ fv := dv.Field(i)
+
+ if len(fieldInfo.name) == 0 {
+ // This field is inlined.
+ if err := fromUnstructured(sv, fv); err != nil {
+ return err
+ }
+ } else {
+ value := unwrapInterface(sv.MapIndex(fieldInfo.nameValue))
+ if value.IsValid() {
+ if err := fromUnstructured(value, fv); err != nil {
+ return err
+ }
+ } else {
+ fv.Set(reflect.Zero(fv.Type()))
+ }
+ }
+ }
+ return nil
+}
+
+func interfaceFromUnstructured(sv, dv reflect.Value) error {
+ // TODO: Is this conversion safe?
+ dv.Set(sv)
+ return nil
+}
+
+func (c *converterImpl) ToUnstructured(obj interface{}, u *map[string]interface{}) error {
+ t := reflect.TypeOf(obj)
+ value := reflect.ValueOf(obj)
+ if t.Kind() != reflect.Ptr || value.IsNil() {
+ return fmt.Errorf("ToUnstructured requires a non-nil pointer to an object, got %v", t)
+ }
+ err := toUnstructured(value.Elem(), reflect.ValueOf(u).Elem())
+ if c.mismatchDetection {
+ newUnstr := &map[string]interface{}{}
+ newErr := toUnstructuredViaJSON(obj, newUnstr)
+ if (err != nil) != (newErr != nil) {
+ glog.Fatalf("ToUnstructured unexpected error for %v: error: %v", obj, err)
+ }
+ if err == nil && !apiequality.Semantic.DeepEqual(u, newUnstr) {
+ glog.Fatalf("ToUnstructured mismatch for %#v, diff: %v", u, diff.ObjectReflectDiff(u, newUnstr))
+ }
+ }
+ return err
+}
+
+func toUnstructuredViaJSON(obj interface{}, u *map[string]interface{}) error {
+ data, err := json.Marshal(obj)
+ if err != nil {
+ return err
+ }
+ return json.Unmarshal(data, u)
+}
+
+func toUnstructured(sv, dv reflect.Value) error {
+ st, dt := sv.Type(), dv.Type()
+
+ // Check if the object has a custom JSON marshaller/unmarshaller.
+ if st.Implements(marshalerType) {
+ if sv.Kind() == reflect.Ptr && sv.IsNil() {
+ // We're done - we don't need to store anything.
+ return nil
+ }
+
+ marshaler := sv.Interface().(encodingjson.Marshaler)
+ data, err := marshaler.MarshalJSON()
+ if err != nil {
+ return err
+ }
+ if bytes.Equal(data, []byte("null")) {
+ // We're done - we don't need to store anything.
+ } else {
+ switch {
+ case len(data) > 0 && data[0] == '"':
+ var result string
+ err := json.Unmarshal(data, &result)
+ if err != nil {
+ return fmt.Errorf("error decoding from json: %v", err)
+ }
+ dv.Set(reflect.ValueOf(result))
+ case len(data) > 0 && data[0] == '{':
+ result := make(map[string]interface{})
+ err := json.Unmarshal(data, &result)
+ if err != nil {
+ return fmt.Errorf("error decoding from json: %v", err)
+ }
+ dv.Set(reflect.ValueOf(result))
+ default:
+ var result int64
+ err := json.Unmarshal(data, &result)
+ if err != nil {
+ return fmt.Errorf("error decoding from json: %v", err)
+ }
+ dv.Set(reflect.ValueOf(result))
+ }
+ }
+ return nil
+ }
+
+ switch st.Kind() {
+ case reflect.String:
+ if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
+ dv.Set(reflect.New(stringType))
+ }
+ dv.Set(reflect.ValueOf(sv.String()))
+ return nil
+ case reflect.Bool:
+ if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
+ dv.Set(reflect.New(boolType))
+ }
+ dv.Set(reflect.ValueOf(sv.Bool()))
+ return nil
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
+ dv.Set(reflect.New(int64Type))
+ }
+ dv.Set(reflect.ValueOf(sv.Int()))
+ return nil
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
+ dv.Set(reflect.New(uint64Type))
+ }
+ dv.Set(reflect.ValueOf(sv.Uint()))
+ return nil
+ case reflect.Float32, reflect.Float64:
+ if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
+ dv.Set(reflect.New(float64Type))
+ }
+ dv.Set(reflect.ValueOf(sv.Float()))
+ return nil
+ case reflect.Map:
+ return mapToUnstructured(sv, dv)
+ case reflect.Slice:
+ return sliceToUnstructured(sv, dv)
+ case reflect.Ptr:
+ return pointerToUnstructured(sv, dv)
+ case reflect.Struct:
+ return structToUnstructured(sv, dv)
+ case reflect.Interface:
+ return interfaceToUnstructured(sv, dv)
+ default:
+ return fmt.Errorf("unrecognized type: %v", st.Kind())
+ }
+}
+
+func mapToUnstructured(sv, dv reflect.Value) error {
+ st, dt := sv.Type(), dv.Type()
+ if sv.IsNil() {
+ dv.Set(reflect.Zero(dt))
+ return nil
+ }
+ if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
+ if st.Key().Kind() == reflect.String {
+ switch st.Elem().Kind() {
+ // TODO It should be possible to reuse the slice for primitive types.
+ // However, it is panicing in the following form.
+ // case reflect.String, reflect.Bool,
+ // reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ // reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ // sv.Set(sv)
+ // return nil
+ default:
+ // We need to do a proper conversion.
+ }
+ }
+ dv.Set(reflect.MakeMap(mapStringInterfaceType))
+ dv = dv.Elem()
+ dt = dv.Type()
+ }
+ if dt.Kind() != reflect.Map {
+ return fmt.Errorf("cannot convert struct to: %v", dt.Kind())
+ }
+
+ if !st.Key().AssignableTo(dt.Key()) && !st.Key().ConvertibleTo(dt.Key()) {
+ return fmt.Errorf("cannot copy map with non-assignable keys: %v %v", st.Key(), dt.Key())
+ }
+
+ for _, key := range sv.MapKeys() {
+ value := reflect.New(dt.Elem()).Elem()
+ if err := toUnstructured(sv.MapIndex(key), value); err != nil {
+ return err
+ }
+ if st.Key().AssignableTo(dt.Key()) {
+ dv.SetMapIndex(key, value)
+ } else {
+ dv.SetMapIndex(key.Convert(dt.Key()), value)
+ }
+ }
+ return nil
+}
+
+func sliceToUnstructured(sv, dv reflect.Value) error {
+ st, dt := sv.Type(), dv.Type()
+ if sv.IsNil() {
+ dv.Set(reflect.Zero(dt))
+ return nil
+ }
+ if st.Elem().Kind() == reflect.Uint8 {
+ dv.Set(reflect.New(stringType))
+ data, err := json.Marshal(sv.Bytes())
+ if err != nil {
+ return err
+ }
+ var result string
+ if err = json.Unmarshal(data, &result); err != nil {
+ return err
+ }
+ dv.Set(reflect.ValueOf(result))
+ return nil
+ }
+ if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
+ switch st.Elem().Kind() {
+ // TODO It should be possible to reuse the slice for primitive types.
+ // However, it is panicing in the following form.
+ // case reflect.String, reflect.Bool,
+ // reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ // reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ // sv.Set(sv)
+ // return nil
+ default:
+ // We need to do a proper conversion.
+ dv.Set(reflect.MakeSlice(reflect.SliceOf(dt), sv.Len(), sv.Cap()))
+ dv = dv.Elem()
+ dt = dv.Type()
+ }
+ }
+ if dt.Kind() != reflect.Slice {
+ return fmt.Errorf("cannot convert slice to: %v", dt.Kind())
+ }
+ for i := 0; i < sv.Len(); i++ {
+ if err := toUnstructured(sv.Index(i), dv.Index(i)); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func pointerToUnstructured(sv, dv reflect.Value) error {
+ if sv.IsNil() {
+ // We're done - we don't need to store anything.
+ return nil
+ }
+ return toUnstructured(sv.Elem(), dv)
+}
+
+func isZero(v reflect.Value) bool {
+ switch v.Kind() {
+ case reflect.Array, reflect.String:
+ return v.Len() == 0
+ case reflect.Bool:
+ return !v.Bool()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return v.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return v.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ return v.Float() == 0
+ case reflect.Map, reflect.Slice:
+ // TODO: It seems that 0-len maps are ignored in it.
+ return v.IsNil() || v.Len() == 0
+ case reflect.Ptr, reflect.Interface:
+ return v.IsNil()
+ }
+ return false
+}
+
+func structToUnstructured(sv, dv reflect.Value) error {
+ st, dt := sv.Type(), dv.Type()
+ if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
+ dv.Set(reflect.MakeMap(mapStringInterfaceType))
+ dv = dv.Elem()
+ dt = dv.Type()
+ }
+ if dt.Kind() != reflect.Map {
+ return fmt.Errorf("cannot convert struct to: %v", dt.Kind())
+ }
+ realMap := dv.Interface().(map[string]interface{})
+
+ for i := 0; i < st.NumField(); i++ {
+ fieldInfo := fieldInfoFromField(st, i)
+ fv := sv.Field(i)
+
+ if fieldInfo.name == "-" {
+ // This field should be skipped.
+ continue
+ }
+ if fieldInfo.omitempty && isZero(fv) {
+ // omitempty fields should be ignored.
+ continue
+ }
+ if len(fieldInfo.name) == 0 {
+ // This field is inlined.
+ if err := toUnstructured(fv, dv); err != nil {
+ return err
+ }
+ continue
+ }
+ switch fv.Type().Kind() {
+ case reflect.String:
+ realMap[fieldInfo.name] = fv.String()
+ case reflect.Bool:
+ realMap[fieldInfo.name] = fv.Bool()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ realMap[fieldInfo.name] = fv.Int()
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ realMap[fieldInfo.name] = fv.Uint()
+ case reflect.Float32, reflect.Float64:
+ realMap[fieldInfo.name] = fv.Float()
+ default:
+ subv := reflect.New(dt.Elem()).Elem()
+ if err := toUnstructured(fv, subv); err != nil {
+ return err
+ }
+ dv.SetMapIndex(fieldInfo.nameValue, subv)
+ }
+ }
+ return nil
+}
+
+func interfaceToUnstructured(sv, dv reflect.Value) error {
+ if !sv.IsValid() || sv.IsNil() {
+ dv.Set(reflect.Zero(dv.Type()))
+ return nil
+ }
+ return toUnstructured(sv.Elem(), dv)
+}
diff --git a/vendor/k8s.io/apimachinery/pkg/conversion/unstructured/doc.go b/vendor/k8s.io/apimachinery/pkg/conversion/unstructured/doc.go
new file mode 100644
index 000000000..cd40e74be
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/conversion/unstructured/doc.go
@@ -0,0 +1,19 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package unstructured provides conversion from runtime objects
+// to map[string]interface{} representation.
+package unstructured // import "k8s.io/apimachinery/pkg/conversion/unstructured"