kennel 2.10.0 → 2.12.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.
- checksums.yaml +4 -4
- data/lib/kennel/models/monitor.rb +75 -45
- data/lib/kennel/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ef24e36c2feeba08b92edd003e6d11bfefaa31bd0839765393325b29e8132cb3
|
|
4
|
+
data.tar.gz: 54f97c79250c564d62f01837cc85badc4cdc3357860f40e0408d33640d1a94a8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '08b01acd5c750342d5134e6c2ca6d235bdb5cefc8f0b61b46e7b475ed7be6fd677772bab5a032d2a67685e02389d6741f05ef1e05a0758d3c6f6ff2fae68cb0d'
|
|
7
|
+
data.tar.gz: 79cc9956a1b1790c2e6bfb7f25c981542a2b21d96f8c3d1bdc5328d1e708c410372fa9405bf16a3fbaf7a27aaf1954ca71cb760ae4bfad82fa346b10635b0e8c
|
|
@@ -6,7 +6,8 @@ module Kennel
|
|
|
6
6
|
|
|
7
7
|
OPTIONAL_SERVICE_CHECK_THRESHOLDS = [:ok, :warning].freeze
|
|
8
8
|
READONLY_ATTRIBUTES = superclass::READONLY_ATTRIBUTES + [
|
|
9
|
-
:multi, :matching_downtimes, :overall_state_modified, :overall_state, :restricted_roles, :draft_status, :assets
|
|
9
|
+
:multi, :matching_downtimes, :overall_state_modified, :overall_state, :restricted_roles, :draft_status, :assets,
|
|
10
|
+
:enable_logs_sample
|
|
10
11
|
]
|
|
11
12
|
TRACKING_FIELD = :message
|
|
12
13
|
|
|
@@ -25,7 +26,7 @@ module Kennel
|
|
|
25
26
|
group_retention_duration: nil,
|
|
26
27
|
groupby_simple_monitor: false,
|
|
27
28
|
variables: nil,
|
|
28
|
-
on_missing_data:
|
|
29
|
+
on_missing_data: nil,
|
|
29
30
|
notification_preset_name: nil,
|
|
30
31
|
notify_by: nil
|
|
31
32
|
}.freeze
|
|
@@ -55,6 +56,7 @@ module Kennel
|
|
|
55
56
|
# datadog UI sets this to false by default, but true is safer
|
|
56
57
|
# except for log alerts which will always have "no error" gaps and should default to false
|
|
57
58
|
notify_no_data: -> { !SKIP_NOTIFY_NO_DATA_TYPES.include?(type) },
|
|
59
|
+
no_data_timeframe: -> { MONITOR_OPTION_DEFAULTS.fetch(:no_data_timeframe) },
|
|
58
60
|
notify_audit: -> { MONITOR_OPTION_DEFAULTS.fetch(:notify_audit) },
|
|
59
61
|
new_host_delay: -> { MONITOR_OPTION_DEFAULTS.fetch(:new_host_delay) },
|
|
60
62
|
new_group_delay: -> { nil },
|
|
@@ -74,6 +76,8 @@ module Kennel
|
|
|
74
76
|
)
|
|
75
77
|
|
|
76
78
|
def build_json
|
|
79
|
+
no_data_options = configure_no_data
|
|
80
|
+
|
|
77
81
|
data = super.merge(
|
|
78
82
|
name: "#{name}#{LOCK}",
|
|
79
83
|
type: type,
|
|
@@ -83,8 +87,7 @@ module Kennel
|
|
|
83
87
|
priority: priority,
|
|
84
88
|
options: {
|
|
85
89
|
timeout_h: timeout_h,
|
|
86
|
-
|
|
87
|
-
no_data_timeframe: notify_no_data ? no_data_timeframe : nil,
|
|
90
|
+
**no_data_options.except(:on_missing_data),
|
|
88
91
|
notify_audit: notify_audit,
|
|
89
92
|
require_full_window: require_full_window,
|
|
90
93
|
new_host_delay: new_host_delay,
|
|
@@ -92,33 +95,14 @@ module Kennel
|
|
|
92
95
|
include_tags: true,
|
|
93
96
|
escalation_message: Utils.presence(escalation_message.strip),
|
|
94
97
|
evaluation_delay: evaluation_delay,
|
|
95
|
-
locked: false, # deprecated: setting this to true will likely fail
|
|
96
98
|
renotify_interval: renotify_interval || 0,
|
|
97
|
-
variables: variables
|
|
99
|
+
variables: variables,
|
|
100
|
+
**configure_thresholds,
|
|
101
|
+
**no_data_options.slice(:on_missing_data) # moved here to avoid generated diff
|
|
98
102
|
}
|
|
99
103
|
)
|
|
100
104
|
|
|
101
105
|
options = data[:options]
|
|
102
|
-
if data.fetch(:type) != "composite"
|
|
103
|
-
thresholds = (options[:thresholds] = { critical: critical })
|
|
104
|
-
|
|
105
|
-
# warning, ok, critical_recovery, and warning_recovery are optional
|
|
106
|
-
[:warning, :ok, :critical_recovery, :warning_recovery].each do |key|
|
|
107
|
-
if (value = send(key))
|
|
108
|
-
thresholds[key] = value
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
thresholds[:critical] = critical unless
|
|
113
|
-
case data.fetch(:type)
|
|
114
|
-
when "service check"
|
|
115
|
-
# avoid diff for default values of 1
|
|
116
|
-
OPTIONAL_SERVICE_CHECK_THRESHOLDS.each { |t| thresholds[t] ||= 1 }
|
|
117
|
-
when "query alert"
|
|
118
|
-
# metric and query values are stored as float by datadog
|
|
119
|
-
thresholds.each { |k, v| thresholds[k] = Float(v) }
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
106
|
|
|
123
107
|
# set without causing lots of nulls to be stored
|
|
124
108
|
if (notify_by_value = notify_by)
|
|
@@ -149,30 +133,46 @@ module Kennel
|
|
|
149
133
|
# Add in statuses where we would re notify on. Possible values: alert, no data, warn
|
|
150
134
|
if options[:renotify_interval] != 0
|
|
151
135
|
statuses = ["alert"]
|
|
152
|
-
statuses << "no data" if options[:notify_no_data]
|
|
136
|
+
statuses << "no data" if options[:notify_no_data] || options[:on_missing_data] == "show_and_notify_no_data"
|
|
153
137
|
statuses << "warn" if options.dig(:thresholds, :warning)
|
|
154
138
|
options[:renotify_statuses] = statuses
|
|
155
139
|
end
|
|
156
140
|
|
|
157
|
-
# on_missing_data cannot be used with notify_no_data or no_data_timeframe
|
|
158
|
-
# TODO migrate everything to only use on_missing_data
|
|
159
|
-
if data.fetch(:type) == "event-v2 alert" || on_missing_data != "default"
|
|
160
|
-
options[:on_missing_data] = on_missing_data
|
|
161
|
-
options[:notify_no_data] = false # cannot set nil or it's an endless update loop
|
|
162
|
-
options.delete :no_data_timeframe
|
|
163
|
-
end
|
|
164
|
-
|
|
165
141
|
# only set when needed to avoid big diff
|
|
166
142
|
if (notification_preset_name = notification_preset_name())
|
|
167
143
|
options[:notification_preset_name] = notification_preset_name
|
|
168
144
|
end
|
|
169
145
|
|
|
170
|
-
# locked is deprecated, will fail if used
|
|
171
|
-
options.delete :locked
|
|
172
|
-
|
|
173
146
|
data
|
|
174
147
|
end
|
|
175
148
|
|
|
149
|
+
# TODO: migrate everything to only use on_missing_data by only sending notify_no_data when it was set by a user
|
|
150
|
+
# and enforce that it is not set at the same time as on_missing_data
|
|
151
|
+
def configure_no_data
|
|
152
|
+
notify = notify_no_data
|
|
153
|
+
timeframe = no_data_timeframe
|
|
154
|
+
action = on_missing_data
|
|
155
|
+
action ||= "default" if type == "event-v2 alert"
|
|
156
|
+
|
|
157
|
+
# TODO: mark setting action && !notify.nil? at all as invalid
|
|
158
|
+
if action && timeframe
|
|
159
|
+
invalid! :invalid_no_data_config, "set either no_data_timeframe or on_missing_data"
|
|
160
|
+
end
|
|
161
|
+
if type == "composite" && action
|
|
162
|
+
invalid! :invalid_no_data_config, "cannot use on_missing_data with composite monitor"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# on_missing_data cannot be used with notify_no_data + no_data_timeframe
|
|
166
|
+
if action
|
|
167
|
+
{ on_missing_data: action || "default" }
|
|
168
|
+
else
|
|
169
|
+
{
|
|
170
|
+
notify_no_data: notify,
|
|
171
|
+
no_data_timeframe: notify ? no_data_timeframe || default_no_data_timeframe : nil
|
|
172
|
+
}
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
176
|
def resolve_linked_tracking_ids!(id_map, **args)
|
|
177
177
|
case as_json[:type]
|
|
178
178
|
when "composite", "slo alert"
|
|
@@ -194,7 +194,7 @@ module Kennel
|
|
|
194
194
|
# deprecated this setting is no longer returned by dd for new monitors
|
|
195
195
|
# datadog UI warns when setting no data timeframe to less than 2x the query window
|
|
196
196
|
# limited to 24h because `no_data_timeframe must not exceed group retention` and max group retention is 24h
|
|
197
|
-
def
|
|
197
|
+
def default_no_data_timeframe
|
|
198
198
|
default = 60
|
|
199
199
|
if type == "query alert" && (minutes = query_window_minutes)
|
|
200
200
|
(minutes * 2).clamp(default, 24 * 60)
|
|
@@ -206,7 +206,8 @@ module Kennel
|
|
|
206
206
|
# validate that monitors that alert on no data resolve in external services by using timeout_h, so it sends a
|
|
207
207
|
# notification when the no data group is removed from the monitor, which datadog does automatically after 24h
|
|
208
208
|
def timeout_h
|
|
209
|
-
|
|
209
|
+
sending_no_data_notifications = (on_missing_data ? on_missing_data == "show_and_notify_no_data" : notify_no_data)
|
|
210
|
+
sending_no_data_notifications ? 24 : MONITOR_OPTION_DEFAULTS.fetch(:timeout_h)
|
|
210
211
|
end
|
|
211
212
|
|
|
212
213
|
def self.api_resource
|
|
@@ -235,7 +236,9 @@ module Kennel
|
|
|
235
236
|
ignore_default(expected, actual, MONITOR_DEFAULTS)
|
|
236
237
|
|
|
237
238
|
options = actual.fetch(:options)
|
|
238
|
-
|
|
239
|
+
|
|
240
|
+
# we do not manage silenced: ignore it when diffing
|
|
241
|
+
options.delete(:silenced)
|
|
239
242
|
|
|
240
243
|
# fields are not returned when set to true
|
|
241
244
|
if ["service check", "event alert"].include?(actual[:type])
|
|
@@ -265,13 +268,38 @@ module Kennel
|
|
|
265
268
|
options.delete(:escalation_message)
|
|
266
269
|
expected_options.delete(:escalation_message)
|
|
267
270
|
end
|
|
271
|
+
|
|
268
272
|
# locked is deprecated: ignored when diffing
|
|
269
273
|
options.delete(:locked)
|
|
270
|
-
expected_options.delete(:locked)
|
|
271
274
|
end
|
|
272
275
|
|
|
273
276
|
private
|
|
274
277
|
|
|
278
|
+
def configure_thresholds
|
|
279
|
+
return {} if type == "composite"
|
|
280
|
+
|
|
281
|
+
thresholds = { critical: critical }
|
|
282
|
+
|
|
283
|
+
# set optional variables
|
|
284
|
+
[:warning, :ok, :critical_recovery, :warning_recovery].each do |key|
|
|
285
|
+
if (value = send(key))
|
|
286
|
+
thresholds[key] = value
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# custom logic for some types
|
|
291
|
+
case type
|
|
292
|
+
when "service check"
|
|
293
|
+
# avoid diff for default values of 1
|
|
294
|
+
OPTIONAL_SERVICE_CHECK_THRESHOLDS.each { |t| thresholds[t] ||= 1 }
|
|
295
|
+
when "query alert"
|
|
296
|
+
# metric and query values are stored as float by datadog
|
|
297
|
+
thresholds.each { |k, v| thresholds[k] = Float(v) }
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
{ thresholds: thresholds }
|
|
301
|
+
end
|
|
302
|
+
|
|
275
303
|
def validate_json(data)
|
|
276
304
|
super
|
|
277
305
|
|
|
@@ -287,9 +315,11 @@ module Kennel
|
|
|
287
315
|
end
|
|
288
316
|
|
|
289
317
|
# verify query includes critical value
|
|
290
|
-
if (
|
|
291
|
-
if
|
|
292
|
-
|
|
318
|
+
if (critical = data.dig(:options, :thresholds, :critical))
|
|
319
|
+
if (query_value = data.fetch(:query)[/\s*[<>]=?\s*(\d+(\.\d+)?)\s*$/, 1])
|
|
320
|
+
if Float(query_value) != Float(critical)
|
|
321
|
+
invalid! :critical_does_not_match_query, "critical and value used in query must match"
|
|
322
|
+
end
|
|
293
323
|
end
|
|
294
324
|
end
|
|
295
325
|
|
data/lib/kennel/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kennel
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.12.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michael Grosser
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-01-
|
|
11
|
+
date: 2026-01-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: diff-lcs
|