-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathvmjob.go
104 lines (92 loc) · 2.63 KB
/
vmjob.go
1
2
3
4
5
6
7
8
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package vmjobs
import (
"errors"
"fmt"
"github.com/urfave/cli"
"os"
"plugin"
)
var (
ImageParamDesc = "VM image to run the command on. Specify it multiple times for multiple vms."
)
// VMJobConfigurator -> implements this interface to declare flags for your job and eventually parse them
type VMJobConfigurator interface {
// Flags -> list of cli.Flag supported specifically by the job.
// if missing, an "image/i" required flag is automatically enforced
Flags() []cli.Flag
// ParseCfg -> called when program starts on a job, to parse job specific config
ParseCfg(c *cli.Context) error
}
// VMJobProcessor -> implements this interface to receive output lines and be able to do some post-processing in your own job
type VMJobProcessor interface {
// Process -> processes each output line
Process(VM, outputLine string)
// Done -> called at the end of program, to let job flush its data if needed
Done()
}
// VMJob -> mandatory interface to be implemented
type VMJob interface {
// Stringer -> name for the job
fmt.Stringer
// Desc -> job description used as cmd line sub cmd description
Desc() string
// Cmd -> returns command to be used and whether there is any other command enqueued to be sent
Cmd() (string, bool)
}
// pluginJob type is used to wrap the VMJob provided
// by plugins. Right now it is only used in main to
// distinguish between plugins and internal jobs
type pluginJob struct {
VMJob
}
var (
jobs = make(map[string]VMJob)
alreadyExistentErr = errors.New("job already registered")
symbolNotFoundErr = errors.New("failed to find a pluginJob exported symbol that implements VMJob interface")
notVMJobErr = errors.New("symbol does not implement VMJob interface")
)
// RegisterJob is used by internal plugins to register themselves in their init()
func RegisterJob(name string, job VMJob) error {
if _, ok := jobs[name]; !ok {
jobs[name] = job
return nil
}
return alreadyExistentErr
}
func ListJobs() []VMJob {
jSlice := make([]VMJob, 0, len(jobs))
for _, j := range jobs {
jSlice = append(jSlice, j)
}
return jSlice
}
func LoadPlugins(folder string) error {
files, err := os.ReadDir(folder)
if err != nil {
return err
}
for _, f := range files {
handle, err := plugin.Open(folder + "/" + f.Name())
if err != nil {
// Skip all non .so files
continue
}
sym, err := handle.Lookup("PluginJob")
if err != nil {
return symbolNotFoundErr
}
pl, ok := sym.(VMJob)
if !ok {
return notVMJobErr
}
err = RegisterJob(pl.String(), pluginJob{pl})
if err != nil {
return err
}
}
return nil
}
func IsPluginJob(job VMJob) bool {
_, isPlugin := job.(pluginJob)
return isPlugin
}