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