scheme.go 22 KB

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