Skip to content

Commit aed0c0e

Browse files
authored
Improvements (#175)
Replaced Update and Create commands with Apply Added flag to pass in gke cluster and shared vpc TF state storage buckets Refactored the k8s api check to use a connect gw cred Co-authored-by: Nick Eberts <[email protected]>
1 parent b756d69 commit aed0c0e

14 files changed

+110
-124
lines changed

README.md

+8-4
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ curl -sLSf -o ./gkekitctl https://github.com/GoogleCloudPlatform/gke-poc-toolkit
4646
./gkekitctl init
4747
```
4848

49-
7. **Run `gkekitctl create` to run the Toolkit.** By default, this command sets up a single-cluster GKE environment. ([Configuration here](cli/pkg/cli_init/samples/default-config.yaml)). Enter your project ID when prompted.
49+
7. **Run `gkekitctl apply` to run the Toolkit.** By default, this command sets up a single-cluster GKE environment. ([Configuration here](cli/pkg/cli_init/samples/default-config.yaml)). Enter your project ID when prompted.
5050

5151
```shell
52-
./gkekitctl create
52+
./gkekitctl apply
5353
```
5454
```shell
5555
# expected output
@@ -73,9 +73,13 @@ time="2022-02-04T21:58:00Z" level=info msg="🌎 5 Namespaces found in cluster=g
7373

7474
## Update
7575

76-
If you want to update your environment change the config file and run the update command. This is a great way to add or remove clusters.
76+
If you want to update your environment change the config file and re-run the apply command. This is a great way to add or remove clusters.
7777
```bash
78-
./gkekitctl update --config <config file name>
78+
## Local tf state
79+
./gkekitctl apply --config <"config file name">
80+
81+
## If you are using remote TF state
82+
./gkekitctl apply --config <"config file name"> --gkestate <"bucket name used for state file"> --vpcstate <"if using sharevpc, bucket name for shared vpc state file">
7983
```
8084

8185
## Clean up

cli/cmd/create.go renamed to cli/cmd/apply.go

+31-9
Original file line numberDiff line numberDiff line change
@@ -26,26 +26,43 @@ import (
2626
)
2727

2828
// createCmd represents the create command
29-
var createCmd = &cobra.Command{
30-
Use: "create",
31-
Short: "Create GKE Demo Environment",
32-
Example: ` gkekitctl create
33-
gkekitctl create --config <file.yaml>`,
29+
var applyCmd = &cobra.Command{
30+
Use: "apply",
31+
Short: "Create or Update GKE Demo Environment",
32+
Example: ` gkekitctl apply
33+
gkekitctl apply --config <file.yaml>`,
3434
Run: func(cmd *cobra.Command, args []string) {
35+
bucketNameClusters, err := cmd.Flags().GetString("gkestate")
36+
if err != nil {
37+
log.Errorf("🚨Failed to get bucketNameClusters value from flag: %s", err)
38+
}
39+
if bucketNameClusters != "" {
40+
log.Infof("✅ Terraform state storage bucket for clusters is %s", bucketNameClusters)
41+
}
42+
bucketNameSharedVPC, err := cmd.Flags().GetString("vpcstate")
43+
if err != nil {
44+
log.Errorf("🚨Failed to get bucketNameSharedVPC value from flag: %s", err)
45+
}
46+
if bucketNameSharedVPC != "" {
47+
log.Infof("✅ Terraform state storage bucket for shared VPC is %s", bucketNameSharedVPC)
48+
}
49+
3550
log.Info("👟 Started config validation...")
3651
conf := config.InitConf(cfgFile)
37-
log.Info("👟 Started generating TFVars...")
3852

3953
// Send user analytics - async
4054
if conf.SendAnalytics {
4155
go analytics.SendAnalytics(conf, Version, GitCommit)
4256
}
4357

58+
log.Info("👟 Started generating TFVars...")
4459
config.GenerateTfvars(conf)
60+
4561
log.Info("👟 Started configuring TF State...")
46-
err := config.CheckTfStateType(conf)
62+
err = config.CheckTfStateType(conf, bucketNameClusters, bucketNameSharedVPC)
63+
4764
if err != nil {
48-
log.Errorf("🚨 Failed checking TF state type: %s", err)
65+
log.Errorf("🚨 Failed setting up TF state: %s", err)
4966
} else {
5067
log.Info("✅ TF state configured successfully.")
5168
}
@@ -78,5 +95,10 @@ var createCmd = &cobra.Command{
7895
}
7996

8097
func init() {
81-
rootCmd.AddCommand(createCmd)
98+
var bucketNameClusters string
99+
var bucketNameSharedVPC string
100+
101+
rootCmd.AddCommand(applyCmd)
102+
applyCmd.Flags().StringVarP(&bucketNameClusters, "gkestate", "g", "", "GKE Tf State bucket name")
103+
applyCmd.Flags().StringVarP(&bucketNameSharedVPC, "vpcstate", "v", "", "Shared VPC Tf State bucket name")
82104
}

cli/cmd/root.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func init() {
6161
// Cobra supports persistent flags, which, if defined here,
6262
// will be global for your application.
6363

64-
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is /.gkekitctl.yaml)")
64+
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file (default is /.gkekitctl.yaml)")
6565

6666
// Cobra also supports local flags, which will only run
6767
// when this action is called directly.

cli/cmd/update.go

-68
This file was deleted.

cli/pkg/config/tf_state.go

+34-13
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package config
1818

1919
import (
2020
"context"
21+
"fmt"
2122
"html/template"
2223
"os"
2324
"strings"
@@ -27,40 +28,60 @@ import (
2728
"github.com/thanhpk/randstr"
2829
)
2930

30-
func CheckTfStateType(conf *Config) error {
31+
func CheckTfStateType(conf *Config, bucketNameClusters string, bucketNameSharedVPC string) error {
3132
if conf.TerraformState == "cloud" {
32-
bucketNames := [3]string{}
3333
if conf.VpcConfig.VpcType == "shared" {
34-
bucketNameSharedVPC := "tf-state-sharedvpc-" + strings.ToLower(randstr.String(6))
35-
err := createTfBackend(conf.VpcConfig.VpcProjectID, bucketNameSharedVPC, "shared_vpc/backend.tf")
34+
if bucketNameSharedVPC == "" {
35+
bucketNameSharedVPC := "tf-state-sharedvpc-" + strings.ToLower(randstr.String(6))
36+
err := createTfStorage(conf.VpcConfig.VpcProjectID, bucketNameSharedVPC)
37+
if err != nil {
38+
return err
39+
}
40+
}
41+
err := createTfBackend(bucketNameSharedVPC, "shared_vpc/backend.tf")
42+
if err != nil {
43+
return err
44+
}
45+
}
46+
if bucketNameClusters == "" {
47+
log.Infof("Clusters Bucket Name: %s", bucketNameClusters)
48+
bucketNameClusters := "tf-state-clusters-" + strings.ToLower(randstr.String(6))
49+
err := createTfStorage(conf.ClustersProjectID, bucketNameClusters)
3650
if err != nil {
3751
return err
3852
}
3953
}
40-
bucketNameClusters := "tf-state-clusters-" + strings.ToLower(randstr.String(6))
41-
err := createTfBackend(conf.ClustersProjectID, bucketNameClusters, "cluster_build/backend.tf")
54+
err := createTfBackend(bucketNameClusters, "cluster_build/backend.tf")
4255
if err != nil {
4356
return err
4457
}
45-
log.Print(bucketNames)
4658
return nil
4759
}
4860
return nil
4961
}
5062

5163
// func CreateTfStateBucket(projectId string, bucketName string) error {
52-
func createTfBackend(projectId string, bucketName string, fileLocation string) error {
64+
func createTfStorage(projectId string, bucketName string) error {
5365
ctx := context.Background()
5466
c, err := storage.NewClient(ctx)
5567
if err != nil {
56-
log.Fatalf("error creating storage client: %s", err)
5768
return err
5869
}
59-
err = c.Bucket(bucketName).Create(ctx, projectId, nil)
60-
if err != nil {
61-
log.Fatalf("error creating storage bucket: %s", err)
62-
return err
70+
attrs, err := c.Bucket(bucketName).Attrs(ctx)
71+
if err == storage.ErrBucketNotExist {
72+
log.Infof("Creating storage bucket: %s ", bucketName)
73+
err = c.Bucket(bucketName).Create(ctx, projectId, nil)
74+
if err != nil {
75+
log.Fatalf("error creating storage bucket: %s", err)
76+
return err
77+
}
78+
} else {
79+
fmt.Printf("The bucket exists and has attributes: %#v\n", attrs)
6380
}
81+
return err
82+
}
83+
84+
func createTfBackend(bucketName string, fileLocation string) error {
6485
vars := make(map[string]interface{})
6586
vars["TfStateBucket"] = bucketName
6687
tmpl, err := template.ParseFiles("templates/terraform_backend.tf.tmpl")

cli/pkg/lifecycle/kubernetes_helpers.go

+28-21
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ package lifecycle
1818

1919
import (
2020
"context"
21-
"encoding/base64"
2221
"fmt"
2322
"gkekitctl/pkg/config"
23+
"strconv"
2424

2525
log "github.com/sirupsen/logrus"
26+
"google.golang.org/api/cloudresourcemanager/v1"
2627
"google.golang.org/api/container/v1"
2728
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2829
"k8s.io/client-go/kubernetes"
@@ -33,6 +34,11 @@ import (
3334

3435
func GenerateKubeConfig(conf *config.Config) (*api.Config, error) {
3536
projectId := conf.ClustersProjectID
37+
projectNumber, err := GetProjectNumber(projectId)
38+
if err != nil {
39+
return api.NewConfig(), fmt.Errorf("GetProjectNumber: %w", err)
40+
}
41+
3642
log.Infof("Clusters Project ID is %s", projectId)
3743
ctx := context.Background()
3844

@@ -57,21 +63,12 @@ func GenerateKubeConfig(conf *config.Config) (*api.Config, error) {
5763
}
5864

5965
for _, f := range resp.Clusters {
60-
name := fmt.Sprintf("gke_%s_%s_%s", projectId, f.Zone, f.Name)
66+
name := fmt.Sprintf("connectgateway_%s_global_%s-membership", projectId, f.Name)
67+
server := fmt.Sprintf("https://connectgateway.googleapis.com/v1beta1/projects/%s/locations/global/gkeMemberships/%s-membership", projectNumber, f.Name)
6168
log.Infof("Connecting to cluster: %s,", name)
62-
cert, err := base64.StdEncoding.DecodeString(f.MasterAuth.ClusterCaCertificate)
63-
if err != nil {
64-
return &ret, fmt.Errorf("invalid certificate cluster=%s cert=%s: %w", name, f.MasterAuth.ClusterCaCertificate, err)
65-
}
66-
// example: gke_my-project_us-central1-b_cluster-1 => https://XX.XX.XX.XX
67-
proxy := ""
68-
if conf.PrivateEndpoint {
69-
proxy = "http://localhost:8888"
70-
}
69+
7170
ret.Clusters[name] = &api.Cluster{
72-
CertificateAuthorityData: cert,
73-
Server: "https://" + f.Endpoint,
74-
ProxyURL: proxy,
71+
Server: server,
7572
}
7673
// Just reuse the context name as an auth name.
7774
ret.Contexts[name] = &api.Context{
@@ -82,18 +79,15 @@ func GenerateKubeConfig(conf *config.Config) (*api.Config, error) {
8279
ret.AuthInfos[name] = &api.AuthInfo{
8380
AuthProvider: &api.AuthProviderConfig{
8481
Name: "gcp",
85-
Config: map[string]string{
86-
"scopes": "https://www.googleapis.com/auth/cloud-platform",
87-
},
8882
},
8983
}
9084
}
9185

9286
// Write kubeconfig to YAML file
93-
// err = clientcmd.WriteToFile(ret, "kubeconfig")
94-
// if err != nil {
95-
// return &ret, err
96-
// }
87+
err = clientcmd.WriteToFile(ret, "kubeconfig")
88+
if err != nil {
89+
return &ret, err
90+
}
9791
return &ret, nil
9892
}
9993

@@ -125,6 +119,19 @@ func ListNamespaces(kubeConfig *api.Config) error {
125119
return nil
126120
}
127121

122+
func GetProjectNumber(project_id string) (string, error) {
123+
ctx := context.Background()
124+
cloudresourcemanagerService, err := cloudresourcemanager.NewService(ctx)
125+
if err != nil {
126+
fmt.Errorf("cloudresourcemanager.NewService: %w", err)
127+
}
128+
project, err := cloudresourcemanagerService.Projects.Get(project_id).Do()
129+
if err != nil {
130+
fmt.Errorf("cloudresourcemanager.NewService: %w", err)
131+
}
132+
return strconv.FormatInt(project.ProjectNumber, 10), nil
133+
}
134+
128135
// Kubectl apply using client.go
129136
// func Apply(config *rest.Config, clusterName string, fileName []byte) error {
130137

test/e2e/cloudbuild-default-config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ steps:
116116
gcloud auth application-default print-access-token
117117
gcloud config set project $$TEST_PROJECT_ID
118118
gcloud auth list
119-
./gkekitctl create --config samples/default-config.yaml
119+
./gkekitctl apply --config samples/default-config.yaml
120120
timeout: "60m"
121121
availableSecrets:
122122
secretManager:

test/e2e/cloudbuild-module-bypass-multi-clusters-networking-acm-standalone-vpc.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ steps:
117117
gcloud auth application-default print-access-token
118118
gcloud config set project $$TEST_PROJECT_ID
119119
gcloud auth list
120-
./gkekitctl create --config samples/module-bypass-multi-clusters-networking-acm-standalone-vpc.yaml
120+
./gkekitctl apply --config samples/module-bypass-multi-clusters-networking-acm-standalone-vpc.yaml
121121
timeout: "60m"
122122
availableSecrets:
123123
secretManager:

test/e2e/cloudbuild-multi-clusters-acm-shared-vpc.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ steps:
129129
gcloud auth application-default print-access-token
130130
gcloud config set project $$TEST_PROJECT_ID
131131
gcloud auth list
132-
./gkekitctl create --config samples/multi-clusters-shared-vpc.yaml
132+
./gkekitctl apply --config samples/multi-clusters-shared-vpc.yaml
133133
timeout: "60m"
134134
availableSecrets:
135135
secretManager:

test/e2e/cloudbuild-multi-clusters-acm-standalone-vpc.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ steps:
117117
gcloud auth application-default print-access-token
118118
gcloud config set project $$TEST_PROJECT_ID
119119
gcloud auth list
120-
./gkekitctl create --config samples/multi-clusters-standalone-vpc.yaml
120+
./gkekitctl apply --config samples/multi-clusters-standalone-vpc.yaml
121121
timeout: "60m"
122122
availableSecrets:
123123
secretManager:

test/e2e/cloudbuild-multi-clusters-networking-acm-shared-vpc.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ steps:
128128
gcloud auth application-default print-access-token
129129
gcloud config set project $$TEST_PROJECT_ID
130130
gcloud auth list
131-
./gkekitctl create --config samples/multi-clusters-networking-acm-shared-vpc.yaml
131+
./gkekitctl apply --config samples/multi-clusters-networking-acm-shared-vpc.yaml
132132
timeout: "60m"
133133
availableSecrets:
134134
secretManager:

0 commit comments

Comments
 (0)