kennel 1.81.2 → 1.85.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Readme.md +11 -1
- data/lib/kennel/api.rb +22 -0
- data/lib/kennel/models/dashboard.rb +6 -5
- data/lib/kennel/models/monitor.rb +1 -11
- data/lib/kennel/models/record.rb +4 -1
- data/lib/kennel/models/slo.rb +1 -1
- data/lib/kennel/syncer.rb +6 -22
- data/lib/kennel/tasks.rb +30 -2
- data/lib/kennel/version.rb +1 -1
- data/template/Readme.md +11 -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: a269f904837e3451d2476a99ebcd9d456dc91ae0f1a90736ca92b76a9e92bee9
|
4
|
+
data.tar.gz: 53b4d080603c79ec8e70dfe2e95cbfcb4fa2325f1e9fa803a5c8bbcafc9db646
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 447b71298164f342b2e7cd707c1deaa12dfd260845c12125f8f9bc31849c13bb0d8c863613ed5b3b295009d5be4c28e351ea4c91b6eb3377a75d8140c25bf311
|
7
|
+
data.tar.gz: 988960502b6480687915669d317f920bc8af88e7926191a78cca3b7d55493b63e981bd5d880d137e3307a56ef1cdea23c18ad1139126e6f6310951100447422a
|
data/Readme.md
CHANGED
@@ -273,9 +273,19 @@ Run `rake kennel:alerts TAG=service:my-service` to see all un-muted alerts for a
|
|
273
273
|
|
274
274
|
### Grepping through all of datadog
|
275
275
|
|
276
|
-
|
276
|
+
```Bash
|
277
|
+
rake kennel:dump > tmp/dump
|
278
|
+
cat tmp/dump | grep foo
|
279
|
+
```
|
277
280
|
focus on a single type: `TYPE=monitors`
|
278
281
|
|
282
|
+
Show full resources or just their urls by pattern:
|
283
|
+
```Bash
|
284
|
+
rake kennel:dump_grep DUMP=tmp/dump PATTERN=foo URLS=true
|
285
|
+
https://foo.datadog.com/dasboard/123
|
286
|
+
https://foo.datadog.com/monitor/123
|
287
|
+
```
|
288
|
+
|
279
289
|
### Find all monitors with No-Data
|
280
290
|
|
281
291
|
`rake kennel:nodata TAG=team:foo`
|
data/lib/kennel/api.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module Kennel
|
3
|
+
# encapsulates knowledge around how the api works
|
3
4
|
class Api
|
5
|
+
CACHE_FILE = "tmp/cache/details"
|
6
|
+
|
4
7
|
def initialize(app_key, api_key)
|
5
8
|
@app_key = app_key
|
6
9
|
@api_key = api_key
|
@@ -49,8 +52,27 @@ module Kennel
|
|
49
52
|
request :delete, "/api/v1/#{api_resource}/#{id}", params: { force: "true" }, ignore_404: true
|
50
53
|
end
|
51
54
|
|
55
|
+
def fill_details!(api_resource, list)
|
56
|
+
return unless api_resource == "dashboard"
|
57
|
+
details_cache do |cache|
|
58
|
+
Utils.parallel(list) { |a| fill_detail!(api_resource, a, cache) }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
52
62
|
private
|
53
63
|
|
64
|
+
# Make diff work even though we cannot mass-fetch definitions
|
65
|
+
def fill_detail!(api_resource, a, cache)
|
66
|
+
args = [api_resource, a.fetch(:id)]
|
67
|
+
full = cache.fetch(args, a.fetch(:modified_at)) { show(*args) }
|
68
|
+
a.merge!(full)
|
69
|
+
end
|
70
|
+
|
71
|
+
def details_cache(&block)
|
72
|
+
cache = FileCache.new CACHE_FILE, Kennel::VERSION
|
73
|
+
cache.open(&block)
|
74
|
+
end
|
75
|
+
|
54
76
|
def request(method, path, body: nil, params: {}, ignore_404: false)
|
55
77
|
params = params.merge(application_key: @app_key, api_key: @api_key)
|
56
78
|
query = Faraday::FlatParamsEncoder.encode(params)
|
@@ -5,8 +5,6 @@ module Kennel
|
|
5
5
|
include TemplateVariables
|
6
6
|
include OptionalValidations
|
7
7
|
|
8
|
-
API_LIST_INCOMPLETE = true
|
9
|
-
DASHBOARD_DEFAULTS = { template_variables: [] }.freeze
|
10
8
|
READONLY_ATTRIBUTES = superclass::READONLY_ATTRIBUTES + [
|
11
9
|
:author_handle, :author_name, :modified_at, :url, :is_read_only, :notify_list
|
12
10
|
]
|
@@ -20,16 +18,18 @@ module Kennel
|
|
20
18
|
SUPPORTED_DEFINITION_OPTIONS = [:events, :markers, :precision].freeze
|
21
19
|
|
22
20
|
DEFAULTS = {
|
23
|
-
template_variable_presets: nil
|
21
|
+
template_variable_presets: nil,
|
22
|
+
reflow_type: "auto"
|
24
23
|
}.freeze
|
25
24
|
|
26
|
-
settings :title, :description, :definitions, :widgets, :layout_type, :template_variable_presets
|
25
|
+
settings :title, :description, :definitions, :widgets, :layout_type, :template_variable_presets, :reflow_type
|
27
26
|
|
28
27
|
defaults(
|
29
28
|
description: -> { "" },
|
30
29
|
definitions: -> { [] },
|
31
30
|
widgets: -> { [] },
|
32
31
|
template_variable_presets: -> { DEFAULTS.fetch(:template_variable_presets) },
|
32
|
+
reflow_type: -> { DEFAULTS.fetch(:reflow_type) },
|
33
33
|
id: -> { nil }
|
34
34
|
)
|
35
35
|
|
@@ -112,6 +112,7 @@ module Kennel
|
|
112
112
|
layout_type: layout_type,
|
113
113
|
title: "#{title}#{LOCK}",
|
114
114
|
description: description,
|
115
|
+
reflow_type: reflow_type,
|
115
116
|
template_variables: render_template_variables,
|
116
117
|
template_variable_presets: template_variable_presets,
|
117
118
|
widgets: all_widgets
|
@@ -124,7 +125,7 @@ module Kennel
|
|
124
125
|
@json
|
125
126
|
end
|
126
127
|
|
127
|
-
def url(id)
|
128
|
+
def self.url(id)
|
128
129
|
Utils.path_to_url "/dashboard/#{id}"
|
129
130
|
end
|
130
131
|
|
@@ -5,8 +5,6 @@ module Kennel
|
|
5
5
|
include OptionalValidations
|
6
6
|
|
7
7
|
RENOTIFY_INTERVALS = [0, 10, 20, 30, 40, 50, 60, 90, 120, 180, 240, 300, 360, 720, 1440].freeze # minutes
|
8
|
-
# 2d and 1w are valid timeframes for anomaly monitors
|
9
|
-
QUERY_INTERVALS = ["1m", "5m", "10m", "15m", "30m", "1h", "2h", "4h", "1d", "2d", "1w"].freeze
|
10
8
|
OPTIONAL_SERVICE_CHECK_THRESHOLDS = [:ok, :warning].freeze
|
11
9
|
READONLY_ATTRIBUTES = superclass::READONLY_ATTRIBUTES + [
|
12
10
|
:multi, :matching_downtimes, :overall_state_modified, :overall_state, :restricted_roles
|
@@ -125,7 +123,7 @@ module Kennel
|
|
125
123
|
"monitor"
|
126
124
|
end
|
127
125
|
|
128
|
-
def url(id)
|
126
|
+
def self.url(id)
|
129
127
|
Utils.path_to_url "/monitors##{id}/edit"
|
130
128
|
end
|
131
129
|
|
@@ -202,14 +200,6 @@ module Kennel
|
|
202
200
|
invalid! "renotify_interval must be one of #{RENOTIFY_INTERVALS.join(", ")}"
|
203
201
|
end
|
204
202
|
|
205
|
-
if type == "query alert"
|
206
|
-
# verify interval is valid
|
207
|
-
interval = data.fetch(:query)[/\(last_(\S+?)\)/, 1]
|
208
|
-
if interval && !QUERY_INTERVALS.include?(interval)
|
209
|
-
invalid! "query interval was #{interval}, but must be one of #{QUERY_INTERVALS.join(", ")}"
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
203
|
if ["query alert", "service check"].include?(type) # TODO: most likely more types need this
|
214
204
|
# verify is_match/is_exact_match uses available variables
|
215
205
|
message = data.fetch(:message)
|
data/lib/kennel/models/record.rb
CHANGED
@@ -6,7 +6,6 @@ module Kennel
|
|
6
6
|
READONLY_ATTRIBUTES = [
|
7
7
|
:deleted, :id, :created, :created_at, :creator, :org_id, :modified, :modified_at, :api_resource
|
8
8
|
].freeze
|
9
|
-
API_LIST_INCOMPLETE = false
|
10
9
|
|
11
10
|
settings :id, :kennel_id
|
12
11
|
|
@@ -19,6 +18,10 @@ module Kennel
|
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
21
|
+
def api_resource_map
|
22
|
+
subclasses.map { |s| [s.api_resource, s] }.to_h
|
23
|
+
end
|
24
|
+
|
22
25
|
private
|
23
26
|
|
24
27
|
def normalize(_expected, actual)
|
data/lib/kennel/models/slo.rb
CHANGED
data/lib/kennel/syncer.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module Kennel
|
3
3
|
class Syncer
|
4
|
-
CACHE_FILE = "tmp/cache/details" # keep in sync with .travis.yml caching
|
5
4
|
TRACKING_FIELDS = [:message, :description].freeze
|
6
5
|
DELETE_ORDER = ["dashboard", "slo", "monitor"].freeze # dashboards references monitors + slos, slos reference monitors
|
7
6
|
|
@@ -42,12 +41,12 @@ module Kennel
|
|
42
41
|
reply = @api.create e.class.api_resource, e.as_json
|
43
42
|
id = reply.fetch(:id)
|
44
43
|
populate_id_map [reply] # allow resolving ids we could previously no resolve
|
45
|
-
Kennel.out.puts "Created #{e.class.api_resource} #{tracking_id(e.as_json)} #{e.url(id)}"
|
44
|
+
Kennel.out.puts "Created #{e.class.api_resource} #{tracking_id(e.as_json)} #{e.class.url(id)}"
|
46
45
|
end
|
47
46
|
|
48
47
|
each_resolved @update do |id, e|
|
49
48
|
@api.update e.class.api_resource, id, e.as_json
|
50
|
-
Kennel.out.puts "Updated #{e.class.api_resource} #{tracking_id(e.as_json)} #{e.url(id)}"
|
49
|
+
Kennel.out.puts "Updated #{e.class.api_resource} #{tracking_id(e.as_json)} #{e.class.url(id)}"
|
51
50
|
end
|
52
51
|
|
53
52
|
@delete.each do |id, _, a|
|
@@ -117,10 +116,10 @@ module Kennel
|
|
117
116
|
end
|
118
117
|
end
|
119
118
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
119
|
+
# fill details of things we need to compare
|
120
|
+
detailed = Hash.new { |h, k| h[k] = [] }
|
121
|
+
items.each { |e, a| detailed[a[:api_resource]] << a if e }
|
122
|
+
detailed.each { |api_resource, actuals| @api.fill_details! api_resource, actuals }
|
124
123
|
|
125
124
|
# pick out things to update or delete
|
126
125
|
items.each do |e, a|
|
@@ -140,21 +139,6 @@ module Kennel
|
|
140
139
|
@delete.sort_by! { |_, _, a| DELETE_ORDER.index a.fetch(:api_resource) }
|
141
140
|
end
|
142
141
|
|
143
|
-
# Make diff work even though we cannot mass-fetch definitions
|
144
|
-
def fill_details(a, cache)
|
145
|
-
resource = a.fetch(:api_resource)
|
146
|
-
args = [resource, a.fetch(:id)]
|
147
|
-
full = cache.fetch(args, a[:modified] || a.fetch(:modified_at)) do
|
148
|
-
@api.show(*args)
|
149
|
-
end
|
150
|
-
a.merge!(full)
|
151
|
-
end
|
152
|
-
|
153
|
-
def details_cache(&block)
|
154
|
-
cache = FileCache.new CACHE_FILE, Kennel::VERSION
|
155
|
-
cache.open(&block)
|
156
|
-
end
|
157
|
-
|
158
142
|
def download_definitions
|
159
143
|
Utils.parallel(Models::Record.subclasses.map(&:api_resource)) do |api_resource|
|
160
144
|
results = @api.list(api_resource, with_downtimes: false) # lookup monitors without adding unnecessary downtime information
|
data/lib/kennel/tasks.rb
CHANGED
@@ -130,15 +130,43 @@ namespace :kennel do
|
|
130
130
|
if type = ENV["TYPE"]
|
131
131
|
[type]
|
132
132
|
else
|
133
|
-
Kennel::Models::Record.
|
133
|
+
Kennel::Models::Record.api_resource_map.keys
|
134
134
|
end
|
135
|
+
api = Kennel.send(:api)
|
136
|
+
list = nil
|
137
|
+
|
135
138
|
resources.each do |resource|
|
136
|
-
Kennel.
|
139
|
+
Kennel::Progress.progress("Downloading #{resource}") do
|
140
|
+
list = api.list(resource)
|
141
|
+
api.fill_details!(resource, list)
|
142
|
+
end
|
143
|
+
list.each do |r|
|
144
|
+
r[:api_resource] = resource
|
137
145
|
Kennel.out.puts JSON.pretty_generate(r)
|
138
146
|
end
|
139
147
|
end
|
140
148
|
end
|
141
149
|
|
150
|
+
desc "Find items from dump by pattern DUMP= PATTERN= [URLS=true]"
|
151
|
+
task dump_grep: :environment do
|
152
|
+
file = ENV.fetch("DUMP")
|
153
|
+
pattern = Regexp.new ENV.fetch("PATTERN")
|
154
|
+
items = File.read(file).gsub("}\n{", "}--SPLIT--{").split("--SPLIT--")
|
155
|
+
models = Kennel::Models::Record.api_resource_map
|
156
|
+
found = items.grep(pattern)
|
157
|
+
exit 1 if found.empty?
|
158
|
+
found.each do |resource|
|
159
|
+
if ENV["URLS"]
|
160
|
+
parsed = JSON.parse(resource)
|
161
|
+
url = models[parsed.fetch("api_resource")].url(parsed.fetch("id"))
|
162
|
+
title = parsed["title"] || parsed["name"]
|
163
|
+
Kennel.out.puts "#{url} # #{title}"
|
164
|
+
else
|
165
|
+
Kennel.out.puts resource
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
142
170
|
task :environment do
|
143
171
|
require "kennel"
|
144
172
|
gem "dotenv"
|
data/lib/kennel/version.rb
CHANGED
data/template/Readme.md
CHANGED
@@ -255,9 +255,19 @@ Run `rake kennel:alerts TAG=service:my-service` to see all un-muted alerts for a
|
|
255
255
|
|
256
256
|
### Grepping through all of datadog
|
257
257
|
|
258
|
-
|
258
|
+
```Bash
|
259
|
+
rake kennel:dump > tmp/dump
|
260
|
+
cat tmp/dump | grep foo
|
261
|
+
```
|
259
262
|
focus on a single type: `TYPE=monitors`
|
260
263
|
|
264
|
+
Show full resources or just their urls by pattern:
|
265
|
+
```Bash
|
266
|
+
rake kennel:dump_grep DUMP=tmp/dump PATTERN=foo URLS=true
|
267
|
+
https://foo.datadog.com/dasboard/123
|
268
|
+
https://foo.datadog.com/monitor/123
|
269
|
+
```
|
270
|
+
|
261
271
|
### Find all monitors with No-Data
|
262
272
|
|
263
273
|
`rake kennel:nodata TAG=team:foo`
|
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.85.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: 2021-
|
11
|
+
date: 2021-03-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|