From c06a23ea0b0aa317b88327a78e55d2fe7b2c1b89 Mon Sep 17 00:00:00 2001 From: Corey Hulen Date: Wed, 29 Mar 2017 18:13:32 -0700 Subject: PLT-6076 Read config file info from enviroment vars (#5873) * Adding viper libs for config file changes * Removing the old fsnotify lib * updating some missing libs * PLT-6076 Read config file info from enviroment vars * Changing unit test to use less important props --- cmd/platform/init.go | 2 ++ utils/config.go | 64 ++++++++++++++++++++++++++++++++++++++-------------- utils/config_test.go | 47 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 17 deletions(-) diff --git a/cmd/platform/init.go b/cmd/platform/init.go index cbfdb58ce..f2a355e9e 100644 --- a/cmd/platform/init.go +++ b/cmd/platform/init.go @@ -16,7 +16,9 @@ func doLoadConfig(filename string) (err string) { } }() utils.TranslationsPreInit() + utils.EnableConfigFromEnviromentVars() utils.LoadConfig(filename) + utils.EnableConfigWatch() return "" } diff --git a/utils/config.go b/utils/config.go index 2996c241c..6f18a48fa 100644 --- a/utils/config.go +++ b/utils/config.go @@ -14,6 +14,8 @@ import ( "strings" l4g "github.com/alecthomas/log4go" + "github.com/fsnotify/fsnotify" + "github.com/spf13/viper" "github.com/mattermost/platform/einterfaces" "github.com/mattermost/platform/model" @@ -153,34 +155,62 @@ func SaveConfig(fileName string, config *model.Config) *model.AppError { return nil } +func EnableConfigFromEnviromentVars() { + viper.SetEnvPrefix("mm") + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + viper.AutomaticEnv() +} + +func EnableConfigWatch() { + viper.WatchConfig() + viper.OnConfigChange(func(e fsnotify.Event) { + l4g.Info(fmt.Sprintf("Config file watcher detected a change reloading %v", CfgFileName)) + LoadConfig(CfgFileName) + }) +} + // LoadConfig will try to search around for the corresponding config file. // It will search /tmp/fileName then attempt ./config/fileName, // then ../config/fileName and last it will look at fileName func LoadConfig(fileName string) { - fileName = FindConfigFile(fileName) + fileNameWithExtension := filepath.Base(fileName) + fileExtension := filepath.Ext(fileNameWithExtension) + fileDir := filepath.Dir(fileName) - file, err := os.Open(fileName) - if err != nil { - panic(T("utils.config.load_config.opening.panic", - map[string]interface{}{"Filename": fileName, "Error": err.Error()})) + if len(fileNameWithExtension) > 0 { + fileNameOnly := fileNameWithExtension[:len(fileNameWithExtension)-len(fileExtension)] + viper.SetConfigName(fileNameOnly) + } else { + viper.SetConfigName("config") } - decoder := json.NewDecoder(file) - config := model.Config{} - err = decoder.Decode(&config) - if err != nil { - panic(T("utils.config.load_config.decoding.panic", - map[string]interface{}{"Filename": fileName, "Error": err.Error()})) + if len(fileDir) > 0 { + viper.AddConfigPath(fileDir) } - if _, err := file.Stat(); err != nil { - panic(T("utils.config.load_config.getting.panic", - map[string]interface{}{"Filename": fileName, "Error": err.Error()})) - } else { - CfgFileName = fileName + viper.SetConfigType("json") + viper.AddConfigPath("./config") + viper.AddConfigPath("../config") + viper.AddConfigPath(".") + + configReadErr := viper.ReadInConfig() + if configReadErr != nil { + errMsg := T("utils.config.load_config.opening.panic", map[string]interface{}{"Filename": fileName, "Error": configReadErr.Error()}) + fmt.Fprintln(os.Stderr, errMsg) + os.Exit(1) } + var config model.Config + unmarshalErr := viper.Unmarshal(&config) + if unmarshalErr != nil { + errMsg := T("utils.config.load_config.decoding.panic", map[string]interface{}{"Filename": fileName, "Error": unmarshalErr.Error()}) + fmt.Fprintln(os.Stderr, errMsg) + os.Exit(1) + } + + CfgFileName = viper.ConfigFileUsed() + needSave := len(config.SqlSettings.AtRestEncryptKey) == 0 || len(*config.FileSettings.PublicLinkSalt) == 0 || len(config.EmailSettings.InviteSalt) == 0 || len(config.EmailSettings.PasswordResetSalt) == 0 @@ -191,7 +221,7 @@ func LoadConfig(fileName string) { } if needSave { - if err := SaveConfig(fileName, &config); err != nil { + if err := SaveConfig(CfgFileName, &config); err != nil { l4g.Warn(T(err.Id)) } } diff --git a/utils/config_test.go b/utils/config_test.go index d42f99a69..c15165fe5 100644 --- a/utils/config_test.go +++ b/utils/config_test.go @@ -4,6 +4,7 @@ package utils import ( + "os" "testing" ) @@ -12,3 +13,49 @@ func TestConfig(t *testing.T) { LoadConfig("config.json") InitTranslations(Cfg.LocalizationSettings) } + +func TestConfigFromEnviroVars(t *testing.T) { + + os.Setenv("MM_TEAMSETTINGS_SITENAME", "From Enviroment") + os.Setenv("MM_TEAMSETTINGS_CUSTOMBRANDTEXT", "Custom Brand") + os.Setenv("MM_SERVICESETTINGS_ENABLECOMMANDS", "false") + os.Setenv("MM_SERVICESETTINGS_READTIMEOUT", "400") + + TranslationsPreInit() + EnableConfigFromEnviromentVars() + LoadConfig("config.json") + + if Cfg.TeamSettings.SiteName != "From Enviroment" { + t.Fatal("Couldn't read config from enviroment var") + } + + if *Cfg.TeamSettings.CustomBrandText != "Custom Brand" { + t.Fatal("Couldn't read config from enviroment var") + } + + if *Cfg.ServiceSettings.EnableCommands != false { + t.Fatal("Couldn't read config from enviroment var") + } + + if *Cfg.ServiceSettings.ReadTimeout != 400 { + t.Fatal("Couldn't read config from enviroment var") + } + + os.Unsetenv("MM_TEAMSETTINGS_SITENAME") + os.Unsetenv("MM_TEAMSETTINGS_CUSTOMBRANDTEXT") + os.Unsetenv("MM_SERVICESETTINGS_ENABLECOMMANDS") + os.Unsetenv("MM_SERVICESETTINGS_READTIMEOUT") + + Cfg.TeamSettings.SiteName = "Mattermost" + *Cfg.ServiceSettings.SiteURL = "" + *Cfg.ServiceSettings.EnableCommands = true + *Cfg.ServiceSettings.ReadTimeout = 300 + SaveConfig(CfgFileName, Cfg) + + LoadConfig("config.json") + + if Cfg.TeamSettings.SiteName != "Mattermost" { + t.Fatal("should have been reset") + } + +} -- cgit v1.2.3-1-g7c22