package main import ( "fmt" "log" "os" "strings" "github.com/spf13/cobra" "github.com/spf13/viper" ) type Config struct { Client struct { API struct { Host string `yaml:"host"` Key string `yaml:"key"` Port int `yaml:"port"` Protocol string `yaml:"protocol"` } `yaml:"api"` } `yaml:"client"` Server struct { API struct { DB struct { Database string `yaml:"database"` Host string `yaml:"host"` Password string `yaml:"password"` Port int `yaml:"port"` SSLMode string `yaml:"sslmode"` User string `yaml:"user"` } `yaml:"db"` Host string `yaml:"host"` Key string `yaml:"key"` Port int `yaml:"port"` TLS struct { Enabled bool `yaml:"enabled"` Certfile string `yaml:"certfile"` Keyfile string `yaml:"keyfile"` } `yaml:"tls"` } `yaml:"api"` UI struct { API struct { Host string `yaml:"host"` Key string `yaml:"key"` Port int `yaml:"port"` Protocol string `yaml:"protocol"` TLS struct { SkipVerify bool `yaml:"skipverify"` } `yaml:"tls"` } `yaml:"api"` Host string `yaml:"host"` Password string `yaml:"password"` Port int `yaml:"port"` TLS struct { Enabled bool `yaml:"enabled"` Certfile string `yaml:"certfile"` Keyfile string `yaml:"keyfile"` } `yaml:"tls"` User string `yaml:"user"` } `yaml:"ui"` } `yaml:"server"` } 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()) } } func init() { // rootCmd cobra.OnInitialize(initConfig) rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.bottin.yaml)") // client.api.host rootCmd.PersistentFlags().String( "client-api-host", "api", "API server host", ) if err := viper.BindPFlag( "client.api.host", rootCmd.PersistentFlags().Lookup("client-api-host"), ); err != nil { log.Fatal(err) } // client.api.key rootCmd.PersistentFlags().String( "client-api-key", "bottin", "API server key", ) if err := viper.BindPFlag( "client.api.key", rootCmd.PersistentFlags().Lookup("client-api-key"), ); err != nil { log.Fatal(err) } // client.api.port rootCmd.PersistentFlags().Int( "client-api-port", 1312, "API server port", ) if err := viper.BindPFlag( "client.api.port", rootCmd.PersistentFlags().Lookup("client-api-port"), ); err != nil { log.Fatal(err) } // client.api.protocol rootCmd.PersistentFlags().String( "client-api-protocol", "https", "API server protocol", ) if err := viper.BindPFlag( "client.api.protocol", rootCmd.PersistentFlags().Lookup("client-api-protocol"), ); err != nil { log.Fatal(err) } // server rootCmd.AddCommand(serverCmd) // server api serverCmd.AddCommand(apiCmd) // server api db // server.api.db.database apiCmd.PersistentFlags().String( "server-api-db-database", "bottin", "Postgres database name", ) if err := viper.BindPFlag( "server.api.db.database", apiCmd.PersistentFlags().Lookup("server-api-db-database"), ); err != nil { log.Fatal(err) } // server.api.db.host apiCmd.PersistentFlags().String( "server-api-db-host", "db", "Postgres host name", ) if err := viper.BindPFlag( "server.api.db.host", apiCmd.PersistentFlags().Lookup("server-api-db-host"), ); err != nil { log.Fatal(err) } // server.api.db.password apiCmd.PersistentFlags().String( "server-api-db-password", "bottin", "Postgres password", ) if err := viper.BindPFlag( "server.api.db.password", apiCmd.PersistentFlags().Lookup("server-api-db-password"), ); err != nil { log.Fatal(err) } // server.api.db.port apiCmd.PersistentFlags().Int( "server-api-db-port", 5432, "Postgres port", ) if err := viper.BindPFlag( "server.api.db.port", apiCmd.PersistentFlags().Lookup("server-api-db-port"), ); err != nil { log.Fatal(err) } // server.api.db.sslmode apiCmd.PersistentFlags().String( "server-api-db-sslmode", "prefer", "Postgres sslmode", ) if err := viper.BindPFlag( "server.api.db.sslmode", apiCmd.PersistentFlags().Lookup("server-api-db-sslmode"), ); err != nil { log.Fatal(err) } // server.api.db.user apiCmd.PersistentFlags().String( "server-api-db-user", "bottin", "Postgres user name", ) if err := viper.BindPFlag( "server.api.db.user", apiCmd.PersistentFlags().Lookup("server-api-db-user"), ); err != nil { log.Fatal(err) } // server.api.host apiCmd.PersistentFlags().String( "server-api-host", "", "API server hostname or IP to answer on (empty = any)", ) if err := viper.BindPFlag( "server.api.host", apiCmd.PersistentFlags().Lookup("server-api-host"), ); err != nil { log.Fatal(err) } // server.api.key apiCmd.PersistentFlags().String( "server-api-key", "bottin", "API server key", ) if err := viper.BindPFlag( "server.api.key", apiCmd.PersistentFlags().Lookup("server-api-key"), ); err != nil { log.Fatal(err) } // server.api.port apiCmd.PersistentFlags().Int( "server-api-port", 1312, "API server port", ) if err := viper.BindPFlag( "server.api.port", apiCmd.PersistentFlags().Lookup("server-api-port"), ); err != nil { log.Fatal(err) } // server api tls // server.api.tls.enabled apiCmd.PersistentFlags().Bool( "server-api-tls-enabled", true, "Use TLS for API server connections (requires certfile and keyfile)", ) if err := viper.BindPFlag( "server.api.tls.enabled", apiCmd.PersistentFlags().Lookup("server-api-tls-enabled"), ); err != nil { log.Fatal(err) } // server.api.tls.certfile apiCmd.PersistentFlags().String( "server-api-tls-certfile", "/etc/bottin/cert.pem", "Path to certificate file", ) if err := viper.BindPFlag( "server.api.tls.certfile", apiCmd.PersistentFlags().Lookup("server-api-tls-certfile"), ); err != nil { log.Fatal(err) } // server.api.tls.keyfile apiCmd.PersistentFlags().String( "server-api-tls-keyfile", "/etc/bottin/key.pem", "Path to private key file", ) if err := viper.BindPFlag( "server.api.tls.keyfile", apiCmd.PersistentFlags().Lookup("server-api-tls-keyfile"), ); err != nil { log.Fatal(err) } // server ui serverCmd.AddCommand(uiCmd) // server ui api // server.ui.api.host uiCmd.PersistentFlags().String( "server-ui-api-host", "api", "Web UI backend API server host name", ) if err := viper.BindPFlag( "server.ui.api.host", uiCmd.PersistentFlags().Lookup("server-ui-api-host"), ); err != nil { log.Fatal(err) } // server.ui.api.key uiCmd.PersistentFlags().String( "server-ui-api-key", "bottin", "Web UI backend API server key", ) if err := viper.BindPFlag( "server.ui.api.key", uiCmd.PersistentFlags().Lookup("server-ui-api-key"), ); err != nil { log.Fatal(err) } // server.ui.api.port uiCmd.PersistentFlags().Int( "server-ui-api-port", 1312, "Web UI backend API server port", ) if err := viper.BindPFlag( "server.ui.api.port", uiCmd.PersistentFlags().Lookup("server-ui-api-port"), ); err != nil { log.Fatal(err) } // server.ui.api.protocol uiCmd.PersistentFlags().String( "server-ui-api-protocol", "https", "Web UI backend API server protocol", ) if err := viper.BindPFlag( "server.ui.api.protocol", uiCmd.PersistentFlags().Lookup("server-ui-api-protocol"), ); err != nil { log.Fatal(err) } // server.ui.api.tls.skipverify uiCmd.PersistentFlags().Bool( "server-ui-api-tls-skipverify", false, "Skip API server TLS certificate verification", ) if err := viper.BindPFlag( "server.ui.api.tls.skipverify", uiCmd.PersistentFlags().Lookup("server-ui-api-tls-skipverify"), ); err != nil { log.Fatal(err) } // server.ui.host uiCmd.PersistentFlags().String( "server-ui-host", "", "Web UI host", ) if err := viper.BindPFlag( "server.ui.host", uiCmd.PersistentFlags().Lookup("server-ui-host"), ); err != nil { log.Fatal(err) } // server.ui.password uiCmd.PersistentFlags().String( "server-ui-password", "bottin", "Web UI password", ) if err := viper.BindPFlag( "server.ui.password", uiCmd.PersistentFlags().Lookup("server-ui-password"), ); err != nil { log.Fatal(err) } // server.ui.port uiCmd.PersistentFlags().Int( "server-ui-port", 2312, "Web UI port", ) if err := viper.BindPFlag( "server.ui.port", uiCmd.PersistentFlags().Lookup("server-ui-port"), ); err != nil { log.Fatal(err) } // server.ui.user uiCmd.PersistentFlags().String( "server-ui-user", "bottin", "Web UI user", ) if err := viper.BindPFlag( "server.ui.user", uiCmd.PersistentFlags().Lookup("server-ui-user"), ); err != nil { log.Fatal(err) } // server ui tls // server.ui.tls.enabled uiCmd.PersistentFlags().Bool( "server-ui-tls-enabled", true, "Web UI enable TLS (requires certfile and keyfile)", ) if err := viper.BindPFlag( "server.ui.tls.enabled", uiCmd.PersistentFlags().Lookup("server-ui-tls-enabled"), ); err != nil { log.Fatal(err) } // server.ui.tls.certfile uiCmd.PersistentFlags().String( "server-ui-tls-certfile", "/etc/bottin/cert.pem", "Path to Web UI TLS certificate file", ) if err := viper.BindPFlag( "server.ui.tls.certfile", uiCmd.PersistentFlags().Lookup("server-ui-tls-certfile"), ); err != nil { log.Fatal(err) } // server.ui.tls.keyfile uiCmd.PersistentFlags().String( "server-ui-tls-keyfile", "/etc/bottin/key.pem", "Path to Web UI TLS private key file", ) if err := viper.BindPFlag( "server.ui.tls.keyfile", uiCmd.PersistentFlags().Lookup("server-ui-tls-keyfile"), ); err != nil { log.Fatal(err) } }