func TestAvailablePlugin(t *testing.T) {
	Convey("newAvailablePlugin()", t, func() {
		Convey("returns an availablePlugin", func() {
			ln, _ := net.Listen("tcp", ":4000")
			defer ln.Close()
			resp := &plugin.Response{
				Meta: plugin.PluginMeta{
					Name:    "testPlugin",
					Version: 1,
				},
				Type:          plugin.CollectorPluginType,
				ListenAddress: "127.0.0.1:4000",
			}
			ap, err := newAvailablePlugin(resp, nil, nil)
			So(ap, ShouldHaveSameTypeAs, new(availablePlugin))
			So(err, ShouldBeNil)
		})
	})

	Convey("Stop()", t, func() {
		Convey("returns nil if plugin successfully stopped", func() {
			r := newRunner(&routing.RoundRobinStrategy{})
			a := plugin.Arg{
				PluginLogPath: "/tmp/snap-test-plugin-stop.log",
			}

			exPlugin, _ := plugin.NewExecutablePlugin(a, PluginPath)
			ap, err := r.startPlugin(exPlugin)
			So(err, ShouldBeNil)

			err = ap.Stop("testing")
			So(err, ShouldBeNil)
		})
	})
}
func TestAvailablePlugin(t *testing.T) {
	Convey("newAvailablePlugin()", t, func() {
		Convey("returns an availablePlugin", func() {
			ln, _ := net.Listen("tcp", ":4000")
			defer ln.Close()
			resp := plugin.Response{
				Meta: plugin.PluginMeta{
					Name:    "testPlugin",
					Version: 1,
				},
				Type:          plugin.CollectorPluginType,
				ListenAddress: "127.0.0.1:4000",
			}
			ap, err := newAvailablePlugin(resp, nil, nil)
			So(ap, ShouldHaveSameTypeAs, new(availablePlugin))
			So(err, ShouldBeNil)
		})
	})

	Convey("Stop()", t, func() {
		Convey("returns nil if plugin successfully stopped", func() {
			r := newRunner()
			r.SetEmitter(new(MockEmitter))
			a := plugin.Arg{}

			exPlugin, _ := plugin.NewExecutablePlugin(a, fixtures.PluginPathMock2)
			ap, err := r.startPlugin(exPlugin)
			So(err, ShouldBeNil)

			err = ap.Stop("testing")
			So(err, ShouldBeNil)
		})
	})
}
Example #3
0
func newExecutablePlugin(a plugin.Arg, path string) (*plugin.ExecutablePlugin, error) {
	// Travis optimization: Try starting the plugin three times before finally
	// returning an error
	var e error
	var ep *plugin.ExecutablePlugin
	for i := 0; i < 3; i++ {
		ep, e = plugin.NewExecutablePlugin(a, path)
		if e == nil {
			break
		}
		if e != nil && i == 2 {
			return nil, e
		}
	}
	return ep, nil
}
Example #4
0
func (r *runner) runPlugin(details *pluginDetails) error {
	if details.IsPackage {
		f, err := os.Open(details.Path)
		if err != nil {
			return err
		}
		defer f.Close()
		tempPath, err := aci.Extract(f)
		if err != nil {
			return err
		}
		details.ExecPath = path.Join(tempPath, "rootfs")
	}
	ePlugin, err := plugin.NewExecutablePlugin(r.pluginManager.GenerateArgs(int(log.GetLevel())), path.Join(details.ExecPath, details.Exec))
	if err != nil {
		runnerLog.WithFields(log.Fields{
			"_block": "run-plugin",
			"path":   path.Join(details.ExecPath, details.Exec),
			"error":  err,
		}).Error("error creating executable plugin")
		return err
	}
	ap, err := r.startPlugin(ePlugin)
	if err != nil {
		runnerLog.WithFields(log.Fields{
			"_block": "run-plugin",
			"path":   path.Join(details.ExecPath, details.Exec),
			"error":  err,
		}).Error("error starting new plugin")
		return err
	}
	ap.exec = details.Exec
	ap.execPath = details.ExecPath
	if details.IsPackage {
		ap.fromPackage = true
	}
	return nil
}
Example #5
0
// LoadPlugin is the method for loading a plugin and
// saving plugin into the LoadedPlugins array
func (p *pluginManager) LoadPlugin(details *pluginDetails, emitter gomit.Emitter) (*loadedPlugin, serror.SnapError) {
	lPlugin := new(loadedPlugin)
	lPlugin.Details = details
	lPlugin.State = DetectedState

	pmLogger.WithFields(log.Fields{
		"_block": "load-plugin",
		"path":   filepath.Base(lPlugin.Details.Exec),
	}).Info("plugin load called")
	ePlugin, err := plugin.NewExecutablePlugin(p.GenerateArgs(int(log.GetLevel())), path.Join(lPlugin.Details.ExecPath, lPlugin.Details.Exec))
	if err != nil {
		pmLogger.WithFields(log.Fields{
			"_block": "load-plugin",
			"error":  err.Error(),
		}).Error("load plugin error while creating executable plugin")
		return nil, serror.New(err)
	}

	pmLogger.WithFields(log.Fields{
		"_block": "load-plugin",
		"path":   filepath.Base(lPlugin.Details.Exec),
	}).Debug(fmt.Sprintf("plugin load timeout set to %ds", p.pluginLoadTimeout))
	resp, err := ePlugin.Run(time.Second * time.Duration(p.pluginLoadTimeout))
	if err != nil {
		pmLogger.WithFields(log.Fields{
			"_block": "load-plugin",
			"error":  err.Error(),
		}).Error("load plugin error when starting plugin")
		return nil, serror.New(err)
	}

	ap, err := newAvailablePlugin(resp, emitter, ePlugin)
	if err != nil {
		pmLogger.WithFields(log.Fields{
			"_block": "load-plugin",
			"error":  err.Error(),
		}).Error("load plugin error while creating available plugin")
		return nil, serror.New(err)
	}

	if resp.Meta.Unsecure {
		err = ap.client.Ping()
	} else {
		err = ap.client.SetKey()
	}

	if err != nil {
		pmLogger.WithFields(log.Fields{
			"_block": "load-plugin",
			"error":  err.Error(),
		}).Error("load plugin error while pinging the plugin")
		return nil, serror.New(err)
	}

	// Get the ConfigPolicy and add it to the loaded plugin
	c, ok := ap.client.(plugin.Plugin)
	if !ok {
		return nil, serror.New(errors.New("missing GetConfigPolicy function"))
	}
	cp, err := c.GetConfigPolicy()
	if err != nil {
		pmLogger.WithFields(log.Fields{
			"_block":         "load-plugin",
			"plugin-type":    "collector",
			"error":          err.Error(),
			"plugin-name":    ap.Name(),
			"plugin-version": ap.Version(),
			"plugin-id":      ap.ID(),
		}).Error("error in getting config policy")
		return nil, serror.New(err)
	}
	lPlugin.ConfigPolicy = cp

	if resp.Type == plugin.CollectorPluginType {
		cfgNode := p.pluginConfig.getPluginConfigDataNode(core.PluginType(resp.Type), resp.Meta.Name, resp.Meta.Version)

		if lPlugin.ConfigPolicy != nil {
			// Get plugin config defaults
			defaults := cdata.NewNode()
			cpolicies := lPlugin.ConfigPolicy.GetAll()
			for _, cpolicy := range cpolicies {
				_, errs := cpolicy.AddDefaults(defaults.Table())
				if len(errs.Errors()) > 0 {
					for _, err := range errs.Errors() {
						pmLogger.WithFields(log.Fields{
							"_block":         "load-plugin",
							"plugin-type":    "collector",
							"plugin-name":    ap.Name(),
							"plugin-version": ap.Version(),
							"plugin-id":      ap.ID(),
						}).Error(err.Error())
					}
					return nil, serror.New(errors.New("error getting default config"))
				}
			}

			// Update config policy with defaults
			cfgNode.ReverseMerge(defaults)
			cp, err = c.GetConfigPolicy()
			if err != nil {
				pmLogger.WithFields(log.Fields{
					"_block":         "load-plugin",
					"plugin-type":    "collector",
					"error":          err.Error(),
					"plugin-name":    ap.Name(),
					"plugin-version": ap.Version(),
					"plugin-id":      ap.ID(),
				}).Error("error in getting config policy")
				return nil, serror.New(err)
			}
			lPlugin.ConfigPolicy = cp
		}

		colClient := ap.client.(client.PluginCollectorClient)

		cfg := plugin.ConfigType{
			ConfigDataNode: cfgNode,
		}

		metricTypes, err := colClient.GetMetricTypes(cfg)
		if err != nil {
			pmLogger.WithFields(log.Fields{
				"_block":      "load-plugin",
				"plugin-type": "collector",
				"error":       err.Error(),
			}).Error("error in getting metric types")
			return nil, serror.New(err)
		}

		// Add metric types to metric catalog
		for _, nmt := range metricTypes {
			// If the version is 0 default it to the plugin version
			// This honors the plugins explicit version but falls back
			// to the plugin version as default
			if nmt.Version() < 1 {
				// Since we have to override version we convert to a internal struct
				nmt = &metricType{
					namespace:          nmt.Namespace(),
					version:            resp.Meta.Version,
					lastAdvertisedTime: nmt.LastAdvertisedTime(),
					config:             nmt.Config(),
					data:               nmt.Data(),
					tags:               nmt.Tags(),
					description:        nmt.Description(),
					unit:               nmt.Unit(),
				}
			}
			// We quit and throw an error on bad metric versions (<1)
			// the is a safety catch otherwise the catalog will be corrupted
			if nmt.Version() < 1 {
				err := errors.New("Bad metric version from plugin")
				pmLogger.WithFields(log.Fields{
					"_block":           "load-plugin",
					"plugin-name":      resp.Meta.Name,
					"plugin-version":   resp.Meta.Version,
					"plugin-type":      resp.Meta.Type.String(),
					"plugin-path":      filepath.Base(lPlugin.Details.ExecPath),
					"metric-namespace": nmt.Namespace(),
					"metric-version":   nmt.Version(),
					"error":            err.Error(),
				}).Error("received metric with bad version")
				return nil, serror.New(err)
			}

			//Add standard tags
			nmt = addStandardAndWorkflowTags(nmt, nil)

			if err := p.metricCatalog.AddLoadedMetricType(lPlugin, nmt); err != nil {
				pmLogger.WithFields(log.Fields{
					"_block":           "load-plugin",
					"plugin-name":      resp.Meta.Name,
					"plugin-version":   resp.Meta.Version,
					"plugin-type":      resp.Meta.Type.String(),
					"plugin-path":      filepath.Base(lPlugin.Details.ExecPath),
					"metric-namespace": nmt.Namespace(),
					"metric-version":   nmt.Version(),
					"error":            err.Error(),
				}).Error("error adding loaded metric type")
				return nil, serror.New(err)
			}
		}
	}

	// Added so clients can adequately clean up connections
	ap.client.Kill("Retrieved necessary plugin info")
	err = ePlugin.Kill()
	if err != nil {
		pmLogger.WithFields(log.Fields{
			"_block": "load-plugin",
			"error":  err.Error(),
		}).Error("load plugin error while killing plugin executable plugin")
		return nil, serror.New(err)
	}

	if resp.State != plugin.PluginSuccess {
		e := fmt.Errorf("Plugin loading did not succeed: %s\n", resp.ErrorMessage)
		pmLogger.WithFields(log.Fields{
			"_block":          "load-plugin",
			"error":           e,
			"plugin response": resp.ErrorMessage,
		}).Error("load plugin error")
		return nil, serror.New(e)
	}

	lPlugin.Meta = resp.Meta
	lPlugin.Type = resp.Type
	lPlugin.Token = resp.Token
	lPlugin.LoadedTime = time.Now()
	lPlugin.State = LoadedState

	aErr := p.loadedPlugins.add(lPlugin)
	if aErr != nil {
		pmLogger.WithFields(log.Fields{
			"_block": "load-plugin",
			"error":  aErr,
		}).Error("load plugin error while adding loaded plugin to load plugins collection")
		return nil, aErr
	}

	return lPlugin, nil
}
Example #6
0
// LoadPlugin is the method for loading a plugin and
// saving plugin into the LoadedPlugins array
func (p *pluginManager) LoadPlugin(details *pluginDetails, emitter gomit.Emitter) (*loadedPlugin, serror.SnapError) {
	lPlugin := new(loadedPlugin)
	lPlugin.Details = details
	lPlugin.State = DetectedState

	pmLogger.WithFields(log.Fields{
		"_block": "load-plugin",
		"path":   filepath.Base(lPlugin.Details.Exec),
	}).Info("plugin load called")
	ePlugin, err := plugin.NewExecutablePlugin(p.GenerateArgs(lPlugin.Details.Exec), path.Join(lPlugin.Details.ExecPath, lPlugin.Details.Exec))

	if err != nil {
		pmLogger.WithFields(log.Fields{
			"_block": "load-plugin",
			"error":  err.Error(),
		}).Error("load plugin error while creating executable plugin")
		return nil, serror.New(err)
	}

	err = ePlugin.Start()
	if err != nil {
		pmLogger.WithFields(log.Fields{
			"_block": "load-plugin",
			"error":  err.Error(),
		}).Error("load plugin error while starting plugin")
		return nil, serror.New(err)
	}

	var resp *plugin.Response
	resp, err = ePlugin.WaitForResponse(time.Second * 3)

	if err != nil {
		pmLogger.WithFields(log.Fields{
			"_block": "load-plugin",
			"error":  err.Error(),
		}).Error("load plugin error while waiting for response from plugin")
		return nil, serror.New(err)
	}

	ap, err := newAvailablePlugin(resp, emitter, ePlugin)
	if err != nil {
		pmLogger.WithFields(log.Fields{
			"_block": "load-plugin",
			"error":  err.Error(),
		}).Error("load plugin error while creating available plugin")
		return nil, serror.New(err)
	}

	if resp.Meta.Unsecure {
		err = ap.client.Ping()
	} else {
		err = ap.client.SetKey()
	}
	if err != nil {
		pmLogger.WithFields(log.Fields{
			"_block": "load-plugin",
			"error":  err.Error(),
		}).Error("load plugin error while pinging the plugin")
		return nil, serror.New(err)
	}

	// Get the ConfigPolicy and add it to the loaded plugin
	c, ok := ap.client.(plugin.Plugin)
	if !ok {
		return nil, serror.New(errors.New("missing GetConfigPolicy function"))
	}
	cp, err := c.GetConfigPolicy()
	if err != nil {
		pmLogger.WithFields(log.Fields{
			"_block":         "load-plugin",
			"plugin-type":    "collector",
			"error":          err.Error(),
			"plugin-name":    ap.Name(),
			"plugin-version": ap.Version(),
			"plugin-id":      ap.ID(),
		}).Error("error in getting config policy")
		return nil, serror.New(err)
	}
	lPlugin.ConfigPolicy = cp

	if resp.Type == plugin.CollectorPluginType {
		colClient := ap.client.(client.PluginCollectorClient)

		cfg := plugin.PluginConfigType{
			ConfigDataNode: p.pluginConfig.getPluginConfigDataNode(core.PluginType(resp.Type), resp.Meta.Name, resp.Meta.Version),
		}

		metricTypes, err := colClient.GetMetricTypes(cfg)
		if err != nil {
			pmLogger.WithFields(log.Fields{
				"_block":      "load-plugin",
				"plugin-type": "collector",
				"error":       err.Error(),
			}).Error("error in getting metric types")
			return nil, serror.New(err)
		}

		// Add metric types to metric catalog
		for _, nmt := range metricTypes {
			// If the version is 0 default it to the plugin version
			// This honors the plugins explicit version but falls back
			// to the plugin version as default
			if nmt.Version() < 1 {
				// Since we have to override version we convert to a internal struct
				nmt = &metricType{
					namespace:          nmt.Namespace(),
					version:            resp.Meta.Version,
					lastAdvertisedTime: nmt.LastAdvertisedTime(),
					config:             nmt.Config(),
					data:               nmt.Data(),
					tags:               nmt.Tags(),
					labels:             nmt.Labels(),
				}
			}
			// We quit and throw an error on bad metric versions (<1)
			// the is a safety catch otherwise the catalog will be corrupted
			if nmt.Version() < 1 {
				err := errors.New("Bad metric version from plugin")
				pmLogger.WithFields(log.Fields{
					"_block":           "load-plugin",
					"plugin-name":      resp.Meta.Name,
					"plugin-version":   resp.Meta.Version,
					"plugin-type":      resp.Meta.Type.String(),
					"plugin-path":      filepath.Base(lPlugin.Details.ExecPath),
					"metric-namespace": nmt.Namespace(),
					"metric-version":   nmt.Version(),
					"error":            err.Error(),
				}).Error("received metric with bad version")
				return nil, serror.New(err)
			}
			p.metricCatalog.AddLoadedMetricType(lPlugin, nmt)
		}
	}

	err = ePlugin.Kill()
	if err != nil {
		pmLogger.WithFields(log.Fields{
			"_block": "load-plugin",
			"error":  err.Error(),
		}).Error("load plugin error while killing plugin executable plugin")
		return nil, serror.New(err)
	}

	if resp.State != plugin.PluginSuccess {
		e := fmt.Errorf("Plugin loading did not succeed: %s\n", resp.ErrorMessage)
		pmLogger.WithFields(log.Fields{
			"_block":          "load-plugin",
			"error":           e,
			"plugin response": resp.ErrorMessage,
		}).Error("load plugin error")
		return nil, serror.New(e)
	}

	lPlugin.Meta = resp.Meta
	lPlugin.Type = resp.Type
	lPlugin.Token = resp.Token
	lPlugin.LoadedTime = time.Now()
	lPlugin.State = LoadedState

	aErr := p.loadedPlugins.add(lPlugin)
	if aErr != nil {
		pmLogger.WithFields(log.Fields{
			"_block": "load-plugin",
			"error":  aErr,
		}).Error("load plugin error while adding loaded plugin to load plugins collection")
		return nil, aErr
	}

	return lPlugin, nil
}