kennel 1.78.4 → 1.81.2
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/Readme.md +14 -8
- data/lib/kennel.rb +36 -8
- data/lib/kennel/models/dashboard.rb +21 -17
- data/lib/kennel/models/monitor.rb +16 -5
- data/lib/kennel/models/record.rb +8 -9
- data/lib/kennel/models/slo.rb +1 -1
- data/lib/kennel/syncer.rb +47 -18
- data/lib/kennel/utils.rb +5 -0
- data/lib/kennel/version.rb +1 -1
- data/template/Readme.md +13 -7
- 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: 5f9d3050dbb7a4e94cd22e64618142bedffd6fdfc5b5ee8e20b621b90f1d8f27
|
|
4
|
+
data.tar.gz: 640a86b74e46e27ec7f1b09dd555f0ba8f99e4fc1f687e5230bb00d12636ae1d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 80dbfff63550b6f5c3127cb8ecc97db6b3db38876469bcb9d50fce00a7e1b78e2f473dd3c3abaec081cb21037f53be72021d907c4285352b30dd3b6991f6c622
|
|
7
|
+
data.tar.gz: 02a3122ec70a951dc01f919c4d13877de88c6266048d006770a62adadd19587d74a603e8281699f878be0a20227a7086e37727c751cf5833e815fc795e3f9ee3
|
data/Readme.md
CHANGED
|
@@ -84,7 +84,7 @@ end
|
|
|
84
84
|
- `cp .env.example .env`
|
|
85
85
|
- open [Datadog API Settings](https://app.datadoghq.com/account/settings#api)
|
|
86
86
|
- create a `API Key` or get an existing one from an admin, then add it to `.env` as `DATADOG_API_KEY`
|
|
87
|
-
-
|
|
87
|
+
- open [Datadog API Settings](https://app.datadoghq.com/access/application-keys) and create a new key, then add it to `.env` as `DATADOG_APP_KEY=`
|
|
88
88
|
- change the `DATADOG_SUBDOMAIN=app` in `.env` to your companies subdomain if you have one
|
|
89
89
|
- verify it works by running `rake plan`, it might show some diff, but should not crash
|
|
90
90
|
-->
|
|
@@ -212,14 +212,20 @@ removing the `id` will cause kennel to create a new resource in datadog.
|
|
|
212
212
|
Some validations might be too strict for your usecase or just wrong, please [open an issue](https://github.com/grosser/kennel/issues) and
|
|
213
213
|
to unblock use the `validate: -> { false }` option.
|
|
214
214
|
|
|
215
|
-
### Linking with
|
|
215
|
+
### Linking resources with kennel_id
|
|
216
216
|
|
|
217
|
-
|
|
217
|
+
Link resources with their kennel_id in the format `project kennel_id` + `:` + `resource kennel_id`,
|
|
218
|
+
this should be used to create dependent resources like monitor + slos,
|
|
219
|
+
so they can be created in a single update and can be re-created if any of them is deleted.
|
|
218
220
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
221
|
+
|Resource|Type|Syntax|
|
|
222
|
+
|---|---|---|
|
|
223
|
+
|Dashboard|uptime|`monitor: {id: "foo:bar"}`|
|
|
224
|
+
|Dashboard|alert_graph|`alert_id: "foo:bar"`|
|
|
225
|
+
|Dashboard|slo|`slo_id: "foo:bar"`|
|
|
226
|
+
|Monitor|composite|`query: -> { "%{foo:bar} && %{foo:baz}" }`|
|
|
227
|
+
|Monitor|slo alert|`query: -> { "error_budget(\"%{foo:bar}\").over(\"7d\") > 123.0" }`|
|
|
228
|
+
|Slo|monitor|`monitor_ids: -> ["foo:bar"]`|
|
|
223
229
|
|
|
224
230
|
### Debugging changes locally
|
|
225
231
|
|
|
@@ -296,5 +302,5 @@ Author
|
|
|
296
302
|
[Michael Grosser](http://grosser.it)<br/>
|
|
297
303
|
michael@grosser.it<br/>
|
|
298
304
|
License: MIT<br/>
|
|
299
|
-
|
|
305
|
+

|
|
300
306
|
<!-- NOT IN -->
|
data/lib/kennel.rb
CHANGED
|
@@ -39,12 +39,7 @@ module Kennel
|
|
|
39
39
|
attr_accessor :out, :err
|
|
40
40
|
|
|
41
41
|
def generate
|
|
42
|
-
|
|
43
|
-
generated.each do |part|
|
|
44
|
-
path = "generated/#{part.tracking_id.sub(":", "/")}.json"
|
|
45
|
-
FileUtils.mkdir_p(File.dirname(path))
|
|
46
|
-
File.write(path, JSON.pretty_generate(part.as_json) << "\n")
|
|
47
|
-
end
|
|
42
|
+
store generated
|
|
48
43
|
end
|
|
49
44
|
|
|
50
45
|
def plan
|
|
@@ -58,6 +53,35 @@ module Kennel
|
|
|
58
53
|
|
|
59
54
|
private
|
|
60
55
|
|
|
56
|
+
def store(parts)
|
|
57
|
+
Progress.progress "Storing" do
|
|
58
|
+
old = Dir["generated/**/*"]
|
|
59
|
+
used = []
|
|
60
|
+
|
|
61
|
+
Utils.parallel(parts, max: 2) do |part|
|
|
62
|
+
path = "generated/#{part.tracking_id.tr("/", ":").sub(":", "/")}.json"
|
|
63
|
+
used << File.dirname(path) # only 1 level of sub folders, so this is safe
|
|
64
|
+
used << path
|
|
65
|
+
write_file_if_necessary(path, JSON.pretty_generate(part.as_json) << "\n")
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# deleting all is slow, so only delete the extras
|
|
69
|
+
(old - used).each { |p| FileUtils.rm_rf(p) }
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def write_file_if_necessary(path, content)
|
|
74
|
+
# 99% case
|
|
75
|
+
begin
|
|
76
|
+
return if File.read(path) == content
|
|
77
|
+
rescue Errno::ENOENT
|
|
78
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# slow 1% case
|
|
82
|
+
File.write(path, content)
|
|
83
|
+
end
|
|
84
|
+
|
|
61
85
|
def syncer
|
|
62
86
|
@syncer ||= Syncer.new(api, generated, project: ENV["PROJECT"])
|
|
63
87
|
end
|
|
@@ -73,8 +97,12 @@ module Kennel
|
|
|
73
97
|
parts = Models::Project.recursive_subclasses.flat_map do |project_class|
|
|
74
98
|
project_class.new.validated_parts
|
|
75
99
|
end
|
|
76
|
-
parts.
|
|
77
|
-
|
|
100
|
+
parts.group_by(&:tracking_id).each do |tracking_id, same|
|
|
101
|
+
next if same.size == 1
|
|
102
|
+
raise <<~ERROR
|
|
103
|
+
#{tracking_id} is defined #{same.size} times
|
|
104
|
+
use a different `kennel_id` when defining multiple projects/monitors/dashboards to avoid this conflict
|
|
105
|
+
ERROR
|
|
78
106
|
end
|
|
79
107
|
parts
|
|
80
108
|
end
|
|
@@ -140,16 +140,16 @@ module Kennel
|
|
|
140
140
|
when "uptime"
|
|
141
141
|
if ids = definition[:monitor_ids]
|
|
142
142
|
definition[:monitor_ids] = ids.map do |id|
|
|
143
|
-
tracking_id?(id) ? resolve_link(id, :monitor, id_map, **args) : id
|
|
143
|
+
tracking_id?(id) ? (resolve_link(id, :monitor, id_map, **args) || id) : id
|
|
144
144
|
end
|
|
145
145
|
end
|
|
146
146
|
when "alert_graph"
|
|
147
147
|
if (id = definition[:alert_id]) && tracking_id?(id)
|
|
148
|
-
definition[:alert_id] = resolve_link(id, :monitor, id_map, **args).to_s
|
|
148
|
+
definition[:alert_id] = (resolve_link(id, :monitor, id_map, **args) || id).to_s
|
|
149
149
|
end
|
|
150
150
|
when "slo"
|
|
151
151
|
if (id = definition[:slo_id]) && tracking_id?(id)
|
|
152
|
-
definition[:slo_id] = resolve_link(id, :slo, id_map, **args).to_s
|
|
152
|
+
definition[:slo_id] = (resolve_link(id, :slo, id_map, **args) || id).to_s
|
|
153
153
|
end
|
|
154
154
|
end
|
|
155
155
|
end
|
|
@@ -186,22 +186,26 @@ module Kennel
|
|
|
186
186
|
end
|
|
187
187
|
|
|
188
188
|
def render_definitions(definitions)
|
|
189
|
-
definitions.map do |title, type, display_type, queries, options = {},
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
189
|
+
definitions.map do |title, type, display_type, queries, options = {}, too_many_args = nil|
|
|
190
|
+
if title.is_a?(Hash) && !type
|
|
191
|
+
title # user gave a full widget, just use it
|
|
192
|
+
else
|
|
193
|
+
# validate inputs
|
|
194
|
+
if too_many_args || (!title || !type || !queries || !options.is_a?(Hash))
|
|
195
|
+
raise ArgumentError, "Expected exactly 5 arguments for each definition (title, type, display_type, queries, options)"
|
|
196
|
+
end
|
|
197
|
+
if (SUPPORTED_DEFINITION_OPTIONS | options.keys) != SUPPORTED_DEFINITION_OPTIONS
|
|
198
|
+
raise ArgumentError, "Supported options are: #{SUPPORTED_DEFINITION_OPTIONS.map(&:inspect).join(", ")}"
|
|
199
|
+
end
|
|
197
200
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
201
|
+
# build definition
|
|
202
|
+
requests = Array(queries).map do |q|
|
|
203
|
+
request = { q: q }
|
|
204
|
+
request[:display_type] = display_type if display_type
|
|
205
|
+
request
|
|
206
|
+
end
|
|
207
|
+
{ definition: { title: title, type: type, requests: requests, **options } }
|
|
203
208
|
end
|
|
204
|
-
{ definition: { title: title, type: type, requests: requests, **options } }
|
|
205
209
|
end
|
|
206
210
|
end
|
|
207
211
|
end
|
|
@@ -12,6 +12,10 @@ module Kennel
|
|
|
12
12
|
:multi, :matching_downtimes, :overall_state_modified, :overall_state, :restricted_roles
|
|
13
13
|
]
|
|
14
14
|
|
|
15
|
+
MONITOR_DEFAULTS = {
|
|
16
|
+
priority: nil
|
|
17
|
+
}.freeze
|
|
18
|
+
|
|
15
19
|
# defaults that datadog uses when options are not sent, so safe to leave out if our values match their defaults
|
|
16
20
|
MONITOR_OPTION_DEFAULTS = {
|
|
17
21
|
evaluation_delay: nil,
|
|
@@ -27,7 +31,7 @@ module Kennel
|
|
|
27
31
|
settings(
|
|
28
32
|
:query, :name, :message, :escalation_message, :critical, :type, :renotify_interval, :warning, :timeout_h, :evaluation_delay,
|
|
29
33
|
:ok, :no_data_timeframe, :notify_no_data, :notify_audit, :tags, :critical_recovery, :warning_recovery, :require_full_window,
|
|
30
|
-
:threshold_windows, :new_host_delay
|
|
34
|
+
:threshold_windows, :new_host_delay, :priority
|
|
31
35
|
)
|
|
32
36
|
|
|
33
37
|
defaults(
|
|
@@ -46,7 +50,8 @@ module Kennel
|
|
|
46
50
|
evaluation_delay: -> { MONITOR_OPTION_DEFAULTS.fetch(:evaluation_delay) },
|
|
47
51
|
critical_recovery: -> { nil },
|
|
48
52
|
warning_recovery: -> { nil },
|
|
49
|
-
threshold_windows: -> { nil }
|
|
53
|
+
threshold_windows: -> { nil },
|
|
54
|
+
priority: -> { MONITOR_DEFAULTS.fetch(:priority) }
|
|
50
55
|
)
|
|
51
56
|
|
|
52
57
|
def as_json
|
|
@@ -57,6 +62,7 @@ module Kennel
|
|
|
57
62
|
query: query.strip,
|
|
58
63
|
message: message.strip,
|
|
59
64
|
tags: tags.uniq,
|
|
65
|
+
priority: priority,
|
|
60
66
|
options: {
|
|
61
67
|
timeout_h: timeout_h,
|
|
62
68
|
notify_no_data: notify_no_data,
|
|
@@ -106,9 +112,11 @@ module Kennel
|
|
|
106
112
|
end
|
|
107
113
|
|
|
108
114
|
def resolve_linked_tracking_ids!(id_map, **args)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
case as_json[:type]
|
|
116
|
+
when "composite", "slo alert"
|
|
117
|
+
type = (as_json[:type] == "composite" ? :monitor : :slo)
|
|
118
|
+
as_json[:query] = as_json[:query].gsub(/%{(.*?)}/) do
|
|
119
|
+
resolve_link($1, type, id_map, **args) || $&
|
|
112
120
|
end
|
|
113
121
|
end
|
|
114
122
|
end
|
|
@@ -129,6 +137,9 @@ module Kennel
|
|
|
129
137
|
|
|
130
138
|
def self.normalize(expected, actual)
|
|
131
139
|
super
|
|
140
|
+
|
|
141
|
+
ignore_default(expected, actual, MONITOR_DEFAULTS)
|
|
142
|
+
|
|
132
143
|
options = actual.fetch(:options)
|
|
133
144
|
options.delete(:silenced) # we do not manage silenced, so ignore it when diffing
|
|
134
145
|
|
data/lib/kennel/models/record.rb
CHANGED
|
@@ -65,19 +65,18 @@ module Kennel
|
|
|
65
65
|
|
|
66
66
|
private
|
|
67
67
|
|
|
68
|
-
def resolve_link(
|
|
69
|
-
|
|
70
|
-
if
|
|
68
|
+
def resolve_link(tracking_id, type, id_map, force:)
|
|
69
|
+
id = id_map[tracking_id]
|
|
70
|
+
if id == :new
|
|
71
71
|
if force
|
|
72
|
-
#
|
|
73
|
-
invalid! "#{id} needs to already exist, try again"
|
|
72
|
+
invalid! "#{type} #{tracking_id} was referenced but is also created by the current run.\nIt could not be created because of a circular dependency, try creating only some of the resources"
|
|
74
73
|
else
|
|
75
|
-
|
|
74
|
+
nil # will be re-resolved after the linked object was created
|
|
76
75
|
end
|
|
77
|
-
elsif
|
|
78
|
-
|
|
76
|
+
elsif id
|
|
77
|
+
id
|
|
79
78
|
else
|
|
80
|
-
invalid! "Unable to find #{type} #{
|
|
79
|
+
invalid! "Unable to find #{type} #{tracking_id} (does not exist and is not being created by the current run)"
|
|
81
80
|
end
|
|
82
81
|
end
|
|
83
82
|
|
data/lib/kennel/models/slo.rb
CHANGED
|
@@ -69,7 +69,7 @@ module Kennel
|
|
|
69
69
|
def resolve_linked_tracking_ids!(id_map, **args)
|
|
70
70
|
return unless as_json[:monitor_ids] # ignore_default can remove it
|
|
71
71
|
as_json[:monitor_ids] = as_json[:monitor_ids].map do |id|
|
|
72
|
-
id.is_a?(String) ? resolve_link(id, :monitor, id_map, **args) : id
|
|
72
|
+
id.is_a?(String) ? (resolve_link(id, :monitor, id_map, **args) || id) : id
|
|
73
73
|
end
|
|
74
74
|
end
|
|
75
75
|
|
data/lib/kennel/syncer.rb
CHANGED
|
@@ -38,23 +38,14 @@ module Kennel
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def update
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
@create.each do |_, e|
|
|
44
|
-
e.resolve_linked_tracking_ids!({}, force: true)
|
|
45
|
-
|
|
41
|
+
each_resolved @create do |_, e|
|
|
46
42
|
reply = @api.create e.class.api_resource, e.as_json
|
|
47
43
|
id = reply.fetch(:id)
|
|
48
|
-
|
|
49
|
-
# resolve ids we could previously no resolve
|
|
50
|
-
changed.delete e
|
|
51
|
-
resolve_linked_tracking_ids! from: [reply], to: changed
|
|
52
|
-
|
|
44
|
+
populate_id_map [reply] # allow resolving ids we could previously no resolve
|
|
53
45
|
Kennel.out.puts "Created #{e.class.api_resource} #{tracking_id(e.as_json)} #{e.url(id)}"
|
|
54
46
|
end
|
|
55
47
|
|
|
56
|
-
@update
|
|
57
|
-
e.resolve_linked_tracking_ids!({}, force: true)
|
|
48
|
+
each_resolved @update do |id, e|
|
|
58
49
|
@api.update e.class.api_resource, id, e.as_json
|
|
59
50
|
Kennel.out.puts "Updated #{e.class.api_resource} #{tracking_id(e.as_json)} #{e.url(id)}"
|
|
60
51
|
end
|
|
@@ -67,6 +58,37 @@ module Kennel
|
|
|
67
58
|
|
|
68
59
|
private
|
|
69
60
|
|
|
61
|
+
# loop over items until everything is resolved or crash when we get stuck
|
|
62
|
+
# this solves cases like composite monitors depending on each other or monitor->monitor slo->slo monitor chains
|
|
63
|
+
def each_resolved(list)
|
|
64
|
+
list = list.dup
|
|
65
|
+
loop do
|
|
66
|
+
return if list.empty?
|
|
67
|
+
list.reject! do |id, e|
|
|
68
|
+
if resolved?(e)
|
|
69
|
+
yield id, e
|
|
70
|
+
true
|
|
71
|
+
else
|
|
72
|
+
false
|
|
73
|
+
end
|
|
74
|
+
end ||
|
|
75
|
+
assert_resolved(list[0][1]) # resolve something or show a circular dependency error
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# TODO: optimize by storing an instance variable if already resolved
|
|
80
|
+
def resolved?(e)
|
|
81
|
+
assert_resolved e
|
|
82
|
+
true
|
|
83
|
+
rescue ValidationError
|
|
84
|
+
false
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# raises ValidationError when not resolved
|
|
88
|
+
def assert_resolved(e)
|
|
89
|
+
resolve_linked_tracking_ids! [e], force: true
|
|
90
|
+
end
|
|
91
|
+
|
|
70
92
|
def noop?
|
|
71
93
|
@create.empty? && @update.empty? && @delete.empty?
|
|
72
94
|
end
|
|
@@ -74,9 +96,15 @@ module Kennel
|
|
|
74
96
|
def calculate_diff
|
|
75
97
|
@update = []
|
|
76
98
|
@delete = []
|
|
99
|
+
@id_map = {}
|
|
77
100
|
|
|
78
101
|
actual = Progress.progress("Downloading definitions") { download_definitions }
|
|
79
|
-
|
|
102
|
+
|
|
103
|
+
# resolve dependencies to avoid diff
|
|
104
|
+
populate_id_map actual
|
|
105
|
+
@expected.each { |e| @id_map[e.tracking_id] ||= :new }
|
|
106
|
+
resolve_linked_tracking_ids! @expected
|
|
107
|
+
|
|
80
108
|
filter_by_project! actual
|
|
81
109
|
|
|
82
110
|
Progress.progress "Diffing" do
|
|
@@ -107,7 +135,6 @@ module Kennel
|
|
|
107
135
|
|
|
108
136
|
ensure_all_ids_found
|
|
109
137
|
@create = @expected.map { |e| [nil, e] }
|
|
110
|
-
@create.sort_by! { |_, e| -DELETE_ORDER.index(e.class.api_resource) }
|
|
111
138
|
end
|
|
112
139
|
|
|
113
140
|
@delete.sort_by! { |_, _, a| DELETE_ORDER.index a.fetch(:api_resource) }
|
|
@@ -214,10 +241,12 @@ module Kennel
|
|
|
214
241
|
end
|
|
215
242
|
end
|
|
216
243
|
|
|
217
|
-
def
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
244
|
+
def populate_id_map(actual)
|
|
245
|
+
actual.each { |a| @id_map[tracking_id(a)] = a.fetch(:id) }
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def resolve_linked_tracking_ids!(list, force: false)
|
|
249
|
+
list.each { |e| e.resolve_linked_tracking_ids!(@id_map, force: force) }
|
|
221
250
|
end
|
|
222
251
|
|
|
223
252
|
def filter_by_project!(definitions)
|
data/lib/kennel/utils.rb
CHANGED
|
@@ -23,6 +23,11 @@ module Kennel
|
|
|
23
23
|
.downcase
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
# for child projects, not used internally
|
|
27
|
+
def title_case(string)
|
|
28
|
+
string.split(/[\s_]/).map(&:capitalize) * " "
|
|
29
|
+
end
|
|
30
|
+
|
|
26
31
|
# simplified version of https://apidock.com/rails/ActiveSupport/Inflector/parameterize
|
|
27
32
|
def parameterize(string)
|
|
28
33
|
string
|
data/lib/kennel/version.rb
CHANGED
data/template/Readme.md
CHANGED
|
@@ -67,7 +67,7 @@ end
|
|
|
67
67
|
- `cp .env.example .env`
|
|
68
68
|
- open [Datadog API Settings](https://app.datadoghq.com/account/settings#api)
|
|
69
69
|
- create a `API Key` or get an existing one from an admin, then add it to `.env` as `DATADOG_API_KEY`
|
|
70
|
-
-
|
|
70
|
+
- open [Datadog API Settings](https://app.datadoghq.com/access/application-keys) and create a new key, then add it to `.env` as `DATADOG_APP_KEY=`
|
|
71
71
|
- change the `DATADOG_SUBDOMAIN=app` in `.env` to your companies subdomain if you have one
|
|
72
72
|
- verify it works by running `rake plan`, it might show some diff, but should not crash
|
|
73
73
|
|
|
@@ -194,14 +194,20 @@ removing the `id` will cause kennel to create a new resource in datadog.
|
|
|
194
194
|
Some validations might be too strict for your usecase or just wrong, please [open an issue](https://github.com/grosser/kennel/issues) and
|
|
195
195
|
to unblock use the `validate: -> { false }` option.
|
|
196
196
|
|
|
197
|
-
### Linking with
|
|
197
|
+
### Linking resources with kennel_id
|
|
198
198
|
|
|
199
|
-
|
|
199
|
+
Link resources with their kennel_id in the format `project kennel_id` + `:` + `resource kennel_id`,
|
|
200
|
+
this should be used to create dependent resources like monitor + slos,
|
|
201
|
+
so they can be created in a single update and can be re-created if any of them is deleted.
|
|
200
202
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
203
|
+
|Resource|Type|Syntax|
|
|
204
|
+
|---|---|---|
|
|
205
|
+
|Dashboard|uptime|`monitor: {id: "foo:bar"}`|
|
|
206
|
+
|Dashboard|alert_graph|`alert_id: "foo:bar"`|
|
|
207
|
+
|Dashboard|slo|`slo_id: "foo:bar"`|
|
|
208
|
+
|Monitor|composite|`query: -> { "%{foo:bar} && %{foo:baz}" }`|
|
|
209
|
+
|Monitor|slo alert|`query: -> { "error_budget(\"%{foo:bar}\").over(\"7d\") > 123.0" }`|
|
|
210
|
+
|Slo|monitor|`monitor_ids: -> ["foo:bar"]`|
|
|
205
211
|
|
|
206
212
|
### Debugging changes locally
|
|
207
213
|
|
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: 1.
|
|
4
|
+
version: 1.81.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michael Grosser
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-02-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|