github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/k8s.io/kubernetes/pkg/conversion/scheme.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes Authors All rights reserved.
     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 conversion
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  )
    23  
    24  // Scheme defines an entire encoding and decoding scheme.
    25  type Scheme struct {
    26  	// versionMap allows one to figure out the go type of an object with
    27  	// the given version and name.
    28  	versionMap map[string]map[string]reflect.Type
    29  
    30  	// typeToVersion allows one to figure out the version for a given go object.
    31  	// The reflect.Type we index by should *not* be a pointer. If the same type
    32  	// is registered for multiple versions, the last one wins.
    33  	typeToVersion map[reflect.Type]string
    34  
    35  	// typeToKind allows one to figure out the desired "kind" field for a given
    36  	// go object. Requirements and caveats are the same as typeToVersion.
    37  	typeToKind map[reflect.Type][]string
    38  
    39  	// converter stores all registered conversion functions. It also has
    40  	// default coverting behavior.
    41  	converter *Converter
    42  
    43  	// cloner stores all registered copy functions. It also has default
    44  	// deep copy behavior.
    45  	cloner *Cloner
    46  
    47  	// Indent will cause the JSON output from Encode to be indented,
    48  	// if and only if it is true.
    49  	Indent bool
    50  
    51  	// InternalVersion is the default internal version. It is recommended that
    52  	// you use "" for the internal version.
    53  	InternalVersion string
    54  
    55  	// MetaInsertionFactory is used to create an object to store and retrieve
    56  	// the version and kind information for all objects. The default uses the
    57  	// keys "apiVersion" and "kind" respectively.
    58  	MetaFactory MetaFactory
    59  }
    60  
    61  // NewScheme manufactures a new scheme.
    62  func NewScheme() *Scheme {
    63  	s := &Scheme{
    64  		versionMap:      map[string]map[string]reflect.Type{},
    65  		typeToVersion:   map[reflect.Type]string{},
    66  		typeToKind:      map[reflect.Type][]string{},
    67  		converter:       NewConverter(),
    68  		cloner:          NewCloner(),
    69  		InternalVersion: "",
    70  		MetaFactory:     DefaultMetaFactory,
    71  	}
    72  	s.converter.nameFunc = s.nameFunc
    73  	return s
    74  }
    75  
    76  // Log sets a logger on the scheme. For test purposes only
    77  func (s *Scheme) Log(l DebugLogger) {
    78  	s.converter.Debug = l
    79  }
    80  
    81  // nameFunc returns the name of the type that we wish to use to determine when two types attempt
    82  // a conversion. Defaults to the go name of the type if the type is not registered.
    83  func (s *Scheme) nameFunc(t reflect.Type) string {
    84  	// find the preferred names for this type
    85  	names, ok := s.typeToKind[t]
    86  	if !ok {
    87  		return t.Name()
    88  	}
    89  	if internal, ok := s.versionMap[""]; ok {
    90  		for _, name := range names {
    91  			if t, ok := internal[name]; ok {
    92  				return s.typeToKind[t][0]
    93  			}
    94  		}
    95  	}
    96  	return names[0]
    97  }
    98  
    99  // AddKnownTypes registers all types passed in 'types' as being members of version 'version.
   100  // Encode() will refuse objects unless their type has been registered with AddKnownTypes.
   101  // All objects passed to types should be pointers to structs. The name that go reports for
   102  // the struct becomes the "kind" field when encoding.
   103  func (s *Scheme) AddKnownTypes(version string, types ...interface{}) {
   104  	knownTypes, found := s.versionMap[version]
   105  	if !found {
   106  		knownTypes = map[string]reflect.Type{}
   107  		s.versionMap[version] = knownTypes
   108  	}
   109  	for _, obj := range types {
   110  		t := reflect.TypeOf(obj)
   111  		if t.Kind() != reflect.Ptr {
   112  			panic("All types must be pointers to structs.")
   113  		}
   114  		t = t.Elem()
   115  		if t.Kind() != reflect.Struct {
   116  			panic("All types must be pointers to structs.")
   117  		}
   118  		knownTypes[t.Name()] = t
   119  		s.typeToVersion[t] = version
   120  		s.typeToKind[t] = append(s.typeToKind[t], t.Name())
   121  	}
   122  }
   123  
   124  // AddKnownTypeWithName is like AddKnownTypes, but it lets you specify what this type should
   125  // be encoded as. Useful for testing when you don't want to make multiple packages to define
   126  // your structs.
   127  func (s *Scheme) AddKnownTypeWithName(version, kind string, obj interface{}) {
   128  	knownTypes, found := s.versionMap[version]
   129  	if !found {
   130  		knownTypes = map[string]reflect.Type{}
   131  		s.versionMap[version] = knownTypes
   132  	}
   133  	t := reflect.TypeOf(obj)
   134  	if t.Kind() != reflect.Ptr {
   135  		panic("All types must be pointers to structs.")
   136  	}
   137  	t = t.Elem()
   138  	if t.Kind() != reflect.Struct {
   139  		panic("All types must be pointers to structs.")
   140  	}
   141  	knownTypes[kind] = t
   142  	s.typeToVersion[t] = version
   143  	s.typeToKind[t] = append(s.typeToKind[t], kind)
   144  }
   145  
   146  // KnownTypes returns an array of the types that are known for a particular version.
   147  func (s *Scheme) KnownTypes(version string) map[string]reflect.Type {
   148  	all, ok := s.versionMap[version]
   149  	if !ok {
   150  		return map[string]reflect.Type{}
   151  	}
   152  	types := make(map[string]reflect.Type)
   153  	for k, v := range all {
   154  		types[k] = v
   155  	}
   156  	return types
   157  }
   158  
   159  // NewObject returns a new object of the given version and name,
   160  // or an error if it hasn't been registered.
   161  func (s *Scheme) NewObject(versionName, kind string) (interface{}, error) {
   162  	if types, ok := s.versionMap[versionName]; ok {
   163  		if t, ok := types[kind]; ok {
   164  			return reflect.New(t).Interface(), nil
   165  		}
   166  		return nil, &notRegisteredErr{kind: kind, version: versionName}
   167  	}
   168  	return nil, &notRegisteredErr{kind: kind, version: versionName}
   169  }
   170  
   171  // AddConversionFuncs adds functions to the list of conversion functions. The given
   172  // functions should know how to convert between two of your API objects, or their
   173  // sub-objects. We deduce how to call these functions from the types of their two
   174  // parameters; see the comment for Converter.Register.
   175  //
   176  // Note that, if you need to copy sub-objects that didn't change, you can use the
   177  // conversion.Scope object that will be passed to your conversion function.
   178  // Additionally, all conversions started by Scheme will set the SrcVersion and
   179  // DestVersion fields on the Meta object. Example:
   180  //
   181  // s.AddConversionFuncs(
   182  //	func(in *InternalObject, out *ExternalObject, scope conversion.Scope) error {
   183  //		// You can depend on Meta() being non-nil, and this being set to
   184  //		// the source version, e.g., ""
   185  //		s.Meta().SrcVersion
   186  //		// You can depend on this being set to the destination version,
   187  //		// e.g., "v1".
   188  //		s.Meta().DestVersion
   189  //		// Call scope.Convert to copy sub-fields.
   190  //		s.Convert(&in.SubFieldThatMoved, &out.NewLocation.NewName, 0)
   191  //		return nil
   192  //	},
   193  // )
   194  //
   195  // (For more detail about conversion functions, see Converter.Register's comment.)
   196  //
   197  // Also note that the default behavior, if you don't add a conversion function, is to
   198  // sanely copy fields that have the same names and same type names. It's OK if the
   199  // destination type has extra fields, but it must not remove any. So you only need to
   200  // add conversion functions for things with changed/removed fields.
   201  func (s *Scheme) AddConversionFuncs(conversionFuncs ...interface{}) error {
   202  	for _, f := range conversionFuncs {
   203  		if err := s.converter.RegisterConversionFunc(f); err != nil {
   204  			return err
   205  		}
   206  	}
   207  	return nil
   208  }
   209  
   210  // Similar to AddConversionFuncs, but registers conversion functions that were
   211  // automatically generated.
   212  func (s *Scheme) AddGeneratedConversionFuncs(conversionFuncs ...interface{}) error {
   213  	for _, f := range conversionFuncs {
   214  		if err := s.converter.RegisterGeneratedConversionFunc(f); err != nil {
   215  			return err
   216  		}
   217  	}
   218  	return nil
   219  }
   220  
   221  // AddDeepCopyFuncs adds functions to the list of deep copy functions.
   222  // Note that to copy sub-objects, you can use the conversion.Cloner object that
   223  // will be passed to your deep-copy function.
   224  func (s *Scheme) AddDeepCopyFuncs(deepCopyFuncs ...interface{}) error {
   225  	for _, f := range deepCopyFuncs {
   226  		if err := s.cloner.RegisterDeepCopyFunc(f); err != nil {
   227  			return err
   228  		}
   229  	}
   230  	return nil
   231  }
   232  
   233  // Similar to AddDeepCopyFuncs, but registers deep copy functions that were
   234  // automatically generated.
   235  func (s *Scheme) AddGeneratedDeepCopyFuncs(deepCopyFuncs ...interface{}) error {
   236  	for _, f := range deepCopyFuncs {
   237  		if err := s.cloner.RegisterGeneratedDeepCopyFunc(f); err != nil {
   238  			return err
   239  		}
   240  	}
   241  	return nil
   242  }
   243  
   244  // AddStructFieldConversion allows you to specify a mechanical copy for a moved
   245  // or renamed struct field without writing an entire conversion function. See
   246  // the comment in Converter.SetStructFieldCopy for parameter details.
   247  // Call as many times as needed, even on the same fields.
   248  func (s *Scheme) AddStructFieldConversion(srcFieldType interface{}, srcFieldName string, destFieldType interface{}, destFieldName string) error {
   249  	return s.converter.SetStructFieldCopy(srcFieldType, srcFieldName, destFieldType, destFieldName)
   250  }
   251  
   252  // AddDefaultingFuncs adds functions to the list of default-value functions.
   253  // Each of the given functions is responsible for applying default values
   254  // when converting an instance of a versioned API object into an internal
   255  // API object.  These functions do not need to handle sub-objects. We deduce
   256  // how to call these functions from the types of their two parameters.
   257  //
   258  // s.AddDefaultingFuncs(
   259  //	func(obj *v1.Pod) {
   260  //		if obj.OptionalField == "" {
   261  //			obj.OptionalField = "DefaultValue"
   262  //		}
   263  //	},
   264  // )
   265  func (s *Scheme) AddDefaultingFuncs(defaultingFuncs ...interface{}) error {
   266  	for _, f := range defaultingFuncs {
   267  		err := s.converter.RegisterDefaultingFunc(f)
   268  		if err != nil {
   269  			return err
   270  		}
   271  	}
   272  	return nil
   273  }
   274  
   275  // Recognizes returns true if the scheme is able to handle the provided version and kind
   276  // of an object.
   277  func (s *Scheme) Recognizes(version, kind string) bool {
   278  	m, ok := s.versionMap[version]
   279  	if !ok {
   280  		return false
   281  	}
   282  	_, ok = m[kind]
   283  	return ok
   284  }
   285  
   286  // RegisterInputDefaults sets the provided field mapping function and field matching
   287  // as the defaults for the provided input type.  The fn may be nil, in which case no
   288  // mapping will happen by default. Use this method to register a mechanism for handling
   289  // a specific input type in conversion, such as a map[string]string to structs.
   290  func (s *Scheme) RegisterInputDefaults(in interface{}, fn FieldMappingFunc, defaultFlags FieldMatchingFlags) error {
   291  	return s.converter.RegisterInputDefaults(in, fn, defaultFlags)
   292  }
   293  
   294  // Performs a deep copy of the given object.
   295  func (s *Scheme) DeepCopy(in interface{}) (interface{}, error) {
   296  	return s.cloner.DeepCopy(in)
   297  }
   298  
   299  // Convert will attempt to convert in into out. Both must be pointers. For easy
   300  // testing of conversion functions. Returns an error if the conversion isn't
   301  // possible. You can call this with types that haven't been registered (for example,
   302  // a to test conversion of types that are nested within registered types), but in
   303  // that case, the conversion.Scope object passed to your conversion functions won't
   304  // have SrcVersion or DestVersion fields set correctly in Meta().
   305  func (s *Scheme) Convert(in, out interface{}) error {
   306  	inVersion := "unknown"
   307  	outVersion := "unknown"
   308  	if v, _, err := s.ObjectVersionAndKind(in); err == nil {
   309  		inVersion = v
   310  	}
   311  	if v, _, err := s.ObjectVersionAndKind(out); err == nil {
   312  		outVersion = v
   313  	}
   314  	flags, meta := s.generateConvertMeta(inVersion, outVersion, in)
   315  	if flags == 0 {
   316  		flags = AllowDifferentFieldTypeNames
   317  	}
   318  	return s.converter.Convert(in, out, flags, meta)
   319  }
   320  
   321  // ConvertToVersion attempts to convert an input object to its matching Kind in another
   322  // version within this scheme. Will return an error if the provided version does not
   323  // contain the inKind (or a mapping by name defined with AddKnownTypeWithName).
   324  func (s *Scheme) ConvertToVersion(in interface{}, outVersion string) (interface{}, error) {
   325  	t := reflect.TypeOf(in)
   326  	if t.Kind() != reflect.Ptr {
   327  		return nil, fmt.Errorf("only pointer types may be converted: %v", t)
   328  	}
   329  	t = t.Elem()
   330  	if t.Kind() != reflect.Struct {
   331  		return nil, fmt.Errorf("only pointers to struct types may be converted: %v", t)
   332  	}
   333  
   334  	kinds, ok := s.typeToKind[t]
   335  	if !ok {
   336  		return nil, fmt.Errorf("%v cannot be converted into version %q", t, outVersion)
   337  	}
   338  	outKind := kinds[0]
   339  
   340  	inVersion, _, err := s.ObjectVersionAndKind(in)
   341  	if err != nil {
   342  		return nil, err
   343  	}
   344  
   345  	out, err := s.NewObject(outVersion, outKind)
   346  	if err != nil {
   347  		return nil, err
   348  	}
   349  
   350  	flags, meta := s.generateConvertMeta(inVersion, outVersion, in)
   351  	if err := s.converter.Convert(in, out, flags, meta); err != nil {
   352  		return nil, err
   353  	}
   354  
   355  	if err := s.SetVersionAndKind(outVersion, outKind, out); err != nil {
   356  		return nil, err
   357  	}
   358  
   359  	return out, nil
   360  }
   361  
   362  // Converter allows access to the converter for the scheme
   363  func (s *Scheme) Converter() *Converter {
   364  	return s.converter
   365  }
   366  
   367  // generateConvertMeta constructs the meta value we pass to Convert.
   368  func (s *Scheme) generateConvertMeta(srcVersion, destVersion string, in interface{}) (FieldMatchingFlags, *Meta) {
   369  	t := reflect.TypeOf(in)
   370  	return s.converter.inputDefaultFlags[t], &Meta{
   371  		SrcVersion:     srcVersion,
   372  		DestVersion:    destVersion,
   373  		KeyNameMapping: s.converter.inputFieldMappingFuncs[t],
   374  	}
   375  }
   376  
   377  // DataVersionAndKind will return the APIVersion and Kind of the given wire-format
   378  // encoding of an API Object, or an error.
   379  func (s *Scheme) DataVersionAndKind(data []byte) (version, kind string, err error) {
   380  	return s.MetaFactory.Interpret(data)
   381  }
   382  
   383  // ObjectVersionAndKind returns the API version and kind of the go object,
   384  // or an error if it's not a pointer or is unregistered.
   385  func (s *Scheme) ObjectVersionAndKind(obj interface{}) (apiVersion, kind string, err error) {
   386  	v, err := EnforcePtr(obj)
   387  	if err != nil {
   388  		return "", "", err
   389  	}
   390  	t := v.Type()
   391  	version, vOK := s.typeToVersion[t]
   392  	kinds, kOK := s.typeToKind[t]
   393  	if !vOK || !kOK {
   394  		return "", "", &notRegisteredErr{t: t}
   395  	}
   396  	apiVersion = version
   397  	kind = kinds[0]
   398  	return
   399  }
   400  
   401  // SetVersionAndKind sets the version and kind fields (with help from
   402  // MetaInsertionFactory). Returns an error if this isn't possible. obj
   403  // must be a pointer.
   404  func (s *Scheme) SetVersionAndKind(version, kind string, obj interface{}) error {
   405  	return s.MetaFactory.Update(version, kind, obj)
   406  }
   407  
   408  // maybeCopy copies obj if it is not a pointer, to get a settable/addressable
   409  // object. Guaranteed to return a pointer.
   410  func maybeCopy(obj interface{}) interface{} {
   411  	v := reflect.ValueOf(obj)
   412  	if v.Kind() == reflect.Ptr {
   413  		return obj
   414  	}
   415  	v2 := reflect.New(v.Type())
   416  	v2.Elem().Set(v)
   417  	return v2.Interface()
   418  }