2014-06-20 22:12:12 +00:00
|
|
|
/*
|
2015-05-01 16:19:44 +00:00
|
|
|
Copyright 2014 The Kubernetes Authors All rights reserved.
|
2014-06-20 22:12:12 +00:00
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2014-09-02 17:55:27 +00:00
|
|
|
package runtime
|
2014-06-20 22:12:12 +00:00
|
|
|
|
|
|
|
import (
|
2015-04-29 03:15:16 +00:00
|
|
|
"encoding/json"
|
2014-11-01 22:38:02 +00:00
|
|
|
"fmt"
|
2015-09-18 00:43:05 +00:00
|
|
|
"io"
|
2015-03-22 21:43:00 +00:00
|
|
|
"net/url"
|
2014-06-20 22:12:12 +00:00
|
|
|
"reflect"
|
2015-04-16 23:21:13 +00:00
|
|
|
|
2015-11-17 15:07:45 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/conversion"
|
2014-06-20 22:12:12 +00:00
|
|
|
)
|
|
|
|
|
2014-09-05 23:11:30 +00:00
|
|
|
// Scheme defines methods for serializing and deserializing API objects. It
|
|
|
|
// is an adaptation of conversion's Scheme for our API objects.
|
|
|
|
type Scheme struct {
|
|
|
|
raw *conversion.Scheme
|
2015-03-02 23:00:09 +00:00
|
|
|
// 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
|
2014-09-05 23:11:30 +00:00
|
|
|
}
|
|
|
|
|
2015-11-17 15:07:45 +00:00
|
|
|
var _ Decoder = &Scheme{}
|
|
|
|
|
2015-03-02 23:00:09 +00:00
|
|
|
// Function to convert a field selector to internal representation.
|
|
|
|
type FieldLabelConversionFunc func(label, value string) (internalLabel, internalValue string, err error)
|
|
|
|
|
2015-04-22 12:25:28 +00:00
|
|
|
func (self *Scheme) Raw() *conversion.Scheme {
|
|
|
|
return self.raw
|
|
|
|
}
|
|
|
|
|
2014-09-11 00:28:07 +00:00
|
|
|
// fromScope gets the input version, desired output version, and desired Scheme
|
|
|
|
// from a conversion.Scope.
|
2014-09-11 17:02:53 +00:00
|
|
|
func (self *Scheme) fromScope(s conversion.Scope) (inVersion, outVersion string, scheme *Scheme) {
|
|
|
|
scheme = self
|
2014-09-11 19:31:46 +00:00
|
|
|
inVersion = s.Meta().SrcVersion
|
|
|
|
outVersion = s.Meta().DestVersion
|
2014-09-11 00:28:07 +00:00
|
|
|
return inVersion, outVersion, scheme
|
|
|
|
}
|
|
|
|
|
|
|
|
// emptyPlugin is used to copy the Kind field to and from plugin objects.
|
|
|
|
type emptyPlugin struct {
|
2014-12-01 05:31:52 +00:00
|
|
|
PluginBase `json:",inline"`
|
2014-09-11 00:28:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// embeddedObjectToRawExtension does the conversion you would expect from the name, using the information
|
|
|
|
// given in conversion.Scope. It's placed in the DefaultScheme as a ConversionFunc to enable plugins;
|
|
|
|
// see the comment for RawExtension.
|
2014-09-11 17:02:53 +00:00
|
|
|
func (self *Scheme) embeddedObjectToRawExtension(in *EmbeddedObject, out *RawExtension, s conversion.Scope) error {
|
2014-09-11 00:28:07 +00:00
|
|
|
if in.Object == nil {
|
|
|
|
out.RawJSON = []byte("null")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Figure out the type and kind of the output object.
|
2014-09-11 17:02:53 +00:00
|
|
|
_, outVersion, scheme := self.fromScope(s)
|
2014-09-11 00:28:07 +00:00
|
|
|
_, kind, err := scheme.raw.ObjectVersionAndKind(in.Object)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Manufacture an object of this type and kind.
|
|
|
|
outObj, err := scheme.New(outVersion, kind)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Manually do the conversion.
|
|
|
|
err = s.Convert(in.Object, outObj, 0)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-08-08 21:29:57 +00:00
|
|
|
// Copy the kind field into the output object.
|
2014-09-11 00:28:07 +00:00
|
|
|
err = s.Convert(
|
|
|
|
&emptyPlugin{PluginBase: PluginBase{Kind: kind}},
|
|
|
|
outObj,
|
|
|
|
conversion.SourceToDest|conversion.IgnoreMissingFields|conversion.AllowDifferentFieldTypeNames,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// Because we provide the correct version, EncodeToVersion will not attempt a conversion.
|
|
|
|
raw, err := scheme.EncodeToVersion(outObj, outVersion)
|
|
|
|
if err != nil {
|
|
|
|
// TODO: if this fails, create an Unknown-- maybe some other
|
|
|
|
// component will understand it.
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
out.RawJSON = raw
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// rawExtensionToEmbeddedObject does the conversion you would expect from the name, using the information
|
2014-09-18 10:08:10 +00:00
|
|
|
// given in conversion.Scope. It's placed in all schemes as a ConversionFunc to enable plugins;
|
2014-09-11 00:28:07 +00:00
|
|
|
// see the comment for RawExtension.
|
2014-09-11 17:02:53 +00:00
|
|
|
func (self *Scheme) rawExtensionToEmbeddedObject(in *RawExtension, out *EmbeddedObject, s conversion.Scope) error {
|
2015-02-02 19:21:50 +00:00
|
|
|
if len(in.RawJSON) == 0 || (len(in.RawJSON) == 4 && string(in.RawJSON) == "null") {
|
2014-09-11 00:28:07 +00:00
|
|
|
out.Object = nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
// Figure out the type and kind of the output object.
|
2014-09-11 17:02:53 +00:00
|
|
|
inVersion, outVersion, scheme := self.fromScope(s)
|
2014-09-11 00:28:07 +00:00
|
|
|
_, kind, err := scheme.raw.DataVersionAndKind(in.RawJSON)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have to make this object ourselves because we don't store the version field for
|
|
|
|
// plugin objects.
|
|
|
|
inObj, err := scheme.New(inVersion, kind)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = scheme.DecodeInto(in.RawJSON, inObj)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make the desired internal version, and do the conversion.
|
|
|
|
outObj, err := scheme.New(outVersion, kind)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = scheme.Convert(inObj, outObj)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// Last step, clear the Kind field; that should always be blank in memory.
|
|
|
|
err = s.Convert(
|
|
|
|
&emptyPlugin{PluginBase: PluginBase{Kind: ""}},
|
|
|
|
outObj,
|
|
|
|
conversion.SourceToDest|conversion.IgnoreMissingFields|conversion.AllowDifferentFieldTypeNames,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
out.Object = outObj
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-12-03 13:41:57 +00:00
|
|
|
// runtimeObjectToRawExtensionArray takes a list of objects and encodes them as RawExtension in the output version
|
2015-04-16 23:21:13 +00:00
|
|
|
// defined by the conversion.Scope. If objects must be encoded to different schema versions than the default, you
|
|
|
|
// should encode them yourself with runtime.Unknown, or convert the object prior to invoking conversion. Objects
|
|
|
|
// outside of the current scheme must be added as runtime.Unknown.
|
2014-12-03 13:41:57 +00:00
|
|
|
func (self *Scheme) runtimeObjectToRawExtensionArray(in *[]Object, out *[]RawExtension, s conversion.Scope) error {
|
|
|
|
src := *in
|
|
|
|
dest := make([]RawExtension, len(src))
|
|
|
|
|
|
|
|
_, outVersion, scheme := self.fromScope(s)
|
|
|
|
|
|
|
|
for i := range src {
|
|
|
|
switch t := src[i].(type) {
|
|
|
|
case *Unknown:
|
2015-04-29 03:15:16 +00:00
|
|
|
// TODO: this should be decoupled from the scheme (since it is JSON specific)
|
2014-12-03 13:41:57 +00:00
|
|
|
dest[i].RawJSON = t.RawJSON
|
2015-04-29 03:15:16 +00:00
|
|
|
case *Unstructured:
|
|
|
|
// TODO: this should be decoupled from the scheme (since it is JSON specific)
|
|
|
|
data, err := json.Marshal(t.Object)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
dest[i].RawJSON = data
|
2014-12-03 13:41:57 +00:00
|
|
|
default:
|
2015-04-16 23:21:13 +00:00
|
|
|
version := outVersion
|
|
|
|
// if the object exists
|
|
|
|
if inVersion, _, err := scheme.ObjectVersionAndKind(src[i]); err == nil && len(inVersion) != 0 {
|
|
|
|
version = inVersion
|
|
|
|
}
|
|
|
|
data, err := scheme.EncodeToVersion(src[i], version)
|
2014-12-03 13:41:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
dest[i].RawJSON = data
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*out = dest
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// rawExtensionToRuntimeObjectArray attempts to decode objects from the array - if they are unrecognized objects,
|
|
|
|
// they are added as Unknown.
|
|
|
|
func (self *Scheme) rawExtensionToRuntimeObjectArray(in *[]RawExtension, out *[]Object, s conversion.Scope) error {
|
|
|
|
src := *in
|
|
|
|
dest := make([]Object, len(src))
|
|
|
|
|
|
|
|
_, _, scheme := self.fromScope(s)
|
|
|
|
|
|
|
|
for i := range src {
|
|
|
|
data := src[i].RawJSON
|
2015-04-29 03:15:16 +00:00
|
|
|
version, kind, err := scheme.raw.DataVersionAndKind(data)
|
2014-12-03 13:41:57 +00:00
|
|
|
if err != nil {
|
2015-04-29 03:15:16 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
dest[i] = &Unknown{
|
|
|
|
TypeMeta: TypeMeta{
|
|
|
|
APIVersion: version,
|
|
|
|
Kind: kind,
|
|
|
|
},
|
|
|
|
RawJSON: data,
|
2014-12-03 13:41:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
*out = dest
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-09-11 17:02:53 +00:00
|
|
|
// NewScheme creates a new Scheme. This scheme is pluggable by default.
|
|
|
|
func NewScheme() *Scheme {
|
2015-03-02 23:00:09 +00:00
|
|
|
s := &Scheme{conversion.NewScheme(), map[string]map[string]FieldLabelConversionFunc{}}
|
2014-09-11 17:02:53 +00:00
|
|
|
s.raw.InternalVersion = ""
|
2014-10-09 22:32:46 +00:00
|
|
|
s.raw.MetaFactory = conversion.SimpleMetaFactory{BaseFields: []string{"TypeMeta"}, VersionField: "APIVersion", KindField: "Kind"}
|
2014-12-03 13:41:57 +00:00
|
|
|
if err := s.raw.AddConversionFuncs(
|
2014-09-11 17:02:53 +00:00
|
|
|
s.embeddedObjectToRawExtension,
|
|
|
|
s.rawExtensionToEmbeddedObject,
|
2014-12-03 13:41:57 +00:00
|
|
|
s.runtimeObjectToRawExtensionArray,
|
|
|
|
s.rawExtensionToRuntimeObjectArray,
|
|
|
|
); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2015-03-22 00:43:52 +00:00
|
|
|
// Enable map[string][]string conversions by default
|
|
|
|
if err := s.raw.AddConversionFuncs(DefaultStringConversions...); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
if err := s.raw.RegisterInputDefaults(&map[string][]string{}, JSONKeyMapper, conversion.AllowDifferentFieldTypeNames|conversion.IgnoreMissingFields); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2015-03-22 21:43:00 +00:00
|
|
|
if err := s.raw.RegisterInputDefaults(&url.Values{}, JSONKeyMapper, conversion.AllowDifferentFieldTypeNames|conversion.IgnoreMissingFields); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2014-09-05 23:11:30 +00:00
|
|
|
return s
|
2014-06-20 23:08:54 +00:00
|
|
|
}
|
|
|
|
|
2014-07-08 07:08:58 +00:00
|
|
|
// AddKnownTypes registers the types of the arguments to the marshaller of the package api.
|
|
|
|
// Encode() refuses the object unless its type is registered with AddKnownTypes.
|
2014-09-05 23:11:30 +00:00
|
|
|
func (s *Scheme) AddKnownTypes(version string, types ...Object) {
|
|
|
|
interfaces := make([]interface{}, len(types))
|
|
|
|
for i := range types {
|
|
|
|
interfaces[i] = types[i]
|
|
|
|
}
|
|
|
|
s.raw.AddKnownTypes(version, interfaces...)
|
2014-06-20 22:12:12 +00:00
|
|
|
}
|
|
|
|
|
2014-09-11 00:28:07 +00:00
|
|
|
// 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 Object) {
|
|
|
|
s.raw.AddKnownTypeWithName(version, kind, obj)
|
|
|
|
}
|
|
|
|
|
2014-09-27 00:29:46 +00:00
|
|
|
// KnownTypes returns the types known for the given version.
|
|
|
|
// Return value must be treated as read-only.
|
2014-09-11 17:02:53 +00:00
|
|
|
func (s *Scheme) KnownTypes(version string) map[string]reflect.Type {
|
|
|
|
return s.raw.KnownTypes(version)
|
|
|
|
}
|
|
|
|
|
2014-10-29 16:10:55 +00:00
|
|
|
// DataVersionAndKind will return the APIVersion and Kind of the given wire-format
|
2014-10-27 02:21:31 +00:00
|
|
|
// encoding of an API Object, or an error.
|
2014-10-29 16:10:55 +00:00
|
|
|
func (s *Scheme) DataVersionAndKind(data []byte) (version, kind string, err error) {
|
|
|
|
return s.raw.DataVersionAndKind(data)
|
|
|
|
}
|
|
|
|
|
2014-09-27 00:29:46 +00:00
|
|
|
// ObjectVersionAndKind returns the version and kind of the given Object.
|
|
|
|
func (s *Scheme) ObjectVersionAndKind(obj Object) (version, kind string, err error) {
|
|
|
|
return s.raw.ObjectVersionAndKind(obj)
|
|
|
|
}
|
|
|
|
|
2015-04-29 03:15:16 +00:00
|
|
|
// Recognizes returns true if the scheme is able to handle the provided version and kind
|
|
|
|
// of an object.
|
|
|
|
func (s *Scheme) Recognizes(version, kind string) bool {
|
|
|
|
return s.raw.Recognizes(version, kind)
|
|
|
|
}
|
|
|
|
|
2014-07-26 00:59:41 +00:00
|
|
|
// New returns a new API object of the given version ("" for internal
|
|
|
|
// representation) and name, or an error if it hasn't been registered.
|
2014-09-05 23:11:30 +00:00
|
|
|
func (s *Scheme) New(versionName, typeName string) (Object, error) {
|
|
|
|
obj, err := s.raw.NewObject(versionName, typeName)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return obj.(Object), nil
|
2014-07-26 00:59:41 +00:00
|
|
|
}
|
|
|
|
|
2014-10-05 21:17:25 +00:00
|
|
|
// Log sets a logger on the scheme. For test purposes only
|
|
|
|
func (s *Scheme) Log(l conversion.DebugLogger) {
|
|
|
|
s.raw.Log(l)
|
|
|
|
}
|
|
|
|
|
2014-07-28 22:13:17 +00:00
|
|
|
// AddConversionFuncs adds a function to the list of conversion functions. The given
|
|
|
|
// function should know how to convert between two API objects. We deduce how to call
|
2014-11-22 23:44:38 +00:00
|
|
|
// it from the types of its two parameters; see the comment for
|
|
|
|
// Converter.RegisterConversionFunction.
|
2014-07-28 22:13:17 +00:00
|
|
|
//
|
|
|
|
// Note that, if you need to copy sub-objects that didn't change, it's safe to call
|
|
|
|
// Convert() inside your conversionFuncs, as long as you don't start a conversion
|
|
|
|
// chain that's infinitely recursive.
|
|
|
|
//
|
|
|
|
// Also note that the default behavior, if you don't add a conversion function, is to
|
|
|
|
// sanely copy fields that have the same names. It's OK if the destination type has
|
|
|
|
// extra fields, but it must not remove any. So you only need to add a conversion
|
|
|
|
// function for things with changed/removed fields.
|
2014-09-05 23:11:30 +00:00
|
|
|
func (s *Scheme) AddConversionFuncs(conversionFuncs ...interface{}) error {
|
|
|
|
return s.raw.AddConversionFuncs(conversionFuncs...)
|
2014-07-28 22:13:17 +00:00
|
|
|
}
|
|
|
|
|
2015-04-22 10:10:23 +00:00
|
|
|
// Similar to AddConversionFuncs, but registers conversion functions that were
|
|
|
|
// automatically generated.
|
|
|
|
func (s *Scheme) AddGeneratedConversionFuncs(conversionFuncs ...interface{}) error {
|
|
|
|
return s.raw.AddGeneratedConversionFuncs(conversionFuncs...)
|
|
|
|
}
|
|
|
|
|
2015-05-13 13:52:53 +00:00
|
|
|
// AddDeepCopyFuncs adds a function to the list of deep-copy functions.
|
|
|
|
// For the expected format of deep-copy function, see the comment for
|
|
|
|
// Copier.RegisterDeepCopyFunction.
|
|
|
|
func (s *Scheme) AddDeepCopyFuncs(deepCopyFuncs ...interface{}) error {
|
|
|
|
return s.raw.AddDeepCopyFuncs(deepCopyFuncs...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Similar to AddDeepCopyFuncs, but registers deep-copy functions that were
|
|
|
|
// automatically generated.
|
|
|
|
func (s *Scheme) AddGeneratedDeepCopyFuncs(deepCopyFuncs ...interface{}) error {
|
|
|
|
return s.raw.AddGeneratedDeepCopyFuncs(deepCopyFuncs...)
|
|
|
|
}
|
|
|
|
|
2015-03-02 23:00:09 +00:00
|
|
|
// AddFieldLabelConversionFunc adds a conversion function to convert field selectors
|
2015-03-22 21:43:00 +00:00
|
|
|
// of the given kind from the given version to internal version representation.
|
|
|
|
func (s *Scheme) AddFieldLabelConversionFunc(version, kind string, conversionFunc FieldLabelConversionFunc) error {
|
2015-03-02 23:00:09 +00:00
|
|
|
if s.fieldLabelConversionFuncs[version] == nil {
|
|
|
|
s.fieldLabelConversionFuncs[version] = map[string]FieldLabelConversionFunc{}
|
|
|
|
}
|
|
|
|
|
2015-03-22 21:43:00 +00:00
|
|
|
s.fieldLabelConversionFuncs[version][kind] = conversionFunc
|
2015-03-02 23:00:09 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-11-22 07:58:12 +00:00
|
|
|
// 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.raw.AddStructFieldConversion(srcFieldType, srcFieldName, destFieldType, destFieldName)
|
|
|
|
}
|
|
|
|
|
2014-11-22 23:44:38 +00:00
|
|
|
// AddDefaultingFuncs adds a function to the list of value-defaulting functions.
|
|
|
|
// We deduce how to call it from the types of its two parameters; see the
|
|
|
|
// comment for Converter.RegisterDefaultingFunction.
|
|
|
|
func (s *Scheme) AddDefaultingFuncs(defaultingFuncs ...interface{}) error {
|
|
|
|
return s.raw.AddDefaultingFuncs(defaultingFuncs...)
|
|
|
|
}
|
|
|
|
|
2015-05-13 13:52:53 +00:00
|
|
|
// Performs a deep copy of the given object.
|
|
|
|
func (s *Scheme) DeepCopy(src interface{}) (interface{}, error) {
|
|
|
|
return s.raw.DeepCopy(src)
|
|
|
|
}
|
|
|
|
|
2014-09-05 23:11:30 +00:00
|
|
|
// Convert will attempt to convert in into out. Both must be pointers.
|
2014-07-28 22:13:17 +00:00
|
|
|
// For easy testing of conversion functions. Returns an error if the conversion isn't
|
|
|
|
// possible.
|
2014-09-05 23:11:30 +00:00
|
|
|
func (s *Scheme) Convert(in, out interface{}) error {
|
|
|
|
return s.raw.Convert(in, out)
|
2014-07-16 21:30:28 +00:00
|
|
|
}
|
|
|
|
|
2015-03-22 21:43:00 +00:00
|
|
|
// Converts the given field label and value for an kind field selector from
|
2015-03-02 23:00:09 +00:00
|
|
|
// versioned representation to an unversioned one.
|
2015-03-22 21:43:00 +00:00
|
|
|
func (s *Scheme) ConvertFieldLabel(version, kind, label, value string) (string, string, error) {
|
2015-03-09 21:39:04 +00:00
|
|
|
if s.fieldLabelConversionFuncs[version] == nil {
|
2015-06-10 16:47:21 +00:00
|
|
|
return "", "", fmt.Errorf("No field label conversion function found for version: %s", version)
|
2015-03-09 21:39:04 +00:00
|
|
|
}
|
2015-03-22 21:43:00 +00:00
|
|
|
conversionFunc, ok := s.fieldLabelConversionFuncs[version][kind]
|
2015-03-09 21:39:04 +00:00
|
|
|
if !ok {
|
2015-06-10 16:47:21 +00:00
|
|
|
return "", "", fmt.Errorf("No field label conversion function found for version %s and kind %s", version, kind)
|
2015-03-02 23:00:09 +00:00
|
|
|
}
|
2015-03-09 21:39:04 +00:00
|
|
|
return conversionFunc(label, value)
|
2015-03-02 23:00:09 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 22:38:02 +00:00
|
|
|
// 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). Will also
|
|
|
|
// return an error if the conversion does not result in a valid Object being
|
|
|
|
// returned.
|
|
|
|
func (s *Scheme) ConvertToVersion(in Object, outVersion string) (Object, error) {
|
|
|
|
unknown, err := s.raw.ConvertToVersion(in, outVersion)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
obj, ok := unknown.(Object)
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("the provided object cannot be converted to a runtime.Object: %#v", unknown)
|
|
|
|
}
|
|
|
|
return obj, nil
|
|
|
|
}
|
|
|
|
|
2014-09-11 17:02:53 +00:00
|
|
|
// EncodeToVersion turns the given api object into an appropriate JSON string.
|
2014-10-07 15:12:16 +00:00
|
|
|
// Will return an error if the object doesn't have an embedded TypeMeta.
|
2014-06-20 23:08:54 +00:00
|
|
|
// Obj may be a pointer to a struct, or a struct. If a struct, a copy
|
2014-07-26 00:59:41 +00:00
|
|
|
// must be made. If a pointer, the object may be modified before encoding,
|
|
|
|
// but will be put back into its original state before returning.
|
|
|
|
//
|
|
|
|
// Memory/wire format differences:
|
|
|
|
// * Having to keep track of the Kind and APIVersion 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 APIVersion and Kind must both be empty.
|
|
|
|
// * Note that the exception does not apply to the 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
|
2015-11-05 10:48:03 +00:00
|
|
|
// example, an api.Pod will get converted to a v1.Pod. However, if
|
|
|
|
// you pass in an object that's already versioned (v1.Pod), Encode
|
2014-07-26 00:59:41 +00:00
|
|
|
// 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.
|
2014-09-11 00:28:07 +00:00
|
|
|
func (s *Scheme) EncodeToVersion(obj Object, destVersion string) (data []byte, err error) {
|
|
|
|
return s.raw.EncodeToVersion(obj, destVersion)
|
|
|
|
}
|
|
|
|
|
2015-09-18 00:43:05 +00:00
|
|
|
func (s *Scheme) EncodeToVersionStream(obj Object, destVersion string, stream io.Writer) error {
|
|
|
|
return s.raw.EncodeToVersionStream(obj, destVersion, stream)
|
|
|
|
}
|
|
|
|
|
2014-07-26 00:59:41 +00:00
|
|
|
// Decode converts a YAML or JSON string back into a pointer to an api object.
|
|
|
|
// Deduces the type based upon the APIVersion and Kind fields, which are set
|
|
|
|
// by Encode. Only versioned objects (APIVersion != "") are accepted. The object
|
|
|
|
// will be converted into the in-memory unversioned type before being returned.
|
2014-09-05 23:11:30 +00:00
|
|
|
func (s *Scheme) Decode(data []byte) (Object, error) {
|
|
|
|
obj, err := s.raw.Decode(data)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return obj.(Object), nil
|
2014-06-20 22:12:12 +00:00
|
|
|
}
|
|
|
|
|
2015-08-07 19:45:20 +00:00
|
|
|
// DecodeToVersion converts a YAML or JSON string back into a pointer to an api
|
|
|
|
// object. Deduces the type based upon the APIVersion and Kind fields, which
|
|
|
|
// are set by Encode. Only versioned objects (APIVersion != "") are
|
|
|
|
// accepted. The object will be converted into the in-memory versioned type
|
|
|
|
// requested before being returned.
|
2015-11-17 15:07:45 +00:00
|
|
|
func (s *Scheme) DecodeToVersion(data []byte, gv unversioned.GroupVersion) (Object, error) {
|
|
|
|
obj, err := s.raw.DecodeToVersion(data, gv)
|
2015-08-07 19:45:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return obj.(Object), nil
|
|
|
|
}
|
|
|
|
|
2014-07-26 00:59:41 +00:00
|
|
|
// DecodeInto parses a YAML or JSON string and stores it in obj. Returns an error
|
2014-06-20 22:12:12 +00:00
|
|
|
// if data.Kind is set and doesn't match the type of obj. Obj should be a
|
|
|
|
// pointer to an api type.
|
2014-07-26 00:59:41 +00:00
|
|
|
// If obj's APIVersion doesn't match that in data, an attempt will be made to convert
|
|
|
|
// data into obj's version.
|
2015-01-19 02:22:55 +00:00
|
|
|
// TODO: allow Decode/DecodeInto to take a default apiVersion and a default kind, to
|
|
|
|
// be applied if the provided object does not have either field (integrate external
|
|
|
|
// apis into the decoding scheme).
|
2014-09-05 23:11:30 +00:00
|
|
|
func (s *Scheme) DecodeInto(data []byte, obj Object) error {
|
|
|
|
return s.raw.DecodeInto(data, obj)
|
2014-07-16 21:30:28 +00:00
|
|
|
}
|
2014-08-01 21:24:12 +00:00
|
|
|
|
2015-11-17 15:07:45 +00:00
|
|
|
func (s *Scheme) DecodeIntoWithSpecifiedVersionKind(data []byte, obj Object, gvk unversioned.GroupVersionKind) error {
|
|
|
|
return s.raw.DecodeIntoWithSpecifiedVersionKind(data, obj, gvk)
|
2015-06-20 00:16:25 +00:00
|
|
|
}
|
|
|
|
|
2015-11-10 09:20:57 +00:00
|
|
|
func (s *Scheme) DecodeParametersInto(parameters url.Values, obj Object) error {
|
|
|
|
return s.raw.DecodeParametersInto(parameters, obj)
|
|
|
|
}
|
|
|
|
|
2014-09-11 17:02:53 +00:00
|
|
|
// Copy does a deep copy of an API object. Useful mostly for tests.
|
2015-06-17 18:59:12 +00:00
|
|
|
func (s *Scheme) Copy(src Object) (Object, error) {
|
|
|
|
dst, err := s.raw.DeepCopy(src)
|
2014-08-25 22:10:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-06-17 18:59:12 +00:00
|
|
|
return dst.(Object), nil
|
2014-08-25 22:10:01 +00:00
|
|
|
}
|
|
|
|
|
2014-09-05 23:11:30 +00:00
|
|
|
func (s *Scheme) CopyOrDie(obj Object) Object {
|
|
|
|
newObj, err := s.Copy(obj)
|
2014-08-25 22:10:01 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return newObj
|
|
|
|
}
|