-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathconfig_service.go
322 lines (318 loc) · 11.9 KB
/
config_service.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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
package patrol
import (
"encoding/json"
"fmt"
)
var (
ERR_SERVICE_EMPTY = fmt.Errorf("Service was empty")
ERR_SERVICE_MAXLENGTH = fmt.Errorf("Service was longer than 63 bytes")
ERR_SERVICE_NAME_EMPTY = fmt.Errorf("Service Name was empty")
ERR_SERVICE_NAME_MAXLENGTH = fmt.Errorf("Service Name was longer than 255 bytes")
ERR_SERVICE_MANAGEMENT_INVALID = fmt.Errorf("Service Management was invalid, please select a method!")
ERR_SERVICE_MANAGEMENT_START_INVALID = fmt.Errorf("Service Management Start was invalid, please select a method!")
ERR_SERVICE_MANAGEMENT_STATUS_INVALID = fmt.Errorf("Service Management Status was invalid, please select a method!")
ERR_SERVICE_MANAGEMENT_STOP_INVALID = fmt.Errorf("Service Management Stop was invalid, please select a method!")
ERR_SERVICE_MANAGEMENT_RESTART_INVALID = fmt.Errorf("Service Management Restart was invalid, please select a method!")
ERR_SERVICE_INVALID_EXITCODE = fmt.Errorf("Service contained an Invalid Exit Code")
ERR_SERVICE_DUPLICATE_EXITCODE = fmt.Errorf("Service contained a Duplicate Exit Code")
)
type ConfigService struct {
// Management Method
//
// SERVICE_MANAGEMENT_SERVICE = 1
// SERVICE_MANAGEMENT_INITD = 2
//
// SERVICE_MANAGEMENT_SERVICE: Patrol will use the command `service *`
// SERVICE_MANAGEMENT_INITD: Patrol will use the command `/etc/init.d/*`
//
// If Management is set it will ignore all of the Management Start/Status/Stop/Restart values
// If Management is 0, Start/Status/Stop/Restart must each be individually set!
// If for whatever reason is necessary, we could choose to user `service` for `status` and `/etc/init.d/` for start or stop!
Management int `json:"management,omitempty"`
ManagementStart int `json:"management-start,omitempty"`
ManagementStatus int `json:"management-status,omitempty"`
ManagementStop int `json:"management-stop,omitempty"`
ManagementRestart int `json:"management-restart,omitempty"`
// Optionally we may override our service parameters.
// For example, instead of `restart` we may choose to use `force-reload`
ManagementStartParameter string `json:"management-start-parameter,omitempty"`
ManagementStatusParameter string `json:"management-status-parameter,omitempty"`
ManagementStopParameter string `json:"management-stop-parameter,omitempty"`
ManagementRestartParameter string `json:"management-restart-parameter,omitempty"`
// Name is used as our Display Name in our HTTP GUI.
// Name can contain any characters but must be less than 255 bytes in length.
Name string `json:"name,omitempty"`
// Service is the parameter of our service.
// This is the equivalent of Binary
Service string `json:"service,omitempty"`
// These are a list of valid exit codes to ignore when returned from Start/Status/Stop/Restart
// By Default 0 is always ignored, it is assumed to mean that the command was successful!
IgnoreExitCodesStart []uint8 `json:"ignore-exit-codes-start,omitempty"`
IgnoreExitCodesStatus []uint8 `json:"ignore-exit-codes-status,omitempty"`
IgnoreExitCodesStop []uint8 `json:"ignore-exit-codes-stop,omitempty"`
IgnoreExitCodesRestart []uint8 `json:"ignore-exit-codes-restart,omitempty"`
// If Disabled is true our Service won't be executed until enabled.
// The only way to enable an Service once Patrol is started is to use the API or restart Patrol
// If we are Disabled and we discover an Service that is running, we will signal it to stop.
Disabled bool `json:"disabled,omitempty"`
// KeyValue - prexisting values to populate objects with on init
KeyValue map[string]interface{} `json:"keyvalue,omitempty"`
// KeyValueClear if true will cause our Service KeyValue to be cleared once a new instance of our Service is started.
KeyValueClear bool `json:"keyvalue-clear,omitempty"`
// If Secret is set, we will require a secret to be passed when pinging and modifying the state of our Service from our HTTP and UDP API.
// We are not going to throttle comparing our secret. Choose a secret with enough bits of uniqueness and don't make your Patrol instance public!
// If you are worried about your secret being public, use TLS and HTTP, DO NOT USE UDP!!!
Secret string `json:"secret,omitempty"`
// Triggers are only available when you extend Patrol as a library
// These values will NOT be able to be set from `config.json` - They must be set manually
//
// TriggerStart is called from tick in runServices() before we attempt to execute an Service.
TriggerStart func(
service *Service,
) `json:"-"`
// TriggerStarted is called from tick in runServices() and isServiceRunning()
// This is called after we either execute a new Service or we discover a newly running Service.
TriggerStarted func(
service *Service,
) `json:"-"`
// TriggerStartFailed is called from tick in runServices() when we fail to execute a new Service.
TriggerStartFailed func(
service *Service,
) `json:"-"`
// TriggerRunning is called from tick() when we discover an Service is running.
TriggerRunning func(
service *Service,
) `json:"-"`
// TriggerDisabled is called from tick() when we discover an Service that is disabled.
TriggerDisabled func(
service *Service,
) `json:"-"`
// TriggerPinged is from Service.apiRequest() when we discover an Service is running from a Ping request.
TriggerClosed func(
service *Service,
history *History,
) `json:"-"`
// TriggerShutdown is called when we call Patrol.Shutdown()
// This will only be called ONCE
// This is called regardless if our Service is running or disabled!
TriggerShutdown func(
service *Service,
) `json:"-"`
// Extra Unstructured Data
X json.RawMessage `json:"x,omitempty"`
}
func (self *ConfigService) IsValid() bool {
if self == nil {
return false
}
return true
}
func (self *ConfigService) Clone() *ConfigService {
if self == nil {
return nil
}
config := &ConfigService{
Management: self.Management,
ManagementStart: self.ManagementStart,
ManagementStatus: self.ManagementStatus,
ManagementStop: self.ManagementStop,
ManagementRestart: self.ManagementRestart,
ManagementStartParameter: self.ManagementStartParameter,
ManagementStatusParameter: self.ManagementStatusParameter,
ManagementStopParameter: self.ManagementStopParameter,
ManagementRestartParameter: self.ManagementRestartParameter,
Name: self.Name,
Service: self.Service,
IgnoreExitCodesStart: make([]uint8, 0, len(self.IgnoreExitCodesStart)),
IgnoreExitCodesStatus: make([]uint8, 0, len(self.IgnoreExitCodesStatus)),
IgnoreExitCodesStop: make([]uint8, 0, len(self.IgnoreExitCodesStop)),
IgnoreExitCodesRestart: make([]uint8, 0, len(self.IgnoreExitCodesRestart)),
Disabled: self.Disabled,
KeyValue: make(map[string]interface{}),
KeyValueClear: self.KeyValueClear,
Secret: self.Secret,
TriggerStart: self.TriggerStart,
TriggerStarted: self.TriggerStarted,
TriggerStartFailed: self.TriggerStartFailed,
TriggerRunning: self.TriggerRunning,
TriggerDisabled: self.TriggerDisabled,
TriggerClosed: self.TriggerClosed,
TriggerShutdown: self.TriggerShutdown,
X: dereference(self.X),
}
for k, v := range self.KeyValue {
config.KeyValue[k] = v
}
for _, i := range self.IgnoreExitCodesStart {
config.IgnoreExitCodesStart = append(config.IgnoreExitCodesStart, i)
}
for _, i := range self.IgnoreExitCodesStatus {
config.IgnoreExitCodesStatus = append(config.IgnoreExitCodesStatus, i)
}
for _, i := range self.IgnoreExitCodesStop {
config.IgnoreExitCodesStop = append(config.IgnoreExitCodesStop, i)
}
for _, i := range self.IgnoreExitCodesRestart {
config.IgnoreExitCodesRestart = append(config.IgnoreExitCodesRestart, i)
}
return config
}
func (self *ConfigService) Validate() error {
if self.Management == 0 &&
(self.ManagementStart > 0 ||
self.ManagementStatus > 0 ||
self.ManagementStop > 0) {
// use specific management values
// start
if self.ManagementStart < SERVICE_MANAGEMENT_SERVICE ||
self.ManagementStart > SERVICE_MANAGEMENT_INITD {
// unknown management value
return ERR_SERVICE_MANAGEMENT_START_INVALID
}
// status
if self.ManagementStatus < SERVICE_MANAGEMENT_SERVICE ||
self.ManagementStatus > SERVICE_MANAGEMENT_INITD {
// unknown management value
return ERR_SERVICE_MANAGEMENT_STATUS_INVALID
}
// stop
if self.ManagementStop < SERVICE_MANAGEMENT_SERVICE ||
self.ManagementStop > SERVICE_MANAGEMENT_INITD {
// unknown management value
return ERR_SERVICE_MANAGEMENT_STOP_INVALID
}
// restart
if self.ManagementRestart < SERVICE_MANAGEMENT_SERVICE ||
self.ManagementRestart > SERVICE_MANAGEMENT_INITD {
// unknown management value
return ERR_SERVICE_MANAGEMENT_RESTART_INVALID
}
} else {
// use master value
if self.Management < SERVICE_MANAGEMENT_SERVICE ||
self.Management > SERVICE_MANAGEMENT_INITD {
// unknown management value
return ERR_SERVICE_MANAGEMENT_INVALID
}
}
if self.Service == "" {
return ERR_SERVICE_EMPTY
}
if len(self.Service) > SERVICE_MAXLENGTH {
return ERR_SERVICE_MAXLENGTH
}
if self.Name == "" {
return ERR_SERVICE_NAME_EMPTY
}
if len(self.Name) > SERVICE_NAME_MAXLENGTH {
return ERR_SERVICE_NAME_MAXLENGTH
}
if len(self.Secret) > SECRET_MAX_LENGTH {
return ERR_SECRET_TOOLONG
}
// start
exists := make(map[uint8]struct{})
for _, ec := range self.IgnoreExitCodesStart {
if ec == 0 {
// can't ignore 0
return ERR_SERVICE_INVALID_EXITCODE
}
if _, ok := exists[ec]; ok {
// exit code already exists
return ERR_SERVICE_DUPLICATE_EXITCODE
}
// does not exist
exists[ec] = struct{}{}
}
// status
exists = make(map[uint8]struct{})
for _, ec := range self.IgnoreExitCodesStatus {
if ec == 0 {
// can't ignore 0
return ERR_SERVICE_INVALID_EXITCODE
}
if _, ok := exists[ec]; ok {
// exit code already exists
return ERR_SERVICE_DUPLICATE_EXITCODE
}
// does not exist
exists[ec] = struct{}{}
}
// stop
exists = make(map[uint8]struct{})
for _, ec := range self.IgnoreExitCodesStop {
if ec == 0 {
// can't ignore 0
return ERR_SERVICE_INVALID_EXITCODE
}
if _, ok := exists[ec]; ok {
// exit code already exists
return ERR_SERVICE_DUPLICATE_EXITCODE
}
// does not exist
exists[ec] = struct{}{}
}
// restart
exists = make(map[uint8]struct{})
for _, ec := range self.IgnoreExitCodesRestart {
if ec == 0 {
// can't ignore 0
return ERR_SERVICE_INVALID_EXITCODE
}
if _, ok := exists[ec]; ok {
// exit code already exists
return ERR_SERVICE_DUPLICATE_EXITCODE
}
// does not exist
exists[ec] = struct{}{}
}
return nil
}
func (self *ConfigService) GetManagementStart() int {
if self.Management > 0 {
return self.Management
}
return self.ManagementStart
}
func (self *ConfigService) GetManagementStatus() int {
if self.Management > 0 {
return self.Management
}
return self.ManagementStatus
}
func (self *ConfigService) GetManagementStop() int {
if self.Management > 0 {
return self.Management
}
return self.ManagementStop
}
func (self *ConfigService) GetManagementRestart() int {
if self.Management > 0 {
return self.Management
}
return self.ManagementRestart
}
func (self *ConfigService) GetManagementStartParameter() string {
if self.ManagementStartParameter == "" {
return "start"
}
return self.ManagementStartParameter
}
func (self *ConfigService) GetManagementStatusParameter() string {
if self.ManagementStatusParameter == "" {
return "status"
}
return self.ManagementStatusParameter
}
func (self *ConfigService) GetManagementStopParameter() string {
if self.ManagementStopParameter == "" {
return "stop"
}
return self.ManagementStopParameter
}
func (self *ConfigService) GetManagementRestartParameter() string {
if self.ManagementRestartParameter == "" {
return "restart"
}
return self.ManagementRestartParameter
}