diff options
Diffstat (limited to 'vendor/k8s.io/apimachinery/pkg/runtime/scheme.go')
-rw-r--r-- | vendor/k8s.io/apimachinery/pkg/runtime/scheme.go | 248 |
1 files changed, 190 insertions, 58 deletions
diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/scheme.go b/vendor/k8s.io/apimachinery/pkg/runtime/scheme.go index 3d94a3041..fd37e293a 100644 --- a/vendor/k8s.io/apimachinery/pkg/runtime/scheme.go +++ b/vendor/k8s.io/apimachinery/pkg/runtime/scheme.go @@ -20,9 +20,13 @@ import ( "fmt" "net/url" "reflect" + "strings" "k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/naming" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/sets" ) // Scheme defines methods for serializing and deserializing API objects, a type @@ -59,18 +63,29 @@ type Scheme struct { // Map from version and resource to the corresponding func to convert // resource field labels in that version to internal version. - fieldLabelConversionFuncs map[string]map[string]FieldLabelConversionFunc + fieldLabelConversionFuncs map[schema.GroupVersionKind]FieldLabelConversionFunc // defaulterFuncs is an array of interfaces to be called with an object to provide defaulting // the provided object must be a pointer. defaulterFuncs map[reflect.Type]func(interface{}) // converter stores all registered conversion functions. It also has - // default coverting behavior. + // default converting behavior. converter *conversion.Converter + + // versionPriority is a map of groups to ordered lists of versions for those groups indicating the + // default priorities of these versions as registered in the scheme + versionPriority map[string][]string + + // observedVersions keeps track of the order we've seen versions during type registration + observedVersions []schema.GroupVersion + + // schemeName is the name of this scheme. If you don't specify a name, the stack of the NewScheme caller will be used. + // This is useful for error reporting to indicate the origin of the scheme. + schemeName string } -// Function to convert a field selector to internal representation. +// FieldLabelConversionFunc converts a field selector to internal representation. type FieldLabelConversionFunc func(label, value string) (internalLabel, internalValue string, err error) // NewScheme creates a new Scheme. This scheme is pluggable by default. @@ -80,23 +95,19 @@ func NewScheme() *Scheme { typeToGVK: map[reflect.Type][]schema.GroupVersionKind{}, unversionedTypes: map[reflect.Type]schema.GroupVersionKind{}, unversionedKinds: map[string]reflect.Type{}, - fieldLabelConversionFuncs: map[string]map[string]FieldLabelConversionFunc{}, + fieldLabelConversionFuncs: map[schema.GroupVersionKind]FieldLabelConversionFunc{}, defaulterFuncs: map[reflect.Type]func(interface{}){}, + versionPriority: map[string][]string{}, + schemeName: naming.GetNameFromCallsite(internalPackages...), } s.converter = conversion.NewConverter(s.nameFunc) - s.AddConversionFuncs(DefaultEmbeddedConversions()...) + utilruntime.Must(s.AddConversionFuncs(DefaultEmbeddedConversions()...)) // Enable map[string][]string conversions by default - if err := s.AddConversionFuncs(DefaultStringConversions...); err != nil { - panic(err) - } - if err := s.RegisterInputDefaults(&map[string][]string{}, JSONKeyMapper, conversion.AllowDifferentFieldTypeNames|conversion.IgnoreMissingFields); err != nil { - panic(err) - } - if err := s.RegisterInputDefaults(&url.Values{}, JSONKeyMapper, conversion.AllowDifferentFieldTypeNames|conversion.IgnoreMissingFields); err != nil { - panic(err) - } + utilruntime.Must(s.AddConversionFuncs(DefaultStringConversions...)) + utilruntime.Must(s.RegisterInputDefaults(&map[string][]string{}, JSONKeyMapper, conversion.AllowDifferentFieldTypeNames|conversion.IgnoreMissingFields)) + utilruntime.Must(s.RegisterInputDefaults(&url.Values{}, JSONKeyMapper, conversion.AllowDifferentFieldTypeNames|conversion.IgnoreMissingFields)) return s } @@ -111,7 +122,7 @@ func (s *Scheme) nameFunc(t reflect.Type) string { for _, gvk := range gvks { internalGV := gvk.GroupVersion() - internalGV.Version = "__internal" // this is hacky and maybe should be passed in + internalGV.Version = APIVersionInternal // this is hacky and maybe should be passed in internalGVK := internalGV.WithKind(gvk.Kind) if internalType, exists := s.gvkToType[internalGVK]; exists { @@ -141,13 +152,14 @@ func (s *Scheme) Converter() *conversion.Converter { // TODO: there is discussion about removing unversioned and replacing it with objects that are manifest into // every version with particular schemas. Resolve this method at that point. func (s *Scheme) AddUnversionedTypes(version schema.GroupVersion, types ...Object) { + s.addObservedVersion(version) s.AddKnownTypes(version, types...) for _, obj := range types { t := reflect.TypeOf(obj).Elem() gvk := version.WithKind(t.Name()) s.unversionedTypes[t] = gvk if old, ok := s.unversionedKinds[gvk.Kind]; ok && t != old { - panic(fmt.Sprintf("%v.%v has already been registered as unversioned kind %q - kind name must be unique", old.PkgPath(), old.Name(), gvk)) + 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)) } s.unversionedKinds[gvk.Kind] = t } @@ -158,6 +170,7 @@ func (s *Scheme) AddUnversionedTypes(version schema.GroupVersion, types ...Objec // the struct becomes the "kind" field when encoding. Version may not be empty - use the // APIVersionInternal constant if you have a type that does not have a formal version. func (s *Scheme) AddKnownTypes(gv schema.GroupVersion, types ...Object) { + s.addObservedVersion(gv) for _, obj := range types { t := reflect.TypeOf(obj) if t.Kind() != reflect.Ptr { @@ -173,6 +186,7 @@ func (s *Scheme) AddKnownTypes(gv schema.GroupVersion, types ...Object) { // your structs. Version may not be empty - use the APIVersionInternal constant if you have a // type that does not have a formal version. func (s *Scheme) AddKnownTypeWithName(gvk schema.GroupVersionKind, obj Object) { + s.addObservedVersion(gvk.GroupVersion()) t := reflect.TypeOf(obj) if len(gvk.Version) == 0 { panic(fmt.Sprintf("version is required on all types: %s %v", gvk, t)) @@ -186,7 +200,7 @@ func (s *Scheme) AddKnownTypeWithName(gvk schema.GroupVersionKind, obj Object) { } if oldT, found := s.gvkToType[gvk]; found && oldT != t { - panic(fmt.Sprintf("Double registration of different types for %v: old=%v.%v, new=%v.%v", gvk, oldT.PkgPath(), oldT.Name(), t.PkgPath(), t.Name())) + 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)) } s.gvkToType[gvk] = t @@ -241,7 +255,7 @@ func (s *Scheme) ObjectKinds(obj Object) ([]schema.GroupVersionKind, bool, error gvks, ok := s.typeToGVK[t] if !ok { - return nil, false, NewNotRegisteredErrForType(t) + return nil, false, NewNotRegisteredErrForType(s.schemeName, t) } _, unversionedType := s.unversionedTypes[t] @@ -279,15 +293,7 @@ func (s *Scheme) New(kind schema.GroupVersionKind) (Object, error) { if t, exists := s.unversionedKinds[kind.Kind]; exists { return reflect.New(t).Interface().(Object), nil } - return nil, NewNotRegisteredErrForKind(kind) -} - -// AddGenericConversionFunc adds a function that accepts the ConversionFunc call pattern -// (for two conversion types) to the converter. These functions are checked first during -// a normal conversion, but are otherwise not called. Use AddConversionFuncs when registering -// typed conversions. -func (s *Scheme) AddGenericConversionFunc(fn conversion.GenericConversionFunc) { - s.converter.AddGenericConversionFunc(fn) + return nil, NewNotRegisteredErrForKind(s.schemeName, kind) } // Log sets a logger on the scheme. For test purposes only @@ -341,36 +347,27 @@ func (s *Scheme) AddConversionFuncs(conversionFuncs ...interface{}) error { return nil } -// AddGeneratedConversionFuncs registers conversion functions that were -// automatically generated. -func (s *Scheme) AddGeneratedConversionFuncs(conversionFuncs ...interface{}) error { - for _, f := range conversionFuncs { - if err := s.converter.RegisterGeneratedConversionFunc(f); err != nil { - return err - } - } - return nil +// AddConversionFunc registers a function that converts between a and b by passing objects of those +// types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce +// any other guarantee. +func (s *Scheme) AddConversionFunc(a, b interface{}, fn conversion.ConversionFunc) error { + return s.converter.RegisterUntypedConversionFunc(a, b, fn) +} + +// AddGeneratedConversionFunc registers a function that converts between a and b by passing objects of those +// types to the provided function. The function *must* accept objects of a and b - this machinery will not enforce +// any other guarantee. +func (s *Scheme) AddGeneratedConversionFunc(a, b interface{}, fn conversion.ConversionFunc) error { + return s.converter.RegisterGeneratedUntypedConversionFunc(a, b, fn) } // AddFieldLabelConversionFunc adds a conversion function to convert field selectors // of the given kind from the given version to internal version representation. -func (s *Scheme) AddFieldLabelConversionFunc(version, kind string, conversionFunc FieldLabelConversionFunc) error { - if s.fieldLabelConversionFuncs[version] == nil { - s.fieldLabelConversionFuncs[version] = map[string]FieldLabelConversionFunc{} - } - - s.fieldLabelConversionFuncs[version][kind] = conversionFunc +func (s *Scheme) AddFieldLabelConversionFunc(gvk schema.GroupVersionKind, conversionFunc FieldLabelConversionFunc) error { + s.fieldLabelConversionFuncs[gvk] = conversionFunc return nil } -// AddStructFieldConversion allows you to specify a mechanical copy for a moved -// or renamed struct field without writing an entire conversion function. See -// the comment in conversion.Converter.SetStructFieldCopy for parameter details. -// Call as many times as needed, even on the same fields. -func (s *Scheme) AddStructFieldConversion(srcFieldType interface{}, srcFieldName string, destFieldType interface{}, destFieldName string) error { - return s.converter.SetStructFieldCopy(srcFieldType, srcFieldName, destFieldType, destFieldName) -} - // RegisterInputDefaults sets the provided field mapping function and field matching // as the defaults for the provided input type. The fn may be nil, in which case no // mapping will happen by default. Use this method to register a mechanism for handling @@ -379,7 +376,7 @@ func (s *Scheme) RegisterInputDefaults(in interface{}, fn conversion.FieldMappin return s.converter.RegisterInputDefaults(in, fn, defaultFlags) } -// AddTypeDefaultingFuncs registers a function that is passed a pointer to an +// AddTypeDefaultingFunc registers a function that is passed a pointer to an // object and can default fields on the object. These functions will be invoked // when Default() is called. The function will never be called unless the // defaulted object matches srcType. If this function is invoked twice with the @@ -472,11 +469,8 @@ func (s *Scheme) Convert(in, out interface{}, context interface{}) error { // ConvertFieldLabel alters the given field label and value for an kind field selector from // versioned representation to an unversioned one or returns an error. -func (s *Scheme) ConvertFieldLabel(version, kind, label, value string) (string, string, error) { - if s.fieldLabelConversionFuncs[version] == nil { - return DefaultMetaV1FieldSelectorConversion(label, value) - } - conversionFunc, ok := s.fieldLabelConversionFuncs[version][kind] +func (s *Scheme) ConvertFieldLabel(gvk schema.GroupVersionKind, label, value string) (string, string, error) { + conversionFunc, ok := s.fieldLabelConversionFuncs[gvk] if !ok { return DefaultMetaV1FieldSelectorConversion(label, value) } @@ -527,7 +521,7 @@ func (s *Scheme) convertToVersion(copy bool, in Object, target GroupVersioner) ( kinds, ok := s.typeToGVK[t] if !ok || len(kinds) == 0 { - return nil, NewNotRegisteredErrForType(t) + return nil, NewNotRegisteredErrForType(s.schemeName, t) } gvk, ok := target.KindForGroupVersionKinds(kinds) @@ -540,7 +534,7 @@ func (s *Scheme) convertToVersion(copy bool, in Object, target GroupVersioner) ( } return copyAndSetTargetKind(copy, in, unversionedKind) } - return nil, NewNotRegisteredErrForTarget(t, target) + return nil, NewNotRegisteredErrForTarget(s.schemeName, t, target) } // target wants to use the existing type, set kind and return (no conversion necessary) @@ -620,3 +614,141 @@ func setTargetKind(obj Object, kind schema.GroupVersionKind) { } obj.GetObjectKind().SetGroupVersionKind(kind) } + +// SetVersionPriority allows specifying a precise order of priority. All specified versions must be in the same group, +// and the specified order overwrites any previously specified order for this group +func (s *Scheme) SetVersionPriority(versions ...schema.GroupVersion) error { + groups := sets.String{} + order := []string{} + for _, version := range versions { + if len(version.Version) == 0 || version.Version == APIVersionInternal { + return fmt.Errorf("internal versions cannot be prioritized: %v", version) + } + + groups.Insert(version.Group) + order = append(order, version.Version) + } + if len(groups) != 1 { + return fmt.Errorf("must register versions for exactly one group: %v", strings.Join(groups.List(), ", ")) + } + + s.versionPriority[groups.List()[0]] = order + return nil +} + +// PrioritizedVersionsForGroup returns versions for a single group in priority order +func (s *Scheme) PrioritizedVersionsForGroup(group string) []schema.GroupVersion { + ret := []schema.GroupVersion{} + for _, version := range s.versionPriority[group] { + ret = append(ret, schema.GroupVersion{Group: group, Version: version}) + } + for _, observedVersion := range s.observedVersions { + if observedVersion.Group != group { + continue + } + found := false + for _, existing := range ret { + if existing == observedVersion { + found = true + break + } + } + if !found { + ret = append(ret, observedVersion) + } + } + + return ret +} + +// PrioritizedVersionsAllGroups returns all known versions in their priority order. Groups are random, but +// versions for a single group are prioritized +func (s *Scheme) PrioritizedVersionsAllGroups() []schema.GroupVersion { + ret := []schema.GroupVersion{} + for group, versions := range s.versionPriority { + for _, version := range versions { + ret = append(ret, schema.GroupVersion{Group: group, Version: version}) + } + } + for _, observedVersion := range s.observedVersions { + found := false + for _, existing := range ret { + if existing == observedVersion { + found = true + break + } + } + if !found { + ret = append(ret, observedVersion) + } + } + return ret +} + +// PreferredVersionAllGroups returns the most preferred version for every group. +// group ordering is random. +func (s *Scheme) PreferredVersionAllGroups() []schema.GroupVersion { + ret := []schema.GroupVersion{} + for group, versions := range s.versionPriority { + for _, version := range versions { + ret = append(ret, schema.GroupVersion{Group: group, Version: version}) + break + } + } + for _, observedVersion := range s.observedVersions { + found := false + for _, existing := range ret { + if existing.Group == observedVersion.Group { + found = true + break + } + } + if !found { + ret = append(ret, observedVersion) + } + } + + return ret +} + +// IsGroupRegistered returns true if types for the group have been registered with the scheme +func (s *Scheme) IsGroupRegistered(group string) bool { + for _, observedVersion := range s.observedVersions { + if observedVersion.Group == group { + return true + } + } + return false +} + +// IsVersionRegistered returns true if types for the version have been registered with the scheme +func (s *Scheme) IsVersionRegistered(version schema.GroupVersion) bool { + for _, observedVersion := range s.observedVersions { + if observedVersion == version { + return true + } + } + + return false +} + +func (s *Scheme) addObservedVersion(version schema.GroupVersion) { + if len(version.Version) == 0 || version.Version == APIVersionInternal { + return + } + for _, observedVersion := range s.observedVersions { + if observedVersion == version { + return + } + } + + s.observedVersions = append(s.observedVersions, version) +} + +func (s *Scheme) Name() string { + return s.schemeName +} + +// internalPackages are packages that ignored when creating a default reflector name. These packages are in the common +// call chains to NewReflector, so they'd be low entropy names for reflectors +var internalPackages = []string{"k8s.io/apimachinery/pkg/runtime/scheme.go"} |