From f0e451a2d3d2899a7a0566391d7fafe5578f5692 Mon Sep 17 00:00:00 2001 From: Corey Hulen Date: Tue, 4 Apr 2017 08:24:58 -0700 Subject: Fixing config file watch and config reload on license save (#5954) * Fixing config file watch and config reload on license save * Fixing config file watch and config reload on license save * Fixing build error * Fixing locking issue --- api/license.go | 2 -- app/admin.go | 2 ++ app/license.go | 3 +++ cmd/platform/init.go | 1 + utils/config.go | 72 ++++++++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 73 insertions(+), 7 deletions(-) diff --git a/api/license.go b/api/license.go index 0e9eb6027..ea5de20d4 100644 --- a/api/license.go +++ b/api/license.go @@ -68,8 +68,6 @@ func addLicense(c *Context, w http.ResponseWriter, r *http.Request) { c.Err = err return } else { - app.ReloadConfig() - app.InvalidateAllCaches() c.LogAudit("success") w.Write([]byte(license.ToJson())) } diff --git a/app/admin.go b/app/admin.go index 509d81840..b86eb5993 100644 --- a/app/admin.go +++ b/app/admin.go @@ -137,8 +137,10 @@ func SaveConfig(cfg *model.Config) *model.AppError { } //oldCfg := utils.Cfg + utils.DisableConfigWatch() utils.SaveConfig(utils.CfgFileName, cfg) utils.LoadConfig(utils.CfgFileName) + utils.EnableConfigWatch() if einterfaces.GetMetricsInterface() != nil { if *utils.Cfg.MetricsSettings.Enable { diff --git a/app/license.go b/app/license.go index 6b448b19d..c41c17fd8 100644 --- a/app/license.go +++ b/app/license.go @@ -100,6 +100,9 @@ func SaveLicense(licenseBytes []byte) (*model.License, *model.AppError) { return nil, model.NewLocAppError("addLicense", model.INVALID_LICENSE_ERROR, nil, "") } + ReloadConfig() + InvalidateAllCaches() + return license, nil } diff --git a/cmd/platform/init.go b/cmd/platform/init.go index f2a355e9e..0458e7a1c 100644 --- a/cmd/platform/init.go +++ b/cmd/platform/init.go @@ -18,6 +18,7 @@ func doLoadConfig(filename string) (err string) { utils.TranslationsPreInit() utils.EnableConfigFromEnviromentVars() utils.LoadConfig(filename) + utils.InitializeConfigWatch() utils.EnableConfigWatch() return "" } diff --git a/utils/config.go b/utils/config.go index dcc8dd9c0..23855b0e7 100644 --- a/utils/config.go +++ b/utils/config.go @@ -12,6 +12,7 @@ import ( "path/filepath" "strconv" "strings" + "sync" l4g "github.com/alecthomas/log4go" "github.com/fsnotify/fsnotify" @@ -28,6 +29,8 @@ const ( LOG_ROTATE_SIZE = 10000 ) +var cfgMutex = &sync.Mutex{} +var watcher *fsnotify.Watcher var Cfg *model.Config = &model.Config{} var CfgDiagnosticId = "" var CfgHash = "" @@ -140,6 +143,9 @@ func GetLogFileLocation(fileLocation string) string { } func SaveConfig(fileName string, config *model.Config) *model.AppError { + cfgMutex.Lock() + defer cfgMutex.Unlock() + b, err := json.MarshalIndent(config, "", " ") if err != nil { return model.NewLocAppError("SaveConfig", "utils.config.save_config.saving.app_error", @@ -161,18 +167,72 @@ func EnableConfigFromEnviromentVars() { viper.AutomaticEnv() } +func InitializeConfigWatch() { + cfgMutex.Lock() + defer cfgMutex.Unlock() + + if watcher == nil { + var err error + watcher, err = fsnotify.NewWatcher() + if err != nil { + l4g.Error(fmt.Sprintf("Failed to watch config file at %v with err=%v", CfgFileName, err.Error())) + } + + go func() { + configFile := filepath.Clean(CfgFileName) + + for { + select { + case event := <-watcher.Events: + // we only care about the config file + if filepath.Clean(event.Name) == configFile { + if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create { + l4g.Info(fmt.Sprintf("Config file watcher detected a change reloading %v", CfgFileName)) + + if configReadErr := viper.ReadInConfig(); configReadErr == nil { + LoadConfig(CfgFileName) + } else { + l4g.Error(fmt.Sprintf("Failed to read while watching config file at %v with err=%v", CfgFileName, configReadErr.Error())) + } + } + } + case err := <-watcher.Errors: + l4g.Error(fmt.Sprintf("Failed while watching config file at %v with err=%v", CfgFileName, err.Error())) + } + } + }() + } +} + 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) - }) + cfgMutex.Lock() + defer cfgMutex.Unlock() + + configFile := filepath.Clean(CfgFileName) + configDir, _ := filepath.Split(configFile) + + if watcher != nil { + watcher.Add(configDir) + } +} + +func DisableConfigWatch() { + cfgMutex.Lock() + defer cfgMutex.Unlock() + + if watcher != nil { + configFile := filepath.Clean(CfgFileName) + configDir, _ := filepath.Split(configFile) + watcher.Remove(configDir) + } } // 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) { + cfgMutex.Lock() + defer cfgMutex.Unlock() fileNameWithExtension := filepath.Base(fileName) fileExtension := filepath.Ext(fileNameWithExtension) @@ -221,9 +281,11 @@ func LoadConfig(fileName string) { } if needSave { + cfgMutex.Unlock() if err := SaveConfig(CfgFileName, &config); err != nil { l4g.Warn(T(err.Id)) } + cfgMutex.Lock() } if err := ValidateLocales(&config); err != nil { -- cgit v1.2.3-1-g7c22