codec.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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 runtime
  14. import (
  15. "bytes"
  16. "encoding/base64"
  17. "fmt"
  18. "io"
  19. "net/url"
  20. "reflect"
  21. "k8s.io/kubernetes/pkg/api/unversioned"
  22. "k8s.io/kubernetes/pkg/conversion/queryparams"
  23. )
  24. // codec binds an encoder and decoder.
  25. type codec struct {
  26. Encoder
  27. Decoder
  28. }
  29. // NewCodec creates a Codec from an Encoder and Decoder.
  30. func NewCodec(e Encoder, d Decoder) Codec {
  31. return codec{e, d}
  32. }
  33. // Encode is a convenience wrapper for encoding to a []byte from an Encoder
  34. func Encode(e Encoder, obj Object) ([]byte, error) {
  35. // TODO: reuse buffer
  36. buf := &bytes.Buffer{}
  37. if err := e.Encode(obj, buf); err != nil {
  38. return nil, err
  39. }
  40. return buf.Bytes(), nil
  41. }
  42. // Decode is a convenience wrapper for decoding data into an Object.
  43. func Decode(d Decoder, data []byte) (Object, error) {
  44. obj, _, err := d.Decode(data, nil, nil)
  45. return obj, err
  46. }
  47. // DecodeInto performs a Decode into the provided object.
  48. func DecodeInto(d Decoder, data []byte, into Object) error {
  49. out, gvk, err := d.Decode(data, nil, into)
  50. if err != nil {
  51. return err
  52. }
  53. if out != into {
  54. return fmt.Errorf("unable to decode %s into %v", gvk, reflect.TypeOf(into))
  55. }
  56. return nil
  57. }
  58. // EncodeOrDie is a version of Encode which will panic instead of returning an error. For tests.
  59. func EncodeOrDie(e Encoder, obj Object) string {
  60. bytes, err := Encode(e, obj)
  61. if err != nil {
  62. panic(err)
  63. }
  64. return string(bytes)
  65. }
  66. // UseOrCreateObject returns obj if the canonical ObjectKind returned by the provided typer matches gvk, or
  67. // invokes the ObjectCreator to instantiate a new gvk. Returns an error if the typer cannot find the object.
  68. func UseOrCreateObject(t ObjectTyper, c ObjectCreater, gvk unversioned.GroupVersionKind, obj Object) (Object, error) {
  69. if obj != nil {
  70. kinds, _, err := t.ObjectKinds(obj)
  71. if err != nil {
  72. return nil, err
  73. }
  74. for _, kind := range kinds {
  75. if gvk == kind {
  76. return obj, nil
  77. }
  78. }
  79. }
  80. return c.New(gvk)
  81. }
  82. // NoopEncoder converts an Decoder to a Serializer or Codec for code that expects them but only uses decoding.
  83. type NoopEncoder struct {
  84. Decoder
  85. }
  86. var _ Serializer = NoopEncoder{}
  87. func (n NoopEncoder) Encode(obj Object, w io.Writer) error {
  88. return fmt.Errorf("encoding is not allowed for this codec: %v", reflect.TypeOf(n.Decoder))
  89. }
  90. // NoopDecoder converts an Encoder to a Serializer or Codec for code that expects them but only uses encoding.
  91. type NoopDecoder struct {
  92. Encoder
  93. }
  94. var _ Serializer = NoopDecoder{}
  95. func (n NoopDecoder) Decode(data []byte, gvk *unversioned.GroupVersionKind, into Object) (Object, *unversioned.GroupVersionKind, error) {
  96. return nil, nil, fmt.Errorf("decoding is not allowed for this codec: %v", reflect.TypeOf(n.Encoder))
  97. }
  98. // NewParameterCodec creates a ParameterCodec capable of transforming url values into versioned objects and back.
  99. func NewParameterCodec(scheme *Scheme) ParameterCodec {
  100. return &parameterCodec{
  101. typer: scheme,
  102. convertor: scheme,
  103. creator: scheme,
  104. }
  105. }
  106. // parameterCodec implements conversion to and from query parameters and objects.
  107. type parameterCodec struct {
  108. typer ObjectTyper
  109. convertor ObjectConvertor
  110. creator ObjectCreater
  111. }
  112. var _ ParameterCodec = &parameterCodec{}
  113. // DecodeParameters converts the provided url.Values into an object of type From with the kind of into, and then
  114. // converts that object to into (if necessary). Returns an error if the operation cannot be completed.
  115. func (c *parameterCodec) DecodeParameters(parameters url.Values, from unversioned.GroupVersion, into Object) error {
  116. if len(parameters) == 0 {
  117. return nil
  118. }
  119. targetGVKs, _, err := c.typer.ObjectKinds(into)
  120. if err != nil {
  121. return err
  122. }
  123. targetGVK := targetGVKs[0]
  124. if targetGVK.GroupVersion() == from {
  125. return c.convertor.Convert(&parameters, into, nil)
  126. }
  127. input, err := c.creator.New(from.WithKind(targetGVK.Kind))
  128. if err != nil {
  129. return err
  130. }
  131. if err := c.convertor.Convert(&parameters, input, nil); err != nil {
  132. return err
  133. }
  134. return c.convertor.Convert(input, into, nil)
  135. }
  136. // EncodeParameters converts the provided object into the to version, then converts that object to url.Values.
  137. // Returns an error if conversion is not possible.
  138. func (c *parameterCodec) EncodeParameters(obj Object, to unversioned.GroupVersion) (url.Values, error) {
  139. gvks, _, err := c.typer.ObjectKinds(obj)
  140. if err != nil {
  141. return nil, err
  142. }
  143. gvk := gvks[0]
  144. if to != gvk.GroupVersion() {
  145. out, err := c.convertor.ConvertToVersion(obj, to)
  146. if err != nil {
  147. return nil, err
  148. }
  149. obj = out
  150. }
  151. return queryparams.Convert(obj)
  152. }
  153. type base64Serializer struct {
  154. Serializer
  155. }
  156. func NewBase64Serializer(s Serializer) Serializer {
  157. return &base64Serializer{s}
  158. }
  159. func (s base64Serializer) Encode(obj Object, stream io.Writer) error {
  160. e := base64.NewEncoder(base64.StdEncoding, stream)
  161. err := s.Serializer.Encode(obj, e)
  162. e.Close()
  163. return err
  164. }
  165. func (s base64Serializer) Decode(data []byte, defaults *unversioned.GroupVersionKind, into Object) (Object, *unversioned.GroupVersionKind, error) {
  166. out := make([]byte, base64.StdEncoding.DecodedLen(len(data)))
  167. n, err := base64.StdEncoding.Decode(out, data)
  168. if err != nil {
  169. return nil, nil, err
  170. }
  171. return s.Serializer.Decode(out[:n], defaults, into)
  172. }
  173. var (
  174. // InternalGroupVersioner will always prefer the internal version for a given group version kind.
  175. InternalGroupVersioner GroupVersioner = internalGroupVersioner{}
  176. // DisabledGroupVersioner will reject all kinds passed to it.
  177. DisabledGroupVersioner GroupVersioner = disabledGroupVersioner{}
  178. )
  179. type internalGroupVersioner struct{}
  180. // KindForGroupVersionKinds returns an internal Kind if one is found, or converts the first provided kind to the internal version.
  181. func (internalGroupVersioner) KindForGroupVersionKinds(kinds []unversioned.GroupVersionKind) (unversioned.GroupVersionKind, bool) {
  182. for _, kind := range kinds {
  183. if kind.Version == APIVersionInternal {
  184. return kind, true
  185. }
  186. }
  187. for _, kind := range kinds {
  188. return unversioned.GroupVersionKind{Group: kind.Group, Version: APIVersionInternal, Kind: kind.Kind}, true
  189. }
  190. return unversioned.GroupVersionKind{}, false
  191. }
  192. type disabledGroupVersioner struct{}
  193. // KindForGroupVersionKinds returns false for any input.
  194. func (disabledGroupVersioner) KindForGroupVersionKinds(kinds []unversioned.GroupVersionKind) (unversioned.GroupVersionKind, bool) {
  195. return unversioned.GroupVersionKind{}, false
  196. }
  197. // GroupVersioners implements GroupVersioner and resolves to the first exact match for any kind.
  198. type GroupVersioners []GroupVersioner
  199. // KindForGroupVersionKinds returns the first match of any of the group versioners, or false if no match occured.
  200. func (gvs GroupVersioners) KindForGroupVersionKinds(kinds []unversioned.GroupVersionKind) (unversioned.GroupVersionKind, bool) {
  201. for _, gv := range gvs {
  202. target, ok := gv.KindForGroupVersionKinds(kinds)
  203. if !ok {
  204. continue
  205. }
  206. return target, true
  207. }
  208. return unversioned.GroupVersionKind{}, false
  209. }
  210. // Assert that unversioned.GroupVersion and GroupVersions implement GroupVersioner
  211. var _ GroupVersioner = unversioned.GroupVersion{}
  212. var _ GroupVersioner = unversioned.GroupVersions{}
  213. var _ GroupVersioner = multiGroupVersioner{}
  214. type multiGroupVersioner struct {
  215. target unversioned.GroupVersion
  216. acceptedGroupKinds []unversioned.GroupKind
  217. }
  218. // NewMultiGroupVersioner returns the provided group version for any kind that matches one of the provided group kinds.
  219. // Kind may be empty in the provided group kind, in which case any kind will match.
  220. func NewMultiGroupVersioner(gv unversioned.GroupVersion, groupKinds ...unversioned.GroupKind) GroupVersioner {
  221. if len(groupKinds) == 0 || (len(groupKinds) == 1 && groupKinds[0].Group == gv.Group) {
  222. return gv
  223. }
  224. return multiGroupVersioner{target: gv, acceptedGroupKinds: groupKinds}
  225. }
  226. // KindForGroupVersionKinds returns the target group version if any kind matches any of the original group kinds. It will
  227. // use the originating kind where possible.
  228. func (v multiGroupVersioner) KindForGroupVersionKinds(kinds []unversioned.GroupVersionKind) (unversioned.GroupVersionKind, bool) {
  229. for _, src := range kinds {
  230. for _, kind := range v.acceptedGroupKinds {
  231. if kind.Group != src.Group {
  232. continue
  233. }
  234. if len(kind.Kind) > 0 && kind.Kind != src.Kind {
  235. continue
  236. }
  237. return v.target.WithKind(src.Kind), true
  238. }
  239. }
  240. return unversioned.GroupVersionKind{}, false
  241. }