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