kennel 1.39.0 → 1.40.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: 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