diff --git a/control/control.go b/control/control.go index 490771e56..7c8990b1f 100644 --- a/control/control.go +++ b/control/control.go @@ -391,7 +391,7 @@ func (p *pluginControl) Start() error { }).Warn("Auto-loading of plugin '", fileName, "' skipped (plugin not executable)") continue } - rp, err := core.NewRequestedPlugin(path.Join(fullPath, fileName)) + rp, err := core.NewRequestedPlugin(path.Join(fullPath, fileName), GetDefaultConfig().TempDirPath, nil) if err != nil { controlLogger.WithFields(log.Fields{ "_block": "start", @@ -582,7 +582,6 @@ func (p *pluginControl) returnPluginDetails(rp *core.RequestedPlugin) (*pluginDe details.Path = rp.Path() details.CheckSum = rp.CheckSum() details.Signature = rp.Signature() - details.IsAutoLoaded = rp.AutoLoaded() if filepath.Ext(rp.Path()) == ".aci" { f, err := os.Open(rp.Path()) @@ -1066,6 +1065,10 @@ func (p *pluginControl) GetAutodiscoverPaths() []string { return p.autodiscoverPaths } +func (p *pluginControl) GetTempDir() string { + return p.Config.TempDirPath +} + func (p *pluginControl) SetPluginTrustLevel(trust int) { p.pluginTrust = trust } diff --git a/control/control_grpc_server_test.go b/control/control_grpc_server_test.go index 3fdcb32cf..525c2ec15 100644 --- a/control/control_grpc_server_test.go +++ b/control/control_grpc_server_test.go @@ -88,7 +88,7 @@ func TestGRPCServerScheduler(t *testing.T) { // collector -- mock // processor -- passthru // publisher -- file - mock, err := core.NewRequestedPlugin(fixtures.PluginPathMock1) + mock, err := core.NewRequestedPlugin(fixtures.PluginPathMock1, GetDefaultConfig().TempDirPath, nil) if err != nil { log.Fatal(err) } @@ -99,7 +99,7 @@ func TestGRPCServerScheduler(t *testing.T) { }) }) <-lpe.done - passthru, err := core.NewRequestedPlugin(helper.PluginFilePath("snap-plugin-processor-passthru")) + passthru, err := core.NewRequestedPlugin(helper.PluginFilePath("snap-plugin-processor-passthru"), GetDefaultConfig().TempDirPath, nil) if err != nil { log.Fatal(err) } @@ -115,7 +115,7 @@ func TestGRPCServerScheduler(t *testing.T) { typeName: catalogedPassthru.TypeName(), } <-lpe.done - filepub, err := core.NewRequestedPlugin(helper.PluginFilePath("snap-plugin-publisher-mock-file")) + filepub, err := core.NewRequestedPlugin(helper.PluginFilePath("snap-plugin-publisher-mock-file"), GetDefaultConfig().TempDirPath, nil) if err != nil { log.Fatal(err) } diff --git a/control/control_test.go b/control/control_test.go index f9dad8da6..509a07a24 100644 --- a/control/control_test.go +++ b/control/control_test.go @@ -1,5 +1,4 @@ // +build legacy - /* http://www.apache.org/licenses/LICENSE-2.0.txt @@ -94,7 +93,8 @@ func load(c *pluginControl, paths ...string) (core.CatalogedPlugin, serror.SnapE // 3 times before letting the error through. Hopefully this cuts down on the number of Travis failures var e serror.SnapError var p core.CatalogedPlugin - rp, err := core.NewRequestedPlugin(paths[0]) + + rp, err := core.NewRequestedPlugin(paths[0], GetDefaultConfig().TempDirPath, nil) if err != nil { return nil, serror.New(err) } @@ -191,7 +191,7 @@ func TestSwapPlugin(t *testing.T) { }) }) - mockRP, mErr := core.NewRequestedPlugin(fixtures.PluginPathMock1) + mockRP, mErr := core.NewRequestedPlugin(fixtures.PluginPathMock1, GetDefaultConfig().TempDirPath, nil) Convey("Requested collector plugin should not error", func() { So(mErr, ShouldBeNil) }) @@ -235,7 +235,7 @@ func TestSwapPlugin(t *testing.T) { Convey("Swap plugin with a different type of plugin", func() { filePath := helper.PluginFilePath("snap-plugin-publisher-mock-file") So(filePath, ShouldNotBeEmpty) - fileRP, pErr := core.NewRequestedPlugin(fixtures.PluginPathMock1) + fileRP, pErr := core.NewRequestedPlugin(fixtures.PluginPathMock1, GetDefaultConfig().TempDirPath, nil) Convey("Requested publisher plugin should not error", func() { So(pErr, ShouldBeNil) Convey("Swapping collector and publisher plugins", func() { @@ -258,7 +258,7 @@ func TestSwapPlugin(t *testing.T) { pm.ExistingPlugin = lp c.pluginManager = pm - mockRP, mErr := core.NewRequestedPlugin(fixtures.PluginPathMock1) + mockRP, mErr := core.NewRequestedPlugin(fixtures.PluginPathMock1, GetDefaultConfig().TempDirPath, nil) So(mErr, ShouldBeNil) err := c.SwapPlugins(mockRP, lp) Convey("So err should be received if rollback fails", func() { @@ -1677,8 +1677,8 @@ func TestMetricSubscriptionToNewVersion(t *testing.T) { c.eventManager.RegisterHandler("TestMetricSubscriptionToNewVersion", lpe) c.Start() _, err := load(c, helper.PluginFilePath("snap-plugin-collector-mock1")) - <-lpe.load So(err, ShouldBeNil) + <-lpe.load So(len(c.pluginManager.all()), ShouldEqual, 1) lp, err2 := c.pluginManager.get("collector" + core.Separator + "mock" + core.Separator + "1") So(err2, ShouldBeNil) @@ -1752,8 +1752,8 @@ func TestMetricSubscriptionToOlderVersion(t *testing.T) { c.eventManager.RegisterHandler("TestMetricSubscriptionToOlderVersion", lpe) c.Start() _, err := load(c, helper.PluginFilePath("snap-plugin-collector-mock2")) - <-lpe.load So(err, ShouldBeNil) + <-lpe.load So(len(c.pluginManager.all()), ShouldEqual, 1) lp, err2 := c.pluginManager.get("collector" + core.Separator + "mock" + core.Separator + "2") So(err2, ShouldBeNil) diff --git a/control/plugin_manager.go b/control/plugin_manager.go index fb9af8e60..378f0afd8 100644 --- a/control/plugin_manager.go +++ b/control/plugin_manager.go @@ -156,15 +156,14 @@ func (l *loadedPlugins) findLatest(typeName, name string) (*loadedPlugin, error) // the struct representing a plugin that is loaded into snap type pluginDetails struct { - CheckSum [sha256.Size]byte - Exec []string - ExecPath string - IsPackage bool - IsAutoLoaded bool - Manifest *schema.ImageManifest - Path string - Signed bool - Signature []byte + CheckSum [sha256.Size]byte + Exec []string + ExecPath string + IsPackage bool + Manifest *schema.ImageManifest + Path string + Signed bool + Signature []byte } type loadedPlugin struct { @@ -318,6 +317,7 @@ func (p *pluginManager) LoadPlugin(details *pluginDetails, emitter gomit.Emitter "_block": "load-plugin", "path": filepath.Base(lPlugin.Details.Exec[0]), }).Info("plugin load called") + // We will create commands by appending the ExecPath to the actual command. // The ExecPath is a temporary location where the plugin/package will be // run from. @@ -325,6 +325,7 @@ func (p *pluginManager) LoadPlugin(details *pluginDetails, emitter gomit.Emitter for i, e := range lPlugin.Details.Exec { commands[i] = filepath.Join(lPlugin.Details.ExecPath, e) } + ePlugin, err := plugin.NewExecutablePlugin( p.GenerateArgs(int(log.GetLevel())), commands...) @@ -575,35 +576,28 @@ func (p *pluginManager) UnloadPlugin(pl core.Plugin) (*loadedPlugin, serror.Snap return nil, se } - // If the plugin has been uploaded via REST API - // aka, was not auto loaded from auto_discover_path - // nor loaded from tests - // then do clean up - if !plugin.Details.IsAutoLoaded { + pmLogger.WithFields(log.Fields{ + "plugin-type": plugin.TypeName(), + "plugin-name": plugin.Name(), + "plugin-version": plugin.Version(), + "plugin-path": plugin.Details.Path, + }).Debugf("Removing plugin") + if err := os.RemoveAll(filepath.Dir(plugin.Details.Path)); err != nil { pmLogger.WithFields(log.Fields{ "plugin-type": plugin.TypeName(), "plugin-name": plugin.Name(), "plugin-version": plugin.Version(), "plugin-path": plugin.Details.Path, - }).Debugf("Removing plugin") - if err := os.RemoveAll(filepath.Dir(plugin.Details.Path)); err != nil { - pmLogger.WithFields(log.Fields{ - "plugin-type": plugin.TypeName(), - "plugin-name": plugin.Name(), - "plugin-version": plugin.Version(), - "plugin-path": plugin.Details.Path, - }).Error(err) - se := serror.New(err) - se.SetFields(map[string]interface{}{ - "plugin-type": plugin.TypeName(), - "plugin-name": plugin.Name(), - "plugin-version": plugin.Version(), - "plugin-path": plugin.Details.Path, - }) - return nil, se - } + }).Error(err) + se := serror.New(err) + se.SetFields(map[string]interface{}{ + "plugin-type": plugin.TypeName(), + "plugin-name": plugin.Name(), + "plugin-version": plugin.Version(), + "plugin-path": plugin.Details.Path, + }) + return nil, se } - p.loadedPlugins.remove(plugin.Key()) // Remove any metrics from the catalog if this was a collector diff --git a/control/plugin_manager_test.go b/control/plugin_manager_test.go index 97cc2471a..8806f1495 100644 --- a/control/plugin_manager_test.go +++ b/control/plugin_manager_test.go @@ -22,18 +22,20 @@ limitations under the License. package control import ( + "bufio" "errors" + "os" "path/filepath" "testing" "time" - . "github.com/smartystreets/goconvey/convey" - "github.com/intelsdi-x/snap/control/fixtures" "github.com/intelsdi-x/snap/control/plugin" "github.com/intelsdi-x/snap/core" "github.com/intelsdi-x/snap/core/ctypes" "github.com/intelsdi-x/snap/core/serror" + "github.com/intelsdi-x/snap/pkg/fileutils" + . "github.com/smartystreets/goconvey/convey" ) func TestLoadedPlugins(t *testing.T) { @@ -65,18 +67,41 @@ func TestLoadedPlugins(t *testing.T) { }) } -func loadPlugin(p *pluginManager, path string) (*loadedPlugin, serror.SnapError) { +func loadPlugin(p *pluginManager, fileName string) (*loadedPlugin, serror.SnapError) { // This is a Travis optimized loading of plugins. From time to time, tests will error in Travis // due to a timeout when waiting for a response from a plugin. We are going to attempt loading a plugin // 3 times before letting the error through. Hopefully this cuts down on the number of Travis failures var e serror.SnapError var lp *loadedPlugin + file, err := os.Open(fileName) + if err != nil { + return nil, serror.New(err) + } + defer file.Close() + + info, err := file.Stat() + if err != nil { + return nil, serror.New(err) + } + size := info.Size() + bytes := make([]byte, size) + buffer := bufio.NewReader(file) + _, err = buffer.Read(bytes) + if err != nil { + return nil, serror.New(err) + } + + path, err := fileutils.WriteFile(filepath.Base(fileName), GetDefaultConfig().TempDirPath, bytes) + if err != nil { + return nil, serror.New(err) + } + details := &pluginDetails{ - Path: path, - ExecPath: filepath.Dir(path), - Exec: []string{filepath.Base(path)}, - IsAutoLoaded: true, + Path: path, + ExecPath: filepath.Dir(path), + Exec: []string{filepath.Base(path)}, } + for i := 0; i < 3; i++ { lp, e = p.LoadPlugin(details, nil) if e == nil { diff --git a/control/subscription_group_medium_test.go b/control/subscription_group_medium_test.go index a558d303d..c49da8504 100644 --- a/control/subscription_group_medium_test.go +++ b/control/subscription_group_medium_test.go @@ -947,7 +947,7 @@ func loadPlg(c *pluginControl, paths ...string) (core.CatalogedPlugin, serror.Sn // 3 times before letting the error through. Hopefully this cuts down on the number of Travis failures var e serror.SnapError var p core.CatalogedPlugin - rp, err := core.NewRequestedPlugin(paths[0]) + rp, err := core.NewRequestedPlugin(paths[0], GetDefaultConfig().TempDirPath, nil) if err != nil { return nil, serror.New(err) } diff --git a/core/plugin.go b/core/plugin.go index 2f269894c..e317bbb6d 100644 --- a/core/plugin.go +++ b/core/plugin.go @@ -20,13 +20,17 @@ limitations under the License. package core import ( + "bufio" "crypto/sha256" "fmt" "io/ioutil" + "os" + "path/filepath" "time" "github.com/intelsdi-x/snap/control/plugin/cpolicy" "github.com/intelsdi-x/snap/core/cdata" + "github.com/intelsdi-x/snap/pkg/fileutils" ) type Plugin interface { @@ -95,21 +99,61 @@ type SubscribedPlugin interface { } type RequestedPlugin struct { - path string - checkSum [sha256.Size]byte - signature []byte - autoLoaded bool -} - -func NewRequestedPlugin(path string) (*RequestedPlugin, error) { - rp := &RequestedPlugin{ - path: path, - signature: nil, - autoLoaded: true, - } - err := rp.generateCheckSum() - if err != nil { - return nil, err + path string + checkSum [sha256.Size]byte + signature []byte +} + +// NewRequestedPlugin returns a Requested Plugin which represents the plugin path and signature +// It takes the full path of the plugin (path), temp path (fileName), and content of the file (b) and returns a requested plugin and error +// The argument b (content of the file) can be nil +func NewRequestedPlugin(path, fileName string, b []byte) (*RequestedPlugin, error) { + var rp *RequestedPlugin + // this case is for the snaptel cli as b is unknown and needs to be read + if b == nil { + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + + info, err := file.Stat() + if err != nil { + return nil, err + } + size := info.Size() + bytes := make([]byte, size) + buffer := bufio.NewReader(file) + _, err = buffer.Read(bytes) + if err != nil { + return nil, err + } + tempFile, err := fileutils.WriteFile(filepath.Base(path), fileName, bytes) + if err != nil { + return nil, err + } + rp = &RequestedPlugin{ + path: tempFile, + signature: nil, + } + genErr := rp.generateCheckSum() + if genErr != nil { + return nil, err + } + } else { + // this is for the REST API as the content is read earlier + tmpFile, err := fileutils.WriteFile(filepath.Base(path), fileName, b) + if err != nil { + return nil, nil + } + rp = &RequestedPlugin{ + path: tmpFile, + signature: nil, + } + genErr := rp.generateCheckSum() + if genErr != nil { + return nil, err + } } return rp, nil } @@ -126,10 +170,6 @@ func (p *RequestedPlugin) Signature() []byte { return p.signature } -func (p *RequestedPlugin) AutoLoaded() bool { - return p.autoLoaded -} - func (p *RequestedPlugin) SetPath(path string) { p.path = path } @@ -138,10 +178,6 @@ func (p *RequestedPlugin) SetSignature(data []byte) { p.signature = data } -func (p *RequestedPlugin) SetAutoLoaded(isAutoLoaded bool) { - p.autoLoaded = isAutoLoaded -} - func (p *RequestedPlugin) generateCheckSum() error { var b []byte var err error diff --git a/core/plugin_test.go b/core/plugin_test.go index 94c5e7841..99e23a9cf 100644 --- a/core/plugin_test.go +++ b/core/plugin_test.go @@ -24,6 +24,7 @@ package core import ( "crypto/sha256" "io/ioutil" + "os" "path" "testing" @@ -36,13 +37,14 @@ var ( SnapPath = helper.BuildPath PluginPath = helper.PluginFilePath(PluginName) SignatureFile = path.Join(SnapPath, "../pkg/psigning", "snap-plugin-collector-mock1.asc") + TempPath = os.TempDir() ) func TestRequestedPlugin(t *testing.T) { // Creating a plugin request Convey("Creating a plugin request from a valid path", t, func() { - rp, err := NewRequestedPlugin(PluginPath) + rp, err := NewRequestedPlugin(PluginPath, TempPath, nil) Convey("Should not return an error", func() { So(err, ShouldBeNil) @@ -51,7 +53,7 @@ func TestRequestedPlugin(t *testing.T) { }) Convey("Should set the path to the plugin", func() { - So(rp.Path(), ShouldEqual, PluginPath) + So(rp.Path(), ShouldContainSubstring, TempPath) }) Convey("Should generate a checksum for the plugin", func() { So(rp.CheckSum(), ShouldNotBeNil) @@ -78,7 +80,7 @@ func TestRequestedPlugin(t *testing.T) { }) Convey("A signature file can be read in for a plugin request", t, func() { - rp1, err1 := NewRequestedPlugin(PluginPath) + rp1, err1 := NewRequestedPlugin(PluginPath, TempPath, nil) So(err1, ShouldBeNil) err1 = rp1.ReadSignatureFile(SignatureFile) @@ -94,7 +96,7 @@ func TestRequestedPlugin(t *testing.T) { }) }) // Try to create a plugin request from a bad path to a plugin - _, err2 := NewRequestedPlugin(PluginPath + "foo") + _, err2 := NewRequestedPlugin(PluginPath+"foo", TempPath, nil) Convey("An error should be generated when creating a plugin request with non-existent path", t, func() { Convey("So error should not be nil", func() { So(err2, ShouldNotBeNil) @@ -103,7 +105,7 @@ func TestRequestedPlugin(t *testing.T) { // Create a plugin request and try to add a signature from an non-existent signature file Convey("When passing in a non-existent signature file", t, func() { - rp3, err3 := NewRequestedPlugin(PluginPath) + rp3, err3 := NewRequestedPlugin(PluginPath, TempPath, nil) So(err3, ShouldBeNil) err3 = rp3.ReadSignatureFile(SignatureFile + "foo") diff --git a/mgmt/rest/api/metric.go b/mgmt/rest/api/metric.go index 503fb97ee..79b58ffbf 100644 --- a/mgmt/rest/api/metric.go +++ b/mgmt/rest/api/metric.go @@ -15,4 +15,5 @@ type Metrics interface { PluginCatalog() core.PluginCatalog AvailablePlugins() []core.AvailablePlugin GetAutodiscoverPaths() []string + GetTempDir() string } diff --git a/mgmt/rest/common/common.go b/mgmt/rest/common/common.go deleted file mode 100644 index a7bbfb745..000000000 --- a/mgmt/rest/common/common.go +++ /dev/null @@ -1,39 +0,0 @@ -package common - -import ( - "io/ioutil" - "os" - "path/filepath" - "runtime" - - log "github.com/Sirupsen/logrus" - "github.com/intelsdi-x/snap/control" -) - -func WriteFile(filename string, b []byte) (string, error) { - // Create temporary directory - dir, err := ioutil.TempDir(control.GetDefaultConfig().TempDirPath, "snap-plugin-") - if err != nil { - return "", err - } - - f, err := os.Create(filepath.Join(dir, filename)) - if err != nil { - return "", err - } - // Close before load - defer f.Close() - - n, err := f.Write(b) - log.Debugf("wrote %v to %v", n, f.Name()) - if err != nil { - return "", err - } - if runtime.GOOS != "windows" { - err = f.Chmod(0700) - if err != nil { - return "", err - } - } - return f.Name(), nil -} diff --git a/mgmt/rest/v1/fixtures/mock_metric_manager.go b/mgmt/rest/v1/fixtures/mock_metric_manager.go index 02624eaf2..a9d13511d 100644 --- a/mgmt/rest/v1/fixtures/mock_metric_manager.go +++ b/mgmt/rest/v1/fixtures/mock_metric_manager.go @@ -127,6 +127,10 @@ func (m MockManagesMetrics) GetAutodiscoverPaths() []string { return nil } +func (m MockManagesMetrics) GetTempDir() string { + return "" +} + // These constants are the expected plugin responses from running // rest_v1_test.go on the plugin routes found in mgmt/rest/server.go const ( diff --git a/mgmt/rest/v1/plugin.go b/mgmt/rest/v1/plugin.go index 3e327b3b9..80b7f6718 100644 --- a/mgmt/rest/v1/plugin.go +++ b/mgmt/rest/v1/plugin.go @@ -37,7 +37,6 @@ import ( "github.com/intelsdi-x/snap/core" "github.com/intelsdi-x/snap/core/serror" "github.com/intelsdi-x/snap/mgmt/rest/api" - "github.com/intelsdi-x/snap/mgmt/rest/common" "github.com/intelsdi-x/snap/mgmt/rest/v1/rbody" "github.com/julienschmidt/httprouter" ) @@ -68,13 +67,13 @@ func (p *plugin) TypeName() string { } func (s *apiV1) loadPlugin(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + var rp *core.RequestedPlugin mediaType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil { rbody.Write(500, rbody.FromError(err), w) return } if strings.HasPrefix(mediaType, "multipart/") { - var pluginPath string var signature []byte var checkSum [sha256.Size]byte lp := &rbody.PluginsLoaded{} @@ -126,7 +125,7 @@ func (s *apiV1) loadPlugin(w http.ResponseWriter, r *http.Request, _ httprouter. rbody.Write(500, rbody.FromError(e), w) return } - if pluginPath, err = common.WriteFile(p.FileName(), b); err != nil { + if rp, err = core.NewRequestedPlugin(p.FileName(), s.metricManager.GetTempDir(), b); err != nil { rbody.Write(500, rbody.FromError(err), w) return } @@ -146,12 +145,7 @@ func (s *apiV1) loadPlugin(w http.ResponseWriter, r *http.Request, _ httprouter. } i++ } - rp, err := core.NewRequestedPlugin(pluginPath) - if err != nil { - rbody.Write(500, rbody.FromError(err), w) - return - } - rp.SetAutoLoaded(false) + // Sanity check, verify the checkSum on the file sent is the same // as after it is written to disk. if rp.CheckSum() != checkSum { diff --git a/mgmt/rest/v2/mock/mock_metric_manager.go b/mgmt/rest/v2/mock/mock_metric_manager.go index 701b46585..438315392 100644 --- a/mgmt/rest/v2/mock/mock_metric_manager.go +++ b/mgmt/rest/v2/mock/mock_metric_manager.go @@ -127,6 +127,10 @@ func (m MockManagesMetrics) GetAutodiscoverPaths() []string { return nil } +func (m MockManagesMetrics) GetTempDir() string { + return "" +} + // These constants are the expected plugin responses from running // rest_v2_test.go on the plugin routes found in mgmt/rest/server.go const ( diff --git a/mgmt/rest/v2/plugin.go b/mgmt/rest/v2/plugin.go index 30b91e422..f899ee37e 100644 --- a/mgmt/rest/v2/plugin.go +++ b/mgmt/rest/v2/plugin.go @@ -37,7 +37,6 @@ import ( "github.com/intelsdi-x/snap/control" "github.com/intelsdi-x/snap/core" "github.com/intelsdi-x/snap/core/serror" - "github.com/intelsdi-x/snap/mgmt/rest/common" "github.com/julienschmidt/httprouter" ) @@ -87,6 +86,7 @@ func (p *plugin) TypeName() string { } func (s *apiV2) loadPlugin(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + var rp *core.RequestedPlugin mediaType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil { Write(415, FromError(err), w) @@ -94,7 +94,6 @@ func (s *apiV2) loadPlugin(w http.ResponseWriter, r *http.Request, _ httprouter. } if strings.HasPrefix(mediaType, "multipart/") { - var pluginPath string var signature []byte var checkSum [sha256.Size]byte mr := multipart.NewReader(r.Body, params["boundary"]) @@ -144,7 +143,7 @@ func (s *apiV2) loadPlugin(w http.ResponseWriter, r *http.Request, _ httprouter. Write(400, FromError(e), w) return } - if pluginPath, err = common.WriteFile(p.FileName(), b); err != nil { + if rp, err = core.NewRequestedPlugin(p.FileName(), s.metricManager.GetTempDir(), b); err != nil { Write(500, FromError(err), w) return } @@ -164,12 +163,7 @@ func (s *apiV2) loadPlugin(w http.ResponseWriter, r *http.Request, _ httprouter. } i++ } - rp, err := core.NewRequestedPlugin(pluginPath) - if err != nil { - Write(500, FromError(err), w) - return - } - rp.SetAutoLoaded(false) + // Sanity check, verify the checkSum on the file sent is the same // as after it is written to disk. if rp.CheckSum() != checkSum { diff --git a/mgmt/tribe/worker/worker.go b/mgmt/tribe/worker/worker.go index 203c44b73..e5ac569e6 100644 --- a/mgmt/tribe/worker/worker.go +++ b/mgmt/tribe/worker/worker.go @@ -71,6 +71,8 @@ var ( } ) +var TempPath = os.TempDir() + type PluginRequestType int func (p PluginRequestType) String() string { @@ -330,7 +332,7 @@ func (w worker) loadPlugin(plugin core.Plugin) error { logger.Error(err) continue } - rp, err := core.NewRequestedPlugin(f.Name()) + rp, err := core.NewRequestedPlugin(f.Name(), TempPath, nil) if err != nil { logger.Error(err) return err diff --git a/pkg/fileutils/file.go b/pkg/fileutils/file.go new file mode 100644 index 000000000..19498cb22 --- /dev/null +++ b/pkg/fileutils/file.go @@ -0,0 +1,42 @@ +package fileutils + +import ( + "io/ioutil" + "os" + "path/filepath" + "runtime" + + log "github.com/Sirupsen/logrus" +) + +// WriteFile creates a temporary directory for loading plugins +// Plugins loaded by the cli and from the auto-load directory go through this route of copying the plugin binaries to the temp dir and executing from temp +// WriteFile takes the name of the original file (fileName), path to the original file (filePath) and the content of the file (b) +// Returns temporary file path and error +func WriteFile(fileName, filePath string, b []byte) (string, error) { + // Create temporary directory + dir, err := ioutil.TempDir(filePath, "snap-plugin-") + if err != nil { + return "", err + } + + f, err := os.Create(filepath.Join(dir, fileName)) + if err != nil { + return "", err + } + // Close before load + defer f.Close() + + n, err := f.Write(b) + log.Debugf("wrote %v to %v", n, f.Name()) + if err != nil { + return "", err + } + if runtime.GOOS != "windows" { + err = f.Chmod(0700) + if err != nil { + return "", err + } + } + return f.Name(), nil +} diff --git a/plugin/collector/snap-plugin-collector-anothermock1/main_test.go b/plugin/collector/snap-plugin-collector-anothermock1/main_test.go index 4459ccfaa..330870b0e 100644 --- a/plugin/collector/snap-plugin-collector-anothermock1/main_test.go +++ b/plugin/collector/snap-plugin-collector-anothermock1/main_test.go @@ -47,11 +47,15 @@ func TestMockPluginLoad(t *testing.T) { Convey("ensure plugin loads and responds", func() { c := control.New(control.GetDefaultConfig()) c.Start() - rp, _ := core.NewRequestedPlugin(PluginPath) - _, err := c.Load(rp) - - So(err, ShouldBeNil) + rp, err := core.NewRequestedPlugin(PluginPath, c.GetTempDir(), nil) + Convey("Should not return an error when requested for a plugin", func() { + So(err, ShouldBeNil) + }) + + _, err = c.Load(rp) + Convey("should not return an error when loading a plugin", func() { + So(err, ShouldBeNil) + }) }) - }) } diff --git a/plugin/collector/snap-plugin-collector-mock1/main_test.go b/plugin/collector/snap-plugin-collector-mock1/main_test.go index 223e84c8e..a10a2622e 100644 --- a/plugin/collector/snap-plugin-collector-mock1/main_test.go +++ b/plugin/collector/snap-plugin-collector-mock1/main_test.go @@ -48,10 +48,16 @@ func TestMockPluginLoad(t *testing.T) { Convey("ensure plugin loads and responds", func() { c := control.New(control.GetDefaultConfig()) c.Start() - rp, _ := core.NewRequestedPlugin(PluginPath) - _, err := c.Load(rp) + rp, err := core.NewRequestedPlugin(PluginPath, c.GetTempDir(), nil) + Convey("Should not return an error when requested for a plugin", func() { + So(err, ShouldBeNil) + }) + + _, err = c.Load(rp) + Convey("should not return an error when loading a plugin", func() { + So(err, ShouldBeNil) + }) - So(err, ShouldBeNil) }) }) diff --git a/plugin/collector/snap-plugin-collector-mock2-grpc/main_test.go b/plugin/collector/snap-plugin-collector-mock2-grpc/main_test.go index ad7e2539e..92b5c62e0 100644 --- a/plugin/collector/snap-plugin-collector-mock2-grpc/main_test.go +++ b/plugin/collector/snap-plugin-collector-mock2-grpc/main_test.go @@ -47,10 +47,15 @@ func TestMockPluginLoad(t *testing.T) { Convey("ensure plugin loads and responds", func() { c := control.New(control.GetDefaultConfig()) c.Start() - rp, _ := core.NewRequestedPlugin(PluginPath) - _, err := c.Load(rp) - - So(err, ShouldBeNil) + rp, err := core.NewRequestedPlugin(PluginPath, c.GetTempDir(), nil) + Convey("Should not return an error when requested for a plugin", func() { + So(err, ShouldBeNil) + }) + + _, err = c.Load(rp) + Convey("should not return an error when loading a plugin", func() { + So(err, ShouldBeNil) + }) }) }) diff --git a/plugin/collector/snap-plugin-collector-mock2/main_test.go b/plugin/collector/snap-plugin-collector-mock2/main_test.go index 4ba9825e3..a63bc24db 100644 --- a/plugin/collector/snap-plugin-collector-mock2/main_test.go +++ b/plugin/collector/snap-plugin-collector-mock2/main_test.go @@ -47,10 +47,15 @@ func TestMockPluginLoad(t *testing.T) { Convey("ensure plugin loads and responds", func() { c := control.New(control.GetDefaultConfig()) c.Start() - rp, _ := core.NewRequestedPlugin(PluginPath) - _, err := c.Load(rp) - - So(err, ShouldBeNil) + rp, err := core.NewRequestedPlugin(PluginPath, c.GetTempDir(), nil) + Convey("Should not return an error when requested for a plugin", func() { + So(err, ShouldBeNil) + }) + + _, err = c.Load(rp) + Convey("should not return an error when loading a plugin", func() { + So(err, ShouldBeNil) + }) }) }) diff --git a/plugin/publisher/snap-plugin-publisher-mock-file-grpc/main_test.go b/plugin/publisher/snap-plugin-publisher-mock-file-grpc/main_test.go index 87309dbb5..2d709621a 100644 --- a/plugin/publisher/snap-plugin-publisher-mock-file-grpc/main_test.go +++ b/plugin/publisher/snap-plugin-publisher-mock-file-grpc/main_test.go @@ -48,10 +48,15 @@ func TestFilePublisherLoad(t *testing.T) { Convey("ensure plugin loads and responds", func() { c := control.New(control.GetDefaultConfig()) c.Start() - rp, _ := core.NewRequestedPlugin(PluginPath) - _, err := c.Load(rp) - - So(err, ShouldBeNil) + rp, err := core.NewRequestedPlugin(PluginPath, c.GetTempDir(), nil) + Convey("Should not return an error when requested for a plugin", func() { + So(err, ShouldBeNil) + }) + + _, err = c.Load(rp) + Convey("should not return an error when loading a plugin", func() { + So(err, ShouldBeNil) + }) }) }) } diff --git a/plugin/publisher/snap-plugin-publisher-mock-file/main_test.go b/plugin/publisher/snap-plugin-publisher-mock-file/main_test.go index 949d69022..07f16c610 100644 --- a/plugin/publisher/snap-plugin-publisher-mock-file/main_test.go +++ b/plugin/publisher/snap-plugin-publisher-mock-file/main_test.go @@ -48,10 +48,15 @@ func TestFilePublisherLoad(t *testing.T) { Convey("ensure plugin loads and responds", func() { c := control.New(control.GetDefaultConfig()) c.Start() - rp, _ := core.NewRequestedPlugin(PluginPath) - _, err := c.Load(rp) - - So(err, ShouldBeNil) + rp, err := core.NewRequestedPlugin(PluginPath, c.GetTempDir(), nil) + Convey("Should not return an error when requested for a plugin", func() { + So(err, ShouldBeNil) + }) + + _, err = c.Load(rp) + Convey("should not return an error when loading a plugin", func() { + So(err, ShouldBeNil) + }) }) }) } diff --git a/scheduler/distributed_task_test.go b/scheduler/distributed_task_test.go index 1485a1670..1c68ca652 100644 --- a/scheduler/distributed_task_test.go +++ b/scheduler/distributed_task_test.go @@ -71,16 +71,16 @@ func TestDistributedWorkflow(t *testing.T) { // mock2 and file onto c1 - rp, err := core.NewRequestedPlugin(mock2Path) + rp, err := core.NewRequestedPlugin(mock2Path, c1.GetTempDir(), nil) So(err, ShouldBeNil) _, err = c1.Load(rp) So(err, ShouldBeNil) - rp, err = core.NewRequestedPlugin(filePath) + rp, err = core.NewRequestedPlugin(filePath, c1.GetTempDir(), nil) So(err, ShouldBeNil) _, err = c1.Load(rp) So(err, ShouldBeNil) // passthru on c2 - rp, err = core.NewRequestedPlugin(passthruPath) + rp, err = core.NewRequestedPlugin(passthruPath, c1.GetTempDir(), nil) So(err, ShouldBeNil) passthru, err := c2.Load(rp) So(err, ShouldBeNil) @@ -209,17 +209,16 @@ func TestDistributedSubscriptions(t *testing.T) { filePath := helper.PluginFilePath("snap-plugin-publisher-mock-file") // mock2 and file onto c1 - - rp, err := core.NewRequestedPlugin(mock2Path) + rp, err := core.NewRequestedPlugin(mock2Path, c1.GetTempDir(), nil) So(err, ShouldBeNil) _, err = c1.Load(rp) So(err, ShouldBeNil) - rp, err = core.NewRequestedPlugin(filePath) + rp, err = core.NewRequestedPlugin(filePath, c1.GetTempDir(), nil) So(err, ShouldBeNil) _, err = c1.Load(rp) So(err, ShouldBeNil) // passthru on c2 - rp, err = core.NewRequestedPlugin(passthruPath) + rp, err = core.NewRequestedPlugin(passthruPath, c1.GetTempDir(), nil) So(err, ShouldBeNil) _, err = c2.Load(rp) So(err, ShouldBeNil) diff --git a/scheduler/workflow_test.go b/scheduler/workflow_test.go index 5d8c8287a..3b63f4fc4 100644 --- a/scheduler/workflow_test.go +++ b/scheduler/workflow_test.go @@ -137,19 +137,19 @@ func TestCollectPublishWorkflow(t *testing.T) { s := New(cfg) s.SetMetricManager(c) Convey("create a workflow", func() { - rp, err := core.NewRequestedPlugin(snap_collector_mock2_path) + rp, err := core.NewRequestedPlugin(snap_collector_mock2_path, c.GetTempDir(), nil) So(err, ShouldBeNil) _, err = c.Load(rp) So(err, ShouldBeNil) - rp2, err := core.NewRequestedPlugin(snap_publisher_file_path) + rp2, err := core.NewRequestedPlugin(snap_publisher_file_path, c.GetTempDir(), nil) So(err, ShouldBeNil) _, err = c.Load(rp2) So(err, ShouldBeNil) - rp3, err := core.NewRequestedPlugin(snap_processor_passthru_path) + rp3, err := core.NewRequestedPlugin(snap_processor_passthru_path, c.GetTempDir(), nil) So(err, ShouldBeNil) _, err = c.Load(rp3) So(err, ShouldBeNil) - rp4, err := core.NewRequestedPlugin(snap_collector_mock1_path) + rp4, err := core.NewRequestedPlugin(snap_collector_mock1_path, c.GetTempDir(), nil) So(err, ShouldBeNil) _, err = c.Load(rp4) So(err, ShouldBeNil) @@ -203,17 +203,17 @@ func TestProcessChainingWorkflow(t *testing.T) { Convey("create a workflow with chained processors", func() { lpe := newEventListener() c.RegisterEventHandler("Control.PluginLoaded", lpe) - rp, err := core.NewRequestedPlugin(snap_collector_mock2_path) + rp, err := core.NewRequestedPlugin(snap_collector_mock2_path, c.GetTempDir(), nil) So(err, ShouldBeNil) _, err = c.Load(rp) So(err, ShouldBeNil) <-lpe.done - rp2, err := core.NewRequestedPlugin(snap_publisher_file_path) + rp2, err := core.NewRequestedPlugin(snap_publisher_file_path, c.GetTempDir(), nil) So(err, ShouldBeNil) _, err = c.Load(rp2) So(err, ShouldBeNil) <-lpe.done - rp3, err := core.NewRequestedPlugin(snap_processor_passthru_path) + rp3, err := core.NewRequestedPlugin(snap_processor_passthru_path, c.GetTempDir(), nil) So(err, ShouldBeNil) _, err = c.Load(rp3) So(err, ShouldBeNil)