MM-16261 - Store Plugin in File Store (#11511)
* Implemneted saving the plugin bundle on the file store upon plugin upload * Fixed compilation error * Fixed compilation issue * Added deletion from file store upon plugin uninstall * Added condition to delete from store only when exists. Added case of saving the bundle to the store when uploading from url. Added checks in plugin tests * Fixed compilation error * Moved storage of plugin bundle within app/installPlugin * Moved storing to filestore before enabling the plugin * Fixed error handling * Code styling improvements * Minor styling fix
Этот коммит содержится в:
коммит произвёл
Jesse Hallam
родитель
b464f31b38
Коммит
859c571558
@@ -6,6 +6,8 @@
|
||||
package api4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
@@ -124,13 +126,19 @@ func installPluginFromUrl(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Query().Get("force") == "true" {
|
||||
force = true
|
||||
}
|
||||
manifest, unpackErr := c.App.InstallPlugin(resp.Body, force)
|
||||
|
||||
fileBytes, readErr := ioutil.ReadAll(resp.Body)
|
||||
if readErr != nil {
|
||||
c.Err = model.NewAppError("installPluginFromUrl", "api.plugin.install.reading_stream_failed.app_error", nil, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
manifest, unpackErr := c.App.InstallPlugin(bytes.NewReader(fileBytes), force)
|
||||
|
||||
if unpackErr != nil {
|
||||
c.Err = unpackErr
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
w.Write([]byte(manifest.ToJson()))
|
||||
}
|
||||
|
||||
@@ -57,6 +57,11 @@ func TestPlugin(t *testing.T) {
|
||||
CheckNoError(t, resp)
|
||||
assert.Equal(t, "testplugin", manifest.Id)
|
||||
|
||||
// Stored in File Store: Install Plugin from URL case
|
||||
pluginStored, err := th.App.FileExists("./plugins/" + manifest.Id + ".tar.gz")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, pluginStored)
|
||||
|
||||
th.App.RemovePlugin(manifest.Id)
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false })
|
||||
@@ -89,6 +94,11 @@ func TestPlugin(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "testplugin", manifest.Id)
|
||||
|
||||
// Stored in File Store: Upload Plugin case
|
||||
pluginStored, err = th.App.FileExists("./plugins/" + manifest.Id + ".tar.gz")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, pluginStored)
|
||||
|
||||
// Upload error cases
|
||||
_, resp = th.SystemAdminClient.UploadPlugin(bytes.NewReader([]byte("badfile")))
|
||||
CheckBadRequestStatus(t, resp)
|
||||
|
||||
@@ -17,11 +17,11 @@ import (
|
||||
)
|
||||
|
||||
// InstallPlugin unpacks and installs a plugin but does not enable or activate it.
|
||||
func (a *App) InstallPlugin(pluginFile io.Reader, replace bool) (*model.Manifest, *model.AppError) {
|
||||
func (a *App) InstallPlugin(pluginFile io.ReadSeeker, replace bool) (*model.Manifest, *model.AppError) {
|
||||
return a.installPlugin(pluginFile, replace)
|
||||
}
|
||||
|
||||
func (a *App) installPlugin(pluginFile io.Reader, replace bool) (*model.Manifest, *model.AppError) {
|
||||
func (a *App) installPlugin(pluginFile io.ReadSeeker, replace bool) (*model.Manifest, *model.AppError) {
|
||||
pluginsEnvironment := a.GetPluginsEnvironment()
|
||||
if pluginsEnvironment == nil {
|
||||
return nil, model.NewAppError("installPlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
@@ -83,6 +83,14 @@ func (a *App) installPlugin(pluginFile io.Reader, replace bool) (*model.Manifest
|
||||
return nil, model.NewAppError("installPlugin", "app.plugin.mvdir.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// Store bundle in the file store to allow access from other servers.
|
||||
pluginFile.Seek(0, 0)
|
||||
|
||||
storePluginFileName := filepath.Join("./plugins", manifest.Id) + ".tar.gz"
|
||||
if _, err := a.WriteFile(pluginFile, storePluginFileName); err != nil {
|
||||
return nil, model.NewAppError("uploadPlugin", "app.plugin.store_bundle.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
if stashed != nil && stashed.Enable {
|
||||
a.EnablePlugin(manifest.Id)
|
||||
}
|
||||
@@ -138,5 +146,18 @@ func (a *App) removePlugin(id string) *model.AppError {
|
||||
return model.NewAppError("removePlugin", "app.plugin.remove.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// Remove bundle from the file store.
|
||||
storePluginFileName := filepath.Join("./plugins", manifest.Id) + ".tar.gz"
|
||||
bundleExist, fileErr := a.FileExists(storePluginFileName)
|
||||
if fileErr != nil {
|
||||
return model.NewAppError("removePlugin", "app.plugin.remove_bundle.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
if bundleExist {
|
||||
if err := a.RemoveFile(storePluginFileName); err != nil {
|
||||
return model.NewAppError("removePlugin", "app.plugin.remove_bundle.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
12
i18n/en.json
12
i18n/en.json
@@ -1512,6 +1512,10 @@
|
||||
"id": "api.plugin.install.invalid_url.app_error",
|
||||
"translation": "An invalid url was given to download the plugin."
|
||||
},
|
||||
{
|
||||
"id": "api.plugin.install.reading_stream_failed.app_error",
|
||||
"translation": "An error ocurred reading the plugin file stream."
|
||||
},
|
||||
{
|
||||
"id": "api.plugin.upload.array.app_error",
|
||||
"translation": "File array is empty in multipart/form request"
|
||||
@@ -3430,6 +3434,14 @@
|
||||
"id": "app.plugin.remove.app_error",
|
||||
"translation": "Unable to delete plugin"
|
||||
},
|
||||
{
|
||||
"id": "app.plugin.remove_bundle.app_error",
|
||||
"translation": "Unable to remove plugin bundle from file store."
|
||||
},
|
||||
{
|
||||
"id": "app.plugin.store_bundle.app_error",
|
||||
"translation": "Unable to store the plugin to the configured file store."
|
||||
},
|
||||
{
|
||||
"id": "app.plugin.upload_disabled.app_error",
|
||||
"translation": "Plugins and/or plugin uploads have been disabled."
|
||||
|
||||
Ссылка в новой задаче
Block a user