gvkparser.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*
  2. Copyright 2018 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 managedfields
  14. import (
  15. "fmt"
  16. "k8s.io/apimachinery/pkg/runtime/schema"
  17. "k8s.io/kube-openapi/pkg/schemaconv"
  18. "k8s.io/kube-openapi/pkg/util/proto"
  19. smdschema "sigs.k8s.io/structured-merge-diff/v4/schema"
  20. "sigs.k8s.io/structured-merge-diff/v4/typed"
  21. )
  22. // groupVersionKindExtensionKey is the key used to lookup the
  23. // GroupVersionKind value for an object definition from the
  24. // definition's "extensions" map.
  25. const groupVersionKindExtensionKey = "x-kubernetes-group-version-kind"
  26. // GvkParser contains a Parser that allows introspecting the schema.
  27. type GvkParser struct {
  28. gvks map[schema.GroupVersionKind]string
  29. parser typed.Parser
  30. }
  31. // Type returns a helper which can produce objects of the given type. Any
  32. // errors are deferred until a further function is called.
  33. func (p *GvkParser) Type(gvk schema.GroupVersionKind) *typed.ParseableType {
  34. typeName, ok := p.gvks[gvk]
  35. if !ok {
  36. return nil
  37. }
  38. t := p.parser.Type(typeName)
  39. return &t
  40. }
  41. // NewGVKParser builds a GVKParser from a proto.Models. This
  42. // will automatically find the proper version of the object, and the
  43. // corresponding schema information.
  44. func NewGVKParser(models proto.Models, preserveUnknownFields bool) (*GvkParser, error) {
  45. typeSchema, err := schemaconv.ToSchemaWithPreserveUnknownFields(models, preserveUnknownFields)
  46. if err != nil {
  47. return nil, fmt.Errorf("failed to convert models to schema: %v", err)
  48. }
  49. parser := GvkParser{
  50. gvks: map[schema.GroupVersionKind]string{},
  51. }
  52. parser.parser = typed.Parser{Schema: smdschema.Schema{Types: typeSchema.Types}}
  53. for _, modelName := range models.ListModels() {
  54. model := models.LookupModel(modelName)
  55. if model == nil {
  56. panic(fmt.Sprintf("ListModels returns a model that can't be looked-up for: %v", modelName))
  57. }
  58. gvkList := parseGroupVersionKind(model)
  59. for _, gvk := range gvkList {
  60. if len(gvk.Kind) > 0 {
  61. _, ok := parser.gvks[gvk]
  62. if ok {
  63. return nil, fmt.Errorf("duplicate entry for %v", gvk)
  64. }
  65. parser.gvks[gvk] = modelName
  66. }
  67. }
  68. }
  69. return &parser, nil
  70. }
  71. // Get and parse GroupVersionKind from the extension. Returns empty if it doesn't have one.
  72. func parseGroupVersionKind(s proto.Schema) []schema.GroupVersionKind {
  73. extensions := s.GetExtensions()
  74. gvkListResult := []schema.GroupVersionKind{}
  75. // Get the extensions
  76. gvkExtension, ok := extensions[groupVersionKindExtensionKey]
  77. if !ok {
  78. return []schema.GroupVersionKind{}
  79. }
  80. // gvk extension must be a list of at least 1 element.
  81. gvkList, ok := gvkExtension.([]interface{})
  82. if !ok {
  83. return []schema.GroupVersionKind{}
  84. }
  85. for _, gvk := range gvkList {
  86. // gvk extension list must be a map with group, version, and
  87. // kind fields
  88. gvkMap, ok := gvk.(map[interface{}]interface{})
  89. if !ok {
  90. continue
  91. }
  92. group, ok := gvkMap["group"].(string)
  93. if !ok {
  94. continue
  95. }
  96. version, ok := gvkMap["version"].(string)
  97. if !ok {
  98. continue
  99. }
  100. kind, ok := gvkMap["kind"].(string)
  101. if !ok {
  102. continue
  103. }
  104. gvkListResult = append(gvkListResult, schema.GroupVersionKind{
  105. Group: group,
  106. Version: version,
  107. Kind: kind,
  108. })
  109. }
  110. return gvkListResult
  111. }