istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/config/schema/codegen/common.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 codegen
    16  
    17  import (
    18  	"bytes"
    19  	"errors"
    20  	"fmt"
    21  	"os"
    22  	"os/exec"
    23  	"path/filepath"
    24  	"sort"
    25  	"strings"
    26  	"text/template"
    27  
    28  	"istio.io/istio/pilot/pkg/features"
    29  	"istio.io/istio/pkg/config/schema/ast"
    30  	"istio.io/istio/pkg/test/env"
    31  )
    32  
    33  func Run() error {
    34  	inp, err := buildInputs()
    35  	if err != nil {
    36  		return err
    37  	}
    38  
    39  	// Include synthetic types used for XDS pushes
    40  	kindEntries := append([]colEntry{
    41  		{
    42  			Resource: &ast.Resource{Identifier: "Address", Kind: "Address", Version: "internal", Group: "internal"},
    43  		},
    44  		{
    45  			Resource: &ast.Resource{Identifier: "DNSName", Kind: "DNSName", Version: "internal", Group: "internal"},
    46  		},
    47  	}, inp.Entries...)
    48  
    49  	sort.Slice(kindEntries, func(i, j int) bool {
    50  		return strings.Compare(kindEntries[i].Resource.Identifier, kindEntries[j].Resource.Identifier) < 0
    51  	})
    52  
    53  	// filter to only types agent needs (to keep binary small)
    54  	agentEntries := []colEntry{}
    55  	for _, e := range inp.Entries {
    56  		if strings.Contains(e.Resource.ProtoPackage, "istio.io") &&
    57  			e.Resource.Kind != "EnvoyFilter" {
    58  			agentEntries = append(agentEntries, e)
    59  		}
    60  	}
    61  
    62  	// add MCS types
    63  	gvrEntries := append([]colEntry{
    64  		{Resource: &ast.Resource{Identifier: "ServiceExport", Plural: "serviceexports", Version: features.MCSAPIVersion, Group: features.MCSAPIGroup}},
    65  		{Resource: &ast.Resource{Identifier: "ServiceImport", Plural: "serviceimports", Version: features.MCSAPIVersion, Group: features.MCSAPIGroup}},
    66  	}, inp.Entries...)
    67  
    68  	return errors.Join(
    69  		writeTemplate("pkg/config/schema/gvk/resources.gen.go", gvkTemplate, map[string]any{
    70  			"Entries":     inp.Entries,
    71  			"PackageName": "gvk",
    72  		}),
    73  		writeTemplate("pkg/config/schema/gvr/resources.gen.go", gvrTemplate, map[string]any{
    74  			"Entries":     gvrEntries,
    75  			"PackageName": "gvr",
    76  		}),
    77  		writeTemplate("pilot/pkg/config/kube/crdclient/types.gen.go", crdclientTemplate, map[string]any{
    78  			"Entries":     inp.Entries,
    79  			"Packages":    inp.Packages,
    80  			"PackageName": "crdclient",
    81  		}),
    82  		writeTemplate("pkg/config/schema/kubetypes/resources.gen.go", typesTemplate, map[string]any{
    83  			"Entries":     inp.Entries,
    84  			"Packages":    inp.Packages,
    85  			"PackageName": "kubetypes",
    86  		}),
    87  		writeTemplate("pkg/config/schema/kubeclient/resources.gen.go", clientsTemplate, map[string]any{
    88  			"Entries":     inp.Entries,
    89  			"Packages":    inp.Packages,
    90  			"PackageName": "kubeclient",
    91  		}),
    92  		writeTemplate("pilot/pkg/config/kube/crdclient/types.gen.go", crdclientTemplate, map[string]any{
    93  			"Entries":     inp.Entries,
    94  			"Packages":    inp.Packages,
    95  			"PackageName": "crdclient",
    96  		}),
    97  		writeTemplate("pkg/config/schema/kind/resources.gen.go", kindTemplate, map[string]any{
    98  			"Entries":     kindEntries,
    99  			"PackageName": "kind",
   100  		}),
   101  		writeTemplate("pkg/config/schema/collections/collections.gen.go", collectionsTemplate, map[string]any{
   102  			"Entries":      inp.Entries,
   103  			"Packages":     inp.Packages,
   104  			"PackageName":  "collections",
   105  			"FilePrefix":   "// +build !agent",
   106  			"CustomImport": `  "istio.io/istio/pkg/config/validation/envoyfilter"`,
   107  		}),
   108  		writeTemplate("pkg/config/schema/collections/collections.agent.gen.go", collectionsTemplate, map[string]any{
   109  			"Entries":      agentEntries,
   110  			"Packages":     inp.Packages,
   111  			"PackageName":  "collections",
   112  			"FilePrefix":   "// +build agent",
   113  			"CustomImport": "",
   114  		}),
   115  	)
   116  }
   117  
   118  func writeTemplate(path, tmpl string, i any) error {
   119  	t, err := applyTemplate(tmpl, i)
   120  	if err != nil {
   121  		return fmt.Errorf("apply template %v: %v", path, err)
   122  	}
   123  	dst := filepath.Join(env.IstioSrc, path)
   124  	if err = os.WriteFile(dst, []byte(t), os.ModePerm); err != nil {
   125  		return fmt.Errorf("write template %v: %v", path, err)
   126  	}
   127  	c := exec.Command("goimports", "-w", "-local", "istio.io", dst)
   128  	c.Stdout = os.Stdout
   129  	c.Stderr = os.Stderr
   130  	return c.Run()
   131  }
   132  
   133  func applyTemplate(tmpl string, i any) (string, error) {
   134  	t := template.New("tmpl").Funcs(template.FuncMap{
   135  		"contains": strings.Contains,
   136  	})
   137  
   138  	t2 := template.Must(t.Parse(tmpl))
   139  
   140  	var b bytes.Buffer
   141  	if err := t2.Execute(&b, i); err != nil {
   142  		return "", err
   143  	}
   144  
   145  	return b.String(), nil
   146  }