From 2552f371637fb6eedd6bb120bd0de3508c64d775 Mon Sep 17 00:00:00 2001 From: Nicholas Eberts Date: Tue, 8 Oct 2024 09:38:35 -0400 Subject: [PATCH] Massive overhaul (#181) * massive overhaul --- cli/cmd/apply.go | 55 +- cli/cmd/connect.go | 48 + cli/cmd/delete.go | 9 +- cli/cmd/init.go | 2 +- cli/cmd/root.go | 16 +- cli/go.mod | 99 +- cli/go.sum | 126 +- cli/pkg/analytics/client.go | 36 +- cli/pkg/cli_init/cluster_build/main.tf | 216 -- cli/pkg/cli_init/clusters/main.tf | 124 + cli/pkg/cli_init/fleet/main.tf | 94 + cli/pkg/cli_init/init.go | 12 +- .../cli_init/{shared_vpc => network}/main.tf | 13 +- cli/pkg/cli_init/samples/default-config.yaml | 54 +- cli/pkg/cli_init/samples/fleet-full.yaml | 52 + .../cli_init/samples/fleet-shared-vpc.yaml | 52 + .../cli_init/templates/cluster_config.tmpl | 1 - .../cli_init/templates/gateway_api_crds.yaml | 3328 ----------------- .../cli_init/templates/terraform.tfvars.tmpl | 35 +- cli/pkg/config/config.go | 245 +- cli/pkg/config/tf_state.go | 33 +- cli/pkg/config/tfvars_generator.go | 25 +- cli/pkg/lifecycle/get_credentials.go | 128 + cli/pkg/lifecycle/kubernetes_helpers.go | 176 - cli/pkg/lifecycle/tf_delete.go | 5 +- cli/pkg/lifecycle/tf_deploy.go | 9 +- terraform/modules/acm/acm.tf | 109 - terraform/modules/asm/asm.tf | 44 - .../manifests/asm-control-plane-revision.yaml | 10 - .../modules/asm/manifests/asm-options.yaml | 13 - ...lusterole-istio-reader-sa-clusterrole.yaml | 27 - ...ng-istio-reader-sa-clusterrolebinding.yaml | 15 - .../asm/manifests/istio-system-ns.yaml | 5 - .../asm/manifests/ksa-istio-reader-sa.yaml | 5 - terraform/modules/asm/scripts/install_mesh.sh | 35 - terraform/modules/cluster_build/cluster.tf | 103 - terraform/modules/cluster_build/logging.tf | 77 - terraform/modules/cluster_build/main.tf | 306 -- terraform/modules/clusters/clusters.tf | 93 + terraform/modules/clusters/main.tf | 119 + .../{cluster_build => clusters}/outputs.tf | 12 +- .../{cluster_build => clusters}/provider.tf | 13 +- .../{cluster_build => clusters}/variables.tf | 96 +- terraform/modules/fleet/admin-cluster.tf | 127 + terraform/modules/fleet/feature-defaults.tf | 163 + .../{cluster_build/rbac.tf => fleet/main.tf} | 29 +- terraform/modules/fleet/mcg.tf | 121 + terraform/modules/fleet/outputs.tf | 19 + terraform/modules/fleet/provider.tf | 42 + terraform/modules/fleet/services.tf | 42 + terraform/modules/fleet/variables.tf | 93 + terraform/modules/gke/gke.tf | 122 - terraform/modules/gke/variables.tf | 122 - terraform/modules/gke_module/gke_module.tf | 53 - terraform/modules/gke_module/variables.tf | 104 - terraform/modules/hub/hub.tf | 36 - terraform/modules/mcg/mcg.tf | 127 - terraform/modules/mcg/scripts/install_crds.sh | 23 - .../modules/{shared_vpc => network}/main.tf | 47 +- .../{cluster_build => network}/network.tf | 30 +- .../{shared_vpc => network}/provider.tf | 11 +- .../attach-vpc.tf => network/shared_vpc.tf} | 30 +- .../{shared_vpc => network}/variables.tf | 6 + terraform/modules/shared_vpc/network.tf | 40 - terraform/modules/shared_vpc/outputs.tf | 0 terraform/modules/windows_nodepool/main.tf | 94 - 66 files changed, 1894 insertions(+), 5662 deletions(-) create mode 100644 cli/cmd/connect.go delete mode 100644 cli/pkg/cli_init/cluster_build/main.tf create mode 100644 cli/pkg/cli_init/clusters/main.tf create mode 100644 cli/pkg/cli_init/fleet/main.tf rename cli/pkg/cli_init/{shared_vpc => network}/main.tf (82%) create mode 100644 cli/pkg/cli_init/samples/fleet-full.yaml create mode 100644 cli/pkg/cli_init/samples/fleet-shared-vpc.yaml delete mode 100644 cli/pkg/cli_init/templates/gateway_api_crds.yaml create mode 100644 cli/pkg/lifecycle/get_credentials.go delete mode 100644 cli/pkg/lifecycle/kubernetes_helpers.go delete mode 100644 terraform/modules/acm/acm.tf delete mode 100644 terraform/modules/asm/asm.tf delete mode 100644 terraform/modules/asm/manifests/asm-control-plane-revision.yaml delete mode 100644 terraform/modules/asm/manifests/asm-options.yaml delete mode 100644 terraform/modules/asm/manifests/clusterole-istio-reader-sa-clusterrole.yaml delete mode 100644 terraform/modules/asm/manifests/clusterolebinding-istio-reader-sa-clusterrolebinding.yaml delete mode 100644 terraform/modules/asm/manifests/istio-system-ns.yaml delete mode 100644 terraform/modules/asm/manifests/ksa-istio-reader-sa.yaml delete mode 100755 terraform/modules/asm/scripts/install_mesh.sh delete mode 100644 terraform/modules/cluster_build/cluster.tf delete mode 100644 terraform/modules/cluster_build/logging.tf delete mode 100644 terraform/modules/cluster_build/main.tf create mode 100644 terraform/modules/clusters/clusters.tf create mode 100644 terraform/modules/clusters/main.tf rename terraform/modules/{cluster_build => clusters}/outputs.tf (61%) rename terraform/modules/{cluster_build => clusters}/provider.tf (74%) rename terraform/modules/{cluster_build => clusters}/variables.tf (56%) create mode 100644 terraform/modules/fleet/admin-cluster.tf create mode 100644 terraform/modules/fleet/feature-defaults.tf rename terraform/modules/{cluster_build/rbac.tf => fleet/main.tf} (53%) create mode 100644 terraform/modules/fleet/mcg.tf create mode 100644 terraform/modules/fleet/outputs.tf create mode 100644 terraform/modules/fleet/provider.tf create mode 100644 terraform/modules/fleet/services.tf create mode 100644 terraform/modules/fleet/variables.tf delete mode 100644 terraform/modules/gke/gke.tf delete mode 100644 terraform/modules/gke/variables.tf delete mode 100644 terraform/modules/gke_module/gke_module.tf delete mode 100644 terraform/modules/gke_module/variables.tf delete mode 100644 terraform/modules/hub/hub.tf delete mode 100644 terraform/modules/mcg/mcg.tf delete mode 100755 terraform/modules/mcg/scripts/install_crds.sh rename terraform/modules/{shared_vpc => network}/main.tf (67%) rename terraform/modules/{cluster_build => network}/network.tf (72%) rename terraform/modules/{shared_vpc => network}/provider.tf (81%) rename terraform/modules/{shared_vpc/attach-vpc.tf => network/shared_vpc.tf} (67%) rename terraform/modules/{shared_vpc => network}/variables.tf (91%) delete mode 100644 terraform/modules/shared_vpc/network.tf delete mode 100644 terraform/modules/shared_vpc/outputs.tf delete mode 100644 terraform/modules/windows_nodepool/main.tf diff --git a/cli/cmd/apply.go b/cli/cmd/apply.go index 0a5f56a6..2db1a1c3 100644 --- a/cli/cmd/apply.go +++ b/cli/cmd/apply.go @@ -30,8 +30,23 @@ var applyCmd = &cobra.Command{ Use: "apply", Short: "Create or Update GKE Demo Environment", Example: ` gkekitctl apply - gkekitctl apply --config `, + gkekitctl apply --config + gkekitctl apply --config -g -v -f `, Run: func(cmd *cobra.Command, args []string) { + bucketNameNetwork, err := cmd.Flags().GetString("vpcstate") + if err != nil { + log.Errorf("🚨Failed to get bucketNameSharedVPC value from flag: %s", err) + } + if bucketNameNetwork != "" { + log.Infof("✅ Terraform state storage bucket for shared VPC is %s", bucketNameNetwork) + } + bucketNameFleet, err := cmd.Flags().GetString("fleetstate") + if err != nil { + log.Errorf("🚨Failed to get bucketNameFleet value from flag: %s", err) + } + if bucketNameFleet != "" { + log.Infof("✅ Terraform state storage bucket for Fleet is %s", bucketNameFleet) + } bucketNameClusters, err := cmd.Flags().GetString("gkestate") if err != nil { log.Errorf("🚨Failed to get bucketNameClusters value from flag: %s", err) @@ -39,13 +54,6 @@ var applyCmd = &cobra.Command{ if bucketNameClusters != "" { log.Infof("✅ Terraform state storage bucket for clusters is %s", bucketNameClusters) } - bucketNameSharedVPC, err := cmd.Flags().GetString("vpcstate") - if err != nil { - log.Errorf("🚨Failed to get bucketNameSharedVPC value from flag: %s", err) - } - if bucketNameSharedVPC != "" { - log.Infof("✅ Terraform state storage bucket for shared VPC is %s", bucketNameSharedVPC) - } log.Info("👟 Started config validation...") conf := config.InitConf(cfgFile) @@ -59,7 +67,7 @@ var applyCmd = &cobra.Command{ config.GenerateTfvars(conf) log.Info("👟 Started configuring TF State...") - err = config.CheckTfStateType(conf, bucketNameClusters, bucketNameSharedVPC) + err = config.CheckTfStateType(conf, bucketNameNetwork, bucketNameFleet, bucketNameClusters) if err != nil { log.Errorf("🚨 Failed setting up TF state: %s", err) @@ -67,38 +75,31 @@ var applyCmd = &cobra.Command{ log.Info("✅ TF state configured successfully.") } - if conf.VpcConfig.VpcType == "shared" { - lifecycle.InitTF("shared_vpc") - lifecycle.ApplyTF("shared_vpc") - } - lifecycle.InitTF("cluster_build") - lifecycle.ApplyTF("cluster_build") + lifecycle.InitTF("network") + lifecycle.ApplyTF("network") + lifecycle.InitTF("fleet") + lifecycle.ApplyTF("fleet") + lifecycle.InitTF("clusters") + lifecycle.ApplyTF("clusters") // Authenticate Kubernetes client-go to all clusters log.Info("☸️ Generating Kubeconfig...") - kc, err := lifecycle.GenerateKubeConfig(conf) + kc, err := lifecycle.GenerateKubeConfig(conf.FleetProjectID) if err != nil { log.Errorf("🚨 Failed to generate kube config: %s", err) } else { log.Infof("✅ Kubeconfig generated: %+v", kc) } - - // Verify access to Kubernetes API on all clusters - log.Info("☸️ Verifying Kubernetes API access for all clusters...") - err = lifecycle.ListNamespaces(kc) - if err != nil { - log.Errorf("🚨 Failed API access check on clusters: %s", err) - } else { - log.Info("✅ Clusters API access check passed.") - } }, } func init() { var bucketNameClusters string - var bucketNameSharedVPC string + var bucketNameNetwork string + var bucketNameFleet string rootCmd.AddCommand(applyCmd) applyCmd.Flags().StringVarP(&bucketNameClusters, "gkestate", "g", "", "GKE Tf State bucket name") - applyCmd.Flags().StringVarP(&bucketNameSharedVPC, "vpcstate", "v", "", "Shared VPC Tf State bucket name") + applyCmd.Flags().StringVarP(&bucketNameNetwork, "vpcstate", "v", "", "Network Tf State bucket name") + applyCmd.Flags().StringVarP(&bucketNameFleet, "fleetstate", "f", "", "Fleet Tf State bucket name") } diff --git a/cli/cmd/connect.go b/cli/cmd/connect.go new file mode 100644 index 00000000..803b1659 --- /dev/null +++ b/cli/cmd/connect.go @@ -0,0 +1,48 @@ +/* +Copyright © 2020 Google Inc. + +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 cmd + +import ( + "gkekitctl/pkg/lifecycle" + + log "github.com/sirupsen/logrus" + + "github.com/spf13/cobra" +) + +// connectCmd represents the connect command +var connectCmd = &cobra.Command{ + Use: "connect", + Short: "connect for all clusters in GKE Demo Environment", + Example: ` gkekitctl connect -p `, + + Run: func(cmd *cobra.Command, args []string) { + log.Println("Getting credentials...") + // conf := config.InitConf(cfgFile) + + log.Info("☸️ Generating Kubeconfig...") + kc, err := lifecycle.GenerateKubeConfig(fleetProjectId) + if err != nil { + log.Errorf("🚨 Failed to generate kube config: %s", err) + } else { + log.Infof("✅ Kubeconfig generated: %+v", kc) + } + }, +} + +func init() { + rootCmd.AddCommand(connectCmd) +} diff --git a/cli/cmd/delete.go b/cli/cmd/delete.go index 4fb1fc82..10cc39bf 100644 --- a/cli/cmd/delete.go +++ b/cli/cmd/delete.go @@ -16,7 +16,6 @@ limitations under the License. package cmd import ( - "gkekitctl/pkg/config" "gkekitctl/pkg/lifecycle" log "github.com/sirupsen/logrus" @@ -32,11 +31,9 @@ var deleteCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { log.Println("Starting delete...") - conf := config.InitConf(cfgFile) - if conf.VpcConfig.VpcType == "shared" { - lifecycle.DestroyTF("shared_vpc") - } - lifecycle.DestroyTF("cluster_build") + lifecycle.DestroyTF("clusters") + lifecycle.DestroyTF("fleet") + lifecycle.DestroyTF("network") }, } diff --git a/cli/cmd/init.go b/cli/cmd/init.go index b84a8ca7..f45197d1 100644 --- a/cli/cmd/init.go +++ b/cli/cmd/init.go @@ -28,7 +28,7 @@ var initCmd = &cobra.Command{ Short: "Initialize local environment for the cli", Example: ` gkekitctl init`, Run: func(cmd *cobra.Command, args []string) { - folders := []string{"samples", "templates", "cluster_build", "shared_vpc"} + folders := []string{"samples", "templates", "clusters", "network", "fleet"} err := cli_init.InitFlatFiles(folders) if err != nil { log.Errorf("🚨 Failed to initialize gkekitctl: %v", err) diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 97e10f1a..b8ddd242 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -23,6 +23,7 @@ import ( ) var cfgFile string +var fleetProjectId string var ( Version string @@ -37,15 +38,6 @@ var rootCmd = &cobra.Command{ Example: ` gkekitctl create gkectl create --config gkekitctl delete`, - - // Uncomment the following line if your bare application - // has an action associated with it: - // Run: func(cmd *cobra.Command, args []string) { - // out := cmd.OutOrStdout() - - // fmt.Fprintln(out, "Terraform state will be stored:", viper.GetString("terraformState")) - // fmt.Fprintln(out, conf.ConfigSync) - // }, } // Execute adds all child commands to the root command and sets flags appropriately. @@ -62,6 +54,7 @@ func init() { // will be global for your application. rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file (default is /.gkekitctl.yaml)") + rootCmd.PersistentFlags().StringVarP(&fleetProjectId, "fleet-project-id", "p", "", "Fleet project ID") // Cobra also supports local flags, which will only run // when this action is called directly. @@ -77,11 +70,6 @@ func initConfig() { // Use config file from the flag. viper.SetConfigFile(cfgFile) } else { - // Find home directory. - // home, err := os.UserHomeDir() - // cobra.CheckErr(err) - - // Search config in home directory with name ".gkekitctl" (without extension). viper.AddConfigPath(".") viper.SetConfigType("yaml") viper.SetConfigName(".gkekitctl") diff --git a/cli/go.mod b/cli/go.mod index 87495edb..32615c7a 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -1,21 +1,106 @@ module gkekitctl -go 1.16 +go 1.22 require ( - cloud.google.com/go/compute v1.10.0 - cloud.google.com/go/serviceusage v1.0.0 - cloud.google.com/go/storage v1.27.0 + cloud.google.com/go/compute v1.28.1 + cloud.google.com/go/serviceusage v1.9.1 + cloud.google.com/go/storage v1.43.0 github.com/gofrs/uuid v4.1.0+incompatible - github.com/hashicorp/go-getter v1.7.1 // indirect github.com/hashicorp/terraform-exec v0.15.0 github.com/manifoldco/promptui v0.9.0 github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.2.1 github.com/spf13/viper v1.9.0 github.com/thanhpk/randstr v1.0.4 - google.golang.org/api v0.100.0 - google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71 + google.golang.org/api v0.196.0 + google.golang.org/genproto v0.0.0-20240924160255-9d4c2d233b61 + google.golang.org/genproto/googleapis/api/serviceusage v0.0.0-20240930140551-af27646dc61f k8s.io/apimachinery v0.22.4 k8s.io/client-go v0.22.4 ) + +require ( + cloud.google.com/go/auth v0.9.3 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect + cloud.google.com/go/compute/metadata v0.5.0 // indirect + cloud.google.com/go/longrunning v0.6.1 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/s2a-go v0.1.8 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/otel v1.29.0 // indirect + go.opentelemetry.io/otel/metric v1.29.0 // indirect + go.opentelemetry.io/otel/trace v1.29.0 // indirect + golang.org/x/sync v0.8.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect +) + +require ( + cloud.google.com/go v0.115.1 // indirect + cloud.google.com/go/gkeconnect v0.11.1 + cloud.google.com/go/iam v1.2.1 // indirect + github.com/aws/aws-sdk-go v1.44.122 // indirect + github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect + github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.3 // indirect + github.com/googleapis/gax-go/v2 v2.13.0 // indirect + github.com/googleapis/gnostic v0.5.5 // indirect + github.com/hashicorp/go-checkpoint v0.5.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-getter v1.7.1 // indirect + github.com/hashicorp/go-safetemp v1.0.0 // indirect + github.com/hashicorp/go-uuid v1.0.1 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hashicorp/terraform-json v0.13.0 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/json-iterator/go v1.1.11 // indirect + github.com/klauspost/compress v1.15.11 // indirect + github.com/magiconair/properties v1.8.5 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.4.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/pelletier/go-toml v1.9.4 // indirect + github.com/spf13/afero v1.6.0 // indirect + github.com/spf13/cast v1.4.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + github.com/ulikunitz/xz v0.5.10 // indirect + github.com/zclconf/go-cty v1.9.1 // indirect + go.opencensus.io v0.24.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/term v0.24.0 // indirect + golang.org/x/text v0.18.0 // indirect + golang.org/x/time v0.6.0 // indirect + google.golang.org/grpc v1.67.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.63.2 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.22.4 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect + sigs.k8s.io/yaml v1.2.0 // indirect +) diff --git a/cli/go.sum b/cli/go.sum index b33bfeab..5f9a0aff 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -29,8 +29,9 @@ cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2Z cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= -cloud.google.com/go v0.104.0 h1:gSmWO7DY1vOm0MVU6DNXM11BWHHsTUmsC5cv1fuW5X8= cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ= +cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc= cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= @@ -45,6 +46,10 @@ cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjby cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/auth v0.9.3 h1:VOEUIAADkkLtyfr3BLa3R8Ed/j6w1jTBmARx+wb5w5U= +cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk= +cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= +cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= @@ -66,8 +71,11 @@ cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6m cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0 h1:aoLIYaA1fX3ywihqpBk2APQKOo20nXsp1GEZQbx5Jk4= cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.28.1 h1:XwPcZjgMCnU2tkwY10VleUjSAfpTj9RDn+kGrbYsi8o= +cloud.google.com/go/compute v1.28.1/go.mod h1:b72iXMY4FucVry3NR3Li4kVyyTvbMDE7x5WsqvxjsYk= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= @@ -102,16 +110,21 @@ cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFP cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkeconnect v0.11.1 h1:X7UpDP2Qg8JfaQ6vsJeFsTo4NcrGprk9Tg4Pf7MK8Qg= +cloud.google.com/go/gkeconnect v0.11.1/go.mod h1:Vu3UoOI2c0amGyv4dT/EmltzscPH41pzS4AXPqQLej0= cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.5.0 h1:fz9X5zyTWBmamZsqvqZqD7khbifcZF/q+Z1J8pfhIUg= cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v1.2.1 h1:QFct02HRb7H12J/3utj0qf5tobFh9V4vR6h9eX5EBRU= +cloud.google.com/go/iam v1.2.1/go.mod h1:3VUIJDPpwT6p/amXRC5GY8fCCh70lxPygguVtI0Z4/g= cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/longrunning v0.6.1 h1:lOLTFxYpr8hcRtcwWir5ITh1PAKUD/sG2lKrTSYjyMc= +cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0= cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= @@ -158,8 +171,8 @@ cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyW cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= -cloud.google.com/go/serviceusage v1.0.0 h1:4klLGhPwPtFvwz+pnTDvpzIDbu5sHbXG2c9bzjjIlYE= -cloud.google.com/go/serviceusage v1.0.0/go.mod h1:oeli61kBAOctA9KEEt2G6/v37wPyOkIWqvNQAChh8WU= +cloud.google.com/go/serviceusage v1.9.1 h1:vm8LfYTGh69ApgUYj/Mtpw/PTso+l5hfu7vS+ey1eOE= +cloud.google.com/go/serviceusage v1.9.1/go.mod h1:Y4zz7UCrgriikHOdm/Bgy4HCZQorm9OuBVNnciWndf8= cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= @@ -169,8 +182,9 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= -cloud.google.com/go/storage v1.27.0 h1:YOO045NZI9RKfCj1c5A/ZtuuENUc8OAW+gHdGnDgyMQ= cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= +cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= @@ -269,6 +283,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= @@ -290,8 +306,12 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= @@ -332,8 +352,9 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -352,8 +373,9 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -361,8 +383,9 @@ github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPg github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= +github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -378,14 +401,18 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbezB6QkpuE6jMD2/gfzk4AftXjs= github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.3.3 h1:QRje2j5GZimBzlbhGA2V2QlGNgL8G6e+wGo/+/2bWI0= +github.com/googleapis/enterprise-certificate-proxy v0.3.3/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -394,8 +421,9 @@ github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/Oth github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= -github.com/googleapis/gax-go/v2 v2.6.0 h1:SXk3ABtQYDT/OH8jAyvEOQ58mgawq5C4o/4/89qN2ZU= github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= +github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= @@ -600,13 +628,19 @@ github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhU github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo= @@ -638,8 +672,21 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= +go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= @@ -659,8 +706,9 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -752,8 +800,9 @@ golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -779,8 +828,9 @@ golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7Lm golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.1.0 h1:isLCZuhj4v+tYv7eskaN4v/TM+A1begWWgyVJDdl1+Y= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -795,6 +845,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -877,14 +929,16 @@ golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -894,13 +948,15 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -965,7 +1021,6 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -1015,15 +1070,15 @@ google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaE google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.100.0 h1:LGUYIrbW9pzYQQ8NWXlaIVkgnfubVBZbMFb9P8TK374= google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.196.0 h1:k/RafYqebaIJBO3+SMnfEGtFVlvp5vSgqTUF54UN/zg= +google.golang.org/api v0.196.0/go.mod h1:g9IL21uGkYgvQ5BZg6BAtoGJQIm8r6EgaAbpNey5wBE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1082,7 +1137,6 @@ google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEc google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= @@ -1127,8 +1181,15 @@ google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53B google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71 h1:GEgb2jF5zxsFJpJfg9RoDDWm7tiwc/DDSTE2BtLUkXU= google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20240924160255-9d4c2d233b61 h1:KipVMxePgXPFBzXOvpKbny3RVdVmJOD64R/Ob7GPWEs= +google.golang.org/genproto v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:HiAZQz/G7n0EywFjmncAwsfnmFm2bjm7qPjwl8hyzjM= +google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61 h1:pAjq8XSSzXoP9ya73v/w+9QEAAJNluLrpmMq5qFJQNY= +google.golang.org/genproto/googleapis/api v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:O6rP0uBq4k0mdi/b4ZEMAZjkhYWhS815kCvaMha4VN8= +google.golang.org/genproto/googleapis/api/serviceusage v0.0.0-20240930140551-af27646dc61f h1:O3cvN+Oj2VaNHI9Y3IYPnez4F/ZF/oyAJ3ttcNbc1gI= +google.golang.org/genproto/googleapis/api/serviceusage v0.0.0-20240930140551-af27646dc61f/go.mod h1:ps1+WYbWKIeXnZltLGfa/W+nEnyDlhKE9cZhXxo0E/g= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1163,8 +1224,9 @@ google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= +google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1180,8 +1242,9 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1209,8 +1272,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1228,6 +1292,8 @@ k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8 k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= diff --git a/cli/pkg/analytics/client.go b/cli/pkg/analytics/client.go index 5521cf40..7038e741 100644 --- a/cli/pkg/analytics/client.go +++ b/cli/pkg/analytics/client.go @@ -81,27 +81,21 @@ func SendAnalytics(conf *config.Config, version string, gitCommit string) { // Create Cluster Object, omitting any user-identified data (Project IDs) // NOTE - ClusterId and CreateId are generated server-side before DB insert to avoid HTTP POST anti-patterns sendObject := Cluster{ - ClusterId: clusterId.String(), - CreateId: createId.String(), - Version: version, - GitCommit: gitCommit, - Timestamp: timestamp, - OS: runtime.GOOS, - TerraformState: conf.TerraformState, - Region: conf.Region, - EnablePreemptibleNodepool: conf.EnablePreemptibleNodepool, - DefaultNodepoolOS: conf.DefaultNodepoolOS, - PrivateEndpoint: conf.PrivateEndpoint, - EnableConfigSync: conf.ConfigSync, - EnablePolicyController: conf.PolicyController, - AnthosServiceMesh: conf.AnthosServiceMesh, - MultiClusterGateway: conf.MultiClusterGateway, - VPCType: conf.VpcConfig.VpcType, - ClusterIndex: i, - ClusterType: cluster.ClusterType, - ClusterMachineType: cluster.MachineType, - ClusterRegion: cluster.Region, - ClusterZones: cluster.Zones, + ClusterId: clusterId.String(), + CreateId: createId.String(), + Version: version, + GitCommit: gitCommit, + Timestamp: timestamp, + OS: runtime.GOOS, + TerraformState: conf.TerraformState, + DefaultNodepoolOS: conf.DefaultNodepoolOS, + PrivateEndpoint: conf.PrivateEndpoint, + VPCType: conf.VpcConfig.VpcType, + ClusterIndex: i, + ClusterType: cluster.ClusterType, + ClusterMachineType: cluster.MachineType, + ClusterRegion: cluster.Region, + ClusterZones: cluster.Zones, } // Encode as JSON json, err := json.Marshal(sendObject) diff --git a/cli/pkg/cli_init/cluster_build/main.tf b/cli/pkg/cli_init/cluster_build/main.tf deleted file mode 100644 index 95e34357..00000000 --- a/cli/pkg/cli_init/cluster_build/main.tf +++ /dev/null @@ -1,216 +0,0 @@ -module "cluster_build" { - source = "{{.TFModuleRepo}}cluster_build?ref={{.TFModuleBranch}}" - project_id = var.project_id - governance_project_id = var.governance_project_id - regional_clusters = var.regional_clusters - region = var.region - zones = var.zones - shared_vpc = var.shared_vpc - vpc_name = var.vpc_name - ip_range_pods_name = var.ip_range_pods_name - vpc_project_id = var.vpc_project_id - vpc_ip_range_pods_name = var.vpc_ip_range_pods_name - vpc_ip_range_services_name = var.vpc_ip_range_services_name - node_pool = var.node_pool - release_channel = var.release_channel - initial_node_count = var.initial_node_count - min_node_count = var.min_node_count - max_node_count = var.max_node_count - linux_machine_type = var.linux_machine_type - windows_machine_type = var.windows_machine_type - private_endpoint = var.private_endpoint - auth_cidr = var.auth_cidr - config_sync = var.config_sync - config_sync_repo = var.config_sync_repo - policy_controller = var.policy_controller - config_connector = var.config_connector - windows_nodepool = var.windows_nodepool - preemptible_nodes = var.preemptible_nodes - cluster_config = var.cluster_config - k8s_users = var.k8s_users - multi_cluster_gateway = var.multi_cluster_gateway - anthos_service_mesh = var.anthos_service_mesh - gke_module_bypass = var.gke_module_bypass -} - -variable "project_id" { - type = string - description = "The project ID to host the cluster in" -} - -variable "governance_project_id" { - type = string - description = "The project ID to host governance resources" -} - -variable "regional_clusters" { - type = bool - description = "Enable regional control plane." - default = true -} - -variable "region" { - type = string - description = "The region to host the cluster in" - default = "us-central1" -} - -variable "zones" { - type = list(string) - description = "The zones used in your nodepool" - default = ["us-central1-b"] -} - -variable "shared_vpc" { - type = bool - description = "boolean value for determining whether to create Standalone VPC or use a preexisting Shared VPC" - default = false -} - -variable "vpc_name" { - type = string - description = "The name of the network being created to host the cluster in" - default = "gke-toolkit-network" -} - -variable "ip_range_pods_name" { - type = string - description = "The secondary ip range to use for pods" - default = "ip-range-pods" -} - -variable "ip_range_services_name" { - type = string - description = "The secondary ip range to use for pods" - default = "ip-range-svc" -} - -variable "vpc_project_id" { - type = string - description = "The Share VPC Project ID - This is optional and only valid if a Shared VPC is used" - default = "" -} - -variable "vpc_ip_range_pods_name" { - type = string - description = "The secondary ip range to use for pods in the shared vpc - This is optional and only valid if a Shared VPC is used" - default = "" -} - -variable "vpc_ip_range_services_name" { - type = string - description = "The secondary ip range to use for services in the shared vpc - This is optional and only valid if a Shared VPC is used" - default = "" -} - -variable "node_pool" { - type = string - default = "gke-toolkit-pool" -} - -variable "release_channel" { - type = string - default = "regular" -} - -variable "initial_node_count" { - type = number - default = 1 -} - -variable "min_node_count" { - type = number - default = 1 -} - -variable "max_node_count" { - type = number - default = 10 -} - -variable "linux_machine_type" { - type = string - default = "n1-standard-2" -} - -variable "windows_machine_type" { - type = string - default = "n1-standard-4" -} - -variable "private_endpoint" { - type = bool - default = false -} - -# Need this default to run PR build test -variable "auth_cidr" { - type = string - default = "1.2.3.4/0" -} - -variable "config_sync" { - type = bool - description = "Enable Config Sync on all clusters." - default = true -} - -variable "config_sync_repo" { - type = string - description = "Name of Cloud Source Repo for Config Sync" - default = "gke-poc-config-sync" -} - -variable "policy_controller" { - type = bool - description = "Enable Policy Controller on all clusters." - default = true -} - -variable "config_connector" { - type = bool - description = "(Beta) Whether ConfigConnector is enabled for this cluster." - default = false -} - -variable "windows_nodepool" { - type = bool - default = false -} - -variable "preemptible_nodes" { - type = bool - description = "Whether underlying node GCE instances are preemptible" - default = true -} - -variable "cluster_config" { - description = "For each cluster, create an object that contain the required fields" - default = {} -} - -variable "k8s_users" { - type = map(string) - default = { - rbac-demo-auditor = "view" - rbac-demo-editor = "edit" - } -} - -variable "multi_cluster_gateway" { - type = bool - description = "Enable Multi-cluster gateway on all clusters." - default = true -} - -variable "anthos_service_mesh" { - type = bool - description = "Enable Anthos Service Mesh on all clusters." - default = true -} - - variable "gke_module_bypass" { - type = bool - description = "Experimental: Setting this to true allows you to use the TF GKE resource directly instead of the GKE module" - default = false - } \ No newline at end of file diff --git a/cli/pkg/cli_init/clusters/main.tf b/cli/pkg/cli_init/clusters/main.tf new file mode 100644 index 00000000..b262988c --- /dev/null +++ b/cli/pkg/cli_init/clusters/main.tf @@ -0,0 +1,124 @@ +module "clusters" { + source = "{{.TFModuleRepo}}clusters?ref={{.TFModuleBranch}}" + project_id = var.project_id + fleet_project = var.fleet_project + regional_clusters = var.regional_clusters + shared_vpc = var.shared_vpc + vpc_name = var.vpc_name + vpc_project_id = var.vpc_project_id + vpc_ip_range_pods_name = var.vpc_ip_range_pods_name + vpc_ip_range_services_name = var.vpc_ip_range_services_name + release_channel = var.release_channel + initial_node_count = var.initial_node_count + min_node_count = var.min_node_count + max_node_count = var.max_node_count + linux_machine_type = var.linux_machine_type + private_endpoint = var.private_endpoint + authenticator_security_group = var.authenticator_security_group + cluster_config = var.cluster_config +} + +variable "project_id" { + type = string + description = "The project ID to host the cluster in" +} + +variable "fleet_project" { + description = "(Optional) Register the cluster with the fleet in this project." + type = string + default = null +} + +variable "regional_clusters" { + type = bool + description = "Enable regional control plane." + default = true +} + +variable "region" { + type = string + description = "The region to host the cluster in" + default = "us-central1" +} + +variable "shared_vpc" { + type = bool + description = "boolean value for determining whether to create Standalone VPC or use a preexisting Shared VPC" + default = false +} + +variable "vpc_name" { + type = string + description = "The name of the network being created to host the cluster in" + default = "gke-toolkit-network" +} + + +variable "vpc_project_id" { + type = string + description = "The Share VPC Project ID - This is optional and only valid if a Shared VPC is used" + default = "" +} + +variable "vpc_ip_range_pods_name" { + type = string + description = "The secondary ip range to use for pods in the shared vpc - This is optional and only valid if a Shared VPC is used" + default = "" +} + +variable "vpc_ip_range_services_name" { + type = string + description = "The secondary ip range to use for services in the shared vpc - This is optional and only valid if a Shared VPC is used" + default = "" +} + +variable "release_channel" { + type = string + default = "regular" +} + +variable "node_pool" { + type = string + default = "gke-toolkit-pool" +} + +variable "initial_node_count" { + type = number + default = 4 +} + +variable "min_node_count" { + type = number + default = 4 +} + +variable "max_node_count" { + type = number + default = 10 +} + +variable "linux_machine_type" { + type = string + default = "n1-standard-4" +} + +variable "private_endpoint" { + type = bool + default = false +} + +variable "authenticator_security_group" { + type = string + description = "The name of the RBAC security group for use with Google security groups in Kubernetes RBAC. Group name must be in format gke-security-groups@yourdomain.com" + default = null +} + +variable "cluster_config" { + description = "For each cluster, create an object that contain the required fields" + default = {} +} + +variable "auth_cidr" { + type = string + default = "172.16.100.16/28" +} \ No newline at end of file diff --git a/cli/pkg/cli_init/fleet/main.tf b/cli/pkg/cli_init/fleet/main.tf new file mode 100644 index 00000000..1a9a2b65 --- /dev/null +++ b/cli/pkg/cli_init/fleet/main.tf @@ -0,0 +1,94 @@ +module "fleet" { + source = "{{.TFModuleRepo}}fleet?ref={{.TFModuleBranch}}" + project_id = var.project_id + fleet_project = var.fleet_project + config_sync_repo = var.config_sync_repo + config_sync_repo_branch = var.config_sync_repo_branch + config_sync_repo_dir = var.config_sync_repo_dir + vpc_name = var.vpc_name + vpc_project_id = var.vpc_project_id + release_channel = var.release_channel + authenticator_security_group = var.authenticator_security_group + cluster_config = var.cluster_config + shared_vpc = var.shared_vpc + vpc_ip_range_pods_name = var.vpc_ip_range_pods_name + vpc_ip_range_services_name = var.vpc_ip_range_services_name +} + +variable "project_id" { + type = string + description = "The project ID to host the cluster in" +} + +variable "fleet_project" { + type = string + description = "(Optional) Register the cluster with the fleet in this project." +} + +variable "vpc_project_id" { + type = string + description = "Shared VPC project needed for setting MCI and MCS RBAC." +} + +variable "config_sync_repo" { + description = "Git repo used as the default config sync repo for your fleet." + type = string + default = null +} + +variable "config_sync_repo_branch" { + description = "Git repo branch used as the default config sync repo for your fleet." + type = string + default = null +} + +variable "config_sync_repo_dir" { + description = "Git repo directory used as the default config sync repo for your fleet." + type = string + default = null +} + +variable "shared_vpc" { + type = bool + description = "Determines whether to create a standalone VPC or use an existing Shared VPC" + default = false +} + +variable "vpc_ip_range_pods_name" { + type = string + description = "The secondary IP range to use for pods in the shared VPC" + default = "" +} + +variable "vpc_ip_range_services_name" { + type = string + description = "The secondary IP range to use for services in the shared VPC" + default = "" +} + +variable "release_channel" { + type = string + description = "The release channel of the cluster" + default = "regular" +} + +variable "authenticator_security_group" { + type = string + description = "The name of the RBAC security group for use with Google security groups in Kubernetes RBAC." + default = null +} + +variable "vpc_name" { + type = string + description = "The name of the VPC - used for shared or local VPC" + default = "" +} + +variable "cluster_config" { + type = map(object({ + subnet_name = string + region = string + })) + description = "For each cluster, create an object that contains the required fields" + default = {} +} diff --git a/cli/pkg/cli_init/init.go b/cli/pkg/cli_init/init.go index 116fe8fe..dacd59d8 100644 --- a/cli/pkg/cli_init/init.go +++ b/cli/pkg/cli_init/init.go @@ -20,7 +20,6 @@ import ( "bytes" "embed" "fmt" - "io/ioutil" "os" "strings" @@ -32,7 +31,7 @@ import ( // embeding flatfiles and setting them as a file system variable, embed.FS. // embed.FS can be treated like io.FS. -//go:embed templates/* samples/* cluster_build/* shared_vpc/* +//go:embed templates/* samples/* clusters/* network/* fleet/* var templates embed.FS func InitFlatFiles(folders []string) error { @@ -56,7 +55,7 @@ func InitFlatFiles(folders []string) error { os.MkdirAll(folder, 0700) } buf.Write(b) - err = ioutil.WriteFile(folder+"/"+file.Name(), buf.Bytes(), 0644) + err = os.WriteFile(folder+"/"+file.Name(), buf.Bytes(), 0644) if err != nil { return err } @@ -92,7 +91,7 @@ func OptInAnalytics() error { return nil } // Write opt-in to all config files - files, err := ioutil.ReadDir("./samples") + files, err := os.ReadDir("./samples") if err != nil { return err } @@ -107,7 +106,6 @@ func OptInAnalytics() error { return nil } -// Source: https://stackoverflow.com/questions/55176623/how-to-ask-yes-or-no-using-golang func yesNo() bool { prompt := promptui.Select{ Label: "Select[Yes/No]", @@ -122,7 +120,7 @@ func yesNo() bool { } func addOptInAnalyticsToConfigFile(f string) error { - input, err := ioutil.ReadFile(f) + input, err := os.ReadFile(f) if err != nil { return err } @@ -135,7 +133,7 @@ func addOptInAnalyticsToConfigFile(f string) error { } } output := strings.Join(lines, "\n") - err = ioutil.WriteFile(f, []byte(output), 0644) + err = os.WriteFile(f, []byte(output), 0644) if err != nil { return err } diff --git a/cli/pkg/cli_init/shared_vpc/main.tf b/cli/pkg/cli_init/network/main.tf similarity index 82% rename from cli/pkg/cli_init/shared_vpc/main.tf rename to cli/pkg/cli_init/network/main.tf index 88d719b0..f55b76af 100644 --- a/cli/pkg/cli_init/shared_vpc/main.tf +++ b/cli/pkg/cli_init/network/main.tf @@ -1,12 +1,13 @@ -module "shared_vpc" { - source = "{{.TFModuleRepo}}shared_vpc?ref={{.TFModuleBranch}}" +module "network" { + source = "{{.TFModuleRepo}}network?ref={{.TFModuleBranch}}" project_id = var.project_id vpc_project_id = var.vpc_project_id - region = var.region vpc_name = var.vpc_name vpc_ip_range_pods_name = var.vpc_ip_range_pods_name vpc_ip_range_services_name = var.vpc_ip_range_services_name cluster_config = var.cluster_config + shared_vpc = var.shared_vpc + region = var.region } variable "project_id" { @@ -20,6 +21,12 @@ variable "vpc_project_id" { default = "" } +variable "shared_vpc" { + type = bool + description = "Determines whether to create a standalone VPC or use an existing Shared VPC" + default = false +} + variable "region" { type = string description = "The region to host the cluster in" diff --git a/cli/pkg/cli_init/samples/default-config.yaml b/cli/pkg/cli_init/samples/default-config.yaml index d9155204..27917d54 100644 --- a/cli/pkg/cli_init/samples/default-config.yaml +++ b/cli/pkg/cli_init/samples/default-config.yaml @@ -2,37 +2,39 @@ # These are the default values used for `gkekitctl create` when # the user does not supply their own config.yml. Note that the user # *does* have to provide their GCP project ID at runtime. -terraformState: cloud + +## Global +sendAnalytics: false +terraformState: cloud # local, cloud + +## VPC Build +vpcConfig: + vpcName: "prod" + vpcType: "standalone" # standalone, shared + vpcProjectId: "my-project" + vpcPodCIDRName: "default" + vpcSvcCIDRName: "default" + +## FleetBuild +configSyncRepo: "default-config-sync-repo" +configSyncBranch: "main" +configSyncDir: "/" + +## Cluster Build +authenticatorSecurityGroup: "gke-security-groups@" clustersProjectId: "my-project" -governanceProjectId: "my-project" -region: "us-central1" -regionalClusters: true -enablePreemptibleNodepool: false # Enforced on Linux Node pools only -enableWindowsNodepool: false -privateEndpoint: false +fleetProjectId: "my-project" +privateEndpoint: true releaseChannel: REGULAR -defaultNodepoolOS: cos -initialNodeCount: 10 -maxNodeCount: 10 +initialNodeCount: 1 # for Autopilot this has to be 1 minNodeCount: 1 -configSync: true -configSyncRepo: "config-sync-repo" -policyController: true -multiClusterGateway: false -anthosServiceMesh: false +maxNodeCount: 10 +defaultNodepoolOS: cos tfModuleRepo: "github.com/GoogleCloudPlatform/gke-poc-toolkit//terraform/modules/" tfModuleBranch: "main" -gkeModuleBypass: false -sendAnalytics: false -vpcConfig: - vpcName: "gke-poc-toolkit" - vpcType: "standalone" - vpcProjectId: "my-project" - podCIDRName: "default" - svcCIDRName: "default" - authCIDR: "0.0.0.0/0" -clustersConfig: -- clusterName: "gke-central" + +clustersConfig: # a list of one or more clusters, each with their own config +- clusterName: "gke-ap-central-00" machineType: "e2-standard-4" region: "us-central1" zones: ["us-central1-a"] diff --git a/cli/pkg/cli_init/samples/fleet-full.yaml b/cli/pkg/cli_init/samples/fleet-full.yaml new file mode 100644 index 00000000..28b0d450 --- /dev/null +++ b/cli/pkg/cli_init/samples/fleet-full.yaml @@ -0,0 +1,52 @@ +## Global +sendAnalytics: true +terraformState: cloud # local, cloud + +## VPC Build +vpcConfig: + vpcName: "prod-3" + vpcType: "standalone" # standalone, shared + vpcProjectId: "app-team-2-bu-1" + vpcPodCIDRName: "mypodcidr" + vpcSvcCIDRName: "mysvccidr" + +## FleetBuild +configSyncRepo: "https://github.com/knee-berts/fleets-next24-demo" +configSyncBranch: "dev" +configSyncDir: "default-configs" + +## Cluster Build +regionalClusters: true # Control plane availability +authenticatorSecurityGroup: "gke-security-groups@gkedemos.joonix.net" +clustersProjectId: "app-team-2-bu-1" +fleetProjectId: "app-team-2-bu-1" +privateEndpoint: true +releaseChannel: REGULAR +initialNodeCount: 10 +minNodeCount: 1 +maxNodeCount: 10 +defaultNodepoolOS: cos +tfModuleRepo: "github.com/knee-berts/gke-poc-toolkit//terraform/modules/" +tfModuleBranch: "main" + +clustersConfig: # a list of one or more clusters, each with their own config +- clusterName: "gke-ap-central-03" + machineType: "e2-standard-4" + region: "us-central1" + zones: ["us-central1-b"] + subnetName: "us-central1" +- clusterName: "gke-ap-east-03" + machineType: "e2-standard-4" + region: "us-east1" + zones: ["us-east1-b"] + subnetName: "us-east1" +# - clusterName: "gke-west" +# machineType: "e2-standard-4" +# region: "us-west1" +# zones: ["us-west1-b"] +# subnetName: "us-west1" +# - clusterName: "gke-eu-north" +# machineType: "e2-standard-4" +# region: "europe-north1" +# zones: ["europe-north1-c"] +# subnetName: "europe-north1" diff --git a/cli/pkg/cli_init/samples/fleet-shared-vpc.yaml b/cli/pkg/cli_init/samples/fleet-shared-vpc.yaml new file mode 100644 index 00000000..559b6c3f --- /dev/null +++ b/cli/pkg/cli_init/samples/fleet-shared-vpc.yaml @@ -0,0 +1,52 @@ +## Global +sendAnalytics: true +terraformState: cloud # local, cloud + +## VPC Build +vpcConfig: + vpcName: "prod" + vpcType: "shared" # standalone, shared + vpcProjectId: "shared-vpc-prod-00" + vpcPodCIDRName: "mypodcidr" + vpcSvcCIDRName: "mysvccidr" + +## FleetBuild +configSyncRepo: "https://github.com/knee-berts/fleets-next24-demo" +configSyncBranch: "dev" +configSyncDir: "default-configs" + +## Cluster Build +regionalClusters: true # Control plane availability +authenticatorSecurityGroup: "gke-security-groups@gkedemos.joonix.net" +clustersProjectId: "fleet-prod-2" +fleetProjectId: "fleet-prod-2" +privateEndpoint: true +releaseChannel: REGULAR +initialNodeCount: 10 +minNodeCount: 1 +maxNodeCount: 10 +defaultNodepoolOS: cos +tfModuleRepo: "github.com/knee-berts/gke-poc-toolkit//terraform/modules/" +tfModuleBranch: "main" + +clustersConfig: # a list of one or more clusters, each with their own config +- clusterName: "gke-std-central-00" + machineType: "e2-standard-4" + region: "us-central1" + zones: ["us-central1-b"] + subnetName: "us-central1" +- clusterName: "gke-std-east-00" + machineType: "e2-standard-4" + region: "us-east1" + zones: ["us-east1-b"] + subnetName: "us-east1" +# - clusterName: "gke-west" +# machineType: "e2-standard-4" +# region: "us-west1" +# zones: ["us-west1-b"] +# subnetName: "us-west1" +# - clusterName: "gke-eu-north" +# machineType: "e2-standard-4" +# region: "europe-north1" +# zones: ["europe-north1-c"] +# subnetName: "europe-north1" diff --git a/cli/pkg/cli_init/templates/cluster_config.tmpl b/cli/pkg/cli_init/templates/cluster_config.tmpl index 427a01d6..c9f5f7f5 100644 --- a/cli/pkg/cli_init/templates/cluster_config.tmpl +++ b/cli/pkg/cli_init/templates/cluster_config.tmpl @@ -3,5 +3,4 @@ {{"\t"}} zones = ["{{.Zones}}"] {{"\t"}} subnet_name = "{{.SubnetName}}" {{"\t"}} linux_machine_type = "{{.MachineType}}" -{{"\t"}} windows_machine_type = "{{.MachineType}}" {{"\t"}}} diff --git a/cli/pkg/cli_init/templates/gateway_api_crds.yaml b/cli/pkg/cli_init/templates/gateway_api_crds.yaml deleted file mode 100644 index ecaac107..00000000 --- a/cli/pkg/cli_init/templates/gateway_api_crds.yaml +++ /dev/null @@ -1,3328 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.5.0 - creationTimestamp: null - name: backendpolicies.networking.x-k8s.io -spec: - group: networking.x-k8s.io - names: - categories: - - gateway-api - kind: BackendPolicy - listKind: BackendPolicyList - plural: backendpolicies - shortNames: - - bp - singular: backendpolicy - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: BackendPolicy defines policies associated with backends. For - the purpose of this API, a backend is defined as any resource that a route - can forward traffic to. A common example of a backend is a Service. Configuration - that is implementation specific may be represented with similar implementation - specific custom resources. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the desired state of BackendPolicy. - properties: - backendRefs: - description: "BackendRefs define which backends this policy should - be applied to. This policy can only apply to backends within the - same namespace. If more than one BackendPolicy targets the same - backend, precedence must be given to the oldest BackendPolicy. \n - Support: Core" - items: - description: BackendRef identifies an API object within the same - namespace as the BackendPolicy. - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - type: string - kind: - description: Kind is the kind of the referent. - maxLength: 253 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - type: string - port: - description: Port is the port of the referent. If unspecified, - this policy applies to all ports on the backend. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - group - - kind - - name - type: object - maxItems: 16 - type: array - tls: - description: "TLS is the TLS configuration for these backends. \n - Support: Extended" - properties: - certificateAuthorityRef: - description: "CertificateAuthorityRef is a reference to a Kubernetes - object that contains one or more trusted CA certificates. The - CA certificates are used to establish a TLS handshake to backends - listed in BackendRefs. The referenced object MUST reside in - the same namespace as BackendPolicy. \n CertificateAuthorityRef - can reference a standard Kubernetes resource, i.e. ConfigMap, - or an implementation-specific custom resource. \n When stored - in a Secret, certificates must be PEM encoded and specified - within the \"ca.crt\" data field of the Secret. When multiple - certificates are specified, the certificates MUST be concatenated - by new lines. \n CertificateAuthorityRef can also reference - a standard Kubernetes resource, i.e. ConfigMap, or an implementation-specific - custom resource. \n Support: Extended" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - options: - additionalProperties: - type: string - description: "Options are a list of key/value pairs to give extended - options to the provider. \n Support: Implementation-specific" - type: object - type: object - required: - - backendRefs - type: object - status: - description: Status defines the current state of BackendPolicy. - properties: - conditions: - description: Conditions describe the current conditions of the BackendPolicy. - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: - \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // +listMapKey=type - \ Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.5.0 - creationTimestamp: null - name: gatewayclasses.networking.x-k8s.io -spec: - group: networking.x-k8s.io - names: - categories: - - gateway-api - kind: GatewayClass - listKind: GatewayClassList - plural: gatewayclasses - shortNames: - - gc - singular: gatewayclass - scope: Cluster - versions: - - additionalPrinterColumns: - - jsonPath: .spec.controller - name: Controller - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: "GatewayClass describes a class of Gateways available to the - user for creating Gateway resources. \n GatewayClass is a Cluster level - resource." - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the desired state of GatewayClass. - properties: - controller: - description: "Controller is a domain/path string that indicates the - controller that is managing Gateways of this class. \n Example: - \"acme.io/gateway-controller\". \n This field is not mutable and - cannot be empty. \n The format of this field is DOMAIN \"/\" PATH, - where DOMAIN and PATH are valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). - \n Support: Core" - maxLength: 253 - type: string - parametersRef: - description: "ParametersRef is a reference to a resource that contains - the configuration parameters corresponding to the GatewayClass. - This is optional if the controller does not require any additional - configuration. \n ParametersRef can reference a standard Kubernetes - resource, i.e. ConfigMap, or an implementation-specific custom resource. - The resource can be cluster-scoped or namespace-scoped. \n If the - referent cannot be found, the GatewayClass's \"InvalidParameters\" - status condition will be true. \n Support: Custom" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: Namespace is the namespace of the referent. This - field is required when scope is set to "Namespace" and ignored - when scope is set to "Cluster". - maxLength: 253 - minLength: 1 - type: string - scope: - default: Cluster - description: Scope represents if the referent is a Cluster or - Namespace scoped resource. This may be set to "Cluster" or "Namespace". - enum: - - Cluster - - Namespace - type: string - required: - - group - - kind - - name - type: object - required: - - controller - type: object - status: - default: - conditions: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Waiting - status: "False" - type: Admitted - description: Status defines the current state of GatewayClass. - properties: - conditions: - default: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Waiting - status: "False" - type: Admitted - description: "Conditions is the current status from the controller - for this GatewayClass. \n Controllers should prefer to publish conditions - using values of GatewayClassConditionType for the type of each Condition." - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: - \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // +listMapKey=type - \ Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.5.0 - creationTimestamp: null - name: gateways.networking.x-k8s.io -spec: - group: networking.x-k8s.io - names: - categories: - - gateway-api - kind: Gateway - listKind: GatewayList - plural: gateways - shortNames: - - gtw - singular: gateway - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.gatewayClassName - name: Class - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: "Gateway represents an instantiation of a service-traffic handling - infrastructure by binding Listeners to a set of IP addresses. \n Implementations - should add the `gateway-exists-finalizer.networking.x-k8s.io` finalizer - on the associated GatewayClass whenever Gateway(s) is running. This ensures - that a GatewayClass associated with a Gateway(s) is not deleted while in - use." - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the desired state of Gateway. - properties: - addresses: - description: "Addresses requested for this gateway. This is optional - and behavior can depend on the GatewayClass. If a value is set in - the spec and the requested address is invalid, the GatewayClass - MUST indicate this in the associated entry in GatewayStatus.Addresses. - \n If no Addresses are specified, the GatewayClass may schedule - the Gateway in an implementation-defined manner, assigning an appropriate - set of Addresses. \n The GatewayClass MUST bind all Listeners to - every GatewayAddress that it assigns to the Gateway. \n Support: - Core" - items: - description: GatewayAddress describes an address that can be bound - to a Gateway. - properties: - type: - default: IPAddress - description: "Type of the address. \n Support: Extended" - enum: - - IPAddress - - NamedAddress - type: string - value: - description: "Value of the address. The validity of the values - will depend on the type and support by the controller. \n - Examples: `1.2.3.4`, `128::1`, `my-ip-address`." - maxLength: 253 - minLength: 1 - type: string - required: - - value - type: object - maxItems: 16 - type: array - gatewayClassName: - description: GatewayClassName used for this Gateway. This is the name - of a GatewayClass resource. - maxLength: 253 - minLength: 1 - type: string - listeners: - description: "Listeners associated with this Gateway. Listeners define - logical endpoints that are bound on this Gateway's addresses. At - least one Listener MUST be specified. \n An implementation MAY group - Listeners by Port and then collapse each group of Listeners into - a single Listener if the implementation determines that the Listeners - in the group are \"compatible\". An implementation MAY also group - together and collapse compatible Listeners belonging to different - Gateways. \n For example, an implementation might consider Listeners - to be compatible with each other if all of the following conditions - are met: \n 1. Either each Listener within the group specifies the - \"HTTP\" Protocol or each Listener within the group specifies - either the \"HTTPS\" or \"TLS\" Protocol. \n 2. Each Listener - within the group specifies a Hostname that is unique within the - group. \n 3. As a special case, one Listener within a group may - omit Hostname, in which case this Listener matches when no other - Listener matches. \n If the implementation does collapse compatible - Listeners, the hostname provided in the incoming client request - MUST be matched to a Listener to find the correct set of Routes. - The incoming hostname MUST be matched using the Hostname field for - each Listener in order of most to least specific. That is, exact - matches must be processed before wildcard matches. \n If this field - specifies multiple Listeners that have the same Port value but are - not compatible, the implementation must raise a \"Conflicted\" condition - in the Listener status. \n Support: Core" - items: - description: Listener embodies the concept of a logical endpoint - where a Gateway can accept network connections. Each listener - in a Gateway must have a unique combination of Hostname, Port, - and Protocol. This will be enforced by a validating webhook. - properties: - hostname: - description: "Hostname specifies the virtual hostname to match - for protocol types that define this concept. When unspecified, - \"\", or `*`, all hostnames are matched. This field can be - omitted for protocols that don't require hostname based matching. - \n Hostname is the fully qualified domain name of a network - host, as defined by RFC 3986. Note the following deviations - from the \"host\" part of the URI as defined in the RFC: \n - 1. IP literals are not allowed. 2. The `:` delimiter is not - respected because ports are not allowed. \n Hostname can be - \"precise\" which is a domain name without the terminating - dot of a network host (e.g. \"foo.example.com\") or \"wildcard\", - which is a domain name prefixed with a single wildcard label - (e.g. `*.example.com`). The wildcard character `*` must appear - by itself as the first DNS label and matches only a single - label. \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - port: - description: "Port is the network port. Multiple listeners may - use the same port, subject to the Listener compatibility rules. - \n Support: Core" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - protocol: - description: "Protocol specifies the network protocol this listener - expects to receive. The GatewayClass MUST apply the Hostname - match appropriately for each protocol: \n * For the \"TLS\" - protocol, the Hostname match MUST be applied to the [SNI](https://tools.ietf.org/html/rfc6066#section-3) - \ server name offered by the client. * For the \"HTTP\" protocol, - the Hostname match MUST be applied to the host portion of - the [effective request URI](https://tools.ietf.org/html/rfc7230#section-5.5) - \ or the [:authority pseudo-header](https://tools.ietf.org/html/rfc7540#section-8.1.2.3) - * For the \"HTTPS\" protocol, the Hostname match MUST be applied - at both the TLS and HTTP protocol layers. \n Support: Core" - type: string - routes: - description: "Routes specifies a schema for associating routes - with the Listener using selectors. A Route is a resource capable - of servicing a request and allows a cluster operator to expose - a cluster resource (i.e. Service) by externally-reachable - URL, load-balance traffic and terminate SSL/TLS. Typically, - a route is a \"HTTPRoute\" or \"TCPRoute\" in group \"networking.x-k8s.io\", - however, an implementation may support other types of resources. - \n The Routes selector MUST select a set of objects that are - compatible with the application protocol specified in the - Protocol field. \n Although a client request may technically - match multiple route rules, only one rule may ultimately receive - the request. Matching precedence MUST be determined in order - of the following criteria: \n * The most specific match. For - example, the most specific HTTPRoute match is determined - by the longest matching combination of hostname and path. - * The oldest Route based on creation timestamp. For example, - a Route with a creation timestamp of \"2020-09-08 01:02:03\" - is given precedence over a Route with a creation timestamp - of \"2020-09-08 01:02:04\". * If everything else is equivalent, - the Route appearing first in alphabetical order (namespace/name) - should be given precedence. For example, foo/bar is given - precedence over foo/baz. \n All valid portions of a Route - selected by this field should be supported. Invalid portions - of a Route can be ignored (sometimes that will mean the full - Route). If a portion of a Route transitions from valid to - invalid, support for that portion of the Route should be dropped - to ensure consistency. For example, even if a filter specified - by a Route is invalid, the rest of the Route should still - be supported. \n Support: Core" - properties: - group: - default: networking.x-k8s.io - description: "Group is the group of the route resource to - select. Omitting the value or specifying the empty string - indicates the networking.x-k8s.io API group. For example, - use the following to select an HTTPRoute: \n routes: kind: - HTTPRoute \n Otherwise, if an alternative API group is - desired, specify the desired group: \n routes: group: - acme.io kind: FooRoute \n Support: Core" - maxLength: 253 - minLength: 1 - type: string - kind: - description: "Kind is the kind of the route resource to - select. \n Kind MUST correspond to kinds of routes that - are compatible with the application protocol specified - in the Listener's Protocol field. \n If an implementation - does not support or recognize this resource type, it SHOULD - set the \"ResolvedRefs\" condition to false for this listener - with the \"InvalidRoutesRef\" reason. \n Support: Core" - type: string - namespaces: - default: - from: Same - description: "Namespaces indicates in which namespaces Routes - should be selected for this Gateway. This is restricted - to the namespace of this Gateway by default. \n Support: - Core" - properties: - from: - default: Same - description: "From indicates where Routes will be selected - for this Gateway. Possible values are: * All: Routes - in all namespaces may be used by this Gateway. * Selector: - Routes in namespaces selected by the selector may - be used by this Gateway. * Same: Only Routes in - the same namespace may be used by this Gateway. \n - Support: Core" - enum: - - All - - Selector - - Same - type: string - selector: - description: "Selector must be specified when From is - set to \"Selector\". In that case, only Routes in - Namespaces matching this Selector will be selected - by this Gateway. This field is ignored for other values - of \"From\". \n Support: Core" - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: - description: A label selector requirement is a - selector that contains values, a key, and an - operator that relates the key and values. - properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are - In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. If the - operator is Exists or DoesNotExist, the - values array must be empty. This array is - replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is "In", - and the values array contains only "value". The - requirements are ANDed. - type: object - type: object - type: object - selector: - description: "Selector specifies a set of route labels used - for selecting routes to associate with the Gateway. If - this Selector is defined, only routes matching the Selector - are associated with the Gateway. An empty Selector matches - all routes. \n Support: Core" - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that - relates the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, - NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists - or DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field - is "key", the operator is "In", and the values array - contains only "value". The requirements are ANDed. - type: object - type: object - required: - - kind - type: object - tls: - description: "TLS is the TLS configuration for the Listener. - This field is required if the Protocol field is \"HTTPS\" - or \"TLS\" and ignored otherwise. \n The association of SNIs - to Certificate defined in GatewayTLSConfig is defined based - on the Hostname field for this listener. \n The GatewayClass - MUST use the longest matching SNI out of all available certificates - for any TLS handshake. \n Support: Core" - properties: - certificateRef: - description: "CertificateRef is a reference to a Kubernetes - object that contains a TLS certificate and private key. - This certificate is used to establish a TLS handshake - for requests that match the hostname of the associated - listener. The referenced object MUST reside in the same - namespace as Gateway. \n This field is required when mode - is set to \"Terminate\" (default) and optional otherwise. - \n CertificateRef can reference a standard Kubernetes - resource, i.e. Secret, or an implementation-specific custom - resource. \n Support: Core (Kubernetes Secrets) \n Support: - Implementation-specific (Other resource types)" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - mode: - default: Terminate - description: "Mode defines the TLS behavior for the TLS - session initiated by the client. There are two possible - modes: - Terminate: The TLS session between the downstream - client and the Gateway is terminated at the Gateway. - This mode requires certificateRef to be set. - Passthrough: - The TLS session is NOT terminated by the Gateway. This - \ implies that the Gateway can't decipher the TLS stream - except for the ClientHello message of the TLS protocol. - \ CertificateRef field is ignored in this mode. \n Support: - Core" - enum: - - Terminate - - Passthrough - type: string - options: - additionalProperties: - type: string - description: "Options are a list of key/value pairs to give - extended options to the provider. \n There variation among - providers as to how ciphersuites are expressed. If there - is a common subset for expressing ciphers then it will - make sense to loft that as a core API construct. \n Support: - Implementation-specific" - type: object - routeOverride: - default: - certificate: Deny - description: "RouteOverride dictates if TLS settings can - be configured via Routes or not. \n CertificateRef must - be defined even if `routeOverride.certificate` is set - to 'Allow' as it will be used as the default certificate - for the listener. \n Support: Core" - properties: - certificate: - default: Deny - description: "Certificate dictates if TLS certificates - can be configured via Routes. If set to 'Allow', a - TLS certificate for a hostname defined in a Route - takes precedence over the certificate defined in Gateway. - \n Support: Core" - enum: - - Allow - - Deny - type: string - type: object - type: object - required: - - port - - protocol - - routes - type: object - maxItems: 64 - minItems: 1 - type: array - required: - - gatewayClassName - - listeners - type: object - status: - default: - conditions: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: NotReconciled - status: "False" - type: Scheduled - description: Status defines the current state of Gateway. - properties: - addresses: - description: "Addresses lists the IP addresses that have actually - been bound to the Gateway. These addresses may differ from the addresses - in the Spec, e.g. if the Gateway automatically assigns an address - from a reserved pool. \n These addresses should all be of type \"IPAddress\"." - items: - description: GatewayAddress describes an address that can be bound - to a Gateway. - properties: - type: - default: IPAddress - description: "Type of the address. \n Support: Extended" - enum: - - IPAddress - - NamedAddress - type: string - value: - description: "Value of the address. The validity of the values - will depend on the type and support by the controller. \n - Examples: `1.2.3.4`, `128::1`, `my-ip-address`." - maxLength: 253 - minLength: 1 - type: string - required: - - value - type: object - maxItems: 16 - type: array - conditions: - default: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: NotReconciled - status: "False" - type: Scheduled - description: "Conditions describe the current conditions of the Gateway. - \n Implementations should prefer to express Gateway conditions using - the `GatewayConditionType` and `GatewayConditionReason` constants - so that operators and tools can converge on a common vocabulary - to describe Gateway state. \n Known condition types are: \n * \"Scheduled\" - * \"Ready\"" - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: - \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // +listMapKey=type - \ Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - listeners: - description: Listeners provide status for each unique listener port - defined in the Spec. - items: - description: ListenerStatus is the status associated with a Listener. - properties: - conditions: - description: Conditions describe the current condition of this - listener. - items: - description: "Condition contains details for one aspect of - the current state of this API Resource. --- This struct - is intended for direct use as an array at the field path - .status.conditions. For example, type FooStatus struct{ - \ // Represents the observations of a foo's current state. - \ // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // - +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should - be when the underlying condition changed. If that is - not known, then using the time when the API field changed - is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, - if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the - current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier - indicating the reason for the condition's last transition. - Producers of specific condition types may define expected - values and meanings for this field, and whether the - values are considered a guaranteed API. The value should - be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across - resources like Available, but because arbitrary conditions - can be useful (see .node.status.conditions), the ability - to deconflict is important. The regex it matches is - (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - hostname: - description: Hostname is the Listener hostname value for which - this message is reporting the status. - maxLength: 253 - minLength: 1 - type: string - port: - description: Port is the unique Listener port value for which - this message is reporting the status. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - protocol: - description: Protocol is the Listener protocol value for which - this message is reporting the status. - type: string - required: - - conditions - - port - - protocol - type: object - maxItems: 64 - type: array - x-kubernetes-list-map-keys: - - port - x-kubernetes-list-type: map - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.5.0 - creationTimestamp: null - name: httproutes.networking.x-k8s.io -spec: - group: networking.x-k8s.io - names: - categories: - - gateway-api - kind: HTTPRoute - listKind: HTTPRouteList - plural: httproutes - singular: httproute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.hostnames - name: Hostnames - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: HTTPRoute is the Schema for the HTTPRoute resource. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the desired state of HTTPRoute. - properties: - gateways: - default: - allow: SameNamespace - description: Gateways defines which Gateways can use this Route. - properties: - allow: - default: SameNamespace - description: 'Allow indicates which Gateways will be allowed to - use this route. Possible values are: * All: Gateways in any - namespace can use this route. * FromList: Only Gateways specified - in GatewayRefs may use this route. * SameNamespace: Only Gateways - in the same namespace may use this route.' - enum: - - All - - FromList - - SameNamespace - type: string - gatewayRefs: - description: GatewayRefs must be specified when Allow is set to - "FromList". In that case, only Gateways referenced in this list - will be allowed to use this route. This field is ignored for - other values of "Allow". - items: - description: GatewayReference identifies a Gateway in a specified - namespace. - properties: - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: Namespace is the namespace of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - name - - namespace - type: object - type: array - type: object - hostnames: - description: "Hostnames defines a set of hostname that should match - against the HTTP Host header to select a HTTPRoute to process the - request. Hostname is the fully qualified domain name of a network - host, as defined by RFC 3986. Note the following deviations from - the \"host\" part of the URI as defined in the RFC: \n 1. IPs are - not allowed. 2. The `:` delimiter is not respected because ports - are not allowed. \n Incoming requests are matched against the hostnames - before the HTTPRoute rules. If no hostname is specified, traffic - is routed based on the HTTPRouteRules. \n Hostname can be \"precise\" - which is a domain name without the terminating dot of a network - host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain - name prefixed with a single wildcard label (e.g. `*.example.com`). - The wildcard character `*` must appear by itself as the first DNS - label and matches only a single label. You cannot have a wildcard - label by itself (e.g. Host == `*`). Requests will be matched against - the Host field in the following order: \n 1. If Host is precise, - the request matches this rule if the HTTP Host header is equal - to Host. 2. If Host is a wildcard, then the request matches this - rule if the HTTP Host header is to equal to the suffix (removing - the first label) of the wildcard rule. \n Support: Core" - items: - description: Hostname is used to specify a hostname that should - be matched. - maxLength: 253 - minLength: 1 - type: string - maxItems: 16 - type: array - rules: - default: - - matches: - - path: - type: Prefix - value: / - description: Rules are a list of HTTP matchers, filters and actions. - items: - description: HTTPRouteRule defines semantics for matching an HTTP - request based on conditions, optionally executing additional processing - steps, and forwarding the request to an API object. - properties: - filters: - description: "Filters define the filters that are applied to - requests that match this rule. \n The effects of ordering - of multiple behaviors are currently unspecified. This can - change in the future based on feedback during the alpha stage. - \n Conformance-levels at this level are defined based on the - type of filter: \n - ALL core filters MUST be supported by - all implementations. - Implementers are encouraged to support - extended filters. - Implementation-specific custom filters - have no API guarantees across implementations. \n Specifying - a core filter multiple times has unspecified or custom conformance. - \n Support: Core" - items: - description: 'HTTPRouteFilter defines additional processing - steps that must be completed during the request or response - lifecycle. HTTPRouteFilters are meant as an extension point - to express additional processing that may be done in Gateway - implementations. Some examples include request or response - modification, implementing authentication strategies, rate-limiting, - and traffic shaping. API guarantee/conformance is defined - based on the type of the filter. TODO(hbagdi): re-render - CRDs once controller-tools supports union tags: - https://github.com/kubernetes-sigs/controller-tools/pull/298 - - https://github.com/kubernetes-sigs/controller-tools/issues/461' - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific - extension to the \"filter\" behavior. For example, - resource \"myroutefilter\" in group \"networking.acme.io\"). - ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema for - a filter that modifies request headers. \n Support: - Core" - properties: - add: - additionalProperties: - type: string - description: "Add adds the given header (name, value) - to the request before the action. It appends to - any existing values associated with the header name. - \n Input: GET /foo HTTP/1.1 my-header: foo \n - Config: add: {\"my-header\": \"bar\"} \n Output: - \ GET /foo HTTP/1.1 my-header: foo my-header: - bar \n Support: Extended" - type: object - remove: - description: "Remove the given header(s) from the - HTTP request before the action. The value of RemoveHeader - is a list of HTTP header names. Note that the header - names are case-insensitive [RFC-2616 4.2]. \n Input: - \ GET /foo HTTP/1.1 my-header1: foo my-header2: - bar my-header3: baz \n Config: remove: [\"my-header1\", - \"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2: - bar \n Support: Extended" - items: - type: string - maxItems: 16 - type: array - set: - additionalProperties: - type: string - description: "Set overwrites the request with the - given header (name, value) before the action. \n - Input: GET /foo HTTP/1.1 my-header: foo \n Config: - \ set: {\"my-header\": \"bar\"} \n Output: GET - /foo HTTP/1.1 my-header: bar \n Support: Extended" - type: object - type: object - requestMirror: - description: "RequestMirror defines a schema for a filter - that mirrors requests. \n Support: Extended" - properties: - backendRef: - description: "BackendRef is a local object reference - to mirror matched requests to. If both BackendRef - and ServiceName are specified, ServiceName will - be given precedence. \n If the referent cannot be - found, the rule is not included in the route. The - controller should raise the \"ResolvedRefs\" condition - on the Gateway with the \"DegradedRoutes\" reason. - The gateway status for this route should be updated - with a condition that describes the error more specifically. - \n Support: Custom" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - port: - description: "Port specifies the destination port - number to use for the backend referenced by the - ServiceName or BackendRef field. \n If unspecified, - the destination port in the request is used when - forwarding to a backendRef or serviceName." - format: int32 - maximum: 65535 - minimum: 1 - type: integer - serviceName: - description: "ServiceName refers to the name of the - Service to mirror matched requests to. When specified, - this takes the place of BackendRef. If both BackendRef - and ServiceName are specified, ServiceName will - be given precedence. \n If the referent cannot be - found, the rule is not included in the route. The - controller should raise the \"ResolvedRefs\" condition - on the Gateway with the \"DegradedRoutes\" reason. - The gateway status for this route should be updated - with a condition that describes the error more specifically. - \n Support: Core" - maxLength: 253 - type: string - type: object - type: - description: "Type identifies the type of filter to apply. - As with other API fields, types are classified into - three conformance levels: \n - Core: Filter types and - their corresponding configuration defined by \"Support: - Core\" in this package, e.g. \"RequestHeaderModifier\". - All implementations must support core filters. \n - - Extended: Filter types and their corresponding configuration - defined by \"Support: Extended\" in this package, - e.g. \"RequestMirror\". Implementers are encouraged - to support extended filters. \n - Custom: Filters that - are defined and supported by specific vendors. In - the future, filters showing convergence in behavior - across multiple implementations will be considered - for inclusion in extended or core conformance levels. - Filter-specific configuration for such filters is - specified using the ExtensionRef field. `Type` should - be set to \"ExtensionRef\" for custom filters. \n - Implementers are encouraged to define custom implementation - types to extend the core API with implementation-specific - behavior." - enum: - - RequestHeaderModifier - - RequestMirror - - ExtensionRef - type: string - required: - - type - type: object - maxItems: 16 - type: array - forwardTo: - description: ForwardTo defines the backend(s) where matching - requests should be sent. If unspecified, the rule performs - no forwarding. If unspecified and no filters are specified - that would result in a response being sent, a 503 error code - is returned. - items: - description: HTTPRouteForwardTo defines how a HTTPRoute should - forward a request. - properties: - backendRef: - description: "BackendRef is a reference to a backend to - forward matched requests to. If both BackendRef and - ServiceName are specified, ServiceName will be given - precedence. \n If the referent cannot be found, the - route must be dropped from the Gateway. The controller - should raise the \"ResolvedRefs\" condition on the Gateway - with the \"DegradedRoutes\" reason. The gateway status - for this route should be updated with a condition that - describes the error more specifically. \n Support: Custom" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - filters: - description: "Filters defined at this-level should be - executed if and only if the request is being forwarded - to the backend defined here. \n Support: Custom (For - broader support of filters, use the Filters field in - HTTPRouteRule.)" - items: - description: 'HTTPRouteFilter defines additional processing - steps that must be completed during the request or - response lifecycle. HTTPRouteFilters are meant as - an extension point to express additional processing - that may be done in Gateway implementations. Some - examples include request or response modification, - implementing authentication strategies, rate-limiting, - and traffic shaping. API guarantee/conformance is - defined based on the type of the filter. TODO(hbagdi): - re-render CRDs once controller-tools supports union - tags: - https://github.com/kubernetes-sigs/controller-tools/pull/298 - - https://github.com/kubernetes-sigs/controller-tools/issues/461' - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific - extension to the \"filter\" behavior. For example, - resource \"myroutefilter\" in group \"networking.acme.io\"). - ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema - for a filter that modifies request headers. \n - Support: Core" - properties: - add: - additionalProperties: - type: string - description: "Add adds the given header (name, - value) to the request before the action. It - appends to any existing values associated - with the header name. \n Input: GET /foo - HTTP/1.1 my-header: foo \n Config: add: - {\"my-header\": \"bar\"} \n Output: GET - /foo HTTP/1.1 my-header: foo my-header: - bar \n Support: Extended" - type: object - remove: - description: "Remove the given header(s) from - the HTTP request before the action. The value - of RemoveHeader is a list of HTTP header names. - Note that the header names are case-insensitive - [RFC-2616 4.2]. \n Input: GET /foo HTTP/1.1 - \ my-header1: foo my-header2: bar my-header3: - baz \n Config: remove: [\"my-header1\", - \"my-header3\"] \n Output: GET /foo HTTP/1.1 - \ my-header2: bar \n Support: Extended" - items: - type: string - maxItems: 16 - type: array - set: - additionalProperties: - type: string - description: "Set overwrites the request with - the given header (name, value) before the - action. \n Input: GET /foo HTTP/1.1 my-header: - foo \n Config: set: {\"my-header\": \"bar\"} - \n Output: GET /foo HTTP/1.1 my-header: - bar \n Support: Extended" - type: object - type: object - requestMirror: - description: "RequestMirror defines a schema for - a filter that mirrors requests. \n Support: Extended" - properties: - backendRef: - description: "BackendRef is a local object reference - to mirror matched requests to. If both BackendRef - and ServiceName are specified, ServiceName - will be given precedence. \n If the referent - cannot be found, the rule is not included - in the route. The controller should raise - the \"ResolvedRefs\" condition on the Gateway - with the \"DegradedRoutes\" reason. The gateway - status for this route should be updated with - a condition that describes the error more - specifically. \n Support: Custom" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - port: - description: "Port specifies the destination - port number to use for the backend referenced - by the ServiceName or BackendRef field. \n - If unspecified, the destination port in the - request is used when forwarding to a backendRef - or serviceName." - format: int32 - maximum: 65535 - minimum: 1 - type: integer - serviceName: - description: "ServiceName refers to the name - of the Service to mirror matched requests - to. When specified, this takes the place of - BackendRef. If both BackendRef and ServiceName - are specified, ServiceName will be given precedence. - \n If the referent cannot be found, the rule - is not included in the route. The controller - should raise the \"ResolvedRefs\" condition - on the Gateway with the \"DegradedRoutes\" - reason. The gateway status for this route - should be updated with a condition that describes - the error more specifically. \n Support: Core" - maxLength: 253 - type: string - type: object - type: - description: "Type identifies the type of filter - to apply. As with other API fields, types are - classified into three conformance levels: \n - - Core: Filter types and their corresponding configuration - defined by \"Support: Core\" in this package, - e.g. \"RequestHeaderModifier\". All implementations - must support core filters. \n - Extended: Filter - types and their corresponding configuration defined - by \"Support: Extended\" in this package, e.g. - \"RequestMirror\". Implementers are encouraged - to support extended filters. \n - Custom: Filters - that are defined and supported by specific vendors. - \ In the future, filters showing convergence - in behavior across multiple implementations - will be considered for inclusion in extended or - core conformance levels. Filter-specific configuration - for such filters is specified using the ExtensionRef - field. `Type` should be set to \"ExtensionRef\" - for custom filters. \n Implementers are encouraged - to define custom implementation types to extend - the core API with implementation-specific behavior." - enum: - - RequestHeaderModifier - - RequestMirror - - ExtensionRef - type: string - required: - - type - type: object - maxItems: 16 - type: array - port: - description: "Port specifies the destination port number - to use for the backend referenced by the ServiceName - or BackendRef field. If unspecified, the destination - port in the request is used when forwarding to a backendRef - or serviceName. \n Support: Core" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - serviceName: - description: "ServiceName refers to the name of the Service - to forward matched requests to. When specified, this - takes the place of BackendRef. If both BackendRef and - ServiceName are specified, ServiceName will be given - precedence. \n If the referent cannot be found, the - route must be dropped from the Gateway. The controller - should raise the \"ResolvedRefs\" condition on the Gateway - with the \"DegradedRoutes\" reason. The gateway status - for this route should be updated with a condition that - describes the error more specifically. \n The protocol - to use should be specified with the AppProtocol field - on Service resources. This field was introduced in Kubernetes - 1.18. If using an earlier version of Kubernetes, a `networking.x-k8s.io/app-protocol` - annotation on the BackendPolicy resource may be used - to define the protocol. If the AppProtocol field is - available, this annotation should not be used. The AppProtocol - field, when populated, takes precedence over the annotation - in the BackendPolicy resource. For custom backends, - it is encouraged to add a semantically-equivalent field - in the Custom Resource Definition. \n Support: Core" - maxLength: 253 - type: string - weight: - default: 1 - description: "Weight specifies the proportion of HTTP - requests forwarded to the backend referenced by the - ServiceName or BackendRef field. This is computed as - weight/(sum of all weights in this ForwardTo list). - For non-zero values, there may be some epsilon from - the exact proportion defined here depending on the precision - an implementation supports. Weight is not a percentage - and the sum of weights does not need to equal 100. \n - If only one backend is specified and it has a weight - greater than 0, 100% of the traffic is forwarded to - that backend. If weight is set to 0, no traffic should - be forwarded for this entry. If unspecified, weight - defaults to 1. \n Support: Core" - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - type: object - maxItems: 16 - type: array - matches: - default: - - path: - type: Prefix - value: / - description: "Matches define conditions used for matching the - rule against incoming HTTP requests. Each match is independent, - i.e. this rule will be matched if **any** one of the matches - is satisfied. \n For example, take the following matches configuration: - \n ``` matches: - path: value: \"/foo\" headers: values: - \ version: \"2\" - path: value: \"/v2/foo\" ``` \n - For a request to match against this rule, a request should - satisfy EITHER of the two conditions: \n - path prefixed with - `/foo` AND contains the header `version: \"2\"` - path prefix - of `/v2/foo` \n See the documentation for HTTPRouteMatch on - how to specify multiple match conditions that should be ANDed - together. \n If no matches are specified, the default is a - prefix path match on \"/\", which has the effect of matching - every HTTP request. \n Each client request MUST map to a maximum - of one route rule. If a request matches multiple rules, matching - precedence MUST be determined in order of the following criteria, - continuing on ties: \n * The longest matching hostname. * - The longest matching path. * The largest number of header - matches. \n If ties still exist across multiple Routes, matching - precedence MUST be determined in order of the following criteria, - continuing on ties: \n * The oldest Route based on creation - timestamp. For example, a Route with a creation timestamp - of \"2020-09-08 01:02:03\" is given precedence over a Route - with a creation timestamp of \"2020-09-08 01:02:04\". * The - Route appearing first in alphabetical order by \"/\". - For example, foo/bar is given precedence over foo/baz. \n - If ties still exist within the Route that has been given precedence, - matching precedence MUST be granted to the first matching - rule meeting the above criteria." - items: - description: "HTTPRouteMatch defines the predicate used to - match requests to a given action. Multiple match types are - ANDed together, i.e. the match will evaluate to true only - if all conditions are satisfied. \n For example, the match - below will match a HTTP request only if its path starts - with `/foo` AND it contains the `version: \"1\"` header: - \n ``` match: path: value: \"/foo\" headers: values: - \ version: \"1\" ```" - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific - extension to the \"match\" behavior. For example, resource - \"myroutematcher\" in group \"networking.acme.io\". - If the referent cannot be found, the rule is not included - in the route. The controller should raise the \"ResolvedRefs\" - condition on the Gateway with the \"DegradedRoutes\" - reason. The gateway status for this route should be - updated with a condition that describes the error more - specifically. \n Support: Custom" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - headers: - description: Headers specifies a HTTP request header matcher. - properties: - type: - default: Exact - description: "Type specifies how to match against - the value of the header. \n Support: Core (Exact) - \n Support: Custom (RegularExpression, ImplementationSpecific) - \n Since RegularExpression PathType has custom conformance, - implementations can support POSIX, PCRE or any other - dialects of regular expressions. Please read the - implementation's documentation to determine the - supported dialect. \n HTTP Header name matching - MUST be case-insensitive (RFC 2616 - section 4.2)." - enum: - - Exact - - RegularExpression - - ImplementationSpecific - type: string - values: - additionalProperties: - type: string - description: "Values is a map of HTTP Headers to be - matched. It MUST contain at least one entry. \n - The HTTP header field name to match is the map key, - and the value of the HTTP header is the map value. - HTTP header field name matching MUST be case-insensitive. - \n Multiple match values are ANDed together, meaning, - a request must match all the specified headers to - select the route." - type: object - required: - - values - type: object - path: - default: - type: Prefix - value: / - description: Path specifies a HTTP request path matcher. - If this field is not specified, a default prefix match - on the "/" path is provided. - properties: - type: - default: Prefix - description: "Type specifies how to match against - the path Value. \n Support: Core (Exact, Prefix) - \n Support: Custom (RegularExpression, ImplementationSpecific) - \n Since RegularExpression PathType has custom conformance, - implementations can support POSIX, PCRE or any other - dialects of regular expressions. Please read the - implementation's documentation to determine the - supported dialect." - enum: - - Exact - - Prefix - - RegularExpression - - ImplementationSpecific - type: string - value: - default: / - description: Value of the HTTP path to match against. - type: string - type: object - queryParams: - description: QueryParams specifies a HTTP query parameter - matcher. - properties: - type: - default: Exact - description: "Type specifies how to match against - the value of the query parameter. \n Support: Extended - (Exact) \n Support: Custom (RegularExpression, ImplementationSpecific) - \n Since RegularExpression QueryParamMatchType has - custom conformance, implementations can support - POSIX, PCRE or any other dialects of regular expressions. - Please read the implementation's documentation to - determine the supported dialect." - enum: - - Exact - - RegularExpression - - ImplementationSpecific - type: string - values: - additionalProperties: - type: string - description: "Values is a map of HTTP query parameters - to be matched. It MUST contain at least one entry. - \n The query parameter name to match is the map - key, and the value of the query parameter is the - map value. \n Multiple match values are ANDed together, - meaning, a request must match all the specified - query parameters to select the route. \n HTTP query - parameter matching MUST be case-sensitive for both - keys and values. (See https://tools.ietf.org/html/rfc7230#section-2.7.3). - \n Note that the query parameter key MUST always - be an exact match by string comparison." - type: object - required: - - values - type: object - type: object - maxItems: 8 - type: array - type: object - maxItems: 16 - type: array - tls: - description: "TLS defines the TLS certificate to use for Hostnames - defined in this Route. This configuration only takes effect if the - AllowRouteOverride field is set to true in the associated Gateway - resource. \n Collisions can happen if multiple HTTPRoutes define - a TLS certificate for the same hostname. In such a case, conflict - resolution guiding principles apply, specifically, if hostnames - are same and two different certificates are specified then the certificate - in the oldest resource wins. \n Please note that HTTP Route-selection - takes place after the TLS Handshake (ClientHello). Due to this, - TLS certificate defined here will take precedence even if the request - has the potential to match multiple routes (in case multiple HTTPRoutes - share the same hostname). \n Support: Core" - properties: - certificateRef: - description: "CertificateRef is a reference to a Kubernetes object - that contains a TLS certificate and private key. This certificate - is used to establish a TLS handshake for requests that match - the hostname of the associated HTTPRoute. The referenced object - MUST reside in the same namespace as HTTPRoute. \n This field - is required when the TLS configuration mode of the associated - Gateway listener is set to \"Passthrough\". \n CertificateRef - can reference a standard Kubernetes resource, i.e. Secret, or - an implementation-specific custom resource. \n Support: Core - (Kubernetes Secrets) \n Support: Implementation-specific (Other - resource types)" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - required: - - certificateRef - type: object - type: object - status: - description: Status defines the current state of HTTPRoute. - properties: - gateways: - description: "Gateways is a list of Gateways that are associated with - the route, and the status of the route with respect to each Gateway. - When a Gateway selects this route, the controller that manages the - Gateway must add an entry to this list when the controller first - sees the route and should update the entry as appropriate when the - route is modified. \n A maximum of 100 Gateways will be represented - in this list. If this list is full, there may be additional Gateways - using this Route that are not included in the list. An empty list - means the route has not been admitted by any Gateway." - items: - description: RouteGatewayStatus describes the status of a route - with respect to an associated Gateway. - properties: - conditions: - description: Conditions describes the status of the route with - respect to the Gateway. The "Admitted" condition must always - be specified by controllers to indicate whether the route - has been admitted or rejected by the Gateway, and why. Note - that the route's availability is also subject to the Gateway's - own status conditions and listener status. - items: - description: "Condition contains details for one aspect of - the current state of this API Resource. --- This struct - is intended for direct use as an array at the field path - .status.conditions. For example, type FooStatus struct{ - \ // Represents the observations of a foo's current state. - \ // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // - +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should - be when the underlying condition changed. If that is - not known, then using the time when the API field changed - is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, - if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the - current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier - indicating the reason for the condition's last transition. - Producers of specific condition types may define expected - values and meanings for this field, and whether the - values are considered a guaranteed API. The value should - be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across - resources like Available, but because arbitrary conditions - can be useful (see .node.status.conditions), the ability - to deconflict is important. The regex it matches is - (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - gatewayRef: - description: GatewayRef is a reference to a Gateway object that - is associated with the route. - properties: - controller: - description: "Controller is a domain/path string that indicates - the controller implementing the Gateway. This corresponds - with the controller field on GatewayClass. \n Example: - \"acme.io/gateway-controller\". \n The format of this - field is DOMAIN \"/\" PATH, where DOMAIN and PATH are - valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names)." - maxLength: 253 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: Namespace is the namespace of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - name - - namespace - type: object - required: - - gatewayRef - type: object - maxItems: 100 - type: array - required: - - gateways - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.5.0 - creationTimestamp: null - name: tcproutes.networking.x-k8s.io -spec: - group: networking.x-k8s.io - names: - categories: - - gateway-api - kind: TCPRoute - listKind: TCPRouteList - plural: tcproutes - singular: tcproute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: TCPRoute is the Schema for the TCPRoute resource. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the desired state of TCPRoute. - properties: - gateways: - default: - allow: SameNamespace - description: Gateways defines which Gateways can use this Route. - properties: - allow: - default: SameNamespace - description: 'Allow indicates which Gateways will be allowed to - use this route. Possible values are: * All: Gateways in any - namespace can use this route. * FromList: Only Gateways specified - in GatewayRefs may use this route. * SameNamespace: Only Gateways - in the same namespace may use this route.' - enum: - - All - - FromList - - SameNamespace - type: string - gatewayRefs: - description: GatewayRefs must be specified when Allow is set to - "FromList". In that case, only Gateways referenced in this list - will be allowed to use this route. This field is ignored for - other values of "Allow". - items: - description: GatewayReference identifies a Gateway in a specified - namespace. - properties: - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: Namespace is the namespace of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - name - - namespace - type: object - type: array - type: object - rules: - description: Rules are a list of TCP matchers and actions. - items: - description: TCPRouteRule is the configuration for a given rule. - properties: - forwardTo: - description: ForwardTo defines the backend(s) where matching - requests should be sent. - items: - description: RouteForwardTo defines how a Route should forward - a request. - properties: - backendRef: - description: "BackendRef is a reference to a backend to - forward matched requests to. If both BackendRef and - ServiceName are specified, ServiceName will be given - precedence. \n If the referent cannot be found, the - rule is not included in the route. The controller should - raise the \"ResolvedRefs\" condition on the Gateway - with the \"DegradedRoutes\" reason. The gateway status - for this route should be updated with a condition that - describes the error more specifically. \n Support: Custom" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - port: - description: "Port specifies the destination port number - to use for the backend referenced by the ServiceName - or BackendRef field. If unspecified, the destination - port in the request is used when forwarding to a backendRef - or serviceName. \n Support: Core" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - serviceName: - description: "ServiceName refers to the name of the Service - to forward matched requests to. When specified, this - takes the place of BackendRef. If both BackendRef and - ServiceName are specified, ServiceName will be given - precedence. \n If the referent cannot be found, the - rule is not included in the route. The controller should - raise the \"ResolvedRefs\" condition on the Gateway - with the \"DegradedRoutes\" reason. The gateway status - for this route should be updated with a condition that - describes the error more specifically. \n The protocol - to use is defined using AppProtocol field (introduced - in Kubernetes 1.18) in the Service resource. In the - absence of the AppProtocol field a `networking.x-k8s.io/app-protocol` - annotation on the BackendPolicy resource may be used - to define the protocol. If the AppProtocol field is - available, this annotation should not be used. The AppProtocol - field, when populated, takes precedence over the annotation - in the BackendPolicy resource. For custom backends, - it is encouraged to add a semantically-equivalent field - in the Custom Resource Definition. \n Support: Core" - maxLength: 253 - type: string - weight: - default: 1 - description: "Weight specifies the proportion of HTTP - requests forwarded to the backend referenced by the - ServiceName or BackendRef field. This is computed as - weight/(sum of all weights in this ForwardTo list). - For non-zero values, there may be some epsilon from - the exact proportion defined here depending on the precision - an implementation supports. Weight is not a percentage - and the sum of weights does not need to equal 100. \n - If only one backend is specified and it has a weight - greater than 0, 100% of the traffic is forwarded to - that backend. If weight is set to 0, no traffic should - be forwarded for this entry. If unspecified, weight - defaults to 1. \n Support: Extended" - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - type: object - maxItems: 16 - minItems: 1 - type: array - matches: - description: "Matches define conditions used for matching the - rule against incoming TCP connections. Each match is independent, - i.e. this rule will be matched if **any** one of the matches - is satisfied. If unspecified (i.e. empty), this Rule will - match all requests for the associated Listener. \n Each client - request MUST map to a maximum of one route rule. If a request - matches multiple rules, matching precedence MUST be determined - in order of the following criteria, continuing on ties: \n - * The most specific match specified by ExtensionRef. Each - implementation that supports ExtensionRef may have different - ways of determining the specificity of the referenced extension. - \n If ties still exist across multiple Routes, matching precedence - MUST be determined in order of the following criteria, continuing - on ties: \n * The oldest Route based on creation timestamp. - For example, a Route with a creation timestamp of \"2020-09-08 - 01:02:03\" is given precedence over a Route with a creation - timestamp of \"2020-09-08 01:02:04\". * The Route appearing - first in alphabetical order by \"/\". For - example, foo/bar is given precedence over foo/baz. \n If - ties still exist within the Route that has been given precedence, - matching precedence MUST be granted to the first matching - rule meeting the above criteria." - items: - description: TCPRouteMatch defines the predicate used to match - connections to a given action. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific - extension to the \"match\" behavior. For example, resource - \"mytcproutematcher\" in group \"networking.acme.io\". - If the referent cannot be found, the rule is not included - in the route. The controller should raise the \"ResolvedRefs\" - condition on the Gateway with the \"DegradedRoutes\" - reason. The gateway status for this route should be - updated with a condition that describes the error more - specifically. \n Support: Custom" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - type: object - maxItems: 8 - type: array - required: - - forwardTo - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - rules - type: object - status: - description: Status defines the current state of TCPRoute. - properties: - gateways: - description: "Gateways is a list of Gateways that are associated with - the route, and the status of the route with respect to each Gateway. - When a Gateway selects this route, the controller that manages the - Gateway must add an entry to this list when the controller first - sees the route and should update the entry as appropriate when the - route is modified. \n A maximum of 100 Gateways will be represented - in this list. If this list is full, there may be additional Gateways - using this Route that are not included in the list. An empty list - means the route has not been admitted by any Gateway." - items: - description: RouteGatewayStatus describes the status of a route - with respect to an associated Gateway. - properties: - conditions: - description: Conditions describes the status of the route with - respect to the Gateway. The "Admitted" condition must always - be specified by controllers to indicate whether the route - has been admitted or rejected by the Gateway, and why. Note - that the route's availability is also subject to the Gateway's - own status conditions and listener status. - items: - description: "Condition contains details for one aspect of - the current state of this API Resource. --- This struct - is intended for direct use as an array at the field path - .status.conditions. For example, type FooStatus struct{ - \ // Represents the observations of a foo's current state. - \ // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // - +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should - be when the underlying condition changed. If that is - not known, then using the time when the API field changed - is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, - if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the - current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier - indicating the reason for the condition's last transition. - Producers of specific condition types may define expected - values and meanings for this field, and whether the - values are considered a guaranteed API. The value should - be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across - resources like Available, but because arbitrary conditions - can be useful (see .node.status.conditions), the ability - to deconflict is important. The regex it matches is - (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - gatewayRef: - description: GatewayRef is a reference to a Gateway object that - is associated with the route. - properties: - controller: - description: "Controller is a domain/path string that indicates - the controller implementing the Gateway. This corresponds - with the controller field on GatewayClass. \n Example: - \"acme.io/gateway-controller\". \n The format of this - field is DOMAIN \"/\" PATH, where DOMAIN and PATH are - valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names)." - maxLength: 253 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: Namespace is the namespace of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - name - - namespace - type: object - required: - - gatewayRef - type: object - maxItems: 100 - type: array - required: - - gateways - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.5.0 - creationTimestamp: null - name: tlsroutes.networking.x-k8s.io -spec: - group: networking.x-k8s.io - names: - categories: - - gateway-api - kind: TLSRoute - listKind: TLSRouteList - plural: tlsroutes - singular: tlsroute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: "The TLSRoute resource is similar to TCPRoute, but can be configured - to match against TLS-specific metadata. This allows more flexibility in - matching streams for a given TLS listener. \n If you need to forward traffic - to a single target for a TLS listener, you could choose to use a TCPRoute - with a TLS listener." - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the desired state of TLSRoute. - properties: - gateways: - default: - allow: SameNamespace - description: Gateways defines which Gateways can use this Route. - properties: - allow: - default: SameNamespace - description: 'Allow indicates which Gateways will be allowed to - use this route. Possible values are: * All: Gateways in any - namespace can use this route. * FromList: Only Gateways specified - in GatewayRefs may use this route. * SameNamespace: Only Gateways - in the same namespace may use this route.' - enum: - - All - - FromList - - SameNamespace - type: string - gatewayRefs: - description: GatewayRefs must be specified when Allow is set to - "FromList". In that case, only Gateways referenced in this list - will be allowed to use this route. This field is ignored for - other values of "Allow". - items: - description: GatewayReference identifies a Gateway in a specified - namespace. - properties: - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: Namespace is the namespace of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - name - - namespace - type: object - type: array - type: object - rules: - description: Rules are a list of TLS matchers and actions. - items: - description: TLSRouteRule is the configuration for a given rule. - properties: - forwardTo: - description: ForwardTo defines the backend(s) where matching - requests should be sent. - items: - description: RouteForwardTo defines how a Route should forward - a request. - properties: - backendRef: - description: "BackendRef is a reference to a backend to - forward matched requests to. If both BackendRef and - ServiceName are specified, ServiceName will be given - precedence. \n If the referent cannot be found, the - rule is not included in the route. The controller should - raise the \"ResolvedRefs\" condition on the Gateway - with the \"DegradedRoutes\" reason. The gateway status - for this route should be updated with a condition that - describes the error more specifically. \n Support: Custom" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - port: - description: "Port specifies the destination port number - to use for the backend referenced by the ServiceName - or BackendRef field. If unspecified, the destination - port in the request is used when forwarding to a backendRef - or serviceName. \n Support: Core" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - serviceName: - description: "ServiceName refers to the name of the Service - to forward matched requests to. When specified, this - takes the place of BackendRef. If both BackendRef and - ServiceName are specified, ServiceName will be given - precedence. \n If the referent cannot be found, the - rule is not included in the route. The controller should - raise the \"ResolvedRefs\" condition on the Gateway - with the \"DegradedRoutes\" reason. The gateway status - for this route should be updated with a condition that - describes the error more specifically. \n The protocol - to use is defined using AppProtocol field (introduced - in Kubernetes 1.18) in the Service resource. In the - absence of the AppProtocol field a `networking.x-k8s.io/app-protocol` - annotation on the BackendPolicy resource may be used - to define the protocol. If the AppProtocol field is - available, this annotation should not be used. The AppProtocol - field, when populated, takes precedence over the annotation - in the BackendPolicy resource. For custom backends, - it is encouraged to add a semantically-equivalent field - in the Custom Resource Definition. \n Support: Core" - maxLength: 253 - type: string - weight: - default: 1 - description: "Weight specifies the proportion of HTTP - requests forwarded to the backend referenced by the - ServiceName or BackendRef field. This is computed as - weight/(sum of all weights in this ForwardTo list). - For non-zero values, there may be some epsilon from - the exact proportion defined here depending on the precision - an implementation supports. Weight is not a percentage - and the sum of weights does not need to equal 100. \n - If only one backend is specified and it has a weight - greater than 0, 100% of the traffic is forwarded to - that backend. If weight is set to 0, no traffic should - be forwarded for this entry. If unspecified, weight - defaults to 1. \n Support: Extended" - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - type: object - maxItems: 16 - minItems: 1 - type: array - matches: - description: "Matches define conditions used for matching the - rule against incoming TLS connections. Each match is independent, - i.e. this rule will be matched if **any** one of the matches - is satisfied. If unspecified (i.e. empty), this Rule will - match all requests for the associated Listener. \n Each client - request MUST map to a maximum of one route rule. If a request - matches multiple rules, matching precedence MUST be determined - in order of the following criteria, continuing on ties: \n - * The longest matching SNI. * The longest matching precise - SNI (without a wildcard). This means that \"b.example.com\" - should be given precedence over \"*.example.com\". * The most - specific match specified by ExtensionRef. Each implementation - \ that supports ExtensionRef may have different ways of determining - the specificity of the referenced extension. \n If ties - still exist across multiple Routes, matching precedence MUST - be determined in order of the following criteria, continuing - on ties: \n * The oldest Route based on creation timestamp. - For example, a Route with a creation timestamp of \"2020-09-08 - 01:02:03\" is given precedence over a Route with a creation - timestamp of \"2020-09-08 01:02:04\". * The Route appearing - first in alphabetical order by \"/\". For - example, foo/bar is given precedence over foo/baz. \n If - ties still exist within the Route that has been given precedence, - matching precedence MUST be granted to the first matching - rule meeting the above criteria." - items: - description: TLSRouteMatch defines the predicate used to match - connections to a given action. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific - extension to the \"match\" behavior. For example, resource - \"mytlsroutematcher\" in group \"networking.acme.io\". - If the referent cannot be found, the rule is not included - in the route. The controller should raise the \"ResolvedRefs\" - condition on the Gateway with the \"DegradedRoutes\" - reason. The gateway status for this route should be - updated with a condition that describes the error more - specifically. \n Support: Custom" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - snis: - description: "SNIs defines a set of SNI names that should - match against the SNI attribute of TLS ClientHello message - in TLS handshake. \n SNI can be \"precise\" which is - a domain name without the terminating dot of a network - host (e.g. \"foo.example.com\") or \"wildcard\", which - is a domain name prefixed with a single wildcard label - (e.g. `*.example.com`). The wildcard character `*` must - appear by itself as the first DNS label and matches - only a single label. You cannot have a wildcard label - by itself (e.g. Host == `*`). \n Requests will be matched - against the Host field in the following order: \n 1. - If SNI is precise, the request matches this rule if - the SNI in ClientHello is equal to one of the defined - SNIs. 2. If SNI is a wildcard, then the request matches - this rule if the SNI is to equal to the suffix (removing - the first label) of the wildcard rule. 3. If SNIs - is unspecified, all requests associated with the gateway - TLS listener will match. This can be used to define - a default backend for a TLS listener. \n Support: - Core" - items: - description: Hostname is used to specify a hostname - that should be matched. - maxLength: 253 - minLength: 1 - type: string - maxItems: 16 - type: array - type: object - maxItems: 8 - type: array - required: - - forwardTo - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - rules - type: object - status: - description: Status defines the current state of TLSRoute. - properties: - gateways: - description: "Gateways is a list of Gateways that are associated with - the route, and the status of the route with respect to each Gateway. - When a Gateway selects this route, the controller that manages the - Gateway must add an entry to this list when the controller first - sees the route and should update the entry as appropriate when the - route is modified. \n A maximum of 100 Gateways will be represented - in this list. If this list is full, there may be additional Gateways - using this Route that are not included in the list. An empty list - means the route has not been admitted by any Gateway." - items: - description: RouteGatewayStatus describes the status of a route - with respect to an associated Gateway. - properties: - conditions: - description: Conditions describes the status of the route with - respect to the Gateway. The "Admitted" condition must always - be specified by controllers to indicate whether the route - has been admitted or rejected by the Gateway, and why. Note - that the route's availability is also subject to the Gateway's - own status conditions and listener status. - items: - description: "Condition contains details for one aspect of - the current state of this API Resource. --- This struct - is intended for direct use as an array at the field path - .status.conditions. For example, type FooStatus struct{ - \ // Represents the observations of a foo's current state. - \ // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // - +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should - be when the underlying condition changed. If that is - not known, then using the time when the API field changed - is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, - if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the - current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier - indicating the reason for the condition's last transition. - Producers of specific condition types may define expected - values and meanings for this field, and whether the - values are considered a guaranteed API. The value should - be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across - resources like Available, but because arbitrary conditions - can be useful (see .node.status.conditions), the ability - to deconflict is important. The regex it matches is - (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - gatewayRef: - description: GatewayRef is a reference to a Gateway object that - is associated with the route. - properties: - controller: - description: "Controller is a domain/path string that indicates - the controller implementing the Gateway. This corresponds - with the controller field on GatewayClass. \n Example: - \"acme.io/gateway-controller\". \n The format of this - field is DOMAIN \"/\" PATH, where DOMAIN and PATH are - valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names)." - maxLength: 253 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: Namespace is the namespace of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - name - - namespace - type: object - required: - - gatewayRef - type: object - maxItems: 100 - type: array - required: - - gateways - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.5.0 - creationTimestamp: null - name: udproutes.networking.x-k8s.io -spec: - group: networking.x-k8s.io - names: - categories: - - gateway-api - kind: UDPRoute - listKind: UDPRouteList - plural: udproutes - singular: udproute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: UDPRoute is a resource that specifies how a Gateway should forward - UDP traffic. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: Spec defines the desired state of UDPRoute. - properties: - gateways: - default: - allow: SameNamespace - description: Gateways defines which Gateways can use this Route. - properties: - allow: - default: SameNamespace - description: 'Allow indicates which Gateways will be allowed to - use this route. Possible values are: * All: Gateways in any - namespace can use this route. * FromList: Only Gateways specified - in GatewayRefs may use this route. * SameNamespace: Only Gateways - in the same namespace may use this route.' - enum: - - All - - FromList - - SameNamespace - type: string - gatewayRefs: - description: GatewayRefs must be specified when Allow is set to - "FromList". In that case, only Gateways referenced in this list - will be allowed to use this route. This field is ignored for - other values of "Allow". - items: - description: GatewayReference identifies a Gateway in a specified - namespace. - properties: - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: Namespace is the namespace of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - name - - namespace - type: object - type: array - type: object - rules: - description: Rules are a list of UDP matchers and actions. - items: - description: UDPRouteRule is the configuration for a given rule. - properties: - forwardTo: - description: ForwardTo defines the backend(s) where matching - requests should be sent. - items: - description: RouteForwardTo defines how a Route should forward - a request. - properties: - backendRef: - description: "BackendRef is a reference to a backend to - forward matched requests to. If both BackendRef and - ServiceName are specified, ServiceName will be given - precedence. \n If the referent cannot be found, the - rule is not included in the route. The controller should - raise the \"ResolvedRefs\" condition on the Gateway - with the \"DegradedRoutes\" reason. The gateway status - for this route should be updated with a condition that - describes the error more specifically. \n Support: Custom" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - port: - description: "Port specifies the destination port number - to use for the backend referenced by the ServiceName - or BackendRef field. If unspecified, the destination - port in the request is used when forwarding to a backendRef - or serviceName. \n Support: Core" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - serviceName: - description: "ServiceName refers to the name of the Service - to forward matched requests to. When specified, this - takes the place of BackendRef. If both BackendRef and - ServiceName are specified, ServiceName will be given - precedence. \n If the referent cannot be found, the - rule is not included in the route. The controller should - raise the \"ResolvedRefs\" condition on the Gateway - with the \"DegradedRoutes\" reason. The gateway status - for this route should be updated with a condition that - describes the error more specifically. \n The protocol - to use is defined using AppProtocol field (introduced - in Kubernetes 1.18) in the Service resource. In the - absence of the AppProtocol field a `networking.x-k8s.io/app-protocol` - annotation on the BackendPolicy resource may be used - to define the protocol. If the AppProtocol field is - available, this annotation should not be used. The AppProtocol - field, when populated, takes precedence over the annotation - in the BackendPolicy resource. For custom backends, - it is encouraged to add a semantically-equivalent field - in the Custom Resource Definition. \n Support: Core" - maxLength: 253 - type: string - weight: - default: 1 - description: "Weight specifies the proportion of HTTP - requests forwarded to the backend referenced by the - ServiceName or BackendRef field. This is computed as - weight/(sum of all weights in this ForwardTo list). - For non-zero values, there may be some epsilon from - the exact proportion defined here depending on the precision - an implementation supports. Weight is not a percentage - and the sum of weights does not need to equal 100. \n - If only one backend is specified and it has a weight - greater than 0, 100% of the traffic is forwarded to - that backend. If weight is set to 0, no traffic should - be forwarded for this entry. If unspecified, weight - defaults to 1. \n Support: Extended" - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - type: object - maxItems: 16 - minItems: 1 - type: array - matches: - description: "Matches define conditions used for matching the - rule against incoming UDP connections. Each match is independent, - i.e. this rule will be matched if **any** one of the matches - is satisfied. If unspecified (i.e. empty), this Rule will - match all requests for the associated Listener. \n Each client - request MUST map to a maximum of one route rule. If a request - matches multiple rules, matching precedence MUST be determined - in order of the following criteria, continuing on ties: \n - * The most specific match specified by ExtensionRef. Each - implementation that supports ExtensionRef may have different - ways of determining the specificity of the referenced extension. - \n If ties still exist across multiple Routes, matching precedence - MUST be determined in order of the following criteria, continuing - on ties: \n * The oldest Route based on creation timestamp. - For example, a Route with a creation timestamp of \"2020-09-08 - 01:02:03\" is given precedence over a Route with a creation - timestamp of \"2020-09-08 01:02:04\". * The Route appearing - first in alphabetical order by \"/\". For - example, foo/bar is given precedence over foo/baz. \n If - ties still exist within the Route that has been given precedence, - matching precedence MUST be granted to the first matching - rule meeting the above criteria." - items: - description: UDPRouteMatch defines the predicate used to match - packets to a given action. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific - extension to the \"match\" behavior. For example, resource - \"myudproutematcher\" in group \"networking.acme.io\". - If the referent cannot be found, the rule is not included - in the route. The controller should raise the \"ResolvedRefs\" - condition on the Gateway with the \"DegradedRoutes\" - reason. The gateway status for this route should be - updated with a condition that describes the error more - specifically. \n Support: Custom" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - minLength: 1 - type: string - kind: - description: Kind is kind of the referent. - maxLength: 253 - minLength: 1 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - type: object - maxItems: 8 - type: array - required: - - forwardTo - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - rules - type: object - status: - description: Status defines the current state of UDPRoute. - properties: - gateways: - description: "Gateways is a list of Gateways that are associated with - the route, and the status of the route with respect to each Gateway. - When a Gateway selects this route, the controller that manages the - Gateway must add an entry to this list when the controller first - sees the route and should update the entry as appropriate when the - route is modified. \n A maximum of 100 Gateways will be represented - in this list. If this list is full, there may be additional Gateways - using this Route that are not included in the list. An empty list - means the route has not been admitted by any Gateway." - items: - description: RouteGatewayStatus describes the status of a route - with respect to an associated Gateway. - properties: - conditions: - description: Conditions describes the status of the route with - respect to the Gateway. The "Admitted" condition must always - be specified by controllers to indicate whether the route - has been admitted or rejected by the Gateway, and why. Note - that the route's availability is also subject to the Gateway's - own status conditions and listener status. - items: - description: "Condition contains details for one aspect of - the current state of this API Resource. --- This struct - is intended for direct use as an array at the field path - .status.conditions. For example, type FooStatus struct{ - \ // Represents the observations of a foo's current state. - \ // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // - +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should - be when the underlying condition changed. If that is - not known, then using the time when the API field changed - is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, - if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the - current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier - indicating the reason for the condition's last transition. - Producers of specific condition types may define expected - values and meanings for this field, and whether the - values are considered a guaranteed API. The value should - be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across - resources like Available, but because arbitrary conditions - can be useful (see .node.status.conditions), the ability - to deconflict is important. The regex it matches is - (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - gatewayRef: - description: GatewayRef is a reference to a Gateway object that - is associated with the route. - properties: - controller: - description: "Controller is a domain/path string that indicates - the controller implementing the Gateway. This corresponds - with the controller field on GatewayClass. \n Example: - \"acme.io/gateway-controller\". \n The format of this - field is DOMAIN \"/\" PATH, where DOMAIN and PATH are - valid Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names)." - maxLength: 253 - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: Namespace is the namespace of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - name - - namespace - type: object - required: - - gatewayRef - type: object - maxItems: 100 - type: array - required: - - gateways - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/cli/pkg/cli_init/templates/terraform.tfvars.tmpl b/cli/pkg/cli_init/templates/terraform.tfvars.tmpl index a56af290..b21f89b0 100644 --- a/cli/pkg/cli_init/templates/terraform.tfvars.tmpl +++ b/cli/pkg/cli_init/templates/terraform.tfvars.tmpl @@ -1,31 +1,28 @@ -## Base Config +## VPC Config +shared_vpc = "{{.VpcType}}" +vpc_name = "{{.VpcName}}" +vpc_project_id = "{{.VpcProjectId}}" +vpc_ip_range_pods_name = "{{.VpcPodCidrName}}" +vpc_ip_range_services_name = "{{.VpcSvcCidrName}}" + +## Fleet Config +config_sync_repo = "{{.ConfigSyncRepo}}" +config_sync_repo_branch = "{{.ConfigSyncRepoBranch}}" +config_sync_repo_dir = "{{.ConfigSyncRepoDir}}" + +## Clusters Base Config regional_clusters = "{{.RegionalClusters}}" -region = "{{.Region}}" +authenticator_security_group = "{{.AuthenticatorSecurityGroup}}" project_id = "{{.ClustersProjectId}}" -governance_project_id = "{{.GovernanceProjectId}}" -config_sync = "{{.ConfigSync}}" -config_sync_repo = "{{.ConfigSyncRepo}}" -policy_controller = "{{.PolicyController}}" +fleet_project = "{{.FleetProjectId}}" private_endpoint = "{{.PrivateEndpoint}}" release_channel = "{{.ReleaseChannel}}" initial_node_count = "{{.InitialNodeCount}}" min_node_count = "{{.MinNodeCount}}" max_node_count = "{{.MaxNodeCount}}" -windows_nodepool = "{{.EnableWindowsNodepool}}" -preemptible_nodes = "{{.EnablePreemptibleNodepool}}" -multi_cluster_gateway = "{{.MultiClusterGateway}}" -anthos_service_mesh = "{{.AnthosServiceMesh}}" +default_nodepool_os = "{{.DefaultNodepoolOs}}" tf_module_repo = "{{.TFModuleRepo}}" tf_module_branch = "{{.TFModuleBranch}}" -gke_module_bypass = "{{.GKEModuleBypass}}" - -## VPC Config -shared_vpc = "{{.VpcType}}" -vpc_name = "{{.VpcName}}" -vpc_project_id = "{{.VpcProjectId}}" -vpc_ip_range_pods_name = "{{.PodCidrName}}" -vpc_ip_range_services_name = "{{.SvcCidrName}}" -auth_cidr = "{{.AuthCIDR}}" ## Clusters Config cluster_config = { diff --git a/cli/pkg/config/config.go b/cli/pkg/config/config.go index 45973e16..9ac530f1 100644 --- a/cli/pkg/config/config.go +++ b/cli/pkg/config/config.go @@ -20,8 +20,6 @@ import ( "bufio" "bytes" "fmt" - "io/ioutil" - "net" "os" "strings" @@ -41,39 +39,33 @@ import ( // Config defines the config file structure. Has config-wide vars, and two sub-structs: // a VPC Config, and a slice of Cluster Configs, representing one or more GKE clusters. type Config struct { - RegionalClusters bool `yaml:"regionalClusters"` - Region string `yaml:"region"` - TerraformState string `yaml:"terraformState"` - SendAnalytics bool `yaml:"sendAnalytics"` - ClustersProjectID string `yaml:"clustersProjectId"` - GovernanceProjectID string `yaml:"governanceProjectId"` - ConfigSync bool `yaml:"configSync"` - ConfigSyncRepo string `yaml:"configSyncRepo"` - AnthosServiceMesh bool `yaml:"anthosServiceMesh"` - MultiClusterGateway bool `yaml:"multiClusterGateway"` - PolicyController bool `yaml:"policyController"` - PrivateEndpoint bool `yaml:"privateEndpoint"` - ReleaseChannel string `yaml:"releaseChannel"` - InitialNodeCount int `yaml:"initialNodeCount"` - MinNodeCount int `yaml:"minNodeCount` - MaxNodeCount int `yaml:"maxNodeCount` - EnableWindowsNodepool bool `yaml:"enableWindowsNodepool"` - EnablePreemptibleNodepool bool `yaml:"enablePreemptibleNodepool"` - DefaultNodepoolOS string `yaml:"defaultNodepoolOS"` - TFModuleRepo string `yaml:"tfModuleRepo"` - TFModuleBranch string `yaml:"tfModuleBranch"` - GKEModuleBypass bool `yaml:"gkeModuleBypass` - VpcConfig VpcConfig `yaml:"vpcConfig"` - ClustersConfig []ClusterConfig `yaml:"clustersConfig"` + RegionalClusters bool `yaml:"regionalClusters"` + AuthenticatorSecurityGroup string `yaml:"authenticatorSecurityGroup"` + TerraformState string `yaml:"terraformState"` + SendAnalytics bool `yaml:"sendAnalytics"` + ClustersProjectID string `yaml:"clustersProjectId"` + FleetProjectID string `yaml:"fleetProjectId"` + PrivateEndpoint bool `yaml:"privateEndpoint"` + ReleaseChannel string `yaml:"releaseChannel"` + InitialNodeCount int `yaml:"initialNodeCount"` + MinNodeCount int `yaml:"minNodeCount` + MaxNodeCount int `yaml:"maxNodeCount` + DefaultNodepoolOS string `yaml:"defaultNodepoolOS"` + TFModuleRepo string `yaml:"tfModuleRepo"` + TFModuleBranch string `yaml:"tfModuleBranch"` + ConfigSyncRepo string `yaml:"configSyncRepo"` + ConfigSyncRepoBranch string `yaml:"configSyncRepoBranch"` + ConfigSyncRepoDir string `yaml:"configSyncRepoDir"` + VpcConfig VpcConfig `yaml:"vpcConfig"` + ClustersConfig []ClusterConfig `yaml:"clustersConfig"` } type VpcConfig struct { - VpcName string `yaml:"vpcName"` - VpcType string `yaml:"vpcType"` - VpcProjectID string `yaml:"vpcProjectId"` - PodCIDRName string `yaml:"podCIDRName"` - SvcCIDRName string `yaml:"svcCIDRName"` - AuthCIDR string `yaml:"authCIDR"` + VpcName string `yaml:"vpcName"` + VpcType string `yaml:"vpcType"` + VpcProjectID string `yaml:"vpcProjectId"` + VpcPodCIDRName string `yaml:"vpcPodCIDRName"` + VpcSvcCIDRName string `yaml:"vpcSvcCIDRName"` } type ClusterConfig struct { @@ -110,38 +102,38 @@ func InitConf(cfgFile string) *Config { } } // Enable GCP APIs - Temporarily adding all apis needed to deal with flakes in the enable service TF module - serviceIds := []string{ - "iam.googleapis.com", - "storage.googleapis.com", - "compute.googleapis.com", - "logging.googleapis.com", - "monitoring.googleapis.com", - "containerregistry.googleapis.com", - "container.googleapis.com", - "binaryauthorization.googleapis.com", - "stackdriver.googleapis.com", - "iap.googleapis.com", - "cloudresourcemanager.googleapis.com", - "dns.googleapis.com", - "iamcredentials.googleapis.com", - "stackdriver.googleapis.com", - "cloudkms.googleapis.com", - } - enableService(conf.ClustersProjectID, serviceIds) - anthosServiceIds := []string{ - "anthos.googleapis.com", - "gkehub.googleapis.com", - "sourcerepo.googleapis.com", - "anthosconfigmanagement.googleapis.com", - "anthos.googleapis.com", - "gkehub.googleapis.com", - "multiclusterservicediscovery.googleapis.com", - "multiclusteringress.googleapis.com", - "trafficdirector.googleapis.com", - "mesh.googleapis.com", - "multiclustermetering.googleapis.com", - } - enableService(conf.ClustersProjectID, anthosServiceIds) + // serviceIds := []string{ + // "iam.googleapis.com", + // "storage.googleapis.com", + // "compute.googleapis.com", + // "logging.googleapis.com", + // "monitoring.googleapis.com", + // "containerregistry.googleapis.com", + // "container.googleapis.com", + // "binaryauthorization.googleapis.com", + // "stackdriver.googleapis.com", + // "iap.googleapis.com", + // "cloudresourcemanager.googleapis.com", + // "dns.googleapis.com", + // "iamcredentials.googleapis.com", + // "stackdriver.googleapis.com", + // "cloudkms.googleapis.com", + // } + // enableService(conf.ClustersProjectID, serviceIds) + // anthosServiceIds := []string{ + // "anthos.googleapis.com", + // "gkehub.googleapis.com", + // "sourcerepo.googleapis.com", + // "anthosconfigmanagement.googleapis.com", + // "anthos.googleapis.com", + // "gkehub.googleapis.com", + // "multiclusterservicediscovery.googleapis.com", + // "multiclusteringress.googleapis.com", + // "trafficdirector.googleapis.com", + // "mesh.googleapis.com", + // "multiclustermetering.googleapis.com", + // } + // enableService(conf.ClustersProjectID, anthosServiceIds) // Validate config err = ValidateConf(conf) @@ -207,7 +199,6 @@ func InitWithDefaults() (*Config, error) { } // populate default conf with user's project ID - config.GovernanceProjectID = projectId config.ClustersProjectID = projectId config.VpcConfig.VpcProjectID = projectId @@ -225,12 +216,6 @@ func ValidateConf(c *Config) error { // if err := validateNodeOS(c.DefaultNodepoolOS); err != nil { // return err // } - if err := validateConfigRegion(c.GovernanceProjectID, c.Region); err != nil { - return err - } - if c.PolicyController && !c.ConfigSync { - return fmt.Errorf("terraform constraints require that if Policy Controller is enabled, config Sync must also be enabled. please set configSync to true and retry.") - } if err := validateTFModuleRepo(c.TFModuleRepo); err != nil { return err } @@ -251,12 +236,6 @@ func ValidateConf(c *Config) error { // } // log.Printf("🌐 VPC name %s is valid + does not yet exist in VPC project %s\n", c.VpcConfig.VpcName, c.VpcConfig.VpcProjectID) - if !c.PrivateEndpoint { - if err := validateAuthCIDR(c.VpcConfig.AuthCIDR); err != nil { - return err - } - } - // Validate each ClusterConfig for i, cc := range c.ClustersConfig { // TODO - what is cluster type? why is line 125 here? @@ -270,9 +249,9 @@ func ValidateConf(c *Config) error { if err := validateMachineType(c.ClustersProjectID, cc.MachineType, cc.Zones); err != nil { return fmt.Errorf("ClustersConfig[%d]: %s", i, err) } - // if err := validateNodeOS(c.DefaultNodepoolOS); err != nil { - // return fmt.Errorf("ClustersConfig[%d]: %s", i, err) - // } + if err := validateNodeOS(c.DefaultNodepoolOS); err != nil { + return fmt.Errorf("ClustersConfig[%d]: %s", i, err) + } } } @@ -281,18 +260,18 @@ func ValidateConf(c *Config) error { } // verifies that field is a valid CIDR of format x.x.x.x/xx -func validateAuthCIDR(authCIDR string) error { - ip, ipNet, err := net.ParseCIDR(authCIDR) - if err != nil { - return fmt.Errorf("Auth CIDR %s is invalid: %v", authCIDR, err) - } - log.Infof("🌐 Valid CIDR: IP: %s, IPNet: %s", ip, ipNet) - return nil -} +// func validateAuthCIDR(authCIDR string) error { +// ip, ipNet, err := net.ParseCIDR(authCIDR) +// if err != nil { +// return fmt.Errorf("Auth CIDR %s is invalid: %v", authCIDR, err) +// } +// log.Infof("🌐 Valid CIDR: IP: %s, IPNet: %s", ip, ipNet) +// return nil +// } // https://cloud.google.com/kubernetes-engine/docs/concepts/node-images func validateNodeOS(nodeOS string) error { - validOS := []string{"cos", "cos_containerd", "ubuntu_containerd", "ubuntu", "windows_sac", "windows_sac_containerd", "windows_ltsc", "windows_ltsc_containerd"} + validOS := []string{"cos", "cos_containerd", "ubuntu_containerd", "ubuntu"} for _, os := range validOS { if nodeOS == os { @@ -306,43 +285,43 @@ func validateNodeOS(nodeOS string) error { // NOTE - the ListRegionsRequest client lib function is returning an empty list for any GCP // project. ListZones works fine. So for now, using ListZones result (where each zone has a region) // to bootstrap a list of valid regions. -func validateConfigRegion(projectID, region string) error { - ctx := context.Background() - c, err := compute.NewZonesRESTClient(ctx) - if err != nil { - return err - } - defer c.Close() - - req := &computepb.ListZonesRequest{ - Project: projectID, - } - it := c.List(ctx, req) - // Use zones to populate a map of valid regions for this project - regions := map[string]bool{} - for { - resp, err := it.Next() - if err == iterator.Done { - break - } - if err != nil { - return err - } - r := resp.GetRegion() - spl := strings.Split(r, "/") - if len(spl) < 2 { - return fmt.Errorf("Error validating region (%s) - GCP region (%s) is invalid\n", region, r) - } - sanitizedRegion := spl[len(spl)-1] - regions[sanitizedRegion] = true - } - - // check if Config.Region is in the map. - if _, ok := regions[region]; !ok { - return fmt.Errorf("Config-wide region %s not found. Must be one of: %v\n", region, regions) - } - return nil -} +// func validateConfigRegion(projectID, region string) error { +// ctx := context.Background() +// c, err := compute.NewZonesRESTClient(ctx) +// if err != nil { +// return err +// } +// defer c.Close() + +// req := &computepb.ListZonesRequest{ +// Project: projectID, +// } +// it := c.List(ctx, req) +// // Use zones to populate a map of valid regions for this project +// regions := map[string]bool{} +// for { +// resp, err := it.Next() +// if err == iterator.Done { +// break +// } +// if err != nil { +// return err +// } +// r := resp.GetRegion() +// spl := strings.Split(r, "/") +// if len(spl) < 2 { +// return fmt.Errorf("error validating region (%s) - GCP region (%s) is invalid\n", region, r) +// } +// sanitizedRegion := spl[len(spl)-1] +// regions[sanitizedRegion] = true +// } + +// // check if Config.Region is in the map. +// if _, ok := regions[region]; !ok { +// return fmt.Errorf("config-wide region %s not found. Must be one of: %v\n", region, regions) +// } +// return nil +// } // Validate region + zone for specific clusters. func validateRegionAndZone(projectId string, clusterRegion string, clusterZones []string) error { @@ -386,20 +365,20 @@ func validateRegionAndZone(projectId string, clusterRegion string, clusterZones // Region must exist if _, ok := regions[clusterRegion]; !ok { - return fmt.Errorf("Region %s invalid - must be one of: %v", clusterRegion, regions) + return fmt.Errorf("region %s invalid - must be one of: %v", clusterRegion, regions) } // Zone must exist for _, clusterZone := range clusterZones { if _, ok := zones[clusterZone]; !ok { - return fmt.Errorf("Zone %s invalid - must be one of: %v", clusterZone, zones) + return fmt.Errorf("zone %s invalid - must be one of: %v", clusterZone, zones) } } // Zone must be in the right region for _, clusterZone := range clusterZones { if zoneRegion, _ := zones[clusterZone]; zoneRegion != clusterRegion { - return fmt.Errorf("Zone %s must be in region %s, not region %s", clusterZone, zoneRegion, clusterRegion) + return fmt.Errorf("zone %s must be in region %s, not region %s", clusterZone, zoneRegion, clusterRegion) } } return nil @@ -434,7 +413,7 @@ func validateMachineType(projectId string, machineType string, zones []string) e validMachineTypes = append(validMachineTypes, *resp.Name) _ = resp } - return fmt.Errorf("Machine type %s is invalid, must be one of: %v", machineType, validMachineTypes) + return fmt.Errorf("machine type %s is invalid, must be one of: %v", machineType, validMachineTypes) } return nil } @@ -506,7 +485,7 @@ func enableService(projectId string, serviceIds []string) { } func setTfModuleRepo(tfRepo string, tfBranch string) error { - files := []string{"cluster_build/main.tf", "shared_vpc/main.tf"} + files := []string{"clusters/main.tf", "network/main.tf", "fleet/main.tf"} for _, file := range files { err := replaceWord("{{.TFModuleRepo}}", file, tfRepo) if err != nil { @@ -522,12 +501,12 @@ func setTfModuleRepo(tfRepo string, tfBranch string) error { } func replaceWord(word string, file string, tfRepo string) error { - input, err := ioutil.ReadFile(file) + input, err := os.ReadFile(file) if err != nil { log.Fatalf("error reading file: %s", err) } output := bytes.Replace(input, []byte(word), []byte(tfRepo), -1) - if err = ioutil.WriteFile(file, output, 0666); err != nil { + if err = os.WriteFile(file, output, 0666); err != nil { log.Fatalf("error writing file: %s", err) } return nil diff --git a/cli/pkg/config/tf_state.go b/cli/pkg/config/tf_state.go index 03c50d9b..f78738b2 100644 --- a/cli/pkg/config/tf_state.go +++ b/cli/pkg/config/tf_state.go @@ -27,20 +27,31 @@ import ( "github.com/thanhpk/randstr" ) -func CheckTfStateType(conf *Config, bucketNameClusters string, bucketNameSharedVPC string) error { +func CheckTfStateType(conf *Config, bucketNameNetwork string, bucketNameFleet string, bucketNameClusters string) error { if conf.TerraformState == "cloud" { - if conf.VpcConfig.VpcType == "shared" { - if bucketNameSharedVPC == "" { - bucketNameSharedVPC = "tf-state-sharedvpc-" + strings.ToLower(randstr.String(6)) - err := createTfStorage(conf.VpcConfig.VpcProjectID, bucketNameSharedVPC) - if err != nil { - return err - } + if bucketNameNetwork == "" { + bucketNameNetwork = "tf-state-network-" + strings.ToLower(randstr.String(6)) + err := createTfStorage(conf.ClustersProjectID, bucketNameNetwork) + if err != nil { + return err } - err := createTfBackend(bucketNameSharedVPC, "shared_vpc/backend.tf") + log.Infof("✅ Created a bucket for the Network TF State: %s", bucketNameNetwork) + } + err := createTfBackend(bucketNameNetwork, "network/backend.tf") + if err != nil { + return err + } + if bucketNameFleet == "" { + bucketNameFleet = "tf-state-fleet-" + strings.ToLower(randstr.String(6)) + err := createTfStorage(conf.ClustersProjectID, bucketNameFleet) if err != nil { return err } + log.Infof("✅ Created a bucket for the Fleet TF State: %s", bucketNameFleet) + } + err = createTfBackend(bucketNameFleet, "fleet/backend.tf") + if err != nil { + return err } if bucketNameClusters == "" { bucketNameClusters = "tf-state-clusters-" + strings.ToLower(randstr.String(6)) @@ -48,9 +59,9 @@ func CheckTfStateType(conf *Config, bucketNameClusters string, bucketNameSharedV if err != nil { return err } - log.Infof("✅ Created a bucket for the Clusters TF State: %s", bucketNameClusters) + log.Infof("✅ Created a bucket for the Clusters TF State: %s", bucketNameFleet) } - err := createTfBackend(bucketNameClusters, "cluster_build/backend.tf") + err = createTfBackend(bucketNameClusters, "clusters/backend.tf") if err != nil { return err } diff --git a/cli/pkg/config/tfvars_generator.go b/cli/pkg/config/tfvars_generator.go index 6916ec3e..f72f5064 100644 --- a/cli/pkg/config/tfvars_generator.go +++ b/cli/pkg/config/tfvars_generator.go @@ -18,7 +18,6 @@ package config import ( "bytes" - "io/ioutil" "os" "strings" "text/template" @@ -30,26 +29,21 @@ func GenerateTfvars(conf *Config) { vars := make(map[string]interface{}) // Set base config vars - vars["Region"] = conf.Region vars["RegionalClusters"] = conf.RegionalClusters + vars["AuthenticatorSecurityGroup"] = conf.AuthenticatorSecurityGroup vars["ClustersProjectId"] = conf.ClustersProjectID - vars["GovernanceProjectId"] = conf.GovernanceProjectID - vars["ConfigSync"] = conf.ConfigSync - vars["ConfigSyncRepo"] = conf.ConfigSyncRepo - vars["PolicyController"] = conf.PolicyController + vars["FleetProjectId"] = conf.FleetProjectID vars["PrivateEndpoint"] = conf.PrivateEndpoint vars["ReleaseChannel"] = conf.ReleaseChannel vars["InitialNodeCount"] = conf.InitialNodeCount vars["MinNodeCount"] = conf.MinNodeCount vars["MaxNodeCount"] = conf.MaxNodeCount vars["DefaultNodepoolOS"] = conf.DefaultNodepoolOS - vars["EnableWindowsNodepool"] = conf.EnableWindowsNodepool - vars["EnablePreemptibleNodepool"] = conf.EnablePreemptibleNodepool - vars["MultiClusterGateway"] = conf.MultiClusterGateway - vars["AnthosServiceMesh"] = conf.AnthosServiceMesh vars["TFModuleRepo"] = conf.TFModuleRepo vars["TFModuleBranch"] = conf.TFModuleBranch - vars["GKEModuleBypass"] = conf.GKEModuleBypass + vars["ConfigSyncRepo"] = conf.ConfigSyncRepo + vars["ConfigSyncRepoBranch"] = conf.ConfigSyncRepoBranch + vars["ConfigSyncRepoDir"] = conf.ConfigSyncRepoDir // Set vpc config vars if conf.VpcConfig.VpcType == "standalone" { @@ -59,9 +53,8 @@ func GenerateTfvars(conf *Config) { } vars["VpcName"] = conf.VpcConfig.VpcName vars["VpcProjectId"] = conf.VpcConfig.VpcProjectID - vars["PodCidrName"] = conf.VpcConfig.PodCIDRName - vars["SvcCidrName"] = conf.VpcConfig.SvcCIDRName - vars["AuthCIDR"] = conf.VpcConfig.AuthCIDR + vars["VpcPodCidrName"] = conf.VpcConfig.VpcPodCIDRName + vars["VpcSvcCidrName"] = conf.VpcConfig.VpcSvcCIDRName // First phase of templating tfvars (base and VPC configs) tmpl, err := template.ParseFiles("templates/terraform.tfvars.tmpl") @@ -102,12 +95,12 @@ func GenerateTfvars(conf *Config) { files := []string{"terraform.tfvars", "clusters.tf"} var buf bytes.Buffer for _, file := range files { - b, err := ioutil.ReadFile(file) + b, err := os.ReadFile(file) if err != nil { log.Fatalf("error reading %s: %s", file, err) } buf.Write(b) - err = ioutil.WriteFile("terraform.tfvars", buf.Bytes(), 0644) + err = os.WriteFile("terraform.tfvars", buf.Bytes(), 0644) if err != nil { log.Fatalf("error writing to %s: %s", file, err) } diff --git a/cli/pkg/lifecycle/get_credentials.go b/cli/pkg/lifecycle/get_credentials.go new file mode 100644 index 00000000..4e0dfb51 --- /dev/null +++ b/cli/pkg/lifecycle/get_credentials.go @@ -0,0 +1,128 @@ +package lifecycle + +import ( + "context" + "fmt" + "strings" + + gateway "cloud.google.com/go/gkeconnect/gateway/apiv1" + gatewaypb "cloud.google.com/go/gkeconnect/gateway/apiv1/gatewaypb" + log "github.com/sirupsen/logrus" + "google.golang.org/api/gkehub/v1" + "google.golang.org/api/option" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" +) + +// GenerateKubeConfig generates a kubeconfig with contexts for all clusters in the GKE Demo Environment. +func GenerateKubeConfig(fleetProjectId string) (*clientcmdapi.Config, error) { + + // Create a GKE Hub client. + ctx := context.Background() + hubClient, err := gkehub.NewService(ctx, option.WithEndpoint("https://gkehub.googleapis.com/v1")) + if err != nil { + log.Errorf("Failed to create GKE Hub client: %v", err) + return nil, err + } + + // Get a list of all GKE Fleet memberships in the project. + parent := fmt.Sprintf("projects/%s/locations/-", fleetProjectId) + req := hubClient.Projects.Locations.Memberships.List(parent) + memberships, err := req.Do() + if err != nil { + log.Errorf("Failed to list memberships: %v", err) + return nil, err + } + + // Create a new kubeconfig. + config := clientcmdapi.NewConfig() + + // Keep track of failed memberships + failedMemberships := []string{} + + // Generate credentials for each membership + for _, membership := range memberships.Resources { + membershipName := membership.Name + membershipLocation := extractLocation(membershipName) + + // Create a Gateway Control Client. + endpoint := "connectgateway.googleapis.com" + if isRegionalMembership(membershipName) { + endpoint = membershipLocation + "-" + endpoint // Use regional endpoint + } else { + endpoint = "connectgateway.googleapis.com" // Use global endpoint + } + + // Create a Gateway Control Client with the correct endpoint + ctx2 := context.Background() + gcc, err := gateway.NewGatewayControlClient(ctx2, option.WithEndpoint(endpoint)) + if err != nil { + log.Errorf("Failed to create gateway control client for %s: %v", membershipName, err) + failedMemberships = append(failedMemberships, membershipName) + continue // Skip to the next membership + } + defer gcc.Close() + + log.Infof("Generating credentials for membership: %s", membershipName) + + // Generate credentials for each membership + req := &gatewaypb.GenerateCredentialsRequest{ + Name: membershipName, + } + resp, err := gcc.GenerateCredentials(ctx, req) + if err != nil { + log.Errorf("Failed to generate credentials for membership %s: Endpoint: %s, Error: %v", membershipName, endpoint, err) + failedMemberships = append(failedMemberships, membershipName) + continue // Skip to the next membership + } + + // Get the kubeconfig from the response + kc := resp.GetKubeconfig() + + // Parse the kubeconfig + parsedConfig, err := clientcmd.Load(kc) + if err != nil { + log.Errorf("Failed to load kubeconfig for membership %s: %v", membershipName, err) + return nil, err + } + + // Merge the parsed config into the main config + for key, context := range parsedConfig.Contexts { + config.Contexts[key] = context + } + for key, cluster := range parsedConfig.Clusters { + config.Clusters[key] = cluster + } + for key, authInfo := range parsedConfig.AuthInfos { + config.AuthInfos[key] = authInfo + } + } + + // Write the kubeconfig to a file. + err = clientcmd.WriteToFile(*config, "kubeconfig") + if err != nil { + log.Errorf("Failed to write kubeconfig: %v", err) + return nil, err + } + if len(failedMemberships) > 0 { + log.Warnf("Failed to generate credentials for the following memberships: %v", failedMemberships) + } else { + log.Info("Kubeconfig generated successfully.") + } + return config, err +} + +func isRegionalMembership(membership string) bool { + // A membership is regional if the membership.name string does not contain "locations/global" + return !strings.Contains(membership, "locations/global") +} + +func extractLocation(path string) string { + parts := strings.Split(path, "/") + for i, part := range parts { + if part == "locations" && i+1 < len(parts) { + return parts[i+1] + } + } + return "" +} diff --git a/cli/pkg/lifecycle/kubernetes_helpers.go b/cli/pkg/lifecycle/kubernetes_helpers.go deleted file mode 100644 index 51211348..00000000 --- a/cli/pkg/lifecycle/kubernetes_helpers.go +++ /dev/null @@ -1,176 +0,0 @@ -/* -Copyright © 2020 Google Inc. - -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 lifecycle - -import ( - "context" - "fmt" - "gkekitctl/pkg/config" - "strconv" - - log "github.com/sirupsen/logrus" - "google.golang.org/api/cloudresourcemanager/v1" - "google.golang.org/api/container/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" - "k8s.io/client-go/tools/clientcmd" - "k8s.io/client-go/tools/clientcmd/api" -) - -func GenerateKubeConfig(conf *config.Config) (*api.Config, error) { - projectId := conf.ClustersProjectID - projectNumber, err := GetProjectNumber(projectId) - if err != nil { - return api.NewConfig(), fmt.Errorf("GetProjectNumber: %w", err) - } - - log.Infof("Clusters Project ID is %s", projectId) - ctx := context.Background() - - svc, err := container.NewService(ctx) - if err != nil { - return api.NewConfig(), fmt.Errorf("container.NewService: %w", err) - } - - // Basic config structure - ret := api.Config{ - APIVersion: "v1", - Kind: "Config", - Clusters: map[string]*api.Cluster{}, // Clusters is a map of referencable names to cluster configs - AuthInfos: map[string]*api.AuthInfo{}, // AuthInfos is a map of referencable names to user configs - Contexts: map[string]*api.Context{}, // Contexts is a map of referencable names to context configs - } - - // Ask Google for a list of all kube clusters in the given project. - resp, err := svc.Projects.Zones.Clusters.List(projectId, "-").Context(ctx).Do() - if err != nil { - return &ret, fmt.Errorf("clusters list project=%s: %w", projectId, err) - } - - for _, f := range resp.Clusters { - name := fmt.Sprintf("connectgateway_%s_global_%s-membership", projectId, f.Name) - server := fmt.Sprintf("https://connectgateway.googleapis.com/v1beta1/projects/%s/locations/global/gkeMemberships/%s-membership", projectNumber, f.Name) - log.Infof("Connecting to cluster: %s,", name) - - ret.Clusters[name] = &api.Cluster{ - Server: server, - } - // Just reuse the context name as an auth name. - ret.Contexts[name] = &api.Context{ - Cluster: name, - AuthInfo: name, - } - // GCP specific configation; use cloud platform scope. - ret.AuthInfos[name] = &api.AuthInfo{ - AuthProvider: &api.AuthProviderConfig{ - Name: "gcp", - }, - } - } - - // Write kubeconfig to YAML file - err = clientcmd.WriteToFile(ret, "kubeconfig") - if err != nil { - return &ret, err - } - return &ret, nil -} - -// Verify `kubectl get` connectivity to all clusters -func ListNamespaces(kubeConfig *api.Config) error { - ctx := context.Background() - - // Just list all the namespaces found in the project to the API. - for clusterName := range kubeConfig.Clusters { - - cfg, err := clientcmd.NewNonInteractiveClientConfig(*kubeConfig, clusterName, &clientcmd.ConfigOverrides{CurrentContext: clusterName}, nil).ClientConfig() - if err != nil { - return fmt.Errorf("failed to create Kubernetes configuration cluster=%s: %w", clusterName, err) - } - - k8s, err := kubernetes.NewForConfig(cfg) - if err != nil { - return fmt.Errorf("failed to create Kubernetes client cluster=%s: %w", clusterName, err) - } - - ns, err := k8s.CoreV1().Namespaces().List(ctx, metav1.ListOptions{}) - if err != nil { - return fmt.Errorf("failed to list namespaces cluster=%s: %w", clusterName, err) - } - - log.Infof("🌎 %d Namespaces found in cluster=%s", len(ns.Items), clusterName) - } - - return nil -} - -func GetProjectNumber(project_id string) (string, error) { - ctx := context.Background() - cloudresourcemanagerService, err := cloudresourcemanager.NewService(ctx) - if err != nil { - fmt.Errorf("cloudresourcemanager.NewService: %w", err) - } - project, err := cloudresourcemanagerService.Projects.Get(project_id).Do() - if err != nil { - fmt.Errorf("cloudresourcemanager.NewService: %w", err) - } - return strconv.FormatInt(project.ProjectNumber, 10), nil -} - -// Kubectl apply using client.go -// func Apply(config *rest.Config, clusterName string, fileName []byte) error { - -// dynamicClient, err := dynamic.NewForConfig(config) -// if err != nil { -// return fmt.Errorf("failed to setup dynamic client for cluster=%s: %w", clusterName, err) -// } -// discoveryClient, err := discovery.NewDiscoveryClientForConfig(config) -// if err != nil { -// return fmt.Errorf("failed to setup diecovery client for cluster=%s: %w", clusterName, err) -// } - -// applyOptions := apply.NewApplyOptions(dynamicClient, discoveryClient) -// if err := applyOptions.Apply(context.TODO(), fileName); err != nil { -// return fmt.Errorf("failed to create apply gateway crd cluster=%s: %w", clusterName, err) -// } - -// return nil -// } - -// check namespace and watch if not created -// func WaitForNamespace(k8s *kubernetes.Clientset, ctx context.Context, nameSpace string, clusterName string) error { -// ns, err := k8s.CoreV1().Namespaces().Get(ctx, "config-management-system", metav1.GetOptions{}) -// timeout := int64(120) -// if clientgo.IsNotFound(err) { -// log.Infof("%s was not found on cluster=%s: %v", nameSpace, clusterName, err) -// ns, err := k8s.CoreV1().Namespaces().Watch(ctx, metav1.ListOptions{ -// FieldSelector: "metadata.name=" + nameSpace, -// Watch: true, -// TimeoutSeconds: &timeout, -// }) -// if err != nil { -// return fmt.Errorf("failed watch on namespace %s on cluster=%s: %v", nameSpace, clusterName, err) -// } -// log.Infof("%s is ready on cluster: %s", ns, clusterName) - -// } else if err != nil { -// return fmt.Errorf("%s namespace on cluster=%s: %w", nameSpace, clusterName, err) -// } -// log.Infof("%s is ready on cluster: %s", ns, clusterName) -// return nil -// } diff --git a/cli/pkg/lifecycle/tf_delete.go b/cli/pkg/lifecycle/tf_delete.go index 3a55bcf2..b1574a03 100644 --- a/cli/pkg/lifecycle/tf_delete.go +++ b/cli/pkg/lifecycle/tf_delete.go @@ -18,7 +18,6 @@ package lifecycle import ( "context" - "io/ioutil" "log" "os" @@ -27,13 +26,13 @@ import ( ) func DestroyTF(tfDir string) { - tmpDir, err := ioutil.TempDir("", "tfinstall") + tmpDir, err := os.MkdirTemp("", "tfinstall") if err != nil { log.Fatalf("error creating temp dir: %s", err) } defer os.RemoveAll(tmpDir) - execPath, err := tfinstall.Find(context.Background(), tfinstall.ExactVersion("1.3.2", tmpDir)) + execPath, err := tfinstall.Find(context.Background(), tfinstall.ExactVersion("1.9.5", tmpDir)) if err != nil { log.Fatalf("error locating Terraform binary: %s", err) } diff --git a/cli/pkg/lifecycle/tf_deploy.go b/cli/pkg/lifecycle/tf_deploy.go index 33e17b16..9babe986 100644 --- a/cli/pkg/lifecycle/tf_deploy.go +++ b/cli/pkg/lifecycle/tf_deploy.go @@ -18,7 +18,6 @@ package lifecycle import ( "context" - "io/ioutil" "os" log "github.com/sirupsen/logrus" @@ -28,13 +27,13 @@ import ( ) func InitTF(tfDir string) { - tmpDir, err := ioutil.TempDir("", "tfinstall") + tmpDir, err := os.MkdirTemp("", "tfinstall") if err != nil { log.Fatalf("error creating temp dir: %s", err) } defer os.RemoveAll(tmpDir) - execPath, err := tfinstall.Find(context.Background(), tfinstall.ExactVersion("1.1.9", tmpDir)) + execPath, err := tfinstall.Find(context.Background(), tfinstall.ExactVersion("1.9.5", tmpDir)) if err != nil { log.Fatalf("error locating Terraform binary: %s", err) } @@ -66,13 +65,13 @@ func InitTF(tfDir string) { } func ApplyTF(tfDir string) { - tmpDir, err := ioutil.TempDir("", "tfinstall") + tmpDir, err := os.MkdirTemp("", "tfinstall") if err != nil { log.Fatalf("error creating temp dir: %s", err) } defer os.RemoveAll(tmpDir) - execPath, err := tfinstall.Find(context.Background(), tfinstall.ExactVersion("1.3.2", tmpDir)) + execPath, err := tfinstall.Find(context.Background(), tfinstall.ExactVersion("1.9.5", tmpDir)) if err != nil { log.Fatalf("error locating Terraform binary: %s", err) } diff --git a/terraform/modules/acm/acm.tf b/terraform/modules/acm/acm.tf deleted file mode 100644 index 2e8de479..00000000 --- a/terraform/modules/acm/acm.tf +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * 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. - */ - -// Defines vars so that we can pass them in from cluster_build/main.tf from the overall tfvars -variable "project_id" { -} - -variable "config_sync_repo" { -} - -variable "policy_controller" { -} - -variable "cluster_config" { -} - -variable "email" { -} - -locals { - acm_service_account = "acm-service-account" - acm_service_account_email = "${local.acm_service_account}@${var.project_id}.iam.gserviceaccount.com" -} - -// https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/sourcerepo_repository -// Create 1 centralized Cloud Source Repo, that all GKE clusters will sync to -resource "google_sourcerepo_repository" "gke-poc-config-sync" { - name = var.config_sync_repo - project = var.project_id -} - -// create ACM service account -module "service_accounts" { - source = "terraform-google-modules/service-accounts/google" - version = "~> 4.2.0" - project_id = var.project_id - display_name = "ACM service account" - names = [local.acm_service_account] - project_roles = ["${var.project_id}=>roles/source.reader"] -} - -module "service_account-iam-bindings" { - depends_on = [ - resource.google_gke_hub_feature_membership.feature_member, - ] - source = "terraform-google-modules/iam/google//modules/service_accounts_iam" - - service_accounts = [local.acm_service_account_email] - project = var.project_id - bindings = { - "roles/iam.workloadIdentityUser" = [ - "serviceAccount:${var.project_id}.svc.id.goog[config-management-system/root-reconciler]", - ] - } -} - - -// enable ACM project-wide -resource "google_gke_hub_feature" "acm" { - name = "configmanagement" - location = "global" - project = var.project_id - provider = google-beta -} - -// install config sync -// https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/gke_hub_feature_membership#git -resource "google_gke_hub_feature_membership" "feature_member" { - provider = google-beta - depends_on = [ - resource.google_gke_hub_feature.acm, - ] - // https://cloud.google.com/anthos-config-management/docs/how-to/installing-config-sync#gcloud - for_each = var.cluster_config - location = "global" - project = var.project_id - feature = "configmanagement" - membership = "projects/${var.project_id}/locations/global/memberships/${each.key}-membership" - configmanagement { - version = "1.14.2" - config_sync { - git { - sync_repo = "https://source.developers.google.com/p/${var.project_id}/r/gke-poc-config-sync" - policy_dir = "/" - sync_branch = "main" - secret_type = "gcpserviceaccount" - gcp_service_account_email = local.acm_service_account_email - } - source_format = "unstructured" - } - policy_controller { - enabled = var.policy_controller - template_library_installed = var.policy_controller - } - } -} diff --git a/terraform/modules/asm/asm.tf b/terraform/modules/asm/asm.tf deleted file mode 100644 index bd2deb2e..00000000 --- a/terraform/modules/asm/asm.tf +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * 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. - */ - -// Defines vars so that we can pass them in from cluster_build/main.tf from the overall tfvars -variable "cluster_config" {} -variable "project_id" {} - -resource "google_gke_hub_feature" "mesh" { - name = "servicemesh" - project = var.project_id - location = "global" - provider = google-beta -} - -// Install asm crds on each cluster -resource "null_resource" "install_mesh" { - for_each = var.cluster_config - depends_on = [ - google_gke_hub_feature.mesh, - ] - provisioner "local-exec" { - interpreter = ["bash", "-exc"] - command = "scripts/install_mesh.sh" - working_dir = path.module - environment = { - CLUSTER = each.key - LOCATION = each.value.region - PROJECT_ID = var.project_id - } - } -} \ No newline at end of file diff --git a/terraform/modules/asm/manifests/asm-control-plane-revision.yaml b/terraform/modules/asm/manifests/asm-control-plane-revision.yaml deleted file mode 100644 index ed8ec186..00000000 --- a/terraform/modules/asm/manifests/asm-control-plane-revision.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: mesh.cloud.google.com/v1alpha1 -kind: ControlPlaneRevision -metadata: - name: asm-managed - namespace: istio-system - labels: - mesh.cloud.google.com/managed-cni-enabled: "true" -spec: - type: managed_service - channel: regular \ No newline at end of file diff --git a/terraform/modules/asm/manifests/asm-options.yaml b/terraform/modules/asm/manifests/asm-options.yaml deleted file mode 100644 index acd6b3ca..00000000 --- a/terraform/modules/asm/manifests/asm-options.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -metadata: - name: asm-options - namespace: istio-system -data: - multicluster_mode: connected - mesh: |- - accessLogFile: /dev/stdout - accessLogEncoding: JSON - defaultConfig: - tracing: - stackdriver: {} -kind: ConfigMap \ No newline at end of file diff --git a/terraform/modules/asm/manifests/clusterole-istio-reader-sa-clusterrole.yaml b/terraform/modules/asm/manifests/clusterole-istio-reader-sa-clusterrole.yaml deleted file mode 100644 index b2cd6f87..00000000 --- a/terraform/modules/asm/manifests/clusterole-istio-reader-sa-clusterrole.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: istio-reader-service-account-clusterrole - labels: - app: istio-reader - release: istio -rules: - - apiGroups: ["config.istio.io", "security.istio.io", "networking.istio.io", "authentication.istio.io", "apiextensions.k8s.io"] - resources: ["*"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["endpoints", "pods", "services", "nodes", "replicationcontrollers", "namespaces", "secrets"] - verbs: ["get", "list", "watch"] - - apiGroups: ["discovery.k8s.io"] - resources: ["endpointslices"] - verbs: ["get", "list", "watch"] - - apiGroups: ["apps"] - resources: ["replicasets"] - verbs: ["get", "list", "watch"] - - apiGroups: ["authentication.k8s.io"] - resources: ["tokenreviews"] - verbs: ["create"] - - apiGroups: ["authorization.k8s.io"] - resources: ["subjectaccessreviews"] - verbs: ["create"] - \ No newline at end of file diff --git a/terraform/modules/asm/manifests/clusterolebinding-istio-reader-sa-clusterrolebinding.yaml b/terraform/modules/asm/manifests/clusterolebinding-istio-reader-sa-clusterrolebinding.yaml deleted file mode 100644 index 09caa53c..00000000 --- a/terraform/modules/asm/manifests/clusterolebinding-istio-reader-sa-clusterrolebinding.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: istio-reader-service-account-clusterrolebinding - labels: - app: istio-reader - release: istio -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: istio-reader-service-account-clusterrole -subjects: - - kind: ServiceAccount - name: istio-reader-service-account - namespace: istio-system \ No newline at end of file diff --git a/terraform/modules/asm/manifests/istio-system-ns.yaml b/terraform/modules/asm/manifests/istio-system-ns.yaml deleted file mode 100644 index ceb257ed..00000000 --- a/terraform/modules/asm/manifests/istio-system-ns.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: istio-system - namespace: istio-system \ No newline at end of file diff --git a/terraform/modules/asm/manifests/ksa-istio-reader-sa.yaml b/terraform/modules/asm/manifests/ksa-istio-reader-sa.yaml deleted file mode 100644 index d65170c3..00000000 --- a/terraform/modules/asm/manifests/ksa-istio-reader-sa.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: istio-reader-service-account - namespace: istio-system diff --git a/terraform/modules/asm/scripts/install_mesh.sh b/terraform/modules/asm/scripts/install_mesh.sh deleted file mode 100755 index 1e5c33d1..00000000 --- a/terraform/modules/asm/scripts/install_mesh.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -# Verify variables -echo -e "Project is ${PROJECT_ID}" -echo -e "CLUSTER is ${CLUSTER}" -echo -e "LOCATION is ${LOCATION}" -#echo -e "ASM_PACKAGE is ${ASM_PACKAGE}" - -export WORKDIR=`pwd` -kubeconfig=tempkubeconfig$RANDOM -echo -e "Adding cluster ${CLUSTER} to kubeconfig located at ${WORKDIR}/tempkubeconfig" -echo -e "Creating tempkubeconfig." -rm ${WORKDIR}/${kubeconfig} -touch ${WORKDIR}/${kubeconfig} -export KUBECONFIG=${WORKDIR}/${kubeconfig} - -# Get cluster creds -gcloud beta container fleet memberships get-credentials ${CLUSTER}-membership --project ${PROJECT_ID} -CONTEXT=`kubectl config view -o jsonpath='{.users[0].name}' --kubeconfig ${KUBECONFIG}` -# Install Gateway API CRDs -echo -e "Installing GatewayAPI CRDs" - -# Verify CRD is established in the cluster -echo -e "Verifying Control Plane Revisions CRD is present on ${CLUSTER}" -until kubectl get crd controlplanerevisions.mesh.cloud.google.com --kubeconfig ${KUBECONFIG} --context=${CONTEXT} -do - echo -n "...still waiting for the control plan revision crd creation" - sleep 1 -done - -# Install SAs, Roles, Roledbinding for ASM -kubectl apply -f ./manifests/istio-system-ns.yaml --kubeconfig ${KUBECONFIG} --context=${CONTEXT} -kubectl apply -f ./manifests/ --kubeconfig ${KUBECONFIG} --context=${CONTEXT} - -kubectl wait --for=condition=ProvisioningFinished controlplanerevision -n istio-system asm-managed --timeout=10m --kubeconfig ${KUBECONFIG} --context=${CONTEXT} \ No newline at end of file diff --git a/terraform/modules/cluster_build/cluster.tf b/terraform/modules/cluster_build/cluster.tf deleted file mode 100644 index 551296dd..00000000 --- a/terraform/modules/cluster_build/cluster.tf +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * 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. - */ - -// GKE Module using safer clusters -module "gke_module" { - depends_on = [ - module.vpc, - module.kms, - module.enabled_google_apis, - module.enabled_governance_apis, - ] - count = var.gke_module_bypass ? 0 : 1 - source = "../gke_module" - project_id = var.project_id - governance_project_id = var.governance_project_id - cluster_config = var.cluster_config - network = local.network_name - ip_range_pods = local.ip_range_pods - ip_range_services = local.ip_range_services - release_channel = var.release_channel - gke_keyring_name = local.gke_keyring_name - gke_key_name = local.gke_key_name - node_pool = var.node_pool - initial_node_count = var.initial_node_count - regional_clusters = var.regional_clusters - config_connector = var.config_connector - network_project_id = local.project_id - private_endpoint = var.private_endpoint - auth_cidr = var.auth_cidr - gke_service_account_email = local.gke_service_account_email - cluster_node_pool = local.cluster_node_pool - asm_label = local.asm_label -} - -// Experiments bypassing GKE Module and use GKE resource directly -module "gke" { - depends_on = [ - module.vpc, - module.kms, - module.enabled_google_apis, - module.enabled_governance_apis, - ] - count = var.gke_module_bypass ? 1 : 0 - source = "../gke" - project_id = var.project_id - governance_project_id = var.governance_project_id - cluster_config = var.cluster_config - network = local.network - ip_range_pods = local.ip_range_pods - ip_range_services = local.ip_range_services - release_channel = var.release_channel - gke_keyring_name = local.gke_keyring_name - gke_key_name = local.gke_key_name - node_pool = var.node_pool - initial_node_count = var.initial_node_count - regional_clusters = var.regional_clusters - min_node_count = var.min_node_count - max_node_count = var.max_node_count - linux_machine_type = var.linux_machine_type - windows_machine_type = var.windows_machine_type - private_endpoint = var.private_endpoint - auth_cidr = var.auth_cidr - windows_nodepool = var.windows_nodepool - preemptible_nodes = var.preemptible_nodes - gke_service_account_email = local.gke_service_account_email - asm_label = local.asm_label -} - -// Add optional Windows Node Pool -module "windows_nodepool" { - depends_on = [ - local.gke_hub_depends_on, - ] - count = var.windows_nodepool ? 1 : 0 - source = "../windows_nodepool" - cluster_config = var.cluster_config - name = format("windows-%s", var.node_pool) - project_id = var.project_id - initial_node_count = var.initial_node_count - min_count = var.min_node_count - max_count = var.max_node_count - disk_size_gb = 100 - disk_type = "pd-ssd" - image_type = "WINDOWS_SAC" - machine_type = var.windows_machine_type - service_account = local.gke_service_account_email - // Intergrity Monitoring is not enabled in Windows Node pools yet. - enable_integrity_monitoring = false - enable_secure_boot = true -} diff --git a/terraform/modules/cluster_build/logging.tf b/terraform/modules/cluster_build/logging.tf deleted file mode 100644 index a78f9ed2..00000000 --- a/terraform/modules/cluster_build/logging.tf +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * 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. - */ - -// Create GCS Bucket in Governance Project -resource "google_storage_bucket" "log-bucket" { - name = "gke-logging-bucket-${random_id.deployment.hex}" - storage_class = "NEARLINE" - force_destroy = true - project = var.governance_project_id - uniform_bucket_level_access = true - location = var.region -} - -// Create BQ Data Set in Governance Project -resource "google_bigquery_dataset" "bigquery-dataset" { - dataset_id = "gke_logs_dataset" - # location = "US" dfeault set in terraform-google-bigquery - default_table_expiration_ms = 3600000 - project = var.governance_project_id - labels = { - env = "default" - } - delete_contents_on_destroy = true -} - -// Create Log Sink in GKE Cluster Project -resource "google_logging_project_sink" "storage-sink" { - name = "gke-storage-sink" - destination = "storage.googleapis.com/${google_storage_bucket.log-bucket.id}" - filter = "resource.type=(k8s_cluster OR gke_cluster) AND log_id(cloudaudit.googleapis.com/activity)" - project = var.project_id - unique_writer_identity = true -} - -// Create Big Query Sink -resource "google_logging_project_sink" "bigquery-sink" { - depends_on = [ - resource.google_bigquery_dataset.bigquery-dataset - ] - name = "gke-bigquery-sink" - destination = "bigquery.googleapis.com/${google_bigquery_dataset.bigquery-dataset.id}" - filter = "resource.type=(k8s_cluster OR gke_cluster) AND log_id(cloudaudit.googleapis.com/activity)" - project = var.project_id - - unique_writer_identity = true -} - -// Add IAM permission in Logging project for Service accounts from GKE Project -resource "google_project_iam_binding" "log-writer-storage" { - role = "roles/storage.objectCreator" - project = var.governance_project_id - members = [ - google_logging_project_sink.storage-sink.writer_identity, - ] -} -// Add IAM permission in Logging project for Service accounts from GKE Project -resource "google_project_iam_binding" "log-writer-bigquery" { - role = "roles/bigquery.dataEditor" - project = var.governance_project_id - members = [ - google_logging_project_sink.bigquery-sink.writer_identity, - ] -} - diff --git a/terraform/modules/cluster_build/main.tf b/terraform/modules/cluster_build/main.tf deleted file mode 100644 index 6fc57ac8..00000000 --- a/terraform/modules/cluster_build/main.tf +++ /dev/null @@ -1,306 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * 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. - */ - -// Data Resources -data "google_project" "project" { - project_id = module.enabled_google_apis.project_id -} - -// Random string used to create a unique key ring name -resource "random_id" "deployment" { - byte_length = 2 -} - -locals { - // Presets for project and network settings - project_id = var.shared_vpc ? var.vpc_project_id : module.enabled_google_apis.project_id - network_name = var.vpc_name - network = "projects/${local.project_id}/global/networks/${var.vpc_name}" - vpc_selflink = format("projects/%s/global/networks/%s", local.project_id, local.network_name) - ip_range_pods = var.shared_vpc ? var.vpc_ip_range_pods_name : var.ip_range_pods_name - ip_range_services = var.shared_vpc ? var.vpc_ip_range_services_name : var.ip_range_services_name - distinct_cluster_regions = toset([for cluster in var.cluster_config : "${cluster.region}"]) - - // Presets for KMS and Key Ring - gke_keyring_name = format("gke-toolkit-kr-%s", random_id.deployment.hex) - gke_key_name = "gke-toolkit-kek" - - // Dynamically create subnet and secondary subnet inputs for multi-cluster creation - nested_subnets = flatten([ - for name, config in var.cluster_config : [ - { - subnet_name = config.subnet_name - subnet_ip = "10.0.${index(keys(var.cluster_config), name)}.0/24" - subnet_region = config.region - subnet_private_access = true - description = "This subnet is managed by Terraform" - } - ] - ]) - - nested_secondary_subnets = { - for name, config in var.cluster_config : config.subnet_name => [ - { - range_name = local.ip_range_pods - ip_cidr_range = "10.${index(keys(var.cluster_config), name) + 1}.0.0/17" - }, - { - range_name = local.ip_range_services - ip_cidr_range = "10.${index(keys(var.cluster_config), name) + 1}.128.0/17" - } - ] - } - - # subnetworks_to_nat = flatten([ for cluster in var.cluster_config : [{ "name" = cluster.subnet_name, "source_ip_ranges_to_nat" = ["PRIMARY_IP_RANGE"], "secondary_ip_range_names" = [] }] ]) - - // Presets for Sevice Account - gke_service_account = "gke-toolkit-sa" - gke_service_account_email = "${local.gke_service_account}@${module.enabled_google_apis.project_id}.iam.gserviceaccount.com" - clu_service_account = format("service-%s@container-engine-robot.iam.gserviceaccount.com", data.google_project.project.number) - prj_service_account = format("%s@cloudservices.gserviceaccount.com", data.google_project.project.number) - kcc_service_account = "gke-toolkit-kcc" - kcc_service_account_email = "${local.kcc_service_account}@${module.enabled_google_apis.project_id}.iam.gserviceaccount.com" - - // Presets for Service Account permissions - service_accounts = { - (local.gke_service_account) = [ - "${module.enabled_google_apis.project_id}=>roles/artifactregistry.reader", - "${module.enabled_google_apis.project_id}=>roles/logging.logWriter", - "${module.enabled_google_apis.project_id}=>roles/monitoring.metricWriter", - "${module.enabled_google_apis.project_id}=>roles/monitoring.viewer", - "${module.enabled_google_apis.project_id}=>roles/stackdriver.resourceMetadata.writer", - "${module.enabled_google_apis.project_id}=>roles/storage.objectViewer", - ] - (local.kcc_service_account) = [ - "${module.enabled_google_apis.project_id}=>roles/owner", - "${module.enabled_google_apis.project_id}=>roles/iam.serviceAccountCreator", - ] - } - - // Presets for Linux Node Pool - linux_pool = [{ - name = format("linux-%s", var.node_pool) - initial_node_count = var.initial_node_count - min_count = var.min_node_count - max_count = var.max_node_count - auto_upgrade = true - auto_repair = true - node_metadata = "GKE_METADATA" - machine_type = var.linux_machine_type - disk_type = "pd-balanced" - disk_size_gb = 30 - image_type = "COS_CONTAINERD" - preemptible = var.preemptible_nodes ? true : false - enable_secure_boot = true - }] - - // Final Node Pool options for Cluster - combines all specified nodepools - cluster_node_pool = flatten(local.linux_pool) - - // These locals are used to construct anthos component depends on rules based on which features are enabled - acm_depends_on = var.anthos_service_mesh ? module.asm : (var.multi_cluster_gateway ? module.mcg : module.hub) - asm_depends_on = var.multi_cluster_gateway ? module.mcg : module.hub - gke_hub_depends_on = var.gke_module_bypass ? module.gke : module.gke_module - - // Labels to apply to the cluster - Needed for to enable the ASM UI - asm_label = var.anthos_service_mesh ? { - mesh_id = format("proj-%s", data.google_project.project.number) - } : {} -} - -// Enable APIs needed in the gke cluster project -module "enabled_google_apis" { - source = "terraform-google-modules/project-factory/google//modules/project_services" - version = "~> 14.2.0" - project_id = var.project_id - disable_services_on_destroy = false - - activate_apis = [ - "iam.googleapis.com", - "storage.googleapis.com", - "compute.googleapis.com", - "logging.googleapis.com", - "monitoring.googleapis.com", - "containerregistry.googleapis.com", - "container.googleapis.com", - "binaryauthorization.googleapis.com", - "stackdriver.googleapis.com", - "iap.googleapis.com", - "cloudresourcemanager.googleapis.com", - "dns.googleapis.com", - "iamcredentials.googleapis.com", - "stackdriver.googleapis.com", - "cloudkms.googleapis.com", - ] -} - -// Enable Anthos APIs in gke cluster project -module "enabled_anthos_apis" { - source = "terraform-google-modules/project-factory/google//modules/project_services" - version = "~> 14.2.0" - count = var.multi_cluster_gateway || var.config_sync || var.anthos_service_mesh ? 1 : 0 - project_id = var.project_id - disable_services_on_destroy = false - - activate_apis = [ - "iam.googleapis.com", - "storage.googleapis.com", - "compute.googleapis.com", - "logging.googleapis.com", - "monitoring.googleapis.com", - "containerregistry.googleapis.com", - "container.googleapis.com", - "binaryauthorization.googleapis.com", - "stackdriver.googleapis.com", - "iap.googleapis.com", - "cloudresourcemanager.googleapis.com", - "dns.googleapis.com", - "iamcredentials.googleapis.com", - "stackdriver.googleapis.com", - "anthos.googleapis.com", - "gkehub.googleapis.com", - "sourcerepo.googleapis.com", - "anthosconfigmanagement.googleapis.com", - "anthos.googleapis.com", - "gkehub.googleapis.com", - "multiclusterservicediscovery.googleapis.com", - "multiclusteringress.googleapis.com", - "trafficdirector.googleapis.com", - "mesh.googleapis.com", - "multiclustermetering.googleapis.com", - "cloudkms.googleapis.com", - "multiclustermetering.googleapis.com", - ] -} - -// Enable APIs needed in the governance project -module "enabled_governance_apis" { - source = "terraform-google-modules/project-factory/google//modules/project_services" - version = "~> 14.2.0" - - project_id = var.governance_project_id - disable_services_on_destroy = false - - activate_apis = [ - "cloudkms.googleapis.com", - ] -} - -// Create the service accounts for GKE and KCC from a map declared in locals. -module "service_accounts" { - for_each = local.service_accounts - depends_on = [ - module.enabled_google_apis, - module.enabled_governance_apis, - ] - source = "terraform-google-modules/service-accounts/google" - version = "~> 4.2.0" - project_id = module.enabled_google_apis.project_id - display_name = "${each.key} service account" - names = [each.key] - project_roles = each.value - generate_keys = true -} - -// Bind the KCC operator Kubernetes service account(KSA) to the -// KCC Google Service account(GSA) so the KSA can assume the workload identity users role. -module "service_account-iam-bindings" { - depends_on = [ - local.gke_hub_depends_on, - ] - count = var.config_connector ? 1 : 0 - source = "terraform-google-modules/iam/google//modules/service_accounts_iam" - - service_accounts = [local.kcc_service_account_email] - project = module.enabled_google_apis.project_id - bindings = { - "roles/iam.workloadIdentityUser" = [ - "serviceAccount:${module.enabled_google_apis.project_id}.svc.id.goog[cnrm-system/cnrm-controller-manager]", - ] - } -} - - -// Create the KMS keyring and owner -module "kms" { - depends_on = [ - module.service_accounts, - module.enabled_governance_apis, - ] - for_each = local.distinct_cluster_regions - source = "terraform-google-modules/kms/google" - version = "~> 2.2.1" - project_id = var.governance_project_id - location = each.key - keyring = "${local.gke_keyring_name}-${each.key}" - keys = [local.gke_key_name] - set_owners_for = [local.gke_key_name] - prevent_destroy = false - owners = [ - "serviceAccount:${local.clu_service_account}", - ] -} - -module "hub" { - depends_on = [ - local.gke_hub_depends_on, - module.enabled_anthos_apis, - ] - count = var.multi_cluster_gateway || var.config_sync || var.anthos_service_mesh ? 1 : 0 - source = "../hub" - project_id = var.project_id - cluster_config = var.cluster_config - regional_clusters = var.regional_clusters -} - -module "acm" { - depends_on = [ - local.acm_depends_on, - module.enabled_anthos_apis, - ] - count = var.config_sync ? 1 : 0 - config_sync_repo = var.config_sync_repo - source = "../acm" - project_id = var.project_id - policy_controller = var.policy_controller - cluster_config = var.cluster_config - email = data.google_client_openid_userinfo.me.email -} - -module "mcg" { - depends_on = [ - module.hub, - module.enabled_anthos_apis, - ] - count = var.multi_cluster_gateway ? 1 : 0 - source = "../mcg" - project_id = var.project_id - cluster_config = var.cluster_config - vpc_project_id = var.vpc_project_id - vpc_name = var.vpc_name -} - -module "asm" { - depends_on = [ - local.asm_depends_on, - module.enabled_anthos_apis, - - ] - count = var.anthos_service_mesh ? 1 : 0 - source = "../asm" - project_id = var.project_id - cluster_config = var.cluster_config -} diff --git a/terraform/modules/clusters/clusters.tf b/terraform/modules/clusters/clusters.tf new file mode 100644 index 00000000..a2257faa --- /dev/null +++ b/terraform/modules/clusters/clusters.tf @@ -0,0 +1,93 @@ +/** + * Copyright 2020 Google LLC + * + * 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. + */ + +# Create clusters listing in the cluster_config variable +resource "google_container_cluster" "gke_ap" { + for_each = var.cluster_config + provider = google-beta + name = each.key + project = var.project_id + location = each.value.region + enable_autopilot = true + initial_node_count = var.initial_node_count + network = "projects/${var.vpc_project_id}/global/networks/${var.vpc_name}" + subnetwork = "projects/${var.vpc_project_id}/regions/{${each.value.region}}/subnetworks/${each.value.subnet_name}" + # networking_mode = "VPC_NATIVE" + # datapath_provider = "ADVANCED_DATAPATH" + + addons_config { + # HTTP Load Balancing is required to be enabled in Autopilot clusters + http_load_balancing { + disabled = false + } + # Horizontal Pod Autoscaling is required to be enabled in Autopilot clusters + horizontal_pod_autoscaling { + disabled = false + } + cloudrun_config { + disabled = true + } + + kalm_config { + enabled = false + } + config_connector_config { + enabled = false + } + gke_backup_agent_config { + enabled = true + } + } + + authenticator_groups_config { security_group = var.authenticator_security_group } + cluster_autoscaling { autoscaling_profile = "OPTIMIZE_UTILIZATION" } + cost_management_config { enabled = true } + deletion_protection = false + fleet { project = var.fleet_project } + gateway_api_config { channel = "CHANNEL_STANDARD" } + ip_allocation_policy { + cluster_secondary_range_name = var.vpc_ip_range_pods_name + services_secondary_range_name = var.vpc_ip_range_services_name + } + logging_config { + enable_components = ["SYSTEM_COMPONENTS", "WORKLOADS", "APISERVER", "CONTROLLER_MANAGER", "SCHEDULER"] + } + master_authorized_networks_config { + cidr_blocks { + cidr_block = "10.0.0.0/8" + display_name = "Internal VMs" + } + } + monitoring_config { + managed_prometheus { enabled = true } + enable_components = ["SYSTEM_COMPONENTS", "APISERVER", "CONTROLLER_MANAGER", "SCHEDULER", "STORAGE", "HPA", "POD", "DAEMONSET", "DEPLOYMENT", "STATEFULSET", "KUBELET", "CADVISOR", "DCGM"] + } + private_cluster_config { + enable_private_nodes = true + enable_private_endpoint = false + master_ipv4_cidr_block = "172.16.${index(keys(var.cluster_config), each.key)}.16/28" + master_global_access_config { + enabled = true + } + } + release_channel { channel = var.release_channel } + secret_manager_config { enabled = true } + + security_posture_config { + mode = "ENTERPRISE" + vulnerability_mode = "VULNERABILITY_ENTERPRISE" + } +} diff --git a/terraform/modules/clusters/main.tf b/terraform/modules/clusters/main.tf new file mode 100644 index 00000000..eafe5175 --- /dev/null +++ b/terraform/modules/clusters/main.tf @@ -0,0 +1,119 @@ +/** + * Copyright 2020 Google LLC + * + * 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. + */ + +// Data Resources +data "google_project" "project" { + project_id = var.project_id +} + +locals { + // Presets for project and network settings + project_id = var.shared_vpc ? var.vpc_project_id : var.project_id + network_name = var.vpc_name + network = "projects/${local.project_id}/global/networks/${var.vpc_name}" + vpc_selflink = format("projects/%s/global/networks/%s", local.project_id, local.network_name) + ip_range_pods = var.vpc_ip_range_pods_name + ip_range_services = var.vpc_ip_range_services_name + distinct_cluster_regions = toset([for cluster in var.cluster_config : "${cluster.region}"]) + + // Dynamically create subnet and secondary subnet inputs for multi-cluster creation + nested_subnets = flatten([ + for name, config in var.cluster_config : [ + { + subnet_name = config.subnet_name + subnet_ip = "10.0.${index(keys(var.cluster_config), name)}.0/24" + subnet_region = config.region + subnet_private_access = true + description = "This subnet is managed by Terraform" + } + ] + ]) + + nested_secondary_subnets = { + for name, config in var.cluster_config : config.subnet_name => [ + { + range_name = local.ip_range_pods + ip_cidr_range = "10.${index(keys(var.cluster_config), name) + 1}.0.0/17" + }, + { + range_name = local.ip_range_services + ip_cidr_range = "10.${index(keys(var.cluster_config), name) + 1}.128.0/17" + } + ] + } + + # subnetworks_to_nat = flatten([ for cluster in var.cluster_config : [{ "name" = cluster.subnet_name, "source_ip_ranges_to_nat" = ["PRIMARY_IP_RANGE"], "secondary_ip_range_names" = [] }] ]) + + // Presets for Linux Node Pool + linux_pool = [{ + name = format("linux-%s", var.node_pool) + initial_node_count = var.initial_node_count + total_min_count = 0 + total_max_count = 20 + auto_upgrade = true + auto_repair = true + node_metadata = "GKE_METADATA" + machine_type = var.linux_machine_type + disk_type = "pd-balanced" + disk_size_gb = 200 + image_type = "COS_CONTAINERD" + enable_secure_boot = true + }] + + // Final Node Pool options for Cluster - combines all specified nodepools + cluster_node_pool = flatten(local.linux_pool) + +} + +// Enable APIs needed in the gke cluster project +# module "enabled_google_apis" { +# source = "terraform-google-modules/project-factory/google//modules/project_services" +# version = "~> 17.0" +# project_id = var.project_id +# disable_services_on_destroy = false + +# activate_apis = [ +# "storage.googleapis.com", +# "compute.googleapis.com", +# "logging.googleapis.com", +# "monitoring.googleapis.com", +# "containerregistry.googleapis.com", +# "container.googleapis.com", +# "binaryauthorization.googleapis.com", +# "stackdriver.googleapis.com", +# "iap.googleapis.com", +# "cloudresourcemanager.googleapis.com", +# "dns.googleapis.com", +# "iamcredentials.googleapis.com", +# "stackdriver.googleapis.com", +# "cloudkms.googleapis.com", +# ] +# } + +# // Create the service accounts from a map declared in locals. +# module "service_accounts" { +# for_each = local.service_accounts +# depends_on = [ +# module.enabled_google_apis, +# ] +# source = "terraform-google-modules/service-accounts/google" +# version = "~> 4.0" +# project_id = module.enabled_google_apis.project_id +# display_name = "${each.key} service account" +# names = [each.key] +# project_roles = each.value +# generate_keys = true +# } \ No newline at end of file diff --git a/terraform/modules/cluster_build/outputs.tf b/terraform/modules/clusters/outputs.tf similarity index 61% rename from terraform/modules/cluster_build/outputs.tf rename to terraform/modules/clusters/outputs.tf index 48638443..34cb03ea 100644 --- a/terraform/modules/cluster_build/outputs.tf +++ b/terraform/modules/clusters/outputs.tf @@ -21,22 +21,16 @@ output "project_id" { output "get_credential_commands" { description = "gcloud get-credentials command to generate kubeconfig for the private cluster" - value = flatten([for s in module.gke : (var.private_endpoint ? (format("gcloud container clusters get-credentials --project %s --zone %s --internal-ip %s", var.project_id, s.location, s.name)) : (format("gcloud container clusters get-credentials --project %s --zone %s %s", var.project_id, s.location, s.name)))]) + value = flatten([for s in google_container_cluster.gke_ap : (format("gcloud container fleet memberships get-credentials %s --project %s --location=%s", s.name, var.project_id, s.location))]) } output "cluster_names" { description = "List of GKE cluster names" - value = flatten([for s in module.gke : s.name]) + value = flatten([for s in google_container_cluster.gke_ap : s.name]) } output "endpoints" { sensitive = true description = "List of GKE cluster endpoints" - value = flatten([for s in module.gke : s.endpoint]) -} - -output "ca_certificates" { - sensitive = true - description = "List of GKE cluster ca certificates (base64 encoded)" - value = flatten([for s in module.gke : s.ca_certificate]) + value = flatten([for s in google_container_cluster.gke_ap : s.endpoint]) } diff --git a/terraform/modules/cluster_build/provider.tf b/terraform/modules/clusters/provider.tf similarity index 74% rename from terraform/modules/cluster_build/provider.tf rename to terraform/modules/clusters/provider.tf index b4049917..8291e2c5 100644 --- a/terraform/modules/cluster_build/provider.tf +++ b/terraform/modules/clusters/provider.tf @@ -15,9 +15,20 @@ */ terraform { + required_version = ">=1.3" + required_providers { google = { - version = "~> 4.57.0" + source = "hashicorp/google" + version = ">= 5.40.0, < 7" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.10" + } + random = { + source = "hashicorp/random" + version = ">= 2.1" } } } diff --git a/terraform/modules/cluster_build/variables.tf b/terraform/modules/clusters/variables.tf similarity index 56% rename from terraform/modules/cluster_build/variables.tf rename to terraform/modules/clusters/variables.tf index 8a5c235b..114d8d8f 100644 --- a/terraform/modules/cluster_build/variables.tf +++ b/terraform/modules/clusters/variables.tf @@ -19,9 +19,10 @@ variable "project_id" { description = "The project ID to host the cluster in" } -variable "governance_project_id" { +variable "fleet_project" { + description = "(Optional) Register the cluster with the fleet in this project." type = string - description = "The project ID to host governance resources" + default = null } variable "regional_clusters" { @@ -36,12 +37,6 @@ variable "region" { default = "us-central1" } -variable "zones" { - type = list(string) - description = "The zones used in your nodepool" - default = ["us-central1-b"] -} - variable "shared_vpc" { type = bool description = "boolean value for determining whether to create Standalone VPC or use a preexisting Shared VPC" @@ -54,17 +49,6 @@ variable "vpc_name" { default = "gke-toolkit-network" } -variable "ip_range_pods_name" { - type = string - description = "The secondary ip range to use for pods" - default = "ip-range-pods" -} - -variable "ip_range_services_name" { - type = string - description = "The secondary ip range to use for pods" - default = "ip-range-svc" -} variable "vpc_project_id" { type = string @@ -114,31 +98,15 @@ variable "linux_machine_type" { default = "n1-standard-4" } -variable "windows_machine_type" { - type = string - default = "n1-standard-4" -} - variable "private_endpoint" { type = bool default = false } -# Need this default to run PR build test -variable "auth_cidr" { - type = string - default = "1.2.3.4/0" -} - -variable "windows_nodepool" { - type = bool - default = false -} - -variable "preemptible_nodes" { - type = bool - description = "Whether underlying node GCE instances are preemptible" - default = true +variable "authenticator_security_group" { + type = string + description = "The name of the RBAC security group for use with Google security groups in Kubernetes RBAC. Group name must be in format gke-security-groups@yourdomain.com" + default = null } variable "cluster_config" { @@ -146,51 +114,7 @@ variable "cluster_config" { default = {} } -variable "k8s_users" { - type = map(string) - default = { - rbac-demo-auditor = "view" - rbac-demo-editor = "edit" - } -} - -variable "config_sync" { - type = bool - description = "Enable Config Sync on all clusters." - default = true -} - -variable "config_sync_repo" { - type = string - description = "Name of Cloud Source Repo for Config Sync" - default = "gke-poc-config-sync" -} - -variable "policy_controller" { - type = bool - description = "Enable Policy Controller on all clusters." - default = true -} - -variable "config_connector" { - type = bool - description = "(Beta) Whether ConfigConnector is enabled for this cluster." - default = false -} - -variable "multi_cluster_gateway" { - type = bool - description = "Enable Multi-cluster gateway on all clusters." - default = true -} - -variable "anthos_service_mesh" { - type = bool - description = "Enable Anthos Service Mesh on all clusters." - default = true -} -variable "gke_module_bypass" { - type = bool - description = "Experimental: Setting this to true allows you to use the TF GKE resource directly instead of the GKE module" - default = false +variable "auth_cidr" { + type = string + default = "172.16.100.16/28" } \ No newline at end of file diff --git a/terraform/modules/fleet/admin-cluster.tf b/terraform/modules/fleet/admin-cluster.tf new file mode 100644 index 00000000..df974d7f --- /dev/null +++ b/terraform/modules/fleet/admin-cluster.tf @@ -0,0 +1,127 @@ + +# module "gke" { +# deletion_protection = false +# source = "terraform-google-modules/kubernetes-engine/google//modules/beta-autopilot-private-cluster" +# authenticator_security_group = var.authenticator_security_group +# enable_cost_allocation = true +# enable_private_endpoint = true +# gke_backup_agent_config = true +# project_id = var.project_id +# fleet_project = var.fleet_project +# network = var.vpc_name +# ip_range_pods = "admin-pods" +# ip_range_services = "admin-svcs" +# identity_namespace = "${var.fleet_project}.svc.id.goog" +# release_channel = var.release_channel +# name = "gke-ap-admin-cp-00" +# region = "us-central1" +# subnetwork = "admin-control-plane" +# network_project_id = var.vpc_project_id +# gateway_api_channel = "CHANNEL_STANDARD" +# grant_registry_access = true +# dns_cache = true +# horizontal_pod_autoscaling = true +# enable_private_nodes = true +# master_ipv4_cidr_block = "172.16.100.16/28" +# depends_on = [ +# module.vpc, +# google_project_service.services, +# ] +# } + +/** + * Copyright 2022 Google LLC + * + * 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. + */ + +resource "google_container_cluster" "admin" { + provider = google-beta + name = "gke-ap-admin-cp-00" + project = var.project_id + location = "us-central1" + enable_autopilot = true + initial_node_count = 1 + network = "projects/${var.vpc_project_id}/global/networks/${var.vpc_name}" + subnetwork = "projects/${var.vpc_project_id}/regions/us-central1/subnetworks/admin-control-plane" + # networking_mode = "VPC_NATIVE" + # datapath_provider = "ADVANCED_DATAPATH" + + addons_config { + # HTTP Load Balancing is required to be enabled in Autopilot clusters + http_load_balancing { + disabled = false + } + # Horizontal Pod Autoscaling is required to be enabled in Autopilot clusters + horizontal_pod_autoscaling { + disabled = false + } + cloudrun_config { + disabled = true + } + + kalm_config { + enabled = false + } + config_connector_config { + enabled = false + } + gke_backup_agent_config { + enabled = true + } + } + + authenticator_groups_config { security_group = var.authenticator_security_group } + cluster_autoscaling { autoscaling_profile = "OPTIMIZE_UTILIZATION" } + cost_management_config { enabled = true } + deletion_protection = false + fleet { project = var.fleet_project } + gateway_api_config { channel = "CHANNEL_STANDARD" } + ip_allocation_policy { + cluster_secondary_range_name = "admin-pods" + services_secondary_range_name = "admin-svcs" + } + logging_config { + enable_components = ["SYSTEM_COMPONENTS", "WORKLOADS", "APISERVER", "CONTROLLER_MANAGER", "SCHEDULER"] + } + master_authorized_networks_config { + cidr_blocks { + cidr_block = "10.0.0.0/8" + display_name = "Internal VMs" + } + } + monitoring_config { + managed_prometheus { enabled = true } + enable_components = ["SYSTEM_COMPONENTS", "APISERVER", "CONTROLLER_MANAGER", "SCHEDULER", "STORAGE", "HPA", "POD", "DAEMONSET", "DEPLOYMENT", "STATEFULSET", "KUBELET", "CADVISOR", "DCGM"] + } + private_cluster_config { + enable_private_nodes = true + enable_private_endpoint = false + master_ipv4_cidr_block = "172.16.100.16/28" + master_global_access_config { + enabled = true + } + } + release_channel { channel = var.release_channel } + secret_manager_config { enabled = true } + + security_posture_config { + mode = "ENTERPRISE" + vulnerability_mode = "VULNERABILITY_ENTERPRISE" + } + depends_on = [ + module.enabled_service_project_apis, + google_gke_hub_feature.mesh_config_defaults, + google_gke_hub_fleet.default, + ] +} diff --git a/terraform/modules/fleet/feature-defaults.tf b/terraform/modules/fleet/feature-defaults.tf new file mode 100644 index 00000000..70a9d5fb --- /dev/null +++ b/terraform/modules/fleet/feature-defaults.tf @@ -0,0 +1,163 @@ +/** + * Copyright 2024 Google LLC + * + * 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. + */ + +# Create Hub Service Account +resource "google_project_iam_member" "hubsa" { + project = var.fleet_project + role = "roles/gkehub.serviceAgent" + member = local.hub_service_account + depends_on = [ + module.enabled_service_project_apis, + ] +} + +locals { + cs_service_account = "cs-service-account" + cs_service_account_email = "${local.cs_service_account}@${var.project_id}.iam.gserviceaccount.com" +} + +// https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/sourcerepo_repository +// Create 1 centralized Cloud Source Repo, that all GKE clusters will sync to +resource "google_sourcerepo_repository" "default-config-sync-repo" { + name = var.config_sync_repo + project = var.fleet_project +} + +// create ACM service account +module "service_accounts" { + source = "terraform-google-modules/service-accounts/google" + # version = "~> 4.2.0" + project_id = var.fleet_project + display_name = "CS service account" + names = [local.cs_service_account] + project_roles = ["${var.fleet_project}=>roles/source.reader"] +} + +module "service_account-iam-bindings" { + depends_on = [ + resource.google_gke_hub_feature.config_management, + ] + source = "terraform-google-modules/iam/google//modules/service_accounts_iam" + + service_accounts = [local.cs_service_account_email] + project = var.fleet_project + bindings = { + "roles/iam.workloadIdentityUser" = [ + "serviceAccount:${var.fleet_project}.svc.id.goog[config-management-system/root-reconciler]", + ] + } +} + +# Fleet Policy Defaults +resource "google_gke_hub_feature" "fleet_policy_defaults" { + project = var.fleet_project + location = "global" + name = "policycontroller" + + fleet_default_member_config { + policycontroller { + policy_controller_hub_config { + install_spec = "INSTALL_SPEC_ENABLED" + policy_content { + bundles { + bundle = "cis-k8s-v1.5.1" + } + } + audit_interval_seconds = 30 + referential_rules_enabled = true + } + } + } + + depends_on = [module.enabled_service_project_apis] +} + +# Config Sync Defaults +resource "google_gke_hub_feature" "config_management" { + name = "configmanagement" + project = var.fleet_project + location = "global" + provider = google + + fleet_default_member_config { + configmanagement { + # Use the default latest version + config_sync { + source_format = "unstructured" + git { + sync_repo = var.config_sync_repo + sync_branch = var.config_sync_repo_branch + policy_dir = var.config_sync_repo_dir + secret_type = "gcpserviceaccount" + gcp_service_account_email = local.cs_service_account_email + } + } + } + } + + depends_on = [module.service_account-iam-bindings] +} + +# Mesh Config Defaults +resource "google_gke_hub_feature" "mesh_config_defaults" { + project = var.fleet_project + location = "global" + name = "servicemesh" + + fleet_default_member_config { + mesh { + management = "MANAGEMENT_AUTOMATIC" + } + } + + depends_on = [google_project_iam_member.hubsa] +} + +# Fleet Observability +resource "google_gke_hub_feature" "fleet_observability" { + name = "fleetobservability" + project = var.fleet_project + location = "global" + + spec { + fleetobservability { + logging_config { + default_config { + mode = "COPY" + } + fleet_scope_logs_config { + mode = "COPY" + } + } + } + } + + depends_on = [module.enabled_service_project_apis] +} + +# Fleet Resource +resource "google_gke_hub_fleet" "default" { + project = var.fleet_project + + default_cluster_config { + security_posture_config { + mode = "ENTERPRISE" + vulnerability_mode = "VULNERABILITY_BASIC" + } + } + + depends_on = [module.enabled_service_project_apis] +} diff --git a/terraform/modules/cluster_build/rbac.tf b/terraform/modules/fleet/main.tf similarity index 53% rename from terraform/modules/cluster_build/rbac.tf rename to terraform/modules/fleet/main.tf index c44bdadf..aea58b66 100644 --- a/terraform/modules/cluster_build/rbac.tf +++ b/terraform/modules/fleet/main.tf @@ -1,5 +1,5 @@ /** - * Copyright 2020 Google LLC + * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,21 +14,20 @@ * limitations under the License. */ -module "rbac_service_accounts" { - for_each = var.k8s_users - source = "terraform-google-modules/service-accounts/google" - version = "~> 4.2.0" +data "google_project" "cluster_project" { project_id = var.project_id - names = [each.key] - project_roles = [ - "${var.project_id}=>roles/container.clusterViewer", - "${var.project_id}=>roles/container.viewer" - ] - generate_keys = true } -resource "local_file" "service_account_key" { - for_each = module.rbac_service_accounts - filename = "../creds/${each.value.email}.json" - content = each.value.key +data "google_project" "fleet_project" { + project_id = var.fleet_project +} + +data "google_project" "vpc_project" { + project_id = var.vpc_project_id +} + +locals { + # Hub service account + hub_service_account_email = format("service-%s@gcp-sa-gkehub.iam.gserviceaccount.com", data.google_project.fleet_project.number) + hub_service_account = "serviceAccount:${local.hub_service_account_email}" } \ No newline at end of file diff --git a/terraform/modules/fleet/mcg.tf b/terraform/modules/fleet/mcg.tf new file mode 100644 index 00000000..bed2d342 --- /dev/null +++ b/terraform/modules/fleet/mcg.tf @@ -0,0 +1,121 @@ +/** + * Copyright 2024 Google LLC + * + * 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. + */ + +// https://cloud.google.com/kubernetes-engine/docs/how-to/multi-cluster-ingress-setup#shared_vpc_deployment +module "firewall_rules" { + source = "terraform-google-modules/network/google//modules/firewall-rules" + project_id = var.vpc_project_id + network_name = var.vpc_name + + rules = [{ + name = "allow-glcb-backend-ingress" + description = null + direction = "INGRESS" + priority = null + ranges = ["130.211.0.0/22", "35.191.0.0/16"] + source_tags = null + source_service_accounts = null + target_tags = null + target_service_accounts = null + allow = [{ + protocol = "tcp" + ports = ["0-65535"] + }] + deny = [] + log_config = { + metadata = "INCLUDE_ALL_METADATA" + } + }] +} + +// enable Multi-cluster service discovery +resource "google_gke_hub_feature" "mcs" { + name = "multiclusterservicediscovery" + location = "global" + project = var.fleet_project + provider = google-beta + depends_on = [module.enabled_service_project_apis] +} + +// enable Multi-cluster Ingress(also gateway) project wide +resource "google_gke_hub_feature" "mci" { + name = "multiclusteringress" + location = "global" + project = var.fleet_project + spec { + multiclusteringress { + config_membership = "projects/${var.project_id}/locations/us-central1/memberships/gke-ap-admin-cp-00" + } + } + depends_on = [ + google_gke_hub_feature.mcs, + google_container_cluster.admin, + ] +} + +// Create IAM binding granting the fleet host project's GKE Hub service account the GKE Service Agent role for cluster project - ONLY NEEDED IF CLUSTER IS IN NOT IN THE FLEET HOST PROJECT and needs to be done for every cluster project +resource "google_project_iam_binding" "serviceagent-fleet-member-hubagent" { + role = "roles/gkehub.serviceAgent" + project = var.project_id + members = [ + "serviceAccount:service-${data.google_project.fleet_project.number}@gcp-sa-mcsd.iam.gserviceaccount.com", + ] + depends_on = [google_gke_hub_feature.mcs] +} + +// Create IAM binding granting the fleet host project's MCS service account the MCS Service Agent role for cluster project - this needs to be done for every cluster project +resource "google_project_iam_binding" "serviceagent-fleet-member-mcsagent" { + role = "roles/multiclusterservicediscovery.serviceAgent" + project = var.project_id + members = [ + "serviceAccount:service-${data.google_project.fleet_project.number}@gcp-sa-mcsd.iam.gserviceaccount.com", + ] + depends_on = [google_gke_hub_feature.mcs] +} + +// Create IAM binding granting the fleet host project MCS service account the MCS Service Agent role on the Shared VPC host project +resource "google_project_iam_binding" "serviceagent-fleet-host" { + role = "roles/multiclusterservicediscovery.serviceAgent" + project = var.shared_vpc ? var.vpc_project_id : var.project_id + members = [ + "serviceAccount:service-${data.google_project.fleet_project.number}@gcp-sa-mcsd.iam.gserviceaccount.com", + ] + depends_on = [google_gke_hub_feature.mcs] +} + + + +// Create IAM binding granting the fleet host project MCS service account the MCS Service Agent role on the Shared VPC host project +resource "google_project_iam_binding" "network-viewer-fleet-host" { + role = "roles/compute.networkViewer" + project = var.shared_vpc ? var.vpc_project_id : var.project_id + members = [ + "serviceAccount:${var.fleet_project}.svc.id.goog[gke-mcs/gke-mcs-importer]", + ] + depends_on = [google_gke_hub_feature.mcs] +} + + + +// Create IAM binding granting the fleet host project MCS service account the MCS Service Agent role on the Shared VPC host project +resource "google_project_iam_binding" "network-viewer-member" { + role = "roles/compute.networkViewer" + project = var.fleet_project + members = [ + "serviceAccount:${var.fleet_project}.svc.id.goog[gke-mcs/gke-mcs-importer]", + ] + depends_on = [google_gke_hub_feature.mcs] +} diff --git a/terraform/modules/fleet/outputs.tf b/terraform/modules/fleet/outputs.tf new file mode 100644 index 00000000..0cd30e6f --- /dev/null +++ b/terraform/modules/fleet/outputs.tf @@ -0,0 +1,19 @@ +/** + * Copyright 2024 Google LLC + * + * 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. + */ + +output "fleet_project" { + value = var.fleet_project +} \ No newline at end of file diff --git a/terraform/modules/fleet/provider.tf b/terraform/modules/fleet/provider.tf new file mode 100644 index 00000000..11a03573 --- /dev/null +++ b/terraform/modules/fleet/provider.tf @@ -0,0 +1,42 @@ +/** + * Copyright 2024 Google LLC + * + * 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. + */ + +terraform { + required_version = ">=1.3" + + required_providers { + google = { + source = "hashicorp/google" + version = ">= 5.40.0, < 7" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.10" + } + random = { + source = "hashicorp/random" + version = ">= 2.1" + } + } +} + +provider "google" { + project = var.project_id +} + +provider "google-beta" { + project = var.project_id +} diff --git a/terraform/modules/fleet/services.tf b/terraform/modules/fleet/services.tf new file mode 100644 index 00000000..b28a3a68 --- /dev/null +++ b/terraform/modules/fleet/services.tf @@ -0,0 +1,42 @@ +/** + * Copyright 2024 Google LLC + * + * 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. + */ + +# Enable Fleet Services +module "enabled_service_project_apis" { + source = "terraform-google-modules/project-factory/google//modules/project_services" + version = "~> 17.0" + + project_id = var.fleet_project + disable_services_on_destroy = false + + activate_apis = [ + "container.googleapis.com", + "anthos.googleapis.com", + "dns.googleapis.com", + "gkehub.googleapis.com", + "gkeconnect.googleapis.com", + "anthosconfigmanagement.googleapis.com", + "anthospolicycontroller.googleapis.com", + "meshconfig.googleapis.com", + "meshca.googleapis.com", + "containersecurity.googleapis.com", + "logging.googleapis.com", + "cloudresourcemanager.googleapis.com", + "multiclusterservicediscovery.googleapis.com", + "compute.googleapis.com", + "iam.googleapis.com", + ] +} \ No newline at end of file diff --git a/terraform/modules/fleet/variables.tf b/terraform/modules/fleet/variables.tf new file mode 100644 index 00000000..8d27f4e4 --- /dev/null +++ b/terraform/modules/fleet/variables.tf @@ -0,0 +1,93 @@ +/** + * Copyright 2020 Google LLC + * + * 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. + */ + +variable "project_id" { + type = string + description = "The project ID to host the cluster in" +} + +variable "fleet_project" { + type = string + description = "(Optional) Register the cluster with the fleet in this project." +} + +variable "vpc_project_id" { + type = string + description = "Shared VPC project needed for setting MCI and MCS RBAC." +} + +variable "config_sync_repo" { + description = "Git repo used as the default config sync repo for your fleet." + type = string + default = null +} + +variable "config_sync_repo_branch" { + description = "Git repo branch used as the default config sync repo for your fleet." + type = string + default = null +} + +variable "config_sync_repo_dir" { + description = "Git repo directory used as the default config sync repo for your fleet." + type = string + default = null +} + +variable "shared_vpc" { + type = bool + description = "Determines whether to create a standalone VPC or use an existing Shared VPC" + default = false +} + +variable "vpc_ip_range_pods_name" { + type = string + description = "The secondary IP range to use for pods in the shared VPC" + default = "" +} + +variable "vpc_ip_range_services_name" { + type = string + description = "The secondary IP range to use for services in the shared VPC" + default = "" +} + +variable "release_channel" { + type = string + description = "The release channel of the cluster" + default = "regular" +} + +variable "authenticator_security_group" { + type = string + description = "The name of the RBAC security group for use with Google security groups in Kubernetes RBAC." + default = null +} + +variable "vpc_name" { + type = string + description = "The name of the VPC - used for shared or local VPC" + default = "" +} + +variable "cluster_config" { + type = map(object({ + subnet_name = string + region = string + })) + description = "For each cluster, create an object that contains the required fields" + default = {} +} diff --git a/terraform/modules/gke/gke.tf b/terraform/modules/gke/gke.tf deleted file mode 100644 index df846718..00000000 --- a/terraform/modules/gke/gke.tf +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright 2022 Google LLC - * - * 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. - */ - -data "google_project" "project" { - project_id = var.project_id -} - -resource "google_container_cluster" "primary" { - for_each = var.cluster_config - name = each.key - project = var.project_id - location = var.regional_clusters ? each.value.region : each.value.zones[0] - node_locations = slice(each.value.zones, 1, length(each.value.zones)) - - # enable_autopilot = false - network = var.network - subnetwork = each.value.subnet_name - networking_mode = "VPC_NATIVE" - enable_intranode_visibility = true - datapath_provider = "ADVANCED_DATAPATH" - # dns_config { - # cluster_dns = "CLOUD_DNS" - # cluster_dns_scope = "CLUSTER_SCOPE" - # } - database_encryption { - state = "ENCRYPTED" - key_name = "projects/${var.governance_project_id}/locations/${each.value.region}/keyRings/${var.gke_keyring_name}-${each.value.region}/cryptoKeys/${var.gke_key_name}" - } - release_channel { - channel = var.release_channel - } - # binary_authorization { - # evaluation_mode = "PROJECT_SINGLETON_POLICY_ENFORCE" - # } - enable_binary_authorization = true - ip_allocation_policy { - cluster_secondary_range_name = var.ip_range_pods - services_secondary_range_name = var.ip_range_services - } - logging_config { - enable_components = ["SYSTEM_COMPONENTS", "WORKLOADS"] - } - monitoring_config { - enable_components = ["SYSTEM_COMPONENTS"] - } - workload_identity_config { - workload_pool = "${data.google_project.project.project_id}.svc.id.goog" - } - private_cluster_config { - enable_private_nodes = true - enable_private_endpoint = var.private_endpoint - master_ipv4_cidr_block = "172.16.${index(keys(var.cluster_config), each.key)}.16/28" - master_global_access_config { - enabled = true - } - } - master_authorized_networks_config { - cidr_blocks { - cidr_block = var.auth_cidr - display_name = "Workstation Public IP" - } - } - resource_labels = var.asm_label - # We can't create a cluster with no node pool defined, but we want to only use - # separately managed node pools. So we create the smallest possible default - # node pool and immediately delete it. - remove_default_node_pool = true - initial_node_count = 12 -} - -resource "google_container_node_pool" "primary_nodes" { - depends_on = [ - resource.google_container_cluster.primary - ] - for_each = var.cluster_config - name = format("linux-%s", var.node_pool) - project = var.project_id - location = var.regional_clusters ? each.value.region : each.value.zones[0] - cluster = each.key - node_locations = each.value.zones - initial_node_count = var.initial_node_count - autoscaling { - min_node_count = var.min_node_count - max_node_count = var.max_node_count - } - management { - auto_upgrade = true - auto_repair = true - } - node_config { - preemptible = var.preemptible_nodes ? true : false - machine_type = var.linux_machine_type - image_type = "COS_CONTAINERD" - disk_type = "pd-ssd" - disk_size_gb = 30 - shielded_instance_config { - enable_secure_boot = true - enable_integrity_monitoring = true - } - - # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles. - service_account = var.gke_service_account_email - oauth_scopes = [ - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/logging.write", - "https://www.googleapis.com/auth/monitoring", - ] - } -} \ No newline at end of file diff --git a/terraform/modules/gke/variables.tf b/terraform/modules/gke/variables.tf deleted file mode 100644 index 1e49058a..00000000 --- a/terraform/modules/gke/variables.tf +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * 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. - */ - -variable "project_id" { - type = string - description = "The project ID to host the cluster in" -} - -variable "governance_project_id" { - type = string - description = "The project ID to host governance resources" -} - -variable "regional_clusters" { -} - -variable "network" { - type = string - description = "The name of the network being created to host the cluster in" -} - -variable "ip_range_pods" { - type = string - description = "The secondary ip range to use for pods" - default = "ip-range-pods" -} - -variable "ip_range_services" { - type = string - description = "The secondary ip range to use for pods" - default = "ip-range-svc" -} - -variable "release_channel" { - type = string - default = "regular" -} - -variable "node_pool" { - type = string - default = "gke-toolkit-pool" -} - -variable "initial_node_count" { - type = number - default = 4 -} - -variable "min_node_count" { - type = number - default = 4 -} - -variable "max_node_count" { - type = number - default = 10 -} - -variable "linux_machine_type" { - type = string - default = "n1-standard-4" -} - -variable "windows_machine_type" { - type = string - default = "n1-standard-4" -} - -variable "private_endpoint" { - type = bool - default = false -} - -# Need this default to run PR build test -variable "auth_cidr" { - type = string - default = "1.2.3.4/0" -} - -variable "windows_nodepool" { - type = bool - default = false -} - -variable "preemptible_nodes" { - type = bool - description = "Whether underlying node GCE instances are preemptible" - default = true -} - -variable "cluster_config" { - description = "For each cluster, create an object that contain the required fields" - default = {} -} - -variable "gke_service_account_email" { - type = string -} - -variable "gke_keyring_name" { - type = string -} - -variable "gke_key_name" { - type = string -} - -variable "asm_label" { -} \ No newline at end of file diff --git a/terraform/modules/gke_module/gke_module.tf b/terraform/modules/gke_module/gke_module.tf deleted file mode 100644 index cc2d4efb..00000000 --- a/terraform/modules/gke_module/gke_module.tf +++ /dev/null @@ -1,53 +0,0 @@ -module "gke" { - for_each = var.cluster_config - source = "terraform-google-modules/kubernetes-engine/google//modules/safer-cluster" - version = "25.0.0" - project_id = var.project_id - network = var.network - ip_range_pods = var.ip_range_pods - ip_range_services = var.ip_range_services - release_channel = var.release_channel - initial_node_count = var.initial_node_count - name = each.key - regional = var.regional_clusters - region = each.value.region - zones = each.value.zones - config_connector = var.config_connector - subnetwork = each.value.subnet_name - network_project_id = var.network_project_id - enable_private_endpoint = var.private_endpoint - gateway_api_channel = "CHANNEL_STANDARD" - grant_registry_access = true - enable_shielded_nodes = true - master_ipv4_cidr_block = "172.16.${index(keys(var.cluster_config), each.key)}.16/28" - master_authorized_networks = [{ - cidr_block = var.auth_cidr - display_name = "Workstation Public IP" - }] - - compute_engine_service_account = var.gke_service_account_email - database_encryption = [{ - state = "ENCRYPTED" - key_name = "projects/${var.governance_project_id}/locations/${each.value.region}/keyRings/${var.gke_keyring_name}-${each.value.region}/cryptoKeys/${var.gke_key_name}" - }] - - node_pools = var.cluster_node_pool - - node_pools_oauth_scopes = { - (var.node_pool) = [ - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/logging.write", - "https://www.googleapis.com/auth/monitoring", - ] - } - - node_pools_metadata = { - (var.node_pool) = { - // Set metadata on the VM to supply more entropy - google-compute-enable-virtio-rng = "true" - // Explicitly remove GCE legacy metadata API endpoint - disable-legacy-endpoints = "true" - } - } - cluster_resource_labels = var.asm_label -} \ No newline at end of file diff --git a/terraform/modules/gke_module/variables.tf b/terraform/modules/gke_module/variables.tf deleted file mode 100644 index 2c0fca05..00000000 --- a/terraform/modules/gke_module/variables.tf +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * 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. - */ - -variable "project_id" { - type = string - description = "The project ID to host the cluster in" -} - -variable "governance_project_id" { - type = string - description = "The project ID to host governance resources" -} - -variable "regional_clusters" { -} - -variable "network" { - type = string - description = "The name of the network being created to host the cluster in" -} - -variable "ip_range_pods" { - type = string - description = "The secondary ip range to use for pods" - default = "ip-range-pods" -} - -variable "ip_range_services" { - type = string - description = "The secondary ip range to use for pods" - default = "ip-range-svc" -} - -variable "release_channel" { - type = string - default = "regular" -} - -variable "node_pool" { - type = string - default = "gke-toolkit-pool" -} - -variable "initial_node_count" { - type = number - default = 4 -} - -variable "network_project_id" { - type = string -} - -variable "config_connector" { - type = bool - description = "(Beta) Whether ConfigConnector is enabled for this cluster." - default = false -} - -variable "private_endpoint" { - type = bool - default = false -} - -# Need this default to run PR build test -variable "auth_cidr" { - type = string - default = "1.2.3.4/0" -} - -variable "cluster_config" { - description = "For each cluster, create an object that contain the required fields" - default = {} -} - -variable "cluster_node_pool" { -} - -variable "asm_label" { -} - -variable "gke_service_account_email" { - type = string -} - -variable "gke_keyring_name" { - type = string -} - -variable "gke_key_name" { - type = string -} \ No newline at end of file diff --git a/terraform/modules/hub/hub.tf b/terraform/modules/hub/hub.tf deleted file mode 100644 index 576c8103..00000000 --- a/terraform/modules/hub/hub.tf +++ /dev/null @@ -1,36 +0,0 @@ -variable "project_id" {} - -variable "cluster_config" {} - -variable "regional_clusters" {} - -data "google_project" "project" { - project_id = var.project_id -} - -// Create IAM binding allowing the hub project's GKE Hub service account access to the registered member project -resource "google_project_iam_binding" "gkehub-serviceagent" { - role = "roles/gkehub.serviceAgent" - project = var.project_id - members = [ - "serviceAccount:service-${data.google_project.project.number}@gcp-sa-gkehub.iam.gserviceaccount.com", - ] -} - -// Register each cluster to GKE Hub (Fleets API) -// https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/gke_hub_feature_membership#configmanagement -resource "google_gke_hub_membership" "membership" { - provider = google-beta - for_each = var.cluster_config - project = var.project_id - - membership_id = "${each.key}-membership" - endpoint { - gke_cluster { - resource_link = "//container.googleapis.com/projects/${var.project_id}/locations/${var.regional_clusters ? each.value.region : each.value.zones[0]}/clusters/${each.key}" - } - } - authority { - issuer = "https://container.googleapis.com/v1/projects/${var.project_id}/locations/${var.regional_clusters ? each.value.region : each.value.zones[0]}/clusters/${each.key}" - } -} \ No newline at end of file diff --git a/terraform/modules/mcg/mcg.tf b/terraform/modules/mcg/mcg.tf deleted file mode 100644 index c312e36f..00000000 --- a/terraform/modules/mcg/mcg.tf +++ /dev/null @@ -1,127 +0,0 @@ -// Defines vars so that we can pass them in from cluster_build/main.tf from the overall tfvars -variable "project_id" { -} - -variable "vpc_project_id" { -} -variable "cluster_config" { -} -variable "vpc_name" { -} -variable "gateway_crds_version" { - default = "v0.3.0" -} - -data "google_project" "project" { - project_id = var.project_id -} - -// https://cloud.google.com/kubernetes-engine/docs/how-to/multi-cluster-ingress-setup#shared_vpc_deployment -module "firewall_rules" { - source = "terraform-google-modules/network/google//modules/firewall-rules" - project_id = var.vpc_project_id - network_name = var.vpc_name - - rules = [{ - name = "allow-glcb-backend-ingress" - description = null - direction = "INGRESS" - priority = null - ranges = ["130.211.0.0/22", "35.191.0.0/16"] - source_tags = null - source_service_accounts = null - target_tags = null - target_service_accounts = null - allow = [{ - protocol = "tcp" - ports = ["0-65535"] - }] - deny = [] - log_config = { - metadata = "INCLUDE_ALL_METADATA" - } - }] -} - -// Install gateway api crds on each cluster -resource "null_resource" "exec_mcg_crds" { - depends_on = [ - resource.google_gke_hub_feature.mcs, - ] - for_each = var.cluster_config - provisioner "local-exec" { - interpreter = ["bash", "-exc"] - command = "scripts/install_crds.sh" - working_dir = path.module - environment = { - CLUSTER = each.key - LOCATION = each.value.region - PROJECT_ID = var.project_id - GATEWAY_API_VERSION = var.gateway_crds_version - } - } -} - -// enable Multi-cluster service discovery -resource "google_gke_hub_feature" "mcs" { - name = "multiclusterservicediscovery" - location = "global" - project = var.project_id - provider = google-beta -} - -// enable Multi-cluster Ingress(also gateway) project wide -resource "google_gke_hub_feature" "mci" { - depends_on = [ - null_resource.exec_mcg_crds, - ] - name = "multiclusteringress" - location = "global" - project = var.project_id - spec { - multiclusteringress { - config_membership = "projects/${var.project_id}/locations/global/memberships/${keys(var.cluster_config)[0]}-membership" - } - } - provider = google-beta -} - -// Create IAM binding allowing the hub project's MCS service account access to the shared vpc project -resource "google_project_iam_binding" "host-serviceagent" { - role = "roles/multiclusterservicediscovery.serviceAgent" - project = var.vpc_project_id - members = [ - "serviceAccount:service-${data.google_project.project.number}@gcp-sa-mcsd.iam.gserviceaccount.com", - ] -} - -// Create IAM binding allowing the hub project's MCS service account access to the gke cluster project -resource "google_project_iam_binding" "member-serviceagent" { - role = "roles/multiclusterservicediscovery.serviceAgent" - project = var.project_id - members = [ - "serviceAccount:service-${data.google_project.project.number}@gcp-sa-mcsd.iam.gserviceaccount.com", - ] -} - -resource "google_project_iam_binding" "network-viewer-member" { - depends_on = [ - resource.google_gke_hub_feature.mcs, - ] - role = "roles/compute.networkViewer" - project = var.project_id - members = [ - "serviceAccount:${var.project_id}.svc.id.goog[gke-mcs/gke-mcs-importer]", - ] -} - -resource "google_project_iam_binding" "container-admin-mcgsa" { - role = "roles/container.admin" - project = var.project_id - depends_on = [ - resource.google_gke_hub_feature.mci, - ] - members = [ - "serviceAccount:service-${data.google_project.project.number}@gcp-sa-multiclusteringress.iam.gserviceaccount.com", - ] -} diff --git a/terraform/modules/mcg/scripts/install_crds.sh b/terraform/modules/mcg/scripts/install_crds.sh deleted file mode 100755 index 0b9aae90..00000000 --- a/terraform/modules/mcg/scripts/install_crds.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -# Verify variables -echo -e "Project is ${PROJECT_ID}" -echo -e "CLUSTER is ${CLUSTER}" -echo -e "LOCATION is ${LOCATION}" -echo -e "GATEWAY_API_VERSION is ${GATEWAY_API_VERSION}" - -export WORKDIR=`pwd` -kubeconfig=tempkubeconfig$RANDOM -echo -e "Adding cluster ${CLUSTER} to kubeconfig located at ${WORKDIR}/tempkubeconfig" -echo -e "Creating tempkubeconfig." -rm ${WORKDIR}/${kubeconfig} -touch ${WORKDIR}/${kubeconfig} -export KUBECONFIG=${WORKDIR}/${kubeconfig} - -# Get cluster creds -gcloud beta container fleet memberships get-credentials ${CLUSTER}-membership --project ${PROJECT_ID} -CONTEXT=`kubectl config view -o jsonpath='{.users[0].name}' --kubeconfig ${KUBECONFIG}` -# Install Gateway API CRDs -echo -e "Installing GatewayAPI CRDs" - -kubectl apply -k "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v0.5.0" --kubeconfig ${KUBECONFIG} --context=${CONTEXT} \ No newline at end of file diff --git a/terraform/modules/shared_vpc/main.tf b/terraform/modules/network/main.tf similarity index 67% rename from terraform/modules/shared_vpc/main.tf rename to terraform/modules/network/main.tf index fcfea640..ae1706cb 100644 --- a/terraform/modules/shared_vpc/main.tf +++ b/terraform/modules/network/main.tf @@ -21,12 +21,27 @@ data "google_project" "project" { // Locals used to construct names of stuffs. locals { + # VPC Self-link + vpc_selflink = format("projects/%s/global/networks/%s", var.project_id, var.vpc_name) + + # Distinct cluster regions + distinct_cluster_regions = toset([for cluster in var.cluster_config : cluster.region]) + // Presets for Service Accounts clu_service_account = format("service-%s@container-engine-robot.iam.gserviceaccount.com", data.google_project.project.number) prj_service_account = format("%s@cloudservices.gserviceaccount.com", data.google_project.project.number) // Dynamically create subnet and secondary subnet inputs for multi-cluster creation - nested_subnets = flatten([ + admin_subnet = flatten([ + { + subnet_name = "admin-control-plane" + subnet_ip = "10.0.100.0/24" + subnet_region = "us-central1" + subnet_private_access = true + description = "This subnet is for the admin control plane and is managed by Terraform" + } + ]) + nested_subnets_raw = flatten([ for name, config in var.cluster_config : [ { subnet_name = config.subnet_name @@ -38,7 +53,22 @@ locals { ] ]) - nested_secondary_subnets = { + nested_subnets = concat(local.admin_subnet, local.nested_subnets_raw) + + admin_secondary_subnets = { + "admin-control-plane" = [ + { + range_name = "admin-pods" + ip_cidr_range = "10.101.0.0/17" + }, + { + range_name = "admin-svcs" + ip_cidr_range = "10.103.0.0/17" + } + ] + } + + nested_secondary_subnets = merge(local.admin_secondary_subnets, { for name, config in var.cluster_config : config.subnet_name => [ { range_name = var.vpc_ip_range_pods_name @@ -47,14 +77,14 @@ locals { { range_name = var.vpc_ip_range_services_name ip_cidr_range = "10.${index(keys(var.cluster_config), name) + 1}.128.0/17" - } + }, ] - } + }) } module "enabled_shared_vpc_apis" { source = "terraform-google-modules/project-factory/google//modules/project_services" - version = "~> 14.2.0" + version = "~> 17.0" project_id = var.vpc_project_id disable_services_on_destroy = true @@ -63,12 +93,13 @@ module "enabled_shared_vpc_apis" { "compute.googleapis.com", "container.googleapis.com", "dns.googleapis.com", + "iam.googleapis.com", ] } module "enabled_service_project_apis" { source = "terraform-google-modules/project-factory/google//modules/project_services" - version = "~> 14.2.0" + version = "~> 17.0" project_id = var.project_id disable_services_on_destroy = false @@ -76,5 +107,9 @@ module "enabled_service_project_apis" { activate_apis = [ "compute.googleapis.com", "container.googleapis.com", + "iam.googleapis.com", + "compute.googleapis.com", + "container.googleapis.com", + "cloudresourcemanager.googleapis.com", ] } \ No newline at end of file diff --git a/terraform/modules/cluster_build/network.tf b/terraform/modules/network/network.tf similarity index 72% rename from terraform/modules/cluster_build/network.tf rename to terraform/modules/network/network.tf index 45aa6cc0..ed26de01 100644 --- a/terraform/modules/cluster_build/network.tf +++ b/terraform/modules/network/network.tf @@ -15,11 +15,14 @@ */ module "vpc" { - count = var.shared_vpc ? 0 : 1 + depends_on = [ + module.enabled_shared_vpc_apis, + module.enabled_service_project_apis + ] source = "terraform-google-modules/network/google" - version = "~> 6.0.1" + version = "~> 9.2.0" - project_id = module.enabled_google_apis.project_id + project_id = var.vpc_project_id network_name = var.vpc_name routing_mode = "GLOBAL" @@ -28,24 +31,17 @@ module "vpc" { secondary_ranges = local.nested_secondary_subnets } -module "cluster-nat" { - depends_on = [ - module.vpc, - ] - for_each = local.distinct_cluster_regions - version = "~> 2.2.2" +# Cloud NAT Module +module "cluster_nat" { + depends_on = [module.vpc] + for_each = local.distinct_cluster_regions + source = "terraform-google-modules/cloud-nat/google" + version = "~> 5.0" create_router = true - project_id = local.project_id + project_id = var.project_id region = each.key router = "gke-toolkit-rtr-${each.key}" network = local.vpc_selflink source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_PRIMARY_IP_RANGES" -} - -data "template_file" "startup_script" { - template = <<-EOF - sudo apt-get update -y - sudo apt-get install -y tinyproxy - EOF } \ No newline at end of file diff --git a/terraform/modules/shared_vpc/provider.tf b/terraform/modules/network/provider.tf similarity index 81% rename from terraform/modules/shared_vpc/provider.tf rename to terraform/modules/network/provider.tf index 6d0bd7e9..95b18fb5 100644 --- a/terraform/modules/shared_vpc/provider.tf +++ b/terraform/modules/network/provider.tf @@ -15,20 +15,19 @@ */ terraform { + required_version = ">=0.13.0" required_providers { google = { - version = ">= 3.53.0, < 5.0.0" + source = "hashicorp/google" + version = ">= 5.41, < 7" } google-beta = { - version = ">= 4.3.0, < 5.0.0" - } - kubernetes = { - version = "~> 2.0" + source = "hashicorp/google-beta" + version = ">= 5.41, < 7" } } } provider "google" { project = var.vpc_project_id - region = var.region } diff --git a/terraform/modules/shared_vpc/attach-vpc.tf b/terraform/modules/network/shared_vpc.tf similarity index 67% rename from terraform/modules/shared_vpc/attach-vpc.tf rename to terraform/modules/network/shared_vpc.tf index 1b8104b7..02401fc6 100644 --- a/terraform/modules/shared_vpc/attach-vpc.tf +++ b/terraform/modules/network/shared_vpc.tf @@ -17,11 +17,20 @@ // Performs necessary steps to attach service project to Shared VPC host project // Modules and resources below do not get executed if SHARED_VPC=false +resource "google_compute_shared_vpc_host_project" "host_project" { + count = var.shared_vpc ? 1 : 0 + depends_on = [ + module.vpc, + ] + provider = google-beta + project = var.vpc_project_id +} + resource "google_compute_subnetwork_iam_binding" "subnet_networkuser" { depends_on = [ - module.shared_vpc + module.vpc ] - for_each = var.cluster_config + for_each = { for key, value in var.cluster_config : key => value if var.shared_vpc != false } project = var.vpc_project_id region = each.value.region subnetwork = each.value.subnet_name @@ -32,7 +41,23 @@ resource "google_compute_subnetwork_iam_binding" "subnet_networkuser" { ] } +resource "google_compute_subnetwork_iam_binding" "subnet_networkuser_cp" { + count = var.shared_vpc ? 1 : 0 + depends_on = [ + google_compute_subnetwork_iam_binding.subnet_networkuser + ] + project = var.vpc_project_id + region = "us-central1" + subnetwork = "admin-control-plane" + role = "roles/compute.networkUser" + members = [ + "serviceAccount:${local.clu_service_account}", + "serviceAccount:${local.prj_service_account}", + ] +} + resource "google_project_iam_binding" "shared_vpc_serviceagent" { + count = var.shared_vpc ? 1 : 0 depends_on = [ google_compute_subnetwork_iam_binding.subnet_networkuser ] @@ -44,6 +69,7 @@ resource "google_project_iam_binding" "shared_vpc_serviceagent" { } resource "google_compute_shared_vpc_service_project" "attach_toolkit" { + count = var.shared_vpc ? 1 : 0 depends_on = [ google_compute_subnetwork_iam_binding.subnet_networkuser, google_project_iam_binding.shared_vpc_serviceagent, diff --git a/terraform/modules/shared_vpc/variables.tf b/terraform/modules/network/variables.tf similarity index 91% rename from terraform/modules/shared_vpc/variables.tf rename to terraform/modules/network/variables.tf index 650fddbe..7600ca11 100644 --- a/terraform/modules/shared_vpc/variables.tf +++ b/terraform/modules/network/variables.tf @@ -25,6 +25,12 @@ variable "vpc_project_id" { default = "" } +variable "shared_vpc" { + type = bool + description = "Determines whether to create a standalone VPC or use an existing Shared VPC" + default = false +} + variable "region" { type = string description = "The region to host the cluster in" diff --git a/terraform/modules/shared_vpc/network.tf b/terraform/modules/shared_vpc/network.tf deleted file mode 100644 index d35043ed..00000000 --- a/terraform/modules/shared_vpc/network.tf +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * 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. - */ - -module "shared_vpc" { - depends_on = [ - module.enabled_shared_vpc_apis, - module.enabled_service_project_apis - ] - source = "terraform-google-modules/network/google" - version = "~> 6.0.1" - - project_id = var.vpc_project_id - network_name = var.vpc_name - # routing_mode = "GLOBAL" default in terraform-google-network - - subnets = local.nested_subnets - - secondary_ranges = local.nested_secondary_subnets -} - -resource "google_compute_shared_vpc_host_project" "host_project" { - depends_on = [ - module.shared_vpc, - ] - provider = google-beta - project = var.vpc_project_id -} \ No newline at end of file diff --git a/terraform/modules/shared_vpc/outputs.tf b/terraform/modules/shared_vpc/outputs.tf deleted file mode 100644 index e69de29b..00000000 diff --git a/terraform/modules/windows_nodepool/main.tf b/terraform/modules/windows_nodepool/main.tf deleted file mode 100644 index 1609aa4b..00000000 --- a/terraform/modules/windows_nodepool/main.tf +++ /dev/null @@ -1,94 +0,0 @@ -// Defines vars so that we can pass them in from cluster_build/cluster.tf from the overall tfvars -variable "cluster_config" { -} - -variable "name" { -} - -variable "project_id" { -} - -variable "min_count" { -} - -variable "max_count" { -} - -variable "disk_size_gb" { -} - -variable "disk_type" { -} - -variable "image_type" { -} - -variable "machine_type" { -} - -variable "initial_node_count" { -} - -variable "service_account" { -} - -variable "enable_integrity_monitoring" { -} - -variable "enable_secure_boot" { -} - - -// Add Windows Node Pool to each GKE cluster created -// https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_node_pool -resource "google_container_node_pool" "windows" { - for_each = var.cluster_config - name = var.name - location = each.value.region - cluster = each.key - initial_node_count = var.initial_node_count - - autoscaling { - min_node_count = var.min_count - max_node_count = var.max_count - } - - node_config { - disk_type = "pd-ssd" - image_type = "WINDOWS_SAC" - disk_size_gb = 100 - machine_type = var.machine_type - - # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles. - service_account = var.service_account - oauth_scopes = [ - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/logging.write", - "https://www.googleapis.com/auth/monitoring", - ] - } - - timeouts { - create = "60m" - update = "60m" - } -} - - - -# // Presets for Windows Node Pool -# windows_pool = [{ -# name = format("windows-%s", var.node_pool) -# min_count = var.min_node_count -# max_count = var.max_node_count -# disk_size_gb = 100 -# disk_type = "pd-ssd" -# image_type = "WINDOWS_SAC" -# machine_type = var.windows_machine_type -# initial_node_count = var.initial_node_count -# // Intergrity Monitoring is not enabled in Windows Node pools yet. -# enable_integrity_monitoring = false -# enable_secure_boot = true -# }] - -