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
@@ -0,0 +1,394 @@
|
|
1
|
+
require "pencil/models/base"
|
2
|
+
require "uri"
|
3
|
+
|
4
|
+
module Pencil
|
5
|
+
module Models
|
6
|
+
class Graph < Base
|
7
|
+
def initialize(name, params={})
|
8
|
+
super
|
9
|
+
|
10
|
+
@params["hosts"] ||= ["*"]
|
11
|
+
@params["title"] ||= name
|
12
|
+
|
13
|
+
if not @params["targets"]
|
14
|
+
raise ArgumentError, "graph #{name} needs a 'targets' map"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def width(opts={})
|
19
|
+
opts["width"] || @params[:url_opts][:width]
|
20
|
+
end
|
21
|
+
|
22
|
+
# translate STR into graphite-speak for applying FUNC to STR
|
23
|
+
# graphite functions take zero or one argument
|
24
|
+
# pass passes STR through, instead of raising an error if FUNC isn't
|
25
|
+
# recognized
|
26
|
+
def translate(func, str, arg=nil, pass=false)
|
27
|
+
# puts "calling translate"
|
28
|
+
# puts "func => #{func}"
|
29
|
+
# puts "str => #{str}"
|
30
|
+
# puts "arg => #{arg}"
|
31
|
+
# procs and lambdas don't support default arguments in 1.8, so I have to
|
32
|
+
# do this
|
33
|
+
z = lambda { |*body| "#{func}(#{body[0]||str})" }
|
34
|
+
y = "#{str}, #{arg}"
|
35
|
+
x = lambda { z.call(y) }
|
36
|
+
|
37
|
+
return \
|
38
|
+
case func.to_s
|
39
|
+
# comb
|
40
|
+
when "sumSeries", "averageSeries", "minSeries", "maxSeries", "group"
|
41
|
+
z.call
|
42
|
+
# transform
|
43
|
+
when "scale", "offset"
|
44
|
+
# perhaps .to_f
|
45
|
+
x.call
|
46
|
+
when "derivative", "integral"
|
47
|
+
z.call
|
48
|
+
when "nonNegativeDerivative"
|
49
|
+
z.call("#{str}#{', ' + arg if arg}")
|
50
|
+
when "log", "timeShift", "summarize", "hitcount",
|
51
|
+
# calculate
|
52
|
+
"movingAverage", "stdev", "asPercent"
|
53
|
+
x.call
|
54
|
+
when "diffSeries", "divideSeries"
|
55
|
+
z.call
|
56
|
+
# filters
|
57
|
+
when "mostDeviant"
|
58
|
+
z.call("#{arg}, #{str}")
|
59
|
+
when "highestCurrent", "lowestCurrent", "nPercentile", "currentAbove",
|
60
|
+
"currentBelow", "highestAverage", "lowestAverage", "averageAbove",
|
61
|
+
"averageBelow", "maximumAbove", "maximumBelow"
|
62
|
+
x.call
|
63
|
+
when "sortByMaxima", "minimalist"
|
64
|
+
z.call
|
65
|
+
when "limit", "exclude"
|
66
|
+
x.call
|
67
|
+
when "key", "alias"
|
68
|
+
"alias(#{str}, \"#{arg}\")"
|
69
|
+
when "cumulative", "drawAsInfinite"
|
70
|
+
z.call
|
71
|
+
when "lineWidth"
|
72
|
+
x.call
|
73
|
+
when "dashed", "keepLastValue"
|
74
|
+
z.call
|
75
|
+
when "substr", "threshold"
|
76
|
+
x.call
|
77
|
+
when "color"
|
78
|
+
@params[:use_color] ? "color(#{str}, \"#{arg}\")" : str
|
79
|
+
else
|
80
|
+
raise "BAD FUNC #{func}" unless pass
|
81
|
+
str
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# FIXME Map().keys => Array of strings
|
86
|
+
# inner means we're dealing with a complex key; @params will be applied
|
87
|
+
# make sure to apply alias and color arguments last, if applicable
|
88
|
+
def handle_metric(name, opts, inner=false)
|
89
|
+
later = []
|
90
|
+
ret = name.dup
|
91
|
+
if inner
|
92
|
+
@params.each do |k, v|
|
93
|
+
ret = translate(k, ret, v, true)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
(opts||{}).each do |k, v|
|
97
|
+
if k == "color" || k == "key"
|
98
|
+
later << [k, v]
|
99
|
+
else
|
100
|
+
ret = translate(k, ret, v)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
later.each do |k, v|
|
104
|
+
ret = translate(k, ret, v)
|
105
|
+
end
|
106
|
+
ret
|
107
|
+
end
|
108
|
+
|
109
|
+
def render_url(hosts, clusters, opts={})
|
110
|
+
opts = {
|
111
|
+
:sum => nil,
|
112
|
+
:title => @params["title"],
|
113
|
+
}.merge(opts)
|
114
|
+
|
115
|
+
if ! [:global, :cluster, nil].member?(opts[:sum])
|
116
|
+
raise ArgumentError, "render graph #{name}: invalid :sum - #{opts[:sum]}"
|
117
|
+
end
|
118
|
+
|
119
|
+
sym_hash = {}
|
120
|
+
(opts[:dynamic_url_opts]||[]).each do |k,v|
|
121
|
+
sym_hash[k.to_sym] = v
|
122
|
+
end
|
123
|
+
|
124
|
+
# fixme key checking may be necessary
|
125
|
+
url_opts = {
|
126
|
+
:title => opts[:title],
|
127
|
+
}.merge(@params[:url_opts]).merge(sym_hash)
|
128
|
+
|
129
|
+
url_opts[:from] = url_opts.delete(:stime) || ""
|
130
|
+
url_opts[:until] = url_opts.delete(:etime) || ""
|
131
|
+
url_opts.delete(:start)
|
132
|
+
url_opts.delete(:duration)
|
133
|
+
|
134
|
+
graphite_opts = [ "vtitle", "yMin", "yMax", "lineWidth", "areaMode",
|
135
|
+
"template", "lineMode", "bgcolor", "graphOnly", "hideAxes", "hideGrid",
|
136
|
+
"hideLegend", "fgcolor", "fontSize", "fontName", "fontItalic",
|
137
|
+
"fontBold", "logBase" ]
|
138
|
+
|
139
|
+
@params.each do |k, v|
|
140
|
+
if graphite_opts.member?(k)
|
141
|
+
url_opts[k.to_sym] = v
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
target = []
|
146
|
+
colors = []
|
147
|
+
#FIXME code duplication
|
148
|
+
if opts[:sum] == :global
|
149
|
+
@params["targets"].each do |stat_name, opts|
|
150
|
+
z = new_map(opts)
|
151
|
+
|
152
|
+
z[:key] ||= stat_name
|
153
|
+
#######################
|
154
|
+
if stat_name.instance_of?(Array)
|
155
|
+
metric = stat_name.map do |m|
|
156
|
+
mm = compose_metric(m.keys.first,
|
157
|
+
"{#{clusters.to_a.join(',')}}",
|
158
|
+
"{#{hosts.to_a.join(',')}}")
|
159
|
+
|
160
|
+
if z.keys.member?("divideSeries")
|
161
|
+
handle_metric(translate(:sumSeries, mm),
|
162
|
+
m[m.keys.first], true)
|
163
|
+
else
|
164
|
+
handle_metric(mm, m[m.keys.first], true)
|
165
|
+
end
|
166
|
+
end.join(",")
|
167
|
+
else
|
168
|
+
metric = compose_metric(stat_name,
|
169
|
+
"{#{clusters.to_a.join(',')}}",
|
170
|
+
"{#{hosts.to_a.join(',')}}")
|
171
|
+
metric = handle_metric(metric, {}, true)
|
172
|
+
end
|
173
|
+
#######################
|
174
|
+
z[:key] = "global #{z[:key]}"
|
175
|
+
# target << handle_metric(translate(:sumSeries, metric), z)
|
176
|
+
|
177
|
+
if z.keys.member?('divideSeries') # special case
|
178
|
+
# apply divideSeries, sumSeries then other options
|
179
|
+
res = translate(:divideSeries, metric)
|
180
|
+
res = translate(:sumSeries, res)
|
181
|
+
z.delete(:divideSeries)
|
182
|
+
h = YAML::Omap.new
|
183
|
+
z.each { |k,v| h[k] = v unless k == 'divideSeries' }
|
184
|
+
target << handle_metric(res, h)
|
185
|
+
else
|
186
|
+
target << handle_metric(translate(:sumSeries, metric), z)
|
187
|
+
end
|
188
|
+
if !@params[:use_color] ||
|
189
|
+
(!z[:color] && @params[:use_color])
|
190
|
+
colors << next_color(colors, z[:color])
|
191
|
+
end
|
192
|
+
end # @params["targets"].each
|
193
|
+
elsif opts[:sum] == :cluster # one line per cluster/metric
|
194
|
+
clusters.each do |cluster|
|
195
|
+
@params["targets"].each do |stat_name, opts|
|
196
|
+
z = new_map(opts)
|
197
|
+
|
198
|
+
metrics = []
|
199
|
+
#######################
|
200
|
+
h = "{#{hosts.to_a.join(',')}}"
|
201
|
+
if stat_name.instance_of?(Array)
|
202
|
+
metrics << stat_name.map do |m|
|
203
|
+
mm = compose_metric(m.keys.first, cluster, h)
|
204
|
+
# note: we take the ratio of the sums in this case, instead of
|
205
|
+
# the sums of the ratios
|
206
|
+
if z.keys.member?('divideSeries')
|
207
|
+
# divideSeries is picky about the number of series given as
|
208
|
+
# arguments, so sum them in this case
|
209
|
+
handle_metric(translate(:sumSeries, mm),
|
210
|
+
m[m.keys.first], true)
|
211
|
+
else
|
212
|
+
handle_metric(mm, m[m.keys.first], true)
|
213
|
+
end
|
214
|
+
end.join(",")
|
215
|
+
else
|
216
|
+
metrics << handle_metric(compose_metric(stat_name,
|
217
|
+
cluster, h), {}, true)
|
218
|
+
end
|
219
|
+
#######################
|
220
|
+
z[:key] = "#{cluster} #{z[:key]}"
|
221
|
+
|
222
|
+
if z.keys.member?('divideSeries') # special case
|
223
|
+
# apply divideSeries, sumSeries then other options
|
224
|
+
res = translate(:divideSeries, metrics.join(','))
|
225
|
+
res = translate(:sumSeries, res)
|
226
|
+
z.delete(:divideSeries)
|
227
|
+
h = Map.new
|
228
|
+
z.each { |k,v| h[k] = v unless k == 'divideSeries' }
|
229
|
+
target << handle_metric(res, h)
|
230
|
+
else
|
231
|
+
target << handle_metric(translate(:sumSeries,
|
232
|
+
metrics.join(',')), z)
|
233
|
+
end
|
234
|
+
|
235
|
+
if !@params[:use_color] || (!z[:color] && @params[:use_color])
|
236
|
+
colors << next_color(colors, z[:color])
|
237
|
+
end
|
238
|
+
end # metrics.each
|
239
|
+
end # clusters.each
|
240
|
+
else # one line per {metric,host,colo}
|
241
|
+
@params["targets"].each do |stat_name, opts|
|
242
|
+
z = new_map(opts)
|
243
|
+
clusters.each do |cluster|
|
244
|
+
hosts.each do |host|
|
245
|
+
label = "#{host} #{z[:key]}"
|
246
|
+
#################
|
247
|
+
if stat_name.instance_of?(Array)
|
248
|
+
metric = stat_name.map do |m|
|
249
|
+
mm = compose_metric(m.keys.first, cluster, host)
|
250
|
+
handle_metric(mm, m[m.keys.first], true)
|
251
|
+
end.join(",")
|
252
|
+
else
|
253
|
+
metric = handle_metric(compose_metric(stat_name, cluster, host), {}, true)
|
254
|
+
end
|
255
|
+
#################
|
256
|
+
|
257
|
+
if label =~ /\*/
|
258
|
+
# for this particular type of graph, don't display a legend,
|
259
|
+
# and color with abandon
|
260
|
+
url_opts[:hideLegend] = true
|
261
|
+
|
262
|
+
z.delete(:color)
|
263
|
+
# fixme proper labeling... maybe
|
264
|
+
# With wildcards let graphite construct the legend (or not).
|
265
|
+
# Since we're handling wildcards we don't know how many
|
266
|
+
# hosts will match, so just put in the default color list.
|
267
|
+
# technically we do know, so this can be fixed
|
268
|
+
z.delete(:key)
|
269
|
+
target << handle_metric(metric, z)
|
270
|
+
colors.concat(@params[:default_colors]) if colors.empty?
|
271
|
+
else
|
272
|
+
z[:key] = "#{host}/#{cluster} #{z[:key]}"
|
273
|
+
target << handle_metric(metric, z)
|
274
|
+
if !@params[:use_color] ||
|
275
|
+
(!z[:color] && @params[:use_color])
|
276
|
+
colors << next_color(colors, z[:color])
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end # @params["targets"].each
|
282
|
+
end # if opts[:sum]
|
283
|
+
|
284
|
+
url_opts[:target] = target
|
285
|
+
url_opts[:colorList] = colors.join(",")
|
286
|
+
|
287
|
+
url = URI.join(@params[:graphite_url], "/render/?").to_s
|
288
|
+
url_parts = []
|
289
|
+
url_opts.each do |k, v|
|
290
|
+
[v].flatten.each do |v|
|
291
|
+
url_parts << "#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}"
|
292
|
+
end
|
293
|
+
end
|
294
|
+
url += url_parts.join("&")
|
295
|
+
return url
|
296
|
+
end
|
297
|
+
|
298
|
+
# return an array of all metrics matching the specifications in
|
299
|
+
# @params["targets"]
|
300
|
+
# metrics are arrays of fields (once delimited by periods)
|
301
|
+
def expand
|
302
|
+
url = URI.join(@params[:graphite_url], "/metrics/expand/?query=").to_s
|
303
|
+
metrics = []
|
304
|
+
|
305
|
+
require "json"
|
306
|
+
@params["targets"].each do |k, v|
|
307
|
+
# temporary hack for Map class complaining block parameters
|
308
|
+
metric = [k, v]
|
309
|
+
unless metric.first.instance_of?(Array)
|
310
|
+
# wrap it
|
311
|
+
metric[0] = [{metric[0] => nil}]
|
312
|
+
end
|
313
|
+
metric.first.each do |m|
|
314
|
+
composed = compose_metric(m.first.first, "*", "*")
|
315
|
+
composed2 = compose_metric2(m.first.first, "*", "*")
|
316
|
+
query = open("#{url}#{composed}").read
|
317
|
+
query2 = open("#{url}#{composed2}").read
|
318
|
+
results = JSON.parse(query)["results"]
|
319
|
+
results2 = JSON.parse(query2)["results"].map {|x| x.split('.')[0..-2].join('.')}
|
320
|
+
metrics << results - results2
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
return metrics.flatten.map { |x| x.split(".") }
|
325
|
+
end
|
326
|
+
|
327
|
+
def hosts_clusters
|
328
|
+
metrics = expand
|
329
|
+
clusters = Set.new
|
330
|
+
|
331
|
+
# find the indicies of the clusters and hosts
|
332
|
+
f = @params[:metric_format].dup.split("%m")
|
333
|
+
first = f.first.split(".")
|
334
|
+
last = f.last.split(".")
|
335
|
+
ci = hi = nil
|
336
|
+
first.each_with_index do |v, i|
|
337
|
+
ci = i if v.match("%c")
|
338
|
+
hi = i if v.match("%h")
|
339
|
+
end
|
340
|
+
unless ci && hi
|
341
|
+
last.reverse.each_with_index do |v, i|
|
342
|
+
ci = -1 -i if v.match("%c")
|
343
|
+
hi = -1 -i if v.match("%h")
|
344
|
+
end
|
345
|
+
end
|
346
|
+
hosts = metrics.map do |m|
|
347
|
+
Host.new(m[hi], m[ci], @params)
|
348
|
+
end.uniq
|
349
|
+
|
350
|
+
# filter by what matches the graph definition
|
351
|
+
hosts = hosts.select { |h| h.multi_match(@params["hosts"]) }
|
352
|
+
hosts.each { |h| clusters << h.cluster }
|
353
|
+
|
354
|
+
return hosts, clusters
|
355
|
+
end
|
356
|
+
|
357
|
+
private
|
358
|
+
def next_color(colors, preferred_color=nil)
|
359
|
+
default_colors = @params[:default_colors].clone
|
360
|
+
|
361
|
+
if preferred_color and !colors.member?(preferred_color)
|
362
|
+
return preferred_color
|
363
|
+
end
|
364
|
+
|
365
|
+
if preferred_color and ! default_colors.member?(preferred_color)
|
366
|
+
default_colors << preferred_color
|
367
|
+
end
|
368
|
+
|
369
|
+
weights = Hash.new(0)
|
370
|
+
colors.each do |c|
|
371
|
+
weights[c] += 1
|
372
|
+
end
|
373
|
+
|
374
|
+
i = 0
|
375
|
+
loop do
|
376
|
+
default_colors.each do |c|
|
377
|
+
return c if weights[c] == i
|
378
|
+
end
|
379
|
+
i += 1
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
# if Map() in config.rb converted a YAML::Omap into an array, we
|
384
|
+
# need to turn it back into a Map (which is ordered, conveniently)
|
385
|
+
def new_map (opts)
|
386
|
+
if opts.is_a?(Array)
|
387
|
+
z = Map(opts.flatten)
|
388
|
+
else
|
389
|
+
z = Map(opts)
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end # Dash::Models::Graph
|
393
|
+
end
|
394
|
+
end # Pencil::Models
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require "pencil/models/base"
|
2
|
+
require "pencil/models/graph"
|
3
|
+
|
4
|
+
module Pencil
|
5
|
+
module Models
|
6
|
+
class Host < Base
|
7
|
+
attr_accessor :graphs
|
8
|
+
attr_reader :cluster
|
9
|
+
|
10
|
+
def initialize(name, cluster, params={})
|
11
|
+
super(name, params)
|
12
|
+
@cluster = cluster
|
13
|
+
# hack for the case where colo{1,2}.host1 both exist
|
14
|
+
@@objects[self.class.to_s].delete(name)
|
15
|
+
@@objects[self.class.to_s]["#{cluster}#{name}"] = self
|
16
|
+
|
17
|
+
@graphs = []
|
18
|
+
Graph.each do |graph_name, graph|
|
19
|
+
graph["hosts"].each do |h|
|
20
|
+
if match(h)
|
21
|
+
@graphs << graph
|
22
|
+
break
|
23
|
+
end
|
24
|
+
end # graph["hosts"].each
|
25
|
+
end # Graph.each
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.find(name)
|
29
|
+
return @@objects[self.name][key] rescue []
|
30
|
+
end
|
31
|
+
|
32
|
+
def key
|
33
|
+
"#{@cluster}#{@name}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def eql?(other)
|
37
|
+
key == other.key
|
38
|
+
end
|
39
|
+
|
40
|
+
def ==(other)
|
41
|
+
key == other.key
|
42
|
+
end
|
43
|
+
|
44
|
+
def <=>(other)
|
45
|
+
if @params[:host_sort] == "builtin"
|
46
|
+
return key <=> other.key
|
47
|
+
elsif @params[:host_sort] == "numeric"
|
48
|
+
regex = /\d+/
|
49
|
+
match = @name.match(regex)
|
50
|
+
match2 = other.name.match(regex)
|
51
|
+
if match.pre_match != match2.pre_match
|
52
|
+
return match.pre_match <=> match2.pre_match
|
53
|
+
else
|
54
|
+
return match[0].to_i <=> match2[0].to_i
|
55
|
+
end
|
56
|
+
else
|
57
|
+
# http://www.bofh.org.uk/2007/12/16/comprehensible-sorting-in-ruby
|
58
|
+
sensible = lambda do |k|
|
59
|
+
k.to_s.split(
|
60
|
+
/((?:(?:^|\s)[-+])?(?:\.\d+|\d+(?:\.\d+?(?:[eE]\d+)?(?:$|(?![eE\.])))?))/ms
|
61
|
+
).map { |v| Float(v) rescue v.downcase }
|
62
|
+
end
|
63
|
+
return sensible.call(self) <=> sensible.call(other)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def hash
|
68
|
+
key.hash
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.find_by_name_and_cluster(name, cluster)
|
72
|
+
Host.each do |host_name, host|
|
73
|
+
next unless host.name == name
|
74
|
+
return host if host.cluster == cluster
|
75
|
+
end
|
76
|
+
return nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.find_by_cluster(cluster)
|
80
|
+
ret = []
|
81
|
+
Host.each do |name, host|
|
82
|
+
ret << host if host.cluster == cluster
|
83
|
+
end
|
84
|
+
return ret
|
85
|
+
end
|
86
|
+
|
87
|
+
end # Pencil::Models::Host
|
88
|
+
end # Pencil::Models
|
89
|
+
end
|
data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_flat_30_cccccc_40x100.png
RENAMED
File without changes
|
data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_flat_50_5c5c5c_40x100.png
RENAMED
File without changes
|
data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_glass_20_333333_1x400.png
RENAMED
File without changes
|
data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_glass_40_000000_1x400.png
RENAMED
File without changes
|
data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_glass_40_ffc73d_1x400.png
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-icons_222222_256x240.png
RENAMED
File without changes
|
data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-icons_4b8e0b_256x240.png
RENAMED
File without changes
|
data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-icons_a83300_256x240.png
RENAMED
File without changes
|
data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-icons_cccccc_256x240.png
RENAMED
File without changes
|
data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-icons_ffffff_256x240.png
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|