/* ███████╗██╗░░░██╗███████╗██████╗░███████╗ ██╔════╝╚██╗░██╔╝██╔════╝██╔══██╗██╔════╝ █████╗░░░╚████╔╝░█████╗░░██║░░██║█████╗░░ ██╔══╝░░░░╚██╔╝░░██╔══╝░░██║░░██║██╔══╝░░ ███████╗░░░██║░░░███████╗██████╔╝███████╗ ╚══════╝░░░╚═╝░░░╚══════╝╚═════╝░╚══════╝ CLI program written to populate IENode resources within the cluster infra cluster for all existing terminals To run the program permissions to access the DB and PubSub are first required. This can be done by creating an ADC file for the bff-sa service account and setting the "GOOGLE_APPLICATION_CREDENTIALS" environment variable to the path of this file, e.g. gcloud auth application-default login --no-launch-browser --impersonate-service-account=bff-sa@ret-edge-dev0-foreman.iam.gserviceaccount.com export GOOGLE_APPLICATION_CREDENTIALS="~/.config/gcloud/application_default_credentials.json" The cli program can then be run like so: Using Database: cicterminals useDatabase --databaseHost=ret-edge-dev0-foreman:us-central1:edge-dev0 --databaseName=edge-dev0 --databaseUser=bff-sa@ret-edge-dev0-foreman.iam --topLevelProjectID=ret-edge-dev0-foreman --chariotTopic=chariot-rides The following flags are required for the cli to run: databaseHost, databaseName, databaseUser, topLevelProjectID and chariotTopic The dryRun flag is an optional and defaults to false if not specified. launchdarklyKey is also an optional flag that defaults to using cluster id if not set. Once the script has finished running you should reset your gcloud login to your user account export GOOGLE_APPLICATION_CREDENTIALS="" gcloud config unset auth/impersonate_service_account gcloud auth application-default login --no-launch-browser */ package main import ( "context" "database/sql" "errors" "flag" "fmt" "os" _ "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/dialers/postgres" "github.com/peterbourgon/ff/v3/ffcli" "edge-infra.dev/pkg/lib/gcp/cloudsql" "edge-infra.dev/hack/tools/cicterminals/cicterminals" usedatabase "edge-infra.dev/hack/tools/cicterminals/use-database" "edge-infra.dev/pkg/edge/api/utils" "edge-infra.dev/pkg/lib/cli/commands" ) var ( fs = flag.NewFlagSet("cicterminals", flag.ExitOnError) databaseHost = fs.String("databaseHost", os.Getenv("DatabaseHost"), "the host of the database to query") databaseName = fs.String("databaseName", os.Getenv("DatabaseName"), "the name of the database to query") databaseUser = fs.String("databaseUser", os.Getenv("DatabaseUser"), "the user of the specified database") topLevelProjectID = fs.String("topLevelProjectID", os.Getenv("TopLevelProjectID"), "the top level project id") chariotTopic = fs.String("chariotTopic", os.Getenv("ChariotTopic"), "chariot pubsub topic") launchdarklyKey = fs.String("launchdarklyKey", os.Getenv("LD_KEY"), "launch darkly sdk key") dryRun = fs.Bool("dryRun", false, "run cicterminals in dryRun mode and output results in stdout") errDatabaseHostRequired = errors.New("error database host is required") errDatabaseNameRequired = errors.New("error database name is required") errDatabaseUserRequired = errors.New("error database user is required") errTopLevelProjectIDRequired = errors.New("error top level project id is required") errChariotTopicRequired = errors.New("error chariot topic is required") ) func main() { fmt.Println(os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")) err := fs.Parse(os.Args[2:]) if err != nil { fmt.Fprintln(os.Stderr, "Flag parsing error ", err) os.Exit(1) } if err := validateRequiredFlags(); err != nil { fmt.Fprintln(os.Stderr, "Flag validation error ", err) os.Exit(1) } if utils.IsNullOrEmpty(launchdarklyKey) { os.Setenv("LD_KEY", *launchdarklyKey) } eyeConfig := cicterminals.New() fmt.Println("") fmt.Println(` ███████╗██╗░️░️░██╗███████╗██████╗░███████╗ ██╔════╝╚██╗░██╔╝██╔════╝██╔══██╗██╔════╝ 👁 █████╗░░░╚████╔╝░█████╗░░██║░░██║█████╗░░ ️️👁 ██╔══╝░░░░╚██╔╝░░██╔══╝░░██║░░██║██╔══╝░░ ███████╗░░░██║░░░███████╗██████╔╝███████╗ ╚══════╝░░░╚═╝░░░╚══════╝╚═════╝░╚══════╝ `) fmt.Println("") fmt.Printf("Connecting to Database: %s with user %s\n", *databaseName, *databaseUser) db, err := connectToDatabase() if err != nil { fmt.Fprintln(os.Stderr, "db connection error occurred ", err) os.Exit(1) } eyeConfig.SetDBConnection(db) useDatabase := eyeConfig.Exec("useDatabase", "cicterminals useDatabase", "populate the IENode CR in CIC using the SQL Database", *topLevelProjectID, *chariotTopic, *dryRun, usedatabase.CreateIENode, fs) cmd := &ffcli.Command{ Name: "cicterminals", ShortUsage: "cicterminals --databaseHost=ret-edge-dev0-foreman:us-central1:edge-dev0 --databaseName=edge-dev0 --databaseUser=bff-sa@ret-edge-dev0-foreman.iam --topLevelProjectID=ret-edge-dev0-foreman --chariotTopic=chariot-rides", ShortHelp: "populate IENode CR for all terminals", Subcommands: []*ffcli.Command{ useDatabase, commands.Version(), }, } if err := cmd.ParseAndRun(context.Background(), os.Args[1:]); err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } } func validateRequiredFlags() error { if utils.IsNullOrEmpty(databaseHost) { return errDatabaseHostRequired } if utils.IsNullOrEmpty(databaseName) { return errDatabaseNameRequired } if utils.IsNullOrEmpty(databaseUser) { return errDatabaseUserRequired } if utils.IsNullOrEmpty(topLevelProjectID) { return errTopLevelProjectIDRequired } if utils.IsNullOrEmpty(chariotTopic) { return errChariotTopicRequired } return nil } func connectToDatabase() (*sql.DB, error) { return cloudsql.GCPPostgresConnection(*databaseHost).Username(*databaseUser).DBName(*databaseName).NewConnection() }