helpers.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  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. gojson "encoding/json"
  16. "fmt"
  17. "io"
  18. "strings"
  19. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  20. "k8s.io/apimachinery/pkg/runtime"
  21. "k8s.io/apimachinery/pkg/runtime/schema"
  22. "k8s.io/apimachinery/pkg/types"
  23. "k8s.io/apimachinery/pkg/util/json"
  24. )
  25. // NestedFieldCopy returns a deep copy of the value of a nested field.
  26. // Returns false if the value is missing.
  27. // No error is returned for a nil field.
  28. func NestedFieldCopy(obj map[string]interface{}, fields ...string) (interface{}, bool, error) {
  29. val, found, err := NestedFieldNoCopy(obj, fields...)
  30. if !found || err != nil {
  31. return nil, found, err
  32. }
  33. return runtime.DeepCopyJSONValue(val), true, nil
  34. }
  35. // NestedFieldNoCopy returns a reference to a nested field.
  36. // Returns false if value is not found and an error if unable
  37. // to traverse obj.
  38. func NestedFieldNoCopy(obj map[string]interface{}, fields ...string) (interface{}, bool, error) {
  39. var val interface{} = obj
  40. for i, field := range fields {
  41. if m, ok := val.(map[string]interface{}); ok {
  42. val, ok = m[field]
  43. if !ok {
  44. return nil, false, nil
  45. }
  46. } else {
  47. return nil, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected map[string]interface{}", jsonPath(fields[:i+1]), val, val)
  48. }
  49. }
  50. return val, true, nil
  51. }
  52. // NestedString returns the string value of a nested field.
  53. // Returns false if value is not found and an error if not a string.
  54. func NestedString(obj map[string]interface{}, fields ...string) (string, bool, error) {
  55. val, found, err := NestedFieldNoCopy(obj, fields...)
  56. if !found || err != nil {
  57. return "", found, err
  58. }
  59. s, ok := val.(string)
  60. if !ok {
  61. return "", false, fmt.Errorf("%v accessor error: %v is of the type %T, expected string", jsonPath(fields), val, val)
  62. }
  63. return s, true, nil
  64. }
  65. // NestedBool returns the bool value of a nested field.
  66. // Returns false if value is not found and an error if not a bool.
  67. func NestedBool(obj map[string]interface{}, fields ...string) (bool, bool, error) {
  68. val, found, err := NestedFieldNoCopy(obj, fields...)
  69. if !found || err != nil {
  70. return false, found, err
  71. }
  72. b, ok := val.(bool)
  73. if !ok {
  74. return false, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected bool", jsonPath(fields), val, val)
  75. }
  76. return b, true, nil
  77. }
  78. // NestedFloat64 returns the float64 value of a nested field.
  79. // Returns false if value is not found and an error if not a float64.
  80. func NestedFloat64(obj map[string]interface{}, fields ...string) (float64, bool, error) {
  81. val, found, err := NestedFieldNoCopy(obj, fields...)
  82. if !found || err != nil {
  83. return 0, found, err
  84. }
  85. f, ok := val.(float64)
  86. if !ok {
  87. return 0, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected float64", jsonPath(fields), val, val)
  88. }
  89. return f, true, nil
  90. }
  91. // NestedInt64 returns the int64 value of a nested field.
  92. // Returns false if value is not found and an error if not an int64.
  93. func NestedInt64(obj map[string]interface{}, fields ...string) (int64, bool, error) {
  94. val, found, err := NestedFieldNoCopy(obj, fields...)
  95. if !found || err != nil {
  96. return 0, found, err
  97. }
  98. i, ok := val.(int64)
  99. if !ok {
  100. return 0, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected int64", jsonPath(fields), val, val)
  101. }
  102. return i, true, nil
  103. }
  104. // NestedStringSlice returns a copy of []string value of a nested field.
  105. // Returns false if value is not found and an error if not a []interface{} or contains non-string items in the slice.
  106. func NestedStringSlice(obj map[string]interface{}, fields ...string) ([]string, bool, error) {
  107. val, found, err := NestedFieldNoCopy(obj, fields...)
  108. if !found || err != nil {
  109. return nil, found, err
  110. }
  111. m, ok := val.([]interface{})
  112. if !ok {
  113. return nil, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected []interface{}", jsonPath(fields), val, val)
  114. }
  115. strSlice := make([]string, 0, len(m))
  116. for _, v := range m {
  117. if str, ok := v.(string); ok {
  118. strSlice = append(strSlice, str)
  119. } else {
  120. return nil, false, fmt.Errorf("%v accessor error: contains non-string key in the slice: %v is of the type %T, expected string", jsonPath(fields), v, v)
  121. }
  122. }
  123. return strSlice, true, nil
  124. }
  125. // NestedSlice returns a deep copy of []interface{} value of a nested field.
  126. // Returns false if value is not found and an error if not a []interface{}.
  127. func NestedSlice(obj map[string]interface{}, fields ...string) ([]interface{}, bool, error) {
  128. val, found, err := NestedFieldNoCopy(obj, fields...)
  129. if !found || err != nil {
  130. return nil, found, err
  131. }
  132. _, ok := val.([]interface{})
  133. if !ok {
  134. return nil, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected []interface{}", jsonPath(fields), val, val)
  135. }
  136. return runtime.DeepCopyJSONValue(val).([]interface{}), true, nil
  137. }
  138. // NestedStringMap returns a copy of map[string]string value of a nested field.
  139. // Returns false if value is not found and an error if not a map[string]interface{} or contains non-string values in the map.
  140. func NestedStringMap(obj map[string]interface{}, fields ...string) (map[string]string, bool, error) {
  141. m, found, err := nestedMapNoCopy(obj, fields...)
  142. if !found || err != nil {
  143. return nil, found, err
  144. }
  145. strMap := make(map[string]string, len(m))
  146. for k, v := range m {
  147. if str, ok := v.(string); ok {
  148. strMap[k] = str
  149. } else {
  150. return nil, false, fmt.Errorf("%v accessor error: contains non-string key in the map: %v is of the type %T, expected string", jsonPath(fields), v, v)
  151. }
  152. }
  153. return strMap, true, nil
  154. }
  155. // NestedMap returns a deep copy of map[string]interface{} value of a nested field.
  156. // Returns false if value is not found and an error if not a map[string]interface{}.
  157. func NestedMap(obj map[string]interface{}, fields ...string) (map[string]interface{}, bool, error) {
  158. m, found, err := nestedMapNoCopy(obj, fields...)
  159. if !found || err != nil {
  160. return nil, found, err
  161. }
  162. return runtime.DeepCopyJSON(m), true, nil
  163. }
  164. // nestedMapNoCopy returns a map[string]interface{} value of a nested field.
  165. // Returns false if value is not found and an error if not a map[string]interface{}.
  166. func nestedMapNoCopy(obj map[string]interface{}, fields ...string) (map[string]interface{}, bool, error) {
  167. val, found, err := NestedFieldNoCopy(obj, fields...)
  168. if !found || err != nil {
  169. return nil, found, err
  170. }
  171. m, ok := val.(map[string]interface{})
  172. if !ok {
  173. return nil, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected map[string]interface{}", jsonPath(fields), val, val)
  174. }
  175. return m, true, nil
  176. }
  177. // SetNestedField sets the value of a nested field to a deep copy of the value provided.
  178. // Returns an error if value cannot be set because one of the nesting levels is not a map[string]interface{}.
  179. func SetNestedField(obj map[string]interface{}, value interface{}, fields ...string) error {
  180. return setNestedFieldNoCopy(obj, runtime.DeepCopyJSONValue(value), fields...)
  181. }
  182. func setNestedFieldNoCopy(obj map[string]interface{}, value interface{}, fields ...string) error {
  183. m := obj
  184. for i, field := range fields[:len(fields)-1] {
  185. if val, ok := m[field]; ok {
  186. if valMap, ok := val.(map[string]interface{}); ok {
  187. m = valMap
  188. } else {
  189. return fmt.Errorf("value cannot be set because %v is not a map[string]interface{}", jsonPath(fields[:i+1]))
  190. }
  191. } else {
  192. newVal := make(map[string]interface{})
  193. m[field] = newVal
  194. m = newVal
  195. }
  196. }
  197. m[fields[len(fields)-1]] = value
  198. return nil
  199. }
  200. // SetNestedStringSlice sets the string slice value of a nested field.
  201. // Returns an error if value cannot be set because one of the nesting levels is not a map[string]interface{}.
  202. func SetNestedStringSlice(obj map[string]interface{}, value []string, fields ...string) error {
  203. m := make([]interface{}, 0, len(value)) // convert []string into []interface{}
  204. for _, v := range value {
  205. m = append(m, v)
  206. }
  207. return setNestedFieldNoCopy(obj, m, fields...)
  208. }
  209. // SetNestedSlice sets the slice value of a nested field.
  210. // Returns an error if value cannot be set because one of the nesting levels is not a map[string]interface{}.
  211. func SetNestedSlice(obj map[string]interface{}, value []interface{}, fields ...string) error {
  212. return SetNestedField(obj, value, fields...)
  213. }
  214. // SetNestedStringMap sets the map[string]string value of a nested field.
  215. // Returns an error if value cannot be set because one of the nesting levels is not a map[string]interface{}.
  216. func SetNestedStringMap(obj map[string]interface{}, value map[string]string, fields ...string) error {
  217. m := make(map[string]interface{}, len(value)) // convert map[string]string into map[string]interface{}
  218. for k, v := range value {
  219. m[k] = v
  220. }
  221. return setNestedFieldNoCopy(obj, m, fields...)
  222. }
  223. // SetNestedMap sets the map[string]interface{} value of a nested field.
  224. // Returns an error if value cannot be set because one of the nesting levels is not a map[string]interface{}.
  225. func SetNestedMap(obj map[string]interface{}, value map[string]interface{}, fields ...string) error {
  226. return SetNestedField(obj, value, fields...)
  227. }
  228. // RemoveNestedField removes the nested field from the obj.
  229. func RemoveNestedField(obj map[string]interface{}, fields ...string) {
  230. m := obj
  231. for _, field := range fields[:len(fields)-1] {
  232. if x, ok := m[field].(map[string]interface{}); ok {
  233. m = x
  234. } else {
  235. return
  236. }
  237. }
  238. delete(m, fields[len(fields)-1])
  239. }
  240. func getNestedString(obj map[string]interface{}, fields ...string) string {
  241. val, found, err := NestedString(obj, fields...)
  242. if !found || err != nil {
  243. return ""
  244. }
  245. return val
  246. }
  247. func jsonPath(fields []string) string {
  248. return "." + strings.Join(fields, ".")
  249. }
  250. func extractOwnerReference(v map[string]interface{}) metav1.OwnerReference {
  251. // though this field is a *bool, but when decoded from JSON, it's
  252. // unmarshalled as bool.
  253. var controllerPtr *bool
  254. if controller, found, err := NestedBool(v, "controller"); err == nil && found {
  255. controllerPtr = &controller
  256. }
  257. var blockOwnerDeletionPtr *bool
  258. if blockOwnerDeletion, found, err := NestedBool(v, "blockOwnerDeletion"); err == nil && found {
  259. blockOwnerDeletionPtr = &blockOwnerDeletion
  260. }
  261. return metav1.OwnerReference{
  262. Kind: getNestedString(v, "kind"),
  263. Name: getNestedString(v, "name"),
  264. APIVersion: getNestedString(v, "apiVersion"),
  265. UID: types.UID(getNestedString(v, "uid")),
  266. Controller: controllerPtr,
  267. BlockOwnerDeletion: blockOwnerDeletionPtr,
  268. }
  269. }
  270. // UnstructuredJSONScheme is capable of converting JSON data into the Unstructured
  271. // type, which can be used for generic access to objects without a predefined scheme.
  272. // TODO: move into serializer/json.
  273. var UnstructuredJSONScheme runtime.Codec = unstructuredJSONScheme{}
  274. type unstructuredJSONScheme struct{}
  275. func (s unstructuredJSONScheme) Decode(data []byte, _ *schema.GroupVersionKind, obj runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
  276. var err error
  277. if obj != nil {
  278. err = s.decodeInto(data, obj)
  279. } else {
  280. obj, err = s.decode(data)
  281. }
  282. if err != nil {
  283. return nil, nil, err
  284. }
  285. gvk := obj.GetObjectKind().GroupVersionKind()
  286. if len(gvk.Kind) == 0 {
  287. return nil, &gvk, runtime.NewMissingKindErr(string(data))
  288. }
  289. return obj, &gvk, nil
  290. }
  291. func (unstructuredJSONScheme) Encode(obj runtime.Object, w io.Writer) error {
  292. switch t := obj.(type) {
  293. case *Unstructured:
  294. return json.NewEncoder(w).Encode(t.Object)
  295. case *UnstructuredList:
  296. items := make([]interface{}, 0, len(t.Items))
  297. for _, i := range t.Items {
  298. items = append(items, i.Object)
  299. }
  300. listObj := make(map[string]interface{}, len(t.Object)+1)
  301. for k, v := range t.Object { // Make a shallow copy
  302. listObj[k] = v
  303. }
  304. listObj["items"] = items
  305. return json.NewEncoder(w).Encode(listObj)
  306. case *runtime.Unknown:
  307. // TODO: Unstructured needs to deal with ContentType.
  308. _, err := w.Write(t.Raw)
  309. return err
  310. default:
  311. return json.NewEncoder(w).Encode(t)
  312. }
  313. }
  314. func (s unstructuredJSONScheme) decode(data []byte) (runtime.Object, error) {
  315. type detector struct {
  316. Items gojson.RawMessage
  317. }
  318. var det detector
  319. if err := json.Unmarshal(data, &det); err != nil {
  320. return nil, err
  321. }
  322. if det.Items != nil {
  323. list := &UnstructuredList{}
  324. err := s.decodeToList(data, list)
  325. return list, err
  326. }
  327. // No Items field, so it wasn't a list.
  328. unstruct := &Unstructured{}
  329. err := s.decodeToUnstructured(data, unstruct)
  330. return unstruct, err
  331. }
  332. func (s unstructuredJSONScheme) decodeInto(data []byte, obj runtime.Object) error {
  333. switch x := obj.(type) {
  334. case *Unstructured:
  335. return s.decodeToUnstructured(data, x)
  336. case *UnstructuredList:
  337. return s.decodeToList(data, x)
  338. case *runtime.VersionedObjects:
  339. o, err := s.decode(data)
  340. if err == nil {
  341. x.Objects = []runtime.Object{o}
  342. }
  343. return err
  344. default:
  345. return json.Unmarshal(data, x)
  346. }
  347. }
  348. func (unstructuredJSONScheme) decodeToUnstructured(data []byte, unstruct *Unstructured) error {
  349. m := make(map[string]interface{})
  350. if err := json.Unmarshal(data, &m); err != nil {
  351. return err
  352. }
  353. unstruct.Object = m
  354. return nil
  355. }
  356. func (s unstructuredJSONScheme) decodeToList(data []byte, list *UnstructuredList) error {
  357. type decodeList struct {
  358. Items []gojson.RawMessage
  359. }
  360. var dList decodeList
  361. if err := json.Unmarshal(data, &dList); err != nil {
  362. return err
  363. }
  364. if err := json.Unmarshal(data, &list.Object); err != nil {
  365. return err
  366. }
  367. // For typed lists, e.g., a PodList, API server doesn't set each item's
  368. // APIVersion and Kind. We need to set it.
  369. listAPIVersion := list.GetAPIVersion()
  370. listKind := list.GetKind()
  371. itemKind := strings.TrimSuffix(listKind, "List")
  372. delete(list.Object, "items")
  373. list.Items = make([]Unstructured, 0, len(dList.Items))
  374. for _, i := range dList.Items {
  375. unstruct := &Unstructured{}
  376. if err := s.decodeToUnstructured([]byte(i), unstruct); err != nil {
  377. return err
  378. }
  379. // This is hacky. Set the item's Kind and APIVersion to those inferred
  380. // from the List.
  381. if len(unstruct.GetKind()) == 0 && len(unstruct.GetAPIVersion()) == 0 {
  382. unstruct.SetKind(itemKind)
  383. unstruct.SetAPIVersion(listAPIVersion)
  384. }
  385. list.Items = append(list.Items, *unstruct)
  386. }
  387. return nil
  388. }
  389. type JSONFallbackEncoder struct {
  390. runtime.Encoder
  391. }
  392. func (c JSONFallbackEncoder) Encode(obj runtime.Object, w io.Writer) error {
  393. err := c.Encoder.Encode(obj, w)
  394. if runtime.IsNotRegisteredError(err) {
  395. switch obj.(type) {
  396. case *Unstructured, *UnstructuredList:
  397. return UnstructuredJSONScheme.Encode(obj, w)
  398. }
  399. }
  400. return err
  401. }