kennel 1.145.1 → 1.147.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 +4 -4
- data/lib/kennel/models/record.rb +1 -1
- data/lib/kennel/optional_validations.rb +1 -1
- data/lib/kennel/syncer/plan.rb +18 -0
- data/lib/kennel/syncer/{plan_displayer.rb → plan_printer.rb} +6 -6
- data/lib/kennel/syncer.rb +38 -50
- data/lib/kennel/template_variables.rb +2 -0
- data/lib/kennel/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7aa3215e281ade43456180bbdbe048939052d0238b1303705842cad7145b5457
|
|
4
|
+
data.tar.gz: ae9ec09767652ff2839da017731f7f7487e237cbea81d9cebb89f39351bd7cca
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0064bfa8723de2680d8a7dfd2d050018a040015efa8e57646039cbb825fb3278bbdf29ea8f60de4dc617d61b0ddc69bac4fa050fc125c10be413d1900eca7556
|
|
7
|
+
data.tar.gz: 5a1dc95851d870c5d00ab6d2b17c357572b44ab058ae87d486e6b4786797211fede1e6ef7dc935fc2e743f0ada6a942556f8222a4dc4b931047ffb7dbb07dc74
|
data/lib/kennel/models/record.rb
CHANGED
|
@@ -160,7 +160,7 @@ module Kennel
|
|
|
160
160
|
bad = Kennel::Utils.all_keys(data).grep_v(Symbol).sort.uniq
|
|
161
161
|
return if bad.empty?
|
|
162
162
|
invalid!(
|
|
163
|
-
|
|
163
|
+
OptionalValidations::UNIGNORABLE,
|
|
164
164
|
"Only use Symbols as hash keys to avoid permanent diffs when updating.\n" \
|
|
165
165
|
"Change these keys to be symbols (usually 'foo' => 1 --> 'foo': 1)\n" \
|
|
166
166
|
"#{bad.map(&:inspect).join("\n")}"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Kennel
|
|
3
|
+
class Syncer
|
|
4
|
+
Plan = Struct.new(:creates, :updates, :deletes) do
|
|
5
|
+
attr_writer :changes
|
|
6
|
+
|
|
7
|
+
def changes
|
|
8
|
+
@changes || (deletes + creates + updates).map(&:change) # roughly ordered in the way that update works
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def empty?
|
|
12
|
+
(creates + updates + deletes).empty?
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
Change = Struct.new(:type, :api_resource, :tracking_id, :id)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
module Kennel
|
|
4
4
|
class Syncer
|
|
5
|
-
class
|
|
5
|
+
class PlanPrinter
|
|
6
6
|
def initialize
|
|
7
7
|
@attribute_differ = AttributeDiffer.new
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
def
|
|
10
|
+
def print(plan)
|
|
11
11
|
Kennel.out.puts "Plan:"
|
|
12
|
-
if
|
|
12
|
+
if plan.empty?
|
|
13
13
|
Kennel.out.puts Console.color(:green, "Nothing to do")
|
|
14
14
|
else
|
|
15
|
-
print_changes "Create",
|
|
16
|
-
print_changes "Update",
|
|
17
|
-
print_changes "Delete",
|
|
15
|
+
print_changes "Create", plan.creates, :green
|
|
16
|
+
print_changes "Update", plan.updates, :yellow
|
|
17
|
+
print_changes "Delete", plan.deletes, :red
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
20
|
|
data/lib/kennel/syncer.rb
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "./syncer/matched_expected"
|
|
4
|
-
require_relative "./syncer/
|
|
4
|
+
require_relative "./syncer/plan"
|
|
5
|
+
require_relative "./syncer/plan_printer"
|
|
5
6
|
require_relative "./syncer/resolver"
|
|
6
7
|
require_relative "./syncer/types"
|
|
7
8
|
|
|
@@ -10,15 +11,7 @@ module Kennel
|
|
|
10
11
|
DELETE_ORDER = ["dashboard", "slo", "monitor", "synthetics/tests"].freeze # dashboards references monitors + slos, slos reference monitors
|
|
11
12
|
LINE_UP = "\e[1A\033[K" # go up and clear
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
InternalPlan = Struct.new(:creates, :updates, :deletes) do
|
|
16
|
-
def empty?
|
|
17
|
-
creates.empty? && updates.empty? && deletes.empty?
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
Change = Struct.new(:type, :api_resource, :tracking_id, :id)
|
|
14
|
+
attr_reader :plan
|
|
22
15
|
|
|
23
16
|
def initialize(api, expected, actual, filter:, strict_imports: true)
|
|
24
17
|
@api = api
|
|
@@ -26,27 +19,16 @@ module Kennel
|
|
|
26
19
|
@filter = filter
|
|
27
20
|
|
|
28
21
|
@resolver = Resolver.new(expected: expected, filter: filter)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
validate_changes(internal_plan)
|
|
32
|
-
@internal_plan = internal_plan
|
|
33
|
-
|
|
34
|
-
@warnings.each { |message| Kennel.out.puts Console.color(:yellow, "Warning: #{message}") }
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def plan
|
|
38
|
-
ip = @internal_plan
|
|
39
|
-
Plan.new(
|
|
40
|
-
changes: (ip.creates + ip.updates + ip.deletes).map(&:change)
|
|
41
|
-
)
|
|
22
|
+
@plan = Plan.new(*calculate_changes(expected: expected, actual: actual))
|
|
23
|
+
validate_changes
|
|
42
24
|
end
|
|
43
25
|
|
|
44
26
|
def print_plan
|
|
45
|
-
|
|
27
|
+
PlanPrinter.new.print(plan)
|
|
46
28
|
end
|
|
47
29
|
|
|
48
30
|
def confirm
|
|
49
|
-
return false if
|
|
31
|
+
return false if plan.empty?
|
|
50
32
|
return true if ENV["CI"] || !Kennel.in.tty? || !Kennel.err.tty?
|
|
51
33
|
Console.ask?("Execute Plan ?")
|
|
52
34
|
end
|
|
@@ -54,7 +36,7 @@ module Kennel
|
|
|
54
36
|
def update
|
|
55
37
|
changes = []
|
|
56
38
|
|
|
57
|
-
|
|
39
|
+
plan.deletes.each do |item|
|
|
58
40
|
message = "#{item.api_resource} #{item.tracking_id} #{item.id}"
|
|
59
41
|
Kennel.out.puts "Deleting #{message}"
|
|
60
42
|
@api.delete item.api_resource, item.id
|
|
@@ -62,34 +44,39 @@ module Kennel
|
|
|
62
44
|
Kennel.out.puts "#{LINE_UP}Deleted #{message}"
|
|
63
45
|
end
|
|
64
46
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
47
|
+
planned_actions = plan.creates + plan.updates
|
|
48
|
+
|
|
49
|
+
# slos need to be updated first in case their timeframes changed
|
|
50
|
+
# because datadog validates that update+create of slo alerts match an existing timeframe
|
|
51
|
+
planned_actions.sort_by! { |item| item.expected.is_a?(Models::Slo) ? 0 : 1 }
|
|
52
|
+
|
|
53
|
+
resolver.each_resolved(planned_actions) do |item|
|
|
54
|
+
if item.is_a?(Types::PlannedCreate)
|
|
55
|
+
message = "#{item.api_resource} #{item.tracking_id}"
|
|
56
|
+
Kennel.out.puts "Creating #{message}"
|
|
57
|
+
reply = @api.create item.api_resource, item.expected.as_json
|
|
58
|
+
id = reply.fetch(:id)
|
|
59
|
+
changes << item.change(id)
|
|
60
|
+
resolver.add_actual [reply] # allow resolving ids we could previously not resolve
|
|
61
|
+
Kennel.out.puts "#{LINE_UP}Created #{message} #{item.url(id)}"
|
|
62
|
+
else
|
|
63
|
+
message = "#{item.api_resource} #{item.tracking_id} #{item.url}"
|
|
64
|
+
Kennel.out.puts "Updating #{message}"
|
|
65
|
+
@api.update item.api_resource, item.id, item.expected.as_json
|
|
66
|
+
changes << item.change
|
|
67
|
+
Kennel.out.puts "#{LINE_UP}Updated #{message}"
|
|
68
|
+
end
|
|
81
69
|
end
|
|
82
70
|
|
|
83
|
-
|
|
71
|
+
plan.changes = changes
|
|
72
|
+
plan
|
|
84
73
|
end
|
|
85
74
|
|
|
86
75
|
private
|
|
87
76
|
|
|
88
|
-
attr_reader :filter, :resolver
|
|
77
|
+
attr_reader :filter, :resolver
|
|
89
78
|
|
|
90
79
|
def calculate_changes(expected:, actual:)
|
|
91
|
-
@warnings = []
|
|
92
|
-
|
|
93
80
|
Progress.progress "Diffing" do
|
|
94
81
|
resolver.add_actual actual
|
|
95
82
|
filter_actual! actual
|
|
@@ -123,7 +110,7 @@ module Kennel
|
|
|
123
110
|
deletes.sort_by! { |item| DELETE_ORDER.index item.api_resource }
|
|
124
111
|
updates.sort_by! { |item| DELETE_ORDER.index item.api_resource } # slo needs to come before slo alert
|
|
125
112
|
|
|
126
|
-
|
|
113
|
+
[creates, updates, deletes]
|
|
127
114
|
end
|
|
128
115
|
end
|
|
129
116
|
|
|
@@ -140,15 +127,16 @@ module Kennel
|
|
|
140
127
|
if @strict_imports
|
|
141
128
|
raise "Unable to find existing #{resource} with id #{id}\nIf the #{resource} was deleted, remove the `id: -> { #{id} }` line."
|
|
142
129
|
else
|
|
143
|
-
|
|
130
|
+
message = "Warning: #{resource} #{e.tracking_id} specifies id #{id}, but no such #{resource} exists. 'id' will be ignored. Remove the `id: -> { #{id} }` line."
|
|
131
|
+
Kennel.err.puts Console.color(:yellow, message)
|
|
144
132
|
end
|
|
145
133
|
end
|
|
146
134
|
end
|
|
147
135
|
|
|
148
136
|
# We've already validated the desired objects ('generated') in isolation.
|
|
149
137
|
# Now that we have made the plan, we can perform some more validation.
|
|
150
|
-
def validate_changes
|
|
151
|
-
|
|
138
|
+
def validate_changes
|
|
139
|
+
@plan.updates.each do |item|
|
|
152
140
|
item.expected.validate_update!(item.diff)
|
|
153
141
|
end
|
|
154
142
|
end
|
|
@@ -17,6 +17,8 @@ module Kennel
|
|
|
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
19
|
def validate_json(data)
|
|
20
|
+
super
|
|
21
|
+
|
|
20
22
|
variables = (data[:template_variables] || []).map { |v| "$#{v.fetch(:name)}" }
|
|
21
23
|
return if variables.empty?
|
|
22
24
|
|
data/lib/kennel/version.rb
CHANGED
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.147.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-
|
|
11
|
+
date: 2023-11-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: diff-lcs
|
|
@@ -113,7 +113,8 @@ files:
|
|
|
113
113
|
- lib/kennel/subclass_tracking.rb
|
|
114
114
|
- lib/kennel/syncer.rb
|
|
115
115
|
- lib/kennel/syncer/matched_expected.rb
|
|
116
|
-
- lib/kennel/syncer/
|
|
116
|
+
- lib/kennel/syncer/plan.rb
|
|
117
|
+
- lib/kennel/syncer/plan_printer.rb
|
|
117
118
|
- lib/kennel/syncer/resolver.rb
|
|
118
119
|
- lib/kennel/syncer/types.rb
|
|
119
120
|
- lib/kennel/tags_validation.rb
|