package plugin import ( "fmt" "io/ioutil" "regexp" "code.fbi.h-da.de/danet/gosdn/controller/customerrs" "github.com/google/uuid" "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 // in the context of the controller is a basic go plugin. A plugin satisfies // the Storable interface and can be stored. // // Note(mbauch): Currently a plugin is built through the controller itself. // This is fine for the time being, but should be reconsidered for the time to // come. In the future we should provide a build environment that allows to // build plugins within the same environment as the controller itself. type Plugin interface { ID() uuid.UUID State() State Path() string Manifest() *Manifest Update() error } // Manifest represents the manifest of a plugin. type Manifest struct { // Name of the plugin Name string `yaml:"name"` // Author of the plugin Author string `yaml:"author"` // Version of the plugin Version string `yaml:"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.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(`^v([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: vX.X.X")) } if len(errs) != 0 { 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 := ioutil.ReadFile(path) if err != nil { return nil, err } 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 }