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, ¬RegisteredErr{kind: kind, version: versionName} 167 } 168 return nil, ¬RegisteredErr{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 "", "", ¬RegisteredErr{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 }