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  }