portertech-sensu-settings 10.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,166 @@
1
+ module Sensu
2
+ module Settings
3
+ module Rules
4
+ # Check that a value is a hash.
5
+ #
6
+ # @param value [Object] to check.
7
+ # @return [TrueClass, FalseClass]
8
+ def must_be_a_hash(value)
9
+ value.is_a?(Hash)
10
+ end
11
+ alias_method :is_a_hash?, :must_be_a_hash
12
+
13
+ # Check that a value is a hash, if set (not nil).
14
+ #
15
+ # @param value [Object] to check.
16
+ # @return [TrueClass, FalseClass]
17
+ def must_be_a_hash_if_set(value)
18
+ value.nil? ? true : must_be_a_hash(value)
19
+ end
20
+
21
+ # Check that a value is an array.
22
+ #
23
+ # @param value [Object] to check.
24
+ # @return [TrueClass, FalseClass]
25
+ def must_be_an_array(value)
26
+ value.is_a?(Array)
27
+ end
28
+ alias_method :is_an_array?, :must_be_an_array
29
+
30
+ # Check that a value is an array, if set (not nil).
31
+ #
32
+ # @param value [Object] to check.
33
+ # @return [TrueClass, FalseClass]
34
+ def must_be_an_array_if_set(value)
35
+ value.nil? ? true : must_be_an_array(value)
36
+ end
37
+
38
+ # Check that a value is a string.
39
+ #
40
+ # @param value [Object] to check.
41
+ # @return [TrueClass, FalseClass]
42
+ def must_be_a_string(value)
43
+ value.is_a?(String)
44
+ end
45
+ alias_method :is_a_string?, :must_be_a_string
46
+
47
+ # Check that a value is a string, if set (not nil).
48
+ #
49
+ # @param value [Object] to check.
50
+ # @return [TrueClass, FalseClass]
51
+ def must_be_a_string_if_set(value)
52
+ value.nil? ? true : must_be_a_string(value)
53
+ end
54
+
55
+ # Check that a value is an integer.
56
+ #
57
+ # @param value [Object] to check.
58
+ # @return [TrueClass, FalseClass]
59
+ def must_be_an_integer(value)
60
+ value.is_a?(Integer)
61
+ end
62
+ alias_method :is_an_integer?, :must_be_an_integer
63
+
64
+ # Check that a value is an integer, if set (not nil).
65
+ #
66
+ # @param value [Object] to check.
67
+ # @return [TrueClass, FalseClass]
68
+ def must_be_an_integer_if_set(value)
69
+ value.nil? ? true : must_be_an_integer(value)
70
+ end
71
+
72
+ # Check that a value is numeric.
73
+ #
74
+ # @param value [Object] to check.
75
+ # @return [TrueClass, FalseClass]
76
+ def must_be_a_numeric(value)
77
+ value.is_a?(Numeric)
78
+ end
79
+
80
+ # Check that a value is numeric, if set (not nil).
81
+ #
82
+ # @param value [Object] to check.
83
+ # @return [TrueClass, FalseClass]
84
+ def must_be_a_numeric_if_set(value)
85
+ value.nil? ? true : must_be_a_numeric(value)
86
+ end
87
+
88
+ # Check that a value matches a regular expression.
89
+ #
90
+ # @param regex [Regexp] pattern to compare with value.
91
+ # @param value [Object] to check if matches pattern.
92
+ # @return [TrueClass, FalseClass]
93
+ def must_match_regex(regex, value)
94
+ value.is_a?(String) && (value =~ regex) == 0
95
+ end
96
+
97
+ # Check if a value is boolean.
98
+ #
99
+ # @param value [Object] to check.
100
+ # @return [TrueClass, FalseClass]
101
+ def must_be_boolean(value)
102
+ !!value == value
103
+ end
104
+
105
+ # Check if a value is boolean, if set (no nil).
106
+ #
107
+ # @param value [Object] to check.
108
+ # @return [TrueClass, FalseClass]
109
+ def must_be_boolean_if_set(value)
110
+ value.nil? ? true : must_be_boolean(value)
111
+ end
112
+
113
+ # Check that value items are all strings and not empty.
114
+ #
115
+ # @param value [Array] with items to check.
116
+ # @param regex [Regexp] to validate string items with.
117
+ # @return [TrueClass, FalseClass]
118
+ def items_must_be_strings(value, regex=nil)
119
+ value.all? do |item|
120
+ item.is_a?(String) && !item.empty? &&
121
+ (regex.nil? || item =~ regex)
122
+ end
123
+ end
124
+
125
+ # Check if either of the values are set (not nil).
126
+ #
127
+ # @param values [Array<Object>] to check if not nil.
128
+ # @return [TrueClass, FalseClass]
129
+ def either_are_set?(*values)
130
+ values.any? do |value|
131
+ !value.nil?
132
+ end
133
+ end
134
+
135
+ # Check if values are valid times (can be parsed).
136
+ #
137
+ # @param values [Array<Object>] to check if valid time.
138
+ # @return [TrueClass, FalseClass]
139
+ def must_be_time(*values)
140
+ values.all? do |value|
141
+ Time.parse(value) rescue false
142
+ end
143
+ end
144
+
145
+ # Check if values are allowed.
146
+ #
147
+ # @param allowed [Array<Object>] allowed values.
148
+ # @param values [Array<Object>] to check if allowed.
149
+ # @return [TrueClass, FalseClass]
150
+ def must_be_either(allowed, *values)
151
+ values.flatten.all? do |value|
152
+ allowed.include?(value)
153
+ end
154
+ end
155
+
156
+ # Check if values are allowed, if set (not nil).
157
+ #
158
+ # @param allowed [Array<Object>] allowed values.
159
+ # @param values [Array<Object>] to check if allowed.
160
+ # @return [TrueClass, FalseClass]
161
+ def must_be_either_if_set(allowed, *values)
162
+ values[0].nil? ? true : must_be_either(allowed, values)
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,88 @@
1
+ require "sensu/settings/rules"
2
+ require "sensu/settings/validators"
3
+ require "sensu/settings/constants"
4
+
5
+ module Sensu
6
+ module Settings
7
+ class Validator
8
+ include Rules
9
+ include Validators
10
+
11
+ # @!attribute [r] failures
12
+ # @return [Array] validation failures.
13
+ attr_reader :failures
14
+
15
+ def initialize
16
+ @failures = []
17
+ end
18
+
19
+ # Run the validator.
20
+ #
21
+ # @param settings [Hash] sensu settings to validate.
22
+ # @param service [String] sensu service to validate for.
23
+ # @return [Array] validation failures.
24
+ def run(settings, service=nil)
25
+ validate_sensu(settings[:sensu])
26
+ validate_transport(settings[:transport])
27
+ validate_categories(settings)
28
+ case service
29
+ when "server"
30
+ validate_tessen(settings[:tessen])
31
+ when "client"
32
+ validate_client(settings[:client])
33
+ when "api"
34
+ validate_api(settings[:api])
35
+ when "rspec"
36
+ validate_client(settings[:client])
37
+ validate_api(settings[:api])
38
+ end
39
+ @failures
40
+ end
41
+
42
+ def reset!
43
+ failure_count = @failures.size
44
+ @failures = []
45
+ failure_count
46
+ end
47
+ alias_method :reset, :reset!
48
+
49
+ private
50
+
51
+ # Validate setting categories: checks, filters, mutators, and
52
+ # handlers. This method also validates each object type,
53
+ # ensuring that they are hashes.
54
+ #
55
+ # @param settings [Hash] sensu settings to validate.
56
+ def validate_categories(settings)
57
+ CATEGORIES.each do |category|
58
+ if is_a_hash?(settings[category])
59
+ validate_method = ("validate_" + category.to_s.chop).to_sym
60
+ settings[category].each do |name, details|
61
+ if details.is_a?(Hash)
62
+ send(validate_method, details.merge(:name => name.to_s))
63
+ else
64
+ object_type = category[0..-2]
65
+ invalid(details, "#{object_type} must be a hash")
66
+ end
67
+ end
68
+ else
69
+ invalid(settings[category], "#{category} must be a hash")
70
+ end
71
+ end
72
+ end
73
+
74
+ # Record an invalid object with a message.
75
+ #
76
+ # @param object [Object] invalid object.
77
+ # @param message [String] message explaining why the object is
78
+ # invalid.
79
+ # @return [Array] current validation failures.
80
+ def invalid(object, message)
81
+ @failures << {
82
+ :object => object,
83
+ :message => message
84
+ }
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,65 @@
1
+ module Sensu
2
+ module Settings
3
+ module Validators
4
+ module API
5
+ # Validate API authentication.
6
+ # Validates: user, password
7
+ #
8
+ # @param api [Hash] sensu api definition.
9
+ def validate_api_authentication(api)
10
+ if either_are_set?(api[:user], api[:password])
11
+ must_be_a_string(api[:user]) ||
12
+ invalid(api, "api user must be a string")
13
+ must_be_a_string(api[:password]) ||
14
+ invalid(api, "api password must be a string")
15
+ end
16
+ end
17
+
18
+ # Validate API endpoints.
19
+ # Validates: endpoints
20
+ #
21
+ # @param api [Hash] sensu api definition.
22
+ def validate_api_endpoints(api)
23
+ if is_an_array?(api[:endpoints])
24
+ api[:endpoints].each do |endpoint|
25
+ if is_a_hash?(endpoint)
26
+ if endpoint[:url]
27
+ must_be_a_string(endpoint[:url]) ||
28
+ invalid(api, "api endpoint url must be a string")
29
+ else
30
+ must_be_a_string(endpoint[:host]) ||
31
+ invalid(api, "api endpoint host must be a string")
32
+ must_be_an_integer(endpoint[:port]) ||
33
+ invalid(api, "api endpoint port must be an integer")
34
+ must_be_boolean_if_set(endpoint[:ssl]) ||
35
+ invalid(api, "api endpoint ssl must be a boolean")
36
+ end
37
+ else
38
+ invalid(api, "api endpoints must each be a hash")
39
+ end
40
+ end
41
+ else
42
+ invalid(api, "api endpoints must be an array")
43
+ end
44
+ end
45
+
46
+ # Validate a Sensu API definition.
47
+ # Validates: port, bind
48
+ #
49
+ # @param api [Hash] sensu api definition.
50
+ def validate_api(api)
51
+ must_be_a_hash_if_set(api) ||
52
+ invalid(api, "api must be a hash")
53
+ if is_a_hash?(api)
54
+ must_be_an_integer_if_set(api[:port]) ||
55
+ invalid(api, "api port must be an integer")
56
+ must_be_a_string_if_set(api[:bind]) ||
57
+ invalid(api, "api bind must be a string")
58
+ validate_api_authentication(api)
59
+ validate_api_endpoints(api) if api[:endpoints]
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,253 @@
1
+ require "parse-cron"
2
+
3
+ module Sensu
4
+ module Settings
5
+ module Validators
6
+ module Check
7
+ # Validate check name.
8
+ # Validates: name
9
+ #
10
+ # @param check [Hash] sensu check definition.
11
+ def validate_check_name(check)
12
+ must_be_a_string(check[:name]) ||
13
+ invalid(check, "check name must be a string")
14
+ must_match_regex(/\A[\w\.-]+\z/, check[:name]) ||
15
+ invalid(check, "check name cannot contain spaces or special characters")
16
+ end
17
+
18
+ # Validate check execution.
19
+ # Validates: command, extension, timeout
20
+ #
21
+ # @param check [Hash] sensu check definition.
22
+ def validate_check_execution(check)
23
+ must_be_a_string_if_set(check[:command]) ||
24
+ invalid(check, "check command must be a string")
25
+ must_be_a_string_if_set(check[:extension]) ||
26
+ invalid(check, "check extension must be a string")
27
+ (!check[:command].nil? ^ !check[:extension].nil?) ||
28
+ invalid(check, "either check command or extension must be set")
29
+ must_be_a_numeric_if_set(check[:timeout]) ||
30
+ invalid(check, "check timeout must be numeric")
31
+ must_be_boolean_if_set(check[:stdin]) ||
32
+ invalid(check, "check stdin must be boolean")
33
+ end
34
+
35
+ # Validate check source.
36
+ # Validates: source
37
+ #
38
+ # @param check [Hash] sensu check definition.
39
+ def validate_check_source(check)
40
+ if is_a_string?(check[:source])
41
+ must_match_regex(/\A[\w\.-]*([:]{3}[\w\|\.-]+[:]{3}[\w\.-]*|[\w\.-]+)\z/, check[:source]) ||
42
+ invalid(check, "check source cannot contain spaces, special characters, or invalid tokens")
43
+ else
44
+ invalid(check, "check source must be a string")
45
+ end
46
+ end
47
+
48
+ # Validate check cron.
49
+ # Validates: cron
50
+ #
51
+ # @param check [Hash] sensu check definition.
52
+ def validate_check_cron(check)
53
+ must_be_a_string(check[:cron]) ||
54
+ invalid(check, "check cron must be a string")
55
+ begin
56
+ cron_parser = CronParser.new(check[:cron])
57
+ cron_parser.next(Time.now)
58
+ rescue ArgumentError
59
+ invalid(check, "check cron string must use the cron syntax")
60
+ end
61
+ end
62
+
63
+ # Validate check scheduling.
64
+ # Validates: publish, interval, standalone, subscribers
65
+ #
66
+ # @param check [Hash] sensu check definition.
67
+ def validate_check_scheduling(check)
68
+ must_be_boolean_if_set(check[:publish]) ||
69
+ invalid(check, "check publish must be boolean")
70
+ unless check[:publish] == false
71
+ if check[:cron]
72
+ validate_check_cron(check)
73
+ else
74
+ (must_be_an_integer(check[:interval]) && check[:interval] > 0) ||
75
+ invalid(check, "check interval must be an integer greater than 0")
76
+ end
77
+ end
78
+ must_be_boolean_if_set(check[:standalone]) ||
79
+ invalid(check, "check standalone must be boolean")
80
+ unless check[:standalone]
81
+ if is_an_array?(check[:subscribers])
82
+ items_must_be_strings(check[:subscribers]) ||
83
+ invalid(check, "check subscribers must each be a string")
84
+ else
85
+ invalid(check, "check subscribers must be an array")
86
+ end
87
+ end
88
+ end
89
+
90
+ # Validate check proxy requests.
91
+ # Validates: proxy_requests (client_attributes, splay, splay_coverage)
92
+ #
93
+ # @param check [Hash] sensu check definition.
94
+ def validate_check_proxy_requests(check)
95
+ if is_a_hash?(check[:proxy_requests])
96
+ proxy_requests = check[:proxy_requests]
97
+ must_be_a_hash(proxy_requests[:client_attributes]) ||
98
+ invalid(check, "check proxy_requests client_attributes must be a hash")
99
+ must_be_boolean_if_set(proxy_requests[:splay]) ||
100
+ invalid(check, "check proxy_requests splay must be boolean")
101
+ if proxy_requests[:splay_coverage]
102
+ (must_be_an_integer(proxy_requests[:splay_coverage]) &&
103
+ proxy_requests[:splay_coverage] > 0 &&
104
+ proxy_requests[:splay_coverage] < 100) ||
105
+ invalid(check, "check proxy_requests splay_coverage must be an integer greater than 0 and less than 100")
106
+ end
107
+ else
108
+ invalid(check, "check proxy_requests must be a hash")
109
+ end
110
+ end
111
+
112
+ # Validate check handling.
113
+ # Validates: handler, handlers
114
+ #
115
+ # @param check [Hash] sensu check definition.
116
+ def validate_check_handling(check)
117
+ must_be_a_string_if_set(check[:handler]) ||
118
+ invalid(check, "check handler must be a string")
119
+ must_be_an_array_if_set(check[:handlers]) ||
120
+ invalid(check, "check handlers must be an array")
121
+ if is_an_array?(check[:handlers])
122
+ items_must_be_strings(check[:handlers]) ||
123
+ invalid(check, "check handlers must each be a string")
124
+ end
125
+ end
126
+
127
+ # Validate check ttl.
128
+ # Validates: ttl, ttl_status
129
+ #
130
+ # @param check [Hash] sensu check definition.
131
+ def validate_check_ttl(check)
132
+ if is_an_integer?(check[:ttl])
133
+ check[:ttl] > 0 ||
134
+ invalid(check, "check ttl must be greater than 0")
135
+ else
136
+ invalid(check, "check ttl must be an integer")
137
+ end
138
+ must_be_an_integer_if_set(check[:ttl_status]) ||
139
+ invalid(check, "check ttl_status must be an integer")
140
+ end
141
+
142
+ # Validate check aggregate.
143
+ # Validates: aggregate
144
+ #
145
+ # @param check [Hash] sensu check definition.
146
+ def validate_check_aggregate(check)
147
+ if check[:aggregates]
148
+ if is_an_array?(check[:aggregates])
149
+ items_must_be_strings(check[:aggregates], /\A[\w\.:|-]+\z/) ||
150
+ invalid(check, "check aggregates items must be strings without spaces or special characters")
151
+ else
152
+ invalid(check, "check aggregates must be an array")
153
+ end
154
+ end
155
+ if check[:aggregate]
156
+ if is_a_string?(check[:aggregate])
157
+ must_match_regex(/\A[\w\.:|-]+\z/, check[:aggregate]) ||
158
+ invalid(check, "check aggregate cannot contain spaces or special characters")
159
+ else
160
+ must_be_boolean(check[:aggregate]) ||
161
+ invalid(check, "check aggregate must be a string (name) or boolean")
162
+ end
163
+ end
164
+ end
165
+
166
+ # Validate check flap detection.
167
+ # Validates: low_flap_threshold, high_flap_threshold
168
+ #
169
+ # @param check [Hash] sensu check definition.
170
+ def validate_check_flap_detection(check)
171
+ if either_are_set?(check[:low_flap_threshold], check[:high_flap_threshold])
172
+ must_be_an_integer(check[:low_flap_threshold]) ||
173
+ invalid(check, "check low flap threshold must be an integer")
174
+ must_be_an_integer(check[:high_flap_threshold]) ||
175
+ invalid(check, "check high flap threshold must be an integer")
176
+ end
177
+ end
178
+
179
+ # Validate check hook execution.
180
+ # Validates: command, timeout
181
+ #
182
+ # @param check [Hash] sensu check definition.
183
+ # @param hook [Hash] sensu check hook definition.
184
+ def validate_check_hook_execution(check, hook)
185
+ must_be_a_string(hook[:command]) ||
186
+ invalid(check, "check hook command must be a string")
187
+ must_be_a_numeric_if_set(hook[:timeout]) ||
188
+ invalid(check, "check hook timeout must be numeric")
189
+ must_be_boolean_if_set(hook[:stdin]) ||
190
+ invalid(check, "check hook stdin must be boolean")
191
+ end
192
+
193
+ # Validate check hooks.
194
+ # Validates: hooks
195
+ #
196
+ # @param check [Hash] sensu check definition.
197
+ def validate_check_hooks(check)
198
+ if check[:hooks].is_a?(Hash)
199
+ check[:hooks].each do |key, hook|
200
+ must_be_either(%w[ok warning critical unknown], key.to_s) ||
201
+ (0..255).map {|i| i.to_s}.include?(key.to_s) ||
202
+ key.to_s == "non-zero" ||
203
+ invalid(check, "check hook key must be a severity, status, or 'non-zero'")
204
+ validate_check_hook_execution(check, hook)
205
+ end
206
+ else
207
+ invalid(check, "check hooks must be a hash")
208
+ end
209
+ end
210
+
211
+ # Validate check truncate output.
212
+ # Validates: truncate_output, truncate_output_length
213
+ #
214
+ # @param check [Hash] sensu check definition.
215
+ def validate_check_truncate_output(check)
216
+ must_be_boolean_if_set(check[:truncate_output]) ||
217
+ invalid(check, "check truncate_output must be boolean")
218
+ if check[:truncate_output_length]
219
+ (must_be_an_integer(check[:truncate_output_length]) &&
220
+ check[:truncate_output_length] > 0) ||
221
+ invalid(check, "check truncate_output_length must be an integer greater than 0")
222
+ end
223
+ end
224
+
225
+ # Validate check subdue.
226
+ # Validates: subdue
227
+ #
228
+ # @param check [Hash] sensu check definition.
229
+ def validate_check_subdue(check)
230
+ validate_time_windows(check, "check", :subdue)
231
+ end
232
+
233
+ # Validate a Sensu check definition.
234
+ #
235
+ # @param check [Hash] sensu check definition.
236
+ def validate_check(check)
237
+ validate_check_name(check)
238
+ validate_check_execution(check)
239
+ validate_check_source(check) if check[:source]
240
+ validate_check_scheduling(check)
241
+ validate_check_proxy_requests(check) if check[:proxy_requests]
242
+ validate_check_handling(check)
243
+ validate_check_ttl(check) if check[:ttl]
244
+ validate_check_aggregate(check)
245
+ validate_check_flap_detection(check)
246
+ validate_check_hooks(check) if check[:hooks]
247
+ validate_check_truncate_output(check)
248
+ validate_check_subdue(check) if check[:subdue]
249
+ end
250
+ end
251
+ end
252
+ end
253
+ end