From 0f098cf0f14d45169808a0d5e6daf4bfc3f03728 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Tue, 21 Aug 2018 02:02:47 +0300 Subject: [PATCH] Add config file support --- README.md | 1 + cmd/podinfo/main.go | 45 +++++++++++++++++++++++---------------------- pkg/api/http.go | 2 ++ pkg/api/server.go | 29 +++++++++++++++-------------- 4 files changed, 41 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 2ff18c9..8a16c2e 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Specifications: * Dependency management with golang/dep * Structured logging with zap * Tracing with Istio and Jaeger +* 12-factor app with viper * Helm chart Web API: diff --git a/cmd/podinfo/main.go b/cmd/podinfo/main.go index 469676b..645538e 100644 --- a/cmd/podinfo/main.go +++ b/cmd/podinfo/main.go @@ -4,10 +4,10 @@ import ( "fmt" "io/ioutil" "os" + "path/filepath" "strings" "time" - "github.com/rs/zerolog/log" "github.com/spf13/pflag" "github.com/spf13/viper" "github.com/stefanprodan/k8s-podinfo/pkg/api" @@ -27,7 +27,8 @@ func main() { fs.Duration("http-server-timeout", 30*time.Second, "server read and write timeout duration") fs.Duration("http-server-shutdown-timeout", 5*time.Second, "server graceful shutdown timeout duration") fs.String("data-path", "/data", "data local path") - fs.String("config-path", "", "config local path") + fs.String("config-path", "", "config dir path") + fs.String("config", "config.yaml", "config file name") fs.String("ui-path", "./ui", "UI local path") fs.String("ui-color", "blue", "UI color") fs.String("ui-message", fmt.Sprintf("greetings from podinfo v%v", version.VERSION), "UI message") @@ -60,12 +61,30 @@ func main() { viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) viper.AutomaticEnv() + // load config from file + if _, err := os.Stat(filepath.Join(viper.GetString("config-path"), viper.GetString("config"))); err == nil { + viper.SetConfigName(strings.Split(viper.GetString("config"), ".")[0]) + viper.AddConfigPath(viper.GetString("config-path")) + if err := viper.ReadInConfig(); err != nil { + fmt.Printf("Error reading config file, %v\n", err) + } + } + // configure logging logger, _ := initZap(viper.GetString("level")) defer logger.Sync() stdLog := zap.RedirectStdLog(logger) defer stdLog() + // start stress tests if any + beginStressTest(viper.GetInt("stress-cpu"), viper.GetInt("stress-memory"), logger) + + // load HTTP server config + var srvCfg api.Config + if err := viper.Unmarshal(&srvCfg); err != nil { + logger.Panic("config unmarshal failed", zap.Error(err)) + } + // log version and port logger.Info("Starting podinfo", zap.String("version", viper.GetString("version")), @@ -73,26 +92,8 @@ func main() { zap.String("port", viper.GetString("port")), ) - // start stress test - beginStressTest(viper.GetInt("stress-cpu"), viper.GetInt("stress-memory"), logger) - - // configure API - srvCfg := &api.Config{ - Port: viper.GetString("port"), - Hostname: viper.GetString("hostname"), - HttpServerShutdownTimeout: viper.GetDuration("http-server-shutdown-timeout"), - HttpServerTimeout: viper.GetDuration("http-server-timeout"), - BackendURL: viper.GetString("backend-url"), - ConfigPath: viper.GetString("config-path"), - DataPath: viper.GetString("data-path"), - HttpClientTimeout: viper.GetDuration("http-client-timeout"), - UIColor: viper.GetString("ui-color"), - UIPath: viper.GetString("ui-path"), - UIMessage: viper.GetString("ui-message"), - } - // start HTTP server - srv, _ := api.NewServer(srvCfg, logger) + srv, _ := api.NewServer(&srvCfg, logger) stopCh := signals.SetupSignalHandler() srv.ListenAndServe(stopCh) } @@ -169,7 +170,7 @@ func beginStressTest(cpus int, mem int, logger *zap.Logger) { f, err := os.Create(path) if err != nil { - log.Error().Err(err).Msgf("memory stress failed") + logger.Error("memory stress failed", zap.Error(err)) } if err := f.Truncate(1000000 * int64(mem)); err != nil { diff --git a/pkg/api/http.go b/pkg/api/http.go index 50c2140..2db9262 100644 --- a/pkg/api/http.go +++ b/pkg/api/http.go @@ -18,6 +18,8 @@ func versionMiddleware(next http.Handler) http.Handler { }) } +// TODO: use Istio tracing package +// https://github.com/istio/istio/blob/master/pkg/tracing/config.go func copyTracingHeaders(from *http.Request, to *http.Request) { headers := []string{ "x-request-id", diff --git a/pkg/api/server.go b/pkg/api/server.go index 37055af..6d5e06c 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" _ "net/http/pprof" + "os" "strings" "sync/atomic" "time" @@ -22,17 +23,17 @@ var ( ) type Config struct { - HttpClientTimeout time.Duration - HttpServerTimeout time.Duration - HttpServerShutdownTimeout time.Duration - BackendURL string - UIMessage string - UIColor string - UIPath string - DataPath string - ConfigPath string - Port string - Hostname string + HttpClientTimeout time.Duration `mapstructure:"http-client-timeout"` + HttpServerTimeout time.Duration `mapstructure:"http-server-timeout"` + HttpServerShutdownTimeout time.Duration `mapstructure:"http-server-shutdown-timeout"` + BackendURL string `mapstructure:"backend-url"` + UIMessage string `mapstructure:"ui-message"` + UIColor string `mapstructure:"ui-color"` + UIPath string `mapstructure:"ui-path"` + DataPath string `mapstructure:"data-path"` + ConfigPath string `mapstructure:"config-path"` + Port string `mapstructure:"port"` + Hostname string `mapstructure:"hostname"` } type Server struct { @@ -76,8 +77,8 @@ func (s *Server) registerHandlers() { func (s *Server) registerMiddlewares() { prom := NewPrometheusMiddleware() s.router.Use(prom.Handler) - zapLog := NewLoggingMiddleware(s.logger) - s.router.Use(zapLog.Handler) + httpLogger := NewLoggingMiddleware(s.logger) + s.router.Use(httpLogger.Handler) s.router.Use(versionMiddleware) } @@ -97,7 +98,7 @@ func (s *Server) ListenAndServe(stopCh <-chan struct{}) { //s.printRoutes() // load configs in memory and start watching for changes in the config dir - if len(s.config.ConfigPath) > 0 { + if stat, err := os.Stat(s.config.ConfigPath); err == nil && stat.IsDir() { var err error watcher, err = fscache.NewWatch(s.config.ConfigPath) if err != nil {