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)