scheme.go 27 KB

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