kennel 1.49.0 → 1.53.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: 7f0aabf5d65787da727c8f2fe6d4e42a3d88bca6cf31a426b2b29efbacc29316
4
- data.tar.gz: 8058d85578b7bf7247c26e50c8759fb4036977f22f321068283c1da77cf5e25e
3
+ metadata.gz: 95c82242166781e34d9132c511942a71c45c480951cb4b986702479cca60e271
4
+ data.tar.gz: 44ab3de5ad5709b6be941bfc8706ae4b712f94a3d1b9ae75a2f028a4e2c42926
5
5
  SHA512:
6
- metadata.gz: 80e9d102685107b747629f2df6045b30f588a1f9f9f7df2a668bfa7513fb96f47606c929d5276734282031328766210ae7c8dc260ef0e259a6cac4e36e915b22
7
- data.tar.gz: 762d5d95e419700fd9deb1b0c56fcaed33a460e3c65a4ed8d8f4ebd8c60875438d402423b48d62a086efe3b79019e72b64fd43bb59251ed20308039735f9f01a
6
+ metadata.gz: eb2bf40bccca3072b58c6eb7e7342de8ed51f6a716eba29eb5d717aeb013da18e082fdc0b4565fa666d6a7146d8dd77bc085f343b06d08fb81a285da7d64d520
7
+ data.tar.gz: be449f1b2c32d1f5996d16d17baa3e215c4446ae2ce4c865bd3cb160baece6bd8f56049cc7e29a56f025339a660ba474b6258fc042d808222a156cc2eb90f8e5
data/Readme.md CHANGED
@@ -154,12 +154,19 @@ end
154
154
  Some validations might be too strict for your usecase or just wrong, please [open an issue](https://github.com/grosser/kennel/issues) and
155
155
  to unblock use the `validate: -> { false }` option.
156
156
 
157
+ ### Monitor re-notification
158
+
159
+ Monitors inherit the re-notification setting from their `project.team`.
160
+ Set this to for example `renotify_interval: -> { 120 }` minutes,
161
+ to make alerts not get ignored by popping back up if they are still alerting.
162
+
157
163
  ### Linking with kennel_ids
158
164
 
159
165
  To link to existing monitors via their kennel_id
160
166
 
161
167
  - Screens `uptime` widgets can use `monitor: {id: "foo:bar"}`
162
168
  - Screens `alert_graph` widgets can use `alert_id: "foo:bar"`
169
+ - Monitors `composite` can use `query: -> { "%{foo:bar} || %{foo:baz}" }`
163
170
 
164
171
  ### Debugging changes locally
165
172
 
@@ -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
@@ -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}"
@@ -39,7 +39,7 @@ module Kennel
39
39
  pair.each do |b|
40
40
  b[:widgets]&.each do |w|
41
41
  if formats = w.dig(:definition, :conditional_formats)
42
- w[:definition][:conditional_formats] = formats.sort_by { |h| h[:value].to_f }
42
+ w[:definition][:conditional_formats] = formats.sort_by(&:hash)
43
43
  end
44
44
  end
45
45
  end
@@ -73,12 +73,15 @@ module Kennel
73
73
 
74
74
  def as_json
75
75
  return @json if @json
76
+ all_widgets = render_definitions + widgets
77
+ expand_q all_widgets
78
+
76
79
  @json = {
77
80
  layout_type: layout_type,
78
81
  title: "#{title}#{LOCK}",
79
82
  description: description,
80
83
  template_variables: render_template_variables,
81
- widgets: render_definitions + widgets
84
+ widgets: all_widgets
82
85
  }
83
86
 
84
87
  @json[:id] = id if id
@@ -98,11 +101,13 @@ module Kennel
98
101
  case definition[:type]
99
102
  when "uptime"
100
103
  if ids = definition[:monitor_ids]
101
- definition[:monitor_ids] = ids.map { |id| resolve_link(id, id_map) }
104
+ definition[:monitor_ids] = ids.map do |id|
105
+ tracking_id?(id) ? resolve_link(id, id_map, force: false) : id
106
+ end
102
107
  end
103
108
  when "alert_graph"
104
- if id = definition[:alert_id]
105
- 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
106
111
  end
107
112
  end
108
113
  end
@@ -110,16 +115,24 @@ module Kennel
110
115
 
111
116
  private
112
117
 
113
- def resolve_link(id, id_map)
114
- return id unless tracking_id?(id)
115
- id_map[id] ||
116
- Kennel.err.puts("Unable to find #{id} in existing monitors (they need to be created first to link them)")
117
- end
118
-
119
118
  def tracking_id?(id)
120
119
  id.is_a?(String) && !id.match?(/\A\d+\z/)
121
120
  end
122
121
 
122
+ # creates queries from metadata to avoid having to keep q and expression in sync
123
+ #
124
+ # {q: :metadata, metadata: [{expression: "sum:bar", alias_name: "foo"}, ...], }
125
+ # -> {q: "sum:bar, ...", metadata: ..., }
126
+ def expand_q(widgets)
127
+ widgets = widgets.flat_map { |w| w.dig(:definition, :widgets) || w } # expand groups
128
+ widgets.each do |w|
129
+ w.dig(:definition, :requests)&.each do |request|
130
+ next unless request.is_a?(Hash) && request[:q] == :metadata
131
+ request[:q] = request.fetch(:metadata).map { |m| m.fetch(:expression) }.join(", ")
132
+ end
133
+ end
134
+ end
135
+
123
136
  def validate_json(data)
124
137
  super
125
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: 120,
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
@@ -29,7 +29,7 @@ module Kennel
29
29
  defaults(
30
30
  message: -> { "\n\n@slack-#{project.slack}" },
31
31
  escalation_message: -> { DEFAULT_ESCALATION_MESSAGE.first },
32
- renotify_interval: -> { MONITOR_OPTION_DEFAULTS.fetch(: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,9 +2,10 @@
2
2
  module Kennel
3
3
  module Models
4
4
  class Team < Base
5
- settings :slack, :email, :tags, :kennel_id
5
+ settings :slack, :email, :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
 
10
11
  def initialize(*)
@@ -72,11 +72,22 @@ module Kennel
72
72
  filter_by_project! actual
73
73
 
74
74
  details_cache do |cache|
75
- actual.each do |a|
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
- fill_details(a, cache) if e.class::API_LIST_INCOMPLETE
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
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "1.49.0"
3
+ VERSION = "1.53.0"
4
4
  end
@@ -136,12 +136,18 @@ end
136
136
  Some validations might be too strict for your usecase or just wrong, please [open an issue](https://github.com/grosser/kennel/issues) and
137
137
  to unblock use the `validate: -> { false }` option.
138
138
 
139
+ ### Monitor re-notification
140
+
141
+ Monitors inherit the re-notification setting from their projects team.
142
+ By default this is `renotify_interval: -> { 120 }` minutes, which will make alerts not get ignored by popping back up.
143
+
139
144
  ### Linking with kennel_ids
140
145
 
141
146
  To link to existing monitors via their kennel_id
142
147
 
143
148
  - Screens `uptime` widgets can use `monitor: {id: "foo:bar"}`
144
149
  - Screens `alert_graph` widgets can use `alert_id: "foo:bar"`
150
+ - Monitors `composite` can use `query: -> { "%{foo:bar} || %{foo:baz}" }`
145
151
 
146
152
  ### Debugging changes locally
147
153
 
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.49.0
4
+ version: 1.53.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-08-20 00:00:00.000000000 Z
11
+ date: 2019-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday