Skip to content
Snippets Groups Projects
plugin.go 5.89 KiB
Newer Older
  • Learn to ignore specific revisions
  • Andre Sterba's avatar
    Andre Sterba committed
    	"os"
    
    	"code.fbi.h-da.de/danet/gosdn/controller/customerrs"
    
    	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/util"
    	"code.fbi.h-da.de/danet/gosdn/controller/plugin/shared"
    
    	hcplugin "github.com/hashicorp/go-plugin"
    	"go.mongodb.org/mongo-driver/bson"
    
    	"gopkg.in/yaml.v3"
    )
    
    // State represents the current state of a plugin within the controller. Since
    // the plugins used within the controller are basic go plugins, they can be
    // CREATED, BUILT, LOADED or FAULTY. A plugin can not be unloaded (this is a
    // limitation of go plugins in general).
    type State int64
    
    const (
    	//CREATED state describes a plugin which has been created but is not yet
    	//built.
    	CREATED State = iota
    	// BUILT state describes a plugin which is built and can be loaded into the
    	// controller.
    	BUILT
    	// LOADED state describes a plugin which is running within the controller.
    	LOADED
    	// FAULTY state describes a plugin which couldn't be built or loaded.
    	FAULTY
    )
    
    
    // Plugin describes an interface for a plugin within the controller. A plugin
    // is based on hashicorp's `go plugin`.
    
    	Ping() error
    	Restart() error
    	Close()
    	shared.DeviceModel
    
    }
    
    // Manifest represents the manifest of a plugin.
    type Manifest struct {
    	// Name of the plugin
    
    	Name string `yaml:"name" json:"name" bson:"name"`
    	// Name of the plugin
    	Firmware string `yaml:"firmware" json:"firmware" bson:"firmware"`
    
    	Author string `yaml:"author" json:"author" bson:"author"`
    
    	Version string `yaml:"version" json:"version" bson:"version"`
    
    }
    
    // Validate is a method to check if the manifest is valid and is compliant with
    // the requirements.
    func (m *Manifest) Validate() error {
    	errs := []error{}
    	if m.Name == "" {
    		errs = append(errs, fmt.Errorf("Name is required"))
    	}
    
    	if m.Firmware == "" {
    		errs = append(errs, fmt.Errorf("Firmware is required"))
    	}
    
    	if m.Author == "" {
    		errs = append(errs, fmt.Errorf("Author is required"))
    	}
    	if m.Version == "" {
    		errs = append(errs, fmt.Errorf("Version is required"))
    	}
    	// regex from: https://stackoverflow.com/a/68921827
    
    	validVersion, err := regexp.MatchString(`^([1-9]\d*|0)(\.(([1-9]\d*)|0)){2}$`,
    
    		m.Version)
    	if err != nil {
    		errs = append(errs, err)
    	}
    	if !validVersion {
    
    		errs = append(errs, fmt.Errorf("Version has to be of form: X.X.X"))
    
    		return customerrs.CombinedErrListError{Errors: errs}
    
    	}
    	return nil
    }
    
    // ReadManifestFromFile reads a manifest file and returns a pointer to a newly
    // created Manifest.
    func ReadManifestFromFile(path string) (*Manifest, error) {
    	manifest := &Manifest{}
    
    
    	manifestFile, err := os.ReadFile(filepath.Join(path, util.ManifestFileName))
    
    	err = yaml.Unmarshal(manifestFile, manifest)
    	if err != nil {
    		return nil, err
    	}
    
    	// validate the loaded manifest
    	if err := manifest.Validate(); err != nil {
    		return nil, err
    	}
    
    	return manifest, nil
    }
    
    
    type LoadedPlugin struct {
    	// ID represents the UUID of the LoadedPlugin.
    	ID string `json:"id" bson:"_id"`
    	// Manifest represents the manifest of the LoadedPlugin.
    	Manifest Manifest `json:"manifest" bson:"manifest"`
    	// State represents the state of the LoadedPlugin.
    
    	State State `json:"state,omitempty" bson:"state"`
    	// ExecPath represents the path to the executable of the plugin.
    	ExecPath string `json:"exec_path,omitempty" bson:"exec_path"`
    	// ReattachConfig represents the configuration to reattach to a already
    	// running plugin.
    
    	ReattachConfig hcplugin.ReattachConfig `json:"reattatch_config,omitempty" bson:"reattatch_config"`
    }
    
    func (lp *LoadedPlugin) UnmarshalBSON(data []byte) error {
    	loadedPluginHelper := new(LoadedPluginHelper)
    	if err := bson.Unmarshal(data, loadedPluginHelper); err != nil {
    		return err
    	}
    
    	lp.ID = loadedPluginHelper.ID
    	lp.Manifest = loadedPluginHelper.Manifest
    	lp.State = loadedPluginHelper.State
    
    	lp.ExecPath = loadedPluginHelper.ExecPath
    
    	lp.ReattachConfig = hcplugin.ReattachConfig{
    		Protocol:        hcplugin.Protocol(loadedPluginHelper.ReattachConfig.Protocol),
    		ProtocolVersion: loadedPluginHelper.ReattachConfig.ProtocolVersion,
    		Addr: &net.UnixAddr{
    			Name: loadedPluginHelper.ReattachConfig.Addr.Name,
    			Net:  loadedPluginHelper.ReattachConfig.Addr.Net,
    		},
    		Pid:  loadedPluginHelper.ReattachConfig.Pid,
    		Test: loadedPluginHelper.ReattachConfig.Test,
    	}
    
    	return nil
    }
    
    func (lp *LoadedPlugin) UnmarshalJSON(data []byte) error {
    	loadedPluginHelper := new(LoadedPluginHelper)
    	if err := json.Unmarshal(data, loadedPluginHelper); err != nil {
    		return err
    	}
    
    	lp.ID = loadedPluginHelper.ID
    	lp.Manifest = loadedPluginHelper.Manifest
    	lp.State = loadedPluginHelper.State
    
    	lp.ExecPath = loadedPluginHelper.ExecPath
    
    	lp.ReattachConfig = hcplugin.ReattachConfig{
    		Protocol:        hcplugin.Protocol(loadedPluginHelper.ReattachConfig.Protocol),
    		ProtocolVersion: loadedPluginHelper.ReattachConfig.ProtocolVersion,
    		Addr: &net.UnixAddr{
    			Name: loadedPluginHelper.ReattachConfig.Addr.Name,
    			Net:  loadedPluginHelper.ReattachConfig.Addr.Net,
    		},
    		Pid:  loadedPluginHelper.ReattachConfig.Pid,
    		Test: loadedPluginHelper.ReattachConfig.Test,
    	}
    
    	return nil
    }
    
    type LoadedPluginHelper struct {
    	ID             string               `json:"id" bson:"_id"`
    	Manifest       Manifest             `json:"manifest" bson:"manifest"`
    	State          State                `json:"state,omitempty" bson:"state"`
    
    	ExecPath       string               `json:"exec_path,omitempty" bson:"exec_path"`
    
    	ReattachConfig LoadedReattachConfig `json:"reattatch_config,omitempty" bson:"reattatch_config"`
    }
    
    type LoadedReattachConfig struct {
    	Protocol        string
    	ProtocolVersion int
    	Addr            LoadedAddress
    	Pid             int
    	Test            bool
    }
    
    type LoadedAddress struct {
    	Name string
    	Net  string
    }