Newer
Older
package plugin
import (
"fmt"
"io/ioutil"
"regexp"
Fabian Seidl
committed
"code.fbi.h-da.de/danet/gosdn/controller/customerrs"
9
10
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
"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 {
Fabian Seidl
committed
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
}