scheme.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  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. "reflect"
  17. "strings"
  18. "k8s.io/apimachinery/pkg/conversion"
  19. "k8s.io/apimachinery/pkg/runtime/schema"
  20. "k8s.io/apimachinery/pkg/util/naming"
  21. utilruntime "k8s.io/apimachinery/pkg/util/runtime"
  22. "k8s.io/apimachinery/pkg/util/sets"
  23. )
  24. // Scheme defines methods for serializing and deserializing API objects, a type
  25. // registry for converting group, version, and kind information to and from Go
  26. // schemas, and mappings between Go schemas of different versions. A scheme is the
  27. // foundation for a versioned API and versioned configuration over time.
  28. //
  29. // In a Scheme, a Type is a particular Go struct, a Version is a point-in-time
  30. // identifier for a particular representation of that Type (typically backwards
  31. // compatible), a Kind is the unique name for that Type within the Version, and a
  32. // Group identifies a set of Versions, Kinds, and Types that evolve over time. An
  33. // Unversioned Type is one that is not yet formally bound to a type and is promised
  34. // to be backwards compatible (effectively a "v1" of a Type that does not expect
  35. // to break in the future).
  36. //
  37. // Schemes are not expected to change at runtime and are only threadsafe after
  38. // registration is complete.
  39. type Scheme struct {
  40. // gvkToType allows one to figure out the go type of an object with
  41. // the given version and name.
  42. gvkToType map[schema.GroupVersionKind]reflect.Type
  43. // typeToGVK allows one to find metadata for a given go object.
  44. // The reflect.Type we index by should *not* be a pointer.
  45. typeToGVK map[reflect.Type][]schema.GroupVersionKind
  46. // unversionedTypes are transformed without conversion in ConvertToVersion.
  47. unversionedTypes map[reflect.Type]schema.GroupVersionKind
  48. // unversionedKinds are the names of kinds that can be created in the context of any group
  49. // or version
  50. // TODO: resolve the status of unversioned types.
  51. unversionedKinds map[string]reflect.Type
  52. // Map from version and resource to the corresponding func to convert
  53. // resource field labels in that version to internal version.
  54. fieldLabelConversionFuncs map[schema.GroupVersionKind]FieldLabelConversionFunc
  55. // defaulterFuncs is a map to funcs to be called with an object to provide defaulting
  56. // the provided object must be a pointer.
  57. defaulterFuncs map[reflect.Type]func(interface{})
  58. // converter stores all registered conversion functions. It also has
  59. // default converting behavior.
  60. converter *conversion.Converter
  61. // versionPriority is a map of groups to ordered lists of versions for those groups indicating the
  62. // default priorities of these versions as registered in the scheme
  63. versionPriority map[string][]string
  64. // observedVersions keeps track of the order we've seen versions during type registration
  65. observedVersions []schema.GroupVersion
  66. // schemeName is the name of this scheme. If you don't specify a name, the stack of the NewScheme caller will be used.
  67. // This is useful for error reporting to indicate the origin of the scheme.
  68. schemeName string
  69. }
  70. // FieldLabelConversionFunc converts a field selector to internal representation.
  71. type FieldLabelConversionFunc func(label, value string) (internalLabel, internalValue string, err error)
  72. // NewScheme creates a new Scheme. This scheme is pluggable by default.
  73. func NewScheme() *Scheme {
  74. s := &Scheme{
  75. gvkToType: map[schema.GroupVersionKind]reflect.Type{},
  76. typeToGVK: map[reflect.Type][]schema.GroupVersionKind{},
  77. unversionedTypes: map[reflect.Type]schema.GroupVersionKind{},
  78. unversionedKinds: map[string]reflect.Type{},
  79. fieldLabelConversionFuncs: map[schema.GroupVersionKind]FieldLabelConversionFunc{},
  80. defaulterFuncs: map[reflect.Type]func(interface{}){},
  81. versionPriority: map[string][]string{},
  82. schemeName: naming.GetNameFromCallsite(internalPackages...),
  83. }
  84. s.converter = conversion.NewConverter(nil)
  85. // Enable couple default conversions by default.
  86. utilruntime.Must(RegisterEmbeddedConversions(s))
  87. utilruntime.Must(RegisterStringConversions(s))
  88. return s
  89. }
  90. // Converter allows access to the converter for the scheme
  91. func (s *Scheme) Converter() *conversion.Converter {
  92. return s.converter
  93. }
  94. // AddUnversionedTypes registers the provided types as "unversioned", which means that they follow special rules.
  95. // Whenever an object of this type is serialized, it is serialized with the provided group version and is not
  96. // converted. Thus unversioned objects are expected to remain backwards compatible forever, as if they were in an
  97. // API group and version that would never be updated.
  98. //
  99. // TODO: there is discussion about removing unversioned and replacing it with objects that are manifest into
  100. // every version with particular schemas. Resolve this method at that point.
  101. func (s *Scheme) AddUnversionedTypes(version schema.GroupVersion, types ...Object) {
  102. s.addObservedVersion(version)
  103. s.AddKnownTypes(version, types...)
  104. for _, obj := range types {
  105. t := reflect.TypeOf(obj).Elem()
  106. gvk := version.WithKind(t.Name())
  107. s.unversionedTypes[t] = gvk
  108. if old, ok := s.unversionedKinds[gvk.Kind]; ok && t != old {
  109. panic(fmt.Sprintf("%v.%v has already been registered as unversioned kind %q - kind name must be unique in scheme %q", old.PkgPath(), old.Name(), gvk, s.schemeName))
  110. }
  111. s.unversionedKinds[gvk.Kind] = t
  112. }
  113. }
  114. // AddKnownTypes registers all types passed in 'types' as being members of version 'version'.
  115. // All objects passed to types should be pointers to structs. The name that go reports for
  116. // the struct becomes the "kind" field when encoding. Version may not be empty - use the
  117. // APIVersionInternal constant if you have a type that does not have a formal version.
  118. func (s *Scheme) AddKnownTypes(gv schema.GroupVersion, types ...Object) {
  119. s.addObservedVersion(gv)
  120. for _, obj := range types {
  121. t := reflect.TypeOf(obj)
  122. if t.Kind() != reflect.Pointer {
  123. panic("All types must be pointers to structs.")
  124. }
  125. t = t.Elem()
  126. s.AddKnownTypeWithName(gv.WithKind(t.Name()), obj)
  127. }
  128. }
  129. // AddKnownTypeWithName is like AddKnownTypes, but it lets you specify what this type should
  130. // be encoded as. Useful for testing when you don't want to make multiple packages to define
  131. // your structs. Version may not be empty - use the APIVersionInternal constant if you have a
  132. // type that does not have a formal version.
  133. func (s *Scheme) AddKnownTypeWithName(gvk schema.GroupVersionKind, obj Object) {
  134. s.addObservedVersion(gvk.GroupVersion())
  135. t := reflect.TypeOf(obj)
  136. if len(gvk.Version) == 0 {
  137. panic(fmt.Sprintf("version is required on all types: %s %v", gvk, t))
  138. }
  139. if t.Kind() != reflect.Pointer {
  140. panic("All types must be pointers to structs.")
  141. }
  142. t = t.Elem()
  143. if t.Kind() != reflect.Struct {
  144. panic("All types must be pointers to structs.")
  145. }
  146. if oldT, found := s.gvkToType[gvk]; found && oldT != t {
  147. panic(fmt.Sprintf("Double registration of different types for %v: old=%v.%v, new=%v.%v in scheme %q", gvk, oldT.PkgPath(), oldT.Name(), t.PkgPath(), t.Name(), s.schemeName))
  148. }
  149. s.gvkToType[gvk] = t
  150. for _, existingGvk := range s.typeToGVK[t] {
  151. if existingGvk == gvk {
  152. return
  153. }
  154. }
  155. s.typeToGVK[t] = append(s.typeToGVK[t], gvk)
  156. // if the type implements DeepCopyInto(<obj>), register a self-conversion
  157. if m := reflect.ValueOf(obj).MethodByName("DeepCopyInto"); m.IsValid() && m.Type().NumIn() == 1 && m.Type().NumOut() == 0 && m.Type().In(0) == reflect.TypeOf(obj) {
  158. if err := s.AddGeneratedConversionFunc(obj, obj, func(a, b interface{}, scope conversion.Scope) error {
  159. // copy a to b
  160. reflect.ValueOf(a).MethodByName("DeepCopyInto").Call([]reflect.Value{reflect.ValueOf(b)})
  161. // clear TypeMeta to match legacy reflective conversion
  162. b.(Object).GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{})
  163. return nil
  164. }); err != nil {
  165. panic(err)
  166. }
  167. }
  168. }
  169. // KnownTypes returns the types known for the given version.
  170. func (s *Scheme) KnownTypes(gv schema.GroupVersion) map[string]reflect.Type {
  171. types := make(map[string]reflect.Type)
  172. for gvk, t := range s.gvkToType {
  173. if gv != gvk.GroupVersion() {
  174. continue
  175. }
  176. types[gvk.Kind] = t
  177. }
  178. return types
  179. }
  180. // VersionsForGroupKind returns the versions that a particular GroupKind can be converted to within the given group.
  181. // A GroupKind might be converted to a different group. That information is available in EquivalentResourceMapper.
  182. func (s *Scheme) VersionsForGroupKind(gk schema.GroupKind) []schema.GroupVersion {
  183. availableVersions := []schema.GroupVersion{}
  184. for gvk := range s.gvkToType {
  185. if gk != gvk.GroupKind() {
  186. continue
  187. }
  188. availableVersions = append(availableVersions, gvk.GroupVersion())
  189. }
  190. // order the return for stability
  191. ret := []schema.GroupVersion{}
  192. for _, version := range s.PrioritizedVersionsForGroup(gk.Group) {
  193. for _, availableVersion := range availableVersions {
  194. if version != availableVersion {
  195. continue
  196. }
  197. ret = append(ret, availableVersion)
  198. }
  199. }
  200. return ret
  201. }
  202. // AllKnownTypes returns the all known types.
  203. func (s *Scheme) AllKnownTypes() map[schema.GroupVersionKind]reflect.Type {
  204. return s.gvkToType
  205. }
  206. // ObjectKinds returns all possible group,version,kind of the go object, true if the
  207. // object is considered unversioned, or an error if it's not a pointer or is unregistered.
  208. func (s *Scheme) ObjectKinds(obj Object) ([]schema.GroupVersionKind, bool, error) {
  209. // Unstructured objects are always considered to have their declared GVK
  210. if _, ok := obj.(Unstructured); ok {
  211. // we require that the GVK be populated in order to recognize the object
  212. gvk := obj.GetObjectKind().GroupVersionKind()
  213. if len(gvk.Kind) == 0 {
  214. return nil, false, NewMissingKindErr("unstructured object has no kind")
  215. }
  216. if len(gvk.Version) == 0 {
  217. return nil, false, NewMissingVersionErr("unstructured object has no version")
  218. }
  219. return []schema.GroupVersionKind{gvk}, false, nil
  220. }
  221. v, err := conversion.EnforcePtr(obj)
  222. if err != nil {
  223. return nil, false, err
  224. }
  225. t := v.Type()
  226. gvks, ok := s.typeToGVK[t]
  227. if !ok {
  228. return nil, false, NewNotRegisteredErrForType(s.schemeName, t)
  229. }
  230. _, unversionedType := s.unversionedTypes[t]
  231. return gvks, unversionedType, nil
  232. }
  233. // Recognizes returns true if the scheme is able to handle the provided group,version,kind
  234. // of an object.
  235. func (s *Scheme) Recognizes(gvk schema.GroupVersionKind) bool {
  236. _, exists := s.gvkToType[gvk]
  237. return exists
  238. }
  239. func (s *Scheme) IsUnversioned(obj Object) (bool, bool) {
  240. v, err := conversion.EnforcePtr(obj)
  241. if err != nil {
  242. return false, false
  243. }
  244. t := v.Type()
  245. if _, ok := s.typeToGVK[t]; !ok {
  246. return false, false
  247. }
  248. _, ok := s.unversionedTypes[t]
  249. return ok, true
  250. }
  251. // New returns a new API object of the given version and name, or an error if it hasn't
  252. // been registered. The version and kind fields must be specified.
  253. func (s *Scheme) New(kind schema.GroupVersionKind) (Object, error) {
  254. if t, exists := s.gvkToType[kind]; exists {
  255. return reflect.New(t).Interface().(Object), nil
  256. }
  257. if t, exists := s.unversionedKinds[kind.Kind]; exists {
  258. return reflect.New(t).Interface().(Object), nil
  259. }
  260. return nil, NewNotRegisteredErrForKind(s.schemeName, kind)
  261. }
  262. // AddIgnoredConversionType identifies a pair of types that should be skipped by
  263. // conversion (because the data inside them is explicitly dropped during
  264. // conversion).
  265. func (s *Scheme) AddIgnoredConversionType(from, to interface{}) error {
  266. return s.converter.RegisterIgnoredConversion(from, to)
  267. }
  268. // AddConversionFunc registers a function that converts between a and b by passing objects of those
  269. // types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce
  270. // any other guarantee.
  271. func (s *Scheme) AddConversionFunc(a, b interface{}, fn conversion.ConversionFunc) error {
  272. return s.converter.RegisterUntypedConversionFunc(a, b, fn)
  273. }
  274. // AddGeneratedConversionFunc registers a function that converts between a and b by passing objects of those
  275. // types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce
  276. // any other guarantee.
  277. func (s *Scheme) AddGeneratedConversionFunc(a, b interface{}, fn conversion.ConversionFunc) error {
  278. return s.converter.RegisterGeneratedUntypedConversionFunc(a, b, fn)
  279. }
  280. // AddFieldLabelConversionFunc adds a conversion function to convert field selectors
  281. // of the given kind from the given version to internal version representation.
  282. func (s *Scheme) AddFieldLabelConversionFunc(gvk schema.GroupVersionKind, conversionFunc FieldLabelConversionFunc) error {
  283. s.fieldLabelConversionFuncs[gvk] = conversionFunc
  284. return nil
  285. }
  286. // AddTypeDefaultingFunc registers a function that is passed a pointer to an
  287. // object and can default fields on the object. These functions will be invoked
  288. // when Default() is called. The function will never be called unless the
  289. // defaulted object matches srcType. If this function is invoked twice with the
  290. // same srcType, the fn passed to the later call will be used instead.
  291. func (s *Scheme) AddTypeDefaultingFunc(srcType Object, fn func(interface{})) {
  292. s.defaulterFuncs[reflect.TypeOf(srcType)] = fn
  293. }
  294. // Default sets defaults on the provided Object.
  295. func (s *Scheme) Default(src Object) {
  296. if fn, ok := s.defaulterFuncs[reflect.TypeOf(src)]; ok {
  297. fn(src)
  298. }
  299. }
  300. // Convert will attempt to convert in into out. Both must be pointers. For easy
  301. // testing of conversion functions. Returns an error if the conversion isn't
  302. // possible. You can call this with types that haven't been registered (for example,
  303. // a to test conversion of types that are nested within registered types). The
  304. // context interface is passed to the convertor. Convert also supports Unstructured
  305. // types and will convert them intelligently.
  306. func (s *Scheme) Convert(in, out interface{}, context interface{}) error {
  307. unstructuredIn, okIn := in.(Unstructured)
  308. unstructuredOut, okOut := out.(Unstructured)
  309. switch {
  310. case okIn && okOut:
  311. // converting unstructured input to an unstructured output is a straight copy - unstructured
  312. // is a "smart holder" and the contents are passed by reference between the two objects
  313. unstructuredOut.SetUnstructuredContent(unstructuredIn.UnstructuredContent())
  314. return nil
  315. case okOut:
  316. // if the output is an unstructured object, use the standard Go type to unstructured
  317. // conversion. The object must not be internal.
  318. obj, ok := in.(Object)
  319. if !ok {
  320. return fmt.Errorf("unable to convert object type %T to Unstructured, must be a runtime.Object", in)
  321. }
  322. gvks, unversioned, err := s.ObjectKinds(obj)
  323. if err != nil {
  324. return err
  325. }
  326. gvk := gvks[0]
  327. // if no conversion is necessary, convert immediately
  328. if unversioned || gvk.Version != APIVersionInternal {
  329. content, err := DefaultUnstructuredConverter.ToUnstructured(in)
  330. if err != nil {
  331. return err
  332. }
  333. unstructuredOut.SetUnstructuredContent(content)
  334. unstructuredOut.GetObjectKind().SetGroupVersionKind(gvk)
  335. return nil
  336. }
  337. // attempt to convert the object to an external version first.
  338. target, ok := context.(GroupVersioner)
  339. if !ok {
  340. return fmt.Errorf("unable to convert the internal object type %T to Unstructured without providing a preferred version to convert to", in)
  341. }
  342. // Convert is implicitly unsafe, so we don't need to perform a safe conversion
  343. versioned, err := s.UnsafeConvertToVersion(obj, target)
  344. if err != nil {
  345. return err
  346. }
  347. content, err := DefaultUnstructuredConverter.ToUnstructured(versioned)
  348. if err != nil {
  349. return err
  350. }
  351. unstructuredOut.SetUnstructuredContent(content)
  352. return nil
  353. case okIn:
  354. // converting an unstructured object to any type is modeled by first converting
  355. // the input to a versioned type, then running standard conversions
  356. typed, err := s.unstructuredToTyped(unstructuredIn)
  357. if err != nil {
  358. return err
  359. }
  360. in = typed
  361. }
  362. meta := s.generateConvertMeta(in)
  363. meta.Context = context
  364. return s.converter.Convert(in, out, meta)
  365. }
  366. // ConvertFieldLabel alters the given field label and value for an kind field selector from
  367. // versioned representation to an unversioned one or returns an error.
  368. func (s *Scheme) ConvertFieldLabel(gvk schema.GroupVersionKind, label, value string) (string, string, error) {
  369. conversionFunc, ok := s.fieldLabelConversionFuncs[gvk]
  370. if !ok {
  371. return DefaultMetaV1FieldSelectorConversion(label, value)
  372. }
  373. return conversionFunc(label, value)
  374. }
  375. // ConvertToVersion attempts to convert an input object to its matching Kind in another
  376. // version within this scheme. Will return an error if the provided version does not
  377. // contain the inKind (or a mapping by name defined with AddKnownTypeWithName). Will also
  378. // return an error if the conversion does not result in a valid Object being
  379. // returned. Passes target down to the conversion methods as the Context on the scope.
  380. func (s *Scheme) ConvertToVersion(in Object, target GroupVersioner) (Object, error) {
  381. return s.convertToVersion(true, in, target)
  382. }
  383. // UnsafeConvertToVersion will convert in to the provided target if such a conversion is possible,
  384. // but does not guarantee the output object does not share fields with the input object. It attempts to be as
  385. // efficient as possible when doing conversion.
  386. func (s *Scheme) UnsafeConvertToVersion(in Object, target GroupVersioner) (Object, error) {
  387. return s.convertToVersion(false, in, target)
  388. }
  389. // convertToVersion handles conversion with an optional copy.
  390. func (s *Scheme) convertToVersion(copy bool, in Object, target GroupVersioner) (Object, error) {
  391. var t reflect.Type
  392. if u, ok := in.(Unstructured); ok {
  393. typed, err := s.unstructuredToTyped(u)
  394. if err != nil {
  395. return nil, err
  396. }
  397. in = typed
  398. // unstructuredToTyped returns an Object, which must be a pointer to a struct.
  399. t = reflect.TypeOf(in).Elem()
  400. } else {
  401. // determine the incoming kinds with as few allocations as possible.
  402. t = reflect.TypeOf(in)
  403. if t.Kind() != reflect.Pointer {
  404. return nil, fmt.Errorf("only pointer types may be converted: %v", t)
  405. }
  406. t = t.Elem()
  407. if t.Kind() != reflect.Struct {
  408. return nil, fmt.Errorf("only pointers to struct types may be converted: %v", t)
  409. }
  410. }
  411. kinds, ok := s.typeToGVK[t]
  412. if !ok || len(kinds) == 0 {
  413. return nil, NewNotRegisteredErrForType(s.schemeName, t)
  414. }
  415. gvk, ok := target.KindForGroupVersionKinds(kinds)
  416. if !ok {
  417. // try to see if this type is listed as unversioned (for legacy support)
  418. // TODO: when we move to server API versions, we should completely remove the unversioned concept
  419. if unversionedKind, ok := s.unversionedTypes[t]; ok {
  420. if gvk, ok := target.KindForGroupVersionKinds([]schema.GroupVersionKind{unversionedKind}); ok {
  421. return copyAndSetTargetKind(copy, in, gvk)
  422. }
  423. return copyAndSetTargetKind(copy, in, unversionedKind)
  424. }
  425. return nil, NewNotRegisteredErrForTarget(s.schemeName, t, target)
  426. }
  427. // target wants to use the existing type, set kind and return (no conversion necessary)
  428. for _, kind := range kinds {
  429. if gvk == kind {
  430. return copyAndSetTargetKind(copy, in, gvk)
  431. }
  432. }
  433. // type is unversioned, no conversion necessary
  434. if unversionedKind, ok := s.unversionedTypes[t]; ok {
  435. if gvk, ok := target.KindForGroupVersionKinds([]schema.GroupVersionKind{unversionedKind}); ok {
  436. return copyAndSetTargetKind(copy, in, gvk)
  437. }
  438. return copyAndSetTargetKind(copy, in, unversionedKind)
  439. }
  440. out, err := s.New(gvk)
  441. if err != nil {
  442. return nil, err
  443. }
  444. if copy {
  445. in = in.DeepCopyObject()
  446. }
  447. meta := s.generateConvertMeta(in)
  448. meta.Context = target
  449. if err := s.converter.Convert(in, out, meta); err != nil {
  450. return nil, err
  451. }
  452. setTargetKind(out, gvk)
  453. return out, nil
  454. }
  455. // unstructuredToTyped attempts to transform an unstructured object to a typed
  456. // object if possible. It will return an error if conversion is not possible, or the versioned
  457. // Go form of the object. Note that this conversion will lose fields.
  458. func (s *Scheme) unstructuredToTyped(in Unstructured) (Object, error) {
  459. // the type must be something we recognize
  460. gvks, _, err := s.ObjectKinds(in)
  461. if err != nil {
  462. return nil, err
  463. }
  464. typed, err := s.New(gvks[0])
  465. if err != nil {
  466. return nil, err
  467. }
  468. if err := DefaultUnstructuredConverter.FromUnstructured(in.UnstructuredContent(), typed); err != nil {
  469. return nil, fmt.Errorf("unable to convert unstructured object to %v: %v", gvks[0], err)
  470. }
  471. return typed, nil
  472. }
  473. // generateConvertMeta constructs the meta value we pass to Convert.
  474. func (s *Scheme) generateConvertMeta(in interface{}) *conversion.Meta {
  475. return s.converter.DefaultMeta(reflect.TypeOf(in))
  476. }
  477. // copyAndSetTargetKind performs a conditional copy before returning the object, or an error if copy was not successful.
  478. func copyAndSetTargetKind(copy bool, obj Object, kind schema.GroupVersionKind) (Object, error) {
  479. if copy {
  480. obj = obj.DeepCopyObject()
  481. }
  482. setTargetKind(obj, kind)
  483. return obj, nil
  484. }
  485. // setTargetKind sets the kind on an object, taking into account whether the target kind is the internal version.
  486. func setTargetKind(obj Object, kind schema.GroupVersionKind) {
  487. if kind.Version == APIVersionInternal {
  488. // internal is a special case
  489. // TODO: look at removing the need to special case this
  490. obj.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{})
  491. return
  492. }
  493. obj.GetObjectKind().SetGroupVersionKind(kind)
  494. }
  495. // SetVersionPriority allows specifying a precise order of priority. All specified versions must be in the same group,
  496. // and the specified order overwrites any previously specified order for this group
  497. func (s *Scheme) SetVersionPriority(versions ...schema.GroupVersion) error {
  498. groups := sets.String{}
  499. order := []string{}
  500. for _, version := range versions {
  501. if len(version.Version) == 0 || version.Version == APIVersionInternal {
  502. return fmt.Errorf("internal versions cannot be prioritized: %v", version)
  503. }
  504. groups.Insert(version.Group)
  505. order = append(order, version.Version)
  506. }
  507. if len(groups) != 1 {
  508. return fmt.Errorf("must register versions for exactly one group: %v", strings.Join(groups.List(), ", "))
  509. }
  510. s.versionPriority[groups.List()[0]] = order
  511. return nil
  512. }
  513. // PrioritizedVersionsForGroup returns versions for a single group in priority order
  514. func (s *Scheme) PrioritizedVersionsForGroup(group string) []schema.GroupVersion {
  515. ret := []schema.GroupVersion{}
  516. for _, version := range s.versionPriority[group] {
  517. ret = append(ret, schema.GroupVersion{Group: group, Version: version})
  518. }
  519. for _, observedVersion := range s.observedVersions {
  520. if observedVersion.Group != group {
  521. continue
  522. }
  523. found := false
  524. for _, existing := range ret {
  525. if existing == observedVersion {
  526. found = true
  527. break
  528. }
  529. }
  530. if !found {
  531. ret = append(ret, observedVersion)
  532. }
  533. }
  534. return ret
  535. }
  536. // PrioritizedVersionsAllGroups returns all known versions in their priority order. Groups are random, but
  537. // versions for a single group are prioritized
  538. func (s *Scheme) PrioritizedVersionsAllGroups() []schema.GroupVersion {
  539. ret := []schema.GroupVersion{}
  540. for group, versions := range s.versionPriority {
  541. for _, version := range versions {
  542. ret = append(ret, schema.GroupVersion{Group: group, Version: version})
  543. }
  544. }
  545. for _, observedVersion := range s.observedVersions {
  546. found := false
  547. for _, existing := range ret {
  548. if existing == observedVersion {
  549. found = true
  550. break
  551. }
  552. }
  553. if !found {
  554. ret = append(ret, observedVersion)
  555. }
  556. }
  557. return ret
  558. }
  559. // PreferredVersionAllGroups returns the most preferred version for every group.
  560. // group ordering is random.
  561. func (s *Scheme) PreferredVersionAllGroups() []schema.GroupVersion {
  562. ret := []schema.GroupVersion{}
  563. for group, versions := range s.versionPriority {
  564. for _, version := range versions {
  565. ret = append(ret, schema.GroupVersion{Group: group, Version: version})
  566. break
  567. }
  568. }
  569. for _, observedVersion := range s.observedVersions {
  570. found := false
  571. for _, existing := range ret {
  572. if existing.Group == observedVersion.Group {
  573. found = true
  574. break
  575. }
  576. }
  577. if !found {
  578. ret = append(ret, observedVersion)
  579. }
  580. }
  581. return ret
  582. }
  583. // IsGroupRegistered returns true if types for the group have been registered with the scheme
  584. func (s *Scheme) IsGroupRegistered(group string) bool {
  585. for _, observedVersion := range s.observedVersions {
  586. if observedVersion.Group == group {
  587. return true
  588. }
  589. }
  590. return false
  591. }
  592. // IsVersionRegistered returns true if types for the version have been registered with the scheme
  593. func (s *Scheme) IsVersionRegistered(version schema.GroupVersion) bool {
  594. for _, observedVersion := range s.observedVersions {
  595. if observedVersion == version {
  596. return true
  597. }
  598. }
  599. return false
  600. }
  601. func (s *Scheme) addObservedVersion(version schema.GroupVersion) {
  602. if len(version.Version) == 0 || version.Version == APIVersionInternal {
  603. return
  604. }
  605. for _, observedVersion := range s.observedVersions {
  606. if observedVersion == version {
  607. return
  608. }
  609. }
  610. s.observedVersions = append(s.observedVersions, version)
  611. }
  612. func (s *Scheme) Name() string {
  613. return s.schemeName
  614. }
  615. // internalPackages are packages that ignored when creating a default reflector name. These packages are in the common
  616. // call chains to NewReflector, so they'd be low entropy names for reflectors
  617. var internalPackages = []string{"k8s.io/apimachinery/pkg/runtime/scheme.go"}