kennel 2.20.0 → 2.21.1

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: d41a632f2e488aacff6253cdb1b161d628d7522ffd4b7ce3e006455b912ca16d
4
- data.tar.gz: 0ffe3c8a9ec7d828aa397460af8f06af307f14e4a9740ff0e1a1693bc6c65950
3
+ metadata.gz: 9487ffad47b72d1a4e4781239ef3fbd500f806e5d63590c03326d7c6b689529e
4
+ data.tar.gz: ec5258bd90e47766deb06f71ab8041b3009f6242279a7d9d9bdede0d36da67ec
5
5
  SHA512:
6
- metadata.gz: 8151f10629556f4b9dbad8b11c69e032fca8ebbd00a50e888482a2bb37659ce70028a8740606a90745de3b3808967165b4cc10c1faeac2ccce707bfc57cb8811
7
- data.tar.gz: 6682f0c4815aacd911464f92c94f376110e52219c465f6f482dfbb85399b0ec4ea2b5d33d78ae394f753a04ef959b6b766325bd4bbc2f0b461dd172a24ed1349
6
+ metadata.gz: 2a02de737a11b72651a05c4fbf5bd6e8180cffb95f9d398696e70ee8c8a8c0217e264892582f842a22c9c73ab1f559035c23e1e8da0f74c14680bcf9757c0c63
7
+ data.tar.gz: 7a2ad8b0f2561a624d410453c601da3c39184625c0565ba5d78a51689bcde28a5a623e3791ee316f7cc3d4141f0d5482735f643ad46c60364f7122ae8e2e5adf
data/lib/kennel/api.rb CHANGED
@@ -22,8 +22,9 @@ module Kennel
22
22
  @client = Faraday.new(url: url)
23
23
  end
24
24
 
25
- def show(api_resource, id, params = {})
26
- response = request :get, "/api/v1/#{api_resource}/#{id}", params: params
25
+ def show(api_resource, id, params = {}, ignore_404: false)
26
+ response = request :get, "/api/v1/#{api_resource}/#{id}", params: params, ignore_404: ignore_404
27
+ return if response.nil? # 404 that was ignored
27
28
  response = response.fetch(:data) if api_resource == "slo"
28
29
  response[:id] = response.delete(:public_id) if api_resource == "synthetics/tests"
29
30
  self.class.with_tracking(api_resource, response)
@@ -74,7 +75,12 @@ module Kennel
74
75
  # fill the resource with the full response from the `show` if `list` does not return it
75
76
  def fill_details!(api_resource, list)
76
77
  details_cache do |cache|
77
- Utils.parallel(list) { |a| fill_detail!(api_resource, a, cache) }.sum
78
+ results = Utils.parallel(list) { |a| fill_detail!(api_resource, a, cache) }
79
+
80
+ # drop resources that were not found (race condition between listing and showing)
81
+ list.select!.with_index { |_, i| results[i][1] }
82
+
83
+ results.count { |uncached, _| uncached }
78
84
  end
79
85
  end
80
86
 
@@ -96,15 +102,16 @@ module Kennel
96
102
  end
97
103
 
98
104
  # Make diff work even though we cannot mass-fetch definitions
105
+ # @return [uncached, found]
99
106
  def fill_detail!(api_resource, a, cache)
100
- uncached = 0
107
+ uncached = false
101
108
  args = [api_resource, a.fetch(:id)]
102
109
  full = cache.fetch(args, a.fetch(:modified_at)) do
103
- uncached += 1
104
- show(*args)
110
+ uncached = true
111
+ show(*args, ignore_404: true)
105
112
  end
106
- a.merge!(full)
107
- uncached
113
+ a.merge!(full) if full
114
+ [uncached, !!full]
108
115
  end
109
116
 
110
117
  def details_cache(&block)
@@ -117,29 +124,18 @@ module Kennel
117
124
  cached = (ENV["FORCE_GET_CACHE"] && method == :get)
118
125
 
119
126
  with_cache cached, path do
120
- response = nil
121
- tries.times do |i|
122
- response = Utils.retry Faraday::ConnectionFailed, Faraday::TimeoutError, times: 2 do
123
- @client.send(method, path) do |request|
124
- request.body = JSON.generate(body) if body
125
- request.headers["Content-type"] = "application/json"
126
- request.headers["DD-API-KEY"] = @api_key
127
- request.headers["DD-APPLICATION-KEY"] = @app_key
128
- end
129
- end
130
-
131
- if response.status == 429
132
- sleep_until_rate_limit_resets(response)
133
- redo
127
+ response = request_with_retries(path, tries) do
128
+ @client.send(method, path) do |request|
129
+ request.body = JSON.generate(body) if body
130
+ request.headers["Content-type"] = "application/json"
131
+ request.headers["DD-API-KEY"] = @api_key
132
+ request.headers["DD-APPLICATION-KEY"] = @app_key
134
133
  end
135
-
136
- last_try = (i == tries - 1)
137
- break if last_try || response.status < 500
138
- Kennel.err.puts "Retrying on server error #{response.status} for #{path}"
139
- sleep retry_backoff_time(i)
140
134
  end
141
135
 
142
- if !response.success? && (response.status != 404 || !ignore_404)
136
+ next if response.status == 404 && ignore_404
137
+
138
+ unless response.success?
143
139
  message = "Error #{response.status} during #{method.upcase} #{path}\n"
144
140
  message << "request:\n#{JSON.pretty_generate(body)}\nresponse:\n" if body
145
141
  message << response.body.encode(message.encoding, invalid: :replace, undef: :replace)
@@ -154,6 +150,28 @@ module Kennel
154
150
  end
155
151
  end
156
152
 
153
+ # retry on rate-limits and server errors, giving up after `tries` attempts
154
+ def request_with_retries(path, tries, &block)
155
+ raise ArgumentError, "tries must be > 0" if tries < 1
156
+ response = nil
157
+ tries.times do |i|
158
+ response = Utils.retry Faraday::ConnectionFailed, Faraday::TimeoutError, times: 2, &block
159
+
160
+ # we do not count 429s into the "tries", tries are only for real errors
161
+ # so this could loop forever if datadog consistently 429s
162
+ if response.status == 429
163
+ sleep_until_rate_limit_resets(response)
164
+ redo
165
+ end
166
+
167
+ last_try = (i == tries - 1)
168
+ break if last_try || response.status < 500
169
+ Kennel.err.puts "Retrying on server error #{response.status} for #{path}"
170
+ sleep retry_backoff_time(i)
171
+ end
172
+ response
173
+ end
174
+
157
175
  def sleep_until_rate_limit_resets(response)
158
176
  limit = response.headers["x-ratelimit-limit"]
159
177
  period = response.headers["x-ratelimit-period"]
@@ -86,7 +86,14 @@ module Kennel
86
86
  end
87
87
  when "synthetics/tests"
88
88
  data[:locations] = :all if data[:locations].sort == Kennel::Models::SyntheticTest::LOCATIONS.sort
89
- else
89
+ when "slo"
90
+ # sli_specification it is only used by datadog if the user switched to "Bad Events"
91
+ # otherwise user would be trying to set sli_specification but the slo does not change since query is used
92
+ if data.key?(:query) && data.key?(:sli_specification)
93
+ delete = (data.dig(:sli_specification, :count, :bad_events_formula) ? :query : :sli_specification)
94
+ data.delete delete
95
+ end
96
+ else # uncovered
90
97
  # noop
91
98
  end
92
99
 
@@ -10,10 +10,16 @@ module Kennel
10
10
 
11
11
  def self.file_location
12
12
  return @file_location if defined?(@file_location)
13
- if (location = instance_methods(false).first)
14
- @file_location = force_relative_path(instance_method(location).source_location.first)
13
+ methods = instance_methods(false)
14
+ if methods.any?
15
+ @file_location = methods.detect do |method|
16
+ location = instance_method(method).source_location.first
17
+ if (path = find_relative_path(location))
18
+ break path
19
+ end
20
+ end || raise("Unable to find file_location for #{name}")
15
21
  else
16
- @file_location = nil
22
+ @file_location = nil # not sure if this is actually needed
17
23
  end
18
24
  end
19
25
 
@@ -29,11 +35,9 @@ module Kennel
29
35
 
30
36
  private
31
37
 
32
- private_class_method def self.force_relative_path(path)
38
+ private_class_method def self.find_relative_path(path)
33
39
  return path unless File.absolute_path?(path)
34
- path.dup.sub!("#{Bundler.root}/", "") ||
35
- path.dup.sub!("#{Dir.pwd}/", "") ||
36
- raise("Unable to make path #{path} relative with bundler root #{Bundler.root} or pwd #{Dir.pwd}")
40
+ path.dup.sub!("#{Bundler.root}/", "") || path.dup.sub!("#{Dir.pwd}/", "")
37
41
  end
38
42
 
39
43
  # hook for users to add custom filtering via `prepend`
@@ -15,7 +15,8 @@ module Kennel
15
15
  groups: nil,
16
16
  monitor_ids: [],
17
17
  thresholds: [],
18
- primary: nil
18
+ primary: nil,
19
+ sli_specification: nil
19
20
  }.freeze
20
21
 
21
22
  settings :type, :description, :thresholds, :query, :tags, :monitor_ids, :monitor_tags, :name, :groups, :sli_specification, :primary
@@ -27,7 +28,8 @@ module Kennel
27
28
  monitor_ids: -> { DEFAULTS.fetch(:monitor_ids) },
28
29
  thresholds: -> { DEFAULTS.fetch(:thresholds) },
29
30
  groups: -> { DEFAULTS.fetch(:groups) },
30
- primary: -> { DEFAULTS.fetch(:primary) }
31
+ primary: -> { DEFAULTS.fetch(:primary) },
32
+ sli_specification: -> { DEFAULTS.fetch(:sli_specification) }
31
33
  )
32
34
 
33
35
  def build_json
@@ -50,9 +52,8 @@ module Kennel
50
52
  data[:target_threshold] = threshold[:target]
51
53
  end
52
54
 
53
- # TODO: if user set sli_specification but we don't use it we should raise, but sadly we can't detect that easily
54
- if type == "time_slice"
55
- data[:sli_specification] = sli_specification
55
+ if (v = sli_specification)
56
+ data[:sli_specification] = v
56
57
  elsif (v = query)
57
58
  data[:query] = v
58
59
  end
@@ -102,10 +103,14 @@ module Kennel
102
103
  [:timeframe, :warning_threshold, :target_threshold].each { |k| actual.delete k }
103
104
  end
104
105
 
105
- # datadog always sets this, but we only set it for time_slice, so discard it for everything else to avoid diff
106
- if expected[:type] != "time_slice"
107
- actual.delete :sli_specification
108
- end
106
+ # discard deprecated query which stays in datadog forever when we are trying to set sli_specification
107
+ # (downgrading to query by setting sli_specification=nil is not supported in the api)
108
+ actual.delete :query if expected[:sli_specification]
109
+
110
+ # user set query so let's not worry about sli_specification even if this might be hiding bugs
111
+ # ideally we'd validate and tell the user that this will have no effect (see importer logic)
112
+ # but I'm not confident this will always be right
113
+ actual.delete :sli_specification if expected[:query]
109
114
 
110
115
  ignore_default(expected, actual, DEFAULTS)
111
116
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "2.20.0"
3
+ VERSION = "2.21.1"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kennel
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.20.0
4
+ version: 2.21.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Grosser