Skip to content

Commit

Permalink
PLT-6076 Read config file info from enviroment vars (#5873)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
coreyhulen authored and jwilander committed Mar 30, 2017
1 parent 6ac87d8 commit c06a23e
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 17 deletions.
2 changes: 2 additions & 0 deletions cmd/platform/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ func doLoadConfig(filename string) (err string) {
}
}()
utils.TranslationsPreInit()
utils.EnableConfigFromEnviromentVars()
utils.LoadConfig(filename)
utils.EnableConfigWatch()
return ""
}

Expand Down
64 changes: 47 additions & 17 deletions utils/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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

Expand All @@ -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))
}
}
Expand Down
47 changes: 47 additions & 0 deletions utils/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package utils

import (
"os"
"testing"
)

Expand All @@ -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")
}

}

0 comments on commit c06a23e

Please sign in to comment.