scheme.go 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  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/sets"
  22. )
  23. // Scheme defines methods for serializing and deserializing API objects, a type
  24. // registry for converting group, version, and kind information to and from Go
  25. // schemas, and mappings between Go schemas of different versions. A scheme is the
  26. // foundation for a versioned API and versioned configuration over time.
  27. //
  28. // In a Scheme, a Type is a particular Go struct, a Version is a point-in-time
  29. // identifier for a particular representation of that Type (typically backwards
  30. // compatible), a Kind is the unique name for that Type within the Version, and a
  31. // Group identifies a set of Versions, Kinds, and Types that evolve over time. An
  32. // Unversioned Type is one that is not yet formally bound to a type and is promised
  33. // to be backwards compatible (effectively a "v1" of a Type that does not expect
  34. // to break in the future).
  35. //
  36. // Schemes are not expected to change at runtime and are only threadsafe after
  37. // registration is complete.
  38. type Scheme struct {
  39. // versionMap allows one to figure out the go type of an object with
  40. // the given version and name.
  41. gvkToType map[schema.GroupVersionKind]reflect.Type
  42. // typeToGroupVersion allows one to find metadata for a given go object.
  43. // The reflect.Type we index by should *not* be a pointer.
  44. typeToGVK map[reflect.Type][]schema.GroupVersionKind
  45. // unversionedTypes are transformed without conversion in ConvertToVersion.
  46. unversionedTypes map[reflect.Type]schema.GroupVersionKind
  47. // unversionedKinds are the names of kinds that can be created in the context of any group
  48. // or version
  49. // TODO: resolve the status of unversioned types.
  50. unversionedKinds map[string]reflect.Type
  51. // Map from version and resource to the corresponding func to convert
  52. // resource field labels in that version to internal version.
  53. fieldLabelConversionFuncs map[string]map[string]FieldLabelConversionFunc
  54. // defaulterFuncs is an array of interfaces to be called with an object to provide defaulting
  55. // the provided object must be a pointer.
  56. defaulterFuncs map[reflect.Type]func(interface{})
  57. // converter stores all registered conversion functions. It also has
  58. // default coverting behavior.
  59. converter *conversion.Converter
  60. // versionPriority is a map of groups to ordered lists of versions for those groups indicating the
  61. // default priorities of these versions as registered in the scheme
  62. versionPriority map[string][]string
  63. // observedVersions keeps track of the order we've seen versions during type registration
  64. observedVersions []schema.GroupVersion
  65. }
  66. // Function to convert a field selector to internal representation.
  67. type FieldLabelConversionFunc func(label, value string) (internalLabel, internalValue string, err error)
  68. // NewScheme creates a new Scheme. This scheme is pluggable by default.
  69. func NewScheme() *Scheme {
  70. s := &Scheme{
  71. gvkToType: map[schema.GroupVersionKind]reflect.Type{},
  72. typeToGVK: map[reflect.Type][]schema.GroupVersionKind{},
  73. unversionedTypes: map[reflect.Type]schema.GroupVersionKind{},
  74. unversionedKinds: map[string]reflect.Type{},
  75. fieldLabelConversionFuncs: map[string]map[string]FieldLabelConversionFunc{},
  76. defaulterFuncs: map[reflect.Type]func(interface{}){},
  77. versionPriority: map[string][]string{},
  78. }
  79. s.converter = conversion.NewConverter(s.nameFunc)
  80. s.AddConversionFuncs(DefaultEmbeddedConversions()...)
  81. // Enable map[string][]string conversions by default
  82. if err := s.AddConversionFuncs(DefaultStringConversions...); err != nil {
  83. panic(err)
  84. }
  85. if err := s.RegisterInputDefaults(&map[string][]string{}, JSONKeyMapper, conversion.AllowDifferentFieldTypeNames|conversion.IgnoreMissingFields); err != nil {
  86. panic(err)
  87. }
  88. if err := s.RegisterInputDefaults(&url.Values{}, JSONKeyMapper, conversion.AllowDifferentFieldTypeNames|conversion.IgnoreMissingFields); err != nil {
  89. panic(err)
  90. }
  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", old.PkgPath(), old.Name(), gvk))
  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", gvk, oldT.PkgPath(), oldT.Name(), t.PkgPath(), t.Name()))
  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(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(kind)
  253. }
  254. // AddGenericConversionFunc adds a function that accepts the ConversionFunc call pattern
  255. // (for two conversion types) to the converter. These functions are checked first during
  256. // a normal conversion, but are otherwise not called. Use AddConversionFuncs when registering
  257. // typed conversions.
  258. func (s *Scheme) AddGenericConversionFunc(fn conversion.GenericConversionFunc) {
  259. s.converter.AddGenericConversionFunc(fn)
  260. }
  261. // Log sets a logger on the scheme. For test purposes only
  262. func (s *Scheme) Log(l conversion.DebugLogger) {
  263. s.converter.Debug = l
  264. }
  265. // AddIgnoredConversionType identifies a pair of types that should be skipped by
  266. // conversion (because the data inside them is explicitly dropped during
  267. // conversion).
  268. func (s *Scheme) AddIgnoredConversionType(from, to interface{}) error {
  269. return s.converter.RegisterIgnoredConversion(from, to)
  270. }
  271. // AddConversionFuncs adds functions to the list of conversion functions. The given
  272. // functions should know how to convert between two of your API objects, or their
  273. // sub-objects. We deduce how to call these functions from the types of their two
  274. // parameters; see the comment for Converter.Register.
  275. //
  276. // Note that, if you need to copy sub-objects that didn't change, you can use the
  277. // conversion.Scope object that will be passed to your conversion function.
  278. // Additionally, all conversions started by Scheme will set the SrcVersion and
  279. // DestVersion fields on the Meta object. Example:
  280. //
  281. // s.AddConversionFuncs(
  282. // func(in *InternalObject, out *ExternalObject, scope conversion.Scope) error {
  283. // // You can depend on Meta() being non-nil, and this being set to
  284. // // the source version, e.g., ""
  285. // s.Meta().SrcVersion
  286. // // You can depend on this being set to the destination version,
  287. // // e.g., "v1".
  288. // s.Meta().DestVersion
  289. // // Call scope.Convert to copy sub-fields.
  290. // s.Convert(&in.SubFieldThatMoved, &out.NewLocation.NewName, 0)
  291. // return nil
  292. // },
  293. // )
  294. //
  295. // (For more detail about conversion functions, see Converter.Register's comment.)
  296. //
  297. // Also note that the default behavior, if you don't add a conversion function, is to
  298. // sanely copy fields that have the same names and same type names. It's OK if the
  299. // destination type has extra fields, but it must not remove any. So you only need to
  300. // add conversion functions for things with changed/removed fields.
  301. func (s *Scheme) AddConversionFuncs(conversionFuncs ...interface{}) error {
  302. for _, f := range conversionFuncs {
  303. if err := s.converter.RegisterConversionFunc(f); err != nil {
  304. return err
  305. }
  306. }
  307. return nil
  308. }
  309. // AddGeneratedConversionFuncs registers conversion functions that were
  310. // automatically generated.
  311. func (s *Scheme) AddGeneratedConversionFuncs(conversionFuncs ...interface{}) error {
  312. for _, f := range conversionFuncs {
  313. if err := s.converter.RegisterGeneratedConversionFunc(f); err != nil {
  314. return err
  315. }
  316. }
  317. return nil
  318. }
  319. // AddFieldLabelConversionFunc adds a conversion function to convert field selectors
  320. // of the given kind from the given version to internal version representation.
  321. func (s *Scheme) AddFieldLabelConversionFunc(version, kind string, conversionFunc FieldLabelConversionFunc) error {
  322. if s.fieldLabelConversionFuncs[version] == nil {
  323. s.fieldLabelConversionFuncs[version] = map[string]FieldLabelConversionFunc{}
  324. }
  325. s.fieldLabelConversionFuncs[version][kind] = conversionFunc
  326. return nil
  327. }
  328. // AddStructFieldConversion allows you to specify a mechanical copy for a moved
  329. // or renamed struct field without writing an entire conversion function. See
  330. // the comment in conversion.Converter.SetStructFieldCopy for parameter details.
  331. // Call as many times as needed, even on the same fields.
  332. func (s *Scheme) AddStructFieldConversion(srcFieldType interface{}, srcFieldName string, destFieldType interface{}, destFieldName string) error {
  333. return s.converter.SetStructFieldCopy(srcFieldType, srcFieldName, destFieldType, destFieldName)
  334. }
  335. // RegisterInputDefaults sets the provided field mapping function and field matching
  336. // as the defaults for the provided input type. The fn may be nil, in which case no
  337. // mapping will happen by default. Use this method to register a mechanism for handling
  338. // a specific input type in conversion, such as a map[string]string to structs.
  339. func (s *Scheme) RegisterInputDefaults(in interface{}, fn conversion.FieldMappingFunc, defaultFlags conversion.FieldMatchingFlags) error {
  340. return s.converter.RegisterInputDefaults(in, fn, defaultFlags)
  341. }
  342. // AddTypeDefaultingFuncs registers a function that is passed a pointer to an
  343. // object and can default fields on the object. These functions will be invoked
  344. // when Default() is called. The function will never be called unless the
  345. // defaulted object matches srcType. If this function is invoked twice with the
  346. // same srcType, the fn passed to the later call will be used instead.
  347. func (s *Scheme) AddTypeDefaultingFunc(srcType Object, fn func(interface{})) {
  348. s.defaulterFuncs[reflect.TypeOf(srcType)] = fn
  349. }
  350. // Default sets defaults on the provided Object.
  351. func (s *Scheme) Default(src Object) {
  352. if fn, ok := s.defaulterFuncs[reflect.TypeOf(src)]; ok {
  353. fn(src)
  354. }
  355. }
  356. // Convert will attempt to convert in into out. Both must be pointers. For easy
  357. // testing of conversion functions. Returns an error if the conversion isn't
  358. // possible. You can call this with types that haven't been registered (for example,
  359. // a to test conversion of types that are nested within registered types). The
  360. // context interface is passed to the convertor. Convert also supports Unstructured
  361. // types and will convert them intelligently.
  362. func (s *Scheme) Convert(in, out interface{}, context interface{}) error {
  363. unstructuredIn, okIn := in.(Unstructured)
  364. unstructuredOut, okOut := out.(Unstructured)
  365. switch {
  366. case okIn && okOut:
  367. // converting unstructured input to an unstructured output is a straight copy - unstructured
  368. // is a "smart holder" and the contents are passed by reference between the two objects
  369. unstructuredOut.SetUnstructuredContent(unstructuredIn.UnstructuredContent())
  370. return nil
  371. case okOut:
  372. // if the output is an unstructured object, use the standard Go type to unstructured
  373. // conversion. The object must not be internal.
  374. obj, ok := in.(Object)
  375. if !ok {
  376. return fmt.Errorf("unable to convert object type %T to Unstructured, must be a runtime.Object", in)
  377. }
  378. gvks, unversioned, err := s.ObjectKinds(obj)
  379. if err != nil {
  380. return err
  381. }
  382. gvk := gvks[0]
  383. // if no conversion is necessary, convert immediately
  384. if unversioned || gvk.Version != APIVersionInternal {
  385. content, err := DefaultUnstructuredConverter.ToUnstructured(in)
  386. if err != nil {
  387. return err
  388. }
  389. unstructuredOut.SetUnstructuredContent(content)
  390. unstructuredOut.GetObjectKind().SetGroupVersionKind(gvk)
  391. return nil
  392. }
  393. // attempt to convert the object to an external version first.
  394. target, ok := context.(GroupVersioner)
  395. if !ok {
  396. return fmt.Errorf("unable to convert the internal object type %T to Unstructured without providing a preferred version to convert to", in)
  397. }
  398. // Convert is implicitly unsafe, so we don't need to perform a safe conversion
  399. versioned, err := s.UnsafeConvertToVersion(obj, target)
  400. if err != nil {
  401. return err
  402. }
  403. content, err := DefaultUnstructuredConverter.ToUnstructured(versioned)
  404. if err != nil {
  405. return err
  406. }
  407. unstructuredOut.SetUnstructuredContent(content)
  408. return nil
  409. case okIn:
  410. // converting an unstructured object to any type is modeled by first converting
  411. // the input to a versioned type, then running standard conversions
  412. typed, err := s.unstructuredToTyped(unstructuredIn)
  413. if err != nil {
  414. return err
  415. }
  416. in = typed
  417. }
  418. flags, meta := s.generateConvertMeta(in)
  419. meta.Context = context
  420. if flags == 0 {
  421. flags = conversion.AllowDifferentFieldTypeNames
  422. }
  423. return s.converter.Convert(in, out, flags, meta)
  424. }
  425. // ConvertFieldLabel alters the given field label and value for an kind field selector from
  426. // versioned representation to an unversioned one or returns an error.
  427. func (s *Scheme) ConvertFieldLabel(version, kind, label, value string) (string, string, error) {
  428. if s.fieldLabelConversionFuncs[version] == nil {
  429. return DefaultMetaV1FieldSelectorConversion(label, value)
  430. }
  431. conversionFunc, ok := s.fieldLabelConversionFuncs[version][kind]
  432. if !ok {
  433. return DefaultMetaV1FieldSelectorConversion(label, value)
  434. }
  435. return conversionFunc(label, value)
  436. }
  437. // ConvertToVersion attempts to convert an input object to its matching Kind in another
  438. // version within this scheme. Will return an error if the provided version does not
  439. // contain the inKind (or a mapping by name defined with AddKnownTypeWithName). Will also
  440. // return an error if the conversion does not result in a valid Object being
  441. // returned. Passes target down to the conversion methods as the Context on the scope.
  442. func (s *Scheme) ConvertToVersion(in Object, target GroupVersioner) (Object, error) {
  443. return s.convertToVersion(true, in, target)
  444. }
  445. // UnsafeConvertToVersion will convert in to the provided target if such a conversion is possible,
  446. // but does not guarantee the output object does not share fields with the input object. It attempts to be as
  447. // efficient as possible when doing conversion.
  448. func (s *Scheme) UnsafeConvertToVersion(in Object, target GroupVersioner) (Object, error) {
  449. return s.convertToVersion(false, in, target)
  450. }
  451. // convertToVersion handles conversion with an optional copy.
  452. func (s *Scheme) convertToVersion(copy bool, in Object, target GroupVersioner) (Object, error) {
  453. var t reflect.Type
  454. if u, ok := in.(Unstructured); ok {
  455. typed, err := s.unstructuredToTyped(u)
  456. if err != nil {
  457. return nil, err
  458. }
  459. in = typed
  460. // unstructuredToTyped returns an Object, which must be a pointer to a struct.
  461. t = reflect.TypeOf(in).Elem()
  462. } else {
  463. // determine the incoming kinds with as few allocations as possible.
  464. t = reflect.TypeOf(in)
  465. if t.Kind() != reflect.Ptr {
  466. return nil, fmt.Errorf("only pointer types may be converted: %v", t)
  467. }
  468. t = t.Elem()
  469. if t.Kind() != reflect.Struct {
  470. return nil, fmt.Errorf("only pointers to struct types may be converted: %v", t)
  471. }
  472. }
  473. kinds, ok := s.typeToGVK[t]
  474. if !ok || len(kinds) == 0 {
  475. return nil, NewNotRegisteredErrForType(t)
  476. }
  477. gvk, ok := target.KindForGroupVersionKinds(kinds)
  478. if !ok {
  479. // try to see if this type is listed as unversioned (for legacy support)
  480. // TODO: when we move to server API versions, we should completely remove the unversioned concept
  481. if unversionedKind, ok := s.unversionedTypes[t]; ok {
  482. if gvk, ok := target.KindForGroupVersionKinds([]schema.GroupVersionKind{unversionedKind}); ok {
  483. return copyAndSetTargetKind(copy, in, gvk)
  484. }
  485. return copyAndSetTargetKind(copy, in, unversionedKind)
  486. }
  487. return nil, NewNotRegisteredErrForTarget(t, target)
  488. }
  489. // target wants to use the existing type, set kind and return (no conversion necessary)
  490. for _, kind := range kinds {
  491. if gvk == kind {
  492. return copyAndSetTargetKind(copy, in, gvk)
  493. }
  494. }
  495. // type is unversioned, no conversion necessary
  496. if unversionedKind, ok := s.unversionedTypes[t]; ok {
  497. if gvk, ok := target.KindForGroupVersionKinds([]schema.GroupVersionKind{unversionedKind}); ok {
  498. return copyAndSetTargetKind(copy, in, gvk)
  499. }
  500. return copyAndSetTargetKind(copy, in, unversionedKind)
  501. }
  502. out, err := s.New(gvk)
  503. if err != nil {
  504. return nil, err
  505. }
  506. if copy {
  507. in = in.DeepCopyObject()
  508. }
  509. flags, meta := s.generateConvertMeta(in)
  510. meta.Context = target
  511. if err := s.converter.Convert(in, out, flags, meta); err != nil {
  512. return nil, err
  513. }
  514. setTargetKind(out, gvk)
  515. return out, nil
  516. }
  517. // unstructuredToTyped attempts to transform an unstructured object to a typed
  518. // object if possible. It will return an error if conversion is not possible, or the versioned
  519. // Go form of the object. Note that this conversion will lose fields.
  520. func (s *Scheme) unstructuredToTyped(in Unstructured) (Object, error) {
  521. // the type must be something we recognize
  522. gvks, _, err := s.ObjectKinds(in)
  523. if err != nil {
  524. return nil, err
  525. }
  526. typed, err := s.New(gvks[0])
  527. if err != nil {
  528. return nil, err
  529. }
  530. if err := DefaultUnstructuredConverter.FromUnstructured(in.UnstructuredContent(), typed); err != nil {
  531. return nil, fmt.Errorf("unable to convert unstructured object to %v: %v", gvks[0], err)
  532. }
  533. return typed, nil
  534. }
  535. // generateConvertMeta constructs the meta value we pass to Convert.
  536. func (s *Scheme) generateConvertMeta(in interface{}) (conversion.FieldMatchingFlags, *conversion.Meta) {
  537. return s.converter.DefaultMeta(reflect.TypeOf(in))
  538. }
  539. // copyAndSetTargetKind performs a conditional copy before returning the object, or an error if copy was not successful.
  540. func copyAndSetTargetKind(copy bool, obj Object, kind schema.GroupVersionKind) (Object, error) {
  541. if copy {
  542. obj = obj.DeepCopyObject()
  543. }
  544. setTargetKind(obj, kind)
  545. return obj, nil
  546. }
  547. // setTargetKind sets the kind on an object, taking into account whether the target kind is the internal version.
  548. func setTargetKind(obj Object, kind schema.GroupVersionKind) {
  549. if kind.Version == APIVersionInternal {
  550. // internal is a special case
  551. // TODO: look at removing the need to special case this
  552. obj.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{})
  553. return
  554. }
  555. obj.GetObjectKind().SetGroupVersionKind(kind)
  556. }
  557. // SetVersionPriority allows specifying a precise order of priority. All specified versions must be in the same group,
  558. // and the specified order overwrites any previously specified order for this group
  559. func (s *Scheme) SetVersionPriority(versions ...schema.GroupVersion) error {
  560. groups := sets.String{}
  561. order := []string{}
  562. for _, version := range versions {
  563. if len(version.Version) == 0 || version.Version == APIVersionInternal {
  564. return fmt.Errorf("internal versions cannot be prioritized: %v", version)
  565. }
  566. groups.Insert(version.Group)
  567. order = append(order, version.Version)
  568. }
  569. if len(groups) != 1 {
  570. return fmt.Errorf("must register versions for exactly one group: %v", strings.Join(groups.List(), ", "))
  571. }
  572. s.versionPriority[groups.List()[0]] = order
  573. return nil
  574. }
  575. // PrioritizedVersionsForGroup returns versions for a single group in priority order
  576. func (s *Scheme) PrioritizedVersionsForGroup(group string) []schema.GroupVersion {
  577. ret := []schema.GroupVersion{}
  578. for _, version := range s.versionPriority[group] {
  579. ret = append(ret, schema.GroupVersion{Group: group, Version: version})
  580. }
  581. for _, observedVersion := range s.observedVersions {
  582. if observedVersion.Group != group {
  583. continue
  584. }
  585. found := false
  586. for _, existing := range ret {
  587. if existing == observedVersion {
  588. found = true
  589. break
  590. }
  591. }
  592. if !found {
  593. ret = append(ret, observedVersion)
  594. }
  595. }
  596. return ret
  597. }
  598. // PrioritizedVersionsAllGroups returns all known versions in their priority order. Groups are random, but
  599. // versions for a single group are prioritized
  600. func (s *Scheme) PrioritizedVersionsAllGroups() []schema.GroupVersion {
  601. ret := []schema.GroupVersion{}
  602. for group, versions := range s.versionPriority {
  603. for _, version := range versions {
  604. ret = append(ret, schema.GroupVersion{Group: group, Version: version})
  605. }
  606. }
  607. for _, observedVersion := range s.observedVersions {
  608. found := false
  609. for _, existing := range ret {
  610. if existing == observedVersion {
  611. found = true
  612. break
  613. }
  614. }
  615. if !found {
  616. ret = append(ret, observedVersion)
  617. }
  618. }
  619. return ret
  620. }
  621. // PreferredVersionAllGroups returns the most preferred version for every group.
  622. // group ordering is random.
  623. func (s *Scheme) PreferredVersionAllGroups() []schema.GroupVersion {
  624. ret := []schema.GroupVersion{}
  625. for group, versions := range s.versionPriority {
  626. for _, version := range versions {
  627. ret = append(ret, schema.GroupVersion{Group: group, Version: version})
  628. break
  629. }
  630. }
  631. for _, observedVersion := range s.observedVersions {
  632. found := false
  633. for _, existing := range ret {
  634. if existing.Group == observedVersion.Group {
  635. found = true
  636. break
  637. }
  638. }
  639. if !found {
  640. ret = append(ret, observedVersion)
  641. }
  642. }
  643. return ret
  644. }
  645. // IsGroupRegistered returns true if types for the group have been registered with the scheme
  646. func (s *Scheme) IsGroupRegistered(group string) bool {
  647. for _, observedVersion := range s.observedVersions {
  648. if observedVersion.Group == group {
  649. return true
  650. }
  651. }
  652. return false
  653. }
  654. // IsVersionRegistered returns true if types for the version have been registered with the scheme
  655. func (s *Scheme) IsVersionRegistered(version schema.GroupVersion) bool {
  656. for _, observedVersion := range s.observedVersions {
  657. if observedVersion == version {
  658. return true
  659. }
  660. }
  661. return false
  662. }
  663. func (s *Scheme) addObservedVersion(version schema.GroupVersion) {
  664. if len(version.Version) == 0 || version.Version == APIVersionInternal {
  665. return
  666. }
  667. for _, observedVersion := range s.observedVersions {
  668. if observedVersion == version {
  669. return
  670. }
  671. }
  672. s.observedVersions = append(s.observedVersions, version)
  673. }