kennel 1.39.0 → 1.40.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ff03815a21fb7a0850ac598043a687268e63b596d33d4b3a741c75f5b11fe87
4
- data.tar.gz: 2570ed375f81545c1eb4b251e2f35f3abbfc4c7779191917f5ba87dae65ad7d7
3
+ metadata.gz: 48d299703094c1309aec2c1e902a6c0e8a37174395a9fccd233cf72f3b75b255
4
+ data.tar.gz: 72f45df5f14f29c97f4a906d6f59cc9a70acc26040fed0a36520e8c675dbacb0
5
5
  SHA512:
6
- metadata.gz: 01a572db1d8b0313833197af3dbb3c86226b0b9903d8593beb237868ee7c9d9ceeb62c69cbd9ea4d77257c08a89758f21b63439a78c9bd5044a31ad0c2d2a901
7
- data.tar.gz: 61c71ec73f73fa2a81415a2167eb97f1638692d3e1e91ae9c910a741a1d3bd9e8685ba5eb92c7971a8c15647f41d8746312bd370532d48d73ece8ed848b07c2b
6
+ metadata.gz: ef6beaa1c5ffa0c2b1c6d534e1fd30cd3276d29bf1a16074e06f1499b76466b187c0694e5bc50ca9c9e8bb814cccfec05f477bee16b15b34067df3c78c83d2d3
7
+ data.tar.gz: eeabb869d2528613cbb1d18b92fe603404c160fc88212b76f97a02d4a77e8262b930fde867ae3fb33e13c0ce330b8998d5494ee233655b294b37461d6e10e5f3
data/lib/kennel.rb CHANGED
@@ -20,6 +20,7 @@ require "kennel/models/base"
20
20
  # parts
21
21
  require "kennel/models/monitor"
22
22
  require "kennel/models/dash"
23
+ require "kennel/models/dashboard"
23
24
  require "kennel/models/screen"
24
25
 
25
26
  # settings
@@ -64,8 +64,9 @@ module Kennel
64
64
  private
65
65
 
66
66
  def pretty_print(hash)
67
- list = hash.sort_by { |k, _| [SORT_ORDER.index(k) || 999, k] } # important to the front and rest deterministic
68
- list.map do |k, v|
67
+ sort_widgets hash
68
+
69
+ sort_hash(hash).map do |k, v|
69
70
  pretty_value =
70
71
  if v.is_a?(Hash) || (v.is_a?(Array) && !v.all? { |e| e.is_a?(String) })
71
72
  # update answer here when changing https://stackoverflow.com/questions/8842546/best-way-to-pretty-print-a-hash
@@ -85,5 +86,19 @@ module Kennel
85
86
  " #{k}: -> {#{pretty_value}}"
86
87
  end.join(",\n")
87
88
  end
89
+
90
+ # sort dashboard widgets + nesting
91
+ def sort_widgets(outer)
92
+ outer[:widgets]&.each do |widgets|
93
+ definition = widgets[:definition]
94
+ definition.replace sort_hash(definition)
95
+ sort_widgets definition
96
+ end
97
+ end
98
+
99
+ # important to the front and rest deterministic
100
+ def sort_hash(hash)
101
+ Hash[hash.sort_by { |k, _| [SORT_ORDER.index(k) || 999, k] }]
102
+ end
88
103
  end
89
104
  end
@@ -74,7 +74,7 @@ module Kennel
74
74
  [expected.size.to_i, actual.size.to_i].max.times do |i|
75
75
  a_r = actual.dig(i, level2, :requests) || []
76
76
  e_r = expected.dig(i, level2, :requests) || []
77
- ignore_defaults e_r, a_r, REQUEST_DEFAULTS
77
+ ignore_defaults e_r, a_r, self::REQUEST_DEFAULTS
78
78
  end
79
79
  end
80
80
 
@@ -75,14 +75,7 @@ module Kennel
75
75
  def validate_json(data)
76
76
  super
77
77
 
78
- # check for bad variables
79
- # TODO: do the same check for apm_query and their group_by
80
- variables = (data[:template_variables] || []).map { |v| "$#{v.fetch(:name)}" }
81
- queries = data[:graphs].flat_map { |g| (g[:definition][:requests] || []).map { |r| r[:q] }.compact }
82
- bad = queries.grep_v(/(#{variables.map { |v| Regexp.escape(v) }.join("|")})\b/)
83
- if bad.any?
84
- invalid! "queries #{bad.join(", ")} must use the template variables #{variables.join(", ")}"
85
- end
78
+ validate_template_variables data, :graphs
86
79
 
87
80
  # check for fields that are unsettable
88
81
  data[:graphs].each do |g|
@@ -92,12 +85,6 @@ module Kennel
92
85
  end
93
86
  end
94
87
 
95
- def render_template_variables
96
- (template_variables || []).map do |v|
97
- v.is_a?(String) ? { default: "*", prefix: v, name: v } : v
98
- end
99
- end
100
-
101
88
  def render_graphs
102
89
  definitions.map do |title, viz, type, queries, options = {}, ignored = nil|
103
90
  # validate inputs
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+ module Kennel
3
+ module Models
4
+ class Dashboard < Base
5
+ include TemplateVariables
6
+ include OptionalValidations
7
+
8
+ API_LIST_INCOMPLETE = true
9
+ DASHBOARD_DEFAULTS = { template_variables: [] }.freeze
10
+ READONLY_ATTRIBUTES = Base::READONLY_ATTRIBUTES + [
11
+ :author_handle, :author_name, :modified_at, :url, :is_read_only, :notify_list
12
+ ]
13
+ REQUEST_DEFAULTS = {
14
+ style: { line_width: "normal", palette: "dog_classic", line_type: "solid" }
15
+ }.freeze
16
+
17
+ settings :id, :title, :description, :widgets, :kennel_id, :layout_type
18
+
19
+ defaults(
20
+ description: -> { "" },
21
+ widgets: -> { [] },
22
+ id: -> { nil }
23
+ )
24
+
25
+ class << self
26
+ def normalize(expected, actual)
27
+ super
28
+
29
+ ignore_default expected, actual, DASHBOARD_DEFAULTS
30
+
31
+ base_pairs(expected, actual).each do |pair|
32
+ ignore_request_defaults(*pair, :widgets, :definition)
33
+ pair.each { |dash| dash[:widgets]&.each { |w| w.delete(:id) } }
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ # expand nested widgets into expected/actual pairs for default resolution
40
+ # [a, e] -> [[a, e], [aw1, ew1], ...]
41
+ def base_pairs(*pair)
42
+ result = [pair]
43
+ slots = pair.map { |d| d[:widgets]&.size }.compact.max.to_i
44
+ slots.times do |i|
45
+ nested = pair.map { |d| d.dig(:widgets, i, :definition) || {} }
46
+ result << nested if nested.any? { |d| d.key?(:widgets) }
47
+ end
48
+ result
49
+ end
50
+ end
51
+
52
+ attr_reader :project
53
+
54
+ def initialize(project, *args)
55
+ @project = project
56
+ super(*args)
57
+ end
58
+
59
+ def self.api_resource
60
+ "dashboard"
61
+ end
62
+
63
+ def as_json
64
+ return @json if @json
65
+ @json = {
66
+ layout_type: layout_type,
67
+ title: "#{title}#{LOCK}",
68
+ description: description,
69
+ template_variables: render_template_variables,
70
+ widgets: widgets
71
+ }
72
+
73
+ @json[:id] = id if id
74
+
75
+ validate_json(@json) if validate
76
+
77
+ @json
78
+ end
79
+
80
+ def url(id)
81
+ Utils.path_to_url "/dashboard/#{id}"
82
+ end
83
+
84
+ private
85
+
86
+ def validate_json(data)
87
+ super
88
+
89
+ validate_template_variables data, :widgets
90
+ end
91
+ end
92
+ end
93
+ end
data/lib/kennel/syncer.rb CHANGED
@@ -74,8 +74,12 @@ module Kennel
74
74
  details_cache do |cache|
75
75
  actual.each do |a|
76
76
  id = a.fetch(:id)
77
+ e = matching_expected(a)
77
78
 
78
- if e = delete_matching_expected(a)
79
+ # check correct class, since we will have multiple actuals for each flavor (dash/screen/dashboard)
80
+ next if e && e.class.api_resource != a[:api_resource]
81
+
82
+ if e && @expected.delete(e)
79
83
  fill_details(a, cache) if e.class::API_LIST_INCOMPLETE
80
84
  diff = e.diff(a)
81
85
  @update << [id, e, a, diff] if diff.any?
@@ -94,7 +98,7 @@ module Kennel
94
98
  def fill_details(a, cache)
95
99
  resource = a.fetch(:api_resource)
96
100
  args = [resource, a.fetch(:id)]
97
- full = cache.fetch(args, a.fetch(:modified)) do
101
+ full = cache.fetch(args, a[:modified] || a.fetch(:modified_at)) do
98
102
  unnest(resource, @api.show(*args))
99
103
  end
100
104
  a.merge!(full)
@@ -117,13 +121,10 @@ module Kennel
117
121
  end
118
122
 
119
123
  Utils.parallel(api_resources.compact.uniq) do |api_resource|
120
- # lookup monitors without adding unnecessary downtime information
121
- results = @api.list(api_resource, with_downtimes: false)
122
- if results.is_a?(Hash)
123
- results = results[results.keys.first]
124
- results.each { |r| r[:id] = Integer(r.fetch(:id)) }
125
- end
126
- results.each { |c| c[:api_resource] = api_resource }
124
+ results = @api.list(api_resource, with_downtimes: false) # lookup monitors without adding unnecessary downtime information
125
+ results = results[results.keys.first] if results.is_a?(Hash) # dashes/screens are nested in {dash: {}}
126
+ results.each { |r| r[:id] = Integer(r[:id]) if r[:id] =~ /\A\d+\z/ } # screen ids are integers as strings
127
+ results.each { |c| c[:api_resource] = api_resource } # store api resource for later diffing
127
128
  end.flatten(1)
128
129
  end
129
130
 
@@ -134,7 +135,7 @@ module Kennel
134
135
  end
135
136
  end
136
137
 
137
- def delete_matching_expected(a)
138
+ def matching_expected(a)
138
139
  # index list by all the thing we look up by: tracking id and actual id
139
140
  @lookup_map ||= @expected.each_with_object({}) do |e, all|
140
141
  keys = [tracking_id(e.as_json)]
@@ -145,8 +146,7 @@ module Kennel
145
146
  end
146
147
  end
147
148
 
148
- e = @lookup_map["#{a.fetch(:api_resource)}:#{a.fetch(:id)}"] || @lookup_map[tracking_id(a)]
149
- @expected.delete(e) if e
149
+ @lookup_map["#{a.fetch(:api_resource)}:#{a.fetch(:id)}"] || @lookup_map[tracking_id(a)]
150
150
  end
151
151
 
152
152
  def print_plan(step, list, color)
@@ -9,9 +9,25 @@ module Kennel
9
9
  private
10
10
 
11
11
  def render_template_variables
12
- template_variables.map do |v|
12
+ (template_variables || []).map do |v|
13
13
  v.is_a?(String) ? { default: "*", prefix: v, name: v } : v
14
14
  end
15
15
  end
16
+
17
+ # check for queries that do not use the variables and would be misleading
18
+ # TODO: do the same check for apm_query and their group_by
19
+ def validate_template_variables(data, key)
20
+ variables = (data[:template_variables] || []).map { |v| "$#{v.fetch(:name)}" }
21
+ queries = data[key].flat_map do |g|
22
+ requests =
23
+ (g.dig(:definition, :requests) || []) +
24
+ (g.dig(:definition, :widgets) || []).flat_map { |w| w.dig(:definition, :requests) || [] }
25
+ requests.map { |r| r[:q] }
26
+ end.compact
27
+ bad = queries.grep_v(/(#{variables.map { |v| Regexp.escape(v) }.join("|")})\b/)
28
+ if bad.any?
29
+ invalid! "queries #{bad.join(", ")} must use the template variables #{variables.join(", ")}"
30
+ end
31
+ end
16
32
  end
17
33
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "1.39.0"
3
+ VERSION = "1.40.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.39.0
4
+ version: 1.40.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: 2019-06-11 00:00:00.000000000 Z
11
+ date: 2019-06-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -66,6 +66,7 @@ files:
66
66
  - lib/kennel/importer.rb
67
67
  - lib/kennel/models/base.rb
68
68
  - lib/kennel/models/dash.rb
69
+ - lib/kennel/models/dashboard.rb
69
70
  - lib/kennel/models/monitor.rb
70
71
  - lib/kennel/models/project.rb
71
72
  - lib/kennel/models/screen.rb