Documentation ¶
Overview ¶
Package conversion provides go object versioning and encoding/decoding mechanisms.
Specifically, conversion provides a way for you to define multiple versions of the same object. You may write functions which implement conversion logic, but for the fields which did not change, copying is automated. This makes it easy to modify the structures you use in memory without affecting the format you store on disk or respond to in your external API calls.
The second offering of this package is automated encoding/decoding. The version and type of the object is recorded in the output, so it can be recreated upon reading. Currently, conversion writes JSON output, and interprets both JSON and YAML input.
In the future, we plan to more explicitly separate the above two mechanisms, and add more serialization options, such as gob.
Index ¶
- Variables
- func EnforcePtr(obj interface{}) (reflect.Value, error)
- func IsNotRegisteredError(err error) bool
- func UpdateVersionAndKind(baseFields []string, versionField, version, kindField, kind string, ...) error
- type Converter
- func (c *Converter) Convert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta) error
- func (c *Converter) DefaultConvert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta) error
- func (c *Converter) RegisterConversionFunc(conversionFunc interface{}) error
- func (c *Converter) RegisterDefaultingFunc(defaultingFunc interface{}) error
- func (c *Converter) SetStructFieldCopy(srcFieldType interface{}, srcFieldName string, destFieldType interface{}, ...) error
- type DebugLogger
- type Equalities
- type FieldMatchingFlags
- type Meta
- type MetaFactory
- type Scheme
- func (s *Scheme) AddConversionFuncs(conversionFuncs ...interface{}) error
- func (s *Scheme) AddDefaultingFuncs(defaultingFuncs ...interface{}) error
- func (s *Scheme) AddKnownTypeWithName(version, kind string, obj interface{})
- func (s *Scheme) AddKnownTypes(version string, types ...interface{})
- func (s *Scheme) AddStructFieldConversion(srcFieldType interface{}, srcFieldName string, destFieldType interface{}, ...) error
- func (s *Scheme) Convert(in, out interface{}) error
- func (s *Scheme) ConvertToVersion(in interface{}, outVersion string) (interface{}, error)
- func (s *Scheme) DataVersionAndKind(data []byte) (version, kind string, err error)
- func (s *Scheme) Decode(data []byte) (interface{}, error)
- func (s *Scheme) DecodeInto(data []byte, obj interface{}) error
- func (s *Scheme) EncodeToVersion(obj interface{}, destVersion string) (data []byte, err error)
- func (s *Scheme) KnownTypes(version string) map[string]reflect.Type
- func (s *Scheme) Log(l DebugLogger)
- func (s *Scheme) NewObject(versionName, kind string) (interface{}, error)
- func (s *Scheme) ObjectVersionAndKind(obj interface{}) (apiVersion, kind string, err error)
- func (s *Scheme) SetVersionAndKind(version, kind string, obj interface{}) error
- type Scope
- type SimpleMetaFactory
Constants ¶
This section is empty.
Variables ¶
var DefaultMetaFactory = SimpleMetaFactory{KindField: "Kind", VersionField: "APIVersion"}
DefaultMetaFactory is a default factory for versioning objects in JSON/YAML. The object in memory and in the default JSON serialization will use the "kind" and "apiVersion" fields.
Functions ¶
func EnforcePtr ¶
EnforcePtr ensures that obj is a pointer of some sort. Returns a reflect.Value of the dereferenced pointer, ensuring that it is settable/addressable. Returns an error if this is not possible.
func IsNotRegisteredError ¶ added in v0.2.1
IsNotRegisteredError returns true if the error indicates the provided object or input data is not registered.
func UpdateVersionAndKind ¶
func UpdateVersionAndKind(baseFields []string, versionField, version, kindField, kind string, obj interface{}) error
UpdateVersionAndKind uses reflection to find and set the versionField and kindField fields on a pointer to a struct to version and kind. Provided as a convenience for others implementing MetaFactory. Pass an array to baseFields to check one or more nested structs for the named fields. The version field is treated as optional if it is not present in the struct.
Types ¶
type Converter ¶
type Converter struct { // If non-nil, will be called to print helpful debugging info. Quite verbose. Debug DebugLogger // contains filtered or unexported fields }
Converter knows how to convert one type to another.
func (*Converter) Convert ¶
func (c *Converter) Convert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta) error
Convert will translate src to dest if it knows how. Both must be pointers. If no conversion func is registered and the default copying mechanism doesn't work on this type pair, an error will be returned. Read the comments on the various FieldMatchingFlags constants to understand what the 'flags' parameter does. 'meta' is given to allow you to pass information to conversion functions, it is not used by Convert() other than storing it in the scope. Not safe for objects with cyclic references!
func (*Converter) DefaultConvert ¶ added in v0.2.1
func (c *Converter) DefaultConvert(src, dest interface{}, flags FieldMatchingFlags, meta *Meta) error
DefaultConvert will translate src to dest if it knows how. Both must be pointers. No conversion func is used. If the default copying mechanism doesn't work on this type pair, an error will be returned. Read the comments on the various FieldMatchingFlags constants to understand what the 'flags' parameter does. 'meta' is given to allow you to pass information to conversion functions, it is not used by DefaultConvert() other than storing it in the scope. Not safe for objects with cyclic references!
func (*Converter) RegisterConversionFunc ¶ added in v0.3.2
RegisterConversionFunc registers a conversion func with the Converter. conversionFunc must take three parameters: a pointer to the input type, a pointer to the output type, and a conversion.Scope (which should be used if recursive conversion calls are desired). It must return an error.
Example: c.RegisteConversionFunc(
func(in *Pod, out *v1beta1.Pod, s Scope) error { // conversion logic... return nil })
func (*Converter) RegisterDefaultingFunc ¶ added in v0.3.2
RegisterDefaultingFunc registers a value-defaulting func with the Converter. defaultingFunc must take one parameters: a pointer to the input type.
Example: c.RegisteDefaultingFunc(
func(in *v1beta1.Pod) { // defaulting logic... })
func (*Converter) SetStructFieldCopy ¶ added in v0.2.1
func (c *Converter) SetStructFieldCopy(srcFieldType interface{}, srcFieldName string, destFieldType interface{}, destFieldName string) error
SetStructFieldCopy registers a correspondence. Whenever a struct field is encountered which has a type and name matching srcFieldType and srcFieldName, it wil be copied into the field in the destination struct matching destFieldType & Name, if such a field exists. May be called multiple times, even for the same source field & type--all applicable copies will be performed.
type DebugLogger ¶
type DebugLogger interface {
Logf(format string, args ...interface{})
}
DebugLogger allows you to get debugging messages if necessary.
type Equalities ¶ added in v0.2.1
Equalities is a map from type to a function comparing two values of that type.
func EqualitiesOrDie ¶ added in v0.2.1
func EqualitiesOrDie(funcs ...interface{}) Equalities
For convenience, panics on errrors
func (Equalities) AddFunc ¶ added in v0.2.1
func (e Equalities) AddFunc(eqFunc interface{}) error
AddFunc uses func as an equality function: it must take two parameters of the same type, and return a boolean.
func (Equalities) AddFuncs ¶ added in v0.2.1
func (e Equalities) AddFuncs(funcs ...interface{}) error
AddFuncs is a shortcut for multiple calls to AddFunc.
func (Equalities) DeepDerivative ¶ added in v0.3.2
func (e Equalities) DeepDerivative(a1, a2 interface{}) bool
DeepDerivative is similar to DeepEqual except that unset fields in a1 are ignored (not compared). This allows us to focus on the fields that matter to the semantic comparison.
The unset fields include a nil pointer and an empty string.
func (Equalities) DeepEqual ¶ added in v0.2.1
func (e Equalities) DeepEqual(a1, a2 interface{}) bool
DeepEqual is like reflect.DeepEqual, but focused on semantic equality instead of memory equality.
It will use e's equality functions if it finds types that match.
An empty slice *is* equal to a nil slice for our purposes; same for maps.
Unexported field members are not compared.
func (Equalities) Equal ¶ added in v0.2.1
func (e Equalities) Equal(a, b interface{}) bool
Equal return true if a matching equality function thinks a == b; if there is no matching equality function, it calls the standard go == operator.
type FieldMatchingFlags ¶
type FieldMatchingFlags int
FieldMatchingFlags contains a list of ways in which struct fields could be copied. These constants may be | combined.
const ( // Loop through destination fields, search for matching source // field to copy it from. Source fields with no corresponding // destination field will be ignored. If SourceToDest is // specified, this flag is ignored. If niether is specified, // or no flags are passed, this flag is the default. DestFromSource FieldMatchingFlags = 0 // Loop through source fields, search for matching dest field // to copy it into. Destination fields with no corresponding // source field will be ignored. SourceToDest FieldMatchingFlags = 1 << iota // Don't treat it as an error if the corresponding source or // dest field can't be found. IgnoreMissingFields // Don't require type names to match. AllowDifferentFieldTypeNames )
func (FieldMatchingFlags) IsSet ¶
func (f FieldMatchingFlags) IsSet(flag FieldMatchingFlags) bool
IsSet returns true if the given flag or combination of flags is set.
type MetaFactory ¶
type MetaFactory interface { // Update sets the given version and kind onto the object. Update(version, kind string, obj interface{}) error // Interpret should return the version and kind of the wire-format of // the object. Interpret(data []byte) (version, kind string, err error) }
MetaFactory is used to store and retrieve the version and kind information for all objects in a scheme.
type Scheme ¶
type Scheme struct { // Indent will cause the JSON output from Encode to be indented, iff it is true. Indent bool // InternalVersion is the default internal version. It is recommended that // you use "" for the internal version. InternalVersion string // MetaInsertionFactory is used to create an object to store and retrieve // the version and kind information for all objects. The default uses the // keys "apiVersion" and "kind" respectively. MetaFactory MetaFactory // contains filtered or unexported fields }
Scheme defines an entire encoding and decoding scheme.
func (*Scheme) AddConversionFuncs ¶
AddConversionFuncs adds functions to the list of conversion functions. The given functions should know how to convert between two of your API objects, or their 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, 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 fields on the Meta object. Example:
s.AddConversionFuncs(
func(in *InternalObject, out *ExternalObject, scope conversion.Scope) error { // You can depend on Meta() being non-nil, and this being set to // the source version, e.g., "" s.Meta().SrcVersion // You can depend on this being set to the destination version, // e.g., "v1beta1". s.Meta().DestVersion // Call scope.Convert to copy sub-fields. s.Convert(&in.SubFieldThatMoved, &out.NewLocation.NewName, 0) return nil },
)
(For more detail about conversion functions, see Converter.Register's comment.)
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 destination type has extra fields, but it must not remove any. So you only need to add conversion functions for things with changed/removed fields.
func (*Scheme) AddDefaultingFuncs ¶ added in v0.3.2
AddDefaultingFuncs adds functions to the list of default-value functions. Each of the given functions is responsible for applying default values when converting an instance of a versioned API object into an internal API object. These functions do not need to handle sub-objects. We deduce how to call these functions from the types of their two parameters.
s.AddDefaultingFuncs(
func(obj *v1beta1.Pod) { if obj.OptionalField == "" { obj.OptionalField = "DefaultValue" } },
)
func (*Scheme) AddKnownTypeWithName ¶
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 (*Scheme) AddKnownTypes ¶
AddKnownTypes registers all types passed in 'types' as being members of version 'version. Encode() will refuse objects unless their type has been registered with AddKnownTypes. All objects passed to types should be pointers to structs. The name that go reports for the struct becomes the "kind" field when encoding.
func (*Scheme) AddStructFieldConversion ¶ added in v0.2.1
func (s *Scheme) AddStructFieldConversion(srcFieldType interface{}, srcFieldName string, destFieldType interface{}, destFieldName string) error
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 Converter.SetStructFieldCopy for parameter details. Call as many times as needed, even on the same fields.
func (*Scheme) Convert ¶
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. 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 fields set correctly in Meta().
func (*Scheme) ConvertToVersion ¶ added in v0.2.1
ConvertToVersion attempts to convert an input object to its matching Kind in another version within this scheme. Will return an error if the provided version does not contain the inKind (or a mapping by name defined with AddKnownTypeWithName).
func (*Scheme) DataVersionAndKind ¶
DataVersionAndKind will return the APIVersion and Kind of the given wire-format encoding of an API Object, or an error.
func (*Scheme) Decode ¶
Decode converts a YAML or JSON string back into a pointer to an api object. Deduces the type based upon the fields added by the MetaInsertionFactory technique. The object will be converted, if necessary, into the s.InternalVersion type before being returned. Decode will not decode objects without version set unless InternalVersion is also "".
func (*Scheme) DecodeInto ¶
DecodeInto parses a YAML or JSON string and stores it in obj. Returns an error if data.Kind is set and doesn't match the type of obj. Obj should be a pointer to an api type. If obj's version doesn't match that in data, an attempt will be made to convert data into obj's version.
func (*Scheme) EncodeToVersion ¶
EncodeToVersion turns the given api object into an appropriate JSON string. Obj may be a pointer to a struct, or a struct. If a struct, a copy will be made, therefore it's recommended to pass a pointer to a struct. The type must have been registered.
Memory/wire format differences:
- Having to keep track of the Kind and Version fields makes tests very annoying, so the rule is that they are set only in wire format (json), not when in native (memory) format. This is possible because both pieces of information are implicit in the go typed object.
- An exception: note that, if there are embedded API objects of known type, for example, PodList{... Items []Pod ...}, these embedded objects must be of the same version of the object they are embedded within, and their Version and Kind must both be empty.
- Note that the exception does not apply to a generic APIObject type which recursively does Encode()/Decode(), and is capable of expressing any API object.
- Only versioned objects should be encoded. This means that, if you pass a native object, Encode will convert it to a versioned object. For example, an api.Pod will get converted to a v1beta1.Pod. However, if you pass in an object that's already versioned (v1beta1.Pod), Encode will not modify it.
The purpose of the above complex conversion behavior is to allow us to change the memory format yet not break compatibility with any stored objects, whether they be in our storage layer (e.g., etcd), or in user's config files.
func (*Scheme) KnownTypes ¶
KnownTypes returns an array of the types that are known for a particular version.
func (*Scheme) Log ¶
func (s *Scheme) Log(l DebugLogger)
Log sets a logger on the scheme. For test purposes only
func (*Scheme) NewObject ¶
NewObject returns a new object of the given version and name, or an error if it hasn't been registered.
func (*Scheme) ObjectVersionAndKind ¶
ObjectVersionAndKind returns the API version and kind of the go object, or an error if it's not a pointer or is unregistered.
func (*Scheme) SetVersionAndKind ¶
SetVersionAndKind sets the version and kind fields (with help from MetaInsertionFactory). Returns an error if this isn't possible. obj must be a pointer.
type Scope ¶
type Scope interface { // Call Convert to convert sub-objects. Note that if you call it with your own exact // parameters, you'll run out of stack space before anything useful happens. Convert(src, dest interface{}, flags FieldMatchingFlags) error // DefaultConvert performs the default conversion, without calling a conversion func // on the current stack frame. This makes it safe to call from a conversion func. DefaultConvert(src, dest interface{}, flags FieldMatchingFlags) error // SrcTags and DestTags contain the struct tags that src and dest had, respectively. // If the enclosing object was not a struct, then these will contain no tags, of course. SrcTag() reflect.StructTag DestTag() reflect.StructTag // Flags returns the flags with which the conversion was started. Flags() FieldMatchingFlags // Meta returns any information originally passed to Convert. Meta() *Meta }
Scope is passed to conversion funcs to allow them to continue an ongoing conversion. If multiple converters exist in the system, Scope will allow you to use the correct one from a conversion function--that is, the one your conversion function was called by.
type SimpleMetaFactory ¶
type SimpleMetaFactory struct { // The name of the API version field in memory of the struct VersionField string // The name of the kind field in memory of the struct. KindField string // Optional, if set will look in the named inline structs to find the fields to set. BaseFields []string }
SimpleMetaFactory provides default methods for retrieving the type and version of objects that are identified with an "apiVersion" and "kind" fields in their JSON/YAML serialization. It may be parameterized with the names of the fields in memory, or an optional list of base structs to search for those fields in memory.
func (SimpleMetaFactory) Interpret ¶
func (SimpleMetaFactory) Interpret(data []byte) (version, kind string, err error)
Interpret will return the APIVersion and Kind of the JSON/YAML wire-format encoding of an object, or an error.
func (SimpleMetaFactory) Update ¶
func (f SimpleMetaFactory) Update(version, kind string, obj interface{}) error