kennel 1.71.1 → 1.74.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: c0ca96d8341536601616efc93c2f48135ee4741de6f656edb713491551c690b1
4
- data.tar.gz: 4e3342aa57b48e41ce77fde7ddfde5069dfd8b7130cef573b4cf370fc05c56ef
3
+ metadata.gz: 769ede5638522cc0c56394f0fde86207b88aad4ade1ff05e0360018972e52a55
4
+ data.tar.gz: 467dfab6d84ec29c1efbba1f7ab1df2fad3fd5767521a677c88b38c8bb8f2e19
5
5
  SHA512:
6
- metadata.gz: bce50a0e0acaab290a2ffb416c0863491165662a894d3e718ee750802d3e2cdbdaef742b996091ce08ec710b4401a92d895a598506e760a7cb56ec751e0e2c1e
7
- data.tar.gz: fff125b288517a5a89c9305542051acbc43540cc0a1ff8a97fe5a9687a44e92793e0ff4cac73368d8dc4902172a08065a5b4ce1f13022b8993d1dfc0dbe0190c
6
+ metadata.gz: 64f8dbae6ba9ea0d51be0c20a955a261ca026c760e77cf05e945b0a2514e6ef99527f8a00a9dc39abc053235fd76474435fb13d610e6e1ed1ce4e92d99e81ea9
7
+ data.tar.gz: 695f7f97b7355291d66b72423ac3c1adcadf804ced559aa35222c431c92198beca00fa625ebbad70ab105173ec8ca0b11eb4ec13a3dd19c04945fa9709821552
@@ -29,7 +29,6 @@ require "kennel/models/project"
29
29
  require "kennel/models/team"
30
30
 
31
31
  module Kennel
32
- MISSING_ID = 1
33
32
  class ValidationError < RuntimeError
34
33
  end
35
34
 
@@ -40,7 +40,8 @@ module Kennel
40
40
  Kennel::Utils.parameterize(title)
41
41
  end
42
42
 
43
- if resource == "monitor"
43
+ case resource
44
+ when "monitor"
44
45
  # flatten monitor options so they are all on the base
45
46
  data.merge!(data.delete(:options))
46
47
  data.merge!(data.delete(:thresholds) || {})
@@ -55,7 +56,7 @@ module Kennel
55
56
  end
56
57
 
57
58
  data[:type] = "query alert" if data[:type] == "metric alert"
58
- elsif resource == "dashboard"
59
+ when "dashboard"
59
60
  widgets = data[:widgets]&.flat_map { |widget| widget.dig(:definition, :widgets) || [widget] }
60
61
  widgets&.each { |widget| dry_up_query!(widget) }
61
62
  end
@@ -13,15 +13,23 @@ module Kennel
13
13
  REQUEST_DEFAULTS = {
14
14
  style: { line_width: "normal", palette: "dog_classic", line_type: "solid" }
15
15
  }.freeze
16
- TIMESERIES_DEFAULTS = { show_legend: false, legend_size: "0" }.freeze
16
+ WIDGET_DEFAULTS = {
17
+ "timeseries" => { show_legend: false, legend_size: "0" },
18
+ "note" => { background_color: "white", font_size: "14", show_tick: false, tick_edge: "left", tick_pos: "50%", text_align: "left" }
19
+ }.freeze
17
20
  SUPPORTED_DEFINITION_OPTIONS = [:events, :markers, :precision].freeze
18
21
 
19
- settings :title, :description, :definitions, :widgets, :layout_type
22
+ DEFAULTS = {
23
+ template_variable_presets: nil
24
+ }.freeze
25
+
26
+ settings :title, :description, :definitions, :widgets, :layout_type, :template_variable_presets
20
27
 
21
28
  defaults(
22
29
  description: -> { "" },
23
30
  definitions: -> { [] },
24
31
  widgets: -> { [] },
32
+ template_variable_presets: -> { DEFAULTS.fetch(:template_variable_presets) },
25
33
  id: -> { nil }
26
34
  )
27
35
 
@@ -33,6 +41,8 @@ module Kennel
33
41
  def normalize(expected, actual)
34
42
  super
35
43
 
44
+ ignore_default(expected, actual, DEFAULTS)
45
+
36
46
  widgets_pairs(expected, actual).each do |pair|
37
47
  # conditional_formats ordering is randomly changed by datadog, compare a stable ordering
38
48
  pair.each do |widgets|
@@ -43,7 +53,7 @@ module Kennel
43
53
  end
44
54
  end
45
55
 
46
- ignore_definition_defaults_for_type pair, "timeseries", TIMESERIES_DEFAULTS
56
+ ignore_widget_defaults pair
47
57
 
48
58
  ignore_request_defaults(*pair)
49
59
 
@@ -54,11 +64,12 @@ module Kennel
54
64
 
55
65
  private
56
66
 
57
- def ignore_definition_defaults_for_type(pair, type, defaults)
67
+ def ignore_widget_defaults(pair)
58
68
  pair.map(&:size).max.times do |i|
59
- if pair.all? { |w| w.dig(i, :definition, :type) == type }
60
- ignore_defaults(pair[0], pair[1], defaults, nesting: :definition)
61
- end
69
+ types = pair.map { |w| w.dig(i, :definition, :type) }.uniq
70
+ next unless types.size == 1
71
+ next unless defaults = WIDGET_DEFAULTS[types.first]
72
+ ignore_defaults(pair[0], pair[1], defaults, nesting: :definition)
62
73
  end
63
74
  end
64
75
 
@@ -102,6 +113,7 @@ module Kennel
102
113
  title: "#{title}#{LOCK}",
103
114
  description: description,
104
115
  template_variables: render_template_variables,
116
+ template_variable_presets: template_variable_presets,
105
117
  widgets: all_widgets
106
118
  }
107
119
 
@@ -120,7 +132,7 @@ module Kennel
120
132
  url[/\/dashboard\/([a-z\d-]+)/, 1]
121
133
  end
122
134
 
123
- def resolve_linked_tracking_ids(id_map)
135
+ def resolve_linked_tracking_ids!(id_map, **args)
124
136
  widgets = as_json[:widgets].flat_map { |w| [w, *w.dig(:definition, :widgets) || []] }
125
137
  widgets.each do |widget|
126
138
  next unless definition = widget[:definition]
@@ -128,16 +140,16 @@ module Kennel
128
140
  when "uptime"
129
141
  if ids = definition[:monitor_ids]
130
142
  definition[:monitor_ids] = ids.map do |id|
131
- tracking_id?(id) ? resolve_link(id, :monitor, id_map) : id
143
+ tracking_id?(id) ? resolve_link(id, :monitor, id_map, **args) : id
132
144
  end
133
145
  end
134
146
  when "alert_graph"
135
147
  if (id = definition[:alert_id]) && tracking_id?(id)
136
- definition[:alert_id] = resolve_link(id, :monitor, id_map).to_s
148
+ definition[:alert_id] = resolve_link(id, :monitor, id_map, **args).to_s
137
149
  end
138
150
  when "slo"
139
151
  if (id = definition[:slo_id]) && tracking_id?(id)
140
- definition[:slo_id] = resolve_link(id, :slo, id_map).to_s
152
+ definition[:slo_id] = resolve_link(id, :slo, id_map, **args).to_s
141
153
  end
142
154
  end
143
155
  end
@@ -167,6 +179,10 @@ module Kennel
167
179
  super
168
180
 
169
181
  validate_template_variables data, :widgets
182
+
183
+ # Avoid diff from datadog presets sorting.
184
+ presets = data[:template_variable_presets]
185
+ invalid! "template_variable_presets must be sorted by name" if presets && presets != presets.sort_by { |p| p[:name] }
170
186
  end
171
187
 
172
188
  def render_definitions
@@ -103,11 +103,10 @@ module Kennel
103
103
  @as_json = data
104
104
  end
105
105
 
106
- def resolve_linked_tracking_ids(id_map)
106
+ def resolve_linked_tracking_ids!(id_map, **args)
107
107
  if as_json[:type] == "composite"
108
108
  as_json[:query] = as_json[:query].gsub(/%\{(.*?)\}/) do
109
- # need force here since it validates the id exists
110
- resolve_link($1, :monitor, id_map, force: true)
109
+ resolve_link($1, :monitor, id_map, **args)
111
110
  end
112
111
  end
113
112
  end
@@ -202,7 +201,7 @@ module Kennel
202
201
  # verify is_match uses available variables
203
202
  message = data.fetch(:message)
204
203
  used = message.scan(/{{\s*#is_match\s*"([a-zA-Z\d_.-]+).name"/).flatten.uniq
205
- allowed = data.fetch(:query)[/by\s*{([^\}]+)}/, 1].to_s.split(/\s*,\s*/)
204
+ allowed = data.fetch(:query)[/by\s*[({]([^})]+)[})]/, 1].to_s.gsub(/["']/, "").split(/\s*,\s*/)
206
205
  unsupported = used - allowed
207
206
  if unsupported.any?
208
207
  invalid! "is_match used with #{unsupported}, but metric is only grouped by #{allowed}"
@@ -60,23 +60,22 @@ module Kennel
60
60
  "#{project.kennel_id}:#{kennel_id}"
61
61
  end
62
62
 
63
- def resolve_linked_tracking_ids(*)
63
+ def resolve_linked_tracking_ids!(*)
64
64
  end
65
65
 
66
66
  private
67
67
 
68
- def resolve_link(id, type, id_map, force: false)
69
- found = id_map[id]
70
- return found if found && found != :new
71
- api_resource = self.class.api_resource
72
-
73
- if found == :new
68
+ def resolve_link(id, type, id_map, force:)
69
+ value = id_map[id]
70
+ if value == :new
74
71
  if force
75
- invalid! "#{api_resource.capitalize} #{id} will be created in the current run and can only be used after that"
72
+ # TODO: remove the need for this by sorting monitors by missing resolutions
73
+ invalid! "#{id} needs to already exist, try again"
76
74
  else
77
- Kennel.err.puts "#{api_resource.capitalize} #{id} will be created in the current run, the next run will link it properly"
78
- Kennel::MISSING_ID
75
+ id # will be re-resolved by syncer after the linked object was created
79
76
  end
77
+ elsif value
78
+ value
80
79
  else
81
80
  invalid! "Unable to find #{type} #{id} (does not exist and is not being created by the current run)"
82
81
  end
@@ -66,9 +66,9 @@ module Kennel
66
66
  url[/\/slo\?slo_id=([a-z\d]+)/, 1]
67
67
  end
68
68
 
69
- def resolve_linked_tracking_ids(id_map)
69
+ def resolve_linked_tracking_ids!(id_map, **args)
70
70
  as_json[:monitor_ids] = as_json[:monitor_ids].map do |id|
71
- id.is_a?(String) ? resolve_link(id, :monitor, id_map) : id
71
+ id.is_a?(String) ? resolve_link(id, :monitor, id_map, **args) : id
72
72
  end
73
73
  end
74
74
 
@@ -38,12 +38,23 @@ module Kennel
38
38
  end
39
39
 
40
40
  def update
41
+ changed = (@create + @update).map { |_, e| e } unless @create.empty?
42
+
41
43
  @create.each do |_, e|
44
+ e.resolve_linked_tracking_ids!({}, force: true)
45
+
42
46
  reply = @api.create e.class.api_resource, e.as_json
43
- Kennel.out.puts "Created #{e.class.api_resource} #{tracking_id(e.as_json)} #{e.url(reply.fetch(:id))}"
47
+ 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
+
53
+ Kennel.out.puts "Created #{e.class.api_resource} #{tracking_id(e.as_json)} #{e.url(id)}"
44
54
  end
45
55
 
46
56
  @update.each do |id, e|
57
+ e.resolve_linked_tracking_ids!({}, force: true)
47
58
  @api.update e.class.api_resource, id, e.as_json
48
59
  Kennel.out.puts "Updated #{e.class.api_resource} #{tracking_id(e.as_json)} #{e.url(id)}"
49
60
  end
@@ -65,12 +76,10 @@ module Kennel
65
76
  @delete = []
66
77
 
67
78
  actual = Progress.progress("Downloading definitions") { download_definitions }
68
-
69
- resolve_linked_tracking_ids actual
79
+ resolve_linked_tracking_ids! from: actual, to: @expected
80
+ filter_by_project! actual
70
81
 
71
82
  Progress.progress "Diffing" do
72
- filter_by_project! actual
73
-
74
83
  items = actual.map do |a|
75
84
  e = matching_expected(a)
76
85
  if e && @expected.delete(e)
@@ -98,6 +107,7 @@ module Kennel
98
107
 
99
108
  ensure_all_ids_found
100
109
  @create = @expected.map { |e| [nil, e] }
110
+ @create.sort_by! { |_, e| -DELETE_ORDER.index(e.class.api_resource) }
101
111
  end
102
112
 
103
113
  @delete.sort_by! { |_, _, a| DELETE_ORDER.index a.fetch(:api_resource) }
@@ -178,7 +188,7 @@ module Kennel
178
188
  end
179
189
 
180
190
  # Do not add tracking-id when working with existing ids on a branch,
181
- # so resource do not get deleted from merges to master.
191
+ # so resource do not get deleted fr:om merges to master.
182
192
  # Also make sure the diff still makes sense, by kicking out the now noop-update.
183
193
  #
184
194
  # Note: ideally we'd never add tracking in the first place, but at that point we do not know the diff yet
@@ -203,10 +213,10 @@ module Kennel
203
213
  end
204
214
  end
205
215
 
206
- def resolve_linked_tracking_ids(actual)
207
- map = actual.each_with_object({}) { |a, lookup| lookup[tracking_id(a)] = a.fetch(:id) }
208
- @expected.each { |e| map[e.tracking_id] ||= :new }
209
- @expected.each { |e| e.resolve_linked_tracking_ids(map) }
216
+ def resolve_linked_tracking_ids!(from:, to:)
217
+ map = from.each_with_object({}) { |a, lookup| lookup[tracking_id(a)] = a.fetch(:id) }
218
+ to.each { |e| map[e.tracking_id] ||= :new }
219
+ to.each { |e| e.resolve_linked_tracking_ids!(map, force: false) }
210
220
  end
211
221
 
212
222
  def filter_by_project!(definitions)
@@ -19,6 +19,7 @@ module Kennel
19
19
  .gsub(/::/, "_") # Foo::Bar -> foo_bar
20
20
  .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2') # FOOBar -> foo_bar
21
21
  .gsub(/([a-z\d])([A-Z])/, '\1_\2') # fooBar -> foo_bar
22
+ .tr("-", "_") # foo-bar -> foo_bar
22
23
  .downcase
23
24
  end
24
25
 
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "1.71.1"
3
+ VERSION = "1.74.0"
4
4
  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.71.1
4
+ version: 1.74.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: 2020-06-04 00:00:00.000000000 Z
11
+ date: 2020-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday