blob: 1eaa85804f3ea704a6e7f0e72da7549f8d87cbc9 [file] [log] [blame]
sslobodrd046be82019-01-16 10:02:22 -05001/*
2Copyright 2015 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package unstructured
18
19import (
20 "bytes"
21 "errors"
22 "fmt"
23
24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25 "k8s.io/apimachinery/pkg/runtime"
26 "k8s.io/apimachinery/pkg/runtime/schema"
27 "k8s.io/apimachinery/pkg/types"
28 utilruntime "k8s.io/apimachinery/pkg/util/runtime"
29)
30
31// Unstructured allows objects that do not have Golang structs registered to be manipulated
32// generically. This can be used to deal with the API objects from a plug-in. Unstructured
33// objects still have functioning TypeMeta features-- kind, version, etc.
34//
35// WARNING: This object has accessors for the v1 standard metadata. You *MUST NOT* use this
36// type if you are dealing with objects that are not in the server meta v1 schema.
37//
38// TODO: make the serialization part of this type distinct from the field accessors.
39// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
40// +k8s:deepcopy-gen=true
41type Unstructured struct {
42 // Object is a JSON compatible map with string, float, int, bool, []interface{}, or
43 // map[string]interface{}
44 // children.
45 Object map[string]interface{}
46}
47
48var _ metav1.Object = &Unstructured{}
49var _ runtime.Unstructured = &Unstructured{}
50
51func (obj *Unstructured) GetObjectKind() schema.ObjectKind { return obj }
52
53func (obj *Unstructured) IsList() bool {
54 field, ok := obj.Object["items"]
55 if !ok {
56 return false
57 }
58 _, ok = field.([]interface{})
59 return ok
60}
61func (obj *Unstructured) ToList() (*UnstructuredList, error) {
62 if !obj.IsList() {
63 // return an empty list back
64 return &UnstructuredList{Object: obj.Object}, nil
65 }
66
67 ret := &UnstructuredList{}
68 ret.Object = obj.Object
69
70 err := obj.EachListItem(func(item runtime.Object) error {
71 castItem := item.(*Unstructured)
72 ret.Items = append(ret.Items, *castItem)
73 return nil
74 })
75 if err != nil {
76 return nil, err
77 }
78
79 return ret, nil
80}
81
82func (obj *Unstructured) EachListItem(fn func(runtime.Object) error) error {
83 field, ok := obj.Object["items"]
84 if !ok {
85 return errors.New("content is not a list")
86 }
87 items, ok := field.([]interface{})
88 if !ok {
89 return fmt.Errorf("content is not a list: %T", field)
90 }
91 for _, item := range items {
92 child, ok := item.(map[string]interface{})
93 if !ok {
94 return fmt.Errorf("items member is not an object: %T", child)
95 }
96 if err := fn(&Unstructured{Object: child}); err != nil {
97 return err
98 }
99 }
100 return nil
101}
102
103func (obj *Unstructured) UnstructuredContent() map[string]interface{} {
104 if obj.Object == nil {
105 return make(map[string]interface{})
106 }
107 return obj.Object
108}
109
110func (obj *Unstructured) SetUnstructuredContent(content map[string]interface{}) {
111 obj.Object = content
112}
113
114// MarshalJSON ensures that the unstructured object produces proper
115// JSON when passed to Go's standard JSON library.
116func (u *Unstructured) MarshalJSON() ([]byte, error) {
117 var buf bytes.Buffer
118 err := UnstructuredJSONScheme.Encode(u, &buf)
119 return buf.Bytes(), err
120}
121
122// UnmarshalJSON ensures that the unstructured object properly decodes
123// JSON when passed to Go's standard JSON library.
124func (u *Unstructured) UnmarshalJSON(b []byte) error {
125 _, _, err := UnstructuredJSONScheme.Decode(b, nil, u)
126 return err
127}
128
129func (in *Unstructured) DeepCopy() *Unstructured {
130 if in == nil {
131 return nil
132 }
133 out := new(Unstructured)
134 *out = *in
135 out.Object = runtime.DeepCopyJSON(in.Object)
136 return out
137}
138
139func (u *Unstructured) setNestedField(value interface{}, fields ...string) {
140 if u.Object == nil {
141 u.Object = make(map[string]interface{})
142 }
143 SetNestedField(u.Object, value, fields...)
144}
145
Stephane Barbarie260a5632019-02-26 16:12:49 -0500146func (u *Unstructured) setNestedStringSlice(value []string, fields ...string) {
sslobodrd046be82019-01-16 10:02:22 -0500147 if u.Object == nil {
148 u.Object = make(map[string]interface{})
149 }
150 SetNestedStringSlice(u.Object, value, fields...)
151}
152
Stephane Barbarie260a5632019-02-26 16:12:49 -0500153func (u *Unstructured) setNestedSlice(value []interface{}, fields ...string) {
154 if u.Object == nil {
155 u.Object = make(map[string]interface{})
156 }
157 SetNestedSlice(u.Object, value, fields...)
158}
159
sslobodrd046be82019-01-16 10:02:22 -0500160func (u *Unstructured) setNestedMap(value map[string]string, fields ...string) {
161 if u.Object == nil {
162 u.Object = make(map[string]interface{})
163 }
164 SetNestedStringMap(u.Object, value, fields...)
165}
166
167func (u *Unstructured) GetOwnerReferences() []metav1.OwnerReference {
168 field, found, err := NestedFieldNoCopy(u.Object, "metadata", "ownerReferences")
169 if !found || err != nil {
170 return nil
171 }
172 original, ok := field.([]interface{})
173 if !ok {
174 return nil
175 }
176 ret := make([]metav1.OwnerReference, 0, len(original))
177 for _, obj := range original {
178 o, ok := obj.(map[string]interface{})
179 if !ok {
180 // expected map[string]interface{}, got something else
181 return nil
182 }
183 ret = append(ret, extractOwnerReference(o))
184 }
185 return ret
186}
187
188func (u *Unstructured) SetOwnerReferences(references []metav1.OwnerReference) {
189 if references == nil {
190 RemoveNestedField(u.Object, "metadata", "ownerReferences")
191 return
192 }
193
194 newReferences := make([]interface{}, 0, len(references))
195 for _, reference := range references {
196 out, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&reference)
197 if err != nil {
198 utilruntime.HandleError(fmt.Errorf("unable to convert Owner Reference: %v", err))
199 continue
200 }
201 newReferences = append(newReferences, out)
202 }
203 u.setNestedField(newReferences, "metadata", "ownerReferences")
204}
205
206func (u *Unstructured) GetAPIVersion() string {
207 return getNestedString(u.Object, "apiVersion")
208}
209
210func (u *Unstructured) SetAPIVersion(version string) {
211 u.setNestedField(version, "apiVersion")
212}
213
214func (u *Unstructured) GetKind() string {
215 return getNestedString(u.Object, "kind")
216}
217
218func (u *Unstructured) SetKind(kind string) {
219 u.setNestedField(kind, "kind")
220}
221
222func (u *Unstructured) GetNamespace() string {
223 return getNestedString(u.Object, "metadata", "namespace")
224}
225
226func (u *Unstructured) SetNamespace(namespace string) {
227 if len(namespace) == 0 {
228 RemoveNestedField(u.Object, "metadata", "namespace")
229 return
230 }
231 u.setNestedField(namespace, "metadata", "namespace")
232}
233
234func (u *Unstructured) GetName() string {
235 return getNestedString(u.Object, "metadata", "name")
236}
237
238func (u *Unstructured) SetName(name string) {
239 if len(name) == 0 {
240 RemoveNestedField(u.Object, "metadata", "name")
241 return
242 }
243 u.setNestedField(name, "metadata", "name")
244}
245
246func (u *Unstructured) GetGenerateName() string {
247 return getNestedString(u.Object, "metadata", "generateName")
248}
249
250func (u *Unstructured) SetGenerateName(generateName string) {
251 if len(generateName) == 0 {
252 RemoveNestedField(u.Object, "metadata", "generateName")
253 return
254 }
255 u.setNestedField(generateName, "metadata", "generateName")
256}
257
258func (u *Unstructured) GetUID() types.UID {
259 return types.UID(getNestedString(u.Object, "metadata", "uid"))
260}
261
262func (u *Unstructured) SetUID(uid types.UID) {
263 if len(string(uid)) == 0 {
264 RemoveNestedField(u.Object, "metadata", "uid")
265 return
266 }
267 u.setNestedField(string(uid), "metadata", "uid")
268}
269
270func (u *Unstructured) GetResourceVersion() string {
271 return getNestedString(u.Object, "metadata", "resourceVersion")
272}
273
274func (u *Unstructured) SetResourceVersion(resourceVersion string) {
275 if len(resourceVersion) == 0 {
276 RemoveNestedField(u.Object, "metadata", "resourceVersion")
277 return
278 }
279 u.setNestedField(resourceVersion, "metadata", "resourceVersion")
280}
281
282func (u *Unstructured) GetGeneration() int64 {
283 val, found, err := NestedInt64(u.Object, "metadata", "generation")
284 if !found || err != nil {
285 return 0
286 }
287 return val
288}
289
290func (u *Unstructured) SetGeneration(generation int64) {
291 if generation == 0 {
292 RemoveNestedField(u.Object, "metadata", "generation")
293 return
294 }
295 u.setNestedField(generation, "metadata", "generation")
296}
297
298func (u *Unstructured) GetSelfLink() string {
299 return getNestedString(u.Object, "metadata", "selfLink")
300}
301
302func (u *Unstructured) SetSelfLink(selfLink string) {
303 if len(selfLink) == 0 {
304 RemoveNestedField(u.Object, "metadata", "selfLink")
305 return
306 }
307 u.setNestedField(selfLink, "metadata", "selfLink")
308}
309
310func (u *Unstructured) GetContinue() string {
311 return getNestedString(u.Object, "metadata", "continue")
312}
313
314func (u *Unstructured) SetContinue(c string) {
315 if len(c) == 0 {
316 RemoveNestedField(u.Object, "metadata", "continue")
317 return
318 }
319 u.setNestedField(c, "metadata", "continue")
320}
321
322func (u *Unstructured) GetCreationTimestamp() metav1.Time {
323 var timestamp metav1.Time
324 timestamp.UnmarshalQueryParameter(getNestedString(u.Object, "metadata", "creationTimestamp"))
325 return timestamp
326}
327
328func (u *Unstructured) SetCreationTimestamp(timestamp metav1.Time) {
329 ts, _ := timestamp.MarshalQueryParameter()
330 if len(ts) == 0 || timestamp.Time.IsZero() {
331 RemoveNestedField(u.Object, "metadata", "creationTimestamp")
332 return
333 }
334 u.setNestedField(ts, "metadata", "creationTimestamp")
335}
336
337func (u *Unstructured) GetDeletionTimestamp() *metav1.Time {
338 var timestamp metav1.Time
339 timestamp.UnmarshalQueryParameter(getNestedString(u.Object, "metadata", "deletionTimestamp"))
340 if timestamp.IsZero() {
341 return nil
342 }
343 return &timestamp
344}
345
346func (u *Unstructured) SetDeletionTimestamp(timestamp *metav1.Time) {
347 if timestamp == nil {
348 RemoveNestedField(u.Object, "metadata", "deletionTimestamp")
349 return
350 }
351 ts, _ := timestamp.MarshalQueryParameter()
352 u.setNestedField(ts, "metadata", "deletionTimestamp")
353}
354
355func (u *Unstructured) GetDeletionGracePeriodSeconds() *int64 {
356 val, found, err := NestedInt64(u.Object, "metadata", "deletionGracePeriodSeconds")
357 if !found || err != nil {
358 return nil
359 }
360 return &val
361}
362
363func (u *Unstructured) SetDeletionGracePeriodSeconds(deletionGracePeriodSeconds *int64) {
364 if deletionGracePeriodSeconds == nil {
365 RemoveNestedField(u.Object, "metadata", "deletionGracePeriodSeconds")
366 return
367 }
368 u.setNestedField(*deletionGracePeriodSeconds, "metadata", "deletionGracePeriodSeconds")
369}
370
371func (u *Unstructured) GetLabels() map[string]string {
372 m, _, _ := NestedStringMap(u.Object, "metadata", "labels")
373 return m
374}
375
376func (u *Unstructured) SetLabels(labels map[string]string) {
377 if labels == nil {
378 RemoveNestedField(u.Object, "metadata", "labels")
379 return
380 }
381 u.setNestedMap(labels, "metadata", "labels")
382}
383
384func (u *Unstructured) GetAnnotations() map[string]string {
385 m, _, _ := NestedStringMap(u.Object, "metadata", "annotations")
386 return m
387}
388
389func (u *Unstructured) SetAnnotations(annotations map[string]string) {
390 if annotations == nil {
391 RemoveNestedField(u.Object, "metadata", "annotations")
392 return
393 }
394 u.setNestedMap(annotations, "metadata", "annotations")
395}
396
397func (u *Unstructured) SetGroupVersionKind(gvk schema.GroupVersionKind) {
398 u.SetAPIVersion(gvk.GroupVersion().String())
399 u.SetKind(gvk.Kind)
400}
401
402func (u *Unstructured) GroupVersionKind() schema.GroupVersionKind {
403 gv, err := schema.ParseGroupVersion(u.GetAPIVersion())
404 if err != nil {
405 return schema.GroupVersionKind{}
406 }
407 gvk := gv.WithKind(u.GetKind())
408 return gvk
409}
410
411func (u *Unstructured) GetInitializers() *metav1.Initializers {
412 m, found, err := nestedMapNoCopy(u.Object, "metadata", "initializers")
413 if !found || err != nil {
414 return nil
415 }
416 out := &metav1.Initializers{}
417 if err := runtime.DefaultUnstructuredConverter.FromUnstructured(m, out); err != nil {
418 utilruntime.HandleError(fmt.Errorf("unable to retrieve initializers for object: %v", err))
419 return nil
420 }
421 return out
422}
423
424func (u *Unstructured) SetInitializers(initializers *metav1.Initializers) {
425 if initializers == nil {
426 RemoveNestedField(u.Object, "metadata", "initializers")
427 return
428 }
429 out, err := runtime.DefaultUnstructuredConverter.ToUnstructured(initializers)
430 if err != nil {
431 utilruntime.HandleError(fmt.Errorf("unable to retrieve initializers for object: %v", err))
432 }
433 u.setNestedField(out, "metadata", "initializers")
434}
435
436func (u *Unstructured) GetFinalizers() []string {
437 val, _, _ := NestedStringSlice(u.Object, "metadata", "finalizers")
438 return val
439}
440
441func (u *Unstructured) SetFinalizers(finalizers []string) {
442 if finalizers == nil {
443 RemoveNestedField(u.Object, "metadata", "finalizers")
444 return
445 }
Stephane Barbarie260a5632019-02-26 16:12:49 -0500446 u.setNestedStringSlice(finalizers, "metadata", "finalizers")
sslobodrd046be82019-01-16 10:02:22 -0500447}
448
449func (u *Unstructured) GetClusterName() string {
450 return getNestedString(u.Object, "metadata", "clusterName")
451}
452
453func (u *Unstructured) SetClusterName(clusterName string) {
454 if len(clusterName) == 0 {
455 RemoveNestedField(u.Object, "metadata", "clusterName")
456 return
457 }
458 u.setNestedField(clusterName, "metadata", "clusterName")
459}
Stephane Barbarie260a5632019-02-26 16:12:49 -0500460
461func (u *Unstructured) GetManagedFields() []metav1.ManagedFieldsEntry {
462 items, found, err := NestedSlice(u.Object, "metadata", "managedFields")
463 if !found || err != nil {
464 return nil
465 }
466 managedFields := []metav1.ManagedFieldsEntry{}
467 for _, item := range items {
468 m, ok := item.(map[string]interface{})
469 if !ok {
470 utilruntime.HandleError(fmt.Errorf("unable to retrieve managedFields for object, item %v is not a map", item))
471 return nil
472 }
473 out := metav1.ManagedFieldsEntry{}
474 if err := runtime.DefaultUnstructuredConverter.FromUnstructured(m, &out); err != nil {
475 utilruntime.HandleError(fmt.Errorf("unable to retrieve managedFields for object: %v", err))
476 return nil
477 }
478 managedFields = append(managedFields, out)
479 }
480 return managedFields
481}
482
483func (u *Unstructured) SetManagedFields(managedFields []metav1.ManagedFieldsEntry) {
484 if managedFields == nil {
485 RemoveNestedField(u.Object, "metadata", "managedFields")
486 return
487 }
488 items := []interface{}{}
489 for _, managedFieldsEntry := range managedFields {
490 out, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&managedFieldsEntry)
491 if err != nil {
492 utilruntime.HandleError(fmt.Errorf("unable to set managedFields for object: %v", err))
493 return
494 }
495 items = append(items, out)
496 }
497 u.setNestedSlice(items, "metadata", "managedFields")
498}