2 Copyright 2015 The Kubernetes Authors.
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
8 http://www.apache.org/licenses/LICENSE-2.0
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.
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"
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.
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.
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
41 type Unstructured struct {
42 // Object is a JSON compatible map with string, float, int, bool, []interface{}, or
43 // map[string]interface{}
45 Object map[string]interface{}
48 var _ metav1.Object = &Unstructured{}
49 var _ runtime.Unstructured = &Unstructured{}
51 func (obj *Unstructured) GetObjectKind() schema.ObjectKind { return obj }
53 func (obj *Unstructured) IsList() bool {
54 field, ok := obj.Object["items"]
58 _, ok = field.([]interface{})
61 func (obj *Unstructured) ToList() (*UnstructuredList, error) {
63 // return an empty list back
64 return &UnstructuredList{Object: obj.Object}, nil
67 ret := &UnstructuredList{}
68 ret.Object = obj.Object
70 err := obj.EachListItem(func(item runtime.Object) error {
71 castItem := item.(*Unstructured)
72 ret.Items = append(ret.Items, *castItem)
82 func (obj *Unstructured) EachListItem(fn func(runtime.Object) error) error {
83 field, ok := obj.Object["items"]
85 return errors.New("content is not a list")
87 items, ok := field.([]interface{})
89 return fmt.Errorf("content is not a list: %T", field)
91 for _, item := range items {
92 child, ok := item.(map[string]interface{})
94 return fmt.Errorf("items member is not an object: %T", child)
96 if err := fn(&Unstructured{Object: child}); err != nil {
103 func (obj *Unstructured) UnstructuredContent() map[string]interface{} {
104 if obj.Object == nil {
105 return make(map[string]interface{})
110 func (obj *Unstructured) SetUnstructuredContent(content map[string]interface{}) {
114 // MarshalJSON ensures that the unstructured object produces proper
115 // JSON when passed to Go's standard JSON library.
116 func (u *Unstructured) MarshalJSON() ([]byte, error) {
118 err := UnstructuredJSONScheme.Encode(u, &buf)
119 return buf.Bytes(), err
122 // UnmarshalJSON ensures that the unstructured object properly decodes
123 // JSON when passed to Go's standard JSON library.
124 func (u *Unstructured) UnmarshalJSON(b []byte) error {
125 _, _, err := UnstructuredJSONScheme.Decode(b, nil, u)
129 func (in *Unstructured) DeepCopy() *Unstructured {
133 out := new(Unstructured)
135 out.Object = runtime.DeepCopyJSON(in.Object)
139 func (u *Unstructured) setNestedField(value interface{}, fields ...string) {
141 u.Object = make(map[string]interface{})
143 SetNestedField(u.Object, value, fields...)
146 func (u *Unstructured) setNestedSlice(value []string, fields ...string) {
148 u.Object = make(map[string]interface{})
150 SetNestedStringSlice(u.Object, value, fields...)
153 func (u *Unstructured) setNestedMap(value map[string]string, fields ...string) {
155 u.Object = make(map[string]interface{})
157 SetNestedStringMap(u.Object, value, fields...)
160 func (u *Unstructured) GetOwnerReferences() []metav1.OwnerReference {
161 field, found, err := NestedFieldNoCopy(u.Object, "metadata", "ownerReferences")
162 if !found || err != nil {
165 original, ok := field.([]interface{})
169 ret := make([]metav1.OwnerReference, 0, len(original))
170 for _, obj := range original {
171 o, ok := obj.(map[string]interface{})
173 // expected map[string]interface{}, got something else
176 ret = append(ret, extractOwnerReference(o))
181 func (u *Unstructured) SetOwnerReferences(references []metav1.OwnerReference) {
182 if references == nil {
183 RemoveNestedField(u.Object, "metadata", "ownerReferences")
187 newReferences := make([]interface{}, 0, len(references))
188 for _, reference := range references {
189 out, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&reference)
191 utilruntime.HandleError(fmt.Errorf("unable to convert Owner Reference: %v", err))
194 newReferences = append(newReferences, out)
196 u.setNestedField(newReferences, "metadata", "ownerReferences")
199 func (u *Unstructured) GetAPIVersion() string {
200 return getNestedString(u.Object, "apiVersion")
203 func (u *Unstructured) SetAPIVersion(version string) {
204 u.setNestedField(version, "apiVersion")
207 func (u *Unstructured) GetKind() string {
208 return getNestedString(u.Object, "kind")
211 func (u *Unstructured) SetKind(kind string) {
212 u.setNestedField(kind, "kind")
215 func (u *Unstructured) GetNamespace() string {
216 return getNestedString(u.Object, "metadata", "namespace")
219 func (u *Unstructured) SetNamespace(namespace string) {
220 if len(namespace) == 0 {
221 RemoveNestedField(u.Object, "metadata", "namespace")
224 u.setNestedField(namespace, "metadata", "namespace")
227 func (u *Unstructured) GetName() string {
228 return getNestedString(u.Object, "metadata", "name")
231 func (u *Unstructured) SetName(name string) {
233 RemoveNestedField(u.Object, "metadata", "name")
236 u.setNestedField(name, "metadata", "name")
239 func (u *Unstructured) GetGenerateName() string {
240 return getNestedString(u.Object, "metadata", "generateName")
243 func (u *Unstructured) SetGenerateName(generateName string) {
244 if len(generateName) == 0 {
245 RemoveNestedField(u.Object, "metadata", "generateName")
248 u.setNestedField(generateName, "metadata", "generateName")
251 func (u *Unstructured) GetUID() types.UID {
252 return types.UID(getNestedString(u.Object, "metadata", "uid"))
255 func (u *Unstructured) SetUID(uid types.UID) {
256 if len(string(uid)) == 0 {
257 RemoveNestedField(u.Object, "metadata", "uid")
260 u.setNestedField(string(uid), "metadata", "uid")
263 func (u *Unstructured) GetResourceVersion() string {
264 return getNestedString(u.Object, "metadata", "resourceVersion")
267 func (u *Unstructured) SetResourceVersion(resourceVersion string) {
268 if len(resourceVersion) == 0 {
269 RemoveNestedField(u.Object, "metadata", "resourceVersion")
272 u.setNestedField(resourceVersion, "metadata", "resourceVersion")
275 func (u *Unstructured) GetGeneration() int64 {
276 val, found, err := NestedInt64(u.Object, "metadata", "generation")
277 if !found || err != nil {
283 func (u *Unstructured) SetGeneration(generation int64) {
285 RemoveNestedField(u.Object, "metadata", "generation")
288 u.setNestedField(generation, "metadata", "generation")
291 func (u *Unstructured) GetSelfLink() string {
292 return getNestedString(u.Object, "metadata", "selfLink")
295 func (u *Unstructured) SetSelfLink(selfLink string) {
296 if len(selfLink) == 0 {
297 RemoveNestedField(u.Object, "metadata", "selfLink")
300 u.setNestedField(selfLink, "metadata", "selfLink")
303 func (u *Unstructured) GetContinue() string {
304 return getNestedString(u.Object, "metadata", "continue")
307 func (u *Unstructured) SetContinue(c string) {
309 RemoveNestedField(u.Object, "metadata", "continue")
312 u.setNestedField(c, "metadata", "continue")
315 func (u *Unstructured) GetCreationTimestamp() metav1.Time {
316 var timestamp metav1.Time
317 timestamp.UnmarshalQueryParameter(getNestedString(u.Object, "metadata", "creationTimestamp"))
321 func (u *Unstructured) SetCreationTimestamp(timestamp metav1.Time) {
322 ts, _ := timestamp.MarshalQueryParameter()
323 if len(ts) == 0 || timestamp.Time.IsZero() {
324 RemoveNestedField(u.Object, "metadata", "creationTimestamp")
327 u.setNestedField(ts, "metadata", "creationTimestamp")
330 func (u *Unstructured) GetDeletionTimestamp() *metav1.Time {
331 var timestamp metav1.Time
332 timestamp.UnmarshalQueryParameter(getNestedString(u.Object, "metadata", "deletionTimestamp"))
333 if timestamp.IsZero() {
339 func (u *Unstructured) SetDeletionTimestamp(timestamp *metav1.Time) {
340 if timestamp == nil {
341 RemoveNestedField(u.Object, "metadata", "deletionTimestamp")
344 ts, _ := timestamp.MarshalQueryParameter()
345 u.setNestedField(ts, "metadata", "deletionTimestamp")
348 func (u *Unstructured) GetDeletionGracePeriodSeconds() *int64 {
349 val, found, err := NestedInt64(u.Object, "metadata", "deletionGracePeriodSeconds")
350 if !found || err != nil {
356 func (u *Unstructured) SetDeletionGracePeriodSeconds(deletionGracePeriodSeconds *int64) {
357 if deletionGracePeriodSeconds == nil {
358 RemoveNestedField(u.Object, "metadata", "deletionGracePeriodSeconds")
361 u.setNestedField(*deletionGracePeriodSeconds, "metadata", "deletionGracePeriodSeconds")
364 func (u *Unstructured) GetLabels() map[string]string {
365 m, _, _ := NestedStringMap(u.Object, "metadata", "labels")
369 func (u *Unstructured) SetLabels(labels map[string]string) {
371 RemoveNestedField(u.Object, "metadata", "labels")
374 u.setNestedMap(labels, "metadata", "labels")
377 func (u *Unstructured) GetAnnotations() map[string]string {
378 m, _, _ := NestedStringMap(u.Object, "metadata", "annotations")
382 func (u *Unstructured) SetAnnotations(annotations map[string]string) {
383 if annotations == nil {
384 RemoveNestedField(u.Object, "metadata", "annotations")
387 u.setNestedMap(annotations, "metadata", "annotations")
390 func (u *Unstructured) SetGroupVersionKind(gvk schema.GroupVersionKind) {
391 u.SetAPIVersion(gvk.GroupVersion().String())
395 func (u *Unstructured) GroupVersionKind() schema.GroupVersionKind {
396 gv, err := schema.ParseGroupVersion(u.GetAPIVersion())
398 return schema.GroupVersionKind{}
400 gvk := gv.WithKind(u.GetKind())
404 func (u *Unstructured) GetInitializers() *metav1.Initializers {
405 m, found, err := nestedMapNoCopy(u.Object, "metadata", "initializers")
406 if !found || err != nil {
409 out := &metav1.Initializers{}
410 if err := runtime.DefaultUnstructuredConverter.FromUnstructured(m, out); err != nil {
411 utilruntime.HandleError(fmt.Errorf("unable to retrieve initializers for object: %v", err))
417 func (u *Unstructured) SetInitializers(initializers *metav1.Initializers) {
418 if initializers == nil {
419 RemoveNestedField(u.Object, "metadata", "initializers")
422 out, err := runtime.DefaultUnstructuredConverter.ToUnstructured(initializers)
424 utilruntime.HandleError(fmt.Errorf("unable to retrieve initializers for object: %v", err))
426 u.setNestedField(out, "metadata", "initializers")
429 func (u *Unstructured) GetFinalizers() []string {
430 val, _, _ := NestedStringSlice(u.Object, "metadata", "finalizers")
434 func (u *Unstructured) SetFinalizers(finalizers []string) {
435 if finalizers == nil {
436 RemoveNestedField(u.Object, "metadata", "finalizers")
439 u.setNestedSlice(finalizers, "metadata", "finalizers")
442 func (u *Unstructured) GetClusterName() string {
443 return getNestedString(u.Object, "metadata", "clusterName")
446 func (u *Unstructured) SetClusterName(clusterName string) {
447 if len(clusterName) == 0 {
448 RemoveNestedField(u.Object, "metadata", "clusterName")
451 u.setNestedField(clusterName, "metadata", "clusterName")