Mercurial > gemma
changeset 332:394fafeb4052
Use viper as config storage (I don't like it).
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Fri, 03 Aug 2018 15:46:05 +0200 |
parents | a85f56207d80 |
children | 154e0f5bff0a |
files | auth/opendb.go cmd/gemma/main.go cmd/gemma/root.go config/config.go controllers/pwreset.go |
diffstat | 5 files changed, 208 insertions(+), 230 deletions(-) [+] |
line wrap: on
line diff
--- a/auth/opendb.go Fri Aug 03 13:52:23 2018 +0200 +++ b/auth/opendb.go Fri Aug 03 15:46:05 2018 +0200 @@ -26,10 +26,10 @@ func OpenDB(user, password string) (*sql.DB, error) { dsn := dbDSN( - config.Config.DBHost, config.Config.DBPort, - config.Config.DBName, + config.DBHost(), config.DBPort(), + config.DBName(), user, password, - config.Config.DBSSLMode) + config.DBSSLMode()) return sql.Open(driver, dsn) }
--- a/cmd/gemma/main.go Fri Aug 03 13:52:23 2018 +0200 +++ b/cmd/gemma/main.go Fri Aug 03 15:46:05 2018 +0200 @@ -1,9 +1,94 @@ package main -import "log" +import ( + "context" + "fmt" + "log" + "net/http" + "os" + "os/signal" + "path/filepath" + "syscall" + + "github.com/gorilla/mux" + "github.com/rs/cors" + "github.com/spf13/cobra" + + "gemma.intevation.de/gemma/auth" + "gemma.intevation.de/gemma/config" + "gemma.intevation.de/gemma/controllers" +) + +func prepareConnectionPool() { + // Install connection pool + cp, err := auth.NewConnectionPool(config.SessionStore()) + if err != nil { + log.Fatalf("Error with session store: %v\n", err) + } + auth.ConnPool = cp +} + +func start(cmd *cobra.Command, args []string) { + + web, err := filepath.Abs(config.Web()) + if err != nil { + log.Fatalf("error: %v\n", err) + } + + prepareConnectionPool() + + m := mux.NewRouter() + controllers.BindRoutes(m) + + m.PathPrefix("/").Handler(http.FileServer(http.Dir(web))) + + addr := fmt.Sprintf("%s:%d", config.WebHost(), config.WebPort()) + log.Printf("listen on %s\n", addr) + + var h http.Handler + + if al := config.AllowedOrigins(); len(al) > 0 { + c := cors.New(cors.Options{ + AllowedOrigins: al, + Debug: true, + }) + h = c.Handler(m) + } else { + h = m + } + + server := http.Server{Addr: addr, Handler: h} + + done := make(chan error) + + go func() { + defer close(done) + done <- server.ListenAndServe() + }() + + sigChan := make(chan os.Signal) + signal.Notify(sigChan, os.Interrupt, os.Kill, syscall.SIGTERM) + + select { + case err := <-done: + if err != nil && err != http.ErrServerClosed { + log.Fatalf("error: %v\n", err) + } + case <-sigChan: + } + + server.Shutdown(context.Background()) + + <-done + + if err := auth.ConnPool.Shutdown(); err != nil { + log.Fatalf("error: %v\n", err) + } +} func main() { - if err := rootCmd.Execute(); err != nil { + config.RootCmd.Run = start + if err := config.RootCmd.Execute(); err != nil { log.Fatalln(err) } }
--- a/cmd/gemma/root.go Fri Aug 03 13:52:23 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,196 +0,0 @@ -package main - -import ( - "context" - "fmt" - "log" - "net/http" - "os" - "os/signal" - "path/filepath" - "syscall" - - "gemma.intevation.de/gemma/auth" - "gemma.intevation.de/gemma/config" - "gemma.intevation.de/gemma/controllers" - - "github.com/gorilla/mux" - "github.com/rs/cors" - "github.com/spf13/cobra" - "github.com/spf13/pflag" - "github.com/spf13/viper" - - homedir "github.com/mitchellh/go-homedir" -) - -var rootCmd = &cobra.Command{ - Use: "gemma", - Short: "gemma is a server for waterway monitoring and management", - Run: start, -} - -// This is not part of the persistent config. -var configFile string - -func init() { - cobra.OnInitialize(initConfig) - fl := rootCmd.PersistentFlags - fl().StringVarP(&configFile, "config", "c", "", "config file (default is $HOME/.gemma.toml)") - - cfg := &config.Config - - fl().StringVarP(&cfg.DBHost, "dbhost", "H", "localhost", "host of the database") - fl().UintVarP(&cfg.DBPort, "dbport", "P", 5432, "port of the database") - fl().StringVarP(&cfg.DBName, "dbname", "d", "gemma", "name of the database") - fl().StringVarP(&cfg.DBSSLMode, "dbssl", "S", "prefer", "SSL mode of the database") - - fl().StringVarP(&cfg.SessionStore, "sessions", "s", "", "path to the sessions file") - - fl().StringVarP(&cfg.Web, "web", "w", "", "path to the web files") - fl().StringVarP(&cfg.WebHost, "host", "o", "localhost", "host of the web app") - fl().UintVarP(&cfg.WebPort, "port", "p", 8000, "port of the web app") - - fl().StringVar(&cfg.ServiceUser, "service-user", "postgres", "user to do service tasks") - fl().StringVar(&cfg.ServicePassword, "service-password", "", "password of user to do service tasks") - - fl().StringVar(&cfg.MailHost, "mail-host", "localhost", "server to send mail with") - fl().UintVar(&cfg.MailPort, "mail-port", 464, "port of server to send mail with") - fl().StringVar(&cfg.MailUser, "mail-user", "gemma", "user to send mail with") - fl().StringVar(&cfg.MailPassword, "mail-password", "", "password of user to send mail with") - fl().StringVar(&cfg.MailFrom, "mail-from", "noreplay@localhost", "from line of mails") - fl().StringVar(&cfg.MailHelo, "mail-helo", "localhost", "name of server to send mail from.") - - fl().StringSliceVar(&cfg.AllowedOrigins, "allowed-origins", []string{"foo.org"}, "allow access for remote origins") - - vbind := func(name string) { viper.BindPFlag(name, fl().Lookup(name)) } - - vbind("dbhost") - vbind("dbport") - vbind("dbname") - vbind("dbssl") - - vbind("sessions") - - vbind("web") - vbind("host") - vbind("port") - - vbind("service-user") - vbind("service-password") - - vbind("mail-host") - vbind("mail-port") - vbind("mail-user") - vbind("mail-password") - vbind("mail-from") - vbind("mail-helo") - - vbind("allowed-origins") -} - -func initConfig() { - // Don't forget to read config either from cfgFile or from home directory! - if configFile != "" { - // Use config file from the flag. - viper.SetConfigFile(configFile) - } else { - // Find home directory. - home, err := homedir.Dir() - if err != nil { - log.Fatalf("error: %v\n", err) - } - - // Search config in home directory with name ".cobra" (without extension). - viper.AddConfigPath(home) - viper.SetConfigName(".gemma") - } - if err := viper.ReadInConfig(); err != nil { - if _, ok := err.(viper.ConfigFileNotFoundError); ok && configFile == "" { - // Don't bother if not found. - return - } - log.Fatalf("Can't read config: %v\n", err) - } -} - -func prepareConnectionPool() { - // Install connection pool - cp, err := auth.NewConnectionPool(config.Config.SessionStore) - if err != nil { - log.Fatalf("Error with session store: %v\n", err) - } - auth.ConnPool = cp -} - -func injectViper(cmd *cobra.Command) { - cmd.Flags().VisitAll(func(f *pflag.Flag) { - if !f.Changed { - if viper.IsSet(f.Name) { - s := fmt.Sprintf("%s", viper.Get(f.Name)) - cmd.Flags().Set(f.Name, s) - } - } - }) -} - -func start(cmd *cobra.Command, args []string) { - - // XXX: This hack is needed because we have our - // own config storage. - injectViper(cmd) - - web, err := filepath.Abs(config.Config.Web) - if err != nil { - log.Fatalf("error: %v\n", err) - } - - prepareConnectionPool() - - m := mux.NewRouter() - controllers.BindRoutes(m) - - m.PathPrefix("/").Handler(http.FileServer(http.Dir(web))) - - addr := fmt.Sprintf("%s:%d", config.Config.WebHost, config.Config.WebPort) - log.Printf("listen on %s\n", addr) - - var h http.Handler - - if len(config.Config.AllowedOrigins) > 0 { - c := cors.New(cors.Options{ - AllowedOrigins: config.Config.AllowedOrigins, - Debug: true, - }) - h = c.Handler(m) - } else { - h = m - } - - server := http.Server{Addr: addr, Handler: h} - - done := make(chan error) - - go func() { - defer close(done) - done <- server.ListenAndServe() - }() - - sigChan := make(chan os.Signal) - signal.Notify(sigChan, os.Interrupt, os.Kill, syscall.SIGTERM) - - select { - case err := <-done: - if err != nil && err != http.ErrServerClosed { - log.Fatalf("error: %v\n", err) - } - case <-sigChan: - } - - server.Shutdown(context.Background()) - - <-done - - if err := auth.ConnPool.Shutdown(); err != nil { - log.Fatalf("error: %v\n", err) - } -}
--- a/config/config.go Fri Aug 03 13:52:23 2018 +0200 +++ b/config/config.go Fri Aug 03 15:46:05 2018 +0200 @@ -1,28 +1,119 @@ package config -var Config Configuration +import ( + "log" + + homedir "github.com/mitchellh/go-homedir" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// This is not part of the persistent config. +var configFile string + +func ConfigFile() string { return configFile } + +func DBHost() string { return viper.GetString("dbhost") } +func DBPort() uint { return uint(viper.GetInt32("dbport")) } +func DBName() string { return viper.GetString("dbname") } +func DBSSLMode() string { return viper.GetString("dbssl") } +func SessionStore() string { return viper.GetString("sessions") } +func Web() string { return viper.GetString("web") } +func WebHost() string { return viper.GetString("host") } +func WebPort() uint { return uint(viper.GetInt32("port")) } + +func ServiceUser() string { return viper.GetString("service-user") } +func ServicePassword() string { return viper.GetString("service-password") } -type Configuration struct { - DBHost string - DBPort uint - DBName string - DBSSLMode string +func MailHost() string { return viper.GetString("mail-host") } +func MailPort() uint { return uint(viper.GetInt32("mail-port")) } +func MailUser() string { return viper.GetString("mail-user") } +func MailPassword() string { return viper.GetString("mail-password") } +func MailFrom() string { return viper.GetString("mail-from") } +func MailHelo() string { return viper.GetString("mail-helo") } + +func AllowedOrigins() []string { return viper.GetStringSlice("allowed-origins") } + +var RootCmd = &cobra.Command{ + Use: "gemma", + Short: "gemma is a server for waterway monitoring and management", +} - SessionStore string +func init() { + cobra.OnInitialize(initConfig) + fl := RootCmd.PersistentFlags() + fl.StringVarP(&configFile, "config", "c", "", "config file (default is $HOME/.gemma.toml)") + + fl.StringP("dbhost", "H", "localhost", "host of the database") + fl.UintP("dbport", "P", 5432, "port of the database") + fl.StringP("dbname", "d", "gemma", "name of the database") + fl.StringP("dbssl", "S", "prefer", "SSL mode of the database") + + fl.StringP("sessions", "s", "", "path to the sessions file") + + fl.StringP("web", "w", "", "path to the web files") + fl.StringP("host", "o", "localhost", "host of the web app") + fl.UintP("port", "p", 8000, "port of the web app") + + fl.String("service-user", "postgres", "user to do service tasks") + fl.String("service-password", "", "password of user to do service tasks") - Web string - WebHost string - WebPort uint + fl.String("mail-host", "localhost", "server to send mail with") + fl.Uint("mail-port", 464, "port of server to send mail with") + fl.String("mail-user", "gemma", "user to send mail with") + fl.String("mail-password", "", "password of user to send mail with") + fl.String("mail-from", "noreplay@localhost", "from line of mails") + fl.String("mail-helo", "localhost", "name of server to send mail from.") + + fl.StringSlice("allowed-origins", []string{"foo.org"}, "allow access for remote origins") + + vbind := func(name string) { viper.BindPFlag(name, fl.Lookup(name)) } - ServiceUser string - ServicePassword string + vbind("dbhost") + vbind("dbport") + vbind("dbname") + vbind("dbssl") + + vbind("sessions") + + vbind("web") + vbind("host") + vbind("port") + + vbind("service-user") + vbind("service-password") - MailHost string - MailPort uint - MailUser string - MailPassword string - MailFrom string - MailHelo string + vbind("mail-host") + vbind("mail-port") + vbind("mail-user") + vbind("mail-password") + vbind("mail-from") + vbind("mail-helo") + + vbind("allowed-origins") +} - AllowedOrigins []string +func initConfig() { + // Don't forget to read config either from cfgFile or from home directory! + if configFile != "" { + // Use config file from the flag. + viper.SetConfigFile(configFile) + } else { + // Find home directory. + home, err := homedir.Dir() + if err != nil { + log.Fatalf("error: %v\n", err) + } + + // Search config in home directory with name ".cobra" (without extension). + viper.AddConfigPath(home) + viper.SetConfigName(".gemma") + } + if err := viper.ReadInConfig(); err != nil { + if _, ok := err.(viper.ConfigFileNotFoundError); ok && configFile == "" { + // Don't bother if not found. + return + } + log.Fatalf("Can't read config: %v\n", err) + } }
--- a/controllers/pwreset.go Fri Aug 03 13:52:23 2018 +0200 +++ b/controllers/pwreset.go Fri Aug 03 15:46:05 2018 +0200 @@ -85,8 +85,7 @@ ) func asServiceUser(fn func(*sql.DB) error) error { - cfg := &config.Config - db, err := auth.OpenDB(cfg.ServiceUser, cfg.ServicePassword) + db, err := auth.OpenDB(config.ServiceUser(), config.ServicePassword()) if err == nil { defer db.Close() err = fn(db) @@ -203,20 +202,19 @@ } func sendMail(email, subject, body string) error { - cfg := &config.Config m := gomail.NewMessage() - m.SetHeader("From", cfg.MailFrom) + m.SetHeader("From", config.MailFrom()) m.SetHeader("To", email) m.SetHeader("Subject", subject) m.SetBody("text/plain", body) d := gomail.Dialer{ - Host: cfg.MailHost, - Port: int(cfg.MailPort), - Username: cfg.MailUser, - Password: cfg.MailPassword, - LocalName: cfg.MailHelo, - SSL: cfg.MailPort == 465, + Host: config.MailHost(), + Port: int(config.MailPort()), + Username: config.MailUser(), + Password: config.MailPassword(), + LocalName: config.MailHelo(), + SSL: config.MailPort() == 465, } return d.DialAndSend(m)