blob: 5028f5fb57a3401943a5ad3618bf05a6e4784c3a [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001/*
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
22 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23 "k8s.io/apimachinery/pkg/runtime"
24 "k8s.io/apimachinery/pkg/runtime/schema"
25)
26
27var _ runtime.Unstructured = &UnstructuredList{}
28var _ metav1.ListInterface = &UnstructuredList{}
29
30// UnstructuredList allows lists that do not have Golang structs
31// registered to be manipulated generically. This can be used to deal
32// with the API lists from a plug-in.
33// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
34// +k8s:deepcopy-gen=true
35type UnstructuredList struct {
36 Object map[string]interface{}
37
38 // Items is a list of unstructured objects.
39 Items []Unstructured `json:"items"`
40}
41
42func (u *UnstructuredList) GetObjectKind() schema.ObjectKind { return u }
43
44func (u *UnstructuredList) IsList() bool { return true }
45
46func (u *UnstructuredList) EachListItem(fn func(runtime.Object) error) error {
47 for i := range u.Items {
48 if err := fn(&u.Items[i]); err != nil {
49 return err
50 }
51 }
52 return nil
53}
54
David Bainbridge86971522019-09-26 22:09:39 +000055// NewEmptyInstance returns a new instance of the concrete type containing only kind/apiVersion and no other data.
56// This should be called instead of reflect.New() for unstructured types because the go type alone does not preserve kind/apiVersion info.
57func (u *UnstructuredList) NewEmptyInstance() runtime.Unstructured {
58 out := new(UnstructuredList)
59 if u != nil {
60 out.SetGroupVersionKind(u.GroupVersionKind())
61 }
62 return out
63}
64
Zack Williamse940c7a2019-08-21 14:25:39 -070065// UnstructuredContent returns a map contain an overlay of the Items field onto
66// the Object field. Items always overwrites overlay.
67func (u *UnstructuredList) UnstructuredContent() map[string]interface{} {
68 out := make(map[string]interface{}, len(u.Object)+1)
69
70 // shallow copy every property
71 for k, v := range u.Object {
72 out[k] = v
73 }
74
75 items := make([]interface{}, len(u.Items))
76 for i, item := range u.Items {
77 items[i] = item.UnstructuredContent()
78 }
79 out["items"] = items
80 return out
81}
82
83// SetUnstructuredContent obeys the conventions of List and keeps Items and the items
84// array in sync. If items is not an array of objects in the incoming map, then any
85// mismatched item will be removed.
86func (obj *UnstructuredList) SetUnstructuredContent(content map[string]interface{}) {
87 obj.Object = content
88 if content == nil {
89 obj.Items = nil
90 return
91 }
92 items, ok := obj.Object["items"].([]interface{})
93 if !ok || items == nil {
94 items = []interface{}{}
95 }
96 unstructuredItems := make([]Unstructured, 0, len(items))
97 newItems := make([]interface{}, 0, len(items))
98 for _, item := range items {
99 o, ok := item.(map[string]interface{})
100 if !ok {
101 continue
102 }
103 unstructuredItems = append(unstructuredItems, Unstructured{Object: o})
104 newItems = append(newItems, o)
105 }
106 obj.Items = unstructuredItems
107 obj.Object["items"] = newItems
108}
109
110func (u *UnstructuredList) DeepCopy() *UnstructuredList {
111 if u == nil {
112 return nil
113 }
114 out := new(UnstructuredList)
115 *out = *u
116 out.Object = runtime.DeepCopyJSON(u.Object)
117 out.Items = make([]Unstructured, len(u.Items))
118 for i := range u.Items {
119 u.Items[i].DeepCopyInto(&out.Items[i])
120 }
121 return out
122}
123
124// MarshalJSON ensures that the unstructured list object produces proper
125// JSON when passed to Go's standard JSON library.
126func (u *UnstructuredList) MarshalJSON() ([]byte, error) {
127 var buf bytes.Buffer
128 err := UnstructuredJSONScheme.Encode(u, &buf)
129 return buf.Bytes(), err
130}
131
132// UnmarshalJSON ensures that the unstructured list object properly
133// decodes JSON when passed to Go's standard JSON library.
134func (u *UnstructuredList) UnmarshalJSON(b []byte) error {
135 _, _, err := UnstructuredJSONScheme.Decode(b, nil, u)
136 return err
137}
138
139func (u *UnstructuredList) GetAPIVersion() string {
140 return getNestedString(u.Object, "apiVersion")
141}
142
143func (u *UnstructuredList) SetAPIVersion(version string) {
144 u.setNestedField(version, "apiVersion")
145}
146
147func (u *UnstructuredList) GetKind() string {
148 return getNestedString(u.Object, "kind")
149}
150
151func (u *UnstructuredList) SetKind(kind string) {
152 u.setNestedField(kind, "kind")
153}
154
155func (u *UnstructuredList) GetResourceVersion() string {
156 return getNestedString(u.Object, "metadata", "resourceVersion")
157}
158
159func (u *UnstructuredList) SetResourceVersion(version string) {
160 u.setNestedField(version, "metadata", "resourceVersion")
161}
162
163func (u *UnstructuredList) GetSelfLink() string {
164 return getNestedString(u.Object, "metadata", "selfLink")
165}
166
167func (u *UnstructuredList) SetSelfLink(selfLink string) {
168 u.setNestedField(selfLink, "metadata", "selfLink")
169}
170
171func (u *UnstructuredList) GetContinue() string {
172 return getNestedString(u.Object, "metadata", "continue")
173}
174
175func (u *UnstructuredList) SetContinue(c string) {
176 u.setNestedField(c, "metadata", "continue")
177}
178
David Bainbridge86971522019-09-26 22:09:39 +0000179func (u *UnstructuredList) GetRemainingItemCount() *int64 {
180 return getNestedInt64Pointer(u.Object, "metadata", "remainingItemCount")
181}
182
183func (u *UnstructuredList) SetRemainingItemCount(c *int64) {
184 if c == nil {
185 RemoveNestedField(u.Object, "metadata", "remainingItemCount")
186 } else {
187 u.setNestedField(*c, "metadata", "remainingItemCount")
188 }
189}
190
Zack Williamse940c7a2019-08-21 14:25:39 -0700191func (u *UnstructuredList) SetGroupVersionKind(gvk schema.GroupVersionKind) {
192 u.SetAPIVersion(gvk.GroupVersion().String())
193 u.SetKind(gvk.Kind)
194}
195
196func (u *UnstructuredList) GroupVersionKind() schema.GroupVersionKind {
197 gv, err := schema.ParseGroupVersion(u.GetAPIVersion())
198 if err != nil {
199 return schema.GroupVersionKind{}
200 }
201 gvk := gv.WithKind(u.GetKind())
202 return gvk
203}
204
205func (u *UnstructuredList) setNestedField(value interface{}, fields ...string) {
206 if u.Object == nil {
207 u.Object = make(map[string]interface{})
208 }
209 SetNestedField(u.Object, value, fields...)
210}