MM-28859 Add feature flag managment system using split.io and remove viper. (#15954)

* Add feature flag managment system using split.io and remove viper.

* Fixing tests.

* Attempt to fix postgres tests.

* Fix watch filepath for advanced logging.

* Review fixes.

* Some error wrapping.

* Remove unessisary store interface.

* Desanitize SplitKey

* Simplify.

* Review feedback.

* Rename split mlog adatper to split logger.

* fsInner

* Style.

* Restore oldcfg test.

* Downgrading non-actionable feature flag errors to warnings.

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Christopher Speller
2020-10-29 15:54:39 -07:00
коммит произвёл GitHub
родитель 8bb772638c
Коммит 1aadd36644
423 изменённых файлов: 37646 добавлений и 20257 удалений

Просмотреть файл

@@ -15,6 +15,7 @@ import (
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"sync"
"sync/atomic"
@@ -127,7 +128,7 @@ type Server struct {
searchConfigListenerId string
searchLicenseListenerId string
loggerLicenseListenerId string
configStore config.Store
configStore *config.Store
asymmetricSigningKey *ecdsa.PrivateKey
postActionCookieSecret []byte
@@ -178,6 +179,11 @@ type Server struct {
// and data corruption.
uploadLockMapMut sync.Mutex
uploadLockMap map[string]bool
featureFlagSynchronizer *config.FeatureFlagSynchronizer
featureFlagStop chan struct{}
featureFlagStopped chan struct{}
featureFlagSynchronizerMutex sync.Mutex
}
func NewServer(options ...Option) (*Server, error) {
@@ -200,7 +206,11 @@ func NewServer(options ...Option) (*Server, error) {
}
if s.configStore == nil {
configStore, err := config.NewFileStore("config.json", true)
innerStore, err := config.NewFileStore("config.json", true)
if err != nil {
return nil, errors.Wrap(err, "failed to load config")
}
configStore, err := config.NewStoreFromBacking(innerStore)
if err != nil {
return nil, errors.Wrap(err, "failed to load config")
}
@@ -292,27 +302,6 @@ func NewServer(options ...Option) (*Server, error) {
return nil, errors.Wrapf(err, "unable to load Mattermost translation files")
}
s.configListenerId = s.AddConfigListener(func(_, _ *model.Config) {
s.configOrLicenseListener()
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CONFIG_CHANGED, "", "", "", nil)
message.Add("config", s.ClientConfigWithComputed())
s.Go(func() {
s.Publish(message)
})
})
s.licenseListenerId = s.AddLicenseListener(func(oldLicense, newLicense *model.License) {
s.configOrLicenseListener()
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_LICENSE_CHANGED, "", "", "", nil)
message.Add("license", s.GetSanitizedClientLicense())
s.Go(func() {
s.Publish(message)
})
})
s.initEnterprise()
if s.newStore == nil {
@@ -353,6 +342,27 @@ func NewServer(options ...Option) (*Server, error) {
s.Store = s.newStore()
s.configListenerId = s.AddConfigListener(func(_, _ *model.Config) {
s.configOrLicenseListener()
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CONFIG_CHANGED, "", "", "", nil)
message.Add("config", s.ClientConfigWithComputed())
s.Go(func() {
s.Publish(message)
})
})
s.licenseListenerId = s.AddLicenseListener(func(oldLicense, newLicense *model.License) {
s.configOrLicenseListener()
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_LICENSE_CHANGED, "", "", "", nil)
message.Add("license", s.GetSanitizedClientLicense())
s.Go(func() {
s.Publish(message)
})
})
s.telemetryService = telemetry.New(s, s.Store, s.SearchEngine, s.Log)
emailService, err := NewEmailService(s)
@@ -365,8 +375,18 @@ func NewServer(options ...Option) (*Server, error) {
s.LoadLicense()
}
s.setupFeatureFlags()
s.initJobs()
s.clusterLeaderListenerId = s.AddClusterLeaderChangedListener(func() {
mlog.Info("Cluster leader changed. Determining if job schedulers should be running:", mlog.Bool("isLeader", s.IsLeader()))
if s.Jobs != nil && s.Jobs.Schedulers != nil {
s.Jobs.Schedulers.HandleClusterLeaderChange(s.IsLeader())
}
s.setupFeatureFlags()
})
if s.joinCluster && s.Cluster != nil {
s.Cluster.StartInterNodeCommunication()
}
@@ -389,13 +409,6 @@ func NewServer(options ...Option) (*Server, error) {
s.regenerateClientConfig()
s.clusterLeaderListenerId = s.AddClusterLeaderChangedListener(func() {
mlog.Info("Cluster leader changed. Determining if job schedulers should be running:", mlog.Bool("isLeader", s.IsLeader()))
if s.Jobs != nil && s.Jobs.Schedulers != nil {
s.Jobs.Schedulers.HandleClusterLeaderChange(s.IsLeader())
}
})
subpath, err := utils.GetSubpathFromConfig(s.Config())
if err != nil {
return nil, errors.Wrap(err, "failed to parse SiteURL subpath")
@@ -480,7 +493,6 @@ func NewServer(options ...Option) (*Server, error) {
s.checkPushNotificationServerUrl()
license := s.License()
if license == nil {
s.UpdateConfig(func(cfg *model.Config) {
cfg.TeamSettings.MaxNotificationsPerChannel = &MaxNotificationsPerChannelDefault
@@ -618,10 +630,9 @@ func (s *Server) initLogging() error {
isJson := config.IsJsonMap(dsn)
// If this is a file based config we need the full path so it can be watched.
if !isJson {
if fs, ok := s.configStore.(*config.FileStore); ok {
dsn = fs.GetFilePath(dsn)
}
if !isJson && strings.HasPrefix(s.configStore.String(), "file://") && !filepath.IsAbs(dsn) {
configPath := strings.TrimPrefix(s.configStore.String(), "file://")
dsn = filepath.Join(filepath.Dir(configPath), dsn)
}
cfg, err := config.NewLogConfigSrc(dsn, isJson, s.configStore)
@@ -752,6 +763,8 @@ func (s *Server) Shutdown() error {
s.Audit.Shutdown()
s.stopFeatureFlagUpdateJob()
s.configStore.Close()
if s.Cluster != nil {