Move enterprise features under Channels (#19010)

* Move enterprise features under Channels

We move the EE features which are Channels related.

While here, we also move some code under *Server.Start()
from NewServer.

```release-note
NONE
```

* move saml and ldap back to server

```release-note
NONE
```

* fix test

```release-note
NONE
```

* try again

```release-note
NONE
```
Этот коммит содержится в:
Agniva De Sarker
2021-11-25 10:07:43 +05:30
коммит произвёл GitHub
родитель 189d447591
Коммит 5ab3ad9bfd
7 изменённых файлов: 115 добавлений и 104 удалений

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

@@ -95,16 +95,16 @@ func (a *App) NotificationsLog() *mlog.Logger {
} }
func (a *App) AccountMigration() einterfaces.AccountMigrationInterface { func (a *App) AccountMigration() einterfaces.AccountMigrationInterface {
return a.ch.srv.AccountMigration return a.ch.AccountMigration
} }
func (a *App) Cluster() einterfaces.ClusterInterface { func (a *App) Cluster() einterfaces.ClusterInterface {
return a.ch.srv.Cluster return a.ch.srv.Cluster
} }
func (a *App) Compliance() einterfaces.ComplianceInterface { func (a *App) Compliance() einterfaces.ComplianceInterface {
return a.ch.srv.Compliance return a.ch.Compliance
} }
func (a *App) DataRetention() einterfaces.DataRetentionInterface { func (a *App) DataRetention() einterfaces.DataRetentionInterface {
return a.ch.srv.DataRetention return a.ch.DataRetention
} }
func (a *App) SearchEngine() *searchengine.Broker { func (a *App) SearchEngine() *searchengine.Broker {
return a.ch.srv.SearchEngine return a.ch.srv.SearchEngine
@@ -113,7 +113,7 @@ func (a *App) Ldap() einterfaces.LdapInterface {
return a.ch.srv.Ldap return a.ch.srv.Ldap
} }
func (a *App) MessageExport() einterfaces.MessageExportInterface { func (a *App) MessageExport() einterfaces.MessageExportInterface {
return a.ch.srv.MessageExport return a.ch.MessageExport
} }
func (a *App) Metrics() einterfaces.MetricsInterface { func (a *App) Metrics() einterfaces.MetricsInterface {
return a.ch.srv.Metrics return a.ch.srv.Metrics

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

@@ -8,6 +8,7 @@ import (
"sync/atomic" "sync/atomic"
"github.com/mattermost/mattermost-server/v6/app/request" "github.com/mattermost/mattermost-server/v6/app/request"
"github.com/mattermost/mattermost-server/v6/einterfaces"
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/plugin" "github.com/mattermost/mattermost-server/v6/plugin"
"github.com/mattermost/mattermost-server/v6/services/imageproxy" "github.com/mattermost/mattermost-server/v6/services/imageproxy"
@@ -18,6 +19,8 @@ import (
type Channels struct { type Channels struct {
srv *Server srv *Server
postActionCookieSecret []byte
pluginCommandsLock sync.RWMutex pluginCommandsLock sync.RWMutex
pluginCommands []*PluginCommand pluginCommands []*PluginCommand
pluginsLock sync.RWMutex pluginsLock sync.RWMutex
@@ -37,6 +40,11 @@ type Channels struct {
cachedDBMSVersion string cachedDBMSVersion string
// previously fetched notices // previously fetched notices
cachedNotices model.ProductNotices cachedNotices model.ProductNotices
AccountMigration einterfaces.AccountMigrationInterface
Compliance einterfaces.ComplianceInterface
DataRetention einterfaces.DataRetentionInterface
MessageExport einterfaces.MessageExportInterface
} }
func init() { func init() {
@@ -50,6 +58,23 @@ func NewChannels(s *Server) (*Channels, error) {
srv: s, srv: s,
imageProxy: imageproxy.MakeImageProxy(s, s.httpService, s.Log), imageProxy: imageproxy.MakeImageProxy(s, s.httpService, s.Log),
} }
// We are passing a partially filled Channels struct so that the enterprise
// methods can have access to app methods.
// Otherwise, passing server would mean it has to call s.Channels(),
// which would be nil at this point.
if complianceInterface != nil {
ch.Compliance = complianceInterface(New(ServerConnector(ch)))
}
if messageExportInterface != nil {
ch.MessageExport = messageExportInterface(New(ServerConnector(ch)))
}
if dataRetentionInterface != nil {
ch.DataRetention = dataRetentionInterface(New(ServerConnector(ch)))
}
if accountMigrationInterface != nil {
ch.AccountMigration = accountMigrationInterface(New(ServerConnector(ch)))
}
// Setup routes. // Setup routes.
pluginsRoute := ch.srv.Router.PathPrefix("/plugins/{plugin_id:[A-Za-z0-9\\_\\-\\.]+}").Subrouter() pluginsRoute := ch.srv.Router.PathPrefix("/plugins/{plugin_id:[A-Za-z0-9\\_\\-\\.]+}").Subrouter()
pluginsRoute.HandleFunc("", ch.ServePluginRequest) pluginsRoute.HandleFunc("", ch.ServePluginRequest)
@@ -75,6 +100,10 @@ func (ch *Channels) Start() error {
if err := ch.ensureAsymmetricSigningKey(); err != nil { if err := ch.ensureAsymmetricSigningKey(); err != nil {
return errors.Wrapf(err, "unable to ensure asymmetric signing key") return errors.Wrapf(err, "unable to ensure asymmetric signing key")
} }
if err := ch.ensurePostActionCookieSecret(); err != nil {
return errors.Wrapf(err, "unable to ensure PostAction cookie secret")
}
return nil return nil
} }

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

@@ -109,14 +109,14 @@ func (a *App) RemoveConfigListener(id string) {
// ensurePostActionCookieSecret ensures that the key for encrypting PostActionCookie exists // ensurePostActionCookieSecret ensures that the key for encrypting PostActionCookie exists
// and future calls to PostActionCookieSecret will always return a valid key, same on all // and future calls to PostActionCookieSecret will always return a valid key, same on all
// servers in the cluster // servers in the cluster
func (s *Server) ensurePostActionCookieSecret() error { func (ch *Channels) ensurePostActionCookieSecret() error {
if s.postActionCookieSecret != nil { if ch.postActionCookieSecret != nil {
return nil return nil
} }
var secret *model.SystemPostActionCookieSecret var secret *model.SystemPostActionCookieSecret
value, err := s.Store.System().GetByName(model.SystemPostActionCookieSecretKey) value, err := ch.srv.Store.System().GetByName(model.SystemPostActionCookieSecretKey)
if err == nil { if err == nil {
if err := json.Unmarshal([]byte(value.Value), &secret); err != nil { if err := json.Unmarshal([]byte(value.Value), &secret); err != nil {
return err return err
@@ -142,7 +142,7 @@ func (s *Server) ensurePostActionCookieSecret() error {
} }
system.Value = string(v) system.Value = string(v)
// If we were able to save the key, use it, otherwise log the error. // If we were able to save the key, use it, otherwise log the error.
if err = s.Store.System().Save(system); err != nil { if err = ch.srv.Store.System().Save(system); err != nil {
mlog.Warn("Failed to save PostActionCookieSecret", mlog.Err(err)) mlog.Warn("Failed to save PostActionCookieSecret", mlog.Err(err))
} else { } else {
secret = newSecret secret = newSecret
@@ -152,7 +152,7 @@ func (s *Server) ensurePostActionCookieSecret() error {
// If we weren't able to save a new key above, another server must have beat us to it. Get the // If we weren't able to save a new key above, another server must have beat us to it. Get the
// key from the database, and if that fails, error out. // key from the database, and if that fails, error out.
if secret == nil { if secret == nil {
value, err := s.Store.System().GetByName(model.SystemPostActionCookieSecretKey) value, err := ch.srv.Store.System().GetByName(model.SystemPostActionCookieSecretKey)
if err != nil { if err != nil {
return err return err
} }
@@ -162,7 +162,7 @@ func (s *Server) ensurePostActionCookieSecret() error {
} }
} }
s.postActionCookieSecret = secret.Secret ch.postActionCookieSecret = secret.Secret
return nil return nil
} }
@@ -294,12 +294,12 @@ func (a *App) AsymmetricSigningKey() *ecdsa.PrivateKey {
return a.ch.AsymmetricSigningKey() return a.ch.AsymmetricSigningKey()
} }
func (s *Server) PostActionCookieSecret() []byte { func (ch *Channels) PostActionCookieSecret() []byte {
return s.postActionCookieSecret return ch.postActionCookieSecret
} }
func (a *App) PostActionCookieSecret() []byte { func (a *App) PostActionCookieSecret() []byte {
return a.Srv().PostActionCookieSecret() return a.ch.PostActionCookieSecret()
} }
func (ch *Channels) regenerateClientConfig() { func (ch *Channels) regenerateClientConfig() {

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

@@ -12,9 +12,9 @@ import (
"github.com/mattermost/mattermost-server/v6/shared/mlog" "github.com/mattermost/mattermost-server/v6/shared/mlog"
) )
var accountMigrationInterface func(*Server) einterfaces.AccountMigrationInterface var accountMigrationInterface func(*App) einterfaces.AccountMigrationInterface
func RegisterAccountMigrationInterface(f func(*Server) einterfaces.AccountMigrationInterface) { func RegisterAccountMigrationInterface(f func(*App) einterfaces.AccountMigrationInterface) {
accountMigrationInterface = f accountMigrationInterface = f
} }
@@ -24,9 +24,9 @@ func RegisterClusterInterface(f func(*Server) einterfaces.ClusterInterface) {
clusterInterface = f clusterInterface = f
} }
var complianceInterface func(*Server) einterfaces.ComplianceInterface var complianceInterface func(*App) einterfaces.ComplianceInterface
func RegisterComplianceInterface(f func(*Server) einterfaces.ComplianceInterface) { func RegisterComplianceInterface(f func(*App) einterfaces.ComplianceInterface) {
complianceInterface = f complianceInterface = f
} }
@@ -36,9 +36,9 @@ func RegisterFixCRTChannelUnreadsJobInterface(f func(*Server) tjobs.FixCRTChanne
fixCRTChannelUnreadsJobInterface = f fixCRTChannelUnreadsJobInterface = f
} }
var dataRetentionInterface func(*Server) einterfaces.DataRetentionInterface var dataRetentionInterface func(*App) einterfaces.DataRetentionInterface
func RegisterDataRetentionInterface(f func(*Server) einterfaces.DataRetentionInterface) { func RegisterDataRetentionInterface(f func(*App) einterfaces.DataRetentionInterface) {
dataRetentionInterface = f dataRetentionInterface = f
} }
@@ -163,9 +163,9 @@ func RegisterLdapInterface(f func(*Server) einterfaces.LdapInterface) {
ldapInterface = f ldapInterface = f
} }
var messageExportInterface func(*Server) einterfaces.MessageExportInterface var messageExportInterface func(*App) einterfaces.MessageExportInterface
func RegisterMessageExportInterface(f func(*Server) einterfaces.MessageExportInterface) { func RegisterMessageExportInterface(f func(*App) einterfaces.MessageExportInterface) {
messageExportInterface = f messageExportInterface = f
} }
@@ -203,15 +203,7 @@ func (s *Server) initEnterprise() {
if metricsInterface != nil { if metricsInterface != nil {
s.Metrics = metricsInterface(s) s.Metrics = metricsInterface(s)
} }
if complianceInterface != nil {
s.Compliance = complianceInterface(s)
}
if messageExportInterface != nil {
s.MessageExport = messageExportInterface(s)
}
if dataRetentionInterface != nil {
s.DataRetention = dataRetentionInterface(s)
}
if clusterInterface != nil { if clusterInterface != nil {
s.Cluster = clusterInterface(s) s.Cluster = clusterInterface(s)
} }
@@ -223,15 +215,14 @@ func (s *Server) initEnterprise() {
s.LicenseManager = licenseInterface(s) s.LicenseManager = licenseInterface(s)
} }
if accountMigrationInterface != nil {
s.AccountMigration = accountMigrationInterface(s)
}
if ldapInterface != nil { if ldapInterface != nil {
s.Ldap = ldapInterface(s) s.Ldap = ldapInterface(s)
} }
if notificationInterface != nil { if notificationInterface != nil {
s.Notification = notificationInterface(s) s.Notification = notificationInterface(s)
} }
if samlInterfaceNew != nil { if samlInterfaceNew != nil {
mlog.Debug("Loading SAML2 library") mlog.Debug("Loading SAML2 library")
s.Saml = samlInterfaceNew(s) s.Saml = samlInterfaceNew(s)
@@ -244,6 +235,7 @@ func (s *Server) initEnterprise() {
} }
}) })
} }
if cloudInterface != nil { if cloudInterface != nil {
s.Cloud = cloudInterface(s) s.Cloud = cloudInterface(s)
} }

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

@@ -57,7 +57,7 @@ func TestSAMLSettings(t *testing.T) {
saml2.Mock.On("ConfigureSP").Return(nil) saml2.Mock.On("ConfigureSP").Return(nil)
saml2.Mock.On("GetMetadata").Return("samlTwo", nil) saml2.Mock.On("GetMetadata").Return("samlTwo", nil)
if tc.setNewInterface { if tc.setNewInterface {
RegisterNewSamlInterface(func(s *Server) einterfaces.SamlInterface { RegisterNewSamlInterface(func(_ *Server) einterfaces.SamlInterface {
return saml2 return saml2
}) })
} else { } else {

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

@@ -140,7 +140,6 @@ type Server struct {
searchLicenseListenerId string searchLicenseListenerId string
loggerLicenseListenerId string loggerLicenseListenerId string
configStore *config.Store configStore *config.Store
postActionCookieSecret []byte
telemetryService *telemetry.TelemetryService telemetryService *telemetry.TelemetryService
userService *users.UserService userService *users.UserService
@@ -163,17 +162,13 @@ type Server struct {
SearchEngine *searchengine.Broker SearchEngine *searchengine.Broker
AccountMigration einterfaces.AccountMigrationInterface
Cluster einterfaces.ClusterInterface Cluster einterfaces.ClusterInterface
Compliance einterfaces.ComplianceInterface
DataRetention einterfaces.DataRetentionInterface
Ldap einterfaces.LdapInterface
MessageExport einterfaces.MessageExportInterface
Cloud einterfaces.CloudInterface Cloud einterfaces.CloudInterface
Metrics einterfaces.MetricsInterface Metrics einterfaces.MetricsInterface
Notification einterfaces.NotificationInterface Notification einterfaces.NotificationInterface
Saml einterfaces.SamlInterface
LicenseManager einterfaces.LicenseInterface LicenseManager einterfaces.LicenseInterface
Saml einterfaces.SamlInterface
Ldap einterfaces.LdapInterface
CacheProvider cache.Provider CacheProvider cache.Provider
@@ -207,6 +202,9 @@ func NewServer(options ...Option) (*Server, error) {
goroutineExitSignal: make(chan struct{}, 1), goroutineExitSignal: make(chan struct{}, 1),
RootRouter: rootRouter, RootRouter: rootRouter,
LocalRouter: localRouter, LocalRouter: localRouter,
WebSocketRouter: &WebSocketRouter{
handlers: make(map[string]webSocketHandler),
},
licenseListeners: map[string]func(*model.License, *model.License){}, licenseListeners: map[string]func(*model.License, *model.License){},
hashSeed: maphash.MakeSeed(), hashSeed: maphash.MakeSeed(),
uploadLockMap: map[string]bool{}, uploadLockMap: map[string]bool{},
@@ -523,18 +521,6 @@ func NewServer(options ...Option) (*Server, error) {
s.Cluster.StartInterNodeCommunication() s.Cluster.StartInterNodeCommunication()
} }
if err = s.ensurePostActionCookieSecret(); err != nil {
return nil, errors.Wrapf(err, "unable to ensure PostAction cookie secret")
}
if err = s.ensureInstallationDate(); err != nil {
return nil, errors.Wrapf(err, "unable to ensure installation date")
}
if err = s.ensureFirstServerRunTimestamp(); err != nil {
return nil, errors.Wrapf(err, "unable to ensure first run timestamp")
}
// If configured with a subpath, redirect 404s at the root back into the subpath. // If configured with a subpath, redirect 404s at the root back into the subpath.
if subpath != "/" { if subpath != "/" {
s.RootRouter.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { s.RootRouter.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -543,35 +529,10 @@ func NewServer(options ...Option) (*Server, error) {
}) })
} }
s.WebSocketRouter = &WebSocketRouter{
handlers: make(map[string]webSocketHandler),
}
mailConfig := s.MailServiceConfig()
if nErr := mail.TestConnection(mailConfig); nErr != nil {
mlog.Error("Mail server connection test is failed", mlog.Err(nErr))
}
if _, err = url.ParseRequestURI(*s.Config().ServiceSettings.SiteURL); err != nil { if _, err = url.ParseRequestURI(*s.Config().ServiceSettings.SiteURL); err != nil {
mlog.Error("SiteURL must be set. Some features will operate incorrectly if the SiteURL is not set. See documentation for details: http://about.mattermost.com/default-site-url") mlog.Error("SiteURL must be set. Some features will operate incorrectly if the SiteURL is not set. See documentation for details: http://about.mattermost.com/default-site-url")
} }
backend, appErr := s.FileBackend()
if appErr != nil {
mlog.Error("Problem with file storage settings", mlog.Err(appErr))
} else {
nErr := backend.TestConnection()
if nErr != nil {
if _, ok := nErr.(*filestore.S3FileBackendNoBucketError); ok {
nErr = backend.(*filestore.S3FileBackend).MakeBucket()
}
if nErr != nil {
mlog.Error("Problem with file storage settings", mlog.Err(nErr))
}
}
}
// Start email batching because it's not like the other jobs // Start email batching because it's not like the other jobs
s.AddConfigListener(func(_, _ *model.Config) { s.AddConfigListener(func(_, _ *model.Config) {
s.EmailService.InitEmailBatching() s.EmailService.InitEmailBatching()
@@ -596,10 +557,6 @@ func NewServer(options ...Option) (*Server, error) {
mlog.Info("Printing current working", mlog.String("directory", pwd)) mlog.Info("Printing current working", mlog.String("directory", pwd))
mlog.Info("Loaded config", mlog.String("source", s.configStore.String())) mlog.Info("Loaded config", mlog.String("source", s.configStore.String()))
s.checkPushNotificationServerURL()
s.ReloadConfig()
license := s.License() license := s.License()
allowAdvancedLogging := license != nil && *license.Features.AdvancedLogging allowAdvancedLogging := license != nil && *license.Features.AdvancedLogging
@@ -624,10 +581,6 @@ func NewServer(options ...Option) (*Server, error) {
s.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableDeveloper = true }) s.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableDeveloper = true })
} }
if err = s.Store.Status().ResetAll(); err != nil {
mlog.Error("Error to reset the server status.", mlog.Err(err))
}
if s.startMetrics { if s.startMetrics {
s.SetupMetricsServer() s.SetupMetricsServer()
} }
@@ -663,11 +616,10 @@ func NewServer(options ...Option) (*Server, error) {
return s, nil return s, nil
} }
c := request.EmptyContext() s.AddConfigListener(func(old, new *model.Config) {
s.AddConfigListener(func(oldConfig *model.Config, newConfig *model.Config) {
appInstance := New(ServerConnector(s.Channels())) appInstance := New(ServerConnector(s.Channels()))
if *oldConfig.GuestAccountsSettings.Enable && !*newConfig.GuestAccountsSettings.Enable { if *old.GuestAccountsSettings.Enable && !*new.GuestAccountsSettings.Enable {
if appErr := appInstance.DeactivateGuests(c); appErr != nil { if appErr := appInstance.DeactivateGuests(request.EmptyContext()); appErr != nil {
mlog.Error("Unable to deactivate guest accounts", mlog.Err(appErr)) mlog.Error("Unable to deactivate guest accounts", mlog.Err(appErr))
} }
} }
@@ -676,7 +628,7 @@ func NewServer(options ...Option) (*Server, error) {
// Disable active guest accounts on first run if guest accounts are disabled // Disable active guest accounts on first run if guest accounts are disabled
if !*s.Config().GuestAccountsSettings.Enable { if !*s.Config().GuestAccountsSettings.Enable {
appInstance := New(ServerConnector(s.Channels())) appInstance := New(ServerConnector(s.Channels()))
if appErr := appInstance.DeactivateGuests(c); appErr != nil { if appErr := appInstance.DeactivateGuests(request.EmptyContext()); appErr != nil {
mlog.Error("Unable to deactivate guest accounts", mlog.Err(appErr)) mlog.Error("Unable to deactivate guest accounts", mlog.Err(appErr))
} }
} }
@@ -685,7 +637,7 @@ func NewServer(options ...Option) (*Server, error) {
s.Go(func() { s.Go(func() {
appInstance := New(ServerConnector(s.Channels())) appInstance := New(ServerConnector(s.Channels()))
s.runLicenseExpirationCheckJob() s.runLicenseExpirationCheckJob()
runCheckAdminSupportStatusJob(appInstance, c) runCheckAdminSupportStatusJob(appInstance, request.EmptyContext())
runDNDStatusExpireJob(appInstance) runDNDStatusExpireJob(appInstance)
}) })
s.runJobs() s.runJobs()
@@ -759,7 +711,7 @@ func (s *Server) runJobs() {
runCommandWebhookCleanupJob(s) runCommandWebhookCleanupJob(s)
}) })
if complianceI := s.Compliance; complianceI != nil { if complianceI := s.Channels().Compliance; complianceI != nil {
complianceI.StartComplianceDailyJob() complianceI.StartComplianceDailyJob()
} }
@@ -1208,6 +1160,40 @@ func (s *Server) Start() error {
} }
} }
if err := s.ensureInstallationDate(); err != nil {
return errors.Wrapf(err, "unable to ensure installation date")
}
if err := s.ensureFirstServerRunTimestamp(); err != nil {
return errors.Wrapf(err, "unable to ensure first run timestamp")
}
if err := s.Store.Status().ResetAll(); err != nil {
mlog.Error("Error to reset the server status.", mlog.Err(err))
}
if err := mail.TestConnection(s.MailServiceConfig()); err != nil {
mlog.Error("Mail server connection test is failed", mlog.Err(err))
}
backend, appErr := s.FileBackend()
if appErr != nil {
mlog.Error("Problem with file storage settings", mlog.Err(appErr))
} else {
err := backend.TestConnection()
if err != nil {
if _, ok := err.(*filestore.S3FileBackendNoBucketError); ok {
err = backend.(*filestore.S3FileBackend).MakeBucket()
}
if err != nil {
mlog.Error("Problem with file storage settings", mlog.Err(err))
}
}
}
s.checkPushNotificationServerURL()
s.ReloadConfig()
mlog.Info("Starting Server...") mlog.Info("Starting Server...")
var handler http.Handler = s.RootRouter var handler http.Handler = s.RootRouter
@@ -2178,7 +2164,7 @@ func (a *App) generateSupportPacketYaml() (*model.FileData, string) {
} }
// Here we are getting information regarding LDAP // Here we are getting information regarding LDAP
ldapInterface := a.Srv().Ldap ldapInterface := a.ch.srv.Ldap
var vendorName, vendorVersion string var vendorName, vendorVersion string
if ldapInterface != nil { if ldapInterface != nil {
vendorName, vendorVersion = ldapInterface.GetVendorNameAndVendorVersion() vendorName, vendorVersion = ldapInterface.GetVendorNameAndVendorVersion()

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

@@ -182,11 +182,15 @@ func TestStartServerNoS3Bucket(t *testing.T) {
AmazonS3PathPrefix: model.NewString(""), AmazonS3PathPrefix: model.NewString(""),
AmazonS3SSL: model.NewBool(false), AmazonS3SSL: model.NewBool(false),
} }
*cfg.ServiceSettings.ListenAddress = ":0"
}) })
return nil return nil
}) })
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, s.Start())
defer s.Shutdown()
// ensure that a new bucket was created // ensure that a new bucket was created
backend, appErr := s.FileBackend() backend, appErr := s.FileBackend()
require.Nil(t, appErr) require.Nil(t, appErr)