summaryrefslogtreecommitdiffstats
path: root/app/plugin_install.go
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2018-06-25 12:33:13 -0700
committerGitHub <noreply@github.com>2018-06-25 12:33:13 -0700
commit1e5c432e1029601a664454388ae366ef69618d62 (patch)
treecb9e8bfb66640ac3b29c934bb2c3202d25aeb368 /app/plugin_install.go
parentecefa6cdd1e7376046bbec82c1b47f7756fea646 (diff)
downloadchat-1e5c432e1029601a664454388ae366ef69618d62.tar.gz
chat-1e5c432e1029601a664454388ae366ef69618d62.tar.bz2
chat-1e5c432e1029601a664454388ae366ef69618d62.zip
MM-10702 Moving plugins to use hashicorp go-plugin. (#8978)
* Moving plugins to use hashicorp go-plugin. * Tweaks from feedback.
Diffstat (limited to 'app/plugin_install.go')
-rw-r--r--app/plugin_install.go119
1 files changed, 119 insertions, 0 deletions
diff --git a/app/plugin_install.go b/app/plugin_install.go
new file mode 100644
index 000000000..c03ad2108
--- /dev/null
+++ b/app/plugin_install.go
@@ -0,0 +1,119 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package app
+
+import (
+ "io"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "path/filepath"
+
+ "github.com/mattermost/mattermost-server/mlog"
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/mattermost/mattermost-server/plugin"
+ "github.com/mattermost/mattermost-server/utils"
+)
+
+// InstallPlugin unpacks and installs a plugin but does not enable or activate it.
+func (a *App) InstallPlugin(pluginFile io.Reader) (*model.Manifest, *model.AppError) {
+ return a.installPlugin(pluginFile)
+}
+
+func (a *App) installPlugin(pluginFile io.Reader) (*model.Manifest, *model.AppError) {
+ if a.Plugins == nil || !*a.Config().PluginSettings.Enable {
+ return nil, model.NewAppError("installPlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
+ }
+
+ tmpDir, err := ioutil.TempDir("", "plugintmp")
+ if err != nil {
+ return nil, model.NewAppError("installPlugin", "app.plugin.filesystem.app_error", nil, err.Error(), http.StatusInternalServerError)
+ }
+ defer os.RemoveAll(tmpDir)
+
+ if err := utils.ExtractTarGz(pluginFile, tmpDir); err != nil {
+ return nil, model.NewAppError("installPlugin", "app.plugin.extract.app_error", nil, err.Error(), http.StatusBadRequest)
+ }
+
+ tmpPluginDir := tmpDir
+ dir, err := ioutil.ReadDir(tmpDir)
+ if err != nil {
+ return nil, model.NewAppError("installPlugin", "app.plugin.filesystem.app_error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ if len(dir) == 1 && dir[0].IsDir() {
+ tmpPluginDir = filepath.Join(tmpPluginDir, dir[0].Name())
+ }
+
+ manifest, _, err := model.FindManifest(tmpPluginDir)
+ if err != nil {
+ return nil, model.NewAppError("installPlugin", "app.plugin.manifest.app_error", nil, err.Error(), http.StatusBadRequest)
+ }
+
+ if !plugin.IsValidId(manifest.Id) {
+ return nil, model.NewAppError("installPlugin", "app.plugin.invalid_id.app_error", map[string]interface{}{"Min": plugin.MinIdLength, "Max": plugin.MaxIdLength, "Regex": plugin.ValidId.String()}, "", http.StatusBadRequest)
+ }
+
+ bundles, err := a.Plugins.Available()
+ if err != nil {
+ return nil, model.NewAppError("installPlugin", "app.plugin.install.app_error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ // Check that there is no plugin with the same ID
+ for _, bundle := range bundles {
+ if bundle.Manifest != nil && bundle.Manifest.Id == manifest.Id {
+ return nil, model.NewAppError("installPlugin", "app.plugin.install_id.app_error", nil, "", http.StatusBadRequest)
+ }
+ }
+
+ pluginPath := filepath.Join(*a.Config().PluginSettings.Directory, manifest.Id)
+ err = utils.CopyDir(tmpPluginDir, pluginPath)
+ if err != nil {
+ return nil, model.NewAppError("installPlugin", "app.plugin.mvdir.app_error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := a.notifyPluginStatusesChanged(); err != nil {
+ mlog.Error("failed to notify plugin status changed", mlog.Err(err))
+ }
+
+ return manifest, nil
+}
+
+func (a *App) RemovePlugin(id string) *model.AppError {
+ return a.removePlugin(id)
+}
+
+func (a *App) removePlugin(id string) *model.AppError {
+ if a.Plugins == nil || !*a.Config().PluginSettings.Enable {
+ return model.NewAppError("removePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
+ }
+
+ plugins, err := a.Plugins.Available()
+ if err != nil {
+ return model.NewAppError("removePlugin", "app.plugin.deactivate.app_error", nil, err.Error(), http.StatusBadRequest)
+ }
+
+ var manifest *model.Manifest
+ var pluginPath string
+ for _, p := range plugins {
+ if p.Manifest != nil && p.Manifest.Id == id {
+ manifest = p.Manifest
+ pluginPath = filepath.Dir(p.ManifestPath)
+ break
+ }
+ }
+
+ if manifest == nil {
+ return model.NewAppError("removePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusBadRequest)
+ }
+
+ a.Plugins.Deactivate(id)
+
+ err = os.RemoveAll(pluginPath)
+ if err != nil {
+ return model.NewAppError("removePlugin", "app.plugin.remove.app_error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ return nil
+}