mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-08 12:41:58 +00:00
Make needed changes in conversion package to support pluggability
This commit is contained in:
@@ -51,6 +51,10 @@ type Scheme struct {
|
||||
// is registered for multiple versions, the last one wins.
|
||||
typeToVersion map[reflect.Type]string
|
||||
|
||||
// typeToKind allows one to figure out the desired "kind" field for a given
|
||||
// go object. Requirements and caveats are the same as typeToVersion.
|
||||
typeToKind map[reflect.Type]string
|
||||
|
||||
// converter stores all registered conversion functions. It also has
|
||||
// default coverting behavior.
|
||||
converter *Converter
|
||||
@@ -73,14 +77,22 @@ type Scheme struct {
|
||||
|
||||
// NewScheme manufactures a new scheme.
|
||||
func NewScheme() *Scheme {
|
||||
return &Scheme{
|
||||
s := &Scheme{
|
||||
versionMap: map[string]map[string]reflect.Type{},
|
||||
typeToVersion: map[reflect.Type]string{},
|
||||
typeToKind: map[reflect.Type]string{},
|
||||
converter: NewConverter(),
|
||||
InternalVersion: "",
|
||||
ExternalVersion: "v1",
|
||||
MetaInsertionFactory: metaInsertion{},
|
||||
}
|
||||
s.converter.Name = func(t reflect.Type) string {
|
||||
if kind, ok := s.typeToKind[t]; ok {
|
||||
return kind
|
||||
}
|
||||
return t.Name()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// AddKnownTypes registers all types passed in 'types' as being members of version 'version.
|
||||
@@ -104,9 +116,32 @@ func (s *Scheme) AddKnownTypes(version string, types ...interface{}) {
|
||||
}
|
||||
knownTypes[t.Name()] = t
|
||||
s.typeToVersion[t] = version
|
||||
s.typeToKind[t] = t.Name()
|
||||
}
|
||||
}
|
||||
|
||||
// AddKnownTypeWithName is like AddKnownTypes, but it lets you specify what this type should
|
||||
// be encoded as. Useful for testing when you don't want to make multiple packages to define
|
||||
// your structs.
|
||||
func (s *Scheme) AddKnownTypeWithName(version, kind string, obj interface{}) {
|
||||
knownTypes, found := s.versionMap[version]
|
||||
if !found {
|
||||
knownTypes = map[string]reflect.Type{}
|
||||
s.versionMap[version] = knownTypes
|
||||
}
|
||||
t := reflect.TypeOf(obj)
|
||||
if t.Kind() != reflect.Ptr {
|
||||
panic("All types must be pointers to structs.")
|
||||
}
|
||||
t = t.Elem()
|
||||
if t.Kind() != reflect.Struct {
|
||||
panic("All types must be pointers to structs.")
|
||||
}
|
||||
knownTypes[kind] = t
|
||||
s.typeToVersion[t] = version
|
||||
s.typeToKind[t] = kind
|
||||
}
|
||||
|
||||
// NewObject returns a new object of the given version and name,
|
||||
// or an error if it hasn't been registered.
|
||||
func (s *Scheme) NewObject(versionName, typeName string) (interface{}, error) {
|
||||
@@ -124,9 +159,23 @@ func (s *Scheme) NewObject(versionName, typeName string) (interface{}, error) {
|
||||
// sub-objects. We deduce how to call these functions from the types of their two
|
||||
// parameters; see the comment for Converter.Register.
|
||||
//
|
||||
// Note that, if you need to copy sub-objects that didn't change, it's safe to call
|
||||
// s.Convert() inside your conversionFuncs, as long as you don't start a conversion
|
||||
// chain that's infinitely recursive.
|
||||
// Note that, if you need to copy sub-objects that didn't change, you can use the
|
||||
// conversion.Scope object that will be passed to your conversion function.
|
||||
// Additionally, all conversions started by Scheme will set the "srcVersion" and
|
||||
// "destVersion" keys on the meta object. Example:
|
||||
//
|
||||
// s.AddConversionFuncs(
|
||||
// func(in *InternalObject, out *ExternalObject, scope conversion.Scope) error {
|
||||
// // You can depend on this being set to the source version, e.g., "".
|
||||
// s.Meta()["srcVersion"].(string)
|
||||
// // You can depend on this being set to the destination version,
|
||||
// // e.g., "v1beta1".
|
||||
// s.Meta()["destVersion"].(string)
|
||||
// // Call scope.Convert to copy sub-fields.
|
||||
// s.Convert(&in.SubFieldThatMoved, &out.NewLocation.NewName, 0)
|
||||
// return nil
|
||||
// },
|
||||
// )
|
||||
//
|
||||
// Also note that the default behavior, if you don't add a conversion function, is to
|
||||
// sanely copy fields that have the same names and same type names. It's OK if the
|
||||
@@ -144,9 +193,28 @@ func (s *Scheme) AddConversionFuncs(conversionFuncs ...interface{}) error {
|
||||
|
||||
// Convert will attempt to convert in into out. Both must be pointers. For easy
|
||||
// testing of conversion functions. Returns an error if the conversion isn't
|
||||
// possible.
|
||||
// possible. You can call this with types that haven't been registered (for example,
|
||||
// a to test conversion of types that are nested within registered types), but in
|
||||
// that case, the conversion.Scope object passed to your conversion functions won't
|
||||
// have "srcVersion" or "destVersion" keys set correctly in Meta().
|
||||
func (s *Scheme) Convert(in, out interface{}) error {
|
||||
return s.converter.Convert(in, out, 0)
|
||||
inVersion := "unknown"
|
||||
outVersion := "unknown"
|
||||
if v, _, err := s.ObjectVersionAndKind(in); err == nil {
|
||||
inVersion = v
|
||||
}
|
||||
if v, _, err := s.ObjectVersionAndKind(out); err == nil {
|
||||
outVersion = v
|
||||
}
|
||||
return s.converter.Convert(in, out, 0, s.generateConvertMeta(inVersion, outVersion))
|
||||
}
|
||||
|
||||
// generateConvertMeta assembles a map for the meta value we pass to Convert.
|
||||
func (s *Scheme) generateConvertMeta(srcVersion, destVersion string) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"srcVersion": srcVersion,
|
||||
"destVersion": destVersion,
|
||||
}
|
||||
}
|
||||
|
||||
// metaInsertion provides a default implementation of MetaInsertionFactory.
|
||||
@@ -194,11 +262,12 @@ func (s *Scheme) ObjectVersionAndKind(obj interface{}) (apiVersion, kind string,
|
||||
return "", "", err
|
||||
}
|
||||
t := v.Type()
|
||||
if version, ok := s.typeToVersion[t]; !ok {
|
||||
version, vOK := s.typeToVersion[t]
|
||||
kind, kOK := s.typeToKind[t]
|
||||
if !vOK || !kOK {
|
||||
return "", "", fmt.Errorf("Unregistered type: %v", t)
|
||||
} else {
|
||||
return version, t.Name(), nil
|
||||
}
|
||||
return version, kind, nil
|
||||
}
|
||||
|
||||
// SetVersionAndKind sets the version and kind fields (with help from
|
||||
@@ -206,7 +275,7 @@ func (s *Scheme) ObjectVersionAndKind(obj interface{}) (apiVersion, kind string,
|
||||
// must be a pointer.
|
||||
func (s *Scheme) SetVersionAndKind(version, kind string, obj interface{}) error {
|
||||
versionAndKind := s.MetaInsertionFactory.Create(version, kind)
|
||||
return s.converter.Convert(versionAndKind, obj, SourceToDest|IgnoreMissingFields|AllowDifferentFieldTypeNames)
|
||||
return s.converter.Convert(versionAndKind, obj, SourceToDest|IgnoreMissingFields|AllowDifferentFieldTypeNames, nil)
|
||||
}
|
||||
|
||||
// maybeCopy copies obj if it is not a pointer, to get a settable/addressable
|
||||
|
Reference in New Issue
Block a user