unstructured.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  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. if references == nil {
  159. RemoveNestedField(u.Object, "metadata", "ownerReferences")
  160. return
  161. }
  162. newReferences := make([]interface{}, 0, len(references))
  163. for _, reference := range references {
  164. out, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&reference)
  165. if err != nil {
  166. utilruntime.HandleError(fmt.Errorf("unable to convert Owner Reference: %v", err))
  167. continue
  168. }
  169. newReferences = append(newReferences, out)
  170. }
  171. u.setNestedField(newReferences, "metadata", "ownerReferences")
  172. }
  173. func (u *Unstructured) GetAPIVersion() string {
  174. return getNestedString(u.Object, "apiVersion")
  175. }
  176. func (u *Unstructured) SetAPIVersion(version string) {
  177. u.setNestedField(version, "apiVersion")
  178. }
  179. func (u *Unstructured) GetKind() string {
  180. return getNestedString(u.Object, "kind")
  181. }
  182. func (u *Unstructured) SetKind(kind string) {
  183. u.setNestedField(kind, "kind")
  184. }
  185. func (u *Unstructured) GetNamespace() string {
  186. return getNestedString(u.Object, "metadata", "namespace")
  187. }
  188. func (u *Unstructured) SetNamespace(namespace string) {
  189. if len(namespace) == 0 {
  190. RemoveNestedField(u.Object, "metadata", "namespace")
  191. return
  192. }
  193. u.setNestedField(namespace, "metadata", "namespace")
  194. }
  195. func (u *Unstructured) GetName() string {
  196. return getNestedString(u.Object, "metadata", "name")
  197. }
  198. func (u *Unstructured) SetName(name string) {
  199. if len(name) == 0 {
  200. RemoveNestedField(u.Object, "metadata", "name")
  201. return
  202. }
  203. u.setNestedField(name, "metadata", "name")
  204. }
  205. func (u *Unstructured) GetGenerateName() string {
  206. return getNestedString(u.Object, "metadata", "generateName")
  207. }
  208. func (u *Unstructured) SetGenerateName(generateName string) {
  209. if len(generateName) == 0 {
  210. RemoveNestedField(u.Object, "metadata", "generateName")
  211. return
  212. }
  213. u.setNestedField(generateName, "metadata", "generateName")
  214. }
  215. func (u *Unstructured) GetUID() types.UID {
  216. return types.UID(getNestedString(u.Object, "metadata", "uid"))
  217. }
  218. func (u *Unstructured) SetUID(uid types.UID) {
  219. if len(string(uid)) == 0 {
  220. RemoveNestedField(u.Object, "metadata", "uid")
  221. return
  222. }
  223. u.setNestedField(string(uid), "metadata", "uid")
  224. }
  225. func (u *Unstructured) GetResourceVersion() string {
  226. return getNestedString(u.Object, "metadata", "resourceVersion")
  227. }
  228. func (u *Unstructured) SetResourceVersion(resourceVersion string) {
  229. if len(resourceVersion) == 0 {
  230. RemoveNestedField(u.Object, "metadata", "resourceVersion")
  231. return
  232. }
  233. u.setNestedField(resourceVersion, "metadata", "resourceVersion")
  234. }
  235. func (u *Unstructured) GetGeneration() int64 {
  236. val, found, err := NestedInt64(u.Object, "metadata", "generation")
  237. if !found || err != nil {
  238. return 0
  239. }
  240. return val
  241. }
  242. func (u *Unstructured) SetGeneration(generation int64) {
  243. if generation == 0 {
  244. RemoveNestedField(u.Object, "metadata", "generation")
  245. return
  246. }
  247. u.setNestedField(generation, "metadata", "generation")
  248. }
  249. func (u *Unstructured) GetSelfLink() string {
  250. return getNestedString(u.Object, "metadata", "selfLink")
  251. }
  252. func (u *Unstructured) SetSelfLink(selfLink string) {
  253. if len(selfLink) == 0 {
  254. RemoveNestedField(u.Object, "metadata", "selfLink")
  255. return
  256. }
  257. u.setNestedField(selfLink, "metadata", "selfLink")
  258. }
  259. func (u *Unstructured) GetContinue() string {
  260. return getNestedString(u.Object, "metadata", "continue")
  261. }
  262. func (u *Unstructured) SetContinue(c string) {
  263. if len(c) == 0 {
  264. RemoveNestedField(u.Object, "metadata", "continue")
  265. return
  266. }
  267. u.setNestedField(c, "metadata", "continue")
  268. }
  269. func (u *Unstructured) GetCreationTimestamp() metav1.Time {
  270. var timestamp metav1.Time
  271. timestamp.UnmarshalQueryParameter(getNestedString(u.Object, "metadata", "creationTimestamp"))
  272. return timestamp
  273. }
  274. func (u *Unstructured) SetCreationTimestamp(timestamp metav1.Time) {
  275. ts, _ := timestamp.MarshalQueryParameter()
  276. if len(ts) == 0 || timestamp.Time.IsZero() {
  277. RemoveNestedField(u.Object, "metadata", "creationTimestamp")
  278. return
  279. }
  280. u.setNestedField(ts, "metadata", "creationTimestamp")
  281. }
  282. func (u *Unstructured) GetDeletionTimestamp() *metav1.Time {
  283. var timestamp metav1.Time
  284. timestamp.UnmarshalQueryParameter(getNestedString(u.Object, "metadata", "deletionTimestamp"))
  285. if timestamp.IsZero() {
  286. return nil
  287. }
  288. return &timestamp
  289. }
  290. func (u *Unstructured) SetDeletionTimestamp(timestamp *metav1.Time) {
  291. if timestamp == nil {
  292. RemoveNestedField(u.Object, "metadata", "deletionTimestamp")
  293. return
  294. }
  295. ts, _ := timestamp.MarshalQueryParameter()
  296. u.setNestedField(ts, "metadata", "deletionTimestamp")
  297. }
  298. func (u *Unstructured) GetDeletionGracePeriodSeconds() *int64 {
  299. val, found, err := NestedInt64(u.Object, "metadata", "deletionGracePeriodSeconds")
  300. if !found || err != nil {
  301. return nil
  302. }
  303. return &val
  304. }
  305. func (u *Unstructured) SetDeletionGracePeriodSeconds(deletionGracePeriodSeconds *int64) {
  306. if deletionGracePeriodSeconds == nil {
  307. RemoveNestedField(u.Object, "metadata", "deletionGracePeriodSeconds")
  308. return
  309. }
  310. u.setNestedField(*deletionGracePeriodSeconds, "metadata", "deletionGracePeriodSeconds")
  311. }
  312. func (u *Unstructured) GetLabels() map[string]string {
  313. m, _, _ := NestedStringMap(u.Object, "metadata", "labels")
  314. return m
  315. }
  316. func (u *Unstructured) SetLabels(labels map[string]string) {
  317. if labels == nil {
  318. RemoveNestedField(u.Object, "metadata", "labels")
  319. return
  320. }
  321. u.setNestedMap(labels, "metadata", "labels")
  322. }
  323. func (u *Unstructured) GetAnnotations() map[string]string {
  324. m, _, _ := NestedStringMap(u.Object, "metadata", "annotations")
  325. return m
  326. }
  327. func (u *Unstructured) SetAnnotations(annotations map[string]string) {
  328. if annotations == nil {
  329. RemoveNestedField(u.Object, "metadata", "annotations")
  330. return
  331. }
  332. u.setNestedMap(annotations, "metadata", "annotations")
  333. }
  334. func (u *Unstructured) SetGroupVersionKind(gvk schema.GroupVersionKind) {
  335. u.SetAPIVersion(gvk.GroupVersion().String())
  336. u.SetKind(gvk.Kind)
  337. }
  338. func (u *Unstructured) GroupVersionKind() schema.GroupVersionKind {
  339. gv, err := schema.ParseGroupVersion(u.GetAPIVersion())
  340. if err != nil {
  341. return schema.GroupVersionKind{}
  342. }
  343. gvk := gv.WithKind(u.GetKind())
  344. return gvk
  345. }
  346. func (u *Unstructured) GetInitializers() *metav1.Initializers {
  347. m, found, err := nestedMapNoCopy(u.Object, "metadata", "initializers")
  348. if !found || err != nil {
  349. return nil
  350. }
  351. out := &metav1.Initializers{}
  352. if err := runtime.DefaultUnstructuredConverter.FromUnstructured(m, out); err != nil {
  353. utilruntime.HandleError(fmt.Errorf("unable to retrieve initializers for object: %v", err))
  354. return nil
  355. }
  356. return out
  357. }
  358. func (u *Unstructured) SetInitializers(initializers *metav1.Initializers) {
  359. if initializers == nil {
  360. RemoveNestedField(u.Object, "metadata", "initializers")
  361. return
  362. }
  363. out, err := runtime.DefaultUnstructuredConverter.ToUnstructured(initializers)
  364. if err != nil {
  365. utilruntime.HandleError(fmt.Errorf("unable to retrieve initializers for object: %v", err))
  366. }
  367. u.setNestedField(out, "metadata", "initializers")
  368. }
  369. func (u *Unstructured) GetFinalizers() []string {
  370. val, _, _ := NestedStringSlice(u.Object, "metadata", "finalizers")
  371. return val
  372. }
  373. func (u *Unstructured) SetFinalizers(finalizers []string) {
  374. if finalizers == nil {
  375. RemoveNestedField(u.Object, "metadata", "finalizers")
  376. return
  377. }
  378. u.setNestedSlice(finalizers, "metadata", "finalizers")
  379. }
  380. func (u *Unstructured) GetClusterName() string {
  381. return getNestedString(u.Object, "metadata", "clusterName")
  382. }
  383. func (u *Unstructured) SetClusterName(clusterName string) {
  384. if len(clusterName) == 0 {
  385. RemoveNestedField(u.Object, "metadata", "clusterName")
  386. return
  387. }
  388. u.setNestedField(clusterName, "metadata", "clusterName")
  389. }