istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/config/schema/ast/ast.go (about) 1 // Copyright Istio Authors 2 // 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 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package ast 16 17 import ( 18 "encoding/json" 19 "fmt" 20 21 "sigs.k8s.io/yaml" 22 23 "istio.io/istio/pkg/config/validation" 24 // Force-import a function. 25 _ "istio.io/istio/pkg/config/validation/envoyfilter" 26 "istio.io/istio/pkg/util/sets" 27 "istio.io/istio/pkg/util/strcase" 28 ) 29 30 // Metadata is the top-level container. 31 type Metadata struct { 32 Resources []*Resource `json:"resources"` 33 } 34 35 var _ json.Unmarshaler = &Metadata{} 36 37 // Resource metadata for resources contained within a collection. 38 type Resource struct { 39 Identifier string `json:"identifier"` 40 Group string `json:"group"` 41 Version string `json:"version"` 42 VersionAliases []string `json:"versionAliases"` 43 Kind string `json:"kind"` 44 Plural string `json:"plural"` 45 ClusterScoped bool `json:"clusterScoped"` 46 Builtin bool `json:"builtin"` 47 Specless bool `json:"specless"` 48 Synthetic bool `json:"synthetic"` 49 Proto string `json:"proto"` 50 ProtoPackage string `json:"protoPackage"` 51 StatusProto string `json:"statusProto"` 52 StatusProtoPackage string `json:"statusProtoPackage"` 53 Validate string `json:"validate"` 54 Description string `json:"description"` 55 } 56 57 // FindResourceForGroupKind looks up a resource with the given group and kind. Returns nil if not found. 58 func (m *Metadata) FindResourceForGroupKind(group, kind string) *Resource { 59 for _, r := range m.Resources { 60 if r.Group == group && r.Kind == kind { 61 return r 62 } 63 } 64 return nil 65 } 66 67 // UnmarshalJSON implements json.Unmarshaler 68 func (m *Metadata) UnmarshalJSON(data []byte) error { 69 var in struct { 70 Resources []*Resource `json:"resources"` 71 } 72 73 if err := json.Unmarshal(data, &in); err != nil { 74 return err 75 } 76 77 m.Resources = in.Resources 78 seen := sets.New[string]() 79 // Process resources. 80 for i, r := range m.Resources { 81 if r.Validate == "" { 82 validateFn := "Validate" + asResourceVariableName(r.Kind) 83 if !validation.IsValidateFunc(validateFn) { 84 validateFn = "validation.EmptyValidate" 85 } else { 86 if r.Kind == "EnvoyFilter" { 87 validateFn = "envoyfilter." + validateFn 88 } else { 89 validateFn = "validation." + validateFn 90 } 91 } 92 m.Resources[i].Validate = validateFn 93 } 94 if r.Identifier == "" { 95 r.Identifier = r.Kind 96 } 97 if seen.InsertContains(r.Identifier) { 98 return fmt.Errorf("identifier %q already registered, set a unique identifier", r.Identifier) 99 } 100 } 101 102 return nil 103 } 104 105 // Parse and return a yaml representation of Metadata 106 func Parse(yamlText string) (*Metadata, error) { 107 var s Metadata 108 err := yaml.Unmarshal([]byte(yamlText), &s) 109 if err != nil { 110 return nil, err 111 } 112 return &s, nil 113 } 114 115 func asResourceVariableName(n string) string { 116 return strcase.CamelCase(n) 117 }