package sequel import ( "database/sql" "flag" "fmt" "github.com/peterbourgon/ff/v3" "edge-infra.dev/pkg/edge/controllers/sequel/dbctl" "edge-infra.dev/pkg/lib/gcp/cloudsql" ) // config is the controllers application config type config struct { host string connectionName string name string user string password string port string db *dbctl.DB namespace string projectID string concurrency int } // newConfig creates the controller config, reading initial values via flags and // environment variables via ff func newConfig(args []string) (*config, error) { fs := flag.NewFlagSet("sequel", flag.ExitOnError) cfg := &config{} cfg.bindFlags(fs) if err := ff.Parse(fs, args, ff.WithEnvVarNoPrefix()); err != nil { return nil, fmt.Errorf("failed to parse configuration: %w", err) } if err := cfg.validate(); err != nil { return nil, fmt.Errorf("invalid configuration: %w", err) } return cfg, nil } // afterParse computes additional values after flags have been parsed func (c *config) afterParse() error { if c.db == nil { conn, err := c.connectDatabase() if err != nil { return err } c.db = dbctl.New(conn) } return nil } func (c *config) validate() error { if c.name == "" { return fmt.Errorf("--name is required") } if c.user == "" { return fmt.Errorf("--user is required") } if c.projectID == "" { return fmt.Errorf("--project-id is required") } return nil } func (c *config) connectDatabase() (*sql.DB, error) { edgeDB := &cloudsql.EdgePostgres{} switch { case c.connectionName != "": edgeDB = cloudsql.GCPPostgresConnection(c.connectionName) case c.connectionName == "": edgeDB = cloudsql.PostgresConnection(c.host, c.port).Password(c.password) } dbConnection, err := edgeDB. DBName(c.name). Username(c.user). NewConnection() if err != nil { return nil, err } if err := dbConnection.Ping(); err != nil { return nil, err } return dbConnection, nil } // bindFlags binds the controller's configuration to command line flags. func (c *config) bindFlags(fs *flag.FlagSet) { fs.StringVar(&c.connectionName, "connection-name", "", "CloudSQL postgres database connection name") fs.StringVar(&c.host, "host", "", "CloudSQL postgres database host") fs.StringVar(&c.port, "port", "", "CloudSQL postgres database port") fs.StringVar(&c.name, "name", "", "CloudSQL postgres database name") fs.StringVar(&c.user, "user", "", "CloudSQL postgres database user") fs.StringVar(&c.password, "password", "", "CloudSQL postgres database password") fs.StringVar(&c.namespace, "namespace", "", "K8s namespace the controller is deployed to") fs.StringVar(&c.projectID, "project-id", "", "GCP project id to store database password secret") fs.IntVar(&c.concurrency, "concurrency", 8, "amount of database users to reconcile at a time") }