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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f9d3050dbb7a4e94cd22e64618142bedffd6fdfc5b5ee8e20b621b90f1d8f27
4
- data.tar.gz: 640a86b74e46e27ec7f1b09dd555f0ba8f99e4fc1f687e5230bb00d12636ae1d
3
+ metadata.gz: a269f904837e3451d2476a99ebcd9d456dc91ae0f1a90736ca92b76a9e92bee9
4
+ data.tar.gz: 53b4d080603c79ec8e70dfe2e95cbfcb4fa2325f1e9fa803a5c8bbcafc9db646
5
5
  SHA512:
6
- metadata.gz: 80dbfff63550b6f5c3127cb8ecc97db6b3db38876469bcb9d50fce00a7e1b78e2f473dd3c3abaec081cb21037f53be72021d907c4285352b30dd3b6991f6c622
7
- data.tar.gz: 02a3122ec70a951dc01f919c4d13877de88c6266048d006770a62adadd19587d74a603e8281699f878be0a20227a7086e37727c751cf5833e815fc795e3f9ee3
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
- `rake kennel:dump`
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)
@@ -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)
@@ -58,7 +58,7 @@ module Kennel
58
58
  "slo"
59
59
  end
60
60
 
61
- def url(id)
61
+ def self.url(id)
62
62
  Utils.path_to_url "/slo?slo_id=#{id}"
63
63
  end
64
64
 
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
- details_cache do |cache|
121
- # fill details of things we need to compare (only do this part in parallel for safety & balancing)
122
- Utils.parallel(items.select { |e, _| e && e.class::API_LIST_INCOMPLETE }) { |_, a| fill_details(a, cache) }
123
- end
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.subclasses.map(&:api_resource)
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.send(:api).list(resource).each do |r|
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"
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "1.81.2"
3
+ VERSION = "1.85.0"
4
4
  end
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
- `rake kennel:dump`
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.81.2
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-02-05 00:00:00.000000000 Z
11
+ date: 2021-03-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday