123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- /*
- Copyright 2018 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package managedfields
- import (
- "fmt"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/kube-openapi/pkg/schemaconv"
- "k8s.io/kube-openapi/pkg/util/proto"
- smdschema "sigs.k8s.io/structured-merge-diff/v4/schema"
- "sigs.k8s.io/structured-merge-diff/v4/typed"
- )
- // groupVersionKindExtensionKey is the key used to lookup the
- // GroupVersionKind value for an object definition from the
- // definition's "extensions" map.
- const groupVersionKindExtensionKey = "x-kubernetes-group-version-kind"
- // GvkParser contains a Parser that allows introspecting the schema.
- type GvkParser struct {
- gvks map[schema.GroupVersionKind]string
- parser typed.Parser
- }
- // Type returns a helper which can produce objects of the given type. Any
- // errors are deferred until a further function is called.
- func (p *GvkParser) Type(gvk schema.GroupVersionKind) *typed.ParseableType {
- typeName, ok := p.gvks[gvk]
- if !ok {
- return nil
- }
- t := p.parser.Type(typeName)
- return &t
- }
- // NewGVKParser builds a GVKParser from a proto.Models. This
- // will automatically find the proper version of the object, and the
- // corresponding schema information.
- func NewGVKParser(models proto.Models, preserveUnknownFields bool) (*GvkParser, error) {
- typeSchema, err := schemaconv.ToSchemaWithPreserveUnknownFields(models, preserveUnknownFields)
- if err != nil {
- return nil, fmt.Errorf("failed to convert models to schema: %v", err)
- }
- parser := GvkParser{
- gvks: map[schema.GroupVersionKind]string{},
- }
- parser.parser = typed.Parser{Schema: smdschema.Schema{Types: typeSchema.Types}}
- for _, modelName := range models.ListModels() {
- model := models.LookupModel(modelName)
- if model == nil {
- panic(fmt.Sprintf("ListModels returns a model that can't be looked-up for: %v", modelName))
- }
- gvkList := parseGroupVersionKind(model)
- for _, gvk := range gvkList {
- if len(gvk.Kind) > 0 {
- _, ok := parser.gvks[gvk]
- if ok {
- return nil, fmt.Errorf("duplicate entry for %v", gvk)
- }
- parser.gvks[gvk] = modelName
- }
- }
- }
- return &parser, nil
- }
- // Get and parse GroupVersionKind from the extension. Returns empty if it doesn't have one.
- func parseGroupVersionKind(s proto.Schema) []schema.GroupVersionKind {
- extensions := s.GetExtensions()
- gvkListResult := []schema.GroupVersionKind{}
- // Get the extensions
- gvkExtension, ok := extensions[groupVersionKindExtensionKey]
- if !ok {
- return []schema.GroupVersionKind{}
- }
- // gvk extension must be a list of at least 1 element.
- gvkList, ok := gvkExtension.([]interface{})
- if !ok {
- return []schema.GroupVersionKind{}
- }
- for _, gvk := range gvkList {
- // gvk extension list must be a map with group, version, and
- // kind fields
- gvkMap, ok := gvk.(map[interface{}]interface{})
- if !ok {
- continue
- }
- group, ok := gvkMap["group"].(string)
- if !ok {
- continue
- }
- version, ok := gvkMap["version"].(string)
- if !ok {
- continue
- }
- kind, ok := gvkMap["kind"].(string)
- if !ok {
- continue
- }
- gvkListResult = append(gvkListResult, schema.GroupVersionKind{
- Group: group,
- Version: version,
- Kind: kind,
- })
- }
- return gvkListResult
- }
|