github.com/aclisp/heapster@v0.19.2-0.20160613100040-51756f899a96/Godeps/_workspace/src/k8s.io/kubernetes/pkg/runtime/scheme.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes Authors All rights reserved.
     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  	"net/url"
    22  	"reflect"
    23  
    24  	"k8s.io/kubernetes/pkg/api/unversioned"
    25  	"k8s.io/kubernetes/pkg/conversion"
    26  )
    27  
    28  // Scheme defines methods for serializing and deserializing API objects, a type
    29  // registry for converting group, version, and kind information to and from Go
    30  // schemas, and mappings between Go schemas of different versions. A scheme is the
    31  // foundation for a versioned API and versioned configuration over time.
    32  //
    33  // In a Scheme, a Type is a particular Go struct, a Version is a point-in-time
    34  // identifier for a particular representation of that Type (typically backwards
    35  // compatible), a Kind is the unique name for that Type within the Version, and a
    36  // Group identifies a set of Versions, Kinds, and Types that evolve over time. An
    37  // Unversioned Type is one that is not yet formally bound to a type and is promised
    38  // to be backwards compatible (effectively a "v1" of a Type that does not expect
    39  // to break in the future).
    40  //
    41  // Schemes are not expected to change at runtime and are only threadsafe after
    42  // registration is complete.
    43  type Scheme struct {
    44  	// versionMap allows one to figure out the go type of an object with
    45  	// the given version and name.
    46  	gvkToType map[unversioned.GroupVersionKind]reflect.Type
    47  
    48  	// typeToGroupVersion allows one to find metadata for a given go object.
    49  	// The reflect.Type we index by should *not* be a pointer.
    50  	typeToGVK map[reflect.Type][]unversioned.GroupVersionKind
    51  
    52  	// unversionedTypes are transformed without conversion in ConvertToVersion.
    53  	unversionedTypes map[reflect.Type]unversioned.GroupVersionKind
    54  
    55  	// unversionedKinds are the names of kinds that can be created in the context of any group
    56  	// or version
    57  	// TODO: resolve the status of unversioned types.
    58  	unversionedKinds map[string]reflect.Type
    59  
    60  	// Map from version and resource to the corresponding func to convert
    61  	// resource field labels in that version to internal version.
    62  	fieldLabelConversionFuncs map[string]map[string]FieldLabelConversionFunc
    63  
    64  	// converter stores all registered conversion functions. It also has
    65  	// default coverting behavior.
    66  	converter *conversion.Converter
    67  
    68  	// cloner stores all registered copy functions. It also has default
    69  	// deep copy behavior.
    70  	cloner *conversion.Cloner
    71  }
    72  
    73  // Function to convert a field selector to internal representation.
    74  type FieldLabelConversionFunc func(label, value string) (internalLabel, internalValue string, err error)
    75  
    76  // NewScheme creates a new Scheme. This scheme is pluggable by default.
    77  func NewScheme() *Scheme {
    78  	s := &Scheme{
    79  		gvkToType:        map[unversioned.GroupVersionKind]reflect.Type{},
    80  		typeToGVK:        map[reflect.Type][]unversioned.GroupVersionKind{},
    81  		unversionedTypes: map[reflect.Type]unversioned.GroupVersionKind{},
    82  		unversionedKinds: map[string]reflect.Type{},
    83  		cloner:           conversion.NewCloner(),
    84  		fieldLabelConversionFuncs: map[string]map[string]FieldLabelConversionFunc{},
    85  	}
    86  	s.converter = conversion.NewConverter(s.nameFunc)
    87  
    88  	s.AddConversionFuncs(DefaultEmbeddedConversions()...)
    89  
    90  	// Enable map[string][]string conversions by default
    91  	if err := s.AddConversionFuncs(DefaultStringConversions...); err != nil {
    92  		panic(err)
    93  	}
    94  	if err := s.RegisterInputDefaults(&map[string][]string{}, JSONKeyMapper, conversion.AllowDifferentFieldTypeNames|conversion.IgnoreMissingFields); err != nil {
    95  		panic(err)
    96  	}
    97  	if err := s.RegisterInputDefaults(&url.Values{}, JSONKeyMapper, conversion.AllowDifferentFieldTypeNames|conversion.IgnoreMissingFields); err != nil {
    98  		panic(err)
    99  	}
   100  	return s
   101  }
   102  
   103  // nameFunc returns the name of the type that we wish to use to determine when two types attempt
   104  // a conversion. Defaults to the go name of the type if the type is not registered.
   105  func (s *Scheme) nameFunc(t reflect.Type) string {
   106  	// find the preferred names for this type
   107  	gvks, ok := s.typeToGVK[t]
   108  	if !ok {
   109  		return t.Name()
   110  	}
   111  
   112  	for _, gvk := range gvks {
   113  		internalGV := gvk.GroupVersion()
   114  		internalGV.Version = "__internal" // this is hacky and maybe should be passed in
   115  		internalGVK := internalGV.WithKind(gvk.Kind)
   116  
   117  		if internalType, exists := s.gvkToType[internalGVK]; exists {
   118  			return s.typeToGVK[internalType][0].Kind
   119  		}
   120  	}
   121  
   122  	return gvks[0].Kind
   123  }
   124  
   125  // fromScope gets the input version, desired output version, and desired Scheme
   126  // from a conversion.Scope.
   127  func (s *Scheme) fromScope(scope conversion.Scope) *Scheme {
   128  	return s
   129  }
   130  
   131  // Converter allows access to the converter for the scheme
   132  func (s *Scheme) Converter() *conversion.Converter {
   133  	return s.converter
   134  }
   135  
   136  // AddUnversionedTypes registers the provided types as "unversioned", which means that they follow special rules.
   137  // Whenever an object of this type is serialized, it is serialized with the provided group version and is not
   138  // converted. Thus unversioned objects are expected to remain backwards compatible forever, as if they were in an
   139  // API group and version that would never be updated.
   140  //
   141  // TODO: there is discussion about removing unversioned and replacing it with objects that are manifest into
   142  //   every version with particular schemas. Resolve this method at that point.
   143  func (s *Scheme) AddUnversionedTypes(version unversioned.GroupVersion, types ...Object) {
   144  	s.AddKnownTypes(version, types...)
   145  	for _, obj := range types {
   146  		t := reflect.TypeOf(obj).Elem()
   147  		gvk := version.WithKind(t.Name())
   148  		s.unversionedTypes[t] = gvk
   149  		if _, ok := s.unversionedKinds[gvk.Kind]; ok {
   150  			panic(fmt.Sprintf("%v has already been registered as unversioned kind %q - kind name must be unique", reflect.TypeOf(t), gvk.Kind))
   151  		}
   152  		s.unversionedKinds[gvk.Kind] = t
   153  	}
   154  }
   155  
   156  // AddKnownTypes registers all types passed in 'types' as being members of version 'version'.
   157  // All objects passed to types should be pointers to structs. The name that go reports for
   158  // the struct becomes the "kind" field when encoding. Version may not be empty - use the
   159  // APIVersionInternal constant if you have a type that does not have a formal version.
   160  func (s *Scheme) AddKnownTypes(gv unversioned.GroupVersion, types ...Object) {
   161  	if len(gv.Version) == 0 {
   162  		panic(fmt.Sprintf("version is required on all types: %s %v", gv, types[0]))
   163  	}
   164  	for _, obj := range types {
   165  		t := reflect.TypeOf(obj)
   166  		if t.Kind() != reflect.Ptr {
   167  			panic("All types must be pointers to structs.")
   168  		}
   169  		t = t.Elem()
   170  		if t.Kind() != reflect.Struct {
   171  			panic("All types must be pointers to structs.")
   172  		}
   173  
   174  		gvk := gv.WithKind(t.Name())
   175  		s.gvkToType[gvk] = t
   176  		s.typeToGVK[t] = append(s.typeToGVK[t], gvk)
   177  	}
   178  }
   179  
   180  // AddKnownTypeWithName is like AddKnownTypes, but it lets you specify what this type should
   181  // be encoded as. Useful for testing when you don't want to make multiple packages to define
   182  // your structs. Version may not be empty - use the APIVersionInternal constant if you have a
   183  // type that does not have a formal version.
   184  func (s *Scheme) AddKnownTypeWithName(gvk unversioned.GroupVersionKind, obj Object) {
   185  	t := reflect.TypeOf(obj)
   186  	if len(gvk.Version) == 0 {
   187  		panic(fmt.Sprintf("version is required on all types: %s %v", gvk, t))
   188  	}
   189  	if t.Kind() != reflect.Ptr {
   190  		panic("All types must be pointers to structs.")
   191  	}
   192  	t = t.Elem()
   193  	if t.Kind() != reflect.Struct {
   194  		panic("All types must be pointers to structs.")
   195  	}
   196  
   197  	s.gvkToType[gvk] = t
   198  	s.typeToGVK[t] = append(s.typeToGVK[t], gvk)
   199  }
   200  
   201  // KnownTypes returns the types known for the given version.
   202  func (s *Scheme) KnownTypes(gv unversioned.GroupVersion) map[string]reflect.Type {
   203  	types := make(map[string]reflect.Type)
   204  	for gvk, t := range s.gvkToType {
   205  		if gv != gvk.GroupVersion() {
   206  			continue
   207  		}
   208  
   209  		types[gvk.Kind] = t
   210  	}
   211  	return types
   212  }
   213  
   214  // ObjectKind returns the group,version,kind of the go object,
   215  // or an error if it's not a pointer or is unregistered.
   216  func (s *Scheme) ObjectKind(obj Object) (unversioned.GroupVersionKind, error) {
   217  	gvks, err := s.ObjectKinds(obj)
   218  	if err != nil {
   219  		return unversioned.GroupVersionKind{}, err
   220  	}
   221  	return gvks[0], nil
   222  }
   223  
   224  // ObjectKinds returns all possible group,version,kind of the go object,
   225  // or an error if it's not a pointer or is unregistered.
   226  func (s *Scheme) ObjectKinds(obj Object) ([]unversioned.GroupVersionKind, error) {
   227  	v, err := conversion.EnforcePtr(obj)
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  	t := v.Type()
   232  
   233  	gvks, ok := s.typeToGVK[t]
   234  	if !ok {
   235  		return nil, &notRegisteredErr{t: t}
   236  	}
   237  
   238  	return gvks, nil
   239  }
   240  
   241  // Recognizes returns true if the scheme is able to handle the provided group,version,kind
   242  // of an object.
   243  func (s *Scheme) Recognizes(gvk unversioned.GroupVersionKind) bool {
   244  	_, exists := s.gvkToType[gvk]
   245  	return exists
   246  }
   247  
   248  func (s *Scheme) IsUnversioned(obj Object) (bool, bool) {
   249  	v, err := conversion.EnforcePtr(obj)
   250  	if err != nil {
   251  		return false, false
   252  	}
   253  	t := v.Type()
   254  
   255  	if _, ok := s.typeToGVK[t]; !ok {
   256  		return false, false
   257  	}
   258  	_, ok := s.unversionedTypes[t]
   259  	return ok, true
   260  }
   261  
   262  // New returns a new API object of the given version and name, or an error if it hasn't
   263  // been registered. The version and kind fields must be specified.
   264  func (s *Scheme) New(kind unversioned.GroupVersionKind) (Object, error) {
   265  	if t, exists := s.gvkToType[kind]; exists {
   266  		return reflect.New(t).Interface().(Object), nil
   267  	}
   268  
   269  	if t, exists := s.unversionedKinds[kind.Kind]; exists {
   270  		return reflect.New(t).Interface().(Object), nil
   271  	}
   272  	return nil, &notRegisteredErr{gvk: kind}
   273  }
   274  
   275  // AddGenericConversionFunc adds a function that accepts the ConversionFunc call pattern
   276  // (for two conversion types) to the converter. These functions are checked first during
   277  // a normal conversion, but are otherwise not called. Use AddConversionFuncs when registering
   278  // typed conversions.
   279  func (s *Scheme) AddGenericConversionFunc(fn conversion.GenericConversionFunc) {
   280  	s.converter.AddGenericConversionFunc(fn)
   281  }
   282  
   283  // Log sets a logger on the scheme. For test purposes only
   284  func (s *Scheme) Log(l conversion.DebugLogger) {
   285  	s.converter.Debug = l
   286  }
   287  
   288  // AddIgnoredConversionType identifies a pair of types that should be skipped by
   289  // conversion (because the data inside them is explicitly dropped during
   290  // conversion).
   291  func (s *Scheme) AddIgnoredConversionType(from, to interface{}) error {
   292  	return s.converter.RegisterIgnoredConversion(from, to)
   293  }
   294  
   295  // AddConversionFuncs adds functions to the list of conversion functions. The given
   296  // functions should know how to convert between two of your API objects, or their
   297  // sub-objects. We deduce how to call these functions from the types of their two
   298  // parameters; see the comment for Converter.Register.
   299  //
   300  // Note that, if you need to copy sub-objects that didn't change, you can use the
   301  // conversion.Scope object that will be passed to your conversion function.
   302  // Additionally, all conversions started by Scheme will set the SrcVersion and
   303  // DestVersion fields on the Meta object. Example:
   304  //
   305  // s.AddConversionFuncs(
   306  //	func(in *InternalObject, out *ExternalObject, scope conversion.Scope) error {
   307  //		// You can depend on Meta() being non-nil, and this being set to
   308  //		// the source version, e.g., ""
   309  //		s.Meta().SrcVersion
   310  //		// You can depend on this being set to the destination version,
   311  //		// e.g., "v1".
   312  //		s.Meta().DestVersion
   313  //		// Call scope.Convert to copy sub-fields.
   314  //		s.Convert(&in.SubFieldThatMoved, &out.NewLocation.NewName, 0)
   315  //		return nil
   316  //	},
   317  // )
   318  //
   319  // (For more detail about conversion functions, see Converter.Register's comment.)
   320  //
   321  // Also note that the default behavior, if you don't add a conversion function, is to
   322  // sanely copy fields that have the same names and same type names. It's OK if the
   323  // destination type has extra fields, but it must not remove any. So you only need to
   324  // add conversion functions for things with changed/removed fields.
   325  func (s *Scheme) AddConversionFuncs(conversionFuncs ...interface{}) error {
   326  	for _, f := range conversionFuncs {
   327  		if err := s.converter.RegisterConversionFunc(f); err != nil {
   328  			return err
   329  		}
   330  	}
   331  	return nil
   332  }
   333  
   334  // Similar to AddConversionFuncs, but registers conversion functions that were
   335  // automatically generated.
   336  func (s *Scheme) AddGeneratedConversionFuncs(conversionFuncs ...interface{}) error {
   337  	for _, f := range conversionFuncs {
   338  		if err := s.converter.RegisterGeneratedConversionFunc(f); err != nil {
   339  			return err
   340  		}
   341  	}
   342  	return nil
   343  }
   344  
   345  // AddDeepCopyFuncs adds a function to the list of deep-copy functions.
   346  // For the expected format of deep-copy function, see the comment for
   347  // Copier.RegisterDeepCopyFunction.
   348  func (s *Scheme) AddDeepCopyFuncs(deepCopyFuncs ...interface{}) error {
   349  	for _, f := range deepCopyFuncs {
   350  		if err := s.cloner.RegisterDeepCopyFunc(f); err != nil {
   351  			return err
   352  		}
   353  	}
   354  	return nil
   355  }
   356  
   357  // Similar to AddDeepCopyFuncs, but registers deep-copy functions that were
   358  // automatically generated.
   359  func (s *Scheme) AddGeneratedDeepCopyFuncs(deepCopyFuncs ...interface{}) error {
   360  	for _, f := range deepCopyFuncs {
   361  		if err := s.cloner.RegisterGeneratedDeepCopyFunc(f); err != nil {
   362  			return err
   363  		}
   364  	}
   365  	return nil
   366  }
   367  
   368  // AddFieldLabelConversionFunc adds a conversion function to convert field selectors
   369  // of the given kind from the given version to internal version representation.
   370  func (s *Scheme) AddFieldLabelConversionFunc(version, kind string, conversionFunc FieldLabelConversionFunc) error {
   371  	if s.fieldLabelConversionFuncs[version] == nil {
   372  		s.fieldLabelConversionFuncs[version] = map[string]FieldLabelConversionFunc{}
   373  	}
   374  
   375  	s.fieldLabelConversionFuncs[version][kind] = conversionFunc
   376  	return nil
   377  }
   378  
   379  // AddStructFieldConversion allows you to specify a mechanical copy for a moved
   380  // or renamed struct field without writing an entire conversion function. See
   381  // the comment in conversion.Converter.SetStructFieldCopy for parameter details.
   382  // Call as many times as needed, even on the same fields.
   383  func (s *Scheme) AddStructFieldConversion(srcFieldType interface{}, srcFieldName string, destFieldType interface{}, destFieldName string) error {
   384  	return s.converter.SetStructFieldCopy(srcFieldType, srcFieldName, destFieldType, destFieldName)
   385  }
   386  
   387  // RegisterInputDefaults sets the provided field mapping function and field matching
   388  // as the defaults for the provided input type.  The fn may be nil, in which case no
   389  // mapping will happen by default. Use this method to register a mechanism for handling
   390  // a specific input type in conversion, such as a map[string]string to structs.
   391  func (s *Scheme) RegisterInputDefaults(in interface{}, fn conversion.FieldMappingFunc, defaultFlags conversion.FieldMatchingFlags) error {
   392  	return s.converter.RegisterInputDefaults(in, fn, defaultFlags)
   393  }
   394  
   395  // AddDefaultingFuncs adds functions to the list of default-value functions.
   396  // Each of the given functions is responsible for applying default values
   397  // when converting an instance of a versioned API object into an internal
   398  // API object.  These functions do not need to handle sub-objects. We deduce
   399  // how to call these functions from the types of their two parameters.
   400  //
   401  // s.AddDefaultingFuncs(
   402  //	func(obj *v1.Pod) {
   403  //		if obj.OptionalField == "" {
   404  //			obj.OptionalField = "DefaultValue"
   405  //		}
   406  //	},
   407  // )
   408  func (s *Scheme) AddDefaultingFuncs(defaultingFuncs ...interface{}) error {
   409  	for _, f := range defaultingFuncs {
   410  		err := s.converter.RegisterDefaultingFunc(f)
   411  		if err != nil {
   412  			return err
   413  		}
   414  	}
   415  	return nil
   416  }
   417  
   418  // Copy does a deep copy of an API object.
   419  func (s *Scheme) Copy(src Object) (Object, error) {
   420  	dst, err := s.DeepCopy(src)
   421  	if err != nil {
   422  		return nil, err
   423  	}
   424  	return dst.(Object), nil
   425  }
   426  
   427  // Performs a deep copy of the given object.
   428  func (s *Scheme) DeepCopy(src interface{}) (interface{}, error) {
   429  	return s.cloner.DeepCopy(src)
   430  }
   431  
   432  // Convert will attempt to convert in into out. Both must be pointers. For easy
   433  // testing of conversion functions. Returns an error if the conversion isn't
   434  // possible. You can call this with types that haven't been registered (for example,
   435  // a to test conversion of types that are nested within registered types), but in
   436  // that case, the conversion.Scope object passed to your conversion functions won't
   437  // have SrcVersion or DestVersion fields set correctly in Meta().
   438  func (s *Scheme) Convert(in, out interface{}) error {
   439  	inVersion := unversioned.GroupVersion{Group: "unknown", Version: "unknown"}
   440  	outVersion := unversioned.GroupVersion{Group: "unknown", Version: "unknown"}
   441  	if inObj, ok := in.(Object); ok {
   442  		if gvk, err := s.ObjectKind(inObj); err == nil {
   443  			inVersion = gvk.GroupVersion()
   444  		}
   445  	}
   446  	if outObj, ok := out.(Object); ok {
   447  		if gvk, err := s.ObjectKind(outObj); err == nil {
   448  			outVersion = gvk.GroupVersion()
   449  		}
   450  	}
   451  	flags, meta := s.generateConvertMeta(inVersion, outVersion, in)
   452  	if flags == 0 {
   453  		flags = conversion.AllowDifferentFieldTypeNames
   454  	}
   455  	return s.converter.Convert(in, out, flags, meta)
   456  }
   457  
   458  // Converts the given field label and value for an kind field selector from
   459  // versioned representation to an unversioned one.
   460  func (s *Scheme) ConvertFieldLabel(version, kind, label, value string) (string, string, error) {
   461  	if s.fieldLabelConversionFuncs[version] == nil {
   462  		return "", "", fmt.Errorf("No field label conversion function found for version: %s", version)
   463  	}
   464  	conversionFunc, ok := s.fieldLabelConversionFuncs[version][kind]
   465  	if !ok {
   466  		return "", "", fmt.Errorf("No field label conversion function found for version %s and kind %s", version, kind)
   467  	}
   468  	return conversionFunc(label, value)
   469  }
   470  
   471  // ConvertToVersion attempts to convert an input object to its matching Kind in another
   472  // version within this scheme. Will return an error if the provided version does not
   473  // contain the inKind (or a mapping by name defined with AddKnownTypeWithName). Will also
   474  // return an error if the conversion does not result in a valid Object being
   475  // returned. The serializer handles loading/serializing nested objects.
   476  func (s *Scheme) ConvertToVersion(in Object, outVersion unversioned.GroupVersion) (Object, error) {
   477  	switch in.(type) {
   478  	case *Unknown, *Unstructured, *UnstructuredList:
   479  		old := in.GetObjectKind().GroupVersionKind()
   480  		defer in.GetObjectKind().SetGroupVersionKind(old)
   481  		setTargetVersion(in, s, outVersion)
   482  		return in, nil
   483  	}
   484  	t := reflect.TypeOf(in)
   485  	if t.Kind() != reflect.Ptr {
   486  		return nil, fmt.Errorf("only pointer types may be converted: %v", t)
   487  	}
   488  
   489  	t = t.Elem()
   490  	if t.Kind() != reflect.Struct {
   491  		return nil, fmt.Errorf("only pointers to struct types may be converted: %v", t)
   492  	}
   493  
   494  	var kind unversioned.GroupVersionKind
   495  	if unversionedKind, ok := s.unversionedTypes[t]; ok {
   496  		kind = unversionedKind
   497  	} else {
   498  		kinds, ok := s.typeToGVK[t]
   499  		if !ok || len(kinds) == 0 {
   500  			return nil, fmt.Errorf("%v is not a registered type and cannot be converted into version %q", t, outVersion)
   501  		}
   502  		kind = kinds[0]
   503  	}
   504  
   505  	outKind := outVersion.WithKind(kind.Kind)
   506  
   507  	inKind, err := s.ObjectKind(in)
   508  	if err != nil {
   509  		return nil, err
   510  	}
   511  
   512  	out, err := s.New(outKind)
   513  	if err != nil {
   514  		return nil, err
   515  	}
   516  
   517  	flags, meta := s.generateConvertMeta(inKind.GroupVersion(), outVersion, in)
   518  	if err := s.converter.Convert(in, out, flags, meta); err != nil {
   519  		return nil, err
   520  	}
   521  
   522  	setTargetVersion(out, s, outVersion)
   523  	return out, nil
   524  }
   525  
   526  // UnsafeConvertToVersion will convert in to the provided outVersion if such a conversion is possible,
   527  // but does not guarantee the output object does not share fields with the input object. It attempts to be as
   528  // efficient as possible when doing conversion.
   529  func (s *Scheme) UnsafeConvertToVersion(in Object, outVersion unversioned.GroupVersion) (Object, error) {
   530  	switch t := in.(type) {
   531  	case *Unknown:
   532  		t.APIVersion = outVersion.String()
   533  		return t, nil
   534  	case *Unstructured:
   535  		t.SetAPIVersion(outVersion.String())
   536  		return t, nil
   537  	case *UnstructuredList:
   538  		t.SetAPIVersion(outVersion.String())
   539  		return t, nil
   540  	}
   541  
   542  	// determine the incoming kinds with as few allocations as possible.
   543  	t := reflect.TypeOf(in)
   544  	if t.Kind() != reflect.Ptr {
   545  		return nil, fmt.Errorf("only pointer types may be converted: %v", t)
   546  	}
   547  	t = t.Elem()
   548  	if t.Kind() != reflect.Struct {
   549  		return nil, fmt.Errorf("only pointers to struct types may be converted: %v", t)
   550  	}
   551  	kinds, ok := s.typeToGVK[t]
   552  	if !ok || len(kinds) == 0 {
   553  		return nil, fmt.Errorf("%v is not a registered type and cannot be converted into version %q", t, outVersion)
   554  	}
   555  
   556  	// if the Go type is also registered to the destination kind, no conversion is necessary
   557  	for i := range kinds {
   558  		if kinds[i].Version == outVersion.Version && kinds[i].Group == outVersion.Group {
   559  			setTargetKind(in, kinds[i])
   560  			return in, nil
   561  		}
   562  	}
   563  
   564  	// type is unversioned, no conversion necessary
   565  	// it should be possible to avoid this allocation
   566  	if unversionedKind, ok := s.unversionedTypes[t]; ok {
   567  		kind := unversionedKind
   568  		outKind := outVersion.WithKind(kind.Kind)
   569  		setTargetKind(in, outKind)
   570  		return in, nil
   571  	}
   572  
   573  	// allocate a new object as the target using the target kind
   574  	// TODO: this should look in the target group version and find the first kind that matches, rather than the
   575  	//   first kind registered in typeToGVK
   576  	kind := kinds[0]
   577  	kind.Version = outVersion.Version
   578  	kind.Group = outVersion.Group
   579  	out, err := s.New(kind)
   580  	if err != nil {
   581  		return nil, err
   582  	}
   583  
   584  	// TODO: try to avoid the allocations here - in fast paths we are not likely to need these flags or meta
   585  	flags, meta := s.converter.DefaultMeta(t)
   586  	if err := s.converter.Convert(in, out, flags, meta); err != nil {
   587  		return nil, err
   588  	}
   589  
   590  	setTargetKind(out, kind)
   591  	return out, nil
   592  }
   593  
   594  // generateConvertMeta constructs the meta value we pass to Convert.
   595  func (s *Scheme) generateConvertMeta(srcGroupVersion, destGroupVersion unversioned.GroupVersion, in interface{}) (conversion.FieldMatchingFlags, *conversion.Meta) {
   596  	return s.converter.DefaultMeta(reflect.TypeOf(in))
   597  }
   598  
   599  // setTargetVersion is deprecated and should be replaced by use of setTargetKind
   600  func setTargetVersion(obj Object, raw *Scheme, gv unversioned.GroupVersion) {
   601  	if gv.Version == APIVersionInternal {
   602  		// internal is a special case
   603  		obj.GetObjectKind().SetGroupVersionKind(unversioned.GroupVersionKind{})
   604  		return
   605  	}
   606  	gvk, _ := raw.ObjectKind(obj)
   607  	obj.GetObjectKind().SetGroupVersionKind(unversioned.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: gvk.Kind})
   608  }
   609  
   610  // setTargetKind sets the kind on an object, taking into account whether the target kind is the internal version.
   611  func setTargetKind(obj Object, kind unversioned.GroupVersionKind) {
   612  	if kind.Version == APIVersionInternal {
   613  		// internal is a special case
   614  		// TODO: look at removing the need to special case this
   615  		obj.GetObjectKind().SetGroupVersionKind(unversioned.GroupVersionKind{})
   616  		return
   617  	}
   618  	obj.GetObjectKind().SetGroupVersionKind(kind)
   619  }