* Move plugins under Channels

We move all plugin related fields under *Channels.
This essentially migrates several methods from being under
*Server to under *Channels.

We also move the plugin startup and shutdown code
to be under Channels.Start and Channels.Shutdown.

While here, we remove the getPluginPublicKeyFiles
method which was a one-line method which uselessly
returned an error.

Lastly, we fix the product initialization order which
was incorrect previously. Products are dependent on
the main server.

So startup should be products -> server.
And shutdown should be server -> products.

```release-note
NONE
```

* Added app layer

```release-note
NONE
```

* Incorporate suggestions

```release-note
NONE
```
Этот коммит содержится в:
Agniva De Sarker
2021-11-08 11:57:22 +05:30
коммит произвёл GitHub
родитель 24248dc764
Коммит 25257d6ef6
14 изменённых файлов: 288 добавлений и 290 удалений

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

@@ -133,6 +133,9 @@ func (a *App) ImageProxy() *imageproxy.ImageProxy {
func (a *App) Timezones() *timezones.Timezones { func (a *App) Timezones() *timezones.Timezones {
return a.ch.srv.timezones return a.ch.srv.timezones
} }
func (a *App) License() *model.License {
return a.Srv().License()
}
func (a *App) DBHealthCheckWrite() error { func (a *App) DBHealthCheckWrite() error {
currentTime := strconv.FormatInt(time.Now().Unix(), 10) currentTime := strconv.FormatInt(time.Now().Unix(), 10)

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

@@ -177,8 +177,6 @@ type AppIface interface {
// GetMarketplacePlugins returns a list of plugins from the marketplace-server, // GetMarketplacePlugins returns a list of plugins from the marketplace-server,
// and plugins that are installed locally. // and plugins that are installed locally.
GetMarketplacePlugins(filter *model.MarketplacePluginFilter) ([]*model.MarketplacePlugin, *model.AppError) GetMarketplacePlugins(filter *model.MarketplacePluginFilter) ([]*model.MarketplacePlugin, *model.AppError)
// GetPluginPublicKeyFiles returns all public keys listed in the config.
GetPluginPublicKeyFiles() ([]string, *model.AppError)
// GetPluginStatus returns the status for a plugin installed on this server. // GetPluginStatus returns the status for a plugin installed on this server.
GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError)
// GetPluginStatuses returns the status for plugins installed on this server. // GetPluginStatuses returns the status for plugins installed on this server.
@@ -828,6 +826,7 @@ type AppIface interface {
Ldap() einterfaces.LdapInterface Ldap() einterfaces.LdapInterface
LeaveChannel(c *request.Context, channelID string, userID string) *model.AppError LeaveChannel(c *request.Context, channelID string, userID string) *model.AppError
LeaveTeam(c *request.Context, team *model.Team, user *model.User, requestorId string) *model.AppError LeaveTeam(c *request.Context, team *model.Team, user *model.User, requestorId string) *model.AppError
License() *model.License
LimitedClientConfig() map[string]string LimitedClientConfig() map[string]string
ListAllCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError) ListAllCommands(teamID string, T i18n.TranslateFunc) ([]*model.Command, *model.AppError)
ListDirectory(path string) ([]string, *model.AppError) ListDirectory(path string) ([]string, *model.AppError)

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

@@ -4,9 +4,12 @@
package app package app
import ( import (
"sync"
"sync/atomic" "sync/atomic"
"github.com/mattermost/mattermost-server/v6/app/request"
"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/services/imageproxy" "github.com/mattermost/mattermost-server/v6/services/imageproxy"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@@ -15,6 +18,10 @@ import (
type Channels struct { type Channels struct {
srv *Server srv *Server
pluginsEnvironment *plugin.Environment
pluginConfigListenerID string
pluginsLock sync.RWMutex
imageProxy *imageproxy.ImageProxy imageProxy *imageproxy.ImageProxy
asymmetricSigningKey atomic.Value asymmetricSigningKey atomic.Value
@@ -44,12 +51,33 @@ func NewChannels(s *Server) (*Channels, error) {
} }
func (ch *Channels) Start() error { func (ch *Channels) Start() error {
// Start plugins
ctx := request.EmptyContext()
ch.initPlugins(ctx, *ch.srv.Config().PluginSettings.Directory, *ch.srv.Config().PluginSettings.ClientDirectory)
ch.AddConfigListener(func(prevCfg, cfg *model.Config) {
if *cfg.PluginSettings.Enable {
ch.initPlugins(ctx, *cfg.PluginSettings.Directory, *ch.srv.Config().PluginSettings.ClientDirectory)
} else {
ch.ShutDownPlugins()
}
})
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")
} }
return nil return nil
} }
func (*Channels) Stop() error { func (ch *Channels) Stop() error {
ch.ShutDownPlugins()
return nil return nil
} }
func (ch *Channels) AddConfigListener(listener func(*model.Config, *model.Config)) string {
return ch.srv.AddConfigListener(listener)
}
func (ch *Channels) RemoveConfigListener(id string) {
ch.srv.RemoveConfigListener(id)
}

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

@@ -17,7 +17,7 @@ func (s *Server) clusterInstallPluginHandler(msg *model.ClusterMessage) {
if jsonErr := json.Unmarshal(msg.Data, &data); jsonErr != nil { if jsonErr := json.Unmarshal(msg.Data, &data); jsonErr != nil {
mlog.Warn("Failed to decode from JSON", mlog.Err(jsonErr)) mlog.Warn("Failed to decode from JSON", mlog.Err(jsonErr))
} }
s.installPluginFromData(data) s.Channels().installPluginFromData(data)
} }
func (s *Server) clusterRemovePluginHandler(msg *model.ClusterMessage) { func (s *Server) clusterRemovePluginHandler(msg *model.ClusterMessage) {
@@ -25,11 +25,11 @@ func (s *Server) clusterRemovePluginHandler(msg *model.ClusterMessage) {
if jsonErr := json.Unmarshal(msg.Data, &data); jsonErr != nil { if jsonErr := json.Unmarshal(msg.Data, &data); jsonErr != nil {
mlog.Warn("Failed to decode from JSON", mlog.Err(jsonErr)) mlog.Warn("Failed to decode from JSON", mlog.Err(jsonErr))
} }
s.removePluginFromData(data) s.Channels().removePluginFromData(data)
} }
func (s *Server) clusterPluginEventHandler(msg *model.ClusterMessage) { func (s *Server) clusterPluginEventHandler(msg *model.ClusterMessage) {
env := s.GetPluginsEnvironment() env := s.Channels().GetPluginsEnvironment()
if env == nil { if env == nil {
return return
} }

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

@@ -7228,28 +7228,6 @@ func (a *OpenTracingAppLayer) GetPluginKey(pluginID string, key string) ([]byte,
return resultVar0, resultVar1 return resultVar0, resultVar1
} }
func (a *OpenTracingAppLayer) GetPluginPublicKeyFiles() ([]string, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetPluginPublicKeyFiles")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.GetPluginPublicKeyFiles()
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) { func (a *OpenTracingAppLayer) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetPluginStatus") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetPluginStatus")
@@ -11034,6 +11012,23 @@ func (a *OpenTracingAppLayer) LeaveTeam(c *request.Context, team *model.Team, us
return resultVar0 return resultVar0
} }
func (a *OpenTracingAppLayer) License() *model.License {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.License")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.License()
return resultVar0
}
func (a *OpenTracingAppLayer) LimitedClientConfig() map[string]string { func (a *OpenTracingAppLayer) LimitedClientConfig() map[string]string {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.LimitedClientConfig") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.LimitedClientConfig")

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

@@ -42,15 +42,15 @@ 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 (s *Server) GetPluginsEnvironment() *plugin.Environment { func (ch *Channels) GetPluginsEnvironment() *plugin.Environment {
if !*s.Config().PluginSettings.Enable { if !*ch.srv.Config().PluginSettings.Enable {
return nil return nil
} }
s.PluginsLock.RLock() ch.pluginsLock.RLock()
defer s.PluginsLock.RUnlock() defer ch.pluginsLock.RUnlock()
return s.PluginsEnvironment return ch.pluginsEnvironment
} }
// GetPluginsEnvironment returns the plugin environment for use if plugins are enabled and // GetPluginsEnvironment returns the plugin environment for use if plugins are enabled and
@@ -59,36 +59,36 @@ func (s *Server) GetPluginsEnvironment() *plugin.Environment {
// 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 (a *App) GetPluginsEnvironment() *plugin.Environment { func (a *App) GetPluginsEnvironment() *plugin.Environment {
return a.Srv().GetPluginsEnvironment() return a.ch.GetPluginsEnvironment()
} }
func (a *App) SetPluginsEnvironment(pluginsEnvironment *plugin.Environment) { func (a *App) SetPluginsEnvironment(pluginsEnvironment *plugin.Environment) {
a.Srv().PluginsLock.Lock() a.ch.pluginsLock.Lock()
defer a.Srv().PluginsLock.Unlock() defer a.ch.pluginsLock.Unlock()
a.Srv().PluginsEnvironment = pluginsEnvironment a.ch.pluginsEnvironment = pluginsEnvironment
} }
func (a *App) SyncPluginsActiveState() { func (a *App) SyncPluginsActiveState() {
a.Srv().syncPluginsActiveState() a.ch.syncPluginsActiveState()
} }
func (s *Server) syncPluginsActiveState() { func (ch *Channels) syncPluginsActiveState() {
// Acquiring lock manually, as plugins might be disabled. See GetPluginsEnvironment. // Acquiring lock manually, as plugins might be disabled. See GetPluginsEnvironment.
s.PluginsLock.RLock() ch.pluginsLock.RLock()
pluginsEnvironment := s.PluginsEnvironment pluginsEnvironment := ch.pluginsEnvironment
s.PluginsLock.RUnlock() ch.pluginsLock.RUnlock()
if pluginsEnvironment == nil { if pluginsEnvironment == nil {
return return
} }
config := s.Config().PluginSettings config := ch.srv.Config().PluginSettings
if *config.Enable { if *config.Enable {
availablePlugins, err := pluginsEnvironment.Available() availablePlugins, err := pluginsEnvironment.Available()
if err != nil { if err != nil {
s.Log.Error("Unable to get available plugins", mlog.Err(err)) ch.srv.Log.Error("Unable to get available plugins", mlog.Err(err))
return return
} }
@@ -104,7 +104,7 @@ func (s *Server) 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 !s.Config().FeatureFlags.AppsEnabled { if !ch.srv.Config().FeatureFlags.AppsEnabled {
pluginEnabled = false pluginEnabled = false
} }
} }
@@ -129,7 +129,7 @@ func (s *Server) syncPluginsActiveState() {
if deactivated && plugin.Manifest.HasClient() { if deactivated && plugin.Manifest.HasClient() {
message := model.NewWebSocketEvent(model.WebsocketEventPluginDisabled, "", "", "", nil) message := model.NewWebSocketEvent(model.WebsocketEventPluginDisabled, "", "", "", nil)
message.Add("manifest", plugin.Manifest.ClientManifest()) message.Add("manifest", plugin.Manifest.ClientManifest())
s.Publish(message) ch.srv.Publish(message)
} }
}(plugin) }(plugin)
} }
@@ -143,14 +143,14 @@ func (s *Server) syncPluginsActiveState() {
pluginID := plugin.Manifest.Id pluginID := plugin.Manifest.Id
updatedManifest, activated, err := pluginsEnvironment.Activate(pluginID) updatedManifest, activated, err := pluginsEnvironment.Activate(pluginID)
if err != nil { if err != nil {
plugin.WrapLogger(s.Log).Error("Unable to activate plugin", mlog.Err(err)) plugin.WrapLogger(ch.srv.Log).Error("Unable to activate plugin", mlog.Err(err))
return return
} }
if activated { if activated {
// Notify all cluster clients if ready // Notify all cluster clients if ready
if err := s.notifyPluginEnabled(updatedManifest); err != nil { if err := ch.notifyPluginEnabled(updatedManifest); err != nil {
s.Log.Error("Failed to notify cluster on plugin enable", mlog.Err(err)) ch.srv.Log.Error("Failed to notify cluster on plugin enable", mlog.Err(err))
} }
} }
}(plugin) }(plugin)
@@ -160,7 +160,7 @@ func (s *Server) syncPluginsActiveState() {
pluginsEnvironment.Shutdown() pluginsEnvironment.Shutdown()
} }
if err := s.notifyPluginStatusesChanged(); err != nil { if err := ch.notifyPluginStatusesChanged(); err != nil {
mlog.Warn("failed to notify plugin status changed", mlog.Err(err)) mlog.Warn("failed to notify plugin status changed", mlog.Err(err))
} }
} }
@@ -170,21 +170,21 @@ func (a *App) NewPluginAPI(c *request.Context, manifest *model.Manifest) plugin.
} }
func (a *App) InitPlugins(c *request.Context, pluginDir, webappPluginDir string) { func (a *App) InitPlugins(c *request.Context, pluginDir, webappPluginDir string) {
a.Srv().initPlugins(c, pluginDir, webappPluginDir) a.ch.initPlugins(c, pluginDir, webappPluginDir)
} }
func (s *Server) initPlugins(c *request.Context, pluginDir, webappPluginDir string) { func (ch *Channels) initPlugins(c *request.Context, pluginDir, webappPluginDir string) {
// Acquiring lock manually, as plugins might be disabled. See GetPluginsEnvironment. // Acquiring lock manually, as plugins might be disabled. See GetPluginsEnvironment.
s.PluginsLock.RLock() ch.pluginsLock.RLock()
pluginsEnvironment := s.PluginsEnvironment pluginsEnvironment := ch.pluginsEnvironment
s.PluginsLock.RUnlock() ch.pluginsLock.RUnlock()
if pluginsEnvironment != nil || !*s.Config().PluginSettings.Enable { if pluginsEnvironment != nil || !*ch.srv.Config().PluginSettings.Enable {
s.syncPluginsActiveState() ch.syncPluginsActiveState()
pluginsEnvironment.TogglePluginHealthCheckJob(*s.Config().PluginSettings.EnableHealthCheck) pluginsEnvironment.TogglePluginHealthCheckJob(*ch.srv.Config().PluginSettings.EnableHealthCheck)
return return
} }
s.Log.Info("Starting up plugins") ch.srv.Log.Info("Starting up plugins")
if err := os.Mkdir(pluginDir, 0744); err != nil && !os.IsExist(err) { if err := os.Mkdir(pluginDir, 0744); err != nil && !os.IsExist(err) {
mlog.Error("Failed to start up plugins", mlog.Err(err)) mlog.Error("Failed to start up plugins", mlog.Err(err))
@@ -197,70 +197,70 @@ func (s *Server) initPlugins(c *request.Context, pluginDir, webappPluginDir stri
} }
newAPIFunc := func(manifest *model.Manifest) plugin.API { newAPIFunc := func(manifest *model.Manifest) plugin.API {
return New(ServerConnector(s.Channels())).NewPluginAPI(c, manifest) return New(ServerConnector(ch)).NewPluginAPI(c, manifest)
} }
env, err := plugin.NewEnvironment(newAPIFunc, NewDriverImpl(s), pluginDir, webappPluginDir, s.Log, s.Metrics) env, err := plugin.NewEnvironment(newAPIFunc, NewDriverImpl(ch.srv), pluginDir, webappPluginDir, ch.srv.Log, ch.srv.Metrics)
if err != nil { if err != nil {
mlog.Error("Failed to start up plugins", mlog.Err(err)) mlog.Error("Failed to start up plugins", mlog.Err(err))
return return
} }
s.PluginsLock.Lock() ch.pluginsLock.Lock()
s.PluginsEnvironment = env ch.pluginsEnvironment = env
s.PluginsLock.Unlock() ch.pluginsLock.Unlock()
s.PluginsEnvironment.TogglePluginHealthCheckJob(*s.Config().PluginSettings.EnableHealthCheck) ch.pluginsEnvironment.TogglePluginHealthCheckJob(*ch.srv.Config().PluginSettings.EnableHealthCheck)
if err := s.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))
} }
plugins := s.processPrepackagedPlugins(prepackagedPluginsDir) plugins := ch.processPrepackagedPlugins(prepackagedPluginsDir)
pluginsEnvironment = s.GetPluginsEnvironment() pluginsEnvironment = ch.GetPluginsEnvironment()
if pluginsEnvironment == nil { if pluginsEnvironment == nil {
mlog.Info("Plugins environment not found, server is likely shutting down") mlog.Info("Plugins environment not found, server is likely shutting down")
return return
} }
pluginsEnvironment.SetPrepackagedPlugins(plugins) pluginsEnvironment.SetPrepackagedPlugins(plugins)
s.installFeatureFlagPlugins() ch.installFeatureFlagPlugins()
// Sync plugin active state when config changes. Also notify plugins. // Sync plugin active state when config changes. Also notify plugins.
s.PluginsLock.Lock() ch.pluginsLock.Lock()
s.RemoveConfigListener(s.PluginConfigListenerId) ch.RemoveConfigListener(ch.pluginConfigListenerID)
s.PluginConfigListenerId = s.AddConfigListener(func(old, new *model.Config) { ch.pluginConfigListenerID = ch.AddConfigListener(func(old, new *model.Config) {
// If plugin status remains unchanged, only then run this. // If plugin status remains unchanged, only then run this.
// Because (*App).InitPlugins is already run as a config change hook. // Because (*App).InitPlugins is already run as a config change hook.
if *old.PluginSettings.Enable == *new.PluginSettings.Enable { if *old.PluginSettings.Enable == *new.PluginSettings.Enable {
s.installFeatureFlagPlugins() ch.installFeatureFlagPlugins()
s.syncPluginsActiveState() ch.syncPluginsActiveState()
} }
if pluginsEnvironment := s.GetPluginsEnvironment(); pluginsEnvironment != nil { if pluginsEnvironment := ch.GetPluginsEnvironment(); pluginsEnvironment != nil {
pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool {
if err := hooks.OnConfigurationChange(); err != nil { if err := hooks.OnConfigurationChange(); err != nil {
s.Log.Error("Plugin OnConfigurationChange hook failed", mlog.Err(err)) ch.srv.Log.Error("Plugin OnConfigurationChange hook failed", mlog.Err(err))
} }
return true return true
}, plugin.OnConfigurationChangeID) }, plugin.OnConfigurationChangeID)
} }
}) })
s.PluginsLock.Unlock() ch.pluginsLock.Unlock()
s.syncPluginsActiveState() ch.syncPluginsActiveState()
} }
// SyncPlugins synchronizes the plugins installed locally // SyncPlugins synchronizes the plugins installed locally
// with the plugin bundles available in the file store. // with the plugin bundles available in the file store.
func (a *App) SyncPlugins() *model.AppError { func (a *App) SyncPlugins() *model.AppError {
return a.Srv().syncPlugins() return a.ch.syncPlugins()
} }
// SyncPlugins synchronizes the plugins installed locally // SyncPlugins synchronizes the plugins installed locally
// with the plugin bundles available in the file store. // with the plugin bundles available in the file store.
func (s *Server) syncPlugins() *model.AppError { func (ch *Channels) syncPlugins() *model.AppError {
mlog.Info("Syncing plugins from the file store") mlog.Info("Syncing plugins from the file store")
pluginsEnvironment := s.GetPluginsEnvironment() pluginsEnvironment := ch.GetPluginsEnvironment()
if pluginsEnvironment == nil { if pluginsEnvironment == nil {
return model.NewAppError("SyncPlugins", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) return model.NewAppError("SyncPlugins", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
} }
@@ -276,14 +276,14 @@ func (s *Server) 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(*s.Config().PluginSettings.Directory, pluginID, managedPluginFileName)) _, err := os.Stat(filepath.Join(*ch.srv.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 {
mlog.Error("Skipping sync for plugin after failure to check if managed", mlog.String("plugin_id", pluginID), mlog.Err(err)) mlog.Error("Skipping sync for plugin after failure to check if managed", mlog.String("plugin_id", pluginID), mlog.Err(err))
} else { } else {
mlog.Debug("Removing local installation of managed plugin before sync", mlog.String("plugin_id", pluginID)) mlog.Debug("Removing local installation of managed plugin before sync", mlog.String("plugin_id", pluginID))
if err := s.removePluginLocally(pluginID); err != nil { if err := ch.removePluginLocally(pluginID); err != nil {
mlog.Error("Failed to remove local installation of managed plugin before sync", mlog.String("plugin_id", pluginID), mlog.Err(err)) mlog.Error("Failed to remove local installation of managed plugin before sync", mlog.String("plugin_id", pluginID), mlog.Err(err))
} }
} }
@@ -292,7 +292,7 @@ func (s *Server) syncPlugins() *model.AppError {
wg.Wait() wg.Wait()
// Install plugins from the file store. // Install plugins from the file store.
pluginSignaturePathMap, appErr := s.getPluginsFromFolder() pluginSignaturePathMap, appErr := ch.getPluginsFromFolder()
if appErr != nil { if appErr != nil {
return appErr return appErr
} }
@@ -301,7 +301,7 @@ func (s *Server) syncPlugins() *model.AppError {
wg.Add(1) wg.Add(1)
go func(plugin *pluginSignaturePath) { go func(plugin *pluginSignaturePath) {
defer wg.Done() defer wg.Done()
reader, appErr := s.fileReader(plugin.path) reader, appErr := ch.srv.fileReader(plugin.path)
if appErr != nil { if appErr != nil {
mlog.Error("Failed to open plugin bundle from file store.", mlog.String("bundle", plugin.path), mlog.Err(appErr)) mlog.Error("Failed to open plugin bundle from file store.", mlog.String("bundle", plugin.path), mlog.Err(appErr))
return return
@@ -309,8 +309,8 @@ func (s *Server) syncPlugins() *model.AppError {
defer reader.Close() defer reader.Close()
var signature filestore.ReadCloseSeeker var signature filestore.ReadCloseSeeker
if *s.Config().PluginSettings.RequirePluginSignature { if *ch.srv.Config().PluginSettings.RequirePluginSignature {
signature, appErr = s.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))
return return
@@ -319,7 +319,7 @@ func (s *Server) syncPlugins() *model.AppError {
} }
mlog.Info("Syncing plugin from file store", mlog.String("bundle", plugin.path)) mlog.Info("Syncing plugin from file store", mlog.String("bundle", plugin.path))
if _, err := s.installPluginLocally(reader, signature, installPluginLocallyAlways); err != nil { if _, err := ch.installPluginLocally(reader, signature, installPluginLocallyAlways); err != nil {
mlog.Error("Failed to sync plugin from file store", mlog.String("bundle", plugin.path), mlog.Err(err)) mlog.Error("Failed to sync plugin from file store", mlog.String("bundle", plugin.path), mlog.Err(err))
} }
}(plugin) }(plugin)
@@ -329,11 +329,11 @@ func (s *Server) syncPlugins() *model.AppError {
return nil return nil
} }
func (s *Server) ShutDownPlugins() { func (ch *Channels) ShutDownPlugins() {
// Acquiring lock manually, as plugins might be disabled. See GetPluginsEnvironment. // Acquiring lock manually, as plugins might be disabled. See GetPluginsEnvironment.
s.PluginsLock.RLock() ch.pluginsLock.RLock()
pluginsEnvironment := s.PluginsEnvironment pluginsEnvironment := ch.pluginsEnvironment
s.PluginsLock.RUnlock() ch.pluginsLock.RUnlock()
if pluginsEnvironment == nil { if pluginsEnvironment == nil {
return return
} }
@@ -342,14 +342,14 @@ func (s *Server) ShutDownPlugins() {
pluginsEnvironment.Shutdown() pluginsEnvironment.Shutdown()
s.RemoveConfigListener(s.PluginConfigListenerId) ch.RemoveConfigListener(ch.pluginConfigListenerID)
s.PluginConfigListenerId = "" ch.pluginConfigListenerID = ""
// Acquiring lock manually before cleaning up PluginsEnvironment. // Acquiring lock manually before cleaning up PluginsEnvironment.
s.PluginsLock.Lock() ch.pluginsLock.Lock()
defer s.PluginsLock.Unlock() defer ch.pluginsLock.Unlock()
if s.PluginsEnvironment == pluginsEnvironment { if ch.pluginsEnvironment == pluginsEnvironment {
s.PluginsEnvironment = nil ch.pluginsEnvironment = nil
} else { } else {
mlog.Warn("Another PluginsEnvironment detected while shutting down plugins.") mlog.Warn("Another PluginsEnvironment detected while shutting down plugins.")
} }
@@ -375,11 +375,11 @@ func (a *App) GetActivePluginManifests() ([]*model.Manifest, *model.AppError) {
// activation if inactive anywhere in the cluster. // activation if inactive anywhere in the cluster.
// Notifies cluster peers through config change. // Notifies cluster peers through config change.
func (a *App) EnablePlugin(id string) *model.AppError { func (a *App) EnablePlugin(id string) *model.AppError {
return a.Srv().enablePlugin(id) return a.ch.enablePlugin(id)
} }
func (s *Server) enablePlugin(id string) *model.AppError { func (ch *Channels) enablePlugin(id string) *model.AppError {
pluginsEnvironment := s.GetPluginsEnvironment() pluginsEnvironment := ch.GetPluginsEnvironment()
if pluginsEnvironment == nil { if pluginsEnvironment == nil {
return model.NewAppError("EnablePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) return model.NewAppError("EnablePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
} }
@@ -403,12 +403,12 @@ func (s *Server) 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)
} }
s.UpdateConfig(func(cfg *model.Config) { ch.srv.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 := s.SaveConfig(s.Config(), true); err != nil { if _, _, err := ch.srv.SaveConfig(ch.srv.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)
} }
@@ -421,11 +421,11 @@ func (s *Server) enablePlugin(id string) *model.AppError {
// DisablePlugin will set the config for an installed plugin to disabled, triggering deactivation if active. // DisablePlugin will set the config for an installed plugin to disabled, triggering deactivation if active.
// Notifies cluster peers through config change. // Notifies cluster peers through config change.
func (a *App) DisablePlugin(id string) *model.AppError { func (a *App) DisablePlugin(id string) *model.AppError {
return a.Srv().disablePlugin(id) return a.ch.disablePlugin(id)
} }
func (s *Server) disablePlugin(id string) *model.AppError { func (ch *Channels) disablePlugin(id string) *model.AppError {
pluginsEnvironment := s.GetPluginsEnvironment() pluginsEnvironment := ch.GetPluginsEnvironment()
if pluginsEnvironment == nil { if pluginsEnvironment == nil {
return model.NewAppError("DisablePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) return model.NewAppError("DisablePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
} }
@@ -449,13 +449,13 @@ func (s *Server) 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)
} }
s.UpdateConfig(func(cfg *model.Config) { ch.srv.UpdateConfig(func(cfg *model.Config) {
cfg.PluginSettings.PluginStates[id] = &model.PluginState{Enable: false} cfg.PluginSettings.PluginStates[id] = &model.PluginState{Enable: false}
}) })
s.unregisterPluginCommands(id) ch.srv.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 := s.SaveConfig(s.Config(), true); err != nil { if _, _, err := ch.srv.SaveConfig(ch.srv.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)
} }
@@ -540,8 +540,8 @@ func (a *App) GetMarketplacePlugins(filter *model.MarketplacePluginFilter) ([]*m
} }
// getPrepackagedPlugin returns a pre-packaged plugin. // getPrepackagedPlugin returns a pre-packaged plugin.
func (s *Server) getPrepackagedPlugin(pluginID, version string) (*plugin.PrepackagedPlugin, *model.AppError) { func (ch *Channels) getPrepackagedPlugin(pluginID, version string) (*plugin.PrepackagedPlugin, *model.AppError) {
pluginsEnvironment := s.GetPluginsEnvironment() pluginsEnvironment := ch.GetPluginsEnvironment()
if pluginsEnvironment == nil { if pluginsEnvironment == nil {
return nil, model.NewAppError("getPrepackagedPlugin", "app.plugin.config.app_error", nil, "plugin environment is nil", http.StatusInternalServerError) return nil, model.NewAppError("getPrepackagedPlugin", "app.plugin.config.app_error", nil, "plugin environment is nil", http.StatusInternalServerError)
} }
@@ -557,16 +557,16 @@ func (s *Server) getPrepackagedPlugin(pluginID, version string) (*plugin.Prepack
} }
// getRemoteMarketplacePlugin returns plugin from marketplace-server. // getRemoteMarketplacePlugin returns plugin from marketplace-server.
func (s *Server) 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(
*s.Config().PluginSettings.MarketplaceURL, *ch.srv.Config().PluginSettings.MarketplaceURL,
s.HTTPService(), ch.srv.HTTPService(),
) )
if err != nil { if err != nil {
return nil, model.NewAppError("GetMarketplacePlugin", "app.plugin.marketplace_client.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, model.NewAppError("GetMarketplacePlugin", "app.plugin.marketplace_client.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
filter := s.getBaseMarketplaceFilter() filter := ch.getBaseMarketplaceFilter()
filter.PluginId = pluginID filter.PluginId = pluginID
filter.ReturnAllVersions = true filter.ReturnAllVersions = true
@@ -717,15 +717,15 @@ func (a *App) mergeLocalPlugins(remoteMarketplacePlugins map[string]*model.Marke
} }
func (a *App) getBaseMarketplaceFilter() *model.MarketplacePluginFilter { func (a *App) getBaseMarketplaceFilter() *model.MarketplacePluginFilter {
return a.Srv().getBaseMarketplaceFilter() return a.ch.getBaseMarketplaceFilter()
} }
func (s *Server) getBaseMarketplaceFilter() *model.MarketplacePluginFilter { func (ch *Channels) getBaseMarketplaceFilter() *model.MarketplacePluginFilter {
filter := &model.MarketplacePluginFilter{ filter := &model.MarketplacePluginFilter{
ServerVersion: model.CurrentVersion, ServerVersion: model.CurrentVersion,
} }
license := s.License() license := ch.srv.License()
if license != nil && license.HasEnterpriseMarketplacePlugins() { if license != nil && license.HasEnterpriseMarketplacePlugins() {
filter.EnterprisePlugins = true filter.EnterprisePlugins = true
} }
@@ -772,8 +772,8 @@ func pluginMatchesFilter(manifest *model.Manifest, filter string) bool {
// it will notify all connected websocket clients (across all peers) to trigger the (re-)installation. // it will notify all connected websocket clients (across all peers) to trigger the (re-)installation.
// There is a small chance that this never occurs, because the last server to finish installing dies before it can announce. // There is a small chance that this never occurs, because the last server to finish installing dies before it can announce.
// There is also a chance that multiple servers notify, but the webapp handles this idempotently. // There is also a chance that multiple servers notify, but the webapp handles this idempotently.
func (s *Server) notifyPluginEnabled(manifest *model.Manifest) error { func (ch *Channels) notifyPluginEnabled(manifest *model.Manifest) error {
pluginsEnvironment := s.GetPluginsEnvironment() pluginsEnvironment := ch.GetPluginsEnvironment()
if pluginsEnvironment == nil { if pluginsEnvironment == nil {
return errors.New("pluginsEnvironment is nil") return errors.New("pluginsEnvironment is nil")
} }
@@ -783,15 +783,15 @@ func (s *Server) notifyPluginEnabled(manifest *model.Manifest) error {
var statuses model.PluginStatuses var statuses model.PluginStatuses
if s.Cluster != nil { if ch.srv.Cluster != nil {
var err *model.AppError var err *model.AppError
statuses, err = s.Cluster.GetPluginStatuses() statuses, err = ch.srv.Cluster.GetPluginStatuses()
if err != nil { if err != nil {
return err return err
} }
} }
localStatus, err := s.GetPluginStatus(manifest.Id) localStatus, err := ch.GetPluginStatus(manifest.Id)
if err != nil { if err != nil {
return err return err
} }
@@ -811,26 +811,26 @@ func (s *Server) notifyPluginEnabled(manifest *model.Manifest) error {
// Notify all cluster peer clients. // Notify all cluster peer clients.
message := model.NewWebSocketEvent(model.WebsocketEventPluginEnabled, "", "", "", nil) message := model.NewWebSocketEvent(model.WebsocketEventPluginEnabled, "", "", "", nil)
message.Add("manifest", manifest.ClientManifest()) message.Add("manifest", manifest.ClientManifest())
s.Publish(message) ch.srv.Publish(message)
return nil return nil
} }
func (s *Server) getPluginsFromFolder() (map[string]*pluginSignaturePath, *model.AppError) { func (ch *Channels) getPluginsFromFolder() (map[string]*pluginSignaturePath, *model.AppError) {
fileStorePaths, appErr := s.listDirectory(fileStorePluginFolder) fileStorePaths, appErr := ch.srv.listDirectory(fileStorePluginFolder)
if appErr != nil { if appErr != nil {
return nil, model.NewAppError("getPluginsFromDir", "app.plugin.sync.list_filestore.app_error", nil, appErr.Error(), http.StatusInternalServerError) return nil, model.NewAppError("getPluginsFromDir", "app.plugin.sync.list_filestore.app_error", nil, appErr.Error(), http.StatusInternalServerError)
} }
return s.getPluginsFromFilePaths(fileStorePaths), nil return ch.getPluginsFromFilePaths(fileStorePaths), nil
} }
func (s *Server) getPluginsFromFilePaths(fileStorePaths []string) map[string]*pluginSignaturePath { func (ch *Channels) getPluginsFromFilePaths(fileStorePaths []string) map[string]*pluginSignaturePath {
pluginSignaturePathMap := make(map[string]*pluginSignaturePath) pluginSignaturePathMap := make(map[string]*pluginSignaturePath)
fsPrefix := "" fsPrefix := ""
if *s.Config().FileSettings.DriverName == model.ImageDriverS3 { if *ch.srv.Config().FileSettings.DriverName == model.ImageDriverS3 {
ptr := s.Config().FileSettings.AmazonS3PathPrefix ptr := ch.srv.Config().FileSettings.AmazonS3PathPrefix
if ptr != nil && *ptr != "" { if ptr != nil && *ptr != "" {
fsPrefix = *ptr + "/" fsPrefix = *ptr + "/"
} }
@@ -863,7 +863,7 @@ func (s *Server) getPluginsFromFilePaths(fileStorePaths []string) map[string]*pl
return pluginSignaturePathMap return pluginSignaturePathMap
} }
func (s *Server) processPrepackagedPlugins(pluginsDir string) []*plugin.PrepackagedPlugin { func (ch *Channels) processPrepackagedPlugins(pluginsDir string) []*plugin.PrepackagedPlugin {
prepackagedPluginsDir, found := fileutils.FindDir(pluginsDir) prepackagedPluginsDir, found := fileutils.FindDir(pluginsDir)
if !found { if !found {
return nil return nil
@@ -879,7 +879,7 @@ func (s *Server) processPrepackagedPlugins(pluginsDir string) []*plugin.Prepacka
return nil return nil
} }
pluginSignaturePathMap := s.getPluginsFromFilePaths(fileStorePaths) pluginSignaturePathMap := ch.getPluginsFromFilePaths(fileStorePaths)
plugins := make([]*plugin.PrepackagedPlugin, 0, len(pluginSignaturePathMap)) plugins := make([]*plugin.PrepackagedPlugin, 0, len(pluginSignaturePathMap))
prepackagedPlugins := make(chan *plugin.PrepackagedPlugin, len(pluginSignaturePathMap)) prepackagedPlugins := make(chan *plugin.PrepackagedPlugin, len(pluginSignaturePathMap))
@@ -888,7 +888,7 @@ func (s *Server) processPrepackagedPlugins(pluginsDir string) []*plugin.Prepacka
wg.Add(1) wg.Add(1)
go func(psPath *pluginSignaturePath) { go func(psPath *pluginSignaturePath) {
defer wg.Done() defer wg.Done()
p, err := s.processPrepackagedPlugin(psPath) p, err := ch.processPrepackagedPlugin(psPath)
if err != nil { if err != nil {
mlog.Error("Failed to install prepackaged plugin", mlog.String("path", psPath.path), mlog.Err(err)) mlog.Error("Failed to install prepackaged plugin", mlog.String("path", psPath.path), mlog.Err(err))
return return
@@ -909,7 +909,7 @@ func (s *Server) processPrepackagedPlugins(pluginsDir string) []*plugin.Prepacka
// processPrepackagedPlugin will return the prepackaged plugin metadata and will also // processPrepackagedPlugin will return the prepackaged plugin metadata and will also
// install the prepackaged plugin if it had been previously enabled and AutomaticPrepackagedPlugins is true. // install the prepackaged plugin if it had been previously enabled and AutomaticPrepackagedPlugins is true.
func (s *Server) processPrepackagedPlugin(pluginPath *pluginSignaturePath) (*plugin.PrepackagedPlugin, error) { func (ch *Channels) processPrepackagedPlugin(pluginPath *pluginSignaturePath) (*plugin.PrepackagedPlugin, error) {
mlog.Debug("Processing prepackaged plugin", mlog.String("path", pluginPath.path)) mlog.Debug("Processing prepackaged plugin", mlog.String("path", pluginPath.path))
fileReader, err := os.Open(pluginPath.path) fileReader, err := os.Open(pluginPath.path)
@@ -930,18 +930,18 @@ func (s *Server) processPrepackagedPlugin(pluginPath *pluginSignaturePath) (*plu
} }
// 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 !*s.Config().PluginSettings.AutomaticPrepackagedPlugins { if !*ch.srv.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 := s.Config().PluginSettings.PluginStates[plugin.Manifest.Id] pluginState := ch.srv.Config().PluginSettings.PluginStates[plugin.Manifest.Id]
if pluginState == nil || !pluginState.Enable { if pluginState == nil || !pluginState.Enable {
return plugin, nil return plugin, nil
} }
mlog.Debug("Installing prepackaged plugin", mlog.String("path", pluginPath.path)) mlog.Debug("Installing prepackaged plugin", mlog.String("path", pluginPath.path))
if _, err := s.installExtractedPlugin(plugin.Manifest, pluginDir, installPluginLocallyOnlyIfNewOrUpgrade); err != nil { if _, err := ch.installExtractedPlugin(plugin.Manifest, pluginDir, installPluginLocallyOnlyIfNewOrUpgrade); err != nil {
return nil, errors.Wrapf(err, "Failed to install extracted prepackaged plugin %s", pluginPath.path) return nil, errors.Wrapf(err, "Failed to install extracted prepackaged plugin %s", pluginPath.path)
} }
@@ -949,24 +949,24 @@ func (s *Server) processPrepackagedPlugin(pluginPath *pluginSignaturePath) (*plu
} }
// installFeatureFlagPlugins handles the automatic installation/upgrade of plugins from feature flags // installFeatureFlagPlugins handles the automatic installation/upgrade of plugins from feature flags
func (s *Server) installFeatureFlagPlugins() { func (ch *Channels) installFeatureFlagPlugins() {
ffControledPlugins := s.Config().FeatureFlags.Plugins() ffControledPlugins := ch.srv.Config().FeatureFlags.Plugins()
// Respect the automatic prepackaged disable setting // Respect the automatic prepackaged disable setting
if !*s.Config().PluginSettings.AutomaticPrepackagedPlugins { if !*ch.srv.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 := s.Config().PluginSettings.PluginStates[pluginID] pluginState := ch.srv.Config().PluginSettings.PluginStates[pluginID]
if pluginState != nil && !pluginState.Enable { if pluginState != nil && !pluginState.Enable {
s.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
} }
// Check if we already installed this version as InstallMarketplacePlugin can't handle re-installs well. // Check if we already installed this version as InstallMarketplacePlugin can't handle re-installs well.
pluginStatus, err := s.GetPluginStatus(pluginID) pluginStatus, err := ch.GetPluginStatus(pluginID)
pluginExists := err == nil pluginExists := err == nil
if pluginExists && pluginStatus.Version == version { if pluginExists && pluginStatus.Version == version {
continue continue
@@ -974,37 +974,37 @@ func (s *Server) installFeatureFlagPlugins() {
if version != "" && version != "control" { if version != "" && version != "control" {
// If we are on-prem skip installation if this is a downgrade // If we are on-prem skip installation if this is a downgrade
license := s.License() license := ch.srv.License()
inCloud := license != nil && *license.Features.Cloud inCloud := license != nil && *license.Features.Cloud
if !inCloud && pluginExists { if !inCloud && pluginExists {
parsedVersion, err := semver.Parse(version) parsedVersion, err := semver.Parse(version)
if err != nil { if err != nil {
s.Log.Debug("Bad version from feature flag", mlog.String("plugin_id", pluginID), mlog.Err(err), mlog.String("version", version)) ch.srv.Log.Debug("Bad version from feature flag", mlog.String("plugin_id", pluginID), mlog.Err(err), mlog.String("version", version))
return return
} }
parsedExistingVersion, err := semver.Parse(pluginStatus.Version) parsedExistingVersion, err := semver.Parse(pluginStatus.Version)
if err != nil { if err != nil {
s.Log.Debug("Bad version from plugin manifest", mlog.String("plugin_id", pluginID), mlog.Err(err), mlog.String("version", pluginStatus.Version)) ch.srv.Log.Debug("Bad version from plugin manifest", mlog.String("plugin_id", pluginID), mlog.Err(err), mlog.String("version", pluginStatus.Version))
return return
} }
if parsedVersion.LTE(parsedExistingVersion) { if parsedVersion.LTE(parsedExistingVersion) {
s.Log.Debug("Skip installation because given version was a downgrade and on-prem installations should not downgrade.", mlog.String("plugin_id", pluginID), mlog.Err(err), mlog.String("version", pluginStatus.Version)) ch.srv.Log.Debug("Skip installation because given version was a downgrade and on-prem installations should not downgrade.", mlog.String("plugin_id", pluginID), mlog.Err(err), mlog.String("version", pluginStatus.Version))
return return
} }
} }
_, err := s.installMarketplacePlugin(&model.InstallMarketplacePluginRequest{ _, err := ch.installMarketplacePlugin(&model.InstallMarketplacePluginRequest{
Id: pluginID, Id: pluginID,
Version: version, Version: version,
}) })
if err != nil { if err != nil {
s.Log.Debug("Unable to install plugin from FF manifest", mlog.String("plugin_id", pluginID), mlog.Err(err), mlog.String("version", version)) ch.srv.Log.Debug("Unable to install plugin from FF manifest", mlog.String("plugin_id", pluginID), mlog.Err(err), mlog.String("version", version))
} else { } else {
if err := s.enablePlugin(pluginID); err != nil { if err := ch.enablePlugin(pluginID); err != nil {
s.Log.Debug("Unable to enable plugin installed from feature flag.", mlog.String("plugin_id", pluginID), mlog.Err(err), mlog.String("version", version)) ch.srv.Log.Debug("Unable to enable plugin installed from feature flag.", mlog.String("plugin_id", pluginID), mlog.Err(err), mlog.String("version", version))
} else { } else {
s.Log.Debug("Installed and enabled plugin.", mlog.String("plugin_id", pluginID), mlog.String("version", version)) ch.srv.Log.Debug("Installed and enabled plugin.", mlog.String("plugin_id", pluginID), mlog.String("version", version))
} }
} }
} }

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

@@ -9,10 +9,10 @@ import (
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"
) )
func (s *Server) notifyClusterPluginEvent(event model.ClusterEvent, data model.PluginEventData) { func (ch *Channels) notifyClusterPluginEvent(event model.ClusterEvent, data model.PluginEventData) {
buf, _ := json.Marshal(data) buf, _ := json.Marshal(data)
if s.Cluster != nil { if ch.srv.Cluster != nil {
s.Cluster.SendClusterMessage(&model.ClusterMessage{ ch.srv.Cluster.SendClusterMessage(&model.ClusterMessage{
Event: event, Event: event,
SendType: model.ClusterSendReliable, SendType: model.ClusterSendReliable,
WaitForAllToSend: true, WaitForAllToSend: true,

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

@@ -62,13 +62,13 @@ const managedPluginFileName = ".filestore"
const fileStorePluginFolder = "plugins" const fileStorePluginFolder = "plugins"
func (a *App) InstallPluginFromData(data model.PluginEventData) { func (a *App) InstallPluginFromData(data model.PluginEventData) {
a.Srv().installPluginFromData(data) a.ch.installPluginFromData(data)
} }
func (s *Server) installPluginFromData(data model.PluginEventData) { func (ch *Channels) installPluginFromData(data model.PluginEventData) {
mlog.Debug("Installing plugin as per cluster message", mlog.String("plugin_id", data.Id)) mlog.Debug("Installing plugin as per cluster message", mlog.String("plugin_id", data.Id))
pluginSignaturePathMap, appErr := s.getPluginsFromFolder() pluginSignaturePathMap, appErr := ch.getPluginsFromFolder()
if appErr != nil { if appErr != nil {
mlog.Error("Failed to get plugin signatures from filestore. Can't install plugin from data.", mlog.Err(appErr)) mlog.Error("Failed to get plugin signatures from filestore. Can't install plugin from data.", mlog.Err(appErr))
return return
@@ -79,7 +79,7 @@ func (s *Server) installPluginFromData(data model.PluginEventData) {
return return
} }
reader, appErr := s.fileReader(plugin.path) reader, appErr := ch.srv.fileReader(plugin.path)
if appErr != nil { if appErr != nil {
mlog.Error("Failed to open plugin bundle from file store.", mlog.String("bundle", plugin.path), mlog.Err(appErr)) mlog.Error("Failed to open plugin bundle from file store.", mlog.String("bundle", plugin.path), mlog.Err(appErr))
return return
@@ -87,8 +87,8 @@ func (s *Server) installPluginFromData(data model.PluginEventData) {
defer reader.Close() defer reader.Close()
var signature filestore.ReadCloseSeeker var signature filestore.ReadCloseSeeker
if *s.Config().PluginSettings.RequirePluginSignature { if *ch.srv.Config().PluginSettings.RequirePluginSignature {
signature, appErr = s.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))
return return
@@ -96,44 +96,44 @@ func (s *Server) installPluginFromData(data model.PluginEventData) {
defer signature.Close() defer signature.Close()
} }
manifest, appErr := s.installPluginLocally(reader, signature, installPluginLocallyAlways) manifest, appErr := ch.installPluginLocally(reader, signature, installPluginLocallyAlways)
if appErr != nil { if appErr != nil {
mlog.Error("Failed to sync plugin from file store", mlog.String("bundle", plugin.path), mlog.Err(appErr)) mlog.Error("Failed to sync plugin from file store", mlog.String("bundle", plugin.path), mlog.Err(appErr))
return return
} }
if err := s.notifyPluginEnabled(manifest); err != nil { if err := ch.notifyPluginEnabled(manifest); err != nil {
mlog.Error("Failed notify plugin enabled", mlog.Err(err)) mlog.Error("Failed notify plugin enabled", mlog.Err(err))
} }
if err := s.notifyPluginStatusesChanged(); err != nil { if err := ch.notifyPluginStatusesChanged(); err != nil {
mlog.Error("Failed to notify plugin status changed", mlog.Err(err)) mlog.Error("Failed to notify plugin status changed", mlog.Err(err))
} }
} }
func (a *App) RemovePluginFromData(data model.PluginEventData) { func (a *App) RemovePluginFromData(data model.PluginEventData) {
a.Srv().removePluginFromData(data) a.ch.removePluginFromData(data)
} }
func (s *Server) removePluginFromData(data model.PluginEventData) { func (ch *Channels) removePluginFromData(data model.PluginEventData) {
mlog.Debug("Removing plugin as per cluster message", mlog.String("plugin_id", data.Id)) mlog.Debug("Removing plugin as per cluster message", mlog.String("plugin_id", data.Id))
if err := s.removePluginLocally(data.Id); err != nil { if err := ch.removePluginLocally(data.Id); err != nil {
mlog.Warn("Failed to remove plugin locally", mlog.Err(err), mlog.String("id", data.Id)) mlog.Warn("Failed to remove plugin locally", mlog.Err(err), mlog.String("id", data.Id))
} }
if err := s.notifyPluginStatusesChanged(); err != nil { if err := ch.notifyPluginStatusesChanged(); err != nil {
mlog.Warn("failed to notify plugin status changed", mlog.Err(err)) mlog.Warn("failed to notify plugin status changed", mlog.Err(err))
} }
} }
// InstallPluginWithSignature verifies and installs plugin. // InstallPluginWithSignature verifies and installs plugin.
func (a *App) InstallPluginWithSignature(pluginFile, signature io.ReadSeeker) (*model.Manifest, *model.AppError) { func (a *App) InstallPluginWithSignature(pluginFile, signature io.ReadSeeker) (*model.Manifest, *model.AppError) {
return a.Srv().installPluginWithSignature(pluginFile, signature) return a.ch.installPluginWithSignature(pluginFile, signature)
} }
func (s *Server) installPluginWithSignature(pluginFile, signature io.ReadSeeker) (*model.Manifest, *model.AppError) { func (ch *Channels) installPluginWithSignature(pluginFile, signature io.ReadSeeker) (*model.Manifest, *model.AppError) {
return s.installPlugin(pluginFile, signature, installPluginLocallyAlways) return ch.installPlugin(pluginFile, signature, installPluginLocallyAlways)
} }
// InstallPlugin unpacks and installs a plugin but does not enable or activate it. // InstallPlugin unpacks and installs a plugin but does not enable or activate it.
@@ -147,40 +147,40 @@ func (a *App) InstallPlugin(pluginFile io.ReadSeeker, replace bool) (*model.Mani
} }
func (a *App) installPlugin(pluginFile, signature io.ReadSeeker, installationStrategy pluginInstallationStrategy) (*model.Manifest, *model.AppError) { func (a *App) installPlugin(pluginFile, signature io.ReadSeeker, installationStrategy pluginInstallationStrategy) (*model.Manifest, *model.AppError) {
return a.Srv().installPlugin(pluginFile, signature, installationStrategy) return a.ch.installPlugin(pluginFile, signature, installationStrategy)
} }
func (s *Server) installPlugin(pluginFile, signature io.ReadSeeker, installationStrategy pluginInstallationStrategy) (*model.Manifest, *model.AppError) { func (ch *Channels) installPlugin(pluginFile, signature io.ReadSeeker, installationStrategy pluginInstallationStrategy) (*model.Manifest, *model.AppError) {
manifest, appErr := s.installPluginLocally(pluginFile, signature, installationStrategy) manifest, appErr := ch.installPluginLocally(pluginFile, signature, installationStrategy)
if appErr != nil { if appErr != nil {
return nil, appErr return nil, appErr
} }
if signature != nil { if signature != nil {
signature.Seek(0, 0) signature.Seek(0, 0)
if _, appErr = s.writeFile(signature, getSignatureStorePath(manifest.Id)); appErr != nil { if _, appErr = ch.srv.writeFile(signature, getSignatureStorePath(manifest.Id)); appErr != nil {
return nil, model.NewAppError("saveSignature", "app.plugin.store_signature.app_error", nil, appErr.Error(), http.StatusInternalServerError) return nil, model.NewAppError("saveSignature", "app.plugin.store_signature.app_error", nil, appErr.Error(), http.StatusInternalServerError)
} }
} }
// Store bundle in the file store to allow access from other servers. // Store bundle in the file store to allow access from other servers.
pluginFile.Seek(0, 0) pluginFile.Seek(0, 0)
if _, appErr := s.writeFile(pluginFile, getBundleStorePath(manifest.Id)); appErr != nil { if _, appErr := ch.srv.writeFile(pluginFile, getBundleStorePath(manifest.Id)); appErr != nil {
return nil, model.NewAppError("uploadPlugin", "app.plugin.store_bundle.app_error", nil, appErr.Error(), http.StatusInternalServerError) return nil, model.NewAppError("uploadPlugin", "app.plugin.store_bundle.app_error", nil, appErr.Error(), http.StatusInternalServerError)
} }
s.notifyClusterPluginEvent( ch.notifyClusterPluginEvent(
model.ClusterEventInstallPlugin, model.ClusterEventInstallPlugin,
model.PluginEventData{ model.PluginEventData{
Id: manifest.Id, Id: manifest.Id,
}, },
) )
if err := s.notifyPluginEnabled(manifest); err != nil { if err := ch.notifyPluginEnabled(manifest); err != nil {
mlog.Warn("Failed notify plugin enabled", mlog.Err(err)) mlog.Warn("Failed notify plugin enabled", mlog.Err(err))
} }
if err := s.notifyPluginStatusesChanged(); err != nil { if err := ch.notifyPluginStatusesChanged(); err != nil {
mlog.Warn("Failed to notify plugin status changed", mlog.Err(err)) mlog.Warn("Failed to notify plugin status changed", mlog.Err(err))
} }
@@ -190,13 +190,13 @@ func (s *Server) installPlugin(pluginFile, signature io.ReadSeeker, installation
// InstallMarketplacePlugin installs a plugin listed in the marketplace server. It will get the plugin bundle // InstallMarketplacePlugin installs a plugin listed in the marketplace server. It will get the plugin bundle
// from the prepackaged folder, if available, or remotely if EnableRemoteMarketplace is true. // from the prepackaged folder, if available, or remotely if EnableRemoteMarketplace is true.
func (a *App) InstallMarketplacePlugin(request *model.InstallMarketplacePluginRequest) (*model.Manifest, *model.AppError) { func (a *App) InstallMarketplacePlugin(request *model.InstallMarketplacePluginRequest) (*model.Manifest, *model.AppError) {
return a.Srv().installMarketplacePlugin(request) return a.ch.installMarketplacePlugin(request)
} }
func (s *Server) installMarketplacePlugin(request *model.InstallMarketplacePluginRequest) (*model.Manifest, *model.AppError) { func (ch *Channels) installMarketplacePlugin(request *model.InstallMarketplacePluginRequest) (*model.Manifest, *model.AppError) {
var pluginFile, signatureFile io.ReadSeeker var pluginFile, signatureFile io.ReadSeeker
prepackagedPlugin, appErr := s.getPrepackagedPlugin(request.Id, request.Version) prepackagedPlugin, appErr := ch.getPrepackagedPlugin(request.Id, request.Version)
if appErr != nil && appErr.Id != "app.plugin.marketplace_plugins.not_found.app_error" { if appErr != nil && appErr.Id != "app.plugin.marketplace_plugins.not_found.app_error" {
return nil, appErr return nil, appErr
} }
@@ -212,14 +212,14 @@ func (s *Server) installMarketplacePlugin(request *model.InstallMarketplacePlugi
signatureFile = bytes.NewReader(prepackagedPlugin.Signature) signatureFile = bytes.NewReader(prepackagedPlugin.Signature)
} }
if *s.Config().PluginSettings.EnableRemoteMarketplace && pluginFile == nil { if *ch.srv.Config().PluginSettings.EnableRemoteMarketplace && pluginFile == nil {
var plugin *model.BaseMarketplacePlugin var plugin *model.BaseMarketplacePlugin
plugin, appErr = s.getRemoteMarketplacePlugin(request.Id, request.Version) plugin, appErr = ch.getRemoteMarketplacePlugin(request.Id, request.Version)
if appErr != nil { if appErr != nil {
return nil, appErr return nil, appErr
} }
downloadedPluginBytes, err := s.downloadFromURL(plugin.DownloadURL) downloadedPluginBytes, err := ch.srv.downloadFromURL(plugin.DownloadURL)
if err != nil { if err != nil {
return nil, model.NewAppError("InstallMarketplacePlugin", "app.plugin.install_marketplace_plugin.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, model.NewAppError("InstallMarketplacePlugin", "app.plugin.install_marketplace_plugin.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
@@ -238,7 +238,7 @@ func (s *Server) installMarketplacePlugin(request *model.InstallMarketplacePlugi
return nil, model.NewAppError("InstallMarketplacePlugin", "app.plugin.marketplace_plugins.signature_not_found.app_error", nil, "", http.StatusInternalServerError) return nil, model.NewAppError("InstallMarketplacePlugin", "app.plugin.marketplace_plugins.signature_not_found.app_error", nil, "", http.StatusInternalServerError)
} }
manifest, appErr := s.installPluginWithSignature(pluginFile, signatureFile) manifest, appErr := ch.installPluginWithSignature(pluginFile, signatureFile)
if appErr != nil { if appErr != nil {
return nil, appErr return nil, appErr
} }
@@ -258,18 +258,18 @@ const (
) )
func (a *App) installPluginLocally(pluginFile, signature io.ReadSeeker, installationStrategy pluginInstallationStrategy) (*model.Manifest, *model.AppError) { func (a *App) installPluginLocally(pluginFile, signature io.ReadSeeker, installationStrategy pluginInstallationStrategy) (*model.Manifest, *model.AppError) {
return a.Srv().installPluginLocally(pluginFile, signature, installationStrategy) return a.ch.installPluginLocally(pluginFile, signature, installationStrategy)
} }
func (s *Server) installPluginLocally(pluginFile, signature io.ReadSeeker, installationStrategy pluginInstallationStrategy) (*model.Manifest, *model.AppError) { func (ch *Channels) installPluginLocally(pluginFile, signature io.ReadSeeker, installationStrategy pluginInstallationStrategy) (*model.Manifest, *model.AppError) {
pluginsEnvironment := s.GetPluginsEnvironment() pluginsEnvironment := ch.GetPluginsEnvironment()
if pluginsEnvironment == nil { if pluginsEnvironment == nil {
return nil, model.NewAppError("installPluginLocally", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) return nil, model.NewAppError("installPluginLocally", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
} }
// verify signature // verify signature
if signature != nil { if signature != nil {
if err := s.verifyPlugin(pluginFile, signature); err != nil { if err := ch.verifyPlugin(pluginFile, signature); err != nil {
return nil, err return nil, err
} }
} }
@@ -285,7 +285,7 @@ func (s *Server) installPluginLocally(pluginFile, signature io.ReadSeeker, insta
return nil, appErr return nil, appErr
} }
manifest, appErr = s.installExtractedPlugin(manifest, pluginDir, installationStrategy) manifest, appErr = ch.installExtractedPlugin(manifest, pluginDir, installationStrategy)
if appErr != nil { if appErr != nil {
return nil, appErr return nil, appErr
} }
@@ -320,8 +320,8 @@ func extractPlugin(pluginFile io.ReadSeeker, extractDir string) (*model.Manifest
return manifest, extractDir, nil return manifest, extractDir, nil
} }
func (s *Server) installExtractedPlugin(manifest *model.Manifest, fromPluginDir string, installationStrategy pluginInstallationStrategy) (*model.Manifest, *model.AppError) { func (ch *Channels) installExtractedPlugin(manifest *model.Manifest, fromPluginDir string, installationStrategy pluginInstallationStrategy) (*model.Manifest, *model.AppError) {
pluginsEnvironment := s.GetPluginsEnvironment() pluginsEnvironment := ch.GetPluginsEnvironment()
if pluginsEnvironment == nil { if pluginsEnvironment == nil {
return nil, model.NewAppError("installExtractedPlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) return nil, model.NewAppError("installExtractedPlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
} }
@@ -368,12 +368,12 @@ func (s *Server) installExtractedPlugin(manifest *model.Manifest, fromPluginDir
// Otherwise remove the existing installation prior to install below. // Otherwise remove the existing installation prior to install below.
mlog.Debug("Removing existing installation of plugin before local install", mlog.String("plugin_id", existingManifest.Id), mlog.String("version", existingManifest.Version)) mlog.Debug("Removing existing installation of plugin before local install", mlog.String("plugin_id", existingManifest.Id), mlog.String("version", existingManifest.Version))
if err := s.removePluginLocally(existingManifest.Id); err != nil { if err := ch.removePluginLocally(existingManifest.Id); err != nil {
return nil, model.NewAppError("installExtractedPlugin", "app.plugin.install_id_failed_remove.app_error", nil, "", http.StatusBadRequest) return nil, model.NewAppError("installExtractedPlugin", "app.plugin.install_id_failed_remove.app_error", nil, "", http.StatusBadRequest)
} }
} }
pluginPath := filepath.Join(*s.Config().PluginSettings.Directory, manifest.Id) pluginPath := filepath.Join(*ch.srv.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)
@@ -395,9 +395,9 @@ func (s *Server) installExtractedPlugin(manifest *model.Manifest, fromPluginDir
} }
// Activate the plugin if enabled. // Activate the plugin if enabled.
pluginState := s.Config().PluginSettings.PluginStates[manifest.Id] pluginState := ch.srv.Config().PluginSettings.PluginStates[manifest.Id]
if pluginState != nil && pluginState.Enable { if pluginState != nil && pluginState.Enable {
if manifest.Id == "com.mattermost.apps" && !s.Config().FeatureFlags.AppsEnabled { if manifest.Id == "com.mattermost.apps" && !ch.srv.Config().FeatureFlags.AppsEnabled {
return manifest, nil return manifest, nil
} }
updatedManifest, _, err := pluginsEnvironment.Activate(manifest.Id) updatedManifest, _, err := pluginsEnvironment.Activate(manifest.Id)
@@ -413,44 +413,44 @@ func (s *Server) installExtractedPlugin(manifest *model.Manifest, fromPluginDir
} }
func (a *App) RemovePlugin(id string) *model.AppError { func (a *App) RemovePlugin(id string) *model.AppError {
return a.Srv().removePlugin(id) return a.ch.removePlugin(id)
} }
func (s *Server) removePlugin(id string) *model.AppError { func (ch *Channels) removePlugin(id string) *model.AppError {
// Disable plugin before removal to make sure this // Disable plugin before removal to make sure this
// plugin remains disabled on re-install. // plugin remains disabled on re-install.
if err := s.disablePlugin(id); err != nil { if err := ch.disablePlugin(id); err != nil {
return err return err
} }
if err := s.removePluginLocally(id); err != nil { if err := ch.removePluginLocally(id); err != nil {
return err return err
} }
// Remove bundle from the file store. // Remove bundle from the file store.
storePluginFileName := getBundleStorePath(id) storePluginFileName := getBundleStorePath(id)
bundleExist, err := s.fileExists(storePluginFileName) bundleExist, err := ch.srv.fileExists(storePluginFileName)
if err != nil { if err != nil {
return model.NewAppError("removePlugin", "app.plugin.remove_bundle.app_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("removePlugin", "app.plugin.remove_bundle.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
if !bundleExist { if !bundleExist {
return nil return nil
} }
if err = s.removeFile(storePluginFileName); err != nil { if err = ch.srv.removeFile(storePluginFileName); err != nil {
return model.NewAppError("removePlugin", "app.plugin.remove_bundle.app_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("removePlugin", "app.plugin.remove_bundle.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
if err = s.removeSignature(id); err != nil { if err = ch.removeSignature(id); err != nil {
mlog.Warn("Can't remove signature", mlog.Err(err)) mlog.Warn("Can't remove signature", mlog.Err(err))
} }
s.notifyClusterPluginEvent( ch.notifyClusterPluginEvent(
model.ClusterEventRemovePlugin, model.ClusterEventRemovePlugin,
model.PluginEventData{ model.PluginEventData{
Id: id, Id: id,
}, },
) )
if err := s.notifyPluginStatusesChanged(); err != nil { if err := ch.notifyPluginStatusesChanged(); err != nil {
mlog.Warn("Failed to notify plugin status changed", mlog.Err(err)) mlog.Warn("Failed to notify plugin status changed", mlog.Err(err))
} }
@@ -458,11 +458,11 @@ func (s *Server) removePlugin(id string) *model.AppError {
} }
func (a *App) removePluginLocally(id string) *model.AppError { func (a *App) removePluginLocally(id string) *model.AppError {
return a.Srv().removePluginLocally(id) return a.ch.removePluginLocally(id)
} }
func (s *Server) removePluginLocally(id string) *model.AppError { func (ch *Channels) removePluginLocally(id string) *model.AppError {
pluginsEnvironment := s.GetPluginsEnvironment() pluginsEnvironment := ch.GetPluginsEnvironment()
if pluginsEnvironment == nil { if pluginsEnvironment == nil {
return model.NewAppError("removePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) return model.NewAppError("removePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
} }
@@ -488,7 +488,7 @@ func (s *Server) removePluginLocally(id string) *model.AppError {
pluginsEnvironment.Deactivate(id) pluginsEnvironment.Deactivate(id)
pluginsEnvironment.RemovePlugin(id) pluginsEnvironment.RemovePlugin(id)
s.unregisterPluginCommands(id) ch.srv.unregisterPluginCommands(id)
if err := os.RemoveAll(pluginPath); err != nil { if err := os.RemoveAll(pluginPath); err != nil {
return model.NewAppError("removePlugin", "app.plugin.remove.app_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("removePlugin", "app.plugin.remove.app_error", nil, err.Error(), http.StatusInternalServerError)
@@ -497,9 +497,9 @@ func (s *Server) removePluginLocally(id string) *model.AppError {
return nil return nil
} }
func (s *Server) removeSignature(pluginID string) *model.AppError { func (ch *Channels) removeSignature(pluginID string) *model.AppError {
filePath := getSignatureStorePath(pluginID) filePath := getSignatureStorePath(pluginID)
exists, err := s.fileExists(filePath) exists, err := ch.srv.fileExists(filePath)
if err != nil { if err != nil {
return model.NewAppError("removeSignature", "app.plugin.remove_bundle.app_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("removeSignature", "app.plugin.remove_bundle.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
@@ -507,7 +507,7 @@ func (s *Server) removeSignature(pluginID string) *model.AppError {
mlog.Debug("no plugin signature to remove", mlog.String("plugin_id", pluginID)) mlog.Debug("no plugin signature to remove", mlog.String("plugin_id", pluginID))
return nil return nil
} }
if err = s.removeFile(filePath); err != nil { if err = ch.srv.removeFile(filePath); err != nil {
return model.NewAppError("removeSignature", "app.plugin.remove_bundle.app_error", nil, err.Error(), http.StatusInternalServerError) return model.NewAppError("removeSignature", "app.plugin.remove_bundle.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
return nil return nil

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

@@ -21,7 +21,7 @@ import (
) )
func (s *Server) ServePluginRequest(w http.ResponseWriter, r *http.Request) { func (s *Server) ServePluginRequest(w http.ResponseWriter, r *http.Request) {
pluginsEnvironment := s.GetPluginsEnvironment() pluginsEnvironment := s.Channels().GetPluginsEnvironment()
if pluginsEnvironment == nil { if pluginsEnvironment == nil {
err := model.NewAppError("ServePluginRequest", "app.plugin.disabled.app_error", nil, "Enable plugins to serve plugin requests", http.StatusNotImplemented) err := model.NewAppError("ServePluginRequest", "app.plugin.disabled.app_error", nil, "Enable plugins to serve plugin requests", http.StatusNotImplemented)
s.Log.Error(err.Error()) s.Log.Error(err.Error())
@@ -46,7 +46,7 @@ func (s *Server) ServePluginRequest(w http.ResponseWriter, r *http.Request) {
} }
func (a *App) ServeInterPluginRequest(w http.ResponseWriter, r *http.Request, sourcePluginId, destinationPluginId string) { func (a *App) ServeInterPluginRequest(w http.ResponseWriter, r *http.Request, sourcePluginId, destinationPluginId string) {
pluginsEnvironment := a.GetPluginsEnvironment() pluginsEnvironment := a.ch.GetPluginsEnvironment()
if pluginsEnvironment == nil { if pluginsEnvironment == nil {
err := model.NewAppError("ServeInterPluginRequest", "app.plugin.disabled.app_error", nil, "Plugin environment not found.", http.StatusNotImplemented) err := model.NewAppError("ServeInterPluginRequest", "app.plugin.disabled.app_error", nil, "Plugin environment not found.", http.StatusNotImplemented)
a.Log().Error(err.Error()) a.Log().Error(err.Error())
@@ -90,7 +90,7 @@ func (s *Server) ServePluginPublicRequest(w http.ResponseWriter, r *http.Request
vars := mux.Vars(r) vars := mux.Vars(r)
pluginID := vars["plugin_id"] pluginID := vars["plugin_id"]
pluginsEnv := s.GetPluginsEnvironment() pluginsEnv := s.Channels().GetPluginsEnvironment()
// Check if someone has nullified the pluginsEnv in the meantime // Check if someone has nullified the pluginsEnv in the meantime
if pluginsEnv == nil { if pluginsEnv == nil {

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

@@ -63,7 +63,7 @@ func TestPluginShutdownTest(t *testing.T) {
done := make(chan bool) done := make(chan bool)
go func() { go func() {
defer close(done) defer close(done)
th.App.Srv().ShutDownPlugins() th.App.ch.ShutDownPlugins()
}() }()
select { select {

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

@@ -19,15 +19,6 @@ import (
"github.com/mattermost/mattermost-server/v6/utils" "github.com/mattermost/mattermost-server/v6/utils"
) )
// GetPluginPublicKeyFiles returns all public keys listed in the config.
func (a *App) GetPluginPublicKeyFiles() ([]string, *model.AppError) {
return a.Srv().getPluginPublicKeyFiles()
}
func (s *Server) getPluginPublicKeyFiles() ([]string, *model.AppError) {
return s.Config().PluginSettings.SignaturePublicKeyFiles, nil
}
// GetPublicKey will return the actual public key saved in the `name` file. // GetPublicKey will return the actual public key saved in the `name` file.
func (a *App) GetPublicKey(name string) ([]byte, *model.AppError) { func (a *App) GetPublicKey(name string) ([]byte, *model.AppError) {
return a.Srv().getPublicKey(name) return a.Srv().getPublicKey(name)
@@ -83,19 +74,16 @@ func (a *App) DeletePublicKey(name string) *model.AppError {
// VerifyPlugin checks that the given signature corresponds to the given plugin and matches a trusted certificate. // VerifyPlugin checks that the given signature corresponds to the given plugin and matches a trusted certificate.
func (a *App) VerifyPlugin(plugin, signature io.ReadSeeker) *model.AppError { func (a *App) VerifyPlugin(plugin, signature io.ReadSeeker) *model.AppError {
return a.Srv().verifyPlugin(plugin, signature) return a.ch.verifyPlugin(plugin, signature)
} }
func (s *Server) verifyPlugin(plugin, signature io.ReadSeeker) *model.AppError { func (ch *Channels) verifyPlugin(plugin, signature io.ReadSeeker) *model.AppError {
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, appErr := s.getPluginPublicKeyFiles() publicKeys := ch.srv.Config().PluginSettings.SignaturePublicKeyFiles
if appErr != nil {
return appErr
}
for _, pk := range publicKeys { for _, pk := range publicKeys {
pkBytes, appErr := s.getPublicKey(pk) pkBytes, appErr := ch.srv.getPublicKey(pk)
if appErr != nil { if appErr != nil {
mlog.Warn("Unable to get public key for ", mlog.String("filename", pk)) mlog.Warn("Unable to get public key for ", mlog.String("filename", pk))
continue continue

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

@@ -10,8 +10,8 @@ import (
) )
// GetPluginStatus returns the status for a plugin installed on this server. // GetPluginStatus returns the status for a plugin installed on this server.
func (s *Server) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) { func (ch *Channels) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) {
pluginsEnvironment := s.GetPluginsEnvironment() pluginsEnvironment := ch.GetPluginsEnvironment()
if pluginsEnvironment == nil { if pluginsEnvironment == nil {
return nil, model.NewAppError("GetPluginStatus", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) return nil, model.NewAppError("GetPluginStatus", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
} }
@@ -24,8 +24,8 @@ func (s *Server) GetPluginStatus(id string) (*model.PluginStatus, *model.AppErro
for _, status := range pluginStatuses { for _, status := range pluginStatuses {
if status.PluginId == id { if status.PluginId == id {
// Add our cluster ID // Add our cluster ID
if s.Cluster != nil { if ch.srv.Cluster != nil {
status.ClusterId = s.Cluster.GetClusterId() status.ClusterId = ch.srv.Cluster.GetClusterId()
} }
return status, nil return status, nil
@@ -37,12 +37,12 @@ func (s *Server) GetPluginStatus(id string) (*model.PluginStatus, *model.AppErro
// GetPluginStatus returns the status for a plugin installed on this server. // GetPluginStatus returns the status for a plugin installed on this server.
func (a *App) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) { func (a *App) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) {
return a.Srv().GetPluginStatus(id) return a.ch.GetPluginStatus(id)
} }
// GetPluginStatuses returns the status for plugins installed on this server. // GetPluginStatuses returns the status for plugins installed on this server.
func (s *Server) GetPluginStatuses() (model.PluginStatuses, *model.AppError) { func (ch *Channels) GetPluginStatuses() (model.PluginStatuses, *model.AppError) {
pluginsEnvironment := s.GetPluginsEnvironment() pluginsEnvironment := ch.GetPluginsEnvironment()
if pluginsEnvironment == nil { if pluginsEnvironment == nil {
return nil, model.NewAppError("GetPluginStatuses", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) return nil, model.NewAppError("GetPluginStatuses", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
} }
@@ -54,8 +54,8 @@ func (s *Server) GetPluginStatuses() (model.PluginStatuses, *model.AppError) {
// Add our cluster ID // Add our cluster ID
for _, status := range pluginStatuses { for _, status := range pluginStatuses {
if s.Cluster != nil { if ch.srv.Cluster != nil {
status.ClusterId = s.Cluster.GetClusterId() status.ClusterId = ch.srv.Cluster.GetClusterId()
} else { } else {
status.ClusterId = "" status.ClusterId = ""
} }
@@ -66,22 +66,22 @@ func (s *Server) GetPluginStatuses() (model.PluginStatuses, *model.AppError) {
// GetPluginStatuses returns the status for plugins installed on this server. // GetPluginStatuses returns the status for plugins installed on this server.
func (a *App) GetPluginStatuses() (model.PluginStatuses, *model.AppError) { func (a *App) GetPluginStatuses() (model.PluginStatuses, *model.AppError) {
return a.Srv().GetPluginStatuses() return a.ch.GetPluginStatuses()
} }
// GetClusterPluginStatuses returns the status for plugins installed anywhere in the cluster. // GetClusterPluginStatuses returns the status for plugins installed anywhere in the cluster.
func (a *App) GetClusterPluginStatuses() (model.PluginStatuses, *model.AppError) { func (a *App) GetClusterPluginStatuses() (model.PluginStatuses, *model.AppError) {
return a.Srv().getClusterPluginStatuses() return a.ch.getClusterPluginStatuses()
} }
func (s *Server) getClusterPluginStatuses() (model.PluginStatuses, *model.AppError) { func (ch *Channels) getClusterPluginStatuses() (model.PluginStatuses, *model.AppError) {
pluginStatuses, err := s.GetPluginStatuses() pluginStatuses, err := ch.GetPluginStatuses()
if err != nil { if err != nil {
return nil, err return nil, err
} }
if s.Cluster != nil && *s.Config().ClusterSettings.Enable { if ch.srv.Cluster != nil && *ch.srv.Config().ClusterSettings.Enable {
clusterPluginStatuses, err := s.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)
} }
@@ -92,8 +92,8 @@ func (s *Server) getClusterPluginStatuses() (model.PluginStatuses, *model.AppErr
return pluginStatuses, nil return pluginStatuses, nil
} }
func (s *Server) notifyPluginStatusesChanged() error { func (ch *Channels) notifyPluginStatusesChanged() error {
pluginStatuses, err := s.getClusterPluginStatuses() pluginStatuses, err := ch.getClusterPluginStatuses()
if err != nil { if err != nil {
return err return err
} }
@@ -102,7 +102,7 @@ func (s *Server) notifyPluginStatusesChanged() error {
message := model.NewWebSocketEvent(model.WebsocketEventPluginStatusesChanged, "", "", "", nil) message := model.NewWebSocketEvent(model.WebsocketEventPluginStatusesChanged, "", "", "", nil)
message.Add("plugin_statuses", pluginStatuses) message.Add("plugin_statuses", pluginStatuses)
message.GetBroadcast().ContainsSensitiveData = true message.GetBroadcast().ContainsSensitiveData = true
s.Publish(message) ch.srv.Publish(message)
return nil return nil
} }

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

@@ -728,7 +728,7 @@ func TestPluginPanicLogs(t *testing.T) {
th.TestLogger.Flush() th.TestLogger.Flush()
// We shutdown plugins first so that the read on the log buffer is race-free. // We shutdown plugins first so that the read on the log buffer is race-free.
th.App.Srv().ShutDownPlugins() th.App.ch.ShutDownPlugins()
tearDown() tearDown()
testlib.AssertLog(t, th.LogBuffer, mlog.LvlDebug.Name, "panic: some text from panic") testlib.AssertLog(t, th.LogBuffer, mlog.LvlDebug.Name, "panic: some text from panic")
@@ -775,7 +775,7 @@ func TestProcessPrepackagedPlugins(t *testing.T) {
*cfg.PluginSettings.EnableRemoteMarketplace = false *cfg.PluginSettings.EnableRemoteMarketplace = false
}) })
plugins := th.App.Srv().processPrepackagedPlugins(prepackagedPluginsDir) plugins := th.App.ch.processPrepackagedPlugins(prepackagedPluginsDir)
require.Len(t, plugins, 1) require.Len(t, plugins, 1)
require.Equal(t, plugins[0].Manifest.Id, "testplugin") require.Equal(t, plugins[0].Manifest.Id, "testplugin")
require.Empty(t, plugins[0].Signature, 0) require.Empty(t, plugins[0].Signature, 0)
@@ -802,7 +802,7 @@ func TestProcessPrepackagedPlugins(t *testing.T) {
env := th.App.GetPluginsEnvironment() env := th.App.GetPluginsEnvironment()
plugins := th.App.Srv().processPrepackagedPlugins(prepackagedPluginsDir) plugins := th.App.ch.processPrepackagedPlugins(prepackagedPluginsDir)
require.Len(t, plugins, 1) require.Len(t, plugins, 1)
require.Equal(t, plugins[0].Manifest.Id, "testplugin") require.Equal(t, plugins[0].Manifest.Id, "testplugin")
require.Empty(t, plugins[0].Signature, 0) require.Empty(t, plugins[0].Signature, 0)
@@ -835,7 +835,7 @@ func TestProcessPrepackagedPlugins(t *testing.T) {
err = testlib.CopyFile(testPlugin2SignaturePath, filepath.Join(prepackagedPluginsDir, "testplugin2.tar.gz.sig")) err = testlib.CopyFile(testPlugin2SignaturePath, filepath.Join(prepackagedPluginsDir, "testplugin2.tar.gz.sig"))
require.NoError(t, err) require.NoError(t, err)
plugins := th.App.Srv().processPrepackagedPlugins(prepackagedPluginsDir) plugins := th.App.ch.processPrepackagedPlugins(prepackagedPluginsDir)
require.Len(t, plugins, 2) require.Len(t, plugins, 2)
require.Contains(t, []string{"testplugin", "testplugin2"}, plugins[0].Manifest.Id) require.Contains(t, []string{"testplugin", "testplugin2"}, plugins[0].Manifest.Id)
require.NotEmpty(t, plugins[0].Signature) require.NotEmpty(t, plugins[0].Signature)
@@ -884,7 +884,7 @@ func TestProcessPrepackagedPlugins(t *testing.T) {
err = testlib.CopyFile(testPlugin2SignaturePath, filepath.Join(prepackagedPluginsDir, "testplugin2.tar.gz.sig")) err = testlib.CopyFile(testPlugin2SignaturePath, filepath.Join(prepackagedPluginsDir, "testplugin2.tar.gz.sig"))
require.NoError(t, err) require.NoError(t, err)
plugins := th.App.Srv().processPrepackagedPlugins(prepackagedPluginsDir) plugins := th.App.ch.processPrepackagedPlugins(prepackagedPluginsDir)
require.Len(t, plugins, 2) require.Len(t, plugins, 2)
require.Contains(t, []string{"testplugin", "testplugin2"}, plugins[0].Manifest.Id) require.Contains(t, []string{"testplugin", "testplugin2"}, plugins[0].Manifest.Id)
require.NotEmpty(t, plugins[0].Signature) require.NotEmpty(t, plugins[0].Signature)
@@ -921,7 +921,7 @@ func TestProcessPrepackagedPlugins(t *testing.T) {
err = testlib.CopyFile(testPlugin2SignaturePath, filepath.Join(prepackagedPluginsDir, "testplugin2.tar.gz.sig")) err = testlib.CopyFile(testPlugin2SignaturePath, filepath.Join(prepackagedPluginsDir, "testplugin2.tar.gz.sig"))
require.NoError(t, err) require.NoError(t, err)
plugins := th.App.Srv().processPrepackagedPlugins(prepackagedPluginsDir) plugins := th.App.ch.processPrepackagedPlugins(prepackagedPluginsDir)
require.Len(t, plugins, 2) require.Len(t, plugins, 2)
require.Contains(t, []string{"testplugin", "testplugin2"}, plugins[0].Manifest.Id) require.Contains(t, []string{"testplugin", "testplugin2"}, plugins[0].Manifest.Id)
require.NotEmpty(t, plugins[0].Signature) require.NotEmpty(t, plugins[0].Signature)

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

@@ -47,7 +47,6 @@ import (
"github.com/mattermost/mattermost-server/v6/einterfaces" "github.com/mattermost/mattermost-server/v6/einterfaces"
"github.com/mattermost/mattermost-server/v6/jobs" "github.com/mattermost/mattermost-server/v6/jobs"
"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/services/awsmeter" "github.com/mattermost/mattermost-server/v6/services/awsmeter"
"github.com/mattermost/mattermost-server/v6/services/cache" "github.com/mattermost/mattermost-server/v6/services/cache"
"github.com/mattermost/mattermost-server/v6/services/httpservice" "github.com/mattermost/mattermost-server/v6/services/httpservice"
@@ -108,10 +107,6 @@ type Server struct {
goroutineCount int32 goroutineCount int32
goroutineExitSignal chan struct{} goroutineExitSignal chan struct{}
PluginsEnvironment *plugin.Environment
PluginConfigListenerId string
PluginsLock sync.RWMutex
EmailService *email.Service EmailService *email.Service
hubs []*Hub hubs []*Hub
@@ -469,7 +464,7 @@ func NewServer(options ...Option) (*Server, error) {
}) })
s.telemetryService = telemetry.New(s, s.Store, s.SearchEngine, s.Log) s.telemetryService = telemetry.New(New(ServerConnector(s.Channels())), s.Store, s.SearchEngine, s.Log)
emailService, err := email.NewService(email.ServiceConfig{ emailService, err := email.NewService(email.ServiceConfig{
ConfigFn: s.Config, ConfigFn: s.Config,
@@ -689,15 +684,6 @@ func NewServer(options ...Option) (*Server, error) {
s.initPostMetadata() s.initPostMetadata()
s.initPlugins(c, *s.Config().PluginSettings.Directory, *s.Config().PluginSettings.ClientDirectory)
s.AddConfigListener(func(prevCfg, cfg *model.Config) {
if *cfg.PluginSettings.Enable {
s.initPlugins(c, *cfg.PluginSettings.Directory, *s.Config().PluginSettings.ClientDirectory)
} else {
s.ShutDownPlugins()
}
})
// Dump the image cache if the proxy settings have changed. (need switch URLs to the correct proxy) // Dump the image cache if the proxy settings have changed. (need switch URLs to the correct proxy)
s.AddConfigListener(func(oldCfg, newCfg *model.Config) { s.AddConfigListener(func(oldCfg, newCfg *model.Config) {
if (oldCfg.ImageProxySettings.Enable != newCfg.ImageProxySettings.Enable) || if (oldCfg.ImageProxySettings.Enable != newCfg.ImageProxySettings.Enable) ||
@@ -1002,17 +988,7 @@ func (s *Server) Shutdown() {
defer sentry.Flush(2 * time.Second) defer sentry.Flush(2 * time.Second)
// Stop products.
// This needs to happen before because products are dependent
// on parent services.
for name, product := range s.products {
if err := product.Stop(); err != nil {
mlog.Warn("Unable to cleanly stop product", mlog.String("name", name), mlog.Err(err))
}
}
s.HubStop() s.HubStop()
s.ShutDownPlugins()
s.RemoveLicenseListener(s.licenseListenerId) s.RemoveLicenseListener(s.licenseListenerId)
s.RemoveLicenseListener(s.loggerLicenseListenerId) s.RemoveLicenseListener(s.loggerLicenseListenerId)
s.RemoveClusterLeaderChangedListener(s.clusterLeaderListenerId) s.RemoveClusterLeaderChangedListener(s.clusterLeaderListenerId)
@@ -1096,6 +1072,15 @@ func (s *Server) Shutdown() {
mlog.Info("Server stopped") mlog.Info("Server stopped")
// Stop products.
// This needs to happen last because products are dependent
// on parent services.
for name, product := range s.products {
if err2 := product.Stop(); err2 != nil {
mlog.Warn("Unable to cleanly stop product", mlog.String("name", name), mlog.Err(err2))
}
}
// shutdown main and notification loggers which will flush any remaining log records. // shutdown main and notification loggers which will flush any remaining log records.
timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), time.Second*15) timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), time.Second*15)
defer timeoutCancel() defer timeoutCancel()
@@ -1204,6 +1189,14 @@ func stripPort(hostport string) string {
} }
func (s *Server) Start() error { func (s *Server) Start() error {
// Start products.
// This needs to happen before because products are dependent on the HTTP server.
for name, product := range s.products {
if err := product.Start(); err != nil {
return errors.Wrapf(err, "Unable to start %s", name)
}
}
mlog.Info("Starting Server...") mlog.Info("Starting Server...")
var handler http.Handler = s.RootRouter var handler http.Handler = s.RootRouter
@@ -1406,14 +1399,6 @@ func (s *Server) Start() error {
mlog.Error("Error starting inter-cluster services", mlog.Err(err)) mlog.Error("Error starting inter-cluster services", mlog.Err(err))
} }
// Start products.
// This needs to happen after the server has started.
for name, product := range s.products {
if err := product.Start(); err != nil {
return errors.Wrapf(err, "Unable to start %s", name)
}
}
return nil return nil
} }