scheme.go 21 KB

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