kennel 1.50.1 → 1.54.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 +21 -13
- data/lib/kennel/importer.rb +18 -0
- data/lib/kennel/models/base.rb +7 -0
- data/lib/kennel/models/dashboard.rb +9 -13
- data/lib/kennel/models/monitor.rb +13 -3
- data/lib/kennel/models/project.rb +2 -2
- data/lib/kennel/models/team.rb +3 -11
- data/lib/kennel/syncer.rb +14 -3
- data/lib/kennel/version.rb +1 -1
- data/template/Readme.md +21 -13
- 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: ff469d7ae1bcb0d5dc6fb5d867c9dad761b5f2d07159ea147d99620544ec2580
|
4
|
+
data.tar.gz: e3322d92c13faee31f51ef53042cc0c768a0c85cfa0644d4fb2dafcf67f3e03a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 18d054b93d83f78b98dabdd584fcec0a99759f32734c2808c32bb64d51042e3087ca36722c88aa61c24707999f7dbefc1aebdd16ce996c964ba3ca2595bec7df
|
7
|
+
data.tar.gz: d1876da783f71a72287ede64c20c9865622f409ec0857a483161cb1f2914c0e40c3a232165697bee8984ea515d34abfc0beb8eede8b42164d0b324c7805e1468
|
data/Readme.md
CHANGED
@@ -42,19 +42,23 @@ Keep datadog monitors/dashboards/etc in version control, avoid chaotic managemen
|
|
42
42
|
- `gem install bundler && bundle install`
|
43
43
|
- `cp .env.example .env`
|
44
44
|
- open [Datadog API Settings](https://app.datadoghq.com/account/settings#api)
|
45
|
-
- find or create your personal "Application Key" and add it to `.env` as `DATADOG_APP_KEY=` (will be on the last page if new)
|
46
45
|
- copy any `API Key` and add it to `.env` as `DATADOG_API_KEY`
|
46
|
+
- find or create your personal "Application Key" and add it to `.env` as `DATADOG_APP_KEY=` (will be on the last page if new)
|
47
|
+
- change the `DATADOG_SUBDOMAIN=app` in `.env` to your companies subdomain if you have one
|
47
48
|
-->
|
48
49
|
|
49
50
|
### Adding a team
|
50
51
|
|
52
|
+
- `mention` is used for all team monitors via `super()`
|
53
|
+
- `renotify_interval` is used for all team monitors (defaults to `0` / off)
|
54
|
+
- `tags` is used for all team monitors/dashboards (defaults to `team:<team-name>`)
|
55
|
+
|
51
56
|
```Ruby
|
52
57
|
# teams/my_team.rb
|
53
58
|
module Teams
|
54
59
|
class MyTeam < Kennel::Models::Team
|
55
60
|
defaults(
|
56
|
-
|
57
|
-
email: -> { "my-team@example.com" }
|
61
|
+
mention: -> { "@slack-my-team" }
|
58
62
|
)
|
59
63
|
end
|
60
64
|
end
|
@@ -62,13 +66,14 @@ end
|
|
62
66
|
|
63
67
|
### Adding a new monitor
|
64
68
|
- use [datadog monitor UI](https://app.datadoghq.com/monitors#create/metric) to create a monitor
|
65
|
-
- get the `id` from the url
|
66
|
-
- `RESOURCE=monitor ID=12345 bundle exec rake kennel:import`
|
67
69
|
- see below
|
68
70
|
|
69
71
|
### Updating an existing monitor
|
72
|
+
- use [datadog monitor UI](https://app.datadoghq.com/monitors#create/metric) to find a monitor
|
73
|
+
- get the `id` from the url
|
74
|
+
- run `RESOURCE=monitor ID=12345 bundle exec rake kennel:import` and copy the output
|
70
75
|
- find or create a project in `projects/`
|
71
|
-
- add
|
76
|
+
- add the monitor to `parts: [` list, for example:
|
72
77
|
```Ruby
|
73
78
|
# projects/my_project.rb
|
74
79
|
class MyProject < Kennel::Models::Project
|
@@ -83,7 +88,8 @@ end
|
|
83
88
|
kennel_id: -> { "load-too-high" }, # make up a unique name
|
84
89
|
name: -> { "Foobar Load too high" }, # nice descriptive name that will show up in alerts and emails
|
85
90
|
message: -> {
|
86
|
-
# Explain what behavior to expect and how to fix the cause
|
91
|
+
# Explain what behavior to expect and how to fix the cause
|
92
|
+
# Use #{super()} to add team notifications.
|
87
93
|
<<~TEXT
|
88
94
|
Foobar will be slow and that could cause Barfoo to go down.
|
89
95
|
Add capacity or debug why it is suddenly slow.
|
@@ -98,21 +104,22 @@ end
|
|
98
104
|
)
|
99
105
|
end
|
100
106
|
```
|
101
|
-
- `bundle exec rake plan
|
102
|
-
- alternatively: `bundle exec rake generate` to only update the generated `json` files
|
107
|
+
- run `PROJECT=my_project bundle exec rake plan`, an Update to the existing monitor should be shown (not Create / Delete)
|
108
|
+
- alternatively: `bundle exec rake generate` to only locally update the generated `json` files
|
103
109
|
- review changes then `git commit`
|
104
110
|
- make a PR ... get reviewed ... merge
|
105
111
|
- datadog is updated by travis
|
106
112
|
|
107
113
|
### Adding a new dashboard
|
108
114
|
- go to [datadog dashboard UI](https://app.datadoghq.com/dashboard/lists) and click on _New Dashboard_ to create a dashboard
|
109
|
-
- get the `id` from the url
|
110
|
-
- `RESOURCE=dashboard ID=abc-def-ghi bundle exec rake kennel:import`
|
111
115
|
- see below
|
112
116
|
|
113
117
|
### Updating an existing dashboard
|
118
|
+
- go to [datadog dashboard UI](https://app.datadoghq.com/dashboard/lists) and click on _New Dashboard_ to find a dashboard
|
119
|
+
- get the `id` from the url
|
120
|
+
- run `RESOURCE=dashboard ID=abc-def-ghi bundle exec rake kennel:import` and copy the output
|
114
121
|
- find or create a project in `projects/`
|
115
|
-
- add a dashboard to `parts: [` list
|
122
|
+
- add a dashboard to `parts: [` list, for example:
|
116
123
|
```Ruby
|
117
124
|
class MyProject < Kennel::Models::Project
|
118
125
|
defaults(
|
@@ -160,6 +167,7 @@ To link to existing monitors via their kennel_id
|
|
160
167
|
|
161
168
|
- Screens `uptime` widgets can use `monitor: {id: "foo:bar"}`
|
162
169
|
- Screens `alert_graph` widgets can use `alert_id: "foo:bar"`
|
170
|
+
- Monitors `composite` can use `query: -> { "%{foo:bar} || %{foo:baz}" }`
|
163
171
|
|
164
172
|
### Debugging changes locally
|
165
173
|
|
@@ -195,7 +203,7 @@ Reuse it in multiple projects.
|
|
195
203
|
```Ruby
|
196
204
|
class Database < Kennel::Models::Project
|
197
205
|
defaults(
|
198
|
-
team: -> { Kennel::Models::Team.new(
|
206
|
+
team: -> { Kennel::Models::Team.new(mention: -> { '@slack-foo' }, kennel_id: -> { 'foo' }) },
|
199
207
|
parts: -> { [Monitors::LoadTooHigh.new(self, critical: -> { 13 })] }
|
200
208
|
)
|
201
209
|
end
|
data/lib/kennel/importer.rb
CHANGED
@@ -53,6 +53,9 @@ module Kennel
|
|
53
53
|
if query && critical
|
54
54
|
query.sub!(/([><=]) (#{Regexp.escape(critical.to_f.to_s)}|#{Regexp.escape(critical.to_i.to_s)})$/, "\\1 \#{critical}")
|
55
55
|
end
|
56
|
+
elsif resource == "dashboard"
|
57
|
+
widgets = data[:widgets]&.flat_map { |widget| widget.dig(:definition, :widgets) || [widget] }
|
58
|
+
widgets&.each { |widget| dry_up_query!(widget) }
|
56
59
|
end
|
57
60
|
|
58
61
|
# simplify template_variables to array of string when possible
|
@@ -71,6 +74,20 @@ module Kennel
|
|
71
74
|
|
72
75
|
private
|
73
76
|
|
77
|
+
# reduce duplication in imports by using dry `q: :metadata` when possible
|
78
|
+
def dry_up_query!(widget)
|
79
|
+
(widget.dig(:definition, :requests) || []).each do |request|
|
80
|
+
next unless request.is_a?(Hash)
|
81
|
+
next unless metadata = request[:metadata]
|
82
|
+
next unless query = request[:q]&.dup
|
83
|
+
metadata.each do |m|
|
84
|
+
next unless exp = m[:expression]
|
85
|
+
query.sub!(exp, "")
|
86
|
+
end
|
87
|
+
request[:q] = :metadata if query.delete(", ") == ""
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
74
91
|
def pretty_print(hash)
|
75
92
|
sort_widgets hash
|
76
93
|
|
@@ -84,6 +101,7 @@ module Kennel
|
|
84
101
|
.gsub(/(^\s*)"([a-zA-Z][a-zA-Z\d_]*)":/, "\\1\\2:") # "foo": 1 -> foo: 1
|
85
102
|
.gsub(/: \[\n\s+\]/, ": []") # empty arrays on a single line
|
86
103
|
.gsub(/^/, " ") # indent
|
104
|
+
.gsub('q: "metadata"', "q: :metadata") # bring symbols back
|
87
105
|
|
88
106
|
"\n#{pretty}\n "
|
89
107
|
elsif k == :message
|
data/lib/kennel/models/base.rb
CHANGED
@@ -148,6 +148,13 @@ module Kennel
|
|
148
148
|
|
149
149
|
private
|
150
150
|
|
151
|
+
def resolve_link(id, id_map, force:)
|
152
|
+
id_map[id] || begin
|
153
|
+
message = "Unable to find #{id} in existing monitors (they need to be created first to link them)"
|
154
|
+
force ? invalid!(message) : Kennel.err.puts(message)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
151
158
|
# let users know which project/resource failed when something happens during diffing where the backtrace is hidden
|
152
159
|
def invalid!(message)
|
153
160
|
raise ValidationError, "#{tracking_id} #{message}"
|
@@ -101,11 +101,13 @@ module Kennel
|
|
101
101
|
case definition[:type]
|
102
102
|
when "uptime"
|
103
103
|
if ids = definition[:monitor_ids]
|
104
|
-
definition[:monitor_ids] = ids.map
|
104
|
+
definition[:monitor_ids] = ids.map do |id|
|
105
|
+
tracking_id?(id) ? resolve_link(id, id_map, force: false) : id
|
106
|
+
end
|
105
107
|
end
|
106
108
|
when "alert_graph"
|
107
|
-
if id = definition[:alert_id]
|
108
|
-
definition[:alert_id] = resolve_link(id, id_map).to_s
|
109
|
+
if (id = definition[:alert_id]) && tracking_id?(id)
|
110
|
+
definition[:alert_id] = resolve_link(id, id_map, force: false).to_s
|
109
111
|
end
|
110
112
|
end
|
111
113
|
end
|
@@ -113,6 +115,10 @@ module Kennel
|
|
113
115
|
|
114
116
|
private
|
115
117
|
|
118
|
+
def tracking_id?(id)
|
119
|
+
id.is_a?(String) && !id.match?(/\A\d+\z/)
|
120
|
+
end
|
121
|
+
|
116
122
|
# creates queries from metadata to avoid having to keep q and expression in sync
|
117
123
|
#
|
118
124
|
# {q: :metadata, metadata: [{expression: "sum:bar", alias_name: "foo"}, ...], }
|
@@ -127,16 +133,6 @@ module Kennel
|
|
127
133
|
end
|
128
134
|
end
|
129
135
|
|
130
|
-
def resolve_link(id, id_map)
|
131
|
-
return id unless tracking_id?(id)
|
132
|
-
id_map[id] ||
|
133
|
-
Kennel.err.puts("Unable to find #{id} in existing monitors (they need to be created first to link them)")
|
134
|
-
end
|
135
|
-
|
136
|
-
def tracking_id?(id)
|
137
|
-
id.is_a?(String) && !id.match?(/\A\d+\z/)
|
138
|
-
end
|
139
|
-
|
140
136
|
def validate_json(data)
|
141
137
|
super
|
142
138
|
|
@@ -15,7 +15,7 @@ module Kennel
|
|
15
15
|
evaluation_delay: nil,
|
16
16
|
new_host_delay: 300,
|
17
17
|
timeout_h: 0,
|
18
|
-
renotify_interval:
|
18
|
+
renotify_interval: 0,
|
19
19
|
no_data_timeframe: nil # this works out ok since if notify_no_data is on, it would never be nil
|
20
20
|
}.freeze
|
21
21
|
DEFAULT_ESCALATION_MESSAGE = ["", nil].freeze
|
@@ -27,9 +27,9 @@ module Kennel
|
|
27
27
|
)
|
28
28
|
|
29
29
|
defaults(
|
30
|
-
message: -> { "\n\n
|
30
|
+
message: -> { "\n\n#{project.mention}" },
|
31
31
|
escalation_message: -> { DEFAULT_ESCALATION_MESSAGE.first },
|
32
|
-
renotify_interval: -> {
|
32
|
+
renotify_interval: -> { project.team.renotify_interval },
|
33
33
|
warning: -> { nil },
|
34
34
|
ok: -> { nil },
|
35
35
|
id: -> { nil },
|
@@ -108,6 +108,16 @@ module Kennel
|
|
108
108
|
@as_json = data
|
109
109
|
end
|
110
110
|
|
111
|
+
# resolve composite monitors ... only works when referenced monitors already exist
|
112
|
+
# since leaving names or bad ids in the query breaks the monitor update
|
113
|
+
def resolve_linked_tracking_ids(id_map)
|
114
|
+
if as_json[:type] == "composite"
|
115
|
+
as_json[:query] = as_json[:query].gsub(/%\{(.*?)\}/) do
|
116
|
+
resolve_link($1, id_map, force: true)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
111
121
|
def self.api_resource
|
112
122
|
"monitor"
|
113
123
|
end
|
@@ -2,10 +2,10 @@
|
|
2
2
|
module Kennel
|
3
3
|
module Models
|
4
4
|
class Project < Base
|
5
|
-
settings :team, :parts, :tags, :
|
5
|
+
settings :team, :parts, :tags, :mention
|
6
6
|
defaults(
|
7
7
|
tags: -> { ["service:#{kennel_id}"] + team.tags },
|
8
|
-
|
8
|
+
mention: -> { team.mention }
|
9
9
|
)
|
10
10
|
|
11
11
|
def self.file_location
|
data/lib/kennel/models/team.rb
CHANGED
@@ -2,19 +2,11 @@
|
|
2
2
|
module Kennel
|
3
3
|
module Models
|
4
4
|
class Team < Base
|
5
|
-
settings :
|
5
|
+
settings :mention, :tags, :renotify_interval, :kennel_id
|
6
6
|
defaults(
|
7
|
-
tags: -> { ["team:#{kennel_id.sub(/^teams_/, "")}"] }
|
7
|
+
tags: -> { ["team:#{kennel_id.sub(/^teams_/, "")}"] },
|
8
|
+
renotify_interval: -> { 0 }
|
8
9
|
)
|
9
|
-
|
10
|
-
def initialize(*)
|
11
|
-
super
|
12
|
-
invalid! "remove leading # from slack" if slack.to_s.start_with?("#")
|
13
|
-
end
|
14
|
-
|
15
|
-
def tracking_id
|
16
|
-
kennel_id
|
17
|
-
end
|
18
10
|
end
|
19
11
|
end
|
20
12
|
end
|
data/lib/kennel/syncer.rb
CHANGED
@@ -72,11 +72,22 @@ module Kennel
|
|
72
72
|
filter_by_project! actual
|
73
73
|
|
74
74
|
details_cache do |cache|
|
75
|
-
actual.
|
76
|
-
id = a.fetch(:id)
|
75
|
+
items = actual.map do |a|
|
77
76
|
e = matching_expected(a)
|
78
77
|
if e && @expected.delete(e)
|
79
|
-
|
78
|
+
[e, a]
|
79
|
+
else
|
80
|
+
[nil, a]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# fill details of things we need to compare (only do this part in parallel for safety & balancing)
|
85
|
+
Utils.parallel(items.select { |e, _| e && e.class::API_LIST_INCOMPLETE }) { |_, a| fill_details(a, cache) }
|
86
|
+
|
87
|
+
# pick out things to update or delete
|
88
|
+
items.each do |e, a|
|
89
|
+
id = a.fetch(:id)
|
90
|
+
if e
|
80
91
|
diff = e.diff(a)
|
81
92
|
@update << [id, e, a, diff] if diff.any?
|
82
93
|
elsif tracking_id(a) # was previously managed
|
data/lib/kennel/version.rb
CHANGED
data/template/Readme.md
CHANGED
@@ -25,18 +25,22 @@ Keep datadog monitors/dashboards/etc in version control, avoid chaotic managemen
|
|
25
25
|
- `gem install bundler && bundle install`
|
26
26
|
- `cp .env.example .env`
|
27
27
|
- open [Datadog API Settings](https://app.datadoghq.com/account/settings#api)
|
28
|
-
- find or create your personal "Application Key" and add it to `.env` as `DATADOG_APP_KEY=` (will be on the last page if new)
|
29
28
|
- copy any `API Key` and add it to `.env` as `DATADOG_API_KEY`
|
29
|
+
- find or create your personal "Application Key" and add it to `.env` as `DATADOG_APP_KEY=` (will be on the last page if new)
|
30
|
+
- change the `DATADOG_SUBDOMAIN=app` in `.env` to your companies subdomain if you have one
|
30
31
|
|
31
32
|
### Adding a team
|
32
33
|
|
34
|
+
- `mention` is used for all team monitors via `super()`
|
35
|
+
- `renotify_interval` is used for all team monitors (defaults to `0` / off)
|
36
|
+
- `tags` is used for all team monitors/dashboards (defaults to `team:<team-name>`)
|
37
|
+
|
33
38
|
```Ruby
|
34
39
|
# teams/my_team.rb
|
35
40
|
module Teams
|
36
41
|
class MyTeam < Kennel::Models::Team
|
37
42
|
defaults(
|
38
|
-
|
39
|
-
email: -> { "my-team@example.com" }
|
43
|
+
mention: -> { "@slack-my-team" }
|
40
44
|
)
|
41
45
|
end
|
42
46
|
end
|
@@ -44,13 +48,14 @@ end
|
|
44
48
|
|
45
49
|
### Adding a new monitor
|
46
50
|
- use [datadog monitor UI](https://app.datadoghq.com/monitors#create/metric) to create a monitor
|
47
|
-
- get the `id` from the url
|
48
|
-
- `RESOURCE=monitor ID=12345 bundle exec rake kennel:import`
|
49
51
|
- see below
|
50
52
|
|
51
53
|
### Updating an existing monitor
|
54
|
+
- use [datadog monitor UI](https://app.datadoghq.com/monitors#create/metric) to find a monitor
|
55
|
+
- get the `id` from the url
|
56
|
+
- run `RESOURCE=monitor ID=12345 bundle exec rake kennel:import` and copy the output
|
52
57
|
- find or create a project in `projects/`
|
53
|
-
- add
|
58
|
+
- add the monitor to `parts: [` list, for example:
|
54
59
|
```Ruby
|
55
60
|
# projects/my_project.rb
|
56
61
|
class MyProject < Kennel::Models::Project
|
@@ -65,7 +70,8 @@ end
|
|
65
70
|
kennel_id: -> { "load-too-high" }, # make up a unique name
|
66
71
|
name: -> { "Foobar Load too high" }, # nice descriptive name that will show up in alerts and emails
|
67
72
|
message: -> {
|
68
|
-
# Explain what behavior to expect and how to fix the cause
|
73
|
+
# Explain what behavior to expect and how to fix the cause
|
74
|
+
# Use #{super()} to add team notifications.
|
69
75
|
<<~TEXT
|
70
76
|
Foobar will be slow and that could cause Barfoo to go down.
|
71
77
|
Add capacity or debug why it is suddenly slow.
|
@@ -80,21 +86,22 @@ end
|
|
80
86
|
)
|
81
87
|
end
|
82
88
|
```
|
83
|
-
- `bundle exec rake plan
|
84
|
-
- alternatively: `bundle exec rake generate` to only update the generated `json` files
|
89
|
+
- run `PROJECT=my_project bundle exec rake plan`, an Update to the existing monitor should be shown (not Create / Delete)
|
90
|
+
- alternatively: `bundle exec rake generate` to only locally update the generated `json` files
|
85
91
|
- review changes then `git commit`
|
86
92
|
- make a PR ... get reviewed ... merge
|
87
93
|
- datadog is updated by travis
|
88
94
|
|
89
95
|
### Adding a new dashboard
|
90
96
|
- go to [datadog dashboard UI](https://app.datadoghq.com/dashboard/lists) and click on _New Dashboard_ to create a dashboard
|
91
|
-
- get the `id` from the url
|
92
|
-
- `RESOURCE=dashboard ID=abc-def-ghi bundle exec rake kennel:import`
|
93
97
|
- see below
|
94
98
|
|
95
99
|
### Updating an existing dashboard
|
100
|
+
- go to [datadog dashboard UI](https://app.datadoghq.com/dashboard/lists) and click on _New Dashboard_ to find a dashboard
|
101
|
+
- get the `id` from the url
|
102
|
+
- run `RESOURCE=dashboard ID=abc-def-ghi bundle exec rake kennel:import` and copy the output
|
96
103
|
- find or create a project in `projects/`
|
97
|
-
- add a dashboard to `parts: [` list
|
104
|
+
- add a dashboard to `parts: [` list, for example:
|
98
105
|
```Ruby
|
99
106
|
class MyProject < Kennel::Models::Project
|
100
107
|
defaults(
|
@@ -142,6 +149,7 @@ To link to existing monitors via their kennel_id
|
|
142
149
|
|
143
150
|
- Screens `uptime` widgets can use `monitor: {id: "foo:bar"}`
|
144
151
|
- Screens `alert_graph` widgets can use `alert_id: "foo:bar"`
|
152
|
+
- Monitors `composite` can use `query: -> { "%{foo:bar} || %{foo:baz}" }`
|
145
153
|
|
146
154
|
### Debugging changes locally
|
147
155
|
|
@@ -177,7 +185,7 @@ Reuse it in multiple projects.
|
|
177
185
|
```Ruby
|
178
186
|
class Database < Kennel::Models::Project
|
179
187
|
defaults(
|
180
|
-
team: -> { Kennel::Models::Team.new(
|
188
|
+
team: -> { Kennel::Models::Team.new(mention: -> { '@slack-foo' }, kennel_id: -> { 'foo' }) },
|
181
189
|
parts: -> { [Monitors::LoadTooHigh.new(self, critical: -> { 13 })] }
|
182
190
|
)
|
183
191
|
end
|
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.54.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: 2019-
|
11
|
+
date: 2019-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|