Newer
Older
package plugin
import (
"fmt"
"net"
"path/filepath"
"regexp"
Fabian Seidl
committed
"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"
"github.com/google/uuid"
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
// in the context of the controller is a basic go plugin. A plugin satisfies
// the Storable interface and can be stored.
type Plugin interface {
ID() uuid.UUID
GetClient() *hcplugin.Client
State() State
Manifest() *Manifest
Update() error
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 of the plugin
Author string `yaml:"author" json:"author" bson:"author"`
// Version of the plugin
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"))
}
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 := os.ReadFile(filepath.Join(path, util.ManifestFileName))
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
}
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
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"`
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.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"`
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
}