kennel 1.122.0 → 1.123.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: 43b746ea91f86217a6fc43383a3368ccd654c89936c44003088054380be8c36d
4
- data.tar.gz: 5fcd75471c8d0152236d032b023b4769975251047bc276f00219df3b1e60964d
3
+ metadata.gz: f09678f23d63da04d4b5db81eaef471bc0aa437b62ac75082f7bd161f8cd38e4
4
+ data.tar.gz: a570cc2617295581459a5977727049c243d492312554496f0b1beb432ad8efe8
5
5
  SHA512:
6
- metadata.gz: e9ce639cdd5748f689eeb352da8ea9c14a2a4243350368574b8b3c1b52534dbf470ca3e969ad96ecd685d8df93d368e7e4d5f5c98da2af7e5cc843ccbc8053ce
7
- data.tar.gz: 7039072c9129311145694b53823cab5c11263e972ae8f6c586e0b86063a8ab9d375c2ecd1069bd2812f626ce631f2940fe55ca9a018033b435df63bcbef1d355
6
+ metadata.gz: 560a1daae6cb797b0e53e06a694e5624667b5597d3d6fb5c783e0166154a8f594064d7bfc1f64fb541723e2b633130d4e8039a8caa3434145552a63114a88678
7
+ data.tar.gz: '091c93ee61b87146c69e6f8782aab7a3cf2c349a03936f686a099eaca1a96d762193ee8385220fcc9d8c694edacf89aa57c6751e6e8a17bcffb37b1f913f9591'
@@ -15,11 +15,13 @@ module Kennel
15
15
  end
16
16
 
17
17
  def open
18
- load_data
19
- expire_old_data
20
- yield self
21
- ensure
22
- persist
18
+ @data = load_data || {}
19
+ begin
20
+ expire_old_data
21
+ yield self
22
+ ensure
23
+ persist
24
+ end
23
25
  end
24
26
 
25
27
  def fetch(key, key_version)
@@ -35,12 +37,9 @@ module Kennel
35
37
  private
36
38
 
37
39
  def load_data
38
- @data =
39
- begin
40
- Marshal.load(File.read(@file)) # rubocop:disable Security/MarshalLoad
41
- rescue StandardError
42
- {}
43
- end
40
+ Marshal.load(File.read(@file)) # rubocop:disable Security/MarshalLoad
41
+ rescue Errno::ENOENT, TypeError, ArgumentError
42
+ nil
44
43
  end
45
44
 
46
45
  def persist
@@ -49,6 +48,7 @@ module Kennel
49
48
 
50
49
  Tempfile.create "kennel-file-cache", dir do |tmp|
51
50
  Marshal.dump @data, tmp
51
+ tmp.flush
52
52
  File.rename tmp.path, @file
53
53
  end
54
54
  end
@@ -38,6 +38,8 @@ module Kennel
38
38
 
39
39
  case resource
40
40
  when "monitor"
41
+ raise "Import the synthetic test page and not the monitor" if data[:type] == "synthetics alert"
42
+
41
43
  # flatten monitor options so they are all on the base which is how Monitor builds them
42
44
  data.merge!(data.delete(:options))
43
45
  data.merge!(data.delete(:thresholds) || {})
@@ -3,7 +3,6 @@ module Kennel
3
3
  module Models
4
4
  class Dashboard < Record
5
5
  include TemplateVariables
6
- include OptionalValidations
7
6
 
8
7
  READONLY_ATTRIBUTES = superclass::READONLY_ATTRIBUTES + [
9
8
  :author_handle, :author_name, :modified_at, :deleted_at, :url, :is_read_only, :notify_list, :restricted_roles
@@ -87,8 +86,7 @@ module Kennel
87
86
  tags: -> do # not inherited by default to make onboarding to using dashboard tags simple
88
87
  team = project.team
89
88
  team.tag_dashboards ? team.tags : []
90
- end,
91
- id: -> { nil }
89
+ end
92
90
  )
93
91
 
94
92
  class << self
@@ -152,29 +150,24 @@ module Kennel
152
150
  end
153
151
  end
154
152
 
155
- def as_json
156
- return @json if @json
153
+ def build_json
157
154
  all_widgets = render_definitions(definitions) + widgets
158
155
  expand_q all_widgets
159
156
  tags = tags()
160
157
  tags_as_string = (tags.empty? ? "" : " (#{tags.join(" ")})")
161
158
 
162
- @json = {
159
+ json = super.merge(
163
160
  layout_type: layout_type,
164
161
  title: "#{title}#{tags_as_string}#{LOCK}",
165
162
  description: description,
166
163
  template_variables: render_template_variables,
167
164
  template_variable_presets: template_variable_presets,
168
165
  widgets: all_widgets
169
- }
170
-
171
- @json[:reflow_type] = reflow_type if reflow_type # setting nil breaks create with "ordered"
166
+ )
172
167
 
173
- @json[:id] = id if id
168
+ json[:reflow_type] = reflow_type if reflow_type # setting nil breaks create with "ordered"
174
169
 
175
- validate_json(@json) if validate
176
-
177
- @json
170
+ json
178
171
  end
179
172
 
180
173
  def self.url(id)
@@ -210,9 +203,8 @@ module Kennel
210
203
  end
211
204
 
212
205
  def validate_update!(_actuals, diffs)
213
- if bad_diff = diffs.find { |diff| diff[1] == "layout_type" }
214
- invalid! "Datadog does not allow update of #{bad_diff[1]} (#{bad_diff[2].inspect} -> #{bad_diff[3].inspect})"
215
- end
206
+ _, path, from, to = diffs.find { |diff| diff[1] == "layout_type" }
207
+ invalid_update!(path, from, to) if path
216
208
  end
217
209
 
218
210
  private
@@ -2,8 +2,6 @@
2
2
  module Kennel
3
3
  module Models
4
4
  class Monitor < Record
5
- include OptionalValidations
6
-
7
5
  RENOTIFY_INTERVALS = [0, 10, 20, 30, 40, 50, 60, 90, 120, 180, 240, 300, 360, 720, 1440].freeze # minutes
8
6
  OPTIONAL_SERVICE_CHECK_THRESHOLDS = [:ok, :warning].freeze
9
7
  READONLY_ATTRIBUTES = superclass::READONLY_ATTRIBUTES + [
@@ -41,7 +39,6 @@ module Kennel
41
39
  renotify_interval: -> { project.team.renotify_interval },
42
40
  warning: -> { nil },
43
41
  ok: -> { nil },
44
- id: -> { nil },
45
42
  notify_no_data: -> { true }, # datadog sets this to false by default, but true is the safer
46
43
  no_data_timeframe: -> { 60 },
47
44
  notify_audit: -> { MONITOR_OPTION_DEFAULTS.fetch(:notify_audit) },
@@ -56,9 +53,8 @@ module Kennel
56
53
  priority: -> { MONITOR_DEFAULTS.fetch(:priority) }
57
54
  )
58
55
 
59
- def as_json
60
- return @as_json if @as_json
61
- data = {
56
+ def build_json
57
+ data = super.merge(
62
58
  name: "#{name}#{LOCK}",
63
59
  type: type,
64
60
  query: query.strip,
@@ -79,9 +75,7 @@ module Kennel
79
75
  locked: false, # setting this to true prevents any edit and breaks updates when using replace workflow
80
76
  renotify_interval: renotify_interval || 0
81
77
  }
82
- }
83
-
84
- data[:id] = id if id
78
+ )
85
79
 
86
80
  options = data[:options]
87
81
  if data.fetch(:type) != "composite"
@@ -120,9 +114,7 @@ module Kennel
120
114
  options[:renotify_statuses] = statuses
121
115
  end
122
116
 
123
- validate_json(data) if validate
124
-
125
- @as_json = data
117
+ data
126
118
  end
127
119
 
128
120
  def resolve_linked_tracking_ids!(id_map, **args)
@@ -140,7 +132,7 @@ module Kennel
140
132
  # ensure type does not change, but not if it's metric->query which is supported and used by importer.rb
141
133
  _, path, from, to = diffs.detect { |_, path, _, _| path == "type" }
142
134
  if path && !(from == "metric alert" && to == "query alert")
143
- invalid! "Datadog does not allow update of #{path} (#{from.inspect} -> #{to.inspect})"
135
+ invalid_update!(path, from, to)
144
136
  end
145
137
  end
146
138
 
@@ -20,7 +20,7 @@ module Kennel
20
20
  def validated_parts
21
21
  all = parts
22
22
  unless all.is_a?(Array) && all.all? { |part| part.is_a?(Record) }
23
- invalid! "#parts must return an array of Records"
23
+ raise "Project #{kennel_id} #parts must return an array of Records"
24
24
  end
25
25
 
26
26
  validate_parts(all)
@@ -29,11 +29,6 @@ module Kennel
29
29
 
30
30
  private
31
31
 
32
- # let users know which project/resource failed when something happens during diffing where the backtrace is hidden
33
- def invalid!(message)
34
- raise ValidationError, "#{kennel_id} #{message}"
35
- end
36
-
37
32
  # hook for users to add custom validations via `prepend`
38
33
  def validate_parts(parts)
39
34
  end
@@ -2,6 +2,8 @@
2
2
  module Kennel
3
3
  module Models
4
4
  class Record < Base
5
+ include OptionalValidations
6
+
5
7
  # Apart from if you just don't like the default for some reason,
6
8
  # overriding MARKER_TEXT allows for namespacing within the same
7
9
  # Datadog account. If you run one Kennel setup with marker text
@@ -30,6 +32,8 @@ module Kennel
30
32
 
31
33
  settings :id, :kennel_id
32
34
 
35
+ defaults(id: nil)
36
+
33
37
  class << self
34
38
  def parse_any_url(url)
35
39
  subclasses.detect do |s|
@@ -96,7 +100,7 @@ module Kennel
96
100
  @tracking_id ||= begin
97
101
  id = "#{project.kennel_id}:#{kennel_id}"
98
102
  unless id.match?(ALLOWED_KENNEL_ID_REGEX) # <-> parse_tracking_id
99
- raise ValidationError, "#{id} must match #{ALLOWED_KENNEL_ID_REGEX}"
103
+ raise "#{id} must match #{ALLOWED_KENNEL_ID_REGEX}"
100
104
  end
101
105
  id
102
106
  end
@@ -108,7 +112,7 @@ module Kennel
108
112
  def add_tracking_id
109
113
  json = as_json
110
114
  if self.class.parse_tracking_id(json)
111
- invalid! "remove \"-- #{MARKER_TEXT}\" line it from #{self.class::TRACKING_FIELD} to copy a resource"
115
+ raise "#{tracking_id} Remove \"-- #{MARKER_TEXT}\" line from #{self.class::TRACKING_FIELD} to copy a resource"
112
116
  end
113
117
  json[self.class::TRACKING_FIELD] =
114
118
  "#{json[self.class::TRACKING_FIELD]}\n" \
@@ -119,9 +123,29 @@ module Kennel
119
123
  self.class.remove_tracking_id(as_json)
120
124
  end
121
125
 
126
+ def build_json
127
+ {
128
+ id: id
129
+ }.compact
130
+ end
131
+
132
+ def as_json
133
+ @as_json ||= begin
134
+ json = build_json
135
+ (id = json.delete(:id)) && json[:id] = id
136
+ validate_json(json) if validate
137
+ json
138
+ end
139
+ end
140
+
141
+ # Can raise DisallowedUpdateError
122
142
  def validate_update!(*)
123
143
  end
124
144
 
145
+ def invalid_update!(field, old_value, new_value)
146
+ raise DisallowedUpdateError, "#{tracking_id} Datadog does not allow update of #{field} (#{old_value.inspect} -> #{new_value.inspect})"
147
+ end
148
+
125
149
  private
126
150
 
127
151
  def resolve(value, type, id_map, force:)
@@ -133,20 +157,24 @@ module Kennel
133
157
  id.is_a?(String) && id.include?(":")
134
158
  end
135
159
 
136
- def resolve_link(tracking_id, type, id_map, force:)
137
- if id_map.new?(type.to_s, tracking_id)
160
+ def resolve_link(sought_tracking_id, sought_type, id_map, force:)
161
+ if id_map.new?(sought_type.to_s, sought_tracking_id)
138
162
  if force
139
- invalid!(
140
- "#{type} #{tracking_id} was referenced but is also created by the current run.\n" \
141
- "It could not be created because of a circular dependency, try creating only some of the resources"
142
- )
163
+ raise UnresolvableIdError, <<~MESSAGE
164
+ #{tracking_id} #{sought_type} #{sought_tracking_id} was referenced but is also created by the current run.
165
+ It could not be created because of a circular dependency. Try creating only some of the resources.
166
+ MESSAGE
143
167
  else
144
168
  nil # will be re-resolved after the linked object was created
145
169
  end
146
- elsif id = id_map.get(type.to_s, tracking_id)
170
+ elsif id = id_map.get(sought_type.to_s, sought_tracking_id)
147
171
  id
148
172
  else
149
- invalid! "Unable to find #{type} #{tracking_id} (does not exist and is not being created by the current run)"
173
+ raise UnresolvableIdError, <<~MESSAGE
174
+ #{tracking_id} Unable to find #{sought_type} #{sought_tracking_id}
175
+ This is either because it doesn't exist, and isn't being created by the current run;
176
+ or it does exist, but is being deleted.
177
+ MESSAGE
150
178
  end
151
179
  end
152
180
 
@@ -15,7 +15,6 @@ module Kennel
15
15
  settings :type, :description, :thresholds, :query, :tags, :monitor_ids, :monitor_tags, :name, :groups
16
16
 
17
17
  defaults(
18
- id: -> { nil },
19
18
  tags: -> { @project.tags },
20
19
  query: -> { DEFAULTS.fetch(:query) },
21
20
  description: -> { DEFAULTS.fetch(:description) },
@@ -24,35 +23,25 @@ module Kennel
24
23
  groups: -> { DEFAULTS.fetch(:groups) }
25
24
  )
26
25
 
27
- def initialize(*)
28
- super
29
- if thresholds.any? { |t| t[:warning] && t[:warning].to_f <= t[:critical].to_f }
30
- raise ValidationError, "Threshold warning must be greater-than critical value"
31
- end
32
- end
33
-
34
- def as_json
35
- return @as_json if @as_json
36
- data = {
26
+ def build_json
27
+ data = super.merge(
37
28
  name: "#{name}#{LOCK}",
38
29
  description: description,
39
30
  thresholds: thresholds,
40
31
  monitor_ids: monitor_ids,
41
32
  tags: tags.uniq,
42
33
  type: type
43
- }
34
+ )
44
35
 
45
36
  if v = query
46
37
  data[:query] = v
47
38
  end
48
- if v = id
49
- data[:id] = v
50
- end
39
+
51
40
  if v = groups
52
41
  data[:groups] = v
53
42
  end
54
43
 
55
- @as_json = data
44
+ data
56
45
  end
57
46
 
58
47
  def self.api_resource
@@ -89,6 +78,16 @@ module Kennel
89
78
 
90
79
  ignore_default(expected, actual, DEFAULTS)
91
80
  end
81
+
82
+ private
83
+
84
+ def validate_json(data)
85
+ super
86
+
87
+ if data[:thresholds].any? { |t| t[:warning] && t[:warning].to_f <= t[:critical].to_f }
88
+ invalid! "Threshold warning must be greater-than critical value"
89
+ end
90
+ end
92
91
  end
93
92
  end
94
93
  end
@@ -11,15 +11,14 @@ module Kennel
11
11
  settings :tags, :config, :message, :subtype, :type, :name, :locations, :options
12
12
 
13
13
  defaults(
14
- id: -> { nil },
15
14
  tags: -> { @project.tags },
16
15
  message: -> { "\n\n#{project.mention}" }
17
16
  )
18
17
 
19
- def as_json
20
- return @as_json if @as_json
18
+ def build_json
21
19
  locations = locations()
22
- data = {
20
+
21
+ super.merge(
23
22
  message: message,
24
23
  tags: tags,
25
24
  config: config,
@@ -28,13 +27,7 @@ module Kennel
28
27
  options: options,
29
28
  name: "#{name}#{LOCK}",
30
29
  locations: locations == :all ? LOCATIONS : locations
31
- }
32
-
33
- if v = id
34
- data[:id] = v
35
- end
36
-
37
- @as_json = data
30
+ )
38
31
  end
39
32
 
40
33
  def self.api_resource
data/lib/kennel/syncer.rb CHANGED
@@ -104,11 +104,11 @@ module Kennel
104
104
  def resolved?(e)
105
105
  assert_resolved e
106
106
  true
107
- rescue ValidationError
107
+ rescue UnresolvableIdError
108
108
  false
109
109
  end
110
110
 
111
- # raises ValidationError when not resolved
111
+ # raises UnresolvableIdError when not resolved
112
112
  def assert_resolved(e)
113
113
  resolve_linked_tracking_ids! [e], force: true
114
114
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "1.122.0"
3
+ VERSION = "1.123.0"
4
4
  end
data/lib/kennel.rb CHANGED
@@ -40,8 +40,9 @@ module Teams
40
40
  end
41
41
 
42
42
  module Kennel
43
- class ValidationError < RuntimeError
44
- end
43
+ ValidationError = Class.new(RuntimeError)
44
+ UnresolvableIdError = Class.new(RuntimeError)
45
+ DisallowedUpdateError = Class.new(RuntimeError)
45
46
 
46
47
  include Kennel::Compatibility
47
48
 
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.122.0
4
+ version: 1.123.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: 2022-10-13 00:00:00.000000000 Z
11
+ date: 2022-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs