Newer
Older
package nucleus
import (
"bytes"
"os/exec"
"path/filepath"
goPlugin "plugin"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/plugin"
"code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors"
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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, sourceFileName string, args ...string) error {
pPath := filepath.Join(path, "plugin.so")
sPath := filepath.Join(path, sourceFileName)
// Provide standard build arguments within a string slice
buildCommand := []string{
"go",
"build",
"-o",
pPath,
"-buildmode=plugin",
}
// Append build arguments
buildCommand = append(buildCommand, args...)
buildCommand = append(buildCommand, sPath)
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, "plugin.so")
// 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(), "plugin.yml"))
if err != nil {
return false, err
}
if p.Manifest().Version < tmpManifest.Version {
err := BuildPlugin(p.Path(), "gostructs.go")
if err != nil {
return false, err
}
log.Info("Plugin update executed.")
return true, nil
}
return false, errors.ErrPluginVersion{
PlugID: p.ID().String(),
ProvidedVer: tmpManifest.Version,
UsedVer: p.Manifest().Version,
}
}