kennel 1.138.1 → 1.140.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/kennel/models/dashboard.rb +2 -3
- data/lib/kennel/models/monitor.rb +3 -1
- data/lib/kennel/models/record.rb +17 -38
- data/lib/kennel/models/slo.rb +10 -1
- data/lib/kennel/models/synthetic_test.rb +2 -0
- data/lib/kennel/optional_validations.rb +52 -43
- data/lib/kennel/tags_validation.rb +15 -0
- data/lib/kennel/template_variables.rb +1 -1
- data/lib/kennel/version.rb +1 -1
- data/lib/kennel.rb +2 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8a15178bd108647314171a012bafa0c977f998a8488418c0d323de095e0a1b3
|
4
|
+
data.tar.gz: 1673aec908b72090afa31e0b3dd8a923dbf505c01ab2f5dfd6211846edab4f7d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0343af2d0a40081a7fd8ffe5bb9932344f75ef91f1b688f4b6e4eb72a0bd5f59c9b67cf72f498bb008f76aae7f6df645b0bcd8258b5c1c892cb8cd3ef21cc468
|
7
|
+
data.tar.gz: 3a1f1df7f6195ec235713dc173e8c869013654355432159e1bd1e59dd29ea3d849407ee9cf43f31453411a54224ae1ea8b80bc1e01e209176d0cfe28f8fc2bc3
|
@@ -3,6 +3,7 @@ module Kennel
|
|
3
3
|
module Models
|
4
4
|
class Dashboard < Record
|
5
5
|
include TemplateVariables
|
6
|
+
include TagsValidation
|
6
7
|
|
7
8
|
READONLY_ATTRIBUTES = superclass::READONLY_ATTRIBUTES + [
|
8
9
|
:author_handle, :author_name, :modified_at, :deleted_at, :url, :is_read_only, :notify_list, :restricted_roles
|
@@ -158,7 +159,7 @@ module Kennel
|
|
158
159
|
template_variables: render_template_variables,
|
159
160
|
template_variable_presets: template_variable_presets,
|
160
161
|
widgets: all_widgets,
|
161
|
-
tags: tags.grep(TAG_PREFIX)
|
162
|
+
tags: tags.grep(TAG_PREFIX)
|
162
163
|
)
|
163
164
|
|
164
165
|
json[:reflow_type] = reflow_type if reflow_type # setting nil breaks create with "ordered"
|
@@ -222,8 +223,6 @@ module Kennel
|
|
222
223
|
def validate_json(data)
|
223
224
|
super
|
224
225
|
|
225
|
-
validate_template_variables data
|
226
|
-
|
227
226
|
# Avoid diff from datadog presets sorting.
|
228
227
|
presets = data[:template_variable_presets]
|
229
228
|
if presets && presets != presets.sort_by { |p| p[:name] }
|
@@ -2,6 +2,8 @@
|
|
2
2
|
module Kennel
|
3
3
|
module Models
|
4
4
|
class Monitor < Record
|
5
|
+
include TagsValidation
|
6
|
+
|
5
7
|
RENOTIFY_INTERVALS = [0, 10, 20, 30, 40, 50, 60, 90, 120, 180, 240, 300, 360, 720, 1440].freeze # minutes
|
6
8
|
OPTIONAL_SERVICE_CHECK_THRESHOLDS = [:ok, :warning].freeze
|
7
9
|
READONLY_ATTRIBUTES = superclass::READONLY_ATTRIBUTES + [
|
@@ -67,7 +69,7 @@ module Kennel
|
|
67
69
|
type: type,
|
68
70
|
query: query.strip,
|
69
71
|
message: message.strip,
|
70
|
-
tags: tags
|
72
|
+
tags: tags,
|
71
73
|
priority: priority,
|
72
74
|
options: {
|
73
75
|
timeout_h: timeout_h,
|
data/lib/kennel/models/record.rb
CHANGED
@@ -2,14 +2,6 @@
|
|
2
2
|
module Kennel
|
3
3
|
module Models
|
4
4
|
class Record < Base
|
5
|
-
class PrepareError < StandardError
|
6
|
-
def initialize(tracking_id)
|
7
|
-
super("Error while preparing #{tracking_id}")
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
UnvalidatedRecordError = Class.new(StandardError)
|
12
|
-
|
13
5
|
include OptionalValidations
|
14
6
|
|
15
7
|
# Apart from if you just don't like the default for some reason,
|
@@ -85,12 +77,12 @@ module Kennel
|
|
85
77
|
end
|
86
78
|
end
|
87
79
|
|
88
|
-
attr_reader :project, :
|
80
|
+
attr_reader :project, :as_json
|
89
81
|
|
90
|
-
def initialize(project,
|
82
|
+
def initialize(project, ...)
|
91
83
|
raise ArgumentError, "First argument must be a project, not #{project.class}" unless project.is_a?(Project)
|
92
84
|
@project = project
|
93
|
-
super(
|
85
|
+
super(...)
|
94
86
|
end
|
95
87
|
|
96
88
|
def diff(actual)
|
@@ -141,29 +133,9 @@ module Kennel
|
|
141
133
|
end
|
142
134
|
|
143
135
|
def build
|
144
|
-
@
|
145
|
-
|
146
|
-
|
147
|
-
begin
|
148
|
-
json = build_json
|
149
|
-
(id = json.delete(:id)) && json[:id] = id
|
150
|
-
validate_json(json)
|
151
|
-
rescue StandardError
|
152
|
-
if unfiltered_validation_errors.empty?
|
153
|
-
@unfiltered_validation_errors = nil
|
154
|
-
raise PrepareError, safe_tracking_id # FIXME: this makes errors hard to debug when running tests
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
@filtered_validation_errors = filter_validation_errors
|
159
|
-
@as_json = json # Only valid if filtered_validation_errors.empty?
|
160
|
-
end
|
161
|
-
|
162
|
-
def as_json
|
163
|
-
# A courtesy to those tests that still expect as_json to perform validation and raise on error
|
164
|
-
build if @unfiltered_validation_errors.nil?
|
165
|
-
raise UnvalidatedRecordError, "#{safe_tracking_id} as_json called on invalid part" unless filtered_validation_errors.empty?
|
166
|
-
|
136
|
+
@as_json = build_json
|
137
|
+
(id = @as_json.delete(:id)) && @as_json[:id] = id
|
138
|
+
validate_json(@as_json)
|
167
139
|
@as_json
|
168
140
|
end
|
169
141
|
|
@@ -184,6 +156,17 @@ module Kennel
|
|
184
156
|
|
185
157
|
private
|
186
158
|
|
159
|
+
def validate_json(data)
|
160
|
+
bad = Kennel::Utils.all_keys(data).grep_v(Symbol).sort.uniq
|
161
|
+
return if bad.empty?
|
162
|
+
invalid!(
|
163
|
+
:hash_keys_must_be_symbols,
|
164
|
+
"Only use Symbols as hash keys to avoid permanent diffs when updating.\n" \
|
165
|
+
"Change these keys to be symbols (usually 'foo' => 1 --> 'foo': 1)\n" \
|
166
|
+
"#{bad.map(&:inspect).join("\n")}"
|
167
|
+
)
|
168
|
+
end
|
169
|
+
|
187
170
|
def resolve(value, type, id_map, force:)
|
188
171
|
return value unless tracking_id?(value)
|
189
172
|
resolve_link(value, type, id_map, force: force)
|
@@ -214,10 +197,6 @@ module Kennel
|
|
214
197
|
end
|
215
198
|
end
|
216
199
|
|
217
|
-
def invalid!(tag, message)
|
218
|
-
unfiltered_validation_errors << ValidationMessage.new(tag || OptionalValidations::UNIGNORABLE, message)
|
219
|
-
end
|
220
|
-
|
221
200
|
def raise_with_location(error, message)
|
222
201
|
super error, "#{message} for project #{project.kennel_id}"
|
223
202
|
end
|
data/lib/kennel/models/slo.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
module Kennel
|
3
3
|
module Models
|
4
4
|
class Slo < Record
|
5
|
+
include TagsValidation
|
6
|
+
|
5
7
|
READONLY_ATTRIBUTES = superclass::READONLY_ATTRIBUTES + [:type_id, :monitor_tags, :target_threshold, :timeframe, :warning_threshold]
|
6
8
|
TRACKING_FIELD = :description
|
7
9
|
DEFAULTS = {
|
@@ -29,7 +31,7 @@ module Kennel
|
|
29
31
|
description: description,
|
30
32
|
thresholds: thresholds,
|
31
33
|
monitor_ids: monitor_ids,
|
32
|
-
tags: tags
|
34
|
+
tags: tags,
|
33
35
|
type: type
|
34
36
|
)
|
35
37
|
|
@@ -84,6 +86,13 @@ module Kennel
|
|
84
86
|
def validate_json(data)
|
85
87
|
super
|
86
88
|
|
89
|
+
# datadog does not allow uppercase tags for slos
|
90
|
+
bad_tags = data[:tags].grep(/[A-Z]/)
|
91
|
+
if bad_tags.any?
|
92
|
+
invalid! :tags_are_upper_case, "Tags must not be upper case (bad tags: #{bad_tags.sort.inspect})"
|
93
|
+
end
|
94
|
+
|
95
|
+
# warning must be <= critical
|
87
96
|
if data[:thresholds].any? { |t| t[:warning] && t[:warning].to_f <= t[:critical].to_f }
|
88
97
|
invalid! :warning_must_be_gt_critical, "Threshold warning must be greater-than critical value"
|
89
98
|
end
|
@@ -4,80 +4,89 @@ module Kennel
|
|
4
4
|
ValidationMessage = Struct.new(:tag, :text)
|
5
5
|
|
6
6
|
UNIGNORABLE = :unignorable
|
7
|
+
UNUSED_IGNORES = :unused_ignores
|
7
8
|
|
8
9
|
def self.included(base)
|
9
10
|
base.settings :ignored_errors
|
10
11
|
base.defaults(ignored_errors: -> { [] })
|
12
|
+
base.attr_reader :validation_errors
|
11
13
|
end
|
12
14
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
def initialize(...)
|
16
|
+
super
|
17
|
+
@validation_errors = []
|
18
|
+
end
|
17
19
|
|
18
|
-
|
20
|
+
def invalid!(tag, message)
|
21
|
+
validation_errors << ValidationMessage.new(tag || OptionalValidations::UNIGNORABLE, message)
|
22
|
+
end
|
19
23
|
|
20
|
-
|
24
|
+
def self.valid?(parts)
|
25
|
+
parts_with_errors = parts.map { |p| [p, filter_validation_errors(p)] }
|
26
|
+
return true if parts_with_errors.all? { |_, errors| errors.empty? }
|
21
27
|
|
28
|
+
# print errors in order
|
29
|
+
example_tag = nil
|
22
30
|
Kennel.err.puts
|
23
|
-
parts_with_errors.sort_by
|
24
|
-
|
31
|
+
parts_with_errors.sort_by! { |p, _| p.safe_tracking_id }
|
32
|
+
parts_with_errors.each do |part, errors|
|
33
|
+
errors.each do |err|
|
25
34
|
Kennel.err.puts "#{part.safe_tracking_id} [#{err.tag.inspect}] #{err.text.gsub("\n", " ")}"
|
26
35
|
example_tag = err.tag unless err.tag == :unignorable
|
27
36
|
end
|
28
37
|
end
|
29
38
|
Kennel.err.puts
|
30
39
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
40
|
+
if example_tag
|
41
|
+
Kennel.err.puts <<~MESSAGE
|
42
|
+
If a particular error cannot be fixed, it can be marked as ignored via `ignored_errors`, e.g.:
|
43
|
+
Kennel::Models::Monitor.new(
|
44
|
+
...,
|
45
|
+
ignored_errors: [#{example_tag.inspect}]
|
46
|
+
)
|
37
47
|
|
38
|
-
|
48
|
+
MESSAGE
|
49
|
+
end
|
39
50
|
|
40
51
|
false
|
41
52
|
end
|
42
53
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
bad = Kennel::Utils.all_keys(data).grep_v(Symbol).sort.uniq
|
47
|
-
return if bad.empty?
|
48
|
-
invalid!(
|
49
|
-
:hash_keys_must_be_symbols,
|
50
|
-
"Only use Symbols as hash keys to avoid permanent diffs when updating.\n" \
|
51
|
-
"Change these keys to be symbols (usually 'foo' => 1 --> 'foo': 1)\n" \
|
52
|
-
"#{bad.map(&:inspect).join("\n")}"
|
53
|
-
)
|
54
|
-
end
|
54
|
+
def self.filter_validation_errors(part)
|
55
|
+
errors = part.validation_errors
|
56
|
+
ignored_tags = part.ignored_errors
|
55
57
|
|
56
|
-
|
57
|
-
|
58
|
-
if ignored_errors.empty?
|
58
|
+
if errors.empty? # 95% case, so keep it fast
|
59
|
+
if ignored_tags.empty? || ignored_tags.include?(UNUSED_IGNORES)
|
59
60
|
[]
|
60
61
|
else
|
61
|
-
|
62
|
+
# tell users to remove the whole line and not just an element
|
63
|
+
[
|
64
|
+
ValidationMessage.new(
|
65
|
+
UNUSED_IGNORES,
|
66
|
+
"`ignored_errors` is non-empty, but there are no errors to ignore. Remove `ignored_errors`"
|
67
|
+
)
|
68
|
+
]
|
62
69
|
end
|
63
70
|
else
|
64
|
-
|
65
|
-
if ENV["NO_IGNORED_ERRORS"]
|
66
|
-
|
67
|
-
unfiltered_validation_errors
|
71
|
+
reported_errors =
|
72
|
+
if ENV["NO_IGNORED_ERRORS"] # let users see what errors are suppressed
|
73
|
+
errors
|
68
74
|
else
|
69
|
-
|
70
|
-
err.tag != UNIGNORABLE && ignored_errors.include?(err.tag)
|
71
|
-
end
|
75
|
+
errors.select { |err| err.tag == UNIGNORABLE || !ignored_tags.include?(err.tag) }
|
72
76
|
end
|
73
77
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
+
# let users know when they can remove an ignore ... unless they don't care (for example for a generic monitor)
|
79
|
+
unless ignored_tags.include?(UNUSED_IGNORES)
|
80
|
+
unused_ignored_tags = ignored_tags - errors.map(&:tag)
|
81
|
+
if unused_ignored_tags.any?
|
82
|
+
reported_errors << ValidationMessage.new(
|
83
|
+
UNUSED_IGNORES,
|
84
|
+
"Unused ignores #{unused_ignored_tags.map(&:inspect).sort.uniq.join(" ")}. Remove these from `ignored_errors`"
|
85
|
+
)
|
86
|
+
end
|
78
87
|
end
|
79
88
|
|
80
|
-
|
89
|
+
reported_errors
|
81
90
|
end
|
82
91
|
end
|
83
92
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Kennel
|
3
|
+
module TagsValidation
|
4
|
+
def validate_json(data)
|
5
|
+
super
|
6
|
+
|
7
|
+
# ideally we'd avoid duplicated tags, but that happens regularly when importing existing monitors
|
8
|
+
data[:tags] = data[:tags].uniq
|
9
|
+
|
10
|
+
# keep tags clean (TODO: reduce this list)
|
11
|
+
bad_tags = data[:tags].grep(/[^A-Za-z:_0-9.\/*@!#-]/)
|
12
|
+
invalid! :tags_invalid, "Only use A-Za-z:_0-9./*@!#- in tags (bad tags: #{bad_tags.sort.inspect})" if bad_tags.any?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -16,7 +16,7 @@ module Kennel
|
|
16
16
|
|
17
17
|
# check for queries that do not use the variables and would be misleading
|
18
18
|
# TODO: do the same check for apm_query and their group_by
|
19
|
-
def
|
19
|
+
def validate_json(data)
|
20
20
|
variables = (data[:template_variables] || []).map { |v| "$#{v.fetch(:name)}" }
|
21
21
|
return if variables.empty?
|
22
22
|
|
data/lib/kennel/version.rb
CHANGED
data/lib/kennel.rb
CHANGED
@@ -13,6 +13,7 @@ require "kennel/filter"
|
|
13
13
|
require "kennel/parts_serializer"
|
14
14
|
require "kennel/projects_provider"
|
15
15
|
require "kennel/attribute_differ"
|
16
|
+
require "kennel/tags_validation"
|
16
17
|
require "kennel/syncer"
|
17
18
|
require "kennel/id_map"
|
18
19
|
require "kennel/api"
|
@@ -126,7 +127,7 @@ module Kennel
|
|
126
127
|
Utils.parallel(parts, &:build)
|
127
128
|
end
|
128
129
|
|
129
|
-
OptionalValidations.valid?(parts)
|
130
|
+
OptionalValidations.valid?(parts) || raise(GenerationAbortedError)
|
130
131
|
|
131
132
|
parts
|
132
133
|
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.
|
4
|
+
version: 1.140.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: 2023-05-
|
11
|
+
date: 2023-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: diff-lcs
|
@@ -116,6 +116,7 @@ files:
|
|
116
116
|
- lib/kennel/syncer/plan_displayer.rb
|
117
117
|
- lib/kennel/syncer/resolver.rb
|
118
118
|
- lib/kennel/syncer/types.rb
|
119
|
+
- lib/kennel/tags_validation.rb
|
119
120
|
- lib/kennel/tasks.rb
|
120
121
|
- lib/kennel/template_variables.rb
|
121
122
|
- lib/kennel/unmuted_alerts.rb
|