-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.go
178 lines (155 loc) · 4.37 KB
/
config.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
105
106
107
108
109
110
111
112
113
114
115
116
117
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
171
172
173
174
175
176
177
178
// Package config handles agent configuration from a config file. It also
// defines the valid actions along with their types.
package config
import (
"encoding/json"
"fmt"
"io/ioutil"
)
type (
// ActionType describes synchronicity of an action
ActionType int
// Service is an HTTP service
Service struct {
MaxPending uint `json:"max_pending"`
Port uint `json:"port"`
Path string `json:"path"`
}
// Stage is a single step for an action
Stage struct {
Service string `json:"service"`
Method string `json:"method"`
Args map[string]string `json:"args"`
}
// Action is a set of stages and how they should be handled
Action struct {
Type ActionType
Stages []Stage `json:"stages"`
}
// Config contains all of the configuration data
Config struct {
Actions map[string]Action `json:"actions"`
Services map[string]Service `json:"services"`
DBPath string `json:"dbpath"`
}
)
const (
// InfoAction is for synchronous information retrieval in JSON format
InfoAction ActionType = iota
// StreamAction is for synchronous data streaming
StreamAction
// AsyncAction is for asynchronous actions
AsyncAction
)
var (
// ValidActions is a whitelist of configurable actions and their types
ValidActions = map[string]ActionType{
"create": AsyncAction,
"containerCreate": AsyncAction,
"delete": AsyncAction,
"containerDelete": AsyncAction,
"containerStart": AsyncAction,
"reboot": AsyncAction,
"containerReboot": AsyncAction,
"restart": AsyncAction,
"containerRestart": AsyncAction,
"poweroff": AsyncAction,
"containerPoweroff": AsyncAction,
"shutdown": AsyncAction,
"containerShutdown": AsyncAction,
"start": AsyncAction,
"cpuMetrics": InfoAction,
"nicMetrics": InfoAction,
"diskMetrics": InfoAction,
"listImages": InfoAction,
"containerListImages": InfoAction,
"getImage": InfoAction,
"containerGetImage": InfoAction,
"deleteImage": AsyncAction,
"containerDeleteImage": AsyncAction,
"fetchImage": AsyncAction,
"containerFetchImage": AsyncAction,
"listSnapshots": InfoAction,
"getSnapshot": InfoAction,
"createSnapshot": AsyncAction,
"deleteSnapshot": AsyncAction,
"rollbackSnapshot": AsyncAction,
"downloadSnapshot": StreamAction,
}
)
// NewConfig creates a new Config
func NewConfig() *Config {
c := &Config{
Actions: make(map[string]Action),
Services: make(map[string]Service),
DBPath: "/tmp/mistify-agent.db",
}
return c
}
func (stage *Stage) validate(prefix string) error {
if stage == nil {
return nil
}
if stage.Method == "" {
return fmt.Errorf("%s: method cannot be empty", prefix)
}
if stage.Service == "" {
return fmt.Errorf("%s: service cannot be empty", prefix)
}
return nil
}
// AddConfig loads a configuration file
func (c *Config) AddConfig(path string) error {
data, err := ioutil.ReadFile(path)
if err != nil {
return err
}
newConfig := Config{}
err = json.Unmarshal(data, &newConfig)
if err != nil {
return err
}
for name, service := range newConfig.Services {
if _, ok := c.Services[name]; ok {
return fmt.Errorf("service %s has already been defined", name)
}
if service.Port <= 0 {
return fmt.Errorf("service %s has no port", name)
}
if service.MaxPending == 0 {
service.MaxPending = 4
}
c.Services[name] = service
}
for name, action := range newConfig.Actions {
if _, ok := c.Actions[name]; ok {
return fmt.Errorf("action %s has already been defined", name)
}
if _, ok := ValidActions[name]; !ok {
return fmt.Errorf("action %s is not a valid action", name)
}
for _, s := range action.Stages {
if err := s.validate(name); err != nil {
return err
}
}
action.Type = ValidActions[name]
c.Actions[name] = action
}
return nil
}
// Fixup does a bit of validation and initializtion
func (c *Config) Fixup() error {
for name, action := range c.Actions {
for _, stage := range action.Stages {
if _, ok := c.Services[stage.Service]; !ok {
return fmt.Errorf("%s unable to find service %s", name, stage.Service)
}
if stage.Args == nil {
stage.Args = make(map[string]string)
}
}
}
// TODO: add builtins for create and delete
return nil
}