github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/util/managedfields/gvkparser.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package managedfields 18 19 import ( 20 "fmt" 21 22 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/schema" 23 "k8s.io/kube-openapi/pkg/schemaconv" 24 "k8s.io/kube-openapi/pkg/util/proto" 25 smdschema "sigs.k8s.io/structured-merge-diff/v4/schema" 26 "sigs.k8s.io/structured-merge-diff/v4/typed" 27 ) 28 29 // groupVersionKindExtensionKey is the key used to lookup the 30 // GroupVersionKind value for an object definition from the 31 // definition's "extensions" map. 32 const groupVersionKindExtensionKey = "x-kubernetes-group-version-kind" 33 34 // GvkParser contains a Parser that allows introspecting the schema. 35 type GvkParser struct { 36 gvks map[schema.GroupVersionKind]string 37 parser typed.Parser 38 } 39 40 // Type returns a helper which can produce objects of the given type. Any 41 // errors are deferred until a further function is called. 42 func (p *GvkParser) Type(gvk schema.GroupVersionKind) *typed.ParseableType { 43 typeName, ok := p.gvks[gvk] 44 if !ok { 45 return nil 46 } 47 t := p.parser.Type(typeName) 48 return &t 49 } 50 51 // NewGVKParser builds a GVKParser from a proto.Models. This 52 // will automatically find the proper version of the object, and the 53 // corresponding schema information. 54 func NewGVKParser(models proto.Models, preserveUnknownFields bool) (*GvkParser, error) { 55 typeSchema, err := schemaconv.ToSchemaWithPreserveUnknownFields(models, preserveUnknownFields) 56 if err != nil { 57 return nil, fmt.Errorf("failed to convert models to schema: %v", err) 58 } 59 parser := GvkParser{ 60 gvks: map[schema.GroupVersionKind]string{}, 61 } 62 parser.parser = typed.Parser{Schema: smdschema.Schema{Types: typeSchema.Types}} 63 for _, modelName := range models.ListModels() { 64 model := models.LookupModel(modelName) 65 if model == nil { 66 panic(fmt.Sprintf("ListModels returns a model that can't be looked-up for: %v", modelName)) 67 } 68 gvkList := parseGroupVersionKind(model) 69 for _, gvk := range gvkList { 70 if len(gvk.Kind) > 0 { 71 _, ok := parser.gvks[gvk] 72 if ok { 73 return nil, fmt.Errorf("duplicate entry for %v", gvk) 74 } 75 parser.gvks[gvk] = modelName 76 } 77 } 78 } 79 return &parser, nil 80 } 81 82 // Get and parse GroupVersionKind from the extension. Returns empty if it doesn't have one. 83 func parseGroupVersionKind(s proto.Schema) []schema.GroupVersionKind { 84 extensions := s.GetExtensions() 85 86 gvkListResult := []schema.GroupVersionKind{} 87 88 // Get the extensions 89 gvkExtension, ok := extensions[groupVersionKindExtensionKey] 90 if !ok { 91 return []schema.GroupVersionKind{} 92 } 93 94 // gvk extension must be a list of at least 1 element. 95 gvkList, ok := gvkExtension.([]interface{}) 96 if !ok { 97 return []schema.GroupVersionKind{} 98 } 99 100 for _, gvk := range gvkList { 101 // gvk extension list must be a map with group, version, and 102 // kind fields 103 gvkMap, ok := gvk.(map[interface{}]interface{}) 104 if !ok { 105 continue 106 } 107 group, ok := gvkMap["group"].(string) 108 if !ok { 109 continue 110 } 111 version, ok := gvkMap["version"].(string) 112 if !ok { 113 continue 114 } 115 kind, ok := gvkMap["kind"].(string) 116 if !ok { 117 continue 118 } 119 120 gvkListResult = append(gvkListResult, schema.GroupVersionKind{ 121 Group: group, 122 Version: version, 123 Kind: kind, 124 }) 125 } 126 127 return gvkListResult 128 }