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"}