factory.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /*
  2. Copyright 2017 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 parse
  14. import (
  15. "fmt"
  16. "reflect"
  17. "k8s.io/kube-openapi/pkg/util/proto"
  18. "k8s.io/kubernetes/pkg/kubectl/apply"
  19. "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
  20. )
  21. // Factory creates an Element by combining object values from recorded, local and remote sources with
  22. // the metadata from an openapi schema.
  23. type Factory struct {
  24. // Resources contains the openapi field metadata for the object models
  25. Resources openapi.Resources
  26. }
  27. // CreateElement returns an Element by collating the recorded, local and remote field values
  28. func (b *Factory) CreateElement(recorded, local, remote map[string]interface{}) (apply.Element, error) {
  29. // Create an Item from the 3 values. Use empty name for field
  30. visitor := &ElementBuildingVisitor{b.Resources}
  31. gvk, err := getCommonGroupVersionKind(recorded, local, remote)
  32. if err != nil {
  33. return nil, err
  34. }
  35. // Get the openapi object metadata
  36. s := visitor.resources.LookupResource(gvk)
  37. oapiKind, err := getKind(s)
  38. if err != nil {
  39. return nil, err
  40. }
  41. data := apply.NewRawElementData(recorded, local, remote)
  42. fieldName := ""
  43. item, err := visitor.getItem(oapiKind, fieldName, data)
  44. if err != nil {
  45. return nil, err
  46. }
  47. // Collate each field of the item into a combined Element
  48. return item.CreateElement(visitor)
  49. }
  50. // getItem returns the appropriate Item based on the underlying type of the arguments
  51. func (v *ElementBuildingVisitor) getItem(s proto.Schema, name string, data apply.RawElementData) (Item, error) {
  52. kind, err := getType(data.GetRecorded(), data.GetLocal(), data.GetRemote())
  53. if err != nil {
  54. return nil, err
  55. }
  56. if kind == nil {
  57. // All of the items values are nil.
  58. return &emptyItem{Name: name}, nil
  59. }
  60. // Create an item matching the type
  61. switch kind.Kind() {
  62. case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint,
  63. reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64,
  64. reflect.String:
  65. p, err := getPrimitive(s)
  66. if err != nil {
  67. return nil, fmt.Errorf("expected openapi Primitive, was %T for %v (%v)", s, kind, err)
  68. }
  69. return &primitiveItem{name, p, data}, nil
  70. case reflect.Array, reflect.Slice:
  71. a, err := getArray(s)
  72. if err != nil {
  73. return nil, fmt.Errorf("expected openapi Array, was %T for %v (%v)", s, kind, err)
  74. }
  75. return &listItem{
  76. Name: name,
  77. Array: a,
  78. ListElementData: apply.ListElementData{
  79. RawElementData: data,
  80. },
  81. }, nil
  82. case reflect.Map:
  83. if k, err := getKind(s); err == nil {
  84. return &typeItem{
  85. Name: name,
  86. Type: k,
  87. MapElementData: apply.MapElementData{
  88. RawElementData: data,
  89. },
  90. }, nil
  91. }
  92. // If it looks like a map, and no openapi type is found, default to mapItem
  93. m, err := getMap(s)
  94. if err != nil {
  95. return nil, fmt.Errorf("expected openapi Kind or Map, was %T for %v (%v)", s, kind, err)
  96. }
  97. return &mapItem{
  98. Name: name,
  99. Map: m,
  100. MapElementData: apply.MapElementData{
  101. RawElementData: data,
  102. },
  103. }, nil
  104. }
  105. return nil, fmt.Errorf("unsupported type %v", kind)
  106. }