Skip to content
Snippets Groups Projects
plugin.go 2.89 KiB
Newer Older
  • Learn to ignore specific revisions
  • package nucleus
    
    import (
    	"bytes"
    	"os/exec"
    	"path/filepath"
    	goPlugin "plugin"
    
    
    	"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",
    
    		"-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
    	}
    
    		PlugID:      p.ID().String(),
    		ProvidedVer: tmpManifest.Version,
    		UsedVer:     p.Manifest().Version,
    	}
    }