package server import ( "database/sql" "flag" "fmt" "os" "time" "github.com/peterbourgon/ff/v3" "google.golang.org/grpc" "edge-infra.dev/pkg/lib/gcp/cloudsql" ) type Config struct { MetricsAddr string HealthzAddr string ForemanProjectID string TopicID string SubscriptionID string DBConnection string DBName string DBUsername string DBPassword string // for testing locally, not used when in the cloud. PollBannersPeriod time.Duration PollBannersMaxRetries int PollSubscriptionExistsPeriod time.Duration // DelayScrapeMessageProcessing prevents deleting outdated watched field objects from thrashing the database // with unnecessary writes & deletes due to pubsub's out-of-order message delivery. // // Tests use a smaller value to prevent unnecessary delays. DelayScrapeMessageProcessing time.Duration BannerCheckPeriod time.Duration GarbageCollectDeletedWatchedFieldObjects bool DB *sql.DB // for testing, the flags for DB will be ignored if set. TestPubSubConn *grpc.ClientConn // for testing, needed since using manager. } func (cfg *Config) Validate() error { if cfg.MetricsAddr == "" { return fmt.Errorf("missing MetricsAddr") } if cfg.HealthzAddr == "" { return fmt.Errorf("missing HealthzAddr") } if cfg.DB == nil { switch "" { case cfg.DBConnection: return fmt.Errorf("missing DBConnection") case cfg.DBName: return fmt.Errorf("missing DBName") case cfg.DBUsername: return fmt.Errorf("missing DBUsername") case cfg.ForemanProjectID: return fmt.Errorf("missing ForemanProjectID") case cfg.TopicID: return fmt.Errorf("missing TopicID") case cfg.SubscriptionID: return fmt.Errorf("missing SubscriptionID") } } return nil } func (cfg *Config) ConnectToDB() (*sql.DB, error) { if cfg.DB != nil { return cfg.DB, nil } return cloudsql.GCPPostgresConnection(cfg.DBConnection). DBName(cfg.DBName). Username(cfg.DBUsername). Password(cfg.DBPassword). NewConnection() } func NewConfig() (*Config, error) { var cfg Config fs := flag.NewFlagSet("kinform-server", flag.ContinueOnError) fs.StringVar(&cfg.MetricsAddr, "metrics-addr", ":8081", "Address to bind metrics endpoint (/metrics) to") fs.StringVar(&cfg.HealthzAddr, "healthz-addr", ":8082", "Address to bind heath-check endpoints (/livez, /readyz) to") fs.StringVar(&cfg.ForemanProjectID, "foreman-project-id", "", "Foreman Project ID is used to create the shared PubSub client") fs.StringVar(&cfg.TopicID, "topic", "", "PubSub Topic ID where kinform publishes messages") fs.StringVar(&cfg.SubscriptionID, "subscription", "", "PubSub Subscription ID where psqlinjector receives kinform messages") fs.DurationVar(&cfg.DelayScrapeMessageProcessing, "delay-scrape-message-processing", 10*time.Second, "How long to wait before deleting outdated watched_field_objects after a cluster scrapes") fs.DurationVar(&cfg.BannerCheckPeriod, "banner-check-period", 60*time.Second, "The frequency of psqlinjector to check if banners were created or deleted") fs.BoolVar(&cfg.GarbageCollectDeletedWatchedFieldObjects, "gc-deleted-watched-field-objects", true, "Garbage collect deleted watched field objects at startup") fs.StringVar(&cfg.DBConnection, "db-connection", "", "postgress connection name") fs.StringVar(&cfg.DBName, "db-name", "", "name of db to connect to") fs.StringVar(&cfg.DBUsername, "db-username", "", "username of the db connection") fs.StringVar(&cfg.DBPassword, "db-password", "", "password of the db connection for testing locally") fs.DurationVar(&cfg.PollBannersPeriod, "poll-banners-period", 60*time.Second, "Time Duration period to poll for banner changes") fs.IntVar(&cfg.PollBannersMaxRetries, "poll-banners-max-retries", 5, "maximum amount of consecutive poll errors before psqlinjector quits") fs.DurationVar(&cfg.PollSubscriptionExistsPeriod, "poll-subscription-exists-period", 97*time.Second, "Time Duration period to probe for subscription deletions") if err := ff.Parse(fs, os.Args[1:], ff.WithEnvVarNoPrefix()); err != nil { return nil, err } return &cfg, nil }