/
configuration.go
102 lines (85 loc) · 2.75 KB
/
configuration.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
package http
import (
"fmt"
"regexp"
"time"
"github.com/mitchellh/mapstructure"
)
type MonitorConfiguration struct {
// URL of the service
URL string `mapstructure:"url"`
// Timeout is the duration to wait for a ping to finish, such as "1s"
Timeout time.Duration `mapstructure:"timeout"`
// Interval is the interval to use when watching the target, such as "1s"
Interval time.Duration `mapstructure:"interval"`
// Method is the HTTP method to use, such as "GET"
Method string `mapstructure:"method"`
// FollowRedirects specifies whether or not redirects should be followed
FollowRedirects bool `mapstructure:"followRedirects"`
// MaximumRedirects specifies the maximum number of redirects to follow before throwing an error
MaximumRedirects int `mapstructure:"maximumRedirects"`
// Expect is the matching clauses to determine an alive service
Expect struct {
// Status is the expected HTTP status
Status int `mapstructure:"status"`
// Regex is a regular expression that the body should match
Regex string `mapstructure:"regex"`
// CompiledRegex is the above regex in its compiled form
CompiledRegex *regexp.Regexp
} `mapstructure:"expect"`
}
func ParseConfiguration(options map[string]interface{}) (*MonitorConfiguration, error) {
config := &MonitorConfiguration{}
// Decode the arbitrary options with support for time.Duration parsing
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
DecodeHook: mapstructure.ComposeDecodeHookFunc(mapstructure.StringToTimeDurationHookFunc()),
WeaklyTypedInput: true,
Metadata: nil,
Result: &config,
})
if err != nil {
return nil, err
}
err = decoder.Decode(options)
if err != nil {
return nil, err
}
// Set default timeout if non is specified
if config.Timeout.Seconds() == 0 {
config.Timeout = time.Second
}
// Set default interval if non is specified
if config.Interval.Seconds() == 0 {
config.Interval = time.Second
}
// Set the default HTTP method
if config.Method == "" {
config.Method = "GET"
}
// Set the default maximum redirect count
if config.MaximumRedirects == 0 {
config.MaximumRedirects = 10
}
if config.Expect.Regex != "" {
// Try the regex on empty
expression, err := regexp.Compile(config.Expect.Regex)
if err != nil {
return nil, err
}
config.Expect.CompiledRegex = expression
}
return config, nil
}
func (config *MonitorConfiguration) Validate() []error {
errors := make([]error, 0)
if config.URL == "" {
errors = append(errors, fmt.Errorf("url cannot be empty"))
}
if config.Method != "GET" {
errors = append(errors, fmt.Errorf("unsupported HTTP method"))
}
if config.Expect.Status < 0 || config.Expect.Status > 600 {
errors = append(errors, fmt.Errorf("invalid HTTP status"))
}
return errors
}