1. package runtime
    2. import (
    3. "fmt"
    4. "net/url"
    5. "reflect"
    6. "strings"
    7. "k8s.io/apimachinery/pkg/conversion"
    8. "k8s.io/apimachinery/pkg/runtime/schema"
    9. "k8s.io/apimachinery/pkg/util/naming"
    10. utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    11. "k8s.io/apimachinery/pkg/util/sets"
    12. )
    13. // Schema定义了所有api object序列化和反序列化的方法。并且可以将一个注册的type转换为gvk,且可以
    14. // 转换两个obj的不同版本。
    15. type Scheme struct {
    16. // gvk到type的映射
    17. // eg. apps/v1/deployment --> typeOf(apps.v1.Deployment)
    18. gvkToType map[schema.GroupVersionKind]reflect.Type
    19. // type到gvk的映射关系
    20. // eg. typeOf(apps.v1.Deployment) --> apps/v1/deployment
    21. // 此处是一对多是因为Scheme允许注册的时候指定gvk,因此有可能出现多个gvk。比如测试的时候,不用
    22. // 在多个包定义多个结构体
    23. // 正常情况下,也是一一对应的关系
    24. // 此处的type不允许为指针
    25. typeToGVK map[reflect.Type][]schema.GroupVersionKind
    26. // unversionedTypes are transformed without conversion in ConvertToVersion.
    27. unversionedTypes map[reflect.Type]schema.GroupVersionKind
    28. // unversionedKinds are the names of kinds that can be created in the context of any group
    29. // or version
    30. // TODO: resolve the status of unversioned types.
    31. unversionedKinds map[string]reflect.Type
    32. // Map from version and resource to the corresponding func to convert
    33. // resource field labels in that version to internal version.
    34. fieldLabelConversionFuncs map[schema.GroupVersionKind]FieldLabelConversionFunc
    35. // obj的初始化函数
    36. defaulterFuncs map[reflect.Type]func(interface{})
    37. // 不同版本的转换函数
    38. // 需要用户定义好转换函数并进行注册
    39. converter *conversion.Converter
    40. // 版本优先级
    41. versionPriority map[string][]string
    42. // 所有注册过的gvk
    43. observedVersions []schema.GroupVersion
    44. schemeName string
    45. }
    46. type FieldLabelConversionFunc func(label, value string) (internalLabel, internalValue string, err error)
    47. func NewScheme() *Scheme {
    48. s := &Scheme{
    49. gvkToType: map[schema.GroupVersionKind]reflect.Type{},
    50. typeToGVK: map[reflect.Type][]schema.GroupVersionKind{},
    51. unversionedTypes: map[reflect.Type]schema.GroupVersionKind{},
    52. unversionedKinds: map[string]reflect.Type{},
    53. fieldLabelConversionFuncs: map[schema.GroupVersionKind]FieldLabelConversionFunc{},
    54. defaulterFuncs: map[reflect.Type]func(interface{}){},
    55. versionPriority: map[string][]string{},
    56. schemeName: naming.GetNameFromCallsite(internalPackages...),
    57. }
    58. s.converter = conversion.NewConverter(s.nameFunc)
    59. // 默认的一些转换函数
    60. utilruntime.Must(RegisterEmbeddedConversions(s))
    61. utilruntime.Must(RegisterStringConversions(s))
    62. // 暂时不清楚作用
    63. utilruntime.Must(s.RegisterInputDefaults(&map[string][]string{}, JSONKeyMapper, conversion.AllowDifferentFieldTypeNames|conversion.IgnoreMissingFields))
    64. utilruntime.Must(s.RegisterInputDefaults(&url.Values{}, JSONKeyMapper, conversion.AllowDifferentFieldTypeNames|conversion.IgnoreMissingFields))
    65. return s
    66. }
    67. // nameFunc returns the name of the type that we wish to use to determine when two types attempt
    68. // a conversion. Defaults to the go name of the type if the type is not registered.
    69. func (s *Scheme) nameFunc(t reflect.Type) string {
    70. // find the preferred names for this type
    71. gvks, ok := s.typeToGVK[t]
    72. if !ok {
    73. return t.Name()
    74. }
    75. for _, gvk := range gvks {
    76. internalGV := gvk.GroupVersion()
    77. internalGV.Version = APIVersionInternal // this is hacky and maybe should be passed in
    78. internalGVK := internalGV.WithKind(gvk.Kind)
    79. if internalType, exists := s.gvkToType[internalGVK]; exists {
    80. return s.typeToGVK[internalType][0].Kind
    81. }
    82. }
    83. return gvks[0].Kind
    84. }
    85. // fromScope gets the input version, desired output version, and desired Scheme
    86. // from a conversion.Scope.
    87. func (s *Scheme) fromScope(scope conversion.Scope) *Scheme {
    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.Ptr {
    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.Ptr {
    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. }
    157. // KnownTypes returns the types known for the given version.
    158. func (s *Scheme) KnownTypes(gv schema.GroupVersion) map[string]reflect.Type {
    159. types := make(map[string]reflect.Type)
    160. for gvk, t := range s.gvkToType {
    161. if gv != gvk.GroupVersion() {
    162. continue
    163. }
    164. types[gvk.Kind] = t
    165. }
    166. return types
    167. }
    168. // AllKnownTypes returns the all known types.
    169. func (s *Scheme) AllKnownTypes() map[schema.GroupVersionKind]reflect.Type {
    170. return s.gvkToType
    171. }
    172. // ObjectKinds returns all possible group,version,kind of the go object, true if the
    173. // object is considered unversioned, or an error if it's not a pointer or is unregistered.
    174. func (s *Scheme) ObjectKinds(obj Object) ([]schema.GroupVersionKind, bool, error) {
    175. // Unstructured objects are always considered to have their declared GVK
    176. if _, ok := obj.(Unstructured); ok {
    177. // we require that the GVK be populated in order to recognize the object
    178. gvk := obj.GetObjectKind().GroupVersionKind()
    179. if len(gvk.Kind) == 0 {
    180. return nil, false, NewMissingKindErr("unstructured object has no kind")
    181. }
    182. if len(gvk.Version) == 0 {
    183. return nil, false, NewMissingVersionErr("unstructured object has no version")
    184. }
    185. return []schema.GroupVersionKind{gvk}, false, nil
    186. }
    187. v, err := conversion.EnforcePtr(obj)
    188. if err != nil {
    189. return nil, false, err
    190. }
    191. t := v.Type()
    192. gvks, ok := s.typeToGVK[t]
    193. if !ok {
    194. return nil, false, NewNotRegisteredErrForType(s.schemeName, t)
    195. }
    196. _, unversionedType := s.unversionedTypes[t]
    197. return gvks, unversionedType, nil
    198. }
    199. // Recognizes returns true if the scheme is able to handle the provided group,version,kind
    200. // of an object.
    201. func (s *Scheme) Recognizes(gvk schema.GroupVersionKind) bool {
    202. _, exists := s.gvkToType[gvk]
    203. return exists
    204. }
    205. func (s *Scheme) IsUnversioned(obj Object) (bool, bool) {
    206. v, err := conversion.EnforcePtr(obj)
    207. if err != nil {
    208. return false, false
    209. }
    210. t := v.Type()
    211. if _, ok := s.typeToGVK[t]; !ok {
    212. return false, false
    213. }
    214. _, ok := s.unversionedTypes[t]
    215. return ok, true
    216. }
    217. // New returns a new API object of the given version and name, or an error if it hasn't
    218. // been registered. The version and kind fields must be specified.
    219. func (s *Scheme) New(kind schema.GroupVersionKind) (Object, error) {
    220. if t, exists := s.gvkToType[kind]; exists {
    221. return reflect.New(t).Interface().(Object), nil
    222. }
    223. if t, exists := s.unversionedKinds[kind.Kind]; exists {
    224. return reflect.New(t).Interface().(Object), nil
    225. }
    226. return nil, NewNotRegisteredErrForKind(s.schemeName, kind)
    227. }
    228. // Log sets a logger on the scheme. For test purposes only
    229. func (s *Scheme) Log(l conversion.DebugLogger) {
    230. s.converter.Debug = l
    231. }
    232. // AddIgnoredConversionType identifies a pair of types that should be skipped by
    233. // conversion (because the data inside them is explicitly dropped during
    234. // conversion).
    235. func (s *Scheme) AddIgnoredConversionType(from, to interface{}) error {
    236. return s.converter.RegisterIgnoredConversion(from, to)
    237. }
    238. // AddConversionFunc registers a function that converts between a and b by passing objects of those
    239. // types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce
    240. // any other guarantee.
    241. func (s *Scheme) AddConversionFunc(a, b interface{}, fn conversion.ConversionFunc) error {
    242. return s.converter.RegisterUntypedConversionFunc(a, b, fn)
    243. }
    244. // AddGeneratedConversionFunc registers a function that converts between a and b by passing objects of those
    245. // types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce
    246. // any other guarantee.
    247. func (s *Scheme) AddGeneratedConversionFunc(a, b interface{}, fn conversion.ConversionFunc) error {
    248. return s.converter.RegisterGeneratedUntypedConversionFunc(a, b, fn)
    249. }
    250. // AddFieldLabelConversionFunc adds a conversion function to convert field selectors
    251. // of the given kind from the given version to internal version representation.
    252. func (s *Scheme) AddFieldLabelConversionFunc(gvk schema.GroupVersionKind, conversionFunc FieldLabelConversionFunc) error {
    253. s.fieldLabelConversionFuncs[gvk] = conversionFunc
    254. return nil
    255. }
    256. // RegisterInputDefaults sets the provided field mapping function and field matching
    257. // as the defaults for the provided input type. The fn may be nil, in which case no
    258. // mapping will happen by default. Use this method to register a mechanism for handling
    259. // a specific input type in conversion, such as a map[string]string to structs.
    260. func (s *Scheme) RegisterInputDefaults(in interface{}, fn conversion.FieldMappingFunc, defaultFlags conversion.FieldMatchingFlags) error {
    261. return s.converter.RegisterInputDefaults(in, fn, defaultFlags)
    262. }
    263. // AddTypeDefaultingFunc registers a function that is passed a pointer to an
    264. // object and can default fields on the object. These functions will be invoked
    265. // when Default() is called. The function will never be called unless the
    266. // defaulted object matches srcType. If this function is invoked twice with the
    267. // same srcType, the fn passed to the later call will be used instead.
    268. func (s *Scheme) AddTypeDefaultingFunc(srcType Object, fn func(interface{})) {
    269. s.defaulterFuncs[reflect.TypeOf(srcType)] = fn
    270. }
    271. // Default sets defaults on the provided Object.
    272. func (s *Scheme) Default(src Object) {
    273. if fn, ok := s.defaulterFuncs[reflect.TypeOf(src)]; ok {
    274. fn(src)
    275. }
    276. }
    277. // Convert will attempt to convert in into out. Both must be pointers. For easy
    278. // testing of conversion functions. Returns an error if the conversion isn't
    279. // possible. You can call this with types that haven't been registered (for example,
    280. // a to test conversion of types that are nested within registered types). The
    281. // context interface is passed to the convertor. Convert also supports Unstructured
    282. // types and will convert them intelligently.
    283. func (s *Scheme) Convert(in, out interface{}, context interface{}) error {
    284. unstructuredIn, okIn := in.(Unstructured)
    285. unstructuredOut, okOut := out.(Unstructured)
    286. switch {
    287. case okIn && okOut:
    288. // converting unstructured input to an unstructured output is a straight copy - unstructured
    289. // is a "smart holder" and the contents are passed by reference between the two objects
    290. unstructuredOut.SetUnstructuredContent(unstructuredIn.UnstructuredContent())
    291. return nil
    292. case okOut:
    293. // if the output is an unstructured object, use the standard Go type to unstructured
    294. // conversion. The object must not be internal.
    295. obj, ok := in.(Object)
    296. if !ok {
    297. return fmt.Errorf("unable to convert object type %T to Unstructured, must be a runtime.Object", in)
    298. }
    299. gvks, unversioned, err := s.ObjectKinds(obj)
    300. if err != nil {
    301. return err
    302. }
    303. gvk := gvks[0]
    304. // if no conversion is necessary, convert immediately
    305. if unversioned || gvk.Version != APIVersionInternal {
    306. content, err := DefaultUnstructuredConverter.ToUnstructured(in)
    307. if err != nil {
    308. return err
    309. }
    310. unstructuredOut.SetUnstructuredContent(content)
    311. unstructuredOut.GetObjectKind().SetGroupVersionKind(gvk)
    312. return nil
    313. }
    314. // attempt to convert the object to an external version first.
    315. target, ok := context.(GroupVersioner)
    316. if !ok {
    317. return fmt.Errorf("unable to convert the internal object type %T to Unstructured without providing a preferred version to convert to", in)
    318. }
    319. // Convert is implicitly unsafe, so we don't need to perform a safe conversion
    320. versioned, err := s.UnsafeConvertToVersion(obj, target)
    321. if err != nil {
    322. return err
    323. }
    324. content, err := DefaultUnstructuredConverter.ToUnstructured(versioned)
    325. if err != nil {
    326. return err
    327. }
    328. unstructuredOut.SetUnstructuredContent(content)
    329. return nil
    330. case okIn:
    331. // converting an unstructured object to any type is modeled by first converting
    332. // the input to a versioned type, then running standard conversions
    333. typed, err := s.unstructuredToTyped(unstructuredIn)
    334. if err != nil {
    335. return err
    336. }
    337. in = typed
    338. }
    339. flags, meta := s.generateConvertMeta(in)
    340. meta.Context = context
    341. if flags == 0 {
    342. flags = conversion.AllowDifferentFieldTypeNames
    343. }
    344. return s.converter.Convert(in, out, flags, meta)
    345. }
    346. // ConvertFieldLabel alters the given field label and value for an kind field selector from
    347. // versioned representation to an unversioned one or returns an error.
    348. func (s *Scheme) ConvertFieldLabel(gvk schema.GroupVersionKind, label, value string) (string, string, error) {
    349. conversionFunc, ok := s.fieldLabelConversionFuncs[gvk]
    350. if !ok {
    351. return DefaultMetaV1FieldSelectorConversion(label, value)
    352. }
    353. return conversionFunc(label, value)
    354. }
    355. // ConvertToVersion attempts to convert an input object to its matching Kind in another
    356. // version within this scheme. Will return an error if the provided version does not
    357. // contain the inKind (or a mapping by name defined with AddKnownTypeWithName). Will also
    358. // return an error if the conversion does not result in a valid Object being
    359. // returned. Passes target down to the conversion methods as the Context on the scope.
    360. func (s *Scheme) ConvertToVersion(in Object, target GroupVersioner) (Object, error) {
    361. return s.convertToVersion(true, in, target)
    362. }
    363. // UnsafeConvertToVersion will convert in to the provided target if such a conversion is possible,
    364. // but does not guarantee the output object does not share fields with the input object. It attempts to be as
    365. // efficient as possible when doing conversion.
    366. func (s *Scheme) UnsafeConvertToVersion(in Object, target GroupVersioner) (Object, error) {
    367. return s.convertToVersion(false, in, target)
    368. }
    369. // convertToVersion handles conversion with an optional copy.
    370. func (s *Scheme) convertToVersion(copy bool, in Object, target GroupVersioner) (Object, error) {
    371. var t reflect.Type
    372. if u, ok := in.(Unstructured); ok {
    373. typed, err := s.unstructuredToTyped(u)
    374. if err != nil {
    375. return nil, err
    376. }
    377. in = typed
    378. // unstructuredToTyped returns an Object, which must be a pointer to a struct.
    379. t = reflect.TypeOf(in).Elem()
    380. } else {
    381. // determine the incoming kinds with as few allocations as possible.
    382. t = reflect.TypeOf(in)
    383. if t.Kind() != reflect.Ptr {
    384. return nil, fmt.Errorf("only pointer types may be converted: %v", t)
    385. }
    386. t = t.Elem()
    387. if t.Kind() != reflect.Struct {
    388. return nil, fmt.Errorf("only pointers to struct types may be converted: %v", t)
    389. }
    390. }
    391. kinds, ok := s.typeToGVK[t]
    392. if !ok || len(kinds) == 0 {
    393. return nil, NewNotRegisteredErrForType(s.schemeName, t)
    394. }
    395. gvk, ok := target.KindForGroupVersionKinds(kinds)
    396. if !ok {
    397. // try to see if this type is listed as unversioned (for legacy support)
    398. // TODO: when we move to server API versions, we should completely remove the unversioned concept
    399. if unversionedKind, ok := s.unversionedTypes[t]; ok {
    400. if gvk, ok := target.KindForGroupVersionKinds([]schema.GroupVersionKind{unversionedKind}); ok {
    401. return copyAndSetTargetKind(copy, in, gvk)
    402. }
    403. return copyAndSetTargetKind(copy, in, unversionedKind)
    404. }
    405. return nil, NewNotRegisteredErrForTarget(s.schemeName, t, target)
    406. }
    407. // target wants to use the existing type, set kind and return (no conversion necessary)
    408. for _, kind := range kinds {
    409. if gvk == kind {
    410. return copyAndSetTargetKind(copy, in, gvk)
    411. }
    412. }
    413. // type is unversioned, no conversion necessary
    414. if unversionedKind, ok := s.unversionedTypes[t]; ok {
    415. if gvk, ok := target.KindForGroupVersionKinds([]schema.GroupVersionKind{unversionedKind}); ok {
    416. return copyAndSetTargetKind(copy, in, gvk)
    417. }
    418. return copyAndSetTargetKind(copy, in, unversionedKind)
    419. }
    420. out, err := s.New(gvk)
    421. if err != nil {
    422. return nil, err
    423. }
    424. if copy {
    425. in = in.DeepCopyObject()
    426. }
    427. flags, meta := s.generateConvertMeta(in)
    428. meta.Context = target
    429. if err := s.converter.Convert(in, out, flags, meta); err != nil {
    430. return nil, err
    431. }
    432. setTargetKind(out, gvk)
    433. return out, nil
    434. }
    435. // unstructuredToTyped attempts to transform an unstructured object to a typed
    436. // object if possible. It will return an error if conversion is not possible, or the versioned
    437. // Go form of the object. Note that this conversion will lose fields.
    438. func (s *Scheme) unstructuredToTyped(in Unstructured) (Object, error) {
    439. // the type must be something we recognize
    440. gvks, _, err := s.ObjectKinds(in)
    441. if err != nil {
    442. return nil, err
    443. }
    444. typed, err := s.New(gvks[0])
    445. if err != nil {
    446. return nil, err
    447. }
    448. if err := DefaultUnstructuredConverter.FromUnstructured(in.UnstructuredContent(), typed); err != nil {
    449. return nil, fmt.Errorf("unable to convert unstructured object to %v: %v", gvks[0], err)
    450. }
    451. return typed, nil
    452. }
    453. // generateConvertMeta constructs the meta value we pass to Convert.
    454. func (s *Scheme) generateConvertMeta(in interface{}) (conversion.FieldMatchingFlags, *conversion.Meta) {
    455. return s.converter.DefaultMeta(reflect.TypeOf(in))
    456. }
    457. // copyAndSetTargetKind performs a conditional copy before returning the object, or an error if copy was not successful.
    458. func copyAndSetTargetKind(copy bool, obj Object, kind schema.GroupVersionKind) (Object, error) {
    459. if copy {
    460. obj = obj.DeepCopyObject()
    461. }
    462. setTargetKind(obj, kind)
    463. return obj, nil
    464. }
    465. // setTargetKind sets the kind on an object, taking into account whether the target kind is the internal version.
    466. func setTargetKind(obj Object, kind schema.GroupVersionKind) {
    467. if kind.Version == APIVersionInternal {
    468. // internal is a special case
    469. // TODO: look at removing the need to special case this
    470. obj.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{})
    471. return
    472. }
    473. obj.GetObjectKind().SetGroupVersionKind(kind)
    474. }
    475. // SetVersionPriority allows specifying a precise order of priority. All specified versions must be in the same group,
    476. // and the specified order overwrites any previously specified order for this group
    477. func (s *Scheme) SetVersionPriority(versions ...schema.GroupVersion) error {
    478. groups := sets.String{}
    479. order := []string{}
    480. for _, version := range versions {
    481. if len(version.Version) == 0 || version.Version == APIVersionInternal {
    482. return fmt.Errorf("internal versions cannot be prioritized: %v", version)
    483. }
    484. groups.Insert(version.Group)
    485. order = append(order, version.Version)
    486. }
    487. if len(groups) != 1 {
    488. return fmt.Errorf("must register versions for exactly one group: %v", strings.Join(groups.List(), ", "))
    489. }
    490. s.versionPriority[groups.List()[0]] = order
    491. return nil
    492. }
    493. // PrioritizedVersionsForGroup returns versions for a single group in priority order
    494. func (s *Scheme) PrioritizedVersionsForGroup(group string) []schema.GroupVersion {
    495. ret := []schema.GroupVersion{}
    496. for _, version := range s.versionPriority[group] {
    497. ret = append(ret, schema.GroupVersion{Group: group, Version: version})
    498. }
    499. for _, observedVersion := range s.observedVersions {
    500. if observedVersion.Group != group {
    501. continue
    502. }
    503. found := false
    504. for _, existing := range ret {
    505. if existing == observedVersion {
    506. found = true
    507. break
    508. }
    509. }
    510. if !found {
    511. ret = append(ret, observedVersion)
    512. }
    513. }
    514. return ret
    515. }
    516. // PrioritizedVersionsAllGroups returns all known versions in their priority order. Groups are random, but
    517. // versions for a single group are prioritized
    518. func (s *Scheme) PrioritizedVersionsAllGroups() []schema.GroupVersion {
    519. ret := []schema.GroupVersion{}
    520. for group, versions := range s.versionPriority {
    521. for _, version := range versions {
    522. ret = append(ret, schema.GroupVersion{Group: group, Version: version})
    523. }
    524. }
    525. for _, observedVersion := range s.observedVersions {
    526. found := false
    527. for _, existing := range ret {
    528. if existing == observedVersion {
    529. found = true
    530. break
    531. }
    532. }
    533. if !found {
    534. ret = append(ret, observedVersion)
    535. }
    536. }
    537. return ret
    538. }
    539. // PreferredVersionAllGroups returns the most preferred version for every group.
    540. // group ordering is random.
    541. func (s *Scheme) PreferredVersionAllGroups() []schema.GroupVersion {
    542. ret := []schema.GroupVersion{}
    543. for group, versions := range s.versionPriority {
    544. for _, version := range versions {
    545. ret = append(ret, schema.GroupVersion{Group: group, Version: version})
    546. break
    547. }
    548. }
    549. for _, observedVersion := range s.observedVersions {
    550. found := false
    551. for _, existing := range ret {
    552. if existing.Group == observedVersion.Group {
    553. found = true
    554. break
    555. }
    556. }
    557. if !found {
    558. ret = append(ret, observedVersion)
    559. }
    560. }
    561. return ret
    562. }
    563. // IsGroupRegistered returns true if types for the group have been registered with the scheme
    564. func (s *Scheme) IsGroupRegistered(group string) bool {
    565. for _, observedVersion := range s.observedVersions {
    566. if observedVersion.Group == group {
    567. return true
    568. }
    569. }
    570. return false
    571. }
    572. // IsVersionRegistered returns true if types for the version have been registered with the scheme
    573. func (s *Scheme) IsVersionRegistered(version schema.GroupVersion) bool {
    574. for _, observedVersion := range s.observedVersions {
    575. if observedVersion == version {
    576. return true
    577. }
    578. }
    579. return false
    580. }
    581. func (s *Scheme) addObservedVersion(version schema.GroupVersion) {
    582. if len(version.Version) == 0 || version.Version == APIVersionInternal {
    583. return
    584. }
    585. for _, observedVersion := range s.observedVersions {
    586. if observedVersion == version {
    587. return
    588. }
    589. }
    590. s.observedVersions = append(s.observedVersions, version)
    591. }
    592. func (s *Scheme) Name() string {
    593. return s.schemeName
    594. }
    595. // internalPackages are packages that ignored when creating a default reflector name. These packages are in the common
    596. // call chains to NewReflector, so they'd be low entropy names for reflectors
    597. var internalPackages = []string{"k8s.io/apimachinery/pkg/runtime/scheme.go"}