kennel 1.159.0 → 1.161.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: afa96484d3351de6a715ca440d8a22d3eb81012866a08987b0ddce36b568ae48
4
- data.tar.gz: 5f8d189f4447e998711ae07a1ee245c56c0453569a5a43e12ca8a9e9c3184030
3
+ metadata.gz: 856d925b4aeee8af7171cb092b746c70c8e21cfa06a1987910a25ef193e79a50
4
+ data.tar.gz: c174845463912362beba00a86f63d11316ec54f0a57459e4c6cd32e0d1d358d4
5
5
  SHA512:
6
- metadata.gz: a3886ae264c55d8112de1f16e7d0af92b97d1ecbf470219ff7131cb45df6fa115ef14142cc3c31056e88a135bb2c4091d15fd9a160a624875f2758db23ad70d8
7
- data.tar.gz: 072d6d09e64c55e1a0c167ec884dfcf17102c05fdba614b5bbc1132e3c582cb5699c6bfdf1faf4d6a5d5d0b7b702adbc94b82753b20530d1d3d435593cea774a
6
+ metadata.gz: 328b385c98c37473d65799e1721da32f9a8ff4d4d238be42a37196aea6e880d5ce1ae76dfb5ec8ffd4e6f60c70c99af070566b09c3fa4c34032d431b4e2a6189
7
+ data.tar.gz: f74557a8ff3fe9ee436034774ed1fe5c5176e9919114e48241f08f3ffbc3950b2a32d25574d9d99c1a3c6470d3381d2880b356a7a54cc2795c2f13b4843980af
data/lib/kennel/api.rb CHANGED
@@ -7,7 +7,7 @@ module Kennel
7
7
 
8
8
  RateLimitParams = Data.define(:limit, :period, :remaining, :reset, :name)
9
9
 
10
- def self.tag(api_resource, reply)
10
+ def self.with_tracking(api_resource, reply)
11
11
  klass = Models::Record.api_resource_map[api_resource]
12
12
  return reply unless klass # do not blow up on unknown models
13
13
 
@@ -28,7 +28,7 @@ module Kennel
28
28
  response = request :get, "/api/v1/#{api_resource}/#{id}", params: params
29
29
  response = response.fetch(:data) if api_resource == "slo"
30
30
  response[:id] = response.delete(:public_id) if api_resource == "synthetics/tests"
31
- self.class.tag(api_resource, response)
31
+ self.class.with_tracking(api_resource, response)
32
32
  end
33
33
 
34
34
  def list(api_resource, params = {})
@@ -44,7 +44,7 @@ module Kennel
44
44
  # ignore monitor synthetics create and that inherit the kennel_id, we do not directly manage them
45
45
  response.reject! { |m| m[:type] == "synthetics alert" } if api_resource == "monitor"
46
46
 
47
- response.map { |r| self.class.tag(api_resource, r) }
47
+ response.map { |r| self.class.with_tracking(api_resource, r) }
48
48
  end
49
49
  end
50
50
 
@@ -52,13 +52,13 @@ module Kennel
52
52
  response = request :post, "/api/v1/#{api_resource}", body: attributes
53
53
  response = response.fetch(:data).first if api_resource == "slo"
54
54
  response[:id] = response.delete(:public_id) if api_resource == "synthetics/tests"
55
- self.class.tag(api_resource, response)
55
+ self.class.with_tracking(api_resource, response)
56
56
  end
57
57
 
58
58
  def update(api_resource, id, attributes)
59
59
  response = request :put, "/api/v1/#{api_resource}/#{id}", body: attributes
60
60
  response[:id] = response.delete(:public_id) if api_resource == "synthetics/tests"
61
- self.class.tag(api_resource, response)
61
+ self.class.with_tracking(api_resource, response)
62
62
  end
63
63
 
64
64
  # - force=true to not dead-lock on dependent monitors+slos
@@ -14,10 +14,6 @@ module Kennel
14
14
  end
15
15
 
16
16
  def import(resource, id)
17
- if ["screen", "dash"].include?(resource)
18
- raise ArgumentError, "resource 'screen' and 'dash' are deprecated, use 'dashboard'"
19
- end
20
-
21
17
  model =
22
18
  Kennel::Models::Record.subclasses.detect { |c| c.api_resource == resource } ||
23
19
  raise(ArgumentError, "#{resource} is not supported")
@@ -51,7 +47,9 @@ module Kennel
51
47
  data.merge!(data.delete(:thresholds) || {})
52
48
 
53
49
  # clean up values that are the default
54
- data.delete(:notify_no_data) if data[:notify_no_data] # Monitor uses true by default
50
+ if !!data[:notify_no_data] == !Models::Monitor::SKIP_NOTIFY_NO_DATA_TYPES.include?(data[:type])
51
+ data.delete(:notify_no_data)
52
+ end
55
53
  data.delete(:notify_audit) unless data[:notify_audit] # Monitor uses false by default
56
54
 
57
55
  # keep all values that are settable
@@ -34,7 +34,8 @@ module Kennel
34
34
  },
35
35
  time: {},
36
36
  title_align: "left",
37
- title_size: "16"
37
+ title_size: "16",
38
+ show_legend: true
38
39
  },
39
40
  "note" => {
40
41
  show_tick: false,
@@ -30,6 +30,7 @@ module Kennel
30
30
  }.freeze
31
31
  DEFAULT_ESCALATION_MESSAGE = ["", nil].freeze
32
32
  ALLOWED_PRIORITY_CLASSES = [NilClass, Integer].freeze
33
+ SKIP_NOTIFY_NO_DATA_TYPES = ["event alert", "event-v2 alert", "log alert"].freeze
33
34
 
34
35
  settings(
35
36
  :query, :name, :message, :escalation_message, :critical, :type, :renotify_interval, :warning, :timeout_h, :evaluation_delay,
@@ -44,7 +45,9 @@ module Kennel
44
45
  renotify_interval: -> { project.team.renotify_interval },
45
46
  warning: -> { nil },
46
47
  ok: -> { nil },
47
- notify_no_data: -> { true }, # datadog UI sets this to false by default, but true is safer
48
+ # datadog UI sets this to false by default, but true is safer
49
+ # except for log alerts which will always have "no error" gaps and should default to false
50
+ notify_no_data: -> { !SKIP_NOTIFY_NO_DATA_TYPES.include?(type) },
48
51
  no_data_timeframe: -> { 60 },
49
52
  notify_audit: -> { MONITOR_OPTION_DEFAULTS.fetch(:notify_audit) },
50
53
  new_host_delay: -> { MONITOR_OPTION_DEFAULTS.fetch(:new_host_delay) },
data/lib/kennel/syncer.rb CHANGED
@@ -91,21 +91,7 @@ module Kennel
91
91
  matching, unmatched_expected, unmatched_actual = MatchedExpected.partition(expected, actual)
92
92
  unmatched_actual.select! { |a| a.fetch(:tracking_id) } # ignore items that were never managed by kennel
93
93
 
94
- # if there is a new item that has the same name/title as a to be deleted item, we should just update it
95
- # careful with unmatched_expected being huge since it has all api resources
96
- unmatched_expected.reject! do |e|
97
- actual = unmatched_actual.detect do |a|
98
- a[:klass] == e.class &&
99
- Kennel::Models::Record::TITLE_FIELDS.any? { |f| (set = a[f]) && set == e.as_json.fetch(f) }
100
- end
101
- next false unless actual # keep in unmatched
102
-
103
- unmatched_actual.delete(actual)
104
- actual[:tracking_id] = e.tracking_id
105
- matching << [e, actual]
106
-
107
- true # remove from unmatched
108
- end
94
+ convert_replace_into_update!(matching, unmatched_actual, unmatched_expected)
109
95
 
110
96
  validate_expected_id_not_missing unmatched_expected
111
97
  fill_details! matching # need details to diff later
@@ -137,6 +123,32 @@ module Kennel
137
123
  end
138
124
  end
139
125
 
126
+ # if there is a new item that has the same name or title as an "to be deleted" item,
127
+ # update it instead to avoid old urls from becoming invalid
128
+ # - careful with unmatched_actual being huge since it has all api resources
129
+ # - don't do it when a monitor type is changing since that would block the update
130
+ def convert_replace_into_update!(matching, unmatched_actual, unmatched_expected)
131
+ unmatched_expected.reject! do |e|
132
+ e_field, e_value = Kennel::Models::Record::TITLE_FIELDS.detect do |field|
133
+ next unless (value = e.as_json[field])
134
+ break [field, value]
135
+ end
136
+ raise unless e_field # uncovered: should never happen ...
137
+ e_monitor_type = e.as_json[:type]
138
+
139
+ actual = unmatched_actual.detect do |a|
140
+ a[:klass] == e.class && a[e_field] == e_value && a[:type] == e_monitor_type
141
+ end
142
+ next false unless actual # keep in unmatched
143
+
144
+ # add as update and remove from unmatched
145
+ unmatched_actual.delete(actual)
146
+ actual[:tracking_id] = e.tracking_id
147
+ matching << [e, actual]
148
+ true
149
+ end
150
+ end
151
+
140
152
  # fill details of things we need to compare
141
153
  def fill_details!(details_needed)
142
154
  details_needed = details_needed.map { |e, a| a if e && e.class.api_resource == "dashboard" }.compact
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "1.159.0"
3
+ VERSION = "1.161.0"
4
4
  end
data/lib/kennel.rb CHANGED
@@ -131,13 +131,13 @@ module Kennel
131
131
 
132
132
  # performance: this takes ~100ms on large codebases, tried rewriting with Set or Hash but it was slower
133
133
  def validate_unique_tracking_ids(parts)
134
- parts.group_by(&:tracking_id).each do |tracking_id, same|
135
- next if same.size == 1
136
- raise <<~ERROR
137
- #{tracking_id} is defined #{same.size} times
138
- use a different `kennel_id` when defining multiple projects/monitors/dashboards to avoid this conflict
139
- ERROR
140
- end
134
+ bad = parts.group_by(&:tracking_id).select { |_, same| same.size > 1 }
135
+ return if bad.empty?
136
+ raise <<~ERROR
137
+ #{bad.map { |tracking_id, same| "#{tracking_id} is defined #{same.size} times" }.join("\n")}
138
+
139
+ use a different `kennel_id` when defining multiple projects/monitors/dashboards to avoid this conflict
140
+ ERROR
141
141
  end
142
142
 
143
143
  def definitions(**kwargs)
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.159.0
4
+ version: 1.161.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: 2025-04-02 00:00:00.000000000 Z
11
+ date: 2025-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs