package main import ( "fmt" "log" "os" "strings" "github.com/spf13/cobra" "github.com/spf13/viper" ) const ( ViperAPITLSEnabled string = "api.tls.enabled" FlagAPITLSEnabled string = "api-tls-enabled" DefaultAPITLSEnabled bool = false DescriptionAPITLSEnabled string = "Whether to use TLS or not. Requires certificate and private key files." ViperAPITLSCertfile string = "api.tls.certfile" FlagAPITLSCertfile string = "api-tls-certfile" DefaultAPITLSCertfile string = "/etc/bottin/cert.pem" DescriptionAPITLSCertfile string = "Path to TLS certificate file" ViperAPITLSKeyfile string = "api.tls.keyfile" FlagAPITLSKeyfile string = "api-tls-keyfile" DefaultAPITLSKeyfile string = "/etc/bottin/key.pem" DescriptionAPITLSKeyFile string = "Path to TLS private key file" ViperAPIPort string = "api.port" FlagAPIPort string = "api-port" DefaultAPIPort int = 1312 DescriptionAPIPort string = "API server port" ViperAPIKey string = "api.key" FlagAPIKey string = "api-key" DefaultAPIKey string = "bottin" DescriptionAPIKey string = "API server key. Leave empty for no key auth (not recommended)" ViperDBDatabase string = "db.database" FlagDBDatabase string = "db-database" DefaultDBDatabase string = "bottin" DescriptionDBDatabase string = "Postgres database" ViperDBSSLMode string = "db.sslmode" FlagDBSSLMode string = "db-sslmode" DefaultDBSSLMode string = "prefer" DescriptionDBSSLMode string = "Postgres sslmode" ViperDBHost string = "db.host" FlagDBHost string = "db-host" DefaultDBHost string = "db" DescriptionDBHost string = "Postgres host" ViperDBPassword string = "db.password" FlagDBPassword string = "db-password" DefaultDBPassword string = "bottin" DescriptionDBPassword string = "Postgres password" ViperDBPort string = "db.port" FlagDBPort string = "db-port" DefaultDBPort int = 5432 DescriptionDBPort string = "Postgres port" ViperDBUser string = "db.user" FlagDBUser string = "db-user" DefaultDBUser string = "bottin" DescriptionDBUser string = "Postgres user" ViperWebUser string = "web.user" FlagWebUser string = "web-user" DefaultWebUser string = "bottin" DescriptionWebUser string = "Web client basic auth user" ViperWebPassword string = "web.password" FlagWebPassword string = "web-password" DefaultWebPassword string = "bottin" DescriptionWebPassword string = "Web client basic auth password" ViperWebPort string = "web.port" FlagWebPort string = "web-port" DefaultWebPort int = 2312 DescriptionWebPort string = "Web client port" ViperWebAPIHost string = "web.api.host" FlagWebAPIHost string = "web-api-host" DefaultWebAPIHost string = "api" DescriptionWebAPIHost string = "Target API server host" ViperWebAPIKey string = "web.api.key" FlagWebAPIKey string = "web-api-key" DefaultWebAPIKey string = "bottin" DescriptionWebAPIKey string = "Target API server key" ViperWebAPIPort string = "web.api.port" FlagWebAPIPort string = "web-api-port" DefaultWebAPIPort int = 1312 DescriptionWebAPIPort string = "Target API server port" ViperWebAPIProtocol string = "web.api.protocol" FlagWebAPIProtocol string = "web-api-protocol" DefaultWebAPIProtocol string = "http" DescriptionWebAPIProtocol string = "Target API server protocol (http/https)" ) type Config struct { API struct { TLS struct { Enabled bool `yaml:"enabled"` // Path to file containing TLS certificate Certfile string `yaml:"certfile"` // Path to file containing TLS private key Keyfile string `yaml:"keyfile"` } `yaml:"tls"` Port int `yaml:"port"` Key string `yaml:"key"` } `yaml:"api"` DB struct { Database string `yaml:"database"` Host string `yaml:"host"` SSLMode string `yaml:"sslmode"` Password string `yaml:"password"` Port int `yaml:"port"` User string `yaml:"user"` } `yaml:"db"` Web struct { User string `yaml:"user"` Password string `yaml:"password"` Port int `yaml:"port"` API struct { Host string `yaml:"host"` Key string `yaml:"key"` Port int `yaml:"port"` Protocol string `yaml:"protocol"` } `yaml:"api"` } `yaml:"web"` } // DefaultConfig returns a Config filled with the default values from the // `Default*` constants defined in this file. func DefaultConfig() (cfg Config) { cfg.API.TLS.Enabled = DefaultAPITLSEnabled cfg.API.TLS.Certfile = DefaultAPITLSCertfile cfg.API.TLS.Keyfile = DefaultAPITLSKeyfile cfg.API.Port = DefaultAPIPort cfg.API.Key = DefaultAPIKey cfg.DB.Database = DefaultDBDatabase cfg.DB.Host = DefaultDBHost cfg.DB.SSLMode = DefaultDBSSLMode cfg.DB.Password = DefaultDBPassword cfg.DB.Port = DefaultDBPort cfg.DB.User = DefaultDBUser cfg.Web.User = DefaultWebUser cfg.Web.Password = DefaultWebPassword cfg.Web.Port = DefaultWebPort cfg.Web.API.Host = DefaultWebAPIHost cfg.Web.API.Key = DefaultWebAPIKey cfg.Web.API.Port = DefaultWebAPIPort cfg.Web.API.Protocol = DefaultWebAPIProtocol return } func init() { // rootCmd cobra.OnInitialize(initConfig) rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.bottin.yaml)") // apiCmd rootCmd.AddCommand(apiCmd) // api.tls.enabled apiCmd.Flags().Bool(FlagAPITLSEnabled, DefaultAPITLSEnabled, DescriptionAPITLSEnabled) if err := viper.BindPFlag(ViperAPITLSEnabled, apiCmd.Flags().Lookup(FlagAPITLSEnabled)); err != nil { log.Fatal(err) } // api.tls.certfile apiCmd.Flags().String(FlagAPITLSCertfile, DefaultAPITLSCertfile, DescriptionAPITLSCertfile) if err := viper.BindPFlag(ViperAPITLSCertfile, apiCmd.Flags().Lookup(FlagAPITLSCertfile)); err != nil { log.Fatal(err) } // api.tls.keyfile apiCmd.Flags().String(FlagAPITLSKeyfile, DefaultAPITLSKeyfile, DescriptionAPITLSKeyFile) if err := viper.BindPFlag(ViperAPITLSKeyfile, apiCmd.Flags().Lookup(FlagAPITLSKeyfile)); err != nil { log.Fatal(err) } // api.key apiCmd.Flags().String(FlagAPIKey, DefaultAPIKey, DescriptionAPIKey) if err := viper.BindPFlag(ViperAPIKey, apiCmd.Flags().Lookup(FlagAPIKey)); err != nil { log.Fatal(err) } // api.port apiCmd.Flags().Int(FlagAPIPort, DefaultAPIPort, DescriptionAPIPort) if err := viper.BindPFlag(ViperAPIPort, apiCmd.Flags().Lookup(FlagAPIPort)); err != nil { log.Fatal(err) } // db.database apiCmd.Flags().String(FlagDBDatabase, DefaultDBDatabase, DescriptionDBDatabase) if err := viper.BindPFlag(ViperDBDatabase, apiCmd.Flags().Lookup(FlagDBDatabase)); err != nil { log.Fatal(err) } // db.sslmode apiCmd.Flags().String(FlagDBSSLMode, DefaultDBSSLMode, DescriptionDBSSLMode) if err := viper.BindPFlag(ViperDBSSLMode, apiCmd.Flags().Lookup(FlagDBSSLMode)); err != nil { log.Fatal(err) } // db.host apiCmd.Flags().String(FlagDBHost, DefaultDBHost, DescriptionDBHost) if err := viper.BindPFlag(ViperDBHost, apiCmd.Flags().Lookup(FlagDBHost)); err != nil { log.Fatal(err) } // db.password apiCmd.Flags().String(FlagDBPassword, DefaultDBPassword, DescriptionDBPassword) if err := viper.BindPFlag(ViperDBPassword, apiCmd.Flags().Lookup(FlagDBPassword)); err != nil { log.Fatal(err) } // db.port apiCmd.Flags().Int(FlagDBPort, DefaultDBPort, DescriptionDBPort) if err := viper.BindPFlag(ViperDBPort, apiCmd.Flags().Lookup(FlagDBPort)); err != nil { log.Fatal(err) } // db.user apiCmd.Flags().String(FlagDBUser, DefaultDBUser, DescriptionDBUser) if err := viper.BindPFlag(ViperDBUser, apiCmd.Flags().Lookup(FlagDBUser)); err != nil { log.Fatal(err) } // WebCmd rootCmd.AddCommand(webCmd) // web.api.host webCmd.Flags().String(FlagWebAPIHost, DefaultWebAPIHost, DescriptionWebAPIHost) if err := viper.BindPFlag(ViperWebAPIHost, webCmd.Flags().Lookup(FlagWebAPIHost)); err != nil { log.Fatal(err) } // web.api.key webCmd.Flags().String(FlagWebAPIKey, DefaultWebAPIKey, DescriptionWebAPIKey) if err := viper.BindPFlag(ViperWebAPIKey, webCmd.Flags().Lookup(FlagWebAPIKey)); err != nil { log.Fatal(err) } // web.api.protocol webCmd.Flags().String(FlagWebAPIProtocol, DefaultWebAPIProtocol, DescriptionWebAPIProtocol) if err := viper.BindPFlag(ViperWebAPIProtocol, webCmd.Flags().Lookup(FlagWebAPIProtocol)); err != nil { log.Fatal(err) } // web.api.port webCmd.Flags().Int(FlagWebAPIPort, DefaultWebAPIPort, DescriptionWebAPIPort) if err := viper.BindPFlag(ViperWebAPIPort, webCmd.Flags().Lookup(FlagWebAPIPort)); err != nil { log.Fatal(err) } // web.password webCmd.Flags().String(FlagWebPassword, DefaultWebPassword, DescriptionWebPassword) if err := viper.BindPFlag(ViperWebPassword, webCmd.Flags().Lookup(FlagWebPassword)); err != nil { log.Fatal(err) } // web.port webCmd.Flags().Int(FlagWebPort, DefaultWebPort, DescriptionWebPort) if err := viper.BindPFlag(ViperWebPort, webCmd.Flags().Lookup(FlagWebPort)); err != nil { log.Fatal(err) } // web.user webCmd.Flags().String(FlagWebUser, DefaultWebUser, DescriptionWebUser) if err := viper.BindPFlag(ViperWebUser, webCmd.Flags().Lookup(FlagWebUser)); err != nil { log.Fatal(err) } } var cfgFile string // initConfig reads in config file and ENV variables if set. func initConfig() { if cfgFile != "" { // 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 ".bottin" (without extension). viper.AddConfigPath(home) viper.SetConfigType("yaml") viper.SetConfigName(".bottin") } viper.SetEnvPrefix("BOTTIN") viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) viper.AutomaticEnv() // read in environment variables that match // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) } }