kennel 1.80.0 → 1.81.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: 0cc9d71dff0d4c4bf8a29d9c58c1b62efbb739f3ebdc0d63fb7bd1a3e1cfec7c
4
- data.tar.gz: 312fbda2e1577d071ba7cad7a6c5571b6b3913517cc3e5e9b92f7858637f96dc
3
+ metadata.gz: 577e1080c2efe476233752e7199c6179b5b2c9f611479a9d36ce23301077a6dd
4
+ data.tar.gz: d4fa1df4c77bd31c9c067c1f2a762ef304502da58fda08add91f651f683a86f2
5
5
  SHA512:
6
- metadata.gz: 8d07c6d405178e7114c1ebaf67ce3f92a09a411208d20353bf7d07f453093e322b98f2e8e2f501cf902a601fafa1b352b5fa19bff9d54f1d042e87fc7ef81277
7
- data.tar.gz: 9d681c94f1d61bbc60a098ea0b6fe12e3efc5b6e3c771ec49743db8e6edaae1c83a64ae322a9f5759fc677465b199842f0401c8a38973d1bbaa14157f53f94da
6
+ metadata.gz: bf160d7bb083a7ad5d1912cd6de95d783203f1b52c8f119a1ab0c7e09a60ca71d2b526346dff1c78cf8710e0b3cb00a63821583a3a7864097c22fc6c6fc27fd9
7
+ data.tar.gz: 3022a0ae8b3d9b37d625ee58402d886f8d29d03ddc6693f2f7331acd2a08d41a16df1ed7942102780e3e2d47b0f0f2afbbf935076de60f4bf54268ecff435a91
data/Readme.md CHANGED
@@ -212,15 +212,20 @@ removing the `id` will cause kennel to create a new resource in datadog.
212
212
  Some validations might be too strict for your usecase or just wrong, please [open an issue](https://github.com/grosser/kennel/issues) and
213
213
  to unblock use the `validate: -> { false }` option.
214
214
 
215
- ### Linking with kennel_ids
216
-
217
- To link to existing monitors via their kennel_id `projects kennel_id` + `:` + `monitors kennel id`
218
-
219
- - Screens `uptime` widgets can use `monitor: {id: "foo:bar"}`
220
- - Screens `alert_graph` widgets can use `alert_id: "foo:bar"`
221
- - Monitors `composite` can use `query: -> { "%{foo:bar} || %{foo:baz}" }`
222
- - Monitors `slo alert` can use `query: -> { "error_budget(\"%{foo:bar}\").over(\"7d\") > 123.0" }`
223
- - Slos can use `monitor_ids: -> ["foo:bar"]`
215
+ ### Linking resources with kennel_id
216
+
217
+ Link resources with their kennel_id in the format `project kennel_id` + `:` + `resource kennel_id`,
218
+ this should be used to create dependent resources like monitor + slos,
219
+ so they can be created in a single update and can be re-created if any of them is deleted.
220
+
221
+ |Resource|Type|Syntax|
222
+ |---|---|---|
223
+ |Dashboard|uptime|`monitor: {id: "foo:bar"}`|
224
+ |Dashboard|alert_graph|`alert_id: "foo:bar"`|
225
+ |Dashboard|slo|`slo_id: "foo:bar"`|
226
+ |Monitor|composite|`query: -> { "%{foo:bar} && %{foo:baz}" }`|
227
+ |Monitor|slo alert|`query: -> { "error_budget(\"%{foo:bar}\").over(\"7d\") > 123.0" }`|
228
+ |Slo|monitor|`monitor_ids: -> ["foo:bar"]`|
224
229
 
225
230
  ### Debugging changes locally
226
231
 
@@ -140,16 +140,16 @@ module Kennel
140
140
  when "uptime"
141
141
  if ids = definition[:monitor_ids]
142
142
  definition[:monitor_ids] = ids.map do |id|
143
- tracking_id?(id) ? resolve_link(id, :monitor, id_map, **args) : id
143
+ tracking_id?(id) ? (resolve_link(id, :monitor, id_map, **args) || id) : id
144
144
  end
145
145
  end
146
146
  when "alert_graph"
147
147
  if (id = definition[:alert_id]) && tracking_id?(id)
148
- definition[:alert_id] = resolve_link(id, :monitor, id_map, **args).to_s
148
+ definition[:alert_id] = (resolve_link(id, :monitor, id_map, **args) || id).to_s
149
149
  end
150
150
  when "slo"
151
151
  if (id = definition[:slo_id]) && tracking_id?(id)
152
- definition[:slo_id] = resolve_link(id, :slo, id_map, **args).to_s
152
+ definition[:slo_id] = (resolve_link(id, :slo, id_map, **args) || id).to_s
153
153
  end
154
154
  end
155
155
  end
@@ -116,7 +116,7 @@ module Kennel
116
116
  when "composite", "slo alert"
117
117
  type = (as_json[:type] == "composite" ? :monitor : :slo)
118
118
  as_json[:query] = as_json[:query].gsub(/%{(.*?)}/) do
119
- resolve_link($1, type, id_map, **args)
119
+ resolve_link($1, type, id_map, **args) || $&
120
120
  end
121
121
  end
122
122
  end
@@ -65,19 +65,18 @@ module Kennel
65
65
 
66
66
  private
67
67
 
68
- def resolve_link(id, type, id_map, force:)
69
- value = id_map[id]
70
- if value == :new
68
+ def resolve_link(tracking_id, type, id_map, force:)
69
+ id = id_map[tracking_id]
70
+ if id == :new
71
71
  if force
72
- # TODO: remove the need for this by sorting monitors by missing resolutions
73
- invalid! "#{id} needs to already exist, try again"
72
+ invalid! "#{type} #{tracking_id} was referenced but is also created by the current run.\nIt could not be created because of a circular dependency, try creating only some of the resources"
74
73
  else
75
- id # will be re-resolved by syncer after the linked object was created
74
+ nil # will be re-resolved after the linked object was created
76
75
  end
77
- elsif value
78
- value
76
+ elsif id
77
+ id
79
78
  else
80
- invalid! "Unable to find #{type} #{id} (does not exist and is not being created by the current run)"
79
+ invalid! "Unable to find #{type} #{tracking_id} (does not exist and is not being created by the current run)"
81
80
  end
82
81
  end
83
82
 
@@ -69,7 +69,7 @@ module Kennel
69
69
  def resolve_linked_tracking_ids!(id_map, **args)
70
70
  return unless as_json[:monitor_ids] # ignore_default can remove it
71
71
  as_json[:monitor_ids] = as_json[:monitor_ids].map do |id|
72
- id.is_a?(String) ? resolve_link(id, :monitor, id_map, **args) : id
72
+ id.is_a?(String) ? (resolve_link(id, :monitor, id_map, **args) || id) : id
73
73
  end
74
74
  end
75
75
 
@@ -38,23 +38,14 @@ module Kennel
38
38
  end
39
39
 
40
40
  def update
41
- changed = (@create + @update).map { |_, e| e }
42
-
43
- @create.each do |_, e|
44
- e.resolve_linked_tracking_ids!({}, force: true)
45
-
41
+ each_resolved @create do |_, e|
46
42
  reply = @api.create e.class.api_resource, e.as_json
47
43
  id = reply.fetch(:id)
48
-
49
- # resolve ids we could previously no resolve
50
- changed.delete e
51
- resolve_linked_tracking_ids! from: [reply], to: changed
52
-
44
+ populate_id_map [reply] # allow resolving ids we could previously no resolve
53
45
  Kennel.out.puts "Created #{e.class.api_resource} #{tracking_id(e.as_json)} #{e.url(id)}"
54
46
  end
55
47
 
56
- @update.each do |id, e|
57
- e.resolve_linked_tracking_ids!({}, force: true)
48
+ each_resolved @update do |id, e|
58
49
  @api.update e.class.api_resource, id, e.as_json
59
50
  Kennel.out.puts "Updated #{e.class.api_resource} #{tracking_id(e.as_json)} #{e.url(id)}"
60
51
  end
@@ -67,6 +58,37 @@ module Kennel
67
58
 
68
59
  private
69
60
 
61
+ # loop over items until everything is resolved or crash when we get stuck
62
+ # this solves cases like composite monitors depending on each other or monitor->monitor slo->slo monitor chains
63
+ def each_resolved(list)
64
+ list = list.dup
65
+ loop do
66
+ return if list.empty?
67
+ list.reject! do |id, e|
68
+ if resolved?(e)
69
+ yield id, e
70
+ true
71
+ else
72
+ false
73
+ end
74
+ end ||
75
+ assert_resolved(list[0][1]) # resolve something or show a circular dependency error
76
+ end
77
+ end
78
+
79
+ # TODO: optimize by storing an instance variable if already resolved
80
+ def resolved?(e)
81
+ assert_resolved e
82
+ true
83
+ rescue ValidationError
84
+ false
85
+ end
86
+
87
+ # raises ValidationError when not resolved
88
+ def assert_resolved(e)
89
+ resolve_linked_tracking_ids! [e], force: true
90
+ end
91
+
70
92
  def noop?
71
93
  @create.empty? && @update.empty? && @delete.empty?
72
94
  end
@@ -74,9 +96,15 @@ module Kennel
74
96
  def calculate_diff
75
97
  @update = []
76
98
  @delete = []
99
+ @id_map = {}
77
100
 
78
101
  actual = Progress.progress("Downloading definitions") { download_definitions }
79
- resolve_linked_tracking_ids! from: actual, to: @expected
102
+
103
+ # resolve dependencies to avoid diff
104
+ populate_id_map actual
105
+ @expected.each { |e| @id_map[e.tracking_id] ||= :new }
106
+ resolve_linked_tracking_ids! @expected
107
+
80
108
  filter_by_project! actual
81
109
 
82
110
  Progress.progress "Diffing" do
@@ -107,7 +135,6 @@ module Kennel
107
135
 
108
136
  ensure_all_ids_found
109
137
  @create = @expected.map { |e| [nil, e] }
110
- @create.sort_by! { |_, e| -DELETE_ORDER.index(e.class.api_resource) }
111
138
  end
112
139
 
113
140
  @delete.sort_by! { |_, _, a| DELETE_ORDER.index a.fetch(:api_resource) }
@@ -214,10 +241,12 @@ module Kennel
214
241
  end
215
242
  end
216
243
 
217
- def resolve_linked_tracking_ids!(from:, to:)
218
- map = from.each_with_object({}) { |a, lookup| lookup[tracking_id(a)] = a.fetch(:id) }
219
- to.each { |e| map[e.tracking_id] ||= :new }
220
- to.each { |e| e.resolve_linked_tracking_ids!(map, force: false) }
244
+ def populate_id_map(actual)
245
+ actual.each { |a| @id_map[tracking_id(a)] = a.fetch(:id) }
246
+ end
247
+
248
+ def resolve_linked_tracking_ids!(list, force: false)
249
+ list.each { |e| e.resolve_linked_tracking_ids!(@id_map, force: force) }
221
250
  end
222
251
 
223
252
  def filter_by_project!(definitions)
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "1.80.0"
3
+ VERSION = "1.81.0"
4
4
  end
@@ -196,13 +196,17 @@ to unblock use the `validate: -> { false }` option.
196
196
 
197
197
  ### Linking with kennel_ids
198
198
 
199
- To link to existing monitors via their kennel_id `projects kennel_id` + `:` + `monitors kennel id`
200
-
201
- - Screens `uptime` widgets can use `monitor: {id: "foo:bar"}`
202
- - Screens `alert_graph` widgets can use `alert_id: "foo:bar"`
203
- - Monitors `composite` can use `query: -> { "%{foo:bar} || %{foo:baz}" }`
204
- - Monitors `slo alert` can use `query: -> { "error_budget(\"%{foo:bar}\").over(\"7d\") > 123.0" }`
205
- - Slos can use `monitor_ids: -> ["foo:bar"]`
199
+ Link resources via their kennel_id `projects kennel_id` + `:` + `monitors kennel id`,
200
+ this should be used to create dependent resources like monitor + slos.
201
+
202
+ |Resource|Type|Syntax|
203
+ |---|---|---|
204
+ |Dashboard|uptime|`monitor: {id: "foo:bar"}`|
205
+ |Dashboard|alert_graph|`alert_id: "foo:bar"`|
206
+ |Dashboard|slo|`slo_id: "foo:bar"`|
207
+ |Monitor|composite|`query: -> { "%{foo:bar} && %{foo:baz}" }`|
208
+ |Monitor|slo alert|`query: -> { "error_budget(\"%{foo:bar}\").over(\"7d\") > 123.0" }`|
209
+ |Slo|monitor|`monitor_ids: -> ["foo:bar"]`|
206
210
 
207
211
  ### Debugging changes locally
208
212
 
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.80.0
4
+ version: 1.81.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: 2021-01-07 00:00:00.000000000 Z
11
+ date: 2021-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday