Skip to content
This repository has been archived by the owner on Nov 8, 2022. It is now read-only.

Commit

Permalink
Adds support for plugin pkgs w\ multiple commands
Browse files Browse the repository at this point in the history
- Plugin packages need to support declaring the interpreter and the entrypoint
  along with the command line args.
  • Loading branch information
jcooklin committed Nov 18, 2016
1 parent 46c56b2 commit 58b1d16
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 31 deletions.
6 changes: 2 additions & 4 deletions control/available_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"errors"
"fmt"
"os"
"path"
"path/filepath"
"strconv"
"strings"
Expand Down Expand Up @@ -72,7 +71,6 @@ type availablePlugin struct {
failedHealthChecks int
healthChan chan error
ePlugin executablePlugin
exec string
execPath string
fromPackage bool
pprofPort string
Expand Down Expand Up @@ -240,8 +238,8 @@ func (a *availablePlugin) Kill(r string) error {
"_module": "control-aplugin",
"block": "kill",
"plugin_name": a,
"pluginPath": path.Join(a.execPath, a.exec),
}).Debug("deleting available plugin path")
"pluginPath": a.execPath,
}).Debug("deleting available plugin package")
os.RemoveAll(filepath.Dir(a.execPath))
}
return a.ePlugin.Kill()
Expand Down
6 changes: 3 additions & 3 deletions control/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ type runsPlugins interface {
SetMetricCatalog(catalogsMetrics)
SetPluginManager(managesPlugins)
Monitor() *monitor
runPlugin(*pluginDetails) error
runPlugin(string, *pluginDetails) error
}

type managesPlugins interface {
Expand Down Expand Up @@ -555,11 +555,11 @@ func (p *pluginControl) returnPluginDetails(rp *core.RequestedPlugin) (*pluginDe
if details.Manifest, err = aci.Manifest(f); err != nil {
return nil, serror.New(err)
}
details.Exec = details.Manifest.App.Exec[0]
details.Exec = details.Manifest.App.Exec
details.IsPackage = true
} else {
details.IsPackage = false
details.Exec = filepath.Base(rp.Path())
details.Exec = []string{filepath.Base(rp.Path())}
details.ExecPath = filepath.Dir(rp.Path())
}

Expand Down
4 changes: 2 additions & 2 deletions control/control_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -960,7 +960,7 @@ func TestRoutingCachingStrategy(t *testing.T) {
}
for _, id := range tasks {
pool.Subscribe(id)
err = c.pluginRunner.runPlugin(lp.Details)
err = c.pluginRunner.runPlugin(lp.Name(), lp.Details)
So(err, ShouldBeNil)
serr := c.subscriptionGroups.Add(id, []core.RequestedMetric{metric}, cdt, []core.SubscribedPlugin{})
So(serr, ShouldBeNil)
Expand Down Expand Up @@ -1031,7 +1031,7 @@ func TestRoutingCachingStrategy(t *testing.T) {
}
for _, id := range tasks {
pool.Subscribe(id)
err = c.pluginRunner.runPlugin(lp.Details)
err = c.pluginRunner.runPlugin(lp.Name(), lp.Details)
So(err, ShouldBeNil)
serrs := c.subscriptionGroups.Add(id, []core.RequestedMetric{metric}, cdt, []core.SubscribedPlugin{})
So(serrs, ShouldBeNil)
Expand Down
19 changes: 12 additions & 7 deletions control/plugin/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
var execLogger = log.WithField("_module", "plugin-exec")

type ExecutablePlugin struct {
name string
cmd command
stdout io.Reader
stderr io.Reader
Expand Down Expand Up @@ -75,15 +76,15 @@ func (cw *commandWrapper) Kill() error {
}
func (cw *commandWrapper) Start() error { return cw.cmd.Start() }

// Initialize a new ExecutablePlugin from path to executable and daemon mode (true or false)
func NewExecutablePlugin(a Arg, path string) (*ExecutablePlugin, error) {
// NewExecutablePlugin returns a new ExecutablePlugin.
func NewExecutablePlugin(a Arg, commands ...string) (*ExecutablePlugin, error) {
jsonArgs, err := json.Marshal(a)
if err != nil {
return nil, err
}
cmd := &exec.Cmd{
Path: path,
Args: []string{path, string(jsonArgs)},
Path: commands[0],
Args: append(commands, string(jsonArgs)),
}
stdout, err := cmd.StdoutPipe()
if err != nil {
Expand Down Expand Up @@ -130,7 +131,7 @@ func (e *ExecutablePlugin) Run(timeout time.Duration) (Response, error) {
close(doneChan)
} else {
execLogger.WithFields(log.Fields{
"plugin": path.Base(e.cmd.Path()),
"plugin": e.name,
"io": "stdout",
}).Debug(stdOutScanner.Text())
}
Expand Down Expand Up @@ -183,6 +184,10 @@ func (e *ExecutablePlugin) Run(timeout time.Duration) (Response, error) {
return resp, err
}

func (e *ExecutablePlugin) SetName(name string) {
e.name = name
}

func (e *ExecutablePlugin) Kill() error {
return e.cmd.Kill()
}
Expand All @@ -193,7 +198,7 @@ func (e *ExecutablePlugin) captureStderr() {
for {
for stdErrScanner.Scan() {
execLogger.
WithField("plugin", path.Base(e.cmd.Path())).
WithField("plugin", e.name).
WithField("io", "stderr").
Debug(stdErrScanner.Text())
}
Expand All @@ -206,7 +211,7 @@ func (e *ExecutablePlugin) captureStderr() {
}

execLogger.
WithField("plugin", path.Base(e.cmd.Path())).
WithField("plugin", e.name).
WithField("io", "stderr").
WithField("scanner_err", errScanner).
WithField("read_string_err", errRead).
Expand Down
21 changes: 16 additions & 5 deletions control/plugin_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ 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
Exec []string
ExecPath string
IsPackage bool
IsAutoLoaded bool
Expand Down Expand Up @@ -298,9 +298,18 @@ func (p *pluginManager) LoadPlugin(details *pluginDetails, emitter gomit.Emitter

pmLogger.WithFields(log.Fields{
"_block": "load-plugin",
"path": filepath.Base(lPlugin.Details.Exec),
"path": filepath.Base(lPlugin.Details.Exec[0]),
}).Info("plugin load called")
ePlugin, err := plugin.NewExecutablePlugin(p.GenerateArgs(int(log.GetLevel())), path.Join(lPlugin.Details.ExecPath, lPlugin.Details.Exec))
// 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.
commands := make([]string, len(lPlugin.Details.Exec))
for i, e := range lPlugin.Details.Exec {
commands[i] = path.Join(lPlugin.Details.ExecPath, e)
}
ePlugin, err := plugin.NewExecutablePlugin(
p.GenerateArgs(int(log.GetLevel())),
commands...)
if err != nil {
pmLogger.WithFields(log.Fields{
"_block": "load-plugin",
Expand All @@ -311,7 +320,7 @@ func (p *pluginManager) LoadPlugin(details *pluginDetails, emitter gomit.Emitter

pmLogger.WithFields(log.Fields{
"_block": "load-plugin",
"path": filepath.Base(lPlugin.Details.Exec),
"path": 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 {
Expand All @@ -322,6 +331,8 @@ func (p *pluginManager) LoadPlugin(details *pluginDetails, emitter gomit.Emitter
return nil, serror.New(err)
}

ePlugin.SetName(resp.Meta.Name)

key := fmt.Sprintf("%s"+core.Separator+"%s"+core.Separator+"%d", resp.Meta.Type.String(), resp.Meta.Name, resp.Meta.Version)
if _, exists := p.loadedPlugins.table[key]; exists {
return nil, serror.New(ErrPluginAlreadyLoaded, map[string]interface{}{
Expand Down Expand Up @@ -534,7 +545,7 @@ func (p *pluginManager) UnloadPlugin(pl core.Plugin) (*loadedPlugin, serror.Snap
}
pmLogger.WithFields(log.Fields{
"_block": "unload-plugin",
"path": filepath.Base(plugin.Details.Exec),
"path": plugin.Details.Exec,
}).Info("plugin unload called")

if plugin.State != LoadedState {
Expand Down
2 changes: 1 addition & 1 deletion control/plugin_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func loadPlugin(p *pluginManager, path string) (*loadedPlugin, serror.SnapError)
details := &pluginDetails{
Path: path,
ExecPath: filepath.Dir(path),
Exec: filepath.Base(path),
Exec: []string{filepath.Base(path)},
IsAutoLoaded: true,
}
for i := 0; i < 3; i++ {
Expand Down
16 changes: 10 additions & 6 deletions control/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ func (r *runner) HandleGomitEvent(e gomit.Event) {
}
}

func (r *runner) runPlugin(details *pluginDetails) error {
func (r *runner) runPlugin(name string, details *pluginDetails) error {
if details.IsPackage {
f, err := os.Open(details.Path)
if err != nil {
Expand All @@ -311,25 +311,29 @@ func (r *runner) runPlugin(details *pluginDetails) error {
}
details.ExecPath = path.Join(tempPath, "rootfs")
}
ePlugin, err := plugin.NewExecutablePlugin(r.pluginManager.GenerateArgs(int(log.GetLevel())), path.Join(details.ExecPath, details.Exec))
commands := make([]string, len(details.Exec))
for i, e := range details.Exec {
commands[i] = path.Join(details.ExecPath, e)
}
ePlugin, err := plugin.NewExecutablePlugin(r.pluginManager.GenerateArgs(int(log.GetLevel())), commands...)
if err != nil {
runnerLog.WithFields(log.Fields{
"_block": "run-plugin",
"path": path.Join(details.ExecPath, details.Exec),
"path": commands,
"error": err,
}).Error("error creating executable plugin")
return err
}
ePlugin.SetName(name)
ap, err := r.startPlugin(ePlugin)
if err != nil {
runnerLog.WithFields(log.Fields{
"_block": "run-plugin",
"path": path.Join(details.ExecPath, details.Exec),
"path": commands,
"error": err,
}).Error("error starting new plugin")
return err
}
ap.exec = details.Exec
ap.execPath = details.ExecPath
if details.IsPackage {
ap.fromPackage = true
Expand Down Expand Up @@ -373,5 +377,5 @@ func (r *runner) restartPlugin(key string) error {
if err != nil {
return err
}
return r.runPlugin(lp.Details)
return r.runPlugin(lp.Name(), lp.Details)
}
2 changes: 1 addition & 1 deletion control/subscription_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ func (s *subscriptionGroup) subscribePlugins(id string,
serrs = append(serrs, serror.New(err))
return serrs
}
err = s.pluginRunner.runPlugin(plg.Details)
err = s.pluginRunner.runPlugin(plg.Name(), plg.Details)
if err != nil {
serrs = append(serrs, serror.New(err))
return serrs
Expand Down
20 changes: 18 additions & 2 deletions pkg/aci/aci.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"os"
"path/filepath"

log "github.com/Sirupsen/logrus"
specaci "github.com/appc/spec/aci"
"github.com/appc/spec/schema"
)
Expand All @@ -39,6 +40,8 @@ var (
ErrCopyingFile = errors.New("Error copying file")
// ErrCreatingFile - Error message for error creating file
ErrCreatingFile = errors.New("Error creating file")
// ErrCreatingSymLink - Error message for creating Symlink
ErrCreatingSymLink = errors.New("Error creating symlink")
// ErrMkdirAll - Error message for error making directory
ErrMkdirAll = errors.New("Error making directory")
// ErrNext - Error message for error interating through tar file
Expand All @@ -47,6 +50,8 @@ var (
ErrUntar = errors.New("Error untarring file")
)

var aciLogger = log.WithField("_module", "aci")

// Manifest returns the ImageManifest inside the ACI file
func Manifest(f io.ReadSeeker) (*schema.ImageManifest, error) {
m, err := specaci.ManifestFromImage(f)
Expand All @@ -72,6 +77,8 @@ func Extract(f io.ReadSeeker) (string, error) {
if err != nil {
return "", err
}
aciLogger.WithField("directory", dir).Debugf(
"Extracting archive to temporary directory")
for {
hdr, err := tr.Reader.Next()
if err == io.EOF {
Expand All @@ -88,11 +95,12 @@ func Extract(f io.ReadSeeker) (string, error) {
if err != nil {
return "", fmt.Errorf("%v: %v\n%v", ErrCreatingFile, file, err)
}
defer w.Close()
_, err = io.Copy(w, tr)
if err != nil {
w.Close()
return "", fmt.Errorf("%v: %v\n%v", ErrCopyingFile, file, err)
}
w.Close()
err = os.Chmod(file, fileMode)
if err != nil {
return "", fmt.Errorf("%v: %v\n%v", ErrChmod, file, err)
Expand All @@ -102,8 +110,16 @@ func Extract(f io.ReadSeeker) (string, error) {
if err != nil {
return "", fmt.Errorf("%v: %v\n%v", ErrMkdirAll, file, err)
}
case tar.TypeSymlink:
err := os.Symlink(
filepath.Join(dir, filepath.Dir(hdr.Name), hdr.Linkname),
filepath.Join(dir, hdr.Name))
if err != nil {
return "", fmt.Errorf("%v: name: %v Linkname: %v \n%v",
ErrCreatingSymLink, hdr.Name, hdr.Linkname, err)
}
default:
return "", fmt.Errorf("%v: %v", ErrUntar, hdr.Name)
return "", fmt.Errorf("%v (type: %d): %v", ErrUntar, hdr.Typeflag, hdr.Name)
}
}
return dir, nil
Expand Down

0 comments on commit 58b1d16

Please sign in to comment.