unstructured.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /*
  2. Copyright 2015 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 unstructured
  14. import (
  15. "bytes"
  16. "errors"
  17. "fmt"
  18. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  19. "k8s.io/apimachinery/pkg/runtime"
  20. "k8s.io/apimachinery/pkg/runtime/schema"
  21. "k8s.io/apimachinery/pkg/types"
  22. utilruntime "k8s.io/apimachinery/pkg/util/runtime"
  23. )
  24. // Unstructured allows objects that do not have Golang structs registered to be manipulated
  25. // generically. This can be used to deal with the API objects from a plug-in. Unstructured
  26. // objects still have functioning TypeMeta features-- kind, version, etc.
  27. //
  28. // WARNING: This object has accessors for the v1 standard metadata. You *MUST NOT* use this
  29. // type if you are dealing with objects that are not in the server meta v1 schema.
  30. //
  31. // TODO: make the serialization part of this type distinct from the field accessors.
  32. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
  33. // +k8s:deepcopy-gen=true
  34. type Unstructured struct {
  35. // Object is a JSON compatible map with string, float, int, bool, []interface{}, or
  36. // map[string]interface{}
  37. // children.
  38. Object map[string]interface{}
  39. }
  40. var _ metav1.Object = &Unstructured{}
  41. var _ runtime.Unstructured = &Unstructured{}
  42. func (obj *Unstructured) GetObjectKind() schema.ObjectKind { return obj }
  43. func (obj *Unstructured) IsList() bool {
  44. field, ok := obj.Object["items"]
  45. if !ok {
  46. return false
  47. }
  48. _, ok = field.([]interface{})
  49. return ok
  50. }
  51. func (obj *Unstructured) ToList() (*UnstructuredList, error) {
  52. if !obj.IsList() {
  53. // return an empty list back
  54. return &UnstructuredList{Object: obj.Object}, nil
  55. }
  56. ret := &UnstructuredList{}
  57. ret.Object = obj.Object
  58. err := obj.EachListItem(func(item runtime.Object) error {
  59. castItem := item.(*Unstructured)
  60. ret.Items = append(ret.Items, *castItem)
  61. return nil
  62. })
  63. if err != nil {
  64. return nil, err
  65. }
  66. return ret, nil
  67. }
  68. func (obj *Unstructured) EachListItem(fn func(runtime.Object) error) error {
  69. field, ok := obj.Object["items"]
  70. if !ok {
  71. return errors.New("content is not a list")
  72. }
  73. items, ok := field.([]interface{})
  74. if !ok {
  75. return fmt.Errorf("content is not a list: %T", field)
  76. }
  77. for _, item := range items {
  78. child, ok := item.(map[string]interface{})
  79. if !ok {
  80. return fmt.Errorf("items member is not an object: %T", child)
  81. }
  82. if err := fn(&Unstructured{Object: child}); err != nil {
  83. return err
  84. }
  85. }
  86. return nil
  87. }
  88. func (obj *Unstructured) UnstructuredContent() map[string]interface{} {
  89. if obj.Object == nil {
  90. return make(map[string]interface{})
  91. }
  92. return obj.Object
  93. }
  94. func (obj *Unstructured) SetUnstructuredContent(content map[string]interface{}) {
  95. obj.Object = content
  96. }
  97. // MarshalJSON ensures that the unstructured object produces proper
  98. // JSON when passed to Go's standard JSON library.
  99. func (u *Unstructured) MarshalJSON() ([]byte, error) {
  100. var buf bytes.Buffer
  101. err := UnstructuredJSONScheme.Encode(u, &buf)
  102. return buf.Bytes(), err
  103. }
  104. // UnmarshalJSON ensures that the unstructured object properly decodes
  105. // JSON when passed to Go's standard JSON library.
  106. func (u *Unstructured) UnmarshalJSON(b []byte) error {
  107. _, _, err := UnstructuredJSONScheme.Decode(b, nil, u)
  108. return err
  109. }
  110. func (in *Unstructured) DeepCopy() *Unstructured {
  111. if in == nil {
  112. return nil
  113. }
  114. out := new(Unstructured)
  115. *out = *in
  116. out.Object = runtime.DeepCopyJSON(in.Object)
  117. return out
  118. }
  119. func (u *Unstructured) setNestedField(value interface{}, fields ...string) {
  120. if u.Object == nil {
  121. u.Object = make(map[string]interface{})
  122. }
  123. SetNestedField(u.Object, value, fields...)
  124. }
  125. func (u *Unstructured) setNestedSlice(value []string, fields ...string) {
  126. if u.Object == nil {
  127. u.Object = make(map[string]interface{})
  128. }
  129. SetNestedStringSlice(u.Object, value, fields...)
  130. }
  131. func (u *Unstructured) setNestedMap(value map[string]string, fields ...string) {
  132. if u.Object == nil {
  133. u.Object = make(map[string]interface{})
  134. }
  135. SetNestedStringMap(u.Object, value, fields...)
  136. }
  137. func (u *Unstructured) GetOwnerReferences() []metav1.OwnerReference {
  138. field, found, err := NestedFieldNoCopy(u.Object, "metadata", "ownerReferences")
  139. if !found || err != nil {
  140. return nil
  141. }
  142. original, ok := field.([]interface{})
  143. if !ok {
  144. return nil
  145. }
  146. ret := make([]metav1.OwnerReference, 0, len(original))
  147. for _, obj := range original {
  148. o, ok := obj.(map[string]interface{})
  149. if !ok {
  150. // expected map[string]interface{}, got something else
  151. return nil
  152. }
  153. ret = append(ret, extractOwnerReference(o))
  154. }
  155. return ret
  156. }
  157. func (u *Unstructured) SetOwnerReferences(references []metav1.OwnerReference) {
  158. newReferences := make([]interface{}, 0, len(references))
  159. for _, reference := range references {
  160. out, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&reference)
  161. if err != nil {
  162. utilruntime.HandleError(fmt.Errorf("unable to convert Owner Reference: %v", err))
  163. continue
  164. }
  165. newReferences = append(newReferences, out)
  166. }
  167. u.setNestedField(newReferences, "metadata", "ownerReferences")
  168. }
  169. func (u *Unstructured) GetAPIVersion() string {
  170. return getNestedString(u.Object, "apiVersion")
  171. }
  172. func (u *Unstructured) SetAPIVersion(version string) {
  173. u.setNestedField(version, "apiVersion")
  174. }
  175. func (u *Unstructured) GetKind() string {
  176. return getNestedString(u.Object, "kind")
  177. }
  178. func (u *Unstructured) SetKind(kind string) {
  179. u.setNestedField(kind, "kind")
  180. }
  181. func (u *Unstructured) GetNamespace() string {
  182. return getNestedString(u.Object, "metadata", "namespace")
  183. }
  184. func (u *Unstructured) SetNamespace(namespace string) {
  185. u.setNestedField(namespace, "metadata", "namespace")
  186. }
  187. func (u *Unstructured) GetName() string {
  188. return getNestedString(u.Object, "metadata", "name")
  189. }
  190. func (u *Unstructured) SetName(name string) {
  191. u.setNestedField(name, "metadata", "name")
  192. }
  193. func (u *Unstructured) GetGenerateName() string {
  194. return getNestedString(u.Object, "metadata", "generateName")
  195. }
  196. func (u *Unstructured) SetGenerateName(name string) {
  197. u.setNestedField(name, "metadata", "generateName")
  198. }
  199. func (u *Unstructured) GetUID() types.UID {
  200. return types.UID(getNestedString(u.Object, "metadata", "uid"))
  201. }
  202. func (u *Unstructured) SetUID(uid types.UID) {
  203. u.setNestedField(string(uid), "metadata", "uid")
  204. }
  205. func (u *Unstructured) GetResourceVersion() string {
  206. return getNestedString(u.Object, "metadata", "resourceVersion")
  207. }
  208. func (u *Unstructured) SetResourceVersion(version string) {
  209. u.setNestedField(version, "metadata", "resourceVersion")
  210. }
  211. func (u *Unstructured) GetGeneration() int64 {
  212. val, found, err := NestedInt64(u.Object, "metadata", "generation")
  213. if !found || err != nil {
  214. return 0
  215. }
  216. return val
  217. }
  218. func (u *Unstructured) SetGeneration(generation int64) {
  219. u.setNestedField(generation, "metadata", "generation")
  220. }
  221. func (u *Unstructured) GetSelfLink() string {
  222. return getNestedString(u.Object, "metadata", "selfLink")
  223. }
  224. func (u *Unstructured) SetSelfLink(selfLink string) {
  225. u.setNestedField(selfLink, "metadata", "selfLink")
  226. }
  227. func (u *Unstructured) GetContinue() string {
  228. return getNestedString(u.Object, "metadata", "continue")
  229. }
  230. func (u *Unstructured) SetContinue(c string) {
  231. u.setNestedField(c, "metadata", "continue")
  232. }
  233. func (u *Unstructured) GetCreationTimestamp() metav1.Time {
  234. var timestamp metav1.Time
  235. timestamp.UnmarshalQueryParameter(getNestedString(u.Object, "metadata", "creationTimestamp"))
  236. return timestamp
  237. }
  238. func (u *Unstructured) SetCreationTimestamp(timestamp metav1.Time) {
  239. ts, _ := timestamp.MarshalQueryParameter()
  240. if len(ts) == 0 || timestamp.Time.IsZero() {
  241. RemoveNestedField(u.Object, "metadata", "creationTimestamp")
  242. return
  243. }
  244. u.setNestedField(ts, "metadata", "creationTimestamp")
  245. }
  246. func (u *Unstructured) GetDeletionTimestamp() *metav1.Time {
  247. var timestamp metav1.Time
  248. timestamp.UnmarshalQueryParameter(getNestedString(u.Object, "metadata", "deletionTimestamp"))
  249. if timestamp.IsZero() {
  250. return nil
  251. }
  252. return &timestamp
  253. }
  254. func (u *Unstructured) SetDeletionTimestamp(timestamp *metav1.Time) {
  255. if timestamp == nil {
  256. RemoveNestedField(u.Object, "metadata", "deletionTimestamp")
  257. return
  258. }
  259. ts, _ := timestamp.MarshalQueryParameter()
  260. u.setNestedField(ts, "metadata", "deletionTimestamp")
  261. }
  262. func (u *Unstructured) GetDeletionGracePeriodSeconds() *int64 {
  263. val, found, err := NestedInt64(u.Object, "metadata", "deletionGracePeriodSeconds")
  264. if !found || err != nil {
  265. return nil
  266. }
  267. return &val
  268. }
  269. func (u *Unstructured) SetDeletionGracePeriodSeconds(deletionGracePeriodSeconds *int64) {
  270. if deletionGracePeriodSeconds == nil {
  271. RemoveNestedField(u.Object, "metadata", "deletionGracePeriodSeconds")
  272. return
  273. }
  274. u.setNestedField(*deletionGracePeriodSeconds, "metadata", "deletionGracePeriodSeconds")
  275. }
  276. func (u *Unstructured) GetLabels() map[string]string {
  277. m, _, _ := NestedStringMap(u.Object, "metadata", "labels")
  278. return m
  279. }
  280. func (u *Unstructured) SetLabels(labels map[string]string) {
  281. u.setNestedMap(labels, "metadata", "labels")
  282. }
  283. func (u *Unstructured) GetAnnotations() map[string]string {
  284. m, _, _ := NestedStringMap(u.Object, "metadata", "annotations")
  285. return m
  286. }
  287. func (u *Unstructured) SetAnnotations(annotations map[string]string) {
  288. u.setNestedMap(annotations, "metadata", "annotations")
  289. }
  290. func (u *Unstructured) SetGroupVersionKind(gvk schema.GroupVersionKind) {
  291. u.SetAPIVersion(gvk.GroupVersion().String())
  292. u.SetKind(gvk.Kind)
  293. }
  294. func (u *Unstructured) GroupVersionKind() schema.GroupVersionKind {
  295. gv, err := schema.ParseGroupVersion(u.GetAPIVersion())
  296. if err != nil {
  297. return schema.GroupVersionKind{}
  298. }
  299. gvk := gv.WithKind(u.GetKind())
  300. return gvk
  301. }
  302. func (u *Unstructured) GetInitializers() *metav1.Initializers {
  303. m, found, err := nestedMapNoCopy(u.Object, "metadata", "initializers")
  304. if !found || err != nil {
  305. return nil
  306. }
  307. out := &metav1.Initializers{}
  308. if err := runtime.DefaultUnstructuredConverter.FromUnstructured(m, out); err != nil {
  309. utilruntime.HandleError(fmt.Errorf("unable to retrieve initializers for object: %v", err))
  310. return nil
  311. }
  312. return out
  313. }
  314. func (u *Unstructured) SetInitializers(initializers *metav1.Initializers) {
  315. if initializers == nil {
  316. RemoveNestedField(u.Object, "metadata", "initializers")
  317. return
  318. }
  319. out, err := runtime.DefaultUnstructuredConverter.ToUnstructured(initializers)
  320. if err != nil {
  321. utilruntime.HandleError(fmt.Errorf("unable to retrieve initializers for object: %v", err))
  322. }
  323. u.setNestedField(out, "metadata", "initializers")
  324. }
  325. func (u *Unstructured) GetFinalizers() []string {
  326. val, _, _ := NestedStringSlice(u.Object, "metadata", "finalizers")
  327. return val
  328. }
  329. func (u *Unstructured) SetFinalizers(finalizers []string) {
  330. u.setNestedSlice(finalizers, "metadata", "finalizers")
  331. }
  332. func (u *Unstructured) GetClusterName() string {
  333. return getNestedString(u.Object, "metadata", "clusterName")
  334. }
  335. func (u *Unstructured) SetClusterName(clusterName string) {
  336. u.setNestedField(clusterName, "metadata", "clusterName")
  337. }