pencil 0.2.10 → 0.3.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.
- data/bin/pencil +2 -6
- data/docs/pencil_options.md +3 -1
- data/lib/{config.rb → pencil/config.rb} +29 -9
- data/lib/pencil/config.ru +2 -0
- data/lib/pencil/helpers.rb +211 -0
- data/lib/pencil/models/base.rb +78 -0
- data/lib/pencil/models/dashboard.rb +124 -0
- data/lib/pencil/models/graph.rb +394 -0
- data/lib/pencil/models/host.rb +89 -0
- data/lib/pencil/models.rb +3 -0
- data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_flat_30_cccccc_40x100.png +0 -0
- data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_flat_50_5c5c5c_40x100.png +0 -0
- data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_glass_20_333333_1x400.png +0 -0
- data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_glass_40_000000_1x400.png +0 -0
- data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_glass_40_ffc73d_1x400.png +0 -0
- data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_gloss-wave_25_333333_500x100.png +0 -0
- data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_highlight-soft_15_000000_1x100.png +0 -0
- data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_highlight-soft_80_eeeeee_1x100.png +0 -0
- data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_inset-soft_30_ff4e0a_1x100.png +0 -0
- data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-icons_222222_256x240.png +0 -0
- data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-icons_4b8e0b_256x240.png +0 -0
- data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-icons_a83300_256x240.png +0 -0
- data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-icons_cccccc_256x240.png +0 -0
- data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-icons_ffffff_256x240.png +0 -0
- data/lib/{public → pencil/public}/css/jquery_themes/pencil/jquery-ui-1.8.16.custom.css +0 -0
- data/lib/{public → pencil/public}/css/thedoc.css +1 -0
- data/lib/{public → pencil/public}/favicon.ico +0 -0
- data/lib/{public → pencil/public}/js/cufon.js +0 -0
- data/lib/{public → pencil/public}/js/gotham.font.js +0 -0
- data/lib/{public → pencil/public}/js/jquery-1.6.2.min.js +0 -0
- data/lib/{public → pencil/public}/js/jquery-ui-1.8.16.custom.min.js +0 -0
- data/lib/{public → pencil/public}/js/pencil.js +0 -0
- data/lib/{public → pencil/public}/js/product-design.font.js +0 -0
- data/lib/pencil/public/style.css +307 -0
- data/lib/{rubyfixes.rb → pencil/rubyfixes.rb} +0 -0
- data/lib/pencil/version.rb +3 -0
- data/lib/{views → pencil/views}/cluster.erb +1 -1
- data/lib/{views → pencil/views}/dash-cluster-zoom.erb +2 -2
- data/lib/{views → pencil/views}/dash-cluster.erb +1 -1
- data/lib/{views → pencil/views}/dash-global-zoom.erb +2 -2
- data/lib/{views → pencil/views}/dash-global.erb +1 -1
- data/lib/{views → pencil/views}/global.erb +1 -1
- data/lib/{views → pencil/views}/host.erb +1 -1
- data/lib/{views → pencil/views}/layout.erb +2 -2
- data/lib/{views → pencil/views}/partials/cluster_selector.erb +0 -0
- data/lib/{views → pencil/views}/partials/cluster_switcher.erb +0 -0
- data/lib/{views → pencil/views}/partials/dash_switcher.erb +0 -0
- data/lib/{views → pencil/views}/partials/graph_switcher.erb +0 -0
- data/lib/{views → pencil/views}/partials/hosts_selector.erb +0 -0
- data/lib/{views → pencil/views}/partials/input_boxes.erb +0 -0
- data/lib/{views → pencil/views}/partials/shortcuts.erb +0 -0
- data/lib/{dash.rb → pencil.rb} +14 -17
- metadata +57 -58
- data/VERSION.rb +0 -1
- data/lib/config.ru +0 -2
- data/lib/helpers.rb +0 -209
- data/lib/models/base.rb +0 -73
- data/lib/models/dashboard.rb +0 -111
- data/lib/models/graph.rb +0 -367
- data/lib/models/host.rb +0 -87
- data/lib/models.rb +0 -3
- data/lib/namespace.rb +0 -4
- data/lib/public/style.css +0 -97
data/bin/pencil
CHANGED
@@ -1,9 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
2
|
+
require 'pencil'
|
3
3
|
|
4
|
-
|
5
|
-
require "dash"
|
4
|
+
Pencil::App.run!
|
6
5
|
|
7
|
-
STDOUT.puts "pencil v#{PENCIL_VERSION} on port #{Dash::App.port}, PID #{$$}"
|
8
|
-
|
9
|
-
Rack::Handler::Mongrel.run(Dash::App, :Port => Dash::App.port)
|
data/docs/pencil_options.md
CHANGED
@@ -203,7 +203,9 @@ Most of these options take a single argument.
|
|
203
203
|
* threshold
|
204
204
|
* color
|
205
205
|
|
206
|
-
Note: key
|
206
|
+
Note: key and color are applied after all other options are applied.
|
207
|
+
|
208
|
+
key is interpreted differently from the other options, which are more
|
207
209
|
simply translated.
|
208
210
|
|
209
211
|
color's interpretation depends on whether :use_color is set.
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require
|
2
|
-
require "models"
|
1
|
+
require 'map'
|
2
|
+
require "pencil/models"
|
3
3
|
|
4
|
-
module
|
4
|
+
module Pencil
|
5
5
|
class Config
|
6
|
-
include
|
6
|
+
include Pencil::Models
|
7
7
|
|
8
8
|
attr_reader :dashboards
|
9
9
|
attr_reader :graphs
|
@@ -32,11 +32,31 @@ module Dash
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def reload!
|
35
|
-
configs = Dir.glob("#{@confdir}
|
36
|
-
configs.each
|
35
|
+
configs = Dir.glob("#{@confdir}/**/*.y{a,}ml")
|
36
|
+
configs.each do |c|
|
37
|
+
yml = YAML.load(File.read(c))
|
38
|
+
next unless yml
|
39
|
+
@rawconfig[:config] = yml[:config] if yml[:config]
|
40
|
+
a = @rawconfig[:dashboards]
|
41
|
+
b = yml[:dashboards]
|
42
|
+
c = @rawconfig[:graphs]
|
43
|
+
d = yml[:graphs]
|
44
|
+
|
45
|
+
if a && b
|
46
|
+
a.merge!(b)
|
47
|
+
elsif b
|
48
|
+
@rawconfig[:dashboards] = b
|
49
|
+
end
|
50
|
+
if c && d
|
51
|
+
c.merge!(d)
|
52
|
+
elsif d
|
53
|
+
@rawconfig[:graphs] = d
|
54
|
+
end
|
55
|
+
end
|
56
|
+
@rawconfig = Map(@rawconfig)
|
37
57
|
|
38
58
|
[:graphs, :dashboards, :config].each do |c|
|
39
|
-
if not @rawconfig[c]
|
59
|
+
if not @rawconfig[c.to_s]
|
40
60
|
raise "Missing config name '#{c.to_s}'"
|
41
61
|
end
|
42
62
|
end
|
@@ -99,5 +119,5 @@ module Dash
|
|
99
119
|
@dashboards, @graphs = dashboards_new, graphs_new
|
100
120
|
@hosts, @clusters = hosts_new, clusters_new
|
101
121
|
end
|
102
|
-
end #
|
103
|
-
end #
|
122
|
+
end # Pencil::Config
|
123
|
+
end # Pencil
|
@@ -0,0 +1,211 @@
|
|
1
|
+
module Pencil
|
2
|
+
module Helpers
|
3
|
+
include Pencil::Models
|
4
|
+
|
5
|
+
@@prefs = [["Start Time", "start"],
|
6
|
+
["Duration", "duration"],
|
7
|
+
["Width", "width"],
|
8
|
+
["Height", "height"]]
|
9
|
+
|
10
|
+
# convert keys to symbols before lookup
|
11
|
+
def param_lookup(name)
|
12
|
+
sym_hash = {}
|
13
|
+
session.each { |k,v| sym_hash[k.to_sym] = v unless v.empty? }
|
14
|
+
params.each { |k,v| sym_hash[k.to_sym] = v unless v.empty? }
|
15
|
+
settings.config.global_config[:url_opts].merge(sym_hash)[name.to_sym]
|
16
|
+
end
|
17
|
+
|
18
|
+
def cluster_graph(g, cluster, title="wtf")
|
19
|
+
image_url = \
|
20
|
+
@dash.render_cluster_graph(g, cluster,
|
21
|
+
:title => title,
|
22
|
+
:dynamic_url_opts => merge_opts)
|
23
|
+
zoom_url = cluster_graph_link(@dash, g, cluster)
|
24
|
+
return image_url, zoom_url
|
25
|
+
end
|
26
|
+
|
27
|
+
def cluster_graph_link(dash, g, cluster)
|
28
|
+
link = dash.graph_opts[g]["click"] ||
|
29
|
+
"/dash/#{cluster}/#{dash.name}/#{g.name}"
|
30
|
+
return append_query_string(link)
|
31
|
+
end
|
32
|
+
|
33
|
+
def cluster_zoom_graph(g, cluster, host, title)
|
34
|
+
image_url = g.render_url([host.name], [cluster], :title => title,
|
35
|
+
:dynamic_url_opts => merge_opts)
|
36
|
+
zoom_url = cluster_zoom_link(cluster, host)
|
37
|
+
return image_url, zoom_url
|
38
|
+
end
|
39
|
+
|
40
|
+
def cluster_zoom_link(cluster, host)
|
41
|
+
return append_query_string("/host/#{cluster}/#{host}")
|
42
|
+
end
|
43
|
+
|
44
|
+
def suggest_cluster_links(clusters, g)
|
45
|
+
links = []
|
46
|
+
clusters.each do |c|
|
47
|
+
href = append_query_string("/dash/#{c}/#{params[:dashboard]}/#{g.name}")
|
48
|
+
links << "<a href=\"#{href}\">#{c}</a>"
|
49
|
+
end
|
50
|
+
return "zoom (" + links.join(", ") + ")"
|
51
|
+
end
|
52
|
+
|
53
|
+
def suggest_dashboards_links(host, graph)
|
54
|
+
suggested = suggest_dashboards(host, graph)
|
55
|
+
return "" if suggested.length == 0
|
56
|
+
|
57
|
+
links = []
|
58
|
+
suggested.each do |d|
|
59
|
+
links << "<a href=\"/dash/#{host.cluster}/#{append_query_string(d)}\">" +
|
60
|
+
"#{d}</a>"
|
61
|
+
end
|
62
|
+
return "(" + links.join(", ") + ")"
|
63
|
+
end
|
64
|
+
|
65
|
+
# it's mildly annoying that when this set is empty there're no uplinks
|
66
|
+
# consider adding a link up to the cluster (which is best we can do)
|
67
|
+
def suggest_dashboards(host, graph)
|
68
|
+
ret = Set.new
|
69
|
+
|
70
|
+
host.graphs.each do |g|
|
71
|
+
Dashboard.find_by_graph(g).each do |d|
|
72
|
+
valid, _ = d.get_valid_hosts(g, host['cluster'])
|
73
|
+
ret << d.name if valid.member?(host)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
return ret
|
78
|
+
end
|
79
|
+
|
80
|
+
# generate the input box fields, filled in to current parameters if specified
|
81
|
+
def input_boxes
|
82
|
+
@prefs = @@prefs
|
83
|
+
erb :'partials/input_boxes', :layout => false
|
84
|
+
end
|
85
|
+
|
86
|
+
def dash_link(dash, cluster)
|
87
|
+
return append_query_string("/dash/#{cluster}/#{dash.name}")
|
88
|
+
end
|
89
|
+
|
90
|
+
def cluster_link(cluster)
|
91
|
+
return append_query_string("/dash/#{cluster}")
|
92
|
+
end
|
93
|
+
|
94
|
+
# fixme this isn't used anymore, but should
|
95
|
+
def css_url
|
96
|
+
style = File.join(settings.root, "public/style.css")
|
97
|
+
mtime = File.mtime(style).to_i.to_s
|
98
|
+
return \
|
99
|
+
%Q[<link href="/style.css?#{mtime}" rel="stylesheet" type="text/css">]
|
100
|
+
end
|
101
|
+
|
102
|
+
def refresh
|
103
|
+
if settings.config.global_config[:refresh_rate] != false && nowish
|
104
|
+
rate = settings.config.global_config[:refresh_rate] || 60
|
105
|
+
return %Q[<meta http-equiv="refresh" content="#{rate}">]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def hosts_selector(hosts, print_clusters=false)
|
110
|
+
@print_clusters = print_clusters
|
111
|
+
@hosts = hosts
|
112
|
+
erb :'partials/hosts_selector', :layout => false
|
113
|
+
end
|
114
|
+
|
115
|
+
def append_query_string(str)
|
116
|
+
v = str.dup
|
117
|
+
(v << "?#{request.query_string}") unless request.query_string.empty?
|
118
|
+
return v
|
119
|
+
end
|
120
|
+
|
121
|
+
def merge_opts
|
122
|
+
static_opts = ["cluster", "dashboard", "zoom", "host", "session_id"]
|
123
|
+
opts = params.dup
|
124
|
+
session.merge(opts).delete_if { |k,v| static_opts.member?(k) || v.empty? }
|
125
|
+
end
|
126
|
+
|
127
|
+
def shortcuts(str)
|
128
|
+
@str = str
|
129
|
+
erb :'partials/shortcuts', :layout => false
|
130
|
+
end
|
131
|
+
def cluster_switcher(clusters)
|
132
|
+
@clusters = clusters
|
133
|
+
erb :'partials/cluster_switcher', :layout => false
|
134
|
+
end
|
135
|
+
|
136
|
+
def dash_switcher
|
137
|
+
erb :'partials/dash_switcher', :layout => false
|
138
|
+
end
|
139
|
+
|
140
|
+
def graph_switcher
|
141
|
+
erb :'partials/graph_switcher', :layout => false
|
142
|
+
end
|
143
|
+
|
144
|
+
def cluster_selector
|
145
|
+
@clusters = settings.config.clusters.sort + ["global"]
|
146
|
+
erb :'partials/cluster_selector', :layout => false
|
147
|
+
end
|
148
|
+
|
149
|
+
def host_uplink
|
150
|
+
link = "/dash/#{append_query_string(@host.cluster)}"
|
151
|
+
"zoom out: <a href=\"#{link}\">#{@host.cluster}</a>"
|
152
|
+
end
|
153
|
+
|
154
|
+
def graph_uplink
|
155
|
+
link = append_query_string(request.path.split("/")[0..-2].join("/"))
|
156
|
+
"zoom out: <a href=\"#{link}\">#{@dash}</a>"
|
157
|
+
end
|
158
|
+
|
159
|
+
def dash_uplink
|
160
|
+
link = append_query_string(request.path.split("/")[0..-2].join("/"))
|
161
|
+
"zoom out: <a href=\"#{link}\">#{@params[:cluster]}</a>"
|
162
|
+
end
|
163
|
+
|
164
|
+
# fixme this is a hack
|
165
|
+
def header(str)
|
166
|
+
<<-FOO
|
167
|
+
<div class="path_container">
|
168
|
+
<h2>#{@title}</h2>
|
169
|
+
<span class="zoom">
|
170
|
+
#{str}
|
171
|
+
</span>
|
172
|
+
</div>
|
173
|
+
<div id="timeslice_container">
|
174
|
+
<h3 id="timeslice">#{range_string}</h3>
|
175
|
+
#{permalink unless @no_graphs}
|
176
|
+
</div>
|
177
|
+
FOO
|
178
|
+
end
|
179
|
+
|
180
|
+
def nowish
|
181
|
+
if settings.config.global_config[:now_threshold] == false
|
182
|
+
return false
|
183
|
+
end
|
184
|
+
threshold = settings.config.global_config[:now_threshold] || 300
|
185
|
+
return @request_time.to_i - @etime.to_i < threshold
|
186
|
+
end
|
187
|
+
|
188
|
+
def range_string
|
189
|
+
format = settings.config.global_config[:date_format] || "%X %x"
|
190
|
+
if @stime && @etime
|
191
|
+
if nowish
|
192
|
+
"timeslice: from #{@stime.strftime(format)}"
|
193
|
+
else
|
194
|
+
"timeslice: #{@stime.strftime(format)} - #{@etime.strftime(format)}"
|
195
|
+
end
|
196
|
+
else
|
197
|
+
"invalid time range"
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
def permalink
|
203
|
+
return "" unless @stime && @duration
|
204
|
+
format = "%F %T" # chronic REALLY understands this
|
205
|
+
url = request.path + "?"
|
206
|
+
url << "&start=#{@stime.strftime(format)}"
|
207
|
+
url << "&duration=#{ChronicDuration.output(@duration)}"
|
208
|
+
"<a id=\"permalink\" href=\"#{url}\">permalink</a>"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Pencil
|
2
|
+
module Models
|
3
|
+
class Base
|
4
|
+
@@objects = Hash.new { |h, k| h[k] = Hash.new }
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize(name, params={})
|
8
|
+
@name = name
|
9
|
+
@match_name = name
|
10
|
+
@params = params
|
11
|
+
@@objects[self.class.to_s][name] = self
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.find(name)
|
15
|
+
return @@objects[self.name][name] rescue []
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.each(&block)
|
19
|
+
h = @@objects[self.name] rescue {}
|
20
|
+
h.each { |k, v| yield(k, v) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.all
|
24
|
+
return @@objects[self.name].values
|
25
|
+
end
|
26
|
+
|
27
|
+
def [](key)
|
28
|
+
return @params[key] rescue []
|
29
|
+
end
|
30
|
+
|
31
|
+
def match(glob)
|
32
|
+
return true if glob == '*'
|
33
|
+
# convert glob to a regular expression
|
34
|
+
glob_re = /^#{Regexp.escape(glob).gsub('\*', '.*').gsub('\#', '\d+')}$/
|
35
|
+
return @match_name.match(glob_re)
|
36
|
+
end
|
37
|
+
|
38
|
+
def multi_match(globs)
|
39
|
+
ret = false
|
40
|
+
|
41
|
+
globs.each do |glob|
|
42
|
+
ret = match(glob)
|
43
|
+
break if ret
|
44
|
+
end
|
45
|
+
|
46
|
+
return ret
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_s
|
50
|
+
return @name
|
51
|
+
end
|
52
|
+
|
53
|
+
def <=>(other)
|
54
|
+
return to_s <=> other.to_s
|
55
|
+
end
|
56
|
+
|
57
|
+
def update_params(hash)
|
58
|
+
@params.merge!(hash)
|
59
|
+
end
|
60
|
+
|
61
|
+
# compose a metric using a :metric_format
|
62
|
+
# format string with %c for metric, %c for cluster, and %h for host
|
63
|
+
def compose_metric (m, c, h)
|
64
|
+
@params[:metric_format].dup.gsub("%m", m).gsub("%c", c).gsub("%h", h)
|
65
|
+
end
|
66
|
+
|
67
|
+
# used to make sure partial metrics are not considered
|
68
|
+
# e.g. foo.bar.baz.colo1.host1 but not
|
69
|
+
# foo.bar.baz.subkey.subkey2[.colo1.host1]
|
70
|
+
# where the latter is returned by the graphite expand api but not as a full
|
71
|
+
# metric
|
72
|
+
# essentially equivalent to matching like /[:METRIC:]$/
|
73
|
+
def compose_metric2 (m, c, h)
|
74
|
+
compose_metric(m, c, h) + ".*"
|
75
|
+
end
|
76
|
+
end # Pencil::Models::Base
|
77
|
+
end
|
78
|
+
end # Pencil::Models
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require "pencil/models/base"
|
2
|
+
require "pencil/models/graph"
|
3
|
+
require "pencil/models/host"
|
4
|
+
require "set"
|
5
|
+
|
6
|
+
module Pencil
|
7
|
+
module Models
|
8
|
+
class Dashboard < Base
|
9
|
+
attr_accessor :graphs
|
10
|
+
attr_accessor :graph_opts
|
11
|
+
|
12
|
+
def initialize(name, params={})
|
13
|
+
super
|
14
|
+
|
15
|
+
@graphs = []
|
16
|
+
@graph_opts = {}
|
17
|
+
params["graphs"].each do |name|
|
18
|
+
# graphs map to option hashes
|
19
|
+
if name.respond_to?(:keys) # could be YAML::Omap
|
20
|
+
g = Graph.find(name.keys.first) # should only be one key
|
21
|
+
@graph_opts[g] = name[name.keys.first]||{}
|
22
|
+
else
|
23
|
+
raise "Bad format for graph (must be a hash-y; #{name.class}:#{name.inspect} is not)"
|
24
|
+
end
|
25
|
+
|
26
|
+
@graphs << g if g
|
27
|
+
end
|
28
|
+
|
29
|
+
@valid_hosts_table = {} # cache calls to get_valid_hosts
|
30
|
+
end
|
31
|
+
|
32
|
+
def clusters
|
33
|
+
clusters = Set.new
|
34
|
+
@graphs.each { |g| clusters += get_valid_hosts(g)[1] }
|
35
|
+
clusters.sort
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_all_hosts(cluster=nil)
|
39
|
+
hosts = Set.new
|
40
|
+
clusters = Set.new
|
41
|
+
@graphs.each do |g|
|
42
|
+
h, c = get_valid_hosts(g, cluster)
|
43
|
+
hosts += h
|
44
|
+
clusters += c
|
45
|
+
end
|
46
|
+
return hosts, clusters
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_valid_hosts(graph, cluster=nil)
|
50
|
+
if @valid_hosts_table[[graph, cluster]]
|
51
|
+
return @valid_hosts_table[[graph, cluster]]
|
52
|
+
end
|
53
|
+
|
54
|
+
clusters = Set.new
|
55
|
+
if cluster
|
56
|
+
hosts = Host.find_by_cluster(cluster)
|
57
|
+
else
|
58
|
+
hosts = Host.all
|
59
|
+
end
|
60
|
+
|
61
|
+
# filter as:
|
62
|
+
# - the dashboard graph hosts definition
|
63
|
+
# - the dashboard hosts definition
|
64
|
+
# - the graph hosts definition
|
65
|
+
# this is new behavior: before the filters were additive
|
66
|
+
filter = graph_opts[graph]["hosts"] || @params["hosts"] || graph["hosts"]
|
67
|
+
if filter
|
68
|
+
hosts = hosts.select { |h| h.multi_match(filter) }
|
69
|
+
end
|
70
|
+
|
71
|
+
hosts.each { |h| clusters << h.cluster }
|
72
|
+
|
73
|
+
@valid_hosts_table[[graph, cluster]] = [hosts, clusters]
|
74
|
+
return hosts, clusters
|
75
|
+
end
|
76
|
+
|
77
|
+
def render_cluster_graph(graph, clusters, opts={})
|
78
|
+
# FIXME: edge case where the dash filter does not filter to a subset of
|
79
|
+
# the hosts filter
|
80
|
+
|
81
|
+
hosts = get_host_wildcards(graph)
|
82
|
+
|
83
|
+
# graphite doesn't support strict matching (as /\d+/), so we need to
|
84
|
+
# enumerate the hosts if a "#" wildcard is found
|
85
|
+
if ! (filter = hosts.select { |h| h =~ /#/ }).empty?
|
86
|
+
hosts_new = hosts - filter
|
87
|
+
hosts2 = Host.all.select { |h| h.multi_match(filter) }
|
88
|
+
hosts = (hosts2.map {|h| h.name } + hosts_new).sort.uniq.join(',')
|
89
|
+
end
|
90
|
+
|
91
|
+
opts[:sum] = :cluster unless opts[:zoom]
|
92
|
+
graph_url = graph.render_url(hosts.to_a, clusters, opts)
|
93
|
+
return graph_url
|
94
|
+
end
|
95
|
+
|
96
|
+
def get_host_wildcards(graph)
|
97
|
+
return graph_opts[graph]["hosts"] || @params["hosts"] || graph["hosts"]
|
98
|
+
end
|
99
|
+
|
100
|
+
def render_global_graph(graph, opts={})
|
101
|
+
hosts = get_host_wildcards(graph)
|
102
|
+
_, clusters = get_valid_hosts(graph)
|
103
|
+
|
104
|
+
next_url = ""
|
105
|
+
type = opts[:zoom] ? :cluster : :global
|
106
|
+
options = opts.merge({:sum => type})
|
107
|
+
graph_url = graph.render_url(hosts, clusters, options)
|
108
|
+
return graph_url
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.find_by_graph(graph)
|
112
|
+
ret = []
|
113
|
+
Dashboard.each do |name, dash|
|
114
|
+
|
115
|
+
if dash["graphs"].map { |x| x.keys.first }.member?(graph.name)
|
116
|
+
ret << dash
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
return ret
|
121
|
+
end
|
122
|
+
end # Pencil::Models::Dashboard
|
123
|
+
end
|
124
|
+
end # Pencil::Models
|