MM-40813: Add config interface (#19571)
We create the basic boilerplate to pass services to each product. The basic idea is to have a map containing service names and the services. The server will pass all services to all products. But it is on the product, to choose what services they will actually consume. Each product will cast the received service to an interface with the methods that product requires. https://mattermost.atlassian.net/browse/MM-40813 ```release-note NONE ```
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
e96daef1e1
Коммит
dbf779b828
@@ -111,7 +111,7 @@ func (s *Server) configureAudit(adt *audit.Audit, bAllowAdvancedLogging bool) er
|
|||||||
dsn := *s.Config().ExperimentalAuditSettings.AdvancedLoggingConfig
|
dsn := *s.Config().ExperimentalAuditSettings.AdvancedLoggingConfig
|
||||||
if bAllowAdvancedLogging && dsn != "" {
|
if bAllowAdvancedLogging && dsn != "" {
|
||||||
var err error
|
var err error
|
||||||
logConfigSrc, err = config.NewLogConfigSrc(dsn, s.configStore)
|
logConfigSrc, err = config.NewLogConfigSrc(dsn, s.configStore.Store)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid config source for audit, %w", err)
|
return fmt.Errorf("invalid config source for audit, %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -20,9 +21,26 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// configSvc is a consumer interface to work
|
||||||
|
// with any config related task with the server.
|
||||||
|
type configSvc interface {
|
||||||
|
Config() *model.Config
|
||||||
|
AddConfigListener(listener func(*model.Config, *model.Config)) string
|
||||||
|
RemoveConfigListener(id string)
|
||||||
|
UpdateConfig(f func(*model.Config))
|
||||||
|
SaveConfig(newCfg *model.Config, sendConfigChangeClusterMessage bool) (*model.Config, *model.Config, *model.AppError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// namer is an interface which enforces that
|
||||||
|
// all services can return their names.
|
||||||
|
type namer interface {
|
||||||
|
Name() ServiceKey
|
||||||
|
}
|
||||||
|
|
||||||
// Channels contains all channels related state.
|
// Channels contains all channels related state.
|
||||||
type Channels struct {
|
type Channels struct {
|
||||||
srv *Server
|
srv *Server
|
||||||
|
cfgSvc configSvc
|
||||||
|
|
||||||
postActionCookieSecret []byte
|
postActionCookieSecret []byte
|
||||||
|
|
||||||
@@ -65,17 +83,44 @@ type Channels struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
RegisterProduct("channels", func(s *Server) (Product, error) {
|
RegisterProduct("channels", func(s *Server, services map[ServiceKey]interface{}) (Product, error) {
|
||||||
return NewChannels(s)
|
return NewChannels(s, services)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChannels(s *Server) (*Channels, error) {
|
func NewChannels(s *Server, services map[ServiceKey]interface{}) (*Channels, error) {
|
||||||
|
|
||||||
ch := &Channels{
|
ch := &Channels{
|
||||||
srv: s,
|
srv: s,
|
||||||
imageProxy: imageproxy.MakeImageProxy(s, s.httpService, s.Log),
|
imageProxy: imageproxy.MakeImageProxy(s, s.httpService, s.Log),
|
||||||
uploadLockMap: map[string]bool{},
|
uploadLockMap: map[string]bool{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To get another service:
|
||||||
|
// 1. Prepare the service interface
|
||||||
|
// 2. Add the field to *Channels
|
||||||
|
// 3. Add the service key to the slice.
|
||||||
|
// 4. Add a new case in the switch statement.
|
||||||
|
requiredServices := []ServiceKey{ConfigKey}
|
||||||
|
for _, svcKey := range requiredServices {
|
||||||
|
svc, ok := services[svcKey]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Service %s not passed", svcKey)
|
||||||
|
}
|
||||||
|
switch svcKey {
|
||||||
|
// Keep adding more services here
|
||||||
|
case ConfigKey:
|
||||||
|
cfgSvc, ok := svc.(configSvc)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("Config service did not satisfy ConfigSvc interface")
|
||||||
|
}
|
||||||
|
_, ok = svc.(namer)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("Config service does not contain Name method")
|
||||||
|
}
|
||||||
|
ch.cfgSvc = cfgSvc
|
||||||
|
}
|
||||||
|
}
|
||||||
// We are passing a partially filled Channels struct so that the enterprise
|
// We are passing a partially filled Channels struct so that the enterprise
|
||||||
// methods can have access to app methods.
|
// methods can have access to app methods.
|
||||||
// Otherwise, passing server would mean it has to call s.Channels(),
|
// Otherwise, passing server would mean it has to call s.Channels(),
|
||||||
@@ -119,7 +164,7 @@ func NewChannels(s *Server) (*Channels, error) {
|
|||||||
func (ch *Channels) Start() error {
|
func (ch *Channels) Start() error {
|
||||||
// Start plugins
|
// Start plugins
|
||||||
ctx := request.EmptyContext()
|
ctx := request.EmptyContext()
|
||||||
ch.initPlugins(ctx, *ch.srv.Config().PluginSettings.Directory, *ch.srv.Config().PluginSettings.ClientDirectory)
|
ch.initPlugins(ctx, *ch.cfgSvc.Config().PluginSettings.Directory, *ch.cfgSvc.Config().PluginSettings.ClientDirectory)
|
||||||
|
|
||||||
ch.AddConfigListener(func(prevCfg, cfg *model.Config) {
|
ch.AddConfigListener(func(prevCfg, cfg *model.Config) {
|
||||||
// We compute the difference between configs
|
// We compute the difference between configs
|
||||||
@@ -142,7 +187,7 @@ func (ch *Channels) Start() error {
|
|||||||
// Do only if some plugin related settings has changed.
|
// Do only if some plugin related settings has changed.
|
||||||
if hasDiff {
|
if hasDiff {
|
||||||
if *cfg.PluginSettings.Enable {
|
if *cfg.PluginSettings.Enable {
|
||||||
ch.initPlugins(ctx, *cfg.PluginSettings.Directory, *ch.srv.Config().PluginSettings.ClientDirectory)
|
ch.initPlugins(ctx, *cfg.PluginSettings.Directory, *ch.cfgSvc.Config().PluginSettings.ClientDirectory)
|
||||||
} else {
|
} else {
|
||||||
ch.ShutDownPlugins()
|
ch.ShutDownPlugins()
|
||||||
}
|
}
|
||||||
|
|||||||
125
app/config.go
125
app/config.go
@@ -31,8 +31,82 @@ const (
|
|||||||
ErrorTermsOfServiceNoRowsFound = "app.terms_of_service.get.no_rows.app_error"
|
ErrorTermsOfServiceNoRowsFound = "app.terms_of_service.get.no_rows.app_error"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// configWrapper is an adapter struct that only exposes the
|
||||||
|
// config related functionality to be passed down to other products.
|
||||||
|
type configWrapper struct {
|
||||||
|
srv *Server
|
||||||
|
*config.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *configWrapper) Name() ServiceKey {
|
||||||
|
return ConfigKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *configWrapper) Config() *model.Config {
|
||||||
|
return w.Store.Get()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *configWrapper) AddConfigListener(listener func(*model.Config, *model.Config)) string {
|
||||||
|
return w.Store.AddListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *configWrapper) RemoveConfigListener(id string) {
|
||||||
|
w.Store.RemoveListener(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *configWrapper) UpdateConfig(f func(*model.Config)) {
|
||||||
|
if w.Store.IsReadOnly() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
old := w.Config()
|
||||||
|
updated := old.Clone()
|
||||||
|
f(updated)
|
||||||
|
if _, _, err := w.Store.Set(updated); err != nil {
|
||||||
|
mlog.Error("Failed to update config", mlog.Err(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *configWrapper) SaveConfig(newCfg *model.Config, sendConfigChangeClusterMessage bool) (*model.Config, *model.Config, *model.AppError) {
|
||||||
|
oldCfg, newCfg, err := w.Store.Set(newCfg)
|
||||||
|
if errors.Cause(err) == config.ErrReadOnlyConfiguration {
|
||||||
|
return nil, nil, model.NewAppError("saveConfig", "ent.cluster.save_config.error", nil, err.Error(), http.StatusForbidden)
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, nil, model.NewAppError("saveConfig", "app.save_config.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
if w.srv.startMetrics && *w.Config().MetricsSettings.Enable {
|
||||||
|
if w.srv.Metrics != nil {
|
||||||
|
w.srv.Metrics.Register()
|
||||||
|
}
|
||||||
|
w.srv.SetupMetricsServer()
|
||||||
|
} else {
|
||||||
|
w.srv.StopMetricsServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
if w.srv.Cluster != nil {
|
||||||
|
err := w.srv.Cluster.ConfigChanged(w.Store.RemoveEnvironmentOverrides(oldCfg),
|
||||||
|
w.Store.RemoveEnvironmentOverrides(newCfg), sendConfigChangeClusterMessage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return oldCfg, newCfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *configWrapper) ReloadConfig() error {
|
||||||
|
if err := w.Store.Load(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) Config() *model.Config {
|
func (s *Server) Config() *model.Config {
|
||||||
return s.configStore.Get()
|
return s.configStore.Config()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) ConfigStore() *configWrapper {
|
||||||
|
return s.configStore
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Config() *model.Config {
|
func (a *App) Config() *model.Config {
|
||||||
@@ -48,15 +122,7 @@ func (a *App) EnvironmentConfig(filter func(reflect.StructField) bool) map[strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) UpdateConfig(f func(*model.Config)) {
|
func (s *Server) UpdateConfig(f func(*model.Config)) {
|
||||||
if s.configStore.IsReadOnly() {
|
s.configStore.UpdateConfig(f)
|
||||||
return
|
|
||||||
}
|
|
||||||
old := s.Config()
|
|
||||||
updated := old.Clone()
|
|
||||||
f(updated)
|
|
||||||
if _, _, err := s.configStore.Set(updated); err != nil {
|
|
||||||
mlog.Error("Failed to update config", mlog.Err(err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) UpdateConfig(f func(*model.Config)) {
|
func (a *App) UpdateConfig(f func(*model.Config)) {
|
||||||
@@ -64,10 +130,7 @@ func (a *App) UpdateConfig(f func(*model.Config)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) ReloadConfig() error {
|
func (s *Server) ReloadConfig() error {
|
||||||
if err := s.configStore.Load(); err != nil {
|
return s.configStore.ReloadConfig()
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) ReloadConfig() error {
|
func (a *App) ReloadConfig() error {
|
||||||
@@ -90,7 +153,7 @@ func (a *App) LimitedClientConfig() map[string]string {
|
|||||||
// will be called with two arguments: the old config and the new config. AddConfigListener returns a unique ID
|
// will be called with two arguments: the old config and the new config. AddConfigListener returns a unique ID
|
||||||
// for the listener that can later be used to remove it.
|
// for the listener that can later be used to remove it.
|
||||||
func (s *Server) AddConfigListener(listener func(*model.Config, *model.Config)) string {
|
func (s *Server) AddConfigListener(listener func(*model.Config, *model.Config)) string {
|
||||||
return s.configStore.AddListener(listener)
|
return s.configStore.AddConfigListener(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) AddConfigListener(listener func(*model.Config, *model.Config)) string {
|
func (a *App) AddConfigListener(listener func(*model.Config, *model.Config)) string {
|
||||||
@@ -99,7 +162,7 @@ func (a *App) AddConfigListener(listener func(*model.Config, *model.Config)) str
|
|||||||
|
|
||||||
// Removes a listener function by the unique ID returned when AddConfigListener was called
|
// Removes a listener function by the unique ID returned when AddConfigListener was called
|
||||||
func (s *Server) RemoveConfigListener(id string) {
|
func (s *Server) RemoveConfigListener(id string) {
|
||||||
s.configStore.RemoveListener(id)
|
s.configStore.RemoveConfigListener(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) RemoveConfigListener(id string) {
|
func (a *App) RemoveConfigListener(id string) {
|
||||||
@@ -303,8 +366,8 @@ func (a *App) PostActionCookieSecret() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ch *Channels) regenerateClientConfig() {
|
func (ch *Channels) regenerateClientConfig() {
|
||||||
clientConfig := config.GenerateClientConfig(ch.srv.Config(), ch.srv.TelemetryId(), ch.srv.License())
|
clientConfig := config.GenerateClientConfig(ch.cfgSvc.Config(), ch.srv.TelemetryId(), ch.srv.License())
|
||||||
limitedClientConfig := config.GenerateLimitedClientConfig(ch.srv.Config(), ch.srv.TelemetryId(), ch.srv.License())
|
limitedClientConfig := config.GenerateLimitedClientConfig(ch.cfgSvc.Config(), ch.srv.TelemetryId(), ch.srv.License())
|
||||||
|
|
||||||
if clientConfig["EnableCustomTermsOfService"] == "true" {
|
if clientConfig["EnableCustomTermsOfService"] == "true" {
|
||||||
termsOfService, err := ch.srv.Store.TermsOfService().GetLatest(true)
|
termsOfService, err := ch.srv.Store.TermsOfService().GetLatest(true)
|
||||||
@@ -402,31 +465,7 @@ func (a *App) GetEnvironmentConfig(filter func(reflect.StructField) bool) map[st
|
|||||||
// SaveConfig replaces the active configuration, optionally notifying cluster peers.
|
// SaveConfig replaces the active configuration, optionally notifying cluster peers.
|
||||||
// It returns both the previous and current configs.
|
// It returns both the previous and current configs.
|
||||||
func (s *Server) SaveConfig(newCfg *model.Config, sendConfigChangeClusterMessage bool) (*model.Config, *model.Config, *model.AppError) {
|
func (s *Server) SaveConfig(newCfg *model.Config, sendConfigChangeClusterMessage bool) (*model.Config, *model.Config, *model.AppError) {
|
||||||
oldCfg, newCfg, err := s.configStore.Set(newCfg)
|
return s.configStore.SaveConfig(newCfg, sendConfigChangeClusterMessage)
|
||||||
if errors.Cause(err) == config.ErrReadOnlyConfiguration {
|
|
||||||
return nil, nil, model.NewAppError("saveConfig", "ent.cluster.save_config.error", nil, err.Error(), http.StatusForbidden)
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, nil, model.NewAppError("saveConfig", "app.save_config.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.startMetrics && *s.Config().MetricsSettings.Enable {
|
|
||||||
if s.Metrics != nil {
|
|
||||||
s.Metrics.Register()
|
|
||||||
}
|
|
||||||
s.SetupMetricsServer()
|
|
||||||
} else {
|
|
||||||
s.StopMetricsServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Cluster != nil {
|
|
||||||
err := s.Cluster.ConfigChanged(s.configStore.RemoveEnvironmentOverrides(oldCfg),
|
|
||||||
s.configStore.RemoveEnvironmentOverrides(newCfg), sendConfigChangeClusterMessage)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return oldCfg, newCfg, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveConfig replaces the active configuration, optionally notifying cluster peers.
|
// SaveConfig replaces the active configuration, optionally notifying cluster peers.
|
||||||
|
|||||||
@@ -1403,12 +1403,15 @@ func TestPushNotificationRace(t *testing.T) {
|
|||||||
Return(&model.Preference{Value: "test"}, nil)
|
Return(&model.Preference{Value: "test"}, nil)
|
||||||
mockStore.On("Preference").Return(&mockPreferenceStore)
|
mockStore.On("Preference").Return(&mockPreferenceStore)
|
||||||
s := &Server{
|
s := &Server{
|
||||||
configStore: memoryStore,
|
Store: mockStore,
|
||||||
Store: mockStore,
|
products: make(map[string]Product),
|
||||||
products: make(map[string]Product),
|
Router: mux.NewRouter(),
|
||||||
Router: mux.NewRouter(),
|
|
||||||
}
|
}
|
||||||
ch, err := NewChannels(s)
|
s.configStore = &configWrapper{srv: s, Store: memoryStore}
|
||||||
|
serviceMap := map[ServiceKey]interface{}{
|
||||||
|
ConfigKey: s.configStore,
|
||||||
|
}
|
||||||
|
ch, err := NewChannels(s, serviceMap)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
s.products["channels"] = ch
|
s.products["channels"] = ch
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func Config(dsn string, readOnly bool, configDefaults *model.Config) Option {
|
|||||||
return errors.Wrap(err, "failed to apply Config option")
|
return errors.Wrap(err, "failed to apply Config option")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.configStore = configStore
|
s.configStore = &configWrapper{srv: s, Store: configStore}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ func Config(dsn string, readOnly bool, configDefaults *model.Config) Option {
|
|||||||
// ConfigStore applies the given config store, typically to replace the traditional sources with a memory store for testing.
|
// ConfigStore applies the given config store, typically to replace the traditional sources with a memory store for testing.
|
||||||
func ConfigStore(configStore *config.Store) Option {
|
func ConfigStore(configStore *config.Store) Option {
|
||||||
return func(s *Server) error {
|
return func(s *Server) error {
|
||||||
s.configStore = configStore
|
s.configStore = &configWrapper{srv: s, Store: configStore}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ type pluginSignaturePath struct {
|
|||||||
// To get the plugins environment when the plugins are disabled, manually acquire the plugins
|
// To get the plugins environment when the plugins are disabled, manually acquire the plugins
|
||||||
// lock instead.
|
// lock instead.
|
||||||
func (ch *Channels) GetPluginsEnvironment() *plugin.Environment {
|
func (ch *Channels) GetPluginsEnvironment() *plugin.Environment {
|
||||||
if !*ch.srv.Config().PluginSettings.Enable {
|
if !*ch.cfgSvc.Config().PluginSettings.Enable {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ func (ch *Channels) syncPluginsActiveState() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config := ch.srv.Config().PluginSettings
|
config := ch.cfgSvc.Config().PluginSettings
|
||||||
|
|
||||||
if *config.Enable {
|
if *config.Enable {
|
||||||
availablePlugins, err := pluginsEnvironment.Available()
|
availablePlugins, err := pluginsEnvironment.Available()
|
||||||
@@ -100,7 +100,7 @@ func (ch *Channels) syncPluginsActiveState() {
|
|||||||
|
|
||||||
// Tie Apps proxy disabled status to the feature flag.
|
// Tie Apps proxy disabled status to the feature flag.
|
||||||
if pluginID == "com.mattermost.apps" {
|
if pluginID == "com.mattermost.apps" {
|
||||||
if !ch.srv.Config().FeatureFlags.AppsEnabled {
|
if !ch.cfgSvc.Config().FeatureFlags.AppsEnabled {
|
||||||
pluginEnabled = false
|
pluginEnabled = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,10 +174,10 @@ func (ch *Channels) initPlugins(c *request.Context, pluginDir, webappPluginDir s
|
|||||||
ch.pluginsLock.RLock()
|
ch.pluginsLock.RLock()
|
||||||
pluginsEnvironment := ch.pluginsEnvironment
|
pluginsEnvironment := ch.pluginsEnvironment
|
||||||
ch.pluginsLock.RUnlock()
|
ch.pluginsLock.RUnlock()
|
||||||
if pluginsEnvironment != nil || !*ch.srv.Config().PluginSettings.Enable {
|
if pluginsEnvironment != nil || !*ch.cfgSvc.Config().PluginSettings.Enable {
|
||||||
ch.syncPluginsActiveState()
|
ch.syncPluginsActiveState()
|
||||||
if pluginsEnvironment != nil {
|
if pluginsEnvironment != nil {
|
||||||
pluginsEnvironment.TogglePluginHealthCheckJob(*ch.srv.Config().PluginSettings.EnableHealthCheck)
|
pluginsEnvironment.TogglePluginHealthCheckJob(*ch.cfgSvc.Config().PluginSettings.EnableHealthCheck)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -207,7 +207,7 @@ func (ch *Channels) initPlugins(c *request.Context, pluginDir, webappPluginDir s
|
|||||||
ch.pluginsEnvironment = env
|
ch.pluginsEnvironment = env
|
||||||
ch.pluginsLock.Unlock()
|
ch.pluginsLock.Unlock()
|
||||||
|
|
||||||
ch.pluginsEnvironment.TogglePluginHealthCheckJob(*ch.srv.Config().PluginSettings.EnableHealthCheck)
|
ch.pluginsEnvironment.TogglePluginHealthCheckJob(*ch.cfgSvc.Config().PluginSettings.EnableHealthCheck)
|
||||||
|
|
||||||
if err := ch.syncPlugins(); err != nil {
|
if err := ch.syncPlugins(); err != nil {
|
||||||
mlog.Error("Failed to sync plugins from the file store", mlog.Err(err))
|
mlog.Error("Failed to sync plugins from the file store", mlog.Err(err))
|
||||||
@@ -274,7 +274,7 @@ func (ch *Channels) syncPlugins() *model.AppError {
|
|||||||
go func(pluginID string) {
|
go func(pluginID string) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
// Only handle managed plugins with .filestore flag file.
|
// Only handle managed plugins with .filestore flag file.
|
||||||
_, err := os.Stat(filepath.Join(*ch.srv.Config().PluginSettings.Directory, pluginID, managedPluginFileName))
|
_, err := os.Stat(filepath.Join(*ch.cfgSvc.Config().PluginSettings.Directory, pluginID, managedPluginFileName))
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
mlog.Warn("Skipping sync for unmanaged plugin", mlog.String("plugin_id", pluginID))
|
mlog.Warn("Skipping sync for unmanaged plugin", mlog.String("plugin_id", pluginID))
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@@ -307,7 +307,7 @@ func (ch *Channels) syncPlugins() *model.AppError {
|
|||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
|
|
||||||
var signature filestore.ReadCloseSeeker
|
var signature filestore.ReadCloseSeeker
|
||||||
if *ch.srv.Config().PluginSettings.RequirePluginSignature {
|
if *ch.cfgSvc.Config().PluginSettings.RequirePluginSignature {
|
||||||
signature, appErr = ch.srv.fileReader(plugin.signaturePath)
|
signature, appErr = ch.srv.fileReader(plugin.signaturePath)
|
||||||
if appErr != nil {
|
if appErr != nil {
|
||||||
mlog.Error("Failed to open plugin signature from file store.", mlog.Err(appErr))
|
mlog.Error("Failed to open plugin signature from file store.", mlog.Err(appErr))
|
||||||
@@ -401,12 +401,12 @@ func (ch *Channels) enablePlugin(id string) *model.AppError {
|
|||||||
return model.NewAppError("EnablePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusNotFound)
|
return model.NewAppError("EnablePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
ch.srv.UpdateConfig(func(cfg *model.Config) {
|
ch.cfgSvc.UpdateConfig(func(cfg *model.Config) {
|
||||||
cfg.PluginSettings.PluginStates[id] = &model.PluginState{Enable: true}
|
cfg.PluginSettings.PluginStates[id] = &model.PluginState{Enable: true}
|
||||||
})
|
})
|
||||||
|
|
||||||
// This call will implicitly invoke SyncPluginsActiveState which will activate enabled plugins.
|
// This call will implicitly invoke SyncPluginsActiveState which will activate enabled plugins.
|
||||||
if _, _, err := ch.srv.SaveConfig(ch.srv.Config(), true); err != nil {
|
if _, _, err := ch.cfgSvc.SaveConfig(ch.cfgSvc.Config(), true); err != nil {
|
||||||
if err.Id == "ent.cluster.save_config.error" {
|
if err.Id == "ent.cluster.save_config.error" {
|
||||||
return model.NewAppError("EnablePlugin", "app.plugin.cluster.save_config.app_error", nil, "", http.StatusInternalServerError)
|
return model.NewAppError("EnablePlugin", "app.plugin.cluster.save_config.app_error", nil, "", http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
@@ -447,13 +447,13 @@ func (ch *Channels) disablePlugin(id string) *model.AppError {
|
|||||||
return model.NewAppError("DisablePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusNotFound)
|
return model.NewAppError("DisablePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
ch.srv.UpdateConfig(func(cfg *model.Config) {
|
ch.cfgSvc.UpdateConfig(func(cfg *model.Config) {
|
||||||
cfg.PluginSettings.PluginStates[id] = &model.PluginState{Enable: false}
|
cfg.PluginSettings.PluginStates[id] = &model.PluginState{Enable: false}
|
||||||
})
|
})
|
||||||
ch.unregisterPluginCommands(id)
|
ch.unregisterPluginCommands(id)
|
||||||
|
|
||||||
// This call will implicitly invoke SyncPluginsActiveState which will deactivate disabled plugins.
|
// This call will implicitly invoke SyncPluginsActiveState which will deactivate disabled plugins.
|
||||||
if _, _, err := ch.srv.SaveConfig(ch.srv.Config(), true); err != nil {
|
if _, _, err := ch.cfgSvc.SaveConfig(ch.cfgSvc.Config(), true); err != nil {
|
||||||
return model.NewAppError("DisablePlugin", "app.plugin.config.app_error", nil, err.Error(), http.StatusInternalServerError)
|
return model.NewAppError("DisablePlugin", "app.plugin.config.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,7 +561,7 @@ func (ch *Channels) getPrepackagedPlugin(pluginID, version string) (*plugin.Prep
|
|||||||
// If version is empty, the latest compatible version is used.
|
// If version is empty, the latest compatible version is used.
|
||||||
func (ch *Channels) getRemoteMarketplacePlugin(pluginID, version string) (*model.BaseMarketplacePlugin, *model.AppError) {
|
func (ch *Channels) getRemoteMarketplacePlugin(pluginID, version string) (*model.BaseMarketplacePlugin, *model.AppError) {
|
||||||
marketplaceClient, err := marketplace.NewClient(
|
marketplaceClient, err := marketplace.NewClient(
|
||||||
*ch.srv.Config().PluginSettings.MarketplaceURL,
|
*ch.cfgSvc.Config().PluginSettings.MarketplaceURL,
|
||||||
ch.srv.HTTPService(),
|
ch.srv.HTTPService(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -835,8 +835,8 @@ func (ch *Channels) getPluginsFromFilePaths(fileStorePaths []string) map[string]
|
|||||||
pluginSignaturePathMap := make(map[string]*pluginSignaturePath)
|
pluginSignaturePathMap := make(map[string]*pluginSignaturePath)
|
||||||
|
|
||||||
fsPrefix := ""
|
fsPrefix := ""
|
||||||
if *ch.srv.Config().FileSettings.DriverName == model.ImageDriverS3 {
|
if *ch.cfgSvc.Config().FileSettings.DriverName == model.ImageDriverS3 {
|
||||||
ptr := ch.srv.Config().FileSettings.AmazonS3PathPrefix
|
ptr := ch.cfgSvc.Config().FileSettings.AmazonS3PathPrefix
|
||||||
if ptr != nil && *ptr != "" {
|
if ptr != nil && *ptr != "" {
|
||||||
fsPrefix = *ptr + "/"
|
fsPrefix = *ptr + "/"
|
||||||
}
|
}
|
||||||
@@ -936,12 +936,12 @@ func (ch *Channels) processPrepackagedPlugin(pluginPath *pluginSignaturePath) (*
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Skip installing the plugin at all if automatic prepackaged plugins is disabled
|
// Skip installing the plugin at all if automatic prepackaged plugins is disabled
|
||||||
if !*ch.srv.Config().PluginSettings.AutomaticPrepackagedPlugins {
|
if !*ch.cfgSvc.Config().PluginSettings.AutomaticPrepackagedPlugins {
|
||||||
return plugin, nil
|
return plugin, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip installing if the plugin is has not been previously enabled.
|
// Skip installing if the plugin is has not been previously enabled.
|
||||||
pluginState := ch.srv.Config().PluginSettings.PluginStates[plugin.Manifest.Id]
|
pluginState := ch.cfgSvc.Config().PluginSettings.PluginStates[plugin.Manifest.Id]
|
||||||
if pluginState == nil || !pluginState.Enable {
|
if pluginState == nil || !pluginState.Enable {
|
||||||
return plugin, nil
|
return plugin, nil
|
||||||
}
|
}
|
||||||
@@ -956,16 +956,16 @@ func (ch *Channels) processPrepackagedPlugin(pluginPath *pluginSignaturePath) (*
|
|||||||
|
|
||||||
// installFeatureFlagPlugins handles the automatic installation/upgrade of plugins from feature flags
|
// installFeatureFlagPlugins handles the automatic installation/upgrade of plugins from feature flags
|
||||||
func (ch *Channels) installFeatureFlagPlugins() {
|
func (ch *Channels) installFeatureFlagPlugins() {
|
||||||
ffControledPlugins := ch.srv.Config().FeatureFlags.Plugins()
|
ffControledPlugins := ch.cfgSvc.Config().FeatureFlags.Plugins()
|
||||||
|
|
||||||
// Respect the automatic prepackaged disable setting
|
// Respect the automatic prepackaged disable setting
|
||||||
if !*ch.srv.Config().PluginSettings.AutomaticPrepackagedPlugins {
|
if !*ch.cfgSvc.Config().PluginSettings.AutomaticPrepackagedPlugins {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for pluginID, version := range ffControledPlugins {
|
for pluginID, version := range ffControledPlugins {
|
||||||
// Skip installing if the plugin has been previously disabled.
|
// Skip installing if the plugin has been previously disabled.
|
||||||
pluginState := ch.srv.Config().PluginSettings.PluginStates[pluginID]
|
pluginState := ch.cfgSvc.Config().PluginSettings.PluginStates[pluginID]
|
||||||
if pluginState != nil && !pluginState.Enable {
|
if pluginState != nil && !pluginState.Enable {
|
||||||
ch.srv.Log.Debug("Not auto installing/upgrade because plugin was disabled", mlog.String("plugin_id", pluginID), mlog.String("version", version))
|
ch.srv.Log.Debug("Not auto installing/upgrade because plugin was disabled", mlog.String("plugin_id", pluginID), mlog.String("version", version))
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ func (ch *Channels) installPluginFromData(data model.PluginEventData) {
|
|||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
|
|
||||||
var signature filestore.ReadCloseSeeker
|
var signature filestore.ReadCloseSeeker
|
||||||
if *ch.srv.Config().PluginSettings.RequirePluginSignature {
|
if *ch.cfgSvc.Config().PluginSettings.RequirePluginSignature {
|
||||||
signature, appErr = ch.srv.fileReader(plugin.signaturePath)
|
signature, appErr = ch.srv.fileReader(plugin.signaturePath)
|
||||||
if appErr != nil {
|
if appErr != nil {
|
||||||
mlog.Error("Failed to open plugin signature from file store.", mlog.Err(appErr))
|
mlog.Error("Failed to open plugin signature from file store.", mlog.Err(appErr))
|
||||||
@@ -196,7 +196,7 @@ func (ch *Channels) InstallMarketplacePlugin(request *model.InstallMarketplacePl
|
|||||||
signatureFile = bytes.NewReader(prepackagedPlugin.Signature)
|
signatureFile = bytes.NewReader(prepackagedPlugin.Signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
if *ch.srv.Config().PluginSettings.EnableRemoteMarketplace && pluginFile == nil {
|
if *ch.cfgSvc.Config().PluginSettings.EnableRemoteMarketplace && pluginFile == nil {
|
||||||
var plugin *model.BaseMarketplacePlugin
|
var plugin *model.BaseMarketplacePlugin
|
||||||
plugin, appErr = ch.getRemoteMarketplacePlugin(request.Id, request.Version)
|
plugin, appErr = ch.getRemoteMarketplacePlugin(request.Id, request.Version)
|
||||||
if appErr != nil {
|
if appErr != nil {
|
||||||
@@ -353,7 +353,7 @@ func (ch *Channels) installExtractedPlugin(manifest *model.Manifest, fromPluginD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pluginPath := filepath.Join(*ch.srv.Config().PluginSettings.Directory, manifest.Id)
|
pluginPath := filepath.Join(*ch.cfgSvc.Config().PluginSettings.Directory, manifest.Id)
|
||||||
err = utils.CopyDir(fromPluginDir, pluginPath)
|
err = utils.CopyDir(fromPluginDir, pluginPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, model.NewAppError("installExtractedPlugin", "app.plugin.mvdir.app_error", nil, err.Error(), http.StatusInternalServerError)
|
return nil, model.NewAppError("installExtractedPlugin", "app.plugin.mvdir.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
@@ -375,9 +375,9 @@ func (ch *Channels) installExtractedPlugin(manifest *model.Manifest, fromPluginD
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Activate the plugin if enabled.
|
// Activate the plugin if enabled.
|
||||||
pluginState := ch.srv.Config().PluginSettings.PluginStates[manifest.Id]
|
pluginState := ch.cfgSvc.Config().PluginSettings.PluginStates[manifest.Id]
|
||||||
if pluginState != nil && pluginState.Enable {
|
if pluginState != nil && pluginState.Enable {
|
||||||
if manifest.Id == "com.mattermost.apps" && !ch.srv.Config().FeatureFlags.AppsEnabled {
|
if manifest.Id == "com.mattermost.apps" && !ch.cfgSvc.Config().FeatureFlags.AppsEnabled {
|
||||||
return manifest, nil
|
return manifest, nil
|
||||||
}
|
}
|
||||||
updatedManifest, _, err := pluginsEnvironment.Activate(manifest.Id)
|
updatedManifest, _, err := pluginsEnvironment.Activate(manifest.Id)
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ func (ch *Channels) servePluginRequest(w http.ResponseWriter, r *http.Request, h
|
|||||||
token := ""
|
token := ""
|
||||||
context := &plugin.Context{
|
context := &plugin.Context{
|
||||||
RequestId: model.NewId(),
|
RequestId: model.NewId(),
|
||||||
IPAddress: utils.GetIPAddress(r, ch.srv.Config().ServiceSettings.TrustedProxyIPHeader),
|
IPAddress: utils.GetIPAddress(r, ch.cfgSvc.Config().ServiceSettings.TrustedProxyIPHeader),
|
||||||
AcceptLanguage: r.Header.Get("Accept-Language"),
|
AcceptLanguage: r.Header.Get("Accept-Language"),
|
||||||
UserAgent: r.UserAgent(),
|
UserAgent: r.UserAgent(),
|
||||||
}
|
}
|
||||||
@@ -183,7 +183,7 @@ func (ch *Channels) servePluginRequest(w http.ResponseWriter, r *http.Request, h
|
|||||||
mlog.String("user_id", userID),
|
mlog.String("user_id", userID),
|
||||||
}
|
}
|
||||||
|
|
||||||
if *ch.srv.Config().ServiceSettings.ExperimentalStrictCSRFEnforcement {
|
if *ch.cfgSvc.Config().ServiceSettings.ExperimentalStrictCSRFEnforcement {
|
||||||
mlog.Warn(csrfErrorMessage, fields...)
|
mlog.Warn(csrfErrorMessage, fields...)
|
||||||
} else {
|
} else {
|
||||||
mlog.Debug(csrfErrorMessage, fields...)
|
mlog.Debug(csrfErrorMessage, fields...)
|
||||||
@@ -212,7 +212,7 @@ func (ch *Channels) servePluginRequest(w http.ResponseWriter, r *http.Request, h
|
|||||||
|
|
||||||
params := mux.Vars(r)
|
params := mux.Vars(r)
|
||||||
|
|
||||||
subpath, _ := utils.GetSubpathFromConfig(ch.srv.Config())
|
subpath, _ := utils.GetSubpathFromConfig(ch.cfgSvc.Config())
|
||||||
|
|
||||||
newQuery := r.URL.Query()
|
newQuery := r.URL.Query()
|
||||||
newQuery.Del("access_token")
|
newQuery.Del("access_token")
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ func (ch *Channels) verifyPlugin(plugin, signature io.ReadSeeker) *model.AppErro
|
|||||||
if err := verifySignature(bytes.NewReader(mattermostPluginPublicKey), plugin, signature); err == nil {
|
if err := verifySignature(bytes.NewReader(mattermostPluginPublicKey), plugin, signature); err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
publicKeys := ch.srv.Config().PluginSettings.SignaturePublicKeyFiles
|
publicKeys := ch.cfgSvc.Config().PluginSettings.SignaturePublicKeyFiles
|
||||||
for _, pk := range publicKeys {
|
for _, pk := range publicKeys {
|
||||||
pkBytes, appErr := ch.srv.getPublicKey(pk)
|
pkBytes, appErr := ch.srv.getPublicKey(pk)
|
||||||
if appErr != nil {
|
if appErr != nil {
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ func (ch *Channels) getClusterPluginStatuses() (model.PluginStatuses, *model.App
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if ch.srv.Cluster != nil && *ch.srv.Config().ClusterSettings.Enable {
|
if ch.srv.Cluster != nil && *ch.cfgSvc.Config().ClusterSettings.Enable {
|
||||||
clusterPluginStatuses, err := ch.srv.Cluster.GetPluginStatuses()
|
clusterPluginStatuses, err := ch.srv.Cluster.GetPluginStatuses()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, model.NewAppError("GetClusterPluginStatuses", "app.plugin.get_cluster_plugin_statuses.app_error", nil, err.Error(), http.StatusInternalServerError)
|
return nil, model.NewAppError("GetClusterPluginStatuses", "app.plugin.get_cluster_plugin_statuses.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ type Product interface {
|
|||||||
Stop() error
|
Stop() error
|
||||||
}
|
}
|
||||||
|
|
||||||
var products = make(map[string]func(*Server) (Product, error))
|
var products = make(map[string]func(*Server, map[ServiceKey]interface{}) (Product, error))
|
||||||
|
|
||||||
func RegisterProduct(name string, f func(*Server) (Product, error)) {
|
func RegisterProduct(name string, f func(*Server, map[ServiceKey]interface{}) (Product, error)) {
|
||||||
products[name] = f
|
products[name] = f
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,12 @@ import (
|
|||||||
// declaring this as var to allow overriding in tests
|
// declaring this as var to allow overriding in tests
|
||||||
var SentryDSN = "placeholder_sentry_dsn"
|
var SentryDSN = "placeholder_sentry_dsn"
|
||||||
|
|
||||||
|
type ServiceKey string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ConfigKey ServiceKey = "config"
|
||||||
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
sqlStore *sqlstore.SqlStore
|
sqlStore *sqlstore.SqlStore
|
||||||
Store store.Store
|
Store store.Store
|
||||||
@@ -150,7 +156,7 @@ type Server struct {
|
|||||||
searchConfigListenerId string
|
searchConfigListenerId string
|
||||||
searchLicenseListenerId string
|
searchLicenseListenerId string
|
||||||
loggerLicenseListenerId string
|
loggerLicenseListenerId string
|
||||||
configStore *config.Store
|
configStore *configWrapper
|
||||||
|
|
||||||
telemetryService *telemetry.TelemetryService
|
telemetryService *telemetry.TelemetryService
|
||||||
userService *users.UserService
|
userService *users.UserService
|
||||||
@@ -231,7 +237,7 @@ func NewServer(options ...Option) (*Server, error) {
|
|||||||
return nil, errors.Wrap(err, "failed to load config")
|
return nil, errors.Wrap(err, "failed to load config")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.configStore = configStore
|
s.configStore = &configWrapper{srv: s, Store: configStore}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Logging
|
// Step 2: Logging
|
||||||
@@ -250,10 +256,13 @@ func NewServer(options ...Option) (*Server, error) {
|
|||||||
|
|
||||||
s.httpService = httpservice.MakeHTTPService(s)
|
s.httpService = httpservice.MakeHTTPService(s)
|
||||||
|
|
||||||
|
serviceMap := map[ServiceKey]interface{}{
|
||||||
|
ConfigKey: s.configStore,
|
||||||
|
}
|
||||||
// Step 3: Initialize products.
|
// Step 3: Initialize products.
|
||||||
// Depends on s.httpService.
|
// Depends on s.httpService.
|
||||||
for name, initializer := range products {
|
for name, initializer := range products {
|
||||||
prod, err2 := initializer(s)
|
prod, err2 := initializer(s, serviceMap)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
return nil, errors.Wrapf(err2, "error initializing product: %s", name)
|
return nil, errors.Wrapf(err2, "error initializing product: %s", name)
|
||||||
}
|
}
|
||||||
@@ -755,7 +764,7 @@ func (s *Server) initLogging() error {
|
|||||||
s.NotificationsLog = l.With(mlog.String("logSource", "notifications"))
|
s.NotificationsLog = l.With(mlog.String("logSource", "notifications"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.configureLogger("logging", s.Log, &s.Config().LogSettings, s.configStore, config.GetLogFileLocation); err != nil {
|
if err := s.configureLogger("logging", s.Log, &s.Config().LogSettings, s.configStore.Store, config.GetLogFileLocation); err != nil {
|
||||||
// if the config is locked then a unit test has already configured and locked the logger; not an error.
|
// if the config is locked then a unit test has already configured and locked the logger; not an error.
|
||||||
if !errors.Is(err, mlog.ErrConfigurationLock) {
|
if !errors.Is(err, mlog.ErrConfigurationLock) {
|
||||||
// revert to default logger if the config is invalid
|
// revert to default logger if the config is invalid
|
||||||
@@ -771,7 +780,7 @@ func (s *Server) initLogging() error {
|
|||||||
mlog.InitGlobalLogger(s.Log)
|
mlog.InitGlobalLogger(s.Log)
|
||||||
|
|
||||||
notificationLogSettings := config.GetLogSettingsFromNotificationsLogSettings(&s.Config().NotificationLogSettings)
|
notificationLogSettings := config.GetLogSettingsFromNotificationsLogSettings(&s.Config().NotificationLogSettings)
|
||||||
if err := s.configureLogger("notification logging", s.NotificationsLog, notificationLogSettings, s.configStore, config.GetNotificationsLogFileLocation); err != nil {
|
if err := s.configureLogger("notification logging", s.NotificationsLog, notificationLogSettings, s.configStore.Store, config.GetNotificationsLogFileLocation); err != nil {
|
||||||
if !errors.Is(err, mlog.ErrConfigurationLock) {
|
if !errors.Is(err, mlog.ErrConfigurationLock) {
|
||||||
mlog.Error("Error configuring notification logger", mlog.Err(err))
|
mlog.Error("Error configuring notification logger", mlog.Err(err))
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ func TestReadReplicaDisabledBasedOnLicense(t *testing.T) {
|
|||||||
s, err := NewServer(func(server *Server) error {
|
s, err := NewServer(func(server *Server) error {
|
||||||
configStore := config.NewTestMemoryStore()
|
configStore := config.NewTestMemoryStore()
|
||||||
configStore.Set(&cfg)
|
configStore.Set(&cfg)
|
||||||
server.configStore = configStore
|
server.configStore = &configWrapper{srv: server, Store: configStore}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -111,7 +111,7 @@ func TestReadReplicaDisabledBasedOnLicense(t *testing.T) {
|
|||||||
s, err := NewServer(func(server *Server) error {
|
s, err := NewServer(func(server *Server) error {
|
||||||
configStore := config.NewTestMemoryStore()
|
configStore := config.NewTestMemoryStore()
|
||||||
configStore.Set(&cfg)
|
configStore.Set(&cfg)
|
||||||
server.configStore = configStore
|
server.configStore = &configWrapper{srv: server, Store: configStore}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -124,7 +124,7 @@ func TestReadReplicaDisabledBasedOnLicense(t *testing.T) {
|
|||||||
s, err := NewServer(func(server *Server) error {
|
s, err := NewServer(func(server *Server) error {
|
||||||
configStore := config.NewTestMemoryStore()
|
configStore := config.NewTestMemoryStore()
|
||||||
configStore.Set(&cfg)
|
configStore.Set(&cfg)
|
||||||
server.configStore = configStore
|
server.configStore = &configWrapper{srv: server, Store: configStore}
|
||||||
server.licenseValue.Store(model.NewTestLicense())
|
server.licenseValue.Store(model.NewTestLicense())
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@@ -169,7 +169,7 @@ func TestStartServerNoS3Bucket(t *testing.T) {
|
|||||||
s, err := NewServer(func(server *Server) error {
|
s, err := NewServer(func(server *Server) error {
|
||||||
configStore, _ := config.NewFileStore("config.json", true)
|
configStore, _ := config.NewFileStore("config.json", true)
|
||||||
store, _ := config.NewStoreFromBacking(configStore, nil, false)
|
store, _ := config.NewStoreFromBacking(configStore, nil, false)
|
||||||
server.configStore = store
|
server.configStore = &configWrapper{srv: server, Store: store}
|
||||||
server.UpdateConfig(func(cfg *model.Config) {
|
server.UpdateConfig(func(cfg *model.Config) {
|
||||||
cfg.FileSettings = model.FileSettings{
|
cfg.FileSettings = model.FileSettings{
|
||||||
DriverName: model.NewString(model.ImageDriverS3),
|
DriverName: model.NewString(model.ImageDriverS3),
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user