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