Newer
Older
package nucleus
import (
"bytes"
"os/exec"
"path/filepath"
goPlugin "plugin"
Fabian Seidl
committed
"code.fbi.h-da.de/danet/gosdn/controller/customerrs"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/plugin"
"code.fbi.h-da.de/danet/gosdn/controller/nucleus/util"
log "github.com/sirupsen/logrus"
)
// BuildPlugin builds a new plugin within the given path. The source file must
// be present at the given path. The built plugin is written to a 'plugin.so'
// file.
func BuildPlugin(path string, sourceFileNames []string, args ...string) error {
pPath := filepath.Join(path, util.PluginOutputName)
fileNames := make([]string, len(sourceFileNames))
for i, fileName := range sourceFileNames {
sPath := filepath.Join(path, fileName)
fileNames[i] = sPath
}
// Provide standard build arguments within a string slice
buildCommand := []string{
"go",
"build",
"-buildmode=plugin",
Malte Bauch
committed
"-trimpath",
"-o",
pPath,
}
// Append build arguments
buildCommand = append(buildCommand, args...)
buildCommand = append(buildCommand, fileNames...)
var stderr bytes.Buffer
// Create the command to be executed
cmd := exec.Command(buildCommand[0], buildCommand[1:]...)
cmd.Dir = "./"
cmd.Stderr = &stderr
// Run the command and build the plugin
err := cmd.Run()
if err != nil {
log.Error(stderr.String())
return err
}
return nil
}
// LoadPlugin opens a go plugin binary which must be named 'plugin.so' at the
// given path. LoadPlugin checks for the symbol 'PluginSymbol' that has to be
// provided within the plugin to be loaded. If the symbol is found, the loaded
// plugin is returned.
func LoadPlugin(path string) (goPlugin.Symbol, error) {
path = filepath.Join(path, util.PluginOutputName)
// Open the plugin, which is a binary (named 'plugin.so') within the given
// path.
gp, err := goPlugin.Open(path)
if err != nil {
return nil, err
}
// Search for the specific symbol within the plugin. If it does not contain
// the symbol is not usable and an error is thrown.
symbol, err := gp.Lookup("PluginSymbol")
if err != nil {
return nil, err
}
return symbol, nil
}
// UpdatePlugin updates a given Plugin. Therefore the version of the
// `plugin.yml` manifest file is compared to the version in use. If a new
// version is within the plugin folder, the new version of the plugin is built.
// NOTE:This should only be used with caution.
func UpdatePlugin(p plugin.Plugin) (updated bool, err error) {
tmpManifest, err := plugin.ReadManifestFromFile(filepath.Join(p.Path(), util.ManifestFileName))
if err != nil {
return false, err
}
if p.Manifest().Version < tmpManifest.Version {
err := BuildPlugin(p.Path(), []string{util.GoStructName, util.GoStructAdditionsName})
if err != nil {
return false, err
}
log.Info("Plugin update executed.")
return true, nil
}
Fabian Seidl
committed
return false, customerrs.PluginVersionError{
PlugID: p.ID().String(),
ProvidedVer: tmpManifest.Version,
UsedVer: p.Manifest().Version,
}
}