kennel 2.14.0 → 2.16.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d289ac0af8158766eeced52cda258b67071189f889e6fa82d63cafe0b4cc7655
4
- data.tar.gz: 5a231e9da146ca9e008a8b507e2cbd4e11913c6f53d19fbd64af5c93b5b1a0aa
3
+ metadata.gz: 3f5c11c126af9e586c2e7f48564760b8625248626204bdd76359001d78cd2038
4
+ data.tar.gz: 7ec6271b5eb235c8ee4b0bbaf3b9d59dc3b3f8796c5cf8288f6d753094e99a3c
5
5
  SHA512:
6
- metadata.gz: a476cf37c12872c6cd4f1eeed55751840ffd5c6206dec0279d281f7862a47bd8e614fa14eefc0ffc32095a15f2d26d4a75b2298b60cc107bf09e1994562f0f15
7
- data.tar.gz: 29dfd3a9b22848badfb52da141620fde5fc89224974cade1e0cdda957a69d9b82798e4a6a03e95339f1cf907e8c036939fa1b5289cf9b8292b83e9e73e68e03a
6
+ metadata.gz: 6778c767c1b28ad451f42e0a7f86557382e93627bfee517d7fcd857f90a674bd63294d67253704975c5653d4de616f731524eaf37bd11ff41822635dfcf78c8a
7
+ data.tar.gz: 626e57f6a9e8a8c8080defd2496d983fa93e0a9fcdf63e5ad87aad662c3f4aaca42ff7e5b0c6c9cb0d94fc66d43808fd10dee65add9d0ca3d1d60b76d2c801e9
data/Readme.md CHANGED
@@ -206,6 +206,7 @@ end
206
206
  class MyProject < Kennel::Models::Project
207
207
  defaults(
208
208
  team: -> { Teams::MyTeam.new }, # use existing team or create new one in teams/
209
+ # kennel_id: -> { "my_project" } # Custom kennel_id (default is snake_cased class name)
209
210
  parts: -> {
210
211
  [
211
212
  Kennel::Models::Monitor.new(
@@ -249,6 +250,7 @@ Remove the code that created the resource. The next update will delete it (see a
249
250
  - go to [datadog dashboard UI](https://app.datadoghq.com/dashboard/lists) and click on _New Dashboard_ to find a dashboard
250
251
  - run `URL='https://app.datadoghq.com/dashboard/bet-foo-bar' bundle exec rake kennel:import` and copy the output
251
252
  - find or create a project in `projects/`
253
+ - tags: only `team:` tags are submitted to datadog since nothing else is supported
252
254
  - add a dashboard to `parts: [` list, for example:
253
255
  ```Ruby
254
256
  class MyProject < Kennel::Models::Project
@@ -264,8 +266,9 @@ Remove the code that created the resource. The next update will delete it (see a
264
266
  template_variables: -> { ["environment"] }, # see https://docs.datadoghq.com/api/?lang=ruby#timeboards
265
267
  kennel_id: -> { "overview-dashboard" }, # make up a unique name
266
268
  layout_type: -> { "ordered" },
269
+ widgets: -> { "... raw widget definitions, most flexible ..." },
267
270
  definitions: -> {
268
- [ # An array or arrays, each one is a graph in the dashboard, alternatively a hash for finer control
271
+ [ # each element is a graph in the dashboard, alternatively a hash for complete control just like in `widgets`
269
272
  [
270
273
  # title, viz, type, query, edit an existing graph and see the json definition
271
274
  "Graph name", "timeseries", "area", "sum:mystats.foobar{$environment}"
@@ -274,7 +277,7 @@ Remove the code that created the resource. The next update will delete it (see a
274
277
  # queries can be an Array as well, this will generate multiple requests
275
278
  # for a single graph
276
279
  "Graph name", "timeseries", "area", ["sum:mystats.foobar{$environment}", "sum:mystats.success{$environment}"],
277
- # add events too ...
280
+ # add events too ... (also supports `:markers` and `:precision`)
278
281
  events: [{q: "tags:foobar,deploy", tags_execution: "and"}]
279
282
  ]
280
283
  ]
@@ -286,6 +289,55 @@ Remove the code that created the resource. The next update will delete it (see a
286
289
  end
287
290
  ```
288
291
 
292
+ ### Adding a new synthetic test
293
+ - go to [datadog synthetic tests UI](https://app.datadoghq.com/synthetics/tests) and click on _New_ to create a test
294
+ - see below
295
+
296
+ ### Updating an existing synthetic test
297
+ - go to [datadog synthetic tests UI](https://app.datadoghq.com/synthetics/tests) to find a test
298
+ - run `URL='https://app.datadoghq.com/synthetics/details/abc-def-ghi' bundle exec rake kennel:import` and copy the output
299
+ - find or create a project in `projects/`
300
+ - add a synthetic test to `parts: [` list, for example:
301
+ ```Ruby
302
+ class MyProject < Kennel::Models::Project
303
+ defaults(
304
+ team: -> { Teams::MyTeam.new },
305
+ parts: -> {
306
+ [
307
+ Kennel::Models::SyntheticTest.new(
308
+ self,
309
+ id: -> { "abc-def-ghi" }, # id from datadog url, not needed when creating a new test
310
+ kennel_id: -> { "my-api-test" },
311
+ name: -> { "My API Test" },
312
+ type: -> { "api" },
313
+ subtype: -> { "http" },
314
+ locations: -> { :all }, # use all locations, or specify: ["aws:us-east-1", "aws:eu-west-1"]
315
+ message: -> {
316
+ <<~TEXT
317
+ API check failed!
318
+ #{super()}
319
+ TEXT
320
+ },
321
+ options: -> {
322
+ {
323
+ tick_every: 60,
324
+ min_failure_duration: 0,
325
+ min_location_failed: 1
326
+ }
327
+ },
328
+ config: -> {
329
+ {
330
+ assertions: [{ type: "statusCode", operator: "is", target: 200 }],
331
+ request: { method: "GET", url: "https://example.com/health" }
332
+ }
333
+ }
334
+ )
335
+ ]
336
+ }
337
+ )
338
+ end
339
+ ```
340
+
289
341
  ### Updating existing resources with id
290
342
  Setting `id` makes kennel take over a manually created datadog resource.
291
343
  When manually creating to import, it is best to remove the `id` and delete the manually created resource.
@@ -327,10 +379,11 @@ module ProjectA
327
379
  - Use `TRACKING_ID=<project-kennel_id>:<resource-kennel_id>` for single resource:
328
380
 
329
381
  Use the project kennel_id and the resources kennel_id, for example `class ProjectA` and `FooAlert` would give `project_a:foo_alert`.
382
+ Alternatively use the path of the generated file `TRACKING_ID=generated/project_a/foo_alert.json`
330
383
 
331
384
  ### Skipping validations
332
385
  Some validations might be too strict for your usecase or just wrong, please [open an issue](https://github.com/grosser/kennel/issues) and
333
- to unblock use the `validate: -> { false }` option.
386
+ to unblock use `ignored_errors: [:name_of_the_error]`.
334
387
 
335
388
  ### Linking resources with kennel_id
336
389
  Link resources with their kennel_id in the format `project kennel_id` + `:` + `resource kennel_id`,
@@ -339,7 +392,7 @@ so they can be created in a single update and can be re-created if any of them i
339
392
 
340
393
  |Resource|Type|Syntax|
341
394
  |---|---|---|
342
- |Dashboard|uptime|`monitor: {id: "foo:bar"}`|
395
+ |Dashboard|uptime|`monitor_ids: ["foo:bar", "foo:baz"]`|
343
396
  |Dashboard|alert_graph|`alert_id: "foo:bar"`|
344
397
  |Dashboard|slo|`slo_id: "foo:bar"`|
345
398
  |Dashboard|timeseries|`queries: [{ data_source: "slo", slo_id: "foo:bar" }]`|
@@ -388,6 +441,9 @@ Run `rake kennel:alerts TAG=service:my-service` to see all un-muted alerts for a
388
441
  ### Validating mentions work
389
442
  `rake kennel:validate_mentions` should run as part of CI
390
443
 
444
+ Use `KNOWN=foo@bar.com,baz@bar.com` to exempt mentions that are not returned by the API.
445
+ Use `KNOWN_RANDOM=@sns-foo,@sns-bar` to ignore for example SNS handles that are randomly invalid in the API.
446
+
391
447
  ### Grepping through all of datadog
392
448
  ```Bash
393
449
  rake kennel:dump > tmp/dump
@@ -405,6 +461,9 @@ https://foo.datadog.com/monitor/123
405
461
  ### Find all monitors with No-Data
406
462
  `rake kennel:nodata TAG=team:foo`
407
463
 
464
+ - `FORMAT=json` to output as JSON with tracking IDs
465
+ - `THRESHOLD_DAYS=N` to filter to monitors with N+ days in no-data
466
+
408
467
  ### Finding the tracking id of a resource
409
468
 
410
469
  When trying to link resources together, this avoids having to go through datadog UI.
@@ -421,6 +480,14 @@ rake kennel:tracking_id ID=123 RESOURCE=monitor
421
480
  - Setting `FORCE_GET_CACHE=true` will cache all get requests, which makes benchmarking improvements more reliable.
422
481
  - Setting `STORE=false` will make `rake plan` not update the files on disk and save a bit of time
423
482
 
483
+ ### Other Environment Variables
484
+ | Variable | Description | Default |
485
+ |----------|-------------|---------|
486
+ | `KENNEL_MARKER_TEXT` | Custom marker text to namespace multiple Kennel instances in the same Datadog account. Each instance will only manage resources with its marker. | `Managed by kennel` |
487
+ | `KENNEL_API_CACHE_FILE` | Path to the API cache file for dashboard details. | `tmp/cache/details` |
488
+ | `KENNEL_NO_GENERATE` | When set, skip generating files during `plan` or `update_datadog`. Useful when generated files are already up to date. | - |
489
+ | `NO_IGNORED_ERRORS` | When set, show all validation errors including ones suppressed via `ignored_errors`. | - |
490
+
424
491
  ### Integration testing
425
492
  ```Bash
426
493
  rake play
data/lib/kennel/filter.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Kennel
4
4
  class Filter
5
+ ID_SEPARATOR = ":"
5
6
  attr_reader :project_filter
6
7
 
7
8
  def initialize
@@ -22,23 +23,18 @@ module Kennel
22
23
  !project_filter.nil?
23
24
  end
24
25
 
25
- def matches_project_id?(project_id)
26
+ def filters_project_id?(project_id)
26
27
  !filtering? || project_filter.include?(project_id)
27
28
  end
28
29
 
29
- def matches_tracking_id?(tracking_id)
30
+ def filters_tracking_id?(tracking_id)
30
31
  return true unless filtering?
31
32
  return tracking_id_filter.include?(tracking_id) if tracking_id_filter
32
33
 
33
- project_id = tracking_id.split(":").first
34
+ project_id = tracking_id.split(ID_SEPARATOR, 2).first
34
35
  project_filter.include?(project_id)
35
36
  end
36
37
 
37
- def tracking_id_for_path(tracking_id)
38
- return tracking_id unless tracking_id.end_with?(".json")
39
- tracking_id.sub("generated/", "").sub(".json", "").sub("/", ":")
40
- end
41
-
42
38
  private
43
39
 
44
40
  attr_reader :tracking_id_filter
@@ -46,7 +42,7 @@ module Kennel
46
42
  # needs to be called after read_tracking_id_filter_from_env
47
43
  def read_project_filter_from_env
48
44
  project_names = ENV["PROJECT"]&.split(",")&.sort&.uniq
49
- tracking_project_names = tracking_id_filter&.map { |id| id.split(":", 2).first }&.sort&.uniq
45
+ tracking_project_names = tracking_id_filter&.map { |id| id.split(ID_SEPARATOR, 2).first }&.sort&.uniq
50
46
  if project_names && tracking_project_names && project_names != tracking_project_names
51
47
  # avoid everything being filtered out
52
48
  raise "do not set a different PROJECT= when using TRACKING_ID="
@@ -57,8 +53,8 @@ module Kennel
57
53
  def read_tracking_id_filter_from_env
58
54
  return unless (tracking_id = ENV["TRACKING_ID"])
59
55
  tracking_id.split(",").map do |id|
60
- # allow users to paste the generated/ path of an objects to update it without manually converting
61
- tracking_id_for_path(id)
56
+ # allow using the generated/ path from `git diff` to update objects without manually converting
57
+ id.include?(ID_SEPARATOR) ? id : PartsSerializer.tracking_id_for_path(id)
62
58
  end.sort.uniq
63
59
  end
64
60
 
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
3
  module Models
4
- class Team < Base
5
- settings :mention, :tags, :renotify_interval, :kennel_id
4
+ class Team
5
+ include SettingsAsMethods
6
+
7
+ settings :mention, :tags, :renotify_interval
6
8
  defaults(
7
- tags: -> { ["team:#{kennel_id.sub(/^teams_/, "").tr("_", "-")}"] },
9
+ tags: -> { ["team:#{StringUtils.snake_case(self.class.name).sub(/^teams_/, "").tr("_", "-")}"] },
8
10
  renotify_interval: -> { 0 }
9
11
  )
10
12
  end
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Kennel
4
4
  class PartsSerializer
5
+ FILE_EXTENSION = ".json"
6
+ FOLDER = "generated"
7
+
5
8
  def initialize(filter:)
6
9
  @filter = filter
7
10
  end
@@ -9,8 +12,15 @@ module Kennel
9
12
  def write(parts)
10
13
  Progress.progress "Storing" do
11
14
  existing = existing_files_and_folders
12
- used = write_changed(parts)
13
- FileUtils.rm_rf(existing - used)
15
+ used, changed = write_changed(parts)
16
+ FileUtils.rm_rf(existing - used) # cleanup abandoned
17
+ suggest_using_project_filter(changed)
18
+ end
19
+ end
20
+
21
+ class << self
22
+ def tracking_id_for_path(path)
23
+ path.sub("#{FOLDER}/", "").sub(FILE_EXTENSION, "").sub("/", ":")
14
24
  end
15
25
  end
16
26
 
@@ -20,28 +30,29 @@ module Kennel
20
30
 
21
31
  def write_changed(parts)
22
32
  used = []
33
+ changed = []
23
34
 
24
35
  Utils.parallel(parts, max: 2) do |part|
25
36
  path = path_for_tracking_id(part.tracking_id)
26
37
 
38
+ # match paths returned from existing_files_and_folders
27
39
  used << File.dirname(path) # we have 1 level of sub folders, so this is enough
28
40
  used << path
29
41
 
30
42
  content = part.as_json.merge(api_resource: part.class.api_resource)
31
- write_file_if_necessary(path, content)
43
+ changed << path if write_file_if_necessary(path, content)
32
44
  end
33
-
34
- used
45
+ [used, changed]
35
46
  end
36
47
 
37
48
  def existing_files_and_folders
38
- paths = Dir["generated/**/*"]
49
+ paths = Dir["#{FOLDER}/**/*"] # we rely on this returning folders and files, see write_changed
39
50
 
40
51
  # when filtering we only need the files we are going to write
41
52
  if filter.filtering?
42
53
  paths.select! do |path|
43
- tracking_id = filter.tracking_id_for_path(path)
44
- filter.matches_tracking_id?(tracking_id)
54
+ tracking_id = self.class.tracking_id_for_path(path)
55
+ filter.filters_tracking_id?(tracking_id)
45
56
  end
46
57
  end
47
58
 
@@ -49,7 +60,7 @@ module Kennel
49
60
  end
50
61
 
51
62
  def path_for_tracking_id(tracking_id)
52
- "generated/#{tracking_id.tr("/", ":").sub(":", "/")}.json"
63
+ "#{FOLDER}/#{tracking_id.tr("/", ":").sub(":", "/")}#{FILE_EXTENSION}"
53
64
  end
54
65
 
55
66
  def write_file_if_necessary(path, content)
@@ -58,13 +69,21 @@ module Kennel
58
69
 
59
70
  # 99% case
60
71
  begin
61
- return if File.read(path) == content
62
- rescue Errno::ENOENT
72
+ return false if File.read(path) == content
73
+ rescue Errno::ENOENT # file or even folder did not exist
63
74
  FileUtils.mkdir_p(File.dirname(path))
64
75
  end
65
76
 
66
77
  # slow 1% case
67
78
  File.write(path, content)
79
+ true
80
+ end
81
+
82
+ def suggest_using_project_filter(changed)
83
+ return if filter.filtering?
84
+ projects = changed.map { |path| path.split("/")[1] }.uniq
85
+ return if projects.size != 1
86
+ warn "Hint: Using PROJECT=#{projects[0]} is faster"
68
87
  end
69
88
  end
70
89
  end
@@ -12,7 +12,8 @@ module Kennel
12
12
  # All requested projects. This is a slow operation when loading all projects.
13
13
  def projects
14
14
  load_requested
15
- loaded_projects.map(&:new)
15
+ projects = loaded_projects.map(&:new)
16
+ @filter.filter_projects projects # in case we loaded more though dependencies
16
17
  end
17
18
 
18
19
  private
@@ -27,7 +27,7 @@ module Kennel
27
27
  # ignore when deleted from the codebase
28
28
  # (when running with filters we cannot see the other resources in the codebase)
29
29
  api_resource = a.fetch(:klass).api_resource
30
- next if !id_map.get(api_resource, tracking_id) && filter.matches_tracking_id?(tracking_id)
30
+ next if !id_map.get(api_resource, tracking_id) && filter.filters_tracking_id?(tracking_id)
31
31
 
32
32
  id_map.set(api_resource, tracking_id, a.fetch(:id))
33
33
  if a.fetch(:klass).api_resource == "synthetics/tests"
data/lib/kennel/syncer.rb CHANGED
@@ -179,7 +179,7 @@ module Kennel
179
179
 
180
180
  actual.select! do |a|
181
181
  tracking_id = a.fetch(:tracking_id)
182
- tracking_id.nil? || filter.matches_tracking_id?(tracking_id)
182
+ tracking_id.nil? || filter.filters_tracking_id?(tracking_id)
183
183
  end
184
184
  end
185
185
  end
data/lib/kennel/tasks.rb CHANGED
@@ -25,6 +25,7 @@ module Kennel
25
25
  source = ".env"
26
26
 
27
27
  # warn when users have things like DATADOG_TOKEN already set and it will not be loaded from .env
28
+ # (KENNEL_SILENCE_UPDATED_ENV is intentionally not documented - users see it when needed)
28
29
  unless ENV["KENNEL_SILENCE_UPDATED_ENV"]
29
30
  updated = Dotenv.parse(source).select { |k, v| ENV[k] && ENV[k] != v }
30
31
  warn "Environment variables #{updated.keys.join(", ")} need to be unset to be sourced from #{source}" if updated.any?
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "2.14.0"
3
+ VERSION = "2.16.0"
4
4
  end
data/lib/kennel.rb CHANGED
@@ -69,7 +69,9 @@ module Kennel
69
69
 
70
70
  def generate
71
71
  parts = generated
72
- PartsSerializer.new(filter: filter).write(parts) if ENV["STORE"] != "false" # quicker when debugging
72
+ if ENV["STORE"] != "false" # quicker when debugging
73
+ PartsSerializer.new(filter: filter).write(parts)
74
+ end
73
75
  parts
74
76
  end
75
77
 
@@ -109,8 +111,7 @@ module Kennel
109
111
  def generated(**kwargs)
110
112
  @generated ||= begin
111
113
  projects = Progress.progress "Loading projects", **kwargs do
112
- projects = ProjectsProvider.new(filter: filter).projects
113
- filter.filter_projects projects
114
+ ProjectsProvider.new(filter: filter).projects
114
115
  end
115
116
 
116
117
  parts = Progress.progress "Finding parts", **kwargs do
data/template/Readme.md CHANGED
@@ -188,6 +188,7 @@ end
188
188
  class MyProject < Kennel::Models::Project
189
189
  defaults(
190
190
  team: -> { Teams::MyTeam.new }, # use existing team or create new one in teams/
191
+ # kennel_id: -> { "my_project" } # Custom kennel_id (default is snake_cased class name)
191
192
  parts: -> {
192
193
  [
193
194
  Kennel::Models::Monitor.new(
@@ -231,6 +232,7 @@ Remove the code that created the resource. The next update will delete it (see a
231
232
  - go to [datadog dashboard UI](https://app.datadoghq.com/dashboard/lists) and click on _New Dashboard_ to find a dashboard
232
233
  - run `URL='https://app.datadoghq.com/dashboard/bet-foo-bar' bundle exec rake kennel:import` and copy the output
233
234
  - find or create a project in `projects/`
235
+ - tags: only `team:` tags are submitted to datadog since nothing else is supported
234
236
  - add a dashboard to `parts: [` list, for example:
235
237
  ```Ruby
236
238
  class MyProject < Kennel::Models::Project
@@ -246,8 +248,9 @@ Remove the code that created the resource. The next update will delete it (see a
246
248
  template_variables: -> { ["environment"] }, # see https://docs.datadoghq.com/api/?lang=ruby#timeboards
247
249
  kennel_id: -> { "overview-dashboard" }, # make up a unique name
248
250
  layout_type: -> { "ordered" },
251
+ widgets: -> { "... raw widget definitions, most flexible ..." },
249
252
  definitions: -> {
250
- [ # An array or arrays, each one is a graph in the dashboard, alternatively a hash for finer control
253
+ [ # each element is a graph in the dashboard, alternatively a hash for complete control just like in `widgets`
251
254
  [
252
255
  # title, viz, type, query, edit an existing graph and see the json definition
253
256
  "Graph name", "timeseries", "area", "sum:mystats.foobar{$environment}"
@@ -256,7 +259,7 @@ Remove the code that created the resource. The next update will delete it (see a
256
259
  # queries can be an Array as well, this will generate multiple requests
257
260
  # for a single graph
258
261
  "Graph name", "timeseries", "area", ["sum:mystats.foobar{$environment}", "sum:mystats.success{$environment}"],
259
- # add events too ...
262
+ # add events too ... (also supports `:markers` and `:precision`)
260
263
  events: [{q: "tags:foobar,deploy", tags_execution: "and"}]
261
264
  ]
262
265
  ]
@@ -268,6 +271,55 @@ Remove the code that created the resource. The next update will delete it (see a
268
271
  end
269
272
  ```
270
273
 
274
+ ### Adding a new synthetic test
275
+ - go to [datadog synthetic tests UI](https://app.datadoghq.com/synthetics/tests) and click on _New_ to create a test
276
+ - see below
277
+
278
+ ### Updating an existing synthetic test
279
+ - go to [datadog synthetic tests UI](https://app.datadoghq.com/synthetics/tests) to find a test
280
+ - run `URL='https://app.datadoghq.com/synthetics/details/abc-def-ghi' bundle exec rake kennel:import` and copy the output
281
+ - find or create a project in `projects/`
282
+ - add a synthetic test to `parts: [` list, for example:
283
+ ```Ruby
284
+ class MyProject < Kennel::Models::Project
285
+ defaults(
286
+ team: -> { Teams::MyTeam.new },
287
+ parts: -> {
288
+ [
289
+ Kennel::Models::SyntheticTest.new(
290
+ self,
291
+ id: -> { "abc-def-ghi" }, # id from datadog url, not needed when creating a new test
292
+ kennel_id: -> { "my-api-test" },
293
+ name: -> { "My API Test" },
294
+ type: -> { "api" },
295
+ subtype: -> { "http" },
296
+ locations: -> { :all }, # use all locations, or specify: ["aws:us-east-1", "aws:eu-west-1"]
297
+ message: -> {
298
+ <<~TEXT
299
+ API check failed!
300
+ #{super()}
301
+ TEXT
302
+ },
303
+ options: -> {
304
+ {
305
+ tick_every: 60,
306
+ min_failure_duration: 0,
307
+ min_location_failed: 1
308
+ }
309
+ },
310
+ config: -> {
311
+ {
312
+ assertions: [{ type: "statusCode", operator: "is", target: 200 }],
313
+ request: { method: "GET", url: "https://example.com/health" }
314
+ }
315
+ }
316
+ )
317
+ ]
318
+ }
319
+ )
320
+ end
321
+ ```
322
+
271
323
  ### Updating existing resources with id
272
324
  Setting `id` makes kennel take over a manually created datadog resource.
273
325
  When manually creating to import, it is best to remove the `id` and delete the manually created resource.
@@ -309,10 +361,11 @@ module ProjectA
309
361
  - Use `TRACKING_ID=<project-kennel_id>:<resource-kennel_id>` for single resource:
310
362
 
311
363
  Use the project kennel_id and the resources kennel_id, for example `class ProjectA` and `FooAlert` would give `project_a:foo_alert`.
364
+ Alternatively use the path of the generated file `TRACKING_ID=generated/project_a/foo_alert.json`
312
365
 
313
366
  ### Skipping validations
314
367
  Some validations might be too strict for your usecase or just wrong, please [open an issue](https://github.com/grosser/kennel/issues) and
315
- to unblock use the `validate: -> { false }` option.
368
+ to unblock use `ignored_errors: [:name_of_the_error]`.
316
369
 
317
370
  ### Linking resources with kennel_id
318
371
  Link resources with their kennel_id in the format `project kennel_id` + `:` + `resource kennel_id`,
@@ -321,7 +374,7 @@ so they can be created in a single update and can be re-created if any of them i
321
374
 
322
375
  |Resource|Type|Syntax|
323
376
  |---|---|---|
324
- |Dashboard|uptime|`monitor: {id: "foo:bar"}`|
377
+ |Dashboard|uptime|`monitor_ids: ["foo:bar", "foo:baz"]`|
325
378
  |Dashboard|alert_graph|`alert_id: "foo:bar"`|
326
379
  |Dashboard|slo|`slo_id: "foo:bar"`|
327
380
  |Dashboard|timeseries|`queries: [{ data_source: "slo", slo_id: "foo:bar" }]`|
@@ -370,6 +423,9 @@ Run `rake kennel:alerts TAG=service:my-service` to see all un-muted alerts for a
370
423
  ### Validating mentions work
371
424
  `rake kennel:validate_mentions` should run as part of CI
372
425
 
426
+ Use `KNOWN=foo@bar.com,baz@bar.com` to exempt mentions that are not returned by the API.
427
+ Use `KNOWN_RANDOM=@sns-foo,@sns-bar` to ignore for example SNS handles that are randomly invalid in the API.
428
+
373
429
  ### Grepping through all of datadog
374
430
  ```Bash
375
431
  rake kennel:dump > tmp/dump
@@ -387,6 +443,9 @@ https://foo.datadog.com/monitor/123
387
443
  ### Find all monitors with No-Data
388
444
  `rake kennel:nodata TAG=team:foo`
389
445
 
446
+ - `FORMAT=json` to output as JSON with tracking IDs
447
+ - `THRESHOLD_DAYS=N` to filter to monitors with N+ days in no-data
448
+
390
449
  ### Finding the tracking id of a resource
391
450
 
392
451
  When trying to link resources together, this avoids having to go through datadog UI.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kennel
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.14.0
4
+ version: 2.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Grosser