forked from sensu/sensu-go
/
check_config.go
213 lines (179 loc) · 5.36 KB
/
check_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
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
package v2
import (
"errors"
fmt "fmt"
"net/url"
"path"
"sort"
"strconv"
"strings"
"time"
jsoniter "github.com/json-iterator/go"
"github.com/robfig/cron"
)
// FixtureCheckConfig returns a fixture for a CheckConfig object.
func FixtureCheckConfig(id string) *CheckConfig {
interval := uint32(60)
timeout := uint32(0)
check := &CheckConfig{
ObjectMeta: NewObjectMeta(id, "default"),
Interval: interval,
Subscriptions: []string{"linux"},
Command: "command",
RuntimeAssets: []string{"ruby-2-4-2"},
CheckHooks: []HookList{*FixtureHookList("hook1")},
Publish: true,
Ttl: 0,
Timeout: timeout,
LowFlapThreshold: 20,
HighFlapThreshold: 60,
}
return check
}
// NewCheckConfig creates a new CheckConfig.
func NewCheckConfig(meta ObjectMeta) *CheckConfig {
return &CheckConfig{ObjectMeta: meta}
}
// MarshalJSON implements the json.Marshaler interface.
func (c *CheckConfig) MarshalJSON() ([]byte, error) {
if c == nil {
return []byte("null"), nil
}
if c.Subscriptions == nil {
c.Subscriptions = []string{}
}
if c.Handlers == nil {
c.Handlers = []string{}
}
type Clone CheckConfig
clone := &Clone{}
*clone = Clone(*c)
return jsoniter.Marshal(clone)
}
// SetNamespace sets the namespace of the resource.
func (c *CheckConfig) SetNamespace(namespace string) {
c.Namespace = namespace
}
// StorePrefix returns the path prefix to this resource in the store
func (c *CheckConfig) StorePrefix() string {
return ChecksResource
}
// URIPath returns the path component of a CheckConfig URI.
func (c *CheckConfig) URIPath() string {
return path.Join(URLPrefix, "namespaces", url.PathEscape(c.Namespace), ChecksResource, url.PathEscape(c.Name))
}
// Validate returns an error if the check does not pass validation tests.
func (c *CheckConfig) Validate() error {
if err := ValidateName(c.Name); err != nil {
return errors.New("check name " + err.Error())
}
if c.Cron != "" {
if c.Interval > 0 {
return errors.New("must only specify either an interval or a cron schedule")
}
if _, err := cron.ParseStandard(c.Cron); err != nil {
return errors.New("check cron string is invalid")
}
}
if c.Interval == 0 && c.Cron == "" {
return errors.New("check interval must be greater than 0 or a valid cron schedule must be provided")
}
if c.Namespace == "" {
return errors.New("namespace must be set")
}
if c.Ttl > 0 && c.Ttl <= int64(c.Interval) {
return errors.New("ttl must be greater than check interval")
}
for _, assetName := range c.RuntimeAssets {
if err := ValidateAssetName(assetName); err != nil {
return fmt.Errorf("asset's %s", err)
}
}
// The entity can be empty but can't contain invalid characters (only
// alphanumeric string)
if c.ProxyEntityName != "" {
if err := ValidateName(c.ProxyEntityName); err != nil {
return errors.New("proxy entity name " + err.Error())
}
}
if c.ProxyRequests != nil {
if err := c.ProxyRequests.Validate(); err != nil {
return err
}
}
if c.OutputMetricFormat != "" {
if err := ValidateOutputMetricFormat(c.OutputMetricFormat); err != nil {
return err
}
}
if c.LowFlapThreshold != 0 && c.HighFlapThreshold != 0 && c.LowFlapThreshold >= c.HighFlapThreshold {
return errors.New("invalid flap thresholds")
}
if err := ValidateEnvVars(c.EnvVars); err != nil {
return err
}
return c.Subdue.Validate()
}
// IsSubdued returns true if the check is subdued at the current time.
// It returns false otherwise.
func (c *CheckConfig) IsSubdued() bool {
subdue := c.GetSubdue()
if subdue == nil {
return false
}
subdued, err := subdue.InWindows(time.Now())
if err != nil {
return false
}
return subdued
}
//
// Sorting
//
type cmpCheckConfig func(a, b *CheckConfig) bool
// SortCheckConfigsByPredicate can be used to sort a given collection using a given
// predicate.
func SortCheckConfigsByPredicate(cs []*CheckConfig, fn cmpCheckConfig) sort.Interface {
return &checkSorter{checks: cs, byFn: fn}
}
// SortCheckConfigsByName can be used to sort a given collection of checks by their
// names.
func SortCheckConfigsByName(es []*CheckConfig, asc bool) sort.Interface {
if asc {
return SortCheckConfigsByPredicate(es, func(a, b *CheckConfig) bool {
return a.Name < b.Name
})
}
return SortCheckConfigsByPredicate(es, func(a, b *CheckConfig) bool {
return a.Name > b.Name
})
}
type checkSorter struct {
checks []*CheckConfig
byFn cmpCheckConfig
}
// Len implements sort.Interface.
func (s *checkSorter) Len() int {
return len(s.checks)
}
// Swap implements sort.Interface.
func (s *checkSorter) Swap(i, j int) {
s.checks[i], s.checks[j] = s.checks[j], s.checks[i]
}
// Less implements sort.Interface.
func (s *checkSorter) Less(i, j int) bool {
return s.byFn(s.checks[i], s.checks[j])
}
// CheckConfigFields returns a set of fields that represent that resource
func CheckConfigFields(r Resource) map[string]string {
resource := r.(*CheckConfig)
return map[string]string{
"check.name": resource.ObjectMeta.Name,
"check.namespace": resource.ObjectMeta.Namespace,
"check.handlers": strings.Join(resource.Handlers, ","),
"check.publish": strconv.FormatBool(resource.Publish),
"check.round_robin": strconv.FormatBool(resource.RoundRobin),
"check.runtime_assets": strings.Join(resource.RuntimeAssets, ","),
"check.subscriptions": strings.Join(resource.Subscriptions, ","),
}
}