MM-13893: introduce file store (#10243)
* config file store Introduce an interface and concrete implementation for accessing the config. This mostly maps 1:1 with the exiting usage in `App`, except for internalizing the watcher. A future change will likely eliminate `App.PersistConfig()` and make this implicit on `Set` or `Patch` * experimental file test changes * emoji: move file driver checks from api4 to app It is no longer possible to app.UpdateConfig and provide an invalid configuration, making it hard to test this case. This check doesn't really belong in the api anyway, since it's a configuration validity check and not a permissions check. Either way, the check now occurs at the App level. * api4: generate valid public link salts for test * TestStartServerRateLimiterCriticalError: use mock store to test invalid config * remove config_test.go * remove needsSave, and have Load() save to the backing store as necessary * restore README.md * move ldap UserFilter check to model isValid checks * remove databaseStore until ready * remove unimplemented Patch * simplify unlockOnce implementation * revert forgetting to set s.Ldap * config/file.go: rename ReadOnlyConfigurationError to ErrReadOnlyConfiguration * config: export FileStore * add TestFileStoreSave * improved config/utils test coverage * restore config/README.md copy * tweaks * file store: acquire a write lock on Save/Close to safely close watcher * fix unmarshal_test.go
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
9cfcab2307
Коммит
285b646d67
133
config/utils.go
Обычный файл
133
config/utils.go
Обычный файл
@@ -0,0 +1,133 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/mattermost/mattermost-server/mlog"
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
"github.com/mattermost/mattermost-server/utils"
|
||||
)
|
||||
|
||||
// desanitize replaces fake settings with their actual values.
|
||||
func desanitize(actual, target *model.Config) {
|
||||
if target.LdapSettings.BindPassword != nil && *target.LdapSettings.BindPassword == model.FAKE_SETTING {
|
||||
*target.LdapSettings.BindPassword = *actual.LdapSettings.BindPassword
|
||||
}
|
||||
|
||||
if *target.FileSettings.PublicLinkSalt == model.FAKE_SETTING {
|
||||
*target.FileSettings.PublicLinkSalt = *actual.FileSettings.PublicLinkSalt
|
||||
}
|
||||
if *target.FileSettings.AmazonS3SecretAccessKey == model.FAKE_SETTING {
|
||||
target.FileSettings.AmazonS3SecretAccessKey = actual.FileSettings.AmazonS3SecretAccessKey
|
||||
}
|
||||
|
||||
if *target.EmailSettings.InviteSalt == model.FAKE_SETTING {
|
||||
target.EmailSettings.InviteSalt = actual.EmailSettings.InviteSalt
|
||||
}
|
||||
if *target.EmailSettings.SMTPPassword == model.FAKE_SETTING {
|
||||
target.EmailSettings.SMTPPassword = actual.EmailSettings.SMTPPassword
|
||||
}
|
||||
|
||||
if *target.GitLabSettings.Secret == model.FAKE_SETTING {
|
||||
target.GitLabSettings.Secret = actual.GitLabSettings.Secret
|
||||
}
|
||||
|
||||
if *target.SqlSettings.DataSource == model.FAKE_SETTING {
|
||||
*target.SqlSettings.DataSource = *actual.SqlSettings.DataSource
|
||||
}
|
||||
if *target.SqlSettings.AtRestEncryptKey == model.FAKE_SETTING {
|
||||
target.SqlSettings.AtRestEncryptKey = actual.SqlSettings.AtRestEncryptKey
|
||||
}
|
||||
|
||||
if *target.ElasticsearchSettings.Password == model.FAKE_SETTING {
|
||||
*target.ElasticsearchSettings.Password = *actual.ElasticsearchSettings.Password
|
||||
}
|
||||
|
||||
target.SqlSettings.DataSourceReplicas = make([]string, len(actual.SqlSettings.DataSourceReplicas))
|
||||
for i := range target.SqlSettings.DataSourceReplicas {
|
||||
target.SqlSettings.DataSourceReplicas[i] = actual.SqlSettings.DataSourceReplicas[i]
|
||||
}
|
||||
|
||||
target.SqlSettings.DataSourceSearchReplicas = make([]string, len(actual.SqlSettings.DataSourceReplicas))
|
||||
for i := range target.SqlSettings.DataSourceSearchReplicas {
|
||||
target.SqlSettings.DataSourceSearchReplicas[i] = actual.SqlSettings.DataSourceSearchReplicas[i]
|
||||
}
|
||||
}
|
||||
|
||||
// fixConfig patches invalid or missing data in the configuration, returning true if changed.
|
||||
func fixConfig(cfg *model.Config) bool {
|
||||
changed := false
|
||||
|
||||
// Ensure SiteURL has no trailing slash.
|
||||
if strings.HasSuffix(*cfg.ServiceSettings.SiteURL, "/") {
|
||||
*cfg.ServiceSettings.SiteURL = strings.TrimRight(*cfg.ServiceSettings.SiteURL, "/")
|
||||
changed = true
|
||||
}
|
||||
|
||||
// Ensure the directory for a local file store has a trailing slash.
|
||||
if *cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL {
|
||||
if !strings.HasSuffix(*cfg.FileSettings.Directory, "/") {
|
||||
*cfg.FileSettings.Directory += "/"
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
|
||||
if FixInvalidLocales(cfg) {
|
||||
changed = true
|
||||
}
|
||||
|
||||
return changed
|
||||
}
|
||||
|
||||
// FixInvalidLocales checks and corrects the given config for invalid locale-related settings.
|
||||
//
|
||||
// Ideally, this function would be completely internal, but it's currently exposed to allow the cli
|
||||
// to test the config change before allowing the save.
|
||||
func FixInvalidLocales(cfg *model.Config) bool {
|
||||
var changed bool
|
||||
|
||||
locales := utils.GetSupportedLocales()
|
||||
if _, ok := locales[*cfg.LocalizationSettings.DefaultServerLocale]; !ok {
|
||||
*cfg.LocalizationSettings.DefaultServerLocale = model.DEFAULT_LOCALE
|
||||
mlog.Warn("DefaultServerLocale must be one of the supported locales. Setting DefaultServerLocale to en as default value.")
|
||||
changed = true
|
||||
}
|
||||
|
||||
if _, ok := locales[*cfg.LocalizationSettings.DefaultClientLocale]; !ok {
|
||||
*cfg.LocalizationSettings.DefaultClientLocale = model.DEFAULT_LOCALE
|
||||
mlog.Warn("DefaultClientLocale must be one of the supported locales. Setting DefaultClientLocale to en as default value.")
|
||||
changed = true
|
||||
}
|
||||
|
||||
if len(*cfg.LocalizationSettings.AvailableLocales) > 0 {
|
||||
isDefaultClientLocaleInAvailableLocales := false
|
||||
for _, word := range strings.Split(*cfg.LocalizationSettings.AvailableLocales, ",") {
|
||||
if _, ok := locales[word]; !ok {
|
||||
*cfg.LocalizationSettings.AvailableLocales = ""
|
||||
isDefaultClientLocaleInAvailableLocales = true
|
||||
mlog.Warn("AvailableLocales must include DefaultClientLocale. Setting AvailableLocales to all locales as default value.")
|
||||
changed = true
|
||||
break
|
||||
}
|
||||
|
||||
if word == *cfg.LocalizationSettings.DefaultClientLocale {
|
||||
isDefaultClientLocaleInAvailableLocales = true
|
||||
}
|
||||
}
|
||||
|
||||
availableLocales := *cfg.LocalizationSettings.AvailableLocales
|
||||
|
||||
if !isDefaultClientLocaleInAvailableLocales {
|
||||
availableLocales += "," + *cfg.LocalizationSettings.DefaultClientLocale
|
||||
mlog.Warn("Adding DefaultClientLocale to AvailableLocales.")
|
||||
changed = true
|
||||
}
|
||||
|
||||
*cfg.LocalizationSettings.AvailableLocales = strings.Join(utils.RemoveDuplicatesFromStringArray(strings.Split(availableLocales, ",")), ",")
|
||||
}
|
||||
|
||||
return changed
|
||||
}
|
||||
Ссылка в новой задаче
Block a user