kennel 2.6.1 → 2.7.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: bb95ceae817bc98d083407c5a6b19483e12e1932a98209c13fd097cd9bcf7ebd
4
- data.tar.gz: 1a0c92f146ab14ffe80bccc86cb12f1561e8d874faefbe7f48f550a4c108cb6e
3
+ metadata.gz: fb759ae2d81d962a137b9ff0485135f0995cf4e31542f0ab4f284eef9ea1c109
4
+ data.tar.gz: d1fafb3a5d44c746280967f752e4eb124510a823c7ac2bd51ca2e935517afbb6
5
5
  SHA512:
6
- metadata.gz: 2b43e7160e79a8174ae60d929d998322cfda2730116500ce8e6ddbfd4114c2217b0d75c5f326ffafbc94c5976155810a858f6d43423430223fa9325207373a75
7
- data.tar.gz: b9c53626a278cea303b617ec12f792f89b5a5ca858a20dd75f244367a38065ed436e5309184b04e8c5ba5f7060a5c5dab472837b2729c2313ab6cb730d6f0bef
6
+ metadata.gz: bf576a0739a2cb98e7098c71bbf222d202766dbb479f9fd3c7b13bc0561b3f699cd1396faf4ef070c34be3bbed102aa8f8ca153d6c8c2c43e4767d945fe8df13
7
+ data.tar.gz: 2f2de90e0ad97900b86d92b168c1065f0128c15a0039eec3f4e611364e650a9faff20c4f6890b375fa15b3321c3e399d4a7a76fd648bcf56083675599ecb9c14
@@ -208,9 +208,10 @@ module Kennel
208
208
  end
209
209
  end
210
210
 
211
- def validate_update!(diffs)
212
- _, path, from, to = diffs.find { |diff| diff[1] == "layout_type" }
213
- invalid_update!(path, from, to) if path
211
+ def allowed_update_error(actual)
212
+ actual_type = actual[:layout_type]
213
+ return if actual_type == layout_type
214
+ "cannot update layout_type from #{actual_type} to #{layout_type}"
214
215
  end
215
216
 
216
217
  private
@@ -180,12 +180,11 @@ module Kennel
180
180
  end
181
181
  end
182
182
 
183
- def validate_update!(diffs)
184
- # ensure type does not change, but not if it's metric->query which is supported and used by importer.rb
185
- _, path, from, to = diffs.detect { |_, path, _, _| path == "type" }
186
- if path && !(from == "metric alert" && to == "query alert")
187
- invalid_update!(path, from, to)
188
- end
183
+ # ensure type does not change, but not if it's metric->query which is supported and used by importer.rb
184
+ def allowed_update_error(actual)
185
+ actual_type = actual[:type]
186
+ return if actual_type == type || (actual_type == "metric alert" && type == "query alert")
187
+ "cannot update type from #{actual_type} to #{type}"
189
188
  end
190
189
 
191
190
  def self.api_resource
@@ -142,12 +142,8 @@ module Kennel
142
142
  @as_json
143
143
  end
144
144
 
145
- # Can raise DisallowedUpdateError
146
- def validate_update!(_diffs)
147
- end
148
-
149
- def invalid_update!(field, old_value, new_value)
150
- raise DisallowedUpdateError, "#{safe_tracking_id} Datadog does not allow update of #{field} (#{old_value.inspect} -> #{new_value.inspect})"
145
+ def allowed_update_error(_a)
146
+ nil
151
147
  end
152
148
 
153
149
  # For use during error handling
@@ -36,7 +36,13 @@ module Kennel
36
36
 
37
37
  def matching_expected(a, map)
38
38
  klass = a.fetch(:klass)
39
- map["#{klass.api_resource}:#{a.fetch(:id)}"] || map[a.fetch(:tracking_id)]
39
+ full_id = "#{klass.api_resource}:#{a.fetch(:id)}"
40
+ if (e = map[full_id]) # we try to update and the user has set the id
41
+ return e unless (error = e.allowed_update_error(a))
42
+ raise DisallowedUpdateError, "#{full_id} Datadog does not allow update: #{error}"
43
+ elsif (e = map[a.fetch(:tracking_id)])
44
+ e.allowed_update_error(a) ? nil : e # force a re-create if we can't update
45
+ end
40
46
  end
41
47
  end
42
48
  end
@@ -12,9 +12,9 @@ module Kennel
12
12
  if plan.empty?
13
13
  Kennel.out.puts Console.color(:green, "Nothing to do")
14
14
  else
15
+ print_changes "Delete", plan.deletes, :red
15
16
  print_changes "Create", plan.creates, :green
16
17
  print_changes "Update", plan.updates, :yellow
17
- print_changes "Delete", plan.deletes, :red
18
18
  end
19
19
  end
20
20
 
data/lib/kennel/syncer.rb CHANGED
@@ -20,7 +20,6 @@ module Kennel
20
20
 
21
21
  @resolver = Resolver.new(expected: expected, filter: filter)
22
22
  @plan = Plan.new(*calculate_changes(expected: expected, actual: actual))
23
- validate_changes
24
23
  end
25
24
 
26
25
  def print_plan
@@ -126,27 +125,19 @@ module Kennel
126
125
  # if there is a new item that has the same name or title as an "to be deleted" item,
127
126
  # update it instead to avoid old urls from becoming invalid
128
127
  # - 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
- # - don't do it when a dashboard layout_type is changing since that would block the update
131
- # - when using a filter and updating the kennel_id of an existing item, old and new must be in the filter
128
+ # - don't do it when update is not allowed
129
+ # - when using a filter and updating the kennel_id of an existing item, old and new must be in the filter (PROJECT= works, but not TRACKING_ID)
132
130
  def convert_replace_into_update!(matching, unmatched_actual, unmatched_expected)
133
131
  unmatched_expected.reject! do |e|
134
- e_field, e_value = Kennel::Models::Record::TITLE_FIELDS.detect do |field|
135
- next unless (value = e.as_json[field])
136
- break [field, value]
137
- end
138
- raise unless e_field # uncovered: should never happen ...
139
- # TODO: ideally reuse invalid_update! logic and just put the fields somewhere
140
- e_monitor_type = e.as_json[:type]
141
- e_dashboard_layout_type = e.as_json[:layout_type]
142
-
132
+ # find actual by title
133
+ e_field, e_value = title_field_and_value(e)
143
134
  actual = unmatched_actual.detect do |a|
144
135
  a[:klass].api_resource == e.class.api_resource &&
145
- a[e_field] == e_value &&
146
- a[:type] == e_monitor_type &&
147
- a[:layout_type] == e_dashboard_layout_type
136
+ a[e_field] == e_value
148
137
  end
149
- next false unless actual # keep in unmatched
138
+
139
+ # keep unmatched if we could not find or can't update
140
+ next false if !actual || e.allowed_update_error(actual)
150
141
 
151
142
  # add as update and remove from unmatched
152
143
  unmatched_actual.delete(actual)
@@ -156,6 +147,14 @@ module Kennel
156
147
  end
157
148
  end
158
149
 
150
+ def title_field_and_value(e)
151
+ Kennel::Models::Record::TITLE_FIELDS.detect do |field|
152
+ next unless (value = e.as_json[field])
153
+ return [field, value]
154
+ end
155
+ raise # uncovered: should never happen ...
156
+ end
157
+
159
158
  # fill details of things we need to compare
160
159
  def fill_details!(details_needed)
161
160
  details_needed = details_needed.map { |e, a| a if e && e.class.api_resource == "dashboard" }.compact
@@ -175,14 +174,6 @@ module Kennel
175
174
  end
176
175
  end
177
176
 
178
- # We've already validated the desired objects ('generated') in isolation.
179
- # Now that we have made the plan, we can perform some more validation.
180
- def validate_changes
181
- @plan.updates.each do |item|
182
- item.expected.validate_update!(item.diff)
183
- end
184
- end
185
-
186
177
  def filter_actual!(actual)
187
178
  return unless filter.filtering? # minor optimization
188
179
 
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "2.6.1"
3
+ VERSION = "2.7.0"
4
4
  end
data/lib/kennel.rb CHANGED
@@ -143,7 +143,10 @@ module Kennel
143
143
  def definitions(**kwargs)
144
144
  @definitions ||= Progress.progress("Downloading definitions", **kwargs) do
145
145
  Utils.parallel(Models::Record.subclasses) do |klass|
146
- api.list(klass.api_resource, with_downtimes: false) # lookup monitors without adding unnecessary downtime information
146
+ # lookup monitors without adding unnecessary downtime information
147
+ params = (klass.api_resource == "monitor" ? { with_downtimes: false } : {})
148
+
149
+ api.list(klass.api_resource, params)
147
150
  end.flatten(1)
148
151
  end
149
152
  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: 2.6.1
4
+ version: 2.7.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-10-30 00:00:00.000000000 Z
11
+ date: 2025-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs