versioning.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package versioning
  14. import (
  15. "io"
  16. "k8s.io/kubernetes/pkg/api/unversioned"
  17. "k8s.io/kubernetes/pkg/runtime"
  18. )
  19. // NewCodecForScheme is a convenience method for callers that are using a scheme.
  20. func NewCodecForScheme(
  21. // TODO: I should be a scheme interface?
  22. scheme *runtime.Scheme,
  23. encoder runtime.Encoder,
  24. decoder runtime.Decoder,
  25. encodeVersion runtime.GroupVersioner,
  26. decodeVersion runtime.GroupVersioner,
  27. ) runtime.Codec {
  28. return NewCodec(encoder, decoder, runtime.UnsafeObjectConvertor(scheme), scheme, scheme, scheme, encodeVersion, decodeVersion)
  29. }
  30. // NewCodec takes objects in their internal versions and converts them to external versions before
  31. // serializing them. It assumes the serializer provided to it only deals with external versions.
  32. // This class is also a serializer, but is generally used with a specific version.
  33. func NewCodec(
  34. encoder runtime.Encoder,
  35. decoder runtime.Decoder,
  36. convertor runtime.ObjectConvertor,
  37. creater runtime.ObjectCreater,
  38. copier runtime.ObjectCopier,
  39. typer runtime.ObjectTyper,
  40. encodeVersion runtime.GroupVersioner,
  41. decodeVersion runtime.GroupVersioner,
  42. ) runtime.Codec {
  43. internal := &codec{
  44. encoder: encoder,
  45. decoder: decoder,
  46. convertor: convertor,
  47. creater: creater,
  48. copier: copier,
  49. typer: typer,
  50. encodeVersion: encodeVersion,
  51. decodeVersion: decodeVersion,
  52. }
  53. return internal
  54. }
  55. type codec struct {
  56. encoder runtime.Encoder
  57. decoder runtime.Decoder
  58. convertor runtime.ObjectConvertor
  59. creater runtime.ObjectCreater
  60. copier runtime.ObjectCopier
  61. typer runtime.ObjectTyper
  62. encodeVersion runtime.GroupVersioner
  63. decodeVersion runtime.GroupVersioner
  64. }
  65. // Decode attempts a decode of the object, then tries to convert it to the internal version. If into is provided and the decoding is
  66. // successful, the returned runtime.Object will be the value passed as into. Note that this may bypass conversion if you pass an
  67. // into that matches the serialized version.
  68. func (c *codec) Decode(data []byte, defaultGVK *unversioned.GroupVersionKind, into runtime.Object) (runtime.Object, *unversioned.GroupVersionKind, error) {
  69. versioned, isVersioned := into.(*runtime.VersionedObjects)
  70. if isVersioned {
  71. into = versioned.Last()
  72. }
  73. obj, gvk, err := c.decoder.Decode(data, defaultGVK, into)
  74. if err != nil {
  75. return nil, gvk, err
  76. }
  77. if d, ok := obj.(runtime.NestedObjectDecoder); ok {
  78. if err := d.DecodeNestedObjects(DirectDecoder{c.decoder}); err != nil {
  79. return nil, gvk, err
  80. }
  81. }
  82. // if we specify a target, use generic conversion.
  83. if into != nil {
  84. if into == obj {
  85. if isVersioned {
  86. return versioned, gvk, nil
  87. }
  88. return into, gvk, nil
  89. }
  90. if err := c.convertor.Convert(obj, into, c.decodeVersion); err != nil {
  91. return nil, gvk, err
  92. }
  93. if isVersioned {
  94. versioned.Objects = []runtime.Object{obj, into}
  95. return versioned, gvk, nil
  96. }
  97. return into, gvk, nil
  98. }
  99. // Convert if needed.
  100. if isVersioned {
  101. // create a copy, because ConvertToVersion does not guarantee non-mutation of objects
  102. copied, err := c.copier.Copy(obj)
  103. if err != nil {
  104. copied = obj
  105. }
  106. versioned.Objects = []runtime.Object{copied}
  107. }
  108. out, err := c.convertor.ConvertToVersion(obj, c.decodeVersion)
  109. if err != nil {
  110. return nil, gvk, err
  111. }
  112. if isVersioned {
  113. if versioned.Last() != out {
  114. versioned.Objects = append(versioned.Objects, out)
  115. }
  116. return versioned, gvk, nil
  117. }
  118. return out, gvk, nil
  119. }
  120. // Encode ensures the provided object is output in the appropriate group and version, invoking
  121. // conversion if necessary. Unversioned objects (according to the ObjectTyper) are output as is.
  122. func (c *codec) Encode(obj runtime.Object, w io.Writer) error {
  123. switch obj.(type) {
  124. case *runtime.Unknown, *runtime.Unstructured, *runtime.UnstructuredList:
  125. return c.encoder.Encode(obj, w)
  126. }
  127. gvks, isUnversioned, err := c.typer.ObjectKinds(obj)
  128. if err != nil {
  129. return err
  130. }
  131. if c.encodeVersion == nil || isUnversioned {
  132. if e, ok := obj.(runtime.NestedObjectEncoder); ok {
  133. if err := e.EncodeNestedObjects(DirectEncoder{Encoder: c.encoder, ObjectTyper: c.typer}); err != nil {
  134. return err
  135. }
  136. }
  137. objectKind := obj.GetObjectKind()
  138. old := objectKind.GroupVersionKind()
  139. objectKind.SetGroupVersionKind(gvks[0])
  140. err = c.encoder.Encode(obj, w)
  141. objectKind.SetGroupVersionKind(old)
  142. return err
  143. }
  144. // Perform a conversion if necessary
  145. objectKind := obj.GetObjectKind()
  146. old := objectKind.GroupVersionKind()
  147. out, err := c.convertor.ConvertToVersion(obj, c.encodeVersion)
  148. if err != nil {
  149. return err
  150. }
  151. if e, ok := out.(runtime.NestedObjectEncoder); ok {
  152. if err := e.EncodeNestedObjects(DirectEncoder{Encoder: c.encoder, ObjectTyper: c.typer}); err != nil {
  153. return err
  154. }
  155. }
  156. // Conversion is responsible for setting the proper group, version, and kind onto the outgoing object
  157. err = c.encoder.Encode(out, w)
  158. // restore the old GVK, in case conversion returned the same object
  159. objectKind.SetGroupVersionKind(old)
  160. return err
  161. }
  162. // DirectEncoder serializes an object and ensures the GVK is set.
  163. type DirectEncoder struct {
  164. runtime.Encoder
  165. runtime.ObjectTyper
  166. }
  167. // Encode does not do conversion. It sets the gvk during serialization.
  168. func (e DirectEncoder) Encode(obj runtime.Object, stream io.Writer) error {
  169. gvks, _, err := e.ObjectTyper.ObjectKinds(obj)
  170. if err != nil {
  171. if runtime.IsNotRegisteredError(err) {
  172. return e.Encoder.Encode(obj, stream)
  173. }
  174. return err
  175. }
  176. kind := obj.GetObjectKind()
  177. oldGVK := kind.GroupVersionKind()
  178. kind.SetGroupVersionKind(gvks[0])
  179. err = e.Encoder.Encode(obj, stream)
  180. kind.SetGroupVersionKind(oldGVK)
  181. return err
  182. }
  183. // DirectDecoder clears the group version kind of a deserialized object.
  184. type DirectDecoder struct {
  185. runtime.Decoder
  186. }
  187. // Decode does not do conversion. It removes the gvk during deserialization.
  188. func (d DirectDecoder) Decode(data []byte, defaults *unversioned.GroupVersionKind, into runtime.Object) (runtime.Object, *unversioned.GroupVersionKind, error) {
  189. obj, gvk, err := d.Decoder.Decode(data, defaults, into)
  190. if obj != nil {
  191. kind := obj.GetObjectKind()
  192. // clearing the gvk is just a convention of a codec
  193. kind.SetGroupVersionKind(unversioned.GroupVersionKind{})
  194. }
  195. return obj, gvk, err
  196. }