MM-27570,MM-27757 - Activate/Deactivate plugins concurrently (#15244)

* Start plugins concurrently

* Determine which plugins need to be activated/deactivated before changing their state

* Test activation/deactivation of plugins in TestSyncPluginsActiveState

* Change test comments

* remove unneeded temp var
Этот коммит содержится в:
Michael Kochell
2020-08-27 09:22:20 -04:00
коммит произвёл GitHub
родитель eaabf96b1b
Коммит 2029a3b48a
2 изменённых файлов: 88 добавлений и 22 удалений

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

@@ -86,46 +86,52 @@ func (a *App) SyncPluginsActiveState() {
return
}
// Deactivate any plugins that have been disabled.
// Determine which plugins need to be activated or deactivated.
disabledPlugins := []*model.BundleInfo{}
enabledPlugins := []*model.BundleInfo{}
for _, plugin := range availablePlugins {
// Determine if plugin is enabled
pluginId := plugin.Manifest.Id
pluginEnabled := false
if state, ok := config.PluginStates[pluginId]; ok {
pluginEnabled = state.Enable
}
// If it's not enabled we need to deactivate it
if !pluginEnabled {
deactivated := pluginsEnvironment.Deactivate(pluginId)
if pluginEnabled {
enabledPlugins = append(enabledPlugins, plugin)
} else {
disabledPlugins = append(disabledPlugins, plugin)
}
}
// Concurrently activate/deactivate each plugin appropriately.
var wg sync.WaitGroup
// Deactivate any plugins that have been disabled.
for _, plugin := range disabledPlugins {
wg.Add(1)
go func(plugin *model.BundleInfo) {
defer wg.Done()
deactivated := pluginsEnvironment.Deactivate(plugin.Manifest.Id)
if deactivated && plugin.Manifest.HasClient() {
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PLUGIN_DISABLED, "", "", "", nil)
message.Add("manifest", plugin.Manifest.ClientManifest())
a.Publish(message)
}
}
}(plugin)
}
// Activate any plugins that have been enabled
for _, plugin := range availablePlugins {
if plugin.Manifest == nil {
plugin.WrapLogger(a.Log()).Error("Plugin manifest could not be loaded", mlog.Err(plugin.ManifestError))
continue
}
for _, plugin := range enabledPlugins {
wg.Add(1)
go func(plugin *model.BundleInfo) {
defer wg.Done()
// Determine if plugin is enabled
pluginId := plugin.Manifest.Id
pluginEnabled := false
if state, ok := config.PluginStates[pluginId]; ok {
pluginEnabled = state.Enable
}
// Activate plugin if enabled
if pluginEnabled {
pluginId := plugin.Manifest.Id
updatedManifest, activated, err := pluginsEnvironment.Activate(pluginId)
if err != nil {
plugin.WrapLogger(a.Log()).Error("Unable to activate plugin", mlog.Err(err))
continue
return
}
if activated {
@@ -134,8 +140,9 @@ func (a *App) SyncPluginsActiveState() {
a.Log().Error("Failed to notify cluster on plugin enable", mlog.Err(err))
}
}
}
}(plugin)
}
wg.Wait()
} else { // If plugins are disabled, shutdown plugins.
pluginsEnvironment.Shutdown()
}

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

@@ -629,6 +629,65 @@ func TestPluginSync(t *testing.T) {
}
}
func TestSyncPluginsActiveState(t *testing.T) {
th := Setup(t)
defer th.TearDown()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.PluginSettings.Enable = true
})
env := th.App.GetPluginsEnvironment()
require.NotNil(t, env)
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.PluginSettings.RequirePluginSignature = false
})
path, _ := fileutils.FindDir("tests")
fileReader, err := os.Open(filepath.Join(path, "testplugin.tar.gz"))
require.NoError(t, err)
defer fileReader.Close()
_, appErr := th.App.WriteFile(fileReader, th.App.getBundleStorePath("testplugin"))
checkNoError(t, appErr)
// Sync with file store so the plugin environment has access to this plugin.
appErr = th.App.SyncPlugins()
checkNoError(t, appErr)
// Verify the plugin was installed and set to deactivated.
pluginStatus, err := env.Statuses()
require.Nil(t, err)
require.Len(t, pluginStatus, 1)
require.Equal(t, pluginStatus[0].PluginId, "testplugin")
require.Equal(t, pluginStatus[0].State, model.PluginStateNotRunning)
// Enable plugin by setting setting config. This implicitly calls SyncPluginsActiveState through a config listener.
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.PluginSettings.PluginStates["testplugin"] = &model.PluginState{Enable: true}
})
// Verify the plugin was activated due to config change.
pluginStatus, err = env.Statuses()
require.Nil(t, err)
require.Len(t, pluginStatus, 1)
require.Equal(t, pluginStatus[0].PluginId, "testplugin")
require.Equal(t, pluginStatus[0].State, model.PluginStateRunning)
// Disable plugin by setting config. This implicitly calls SyncPluginsActiveState through a config listener.
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.PluginSettings.PluginStates["testplugin"] = &model.PluginState{Enable: false}
})
// Verify the plugin was deactivated due to config change.
pluginStatus, err = env.Statuses()
require.Nil(t, err)
require.Len(t, pluginStatus, 1)
require.Equal(t, pluginStatus[0].PluginId, "testplugin")
require.Equal(t, pluginStatus[0].State, model.PluginStateNotRunning)
}
func TestPluginPanicLogs(t *testing.T) {
t.Run("should panic", func(t *testing.T) {
th := Setup(t).InitBasic()