codec.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  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. "encoding/json"
  18. "fmt"
  19. "io"
  20. "net/url"
  21. "reflect"
  22. "strconv"
  23. "strings"
  24. "k8s.io/apimachinery/pkg/conversion/queryparams"
  25. "k8s.io/apimachinery/pkg/runtime/schema"
  26. "k8s.io/klog/v2"
  27. )
  28. // codec binds an encoder and decoder.
  29. type codec struct {
  30. Encoder
  31. Decoder
  32. }
  33. // NewCodec creates a Codec from an Encoder and Decoder.
  34. func NewCodec(e Encoder, d Decoder) Codec {
  35. return codec{e, d}
  36. }
  37. // Encode is a convenience wrapper for encoding to a []byte from an Encoder
  38. func Encode(e Encoder, obj Object) ([]byte, error) {
  39. // TODO: reuse buffer
  40. buf := &bytes.Buffer{}
  41. if err := e.Encode(obj, buf); err != nil {
  42. return nil, err
  43. }
  44. return buf.Bytes(), nil
  45. }
  46. // Decode is a convenience wrapper for decoding data into an Object.
  47. func Decode(d Decoder, data []byte) (Object, error) {
  48. obj, _, err := d.Decode(data, nil, nil)
  49. return obj, err
  50. }
  51. // DecodeInto performs a Decode into the provided object.
  52. func DecodeInto(d Decoder, data []byte, into Object) error {
  53. out, gvk, err := d.Decode(data, nil, into)
  54. if err != nil {
  55. return err
  56. }
  57. if out != into {
  58. return fmt.Errorf("unable to decode %s into %v", gvk, reflect.TypeOf(into))
  59. }
  60. return nil
  61. }
  62. // EncodeOrDie is a version of Encode which will panic instead of returning an error. For tests.
  63. func EncodeOrDie(e Encoder, obj Object) string {
  64. bytes, err := Encode(e, obj)
  65. if err != nil {
  66. panic(err)
  67. }
  68. return string(bytes)
  69. }
  70. // UseOrCreateObject returns obj if the canonical ObjectKind returned by the provided typer matches gvk, or
  71. // invokes the ObjectCreator to instantiate a new gvk. Returns an error if the typer cannot find the object.
  72. func UseOrCreateObject(t ObjectTyper, c ObjectCreater, gvk schema.GroupVersionKind, obj Object) (Object, error) {
  73. if obj != nil {
  74. kinds, _, err := t.ObjectKinds(obj)
  75. if err != nil {
  76. return nil, err
  77. }
  78. for _, kind := range kinds {
  79. if gvk == kind {
  80. return obj, nil
  81. }
  82. }
  83. }
  84. return c.New(gvk)
  85. }
  86. // NoopEncoder converts an Decoder to a Serializer or Codec for code that expects them but only uses decoding.
  87. type NoopEncoder struct {
  88. Decoder
  89. }
  90. var _ Serializer = NoopEncoder{}
  91. const noopEncoderIdentifier Identifier = "noop"
  92. func (n NoopEncoder) Encode(obj Object, w io.Writer) error {
  93. // There is no need to handle runtime.CacheableObject, as we don't
  94. // process the obj at all.
  95. return fmt.Errorf("encoding is not allowed for this codec: %v", reflect.TypeOf(n.Decoder))
  96. }
  97. // Identifier implements runtime.Encoder interface.
  98. func (n NoopEncoder) Identifier() Identifier {
  99. return noopEncoderIdentifier
  100. }
  101. // NoopDecoder converts an Encoder to a Serializer or Codec for code that expects them but only uses encoding.
  102. type NoopDecoder struct {
  103. Encoder
  104. }
  105. var _ Serializer = NoopDecoder{}
  106. func (n NoopDecoder) Decode(data []byte, gvk *schema.GroupVersionKind, into Object) (Object, *schema.GroupVersionKind, error) {
  107. return nil, nil, fmt.Errorf("decoding is not allowed for this codec: %v", reflect.TypeOf(n.Encoder))
  108. }
  109. // NewParameterCodec creates a ParameterCodec capable of transforming url values into versioned objects and back.
  110. func NewParameterCodec(scheme *Scheme) ParameterCodec {
  111. return &parameterCodec{
  112. typer: scheme,
  113. convertor: scheme,
  114. creator: scheme,
  115. defaulter: scheme,
  116. }
  117. }
  118. // parameterCodec implements conversion to and from query parameters and objects.
  119. type parameterCodec struct {
  120. typer ObjectTyper
  121. convertor ObjectConvertor
  122. creator ObjectCreater
  123. defaulter ObjectDefaulter
  124. }
  125. var _ ParameterCodec = &parameterCodec{}
  126. // DecodeParameters converts the provided url.Values into an object of type From with the kind of into, and then
  127. // converts that object to into (if necessary). Returns an error if the operation cannot be completed.
  128. func (c *parameterCodec) DecodeParameters(parameters url.Values, from schema.GroupVersion, into Object) error {
  129. if len(parameters) == 0 {
  130. return nil
  131. }
  132. targetGVKs, _, err := c.typer.ObjectKinds(into)
  133. if err != nil {
  134. return err
  135. }
  136. for i := range targetGVKs {
  137. if targetGVKs[i].GroupVersion() == from {
  138. if err := c.convertor.Convert(&parameters, into, nil); err != nil {
  139. return err
  140. }
  141. // in the case where we going into the same object we're receiving, default on the outbound object
  142. if c.defaulter != nil {
  143. c.defaulter.Default(into)
  144. }
  145. return nil
  146. }
  147. }
  148. input, err := c.creator.New(from.WithKind(targetGVKs[0].Kind))
  149. if err != nil {
  150. return err
  151. }
  152. if err := c.convertor.Convert(&parameters, input, nil); err != nil {
  153. return err
  154. }
  155. // if we have defaulter, default the input before converting to output
  156. if c.defaulter != nil {
  157. c.defaulter.Default(input)
  158. }
  159. return c.convertor.Convert(input, into, nil)
  160. }
  161. // EncodeParameters converts the provided object into the to version, then converts that object to url.Values.
  162. // Returns an error if conversion is not possible.
  163. func (c *parameterCodec) EncodeParameters(obj Object, to schema.GroupVersion) (url.Values, error) {
  164. gvks, _, err := c.typer.ObjectKinds(obj)
  165. if err != nil {
  166. return nil, err
  167. }
  168. gvk := gvks[0]
  169. if to != gvk.GroupVersion() {
  170. out, err := c.convertor.ConvertToVersion(obj, to)
  171. if err != nil {
  172. return nil, err
  173. }
  174. obj = out
  175. }
  176. return queryparams.Convert(obj)
  177. }
  178. type base64Serializer struct {
  179. Encoder
  180. Decoder
  181. identifier Identifier
  182. }
  183. func NewBase64Serializer(e Encoder, d Decoder) Serializer {
  184. return &base64Serializer{
  185. Encoder: e,
  186. Decoder: d,
  187. identifier: identifier(e),
  188. }
  189. }
  190. func identifier(e Encoder) Identifier {
  191. result := map[string]string{
  192. "name": "base64",
  193. }
  194. if e != nil {
  195. result["encoder"] = string(e.Identifier())
  196. }
  197. identifier, err := json.Marshal(result)
  198. if err != nil {
  199. klog.Fatalf("Failed marshaling identifier for base64Serializer: %v", err)
  200. }
  201. return Identifier(identifier)
  202. }
  203. func (s base64Serializer) Encode(obj Object, stream io.Writer) error {
  204. if co, ok := obj.(CacheableObject); ok {
  205. return co.CacheEncode(s.Identifier(), s.doEncode, stream)
  206. }
  207. return s.doEncode(obj, stream)
  208. }
  209. func (s base64Serializer) doEncode(obj Object, stream io.Writer) error {
  210. e := base64.NewEncoder(base64.StdEncoding, stream)
  211. err := s.Encoder.Encode(obj, e)
  212. e.Close()
  213. return err
  214. }
  215. // Identifier implements runtime.Encoder interface.
  216. func (s base64Serializer) Identifier() Identifier {
  217. return s.identifier
  218. }
  219. func (s base64Serializer) Decode(data []byte, defaults *schema.GroupVersionKind, into Object) (Object, *schema.GroupVersionKind, error) {
  220. out := make([]byte, base64.StdEncoding.DecodedLen(len(data)))
  221. n, err := base64.StdEncoding.Decode(out, data)
  222. if err != nil {
  223. return nil, nil, err
  224. }
  225. return s.Decoder.Decode(out[:n], defaults, into)
  226. }
  227. // SerializerInfoForMediaType returns the first info in types that has a matching media type (which cannot
  228. // include media-type parameters), or the first info with an empty media type, or false if no type matches.
  229. func SerializerInfoForMediaType(types []SerializerInfo, mediaType string) (SerializerInfo, bool) {
  230. for _, info := range types {
  231. if info.MediaType == mediaType {
  232. return info, true
  233. }
  234. }
  235. for _, info := range types {
  236. if len(info.MediaType) == 0 {
  237. return info, true
  238. }
  239. }
  240. return SerializerInfo{}, false
  241. }
  242. var (
  243. // InternalGroupVersioner will always prefer the internal version for a given group version kind.
  244. InternalGroupVersioner GroupVersioner = internalGroupVersioner{}
  245. // DisabledGroupVersioner will reject all kinds passed to it.
  246. DisabledGroupVersioner GroupVersioner = disabledGroupVersioner{}
  247. )
  248. const (
  249. internalGroupVersionerIdentifier = "internal"
  250. disabledGroupVersionerIdentifier = "disabled"
  251. )
  252. type internalGroupVersioner struct{}
  253. // KindForGroupVersionKinds returns an internal Kind if one is found, or converts the first provided kind to the internal version.
  254. func (internalGroupVersioner) KindForGroupVersionKinds(kinds []schema.GroupVersionKind) (schema.GroupVersionKind, bool) {
  255. for _, kind := range kinds {
  256. if kind.Version == APIVersionInternal {
  257. return kind, true
  258. }
  259. }
  260. for _, kind := range kinds {
  261. return schema.GroupVersionKind{Group: kind.Group, Version: APIVersionInternal, Kind: kind.Kind}, true
  262. }
  263. return schema.GroupVersionKind{}, false
  264. }
  265. // Identifier implements GroupVersioner interface.
  266. func (internalGroupVersioner) Identifier() string {
  267. return internalGroupVersionerIdentifier
  268. }
  269. type disabledGroupVersioner struct{}
  270. // KindForGroupVersionKinds returns false for any input.
  271. func (disabledGroupVersioner) KindForGroupVersionKinds(kinds []schema.GroupVersionKind) (schema.GroupVersionKind, bool) {
  272. return schema.GroupVersionKind{}, false
  273. }
  274. // Identifier implements GroupVersioner interface.
  275. func (disabledGroupVersioner) Identifier() string {
  276. return disabledGroupVersionerIdentifier
  277. }
  278. // Assert that schema.GroupVersion and GroupVersions implement GroupVersioner
  279. var _ GroupVersioner = schema.GroupVersion{}
  280. var _ GroupVersioner = schema.GroupVersions{}
  281. var _ GroupVersioner = multiGroupVersioner{}
  282. type multiGroupVersioner struct {
  283. target schema.GroupVersion
  284. acceptedGroupKinds []schema.GroupKind
  285. coerce bool
  286. }
  287. // NewMultiGroupVersioner returns the provided group version for any kind that matches one of the provided group kinds.
  288. // Kind may be empty in the provided group kind, in which case any kind will match.
  289. func NewMultiGroupVersioner(gv schema.GroupVersion, groupKinds ...schema.GroupKind) GroupVersioner {
  290. if len(groupKinds) == 0 || (len(groupKinds) == 1 && groupKinds[0].Group == gv.Group) {
  291. return gv
  292. }
  293. return multiGroupVersioner{target: gv, acceptedGroupKinds: groupKinds}
  294. }
  295. // NewCoercingMultiGroupVersioner returns the provided group version for any incoming kind.
  296. // Incoming kinds that match the provided groupKinds are preferred.
  297. // Kind may be empty in the provided group kind, in which case any kind will match.
  298. // Examples:
  299. //
  300. // gv=mygroup/__internal, groupKinds=mygroup/Foo, anothergroup/Bar
  301. // KindForGroupVersionKinds(yetanother/v1/Baz, anothergroup/v1/Bar) -> mygroup/__internal/Bar (matched preferred group/kind)
  302. //
  303. // gv=mygroup/__internal, groupKinds=mygroup, anothergroup
  304. // KindForGroupVersionKinds(yetanother/v1/Baz, anothergroup/v1/Bar) -> mygroup/__internal/Bar (matched preferred group)
  305. //
  306. // gv=mygroup/__internal, groupKinds=mygroup, anothergroup
  307. // KindForGroupVersionKinds(yetanother/v1/Baz, yetanother/v1/Bar) -> mygroup/__internal/Baz (no preferred group/kind match, uses first kind in list)
  308. func NewCoercingMultiGroupVersioner(gv schema.GroupVersion, groupKinds ...schema.GroupKind) GroupVersioner {
  309. return multiGroupVersioner{target: gv, acceptedGroupKinds: groupKinds, coerce: true}
  310. }
  311. // KindForGroupVersionKinds returns the target group version if any kind matches any of the original group kinds. It will
  312. // use the originating kind where possible.
  313. func (v multiGroupVersioner) KindForGroupVersionKinds(kinds []schema.GroupVersionKind) (schema.GroupVersionKind, bool) {
  314. for _, src := range kinds {
  315. for _, kind := range v.acceptedGroupKinds {
  316. if kind.Group != src.Group {
  317. continue
  318. }
  319. if len(kind.Kind) > 0 && kind.Kind != src.Kind {
  320. continue
  321. }
  322. return v.target.WithKind(src.Kind), true
  323. }
  324. }
  325. if v.coerce && len(kinds) > 0 {
  326. return v.target.WithKind(kinds[0].Kind), true
  327. }
  328. return schema.GroupVersionKind{}, false
  329. }
  330. // Identifier implements GroupVersioner interface.
  331. func (v multiGroupVersioner) Identifier() string {
  332. groupKinds := make([]string, 0, len(v.acceptedGroupKinds))
  333. for _, gk := range v.acceptedGroupKinds {
  334. groupKinds = append(groupKinds, gk.String())
  335. }
  336. result := map[string]string{
  337. "name": "multi",
  338. "target": v.target.String(),
  339. "accepted": strings.Join(groupKinds, ","),
  340. "coerce": strconv.FormatBool(v.coerce),
  341. }
  342. identifier, err := json.Marshal(result)
  343. if err != nil {
  344. klog.Fatalf("Failed marshaling Identifier for %#v: %v", v, err)
  345. }
  346. return string(identifier)
  347. }