pencil 0.2.10 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/bin/pencil +2 -6
  2. data/docs/pencil_options.md +3 -1
  3. data/lib/{config.rb → pencil/config.rb} +29 -9
  4. data/lib/pencil/config.ru +2 -0
  5. data/lib/pencil/helpers.rb +211 -0
  6. data/lib/pencil/models/base.rb +78 -0
  7. data/lib/pencil/models/dashboard.rb +124 -0
  8. data/lib/pencil/models/graph.rb +394 -0
  9. data/lib/pencil/models/host.rb +89 -0
  10. data/lib/pencil/models.rb +3 -0
  11. data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_flat_30_cccccc_40x100.png +0 -0
  12. data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_flat_50_5c5c5c_40x100.png +0 -0
  13. data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_glass_20_333333_1x400.png +0 -0
  14. data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_glass_40_000000_1x400.png +0 -0
  15. data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_glass_40_ffc73d_1x400.png +0 -0
  16. data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_gloss-wave_25_333333_500x100.png +0 -0
  17. data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_highlight-soft_15_000000_1x100.png +0 -0
  18. data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_highlight-soft_80_eeeeee_1x100.png +0 -0
  19. data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-bg_inset-soft_30_ff4e0a_1x100.png +0 -0
  20. data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-icons_222222_256x240.png +0 -0
  21. data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-icons_4b8e0b_256x240.png +0 -0
  22. data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-icons_a83300_256x240.png +0 -0
  23. data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-icons_cccccc_256x240.png +0 -0
  24. data/lib/{public → pencil/public}/css/jquery_themes/pencil/images/ui-icons_ffffff_256x240.png +0 -0
  25. data/lib/{public → pencil/public}/css/jquery_themes/pencil/jquery-ui-1.8.16.custom.css +0 -0
  26. data/lib/{public → pencil/public}/css/thedoc.css +1 -0
  27. data/lib/{public → pencil/public}/favicon.ico +0 -0
  28. data/lib/{public → pencil/public}/js/cufon.js +0 -0
  29. data/lib/{public → pencil/public}/js/gotham.font.js +0 -0
  30. data/lib/{public → pencil/public}/js/jquery-1.6.2.min.js +0 -0
  31. data/lib/{public → pencil/public}/js/jquery-ui-1.8.16.custom.min.js +0 -0
  32. data/lib/{public → pencil/public}/js/pencil.js +0 -0
  33. data/lib/{public → pencil/public}/js/product-design.font.js +0 -0
  34. data/lib/pencil/public/style.css +307 -0
  35. data/lib/{rubyfixes.rb → pencil/rubyfixes.rb} +0 -0
  36. data/lib/pencil/version.rb +3 -0
  37. data/lib/{views → pencil/views}/cluster.erb +1 -1
  38. data/lib/{views → pencil/views}/dash-cluster-zoom.erb +2 -2
  39. data/lib/{views → pencil/views}/dash-cluster.erb +1 -1
  40. data/lib/{views → pencil/views}/dash-global-zoom.erb +2 -2
  41. data/lib/{views → pencil/views}/dash-global.erb +1 -1
  42. data/lib/{views → pencil/views}/global.erb +1 -1
  43. data/lib/{views → pencil/views}/host.erb +1 -1
  44. data/lib/{views → pencil/views}/layout.erb +2 -2
  45. data/lib/{views → pencil/views}/partials/cluster_selector.erb +0 -0
  46. data/lib/{views → pencil/views}/partials/cluster_switcher.erb +0 -0
  47. data/lib/{views → pencil/views}/partials/dash_switcher.erb +0 -0
  48. data/lib/{views → pencil/views}/partials/graph_switcher.erb +0 -0
  49. data/lib/{views → pencil/views}/partials/hosts_selector.erb +0 -0
  50. data/lib/{views → pencil/views}/partials/input_boxes.erb +0 -0
  51. data/lib/{views → pencil/views}/partials/shortcuts.erb +0 -0
  52. data/lib/{dash.rb → pencil.rb} +14 -17
  53. metadata +57 -58
  54. data/VERSION.rb +0 -1
  55. data/lib/config.ru +0 -2
  56. data/lib/helpers.rb +0 -209
  57. data/lib/models/base.rb +0 -73
  58. data/lib/models/dashboard.rb +0 -111
  59. data/lib/models/graph.rb +0 -367
  60. data/lib/models/host.rb +0 -87
  61. data/lib/models.rb +0 -3
  62. data/lib/namespace.rb +0 -4
  63. data/lib/public/style.css +0 -97
data/lib/models/graph.rb DELETED
@@ -1,367 +0,0 @@
1
- require "models/base"
2
- require "uri"
3
-
4
- module Dash::Models
5
- class Graph < Base
6
- def initialize(name, params={})
7
- super
8
-
9
- @params["hosts"] ||= ["*"]
10
- @params["title"] ||= name
11
-
12
- if not @params["targets"]
13
- raise ArgumentError, "graph #{name} needs a 'targets' map"
14
- end
15
- end
16
-
17
- # fixme parameters in general
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
- # inner means we're dealing with a complex key; @params will be applied
86
- def handle_metric(name, opts, inner=false)
87
- ret = name.dup
88
- if inner
89
- @params.each do |k, v|
90
- ret = translate(k, ret, v, true)
91
- end
92
- end
93
- (opts||{}).each do |k, v|
94
- #puts "#{k} => #{v}"
95
- ret = translate(k, ret, v)
96
- end
97
- ret
98
- end
99
-
100
- def render_url(hosts, clusters, opts={})
101
- opts = {
102
- :sum => nil,
103
- :title => @params["title"],
104
- }.merge(opts)
105
-
106
- if ! [:global, :cluster, nil].member?(opts[:sum])
107
- raise ArgumentError, "render graph #{name}: invalid :sum - #{opts[:sum]}"
108
- end
109
-
110
- sym_hash = {}
111
- (opts[:dynamic_url_opts]||[]).each do |k,v|
112
- sym_hash[k.to_sym] = v
113
- end
114
-
115
- # fixme key checking may be necessary
116
- url_opts = {
117
- :title => opts[:title],
118
- }.merge(@params[:url_opts]).merge(sym_hash)
119
-
120
- url_opts[:from] = url_opts.delete(:stime) || ""
121
- url_opts[:until] = url_opts.delete(:etime) || ""
122
- url_opts.delete(:start)
123
- url_opts.delete(:duration)
124
-
125
- graphite_opts = [ "vtitle", "yMin", "yMax", "lineWidth", "areaMode",
126
- "template", "lineMode", "bgcolor", "graphOnly", "hideAxes", "hideGrid",
127
- "hideLegend", "fgcolor", "fontSize", "fontName", "fontItalic",
128
- "fontBold" ]
129
-
130
- @params.each do |k, v|
131
- if graphite_opts.member?(k)
132
- url_opts[k.to_sym] = v
133
- end
134
- end
135
-
136
- target = []
137
- colors = []
138
- #FIXME code duplication
139
- if opts[:sum] == :global
140
- @params["targets"].each do |stat_name, opts|
141
- z = Marshal.load(Marshal.dump(opts))
142
- z[:key] ||= stat_name
143
- #######################
144
- if stat_name.instance_of?(Array)
145
- metric = stat_name.map do |m|
146
- mm = compose_metric(m.keys.first,
147
- "{#{clusters.to_a.join(',')}}",
148
- "{#{hosts.to_a.join(',')}}")
149
-
150
- if z.keys.member?(:divideSeries)
151
- handle_metric(translate(:sumSeries, mm),
152
- m[m.keys.first], true)
153
- else
154
- handle_metric(mm, m[m.keys.first], true)
155
- end
156
- end.join(",")
157
- else
158
- metric = compose_metric(stat_name,
159
- "{#{clusters.to_a.join(',')}}",
160
- "{#{hosts.to_a.join(',')}}")
161
- metric = handle_metric(metric, {}, true)
162
- end
163
- #######################
164
- z[:key] = "global #{z[:key]}"
165
- # target << handle_metric(translate(:sumSeries, metric), z)
166
-
167
- if z.keys.member?(:divideSeries) # special case
168
- # apply divideSeries, sumSeries then other options
169
- res = translate(:divideSeries, metric)
170
- res = translate(:sumSeries, res)
171
- z.delete(:divideSeries)
172
- h = YAML::Omap.new
173
- z.each { |k,v| h[k] = v unless k == :divideSeries }
174
- target << handle_metric(res, h)
175
- else
176
- target << handle_metric(translate(:sumSeries, metric), z)
177
- end
178
- if !@params[:use_color] ||
179
- (!z[:color] && @params[:use_color])
180
- colors << next_color(colors, z[:color])
181
- end
182
- end # @params["targets"].each
183
- elsif opts[:sum] == :cluster # one line per cluster/metric
184
- clusters.each do |cluster|
185
- @params["targets"].each do |stat_name, opts|
186
- z = Marshal.load(Marshal.dump(opts))
187
- metrics = []
188
- #######################
189
- h = "{#{hosts.to_a.join(',')}}"
190
- if stat_name.instance_of?(Array)
191
- metrics << stat_name.map do |m|
192
- mm = compose_metric(m.keys.first, cluster, h)
193
- # note: we take the ratio of the sums in this case, instead of
194
- # the sums of the ratios
195
- if z.keys.member?(:divideSeries)
196
- # divideSeries is picky about the number of series given as
197
- # arguments, so sum them in this case
198
- handle_metric(translate(:sumSeries, mm),
199
- m[m.keys.first], true)
200
- else
201
- handle_metric(mm, m[m.keys.first], true)
202
- end
203
- end.join(",")
204
- else
205
- metrics << handle_metric(compose_metric(stat_name,
206
- cluster, h), {}, true)
207
- end
208
- #######################
209
- z[:key] = "#{cluster} #{z[:key]}"
210
-
211
- if z.keys.member?(:divideSeries) # special case
212
- # apply divideSeries, sumSeries then other options
213
- res = translate(:divideSeries, metrics.join(','))
214
- res = translate(:sumSeries, res)
215
- z.delete(:divideSeries)
216
- h = YAML::Omap.new
217
- z.each { |k,v| h[k] = v unless k == :divideSeries }
218
- target << handle_metric(res, h)
219
- else
220
- target << handle_metric(translate(:sumSeries,
221
- metrics.join(',')), z)
222
- end
223
-
224
- if !@params[:use_color] || (!z[:color] && @params[:use_color])
225
- colors << next_color(colors, z[:color])
226
- end
227
- end # metrics.each
228
- end # clusters.each
229
- else # one line per {metric,host,colo}
230
- @params["targets"].each do |stat_name, opts|
231
- clusters.each do |cluster|
232
- hosts.each do |host|
233
- label = "#{host} #{opts[:key]}"
234
- #################
235
- if stat_name.instance_of?(Array)
236
- metric = stat_name.map do |m|
237
- mm = compose_metric(m.keys.first, cluster, host)
238
- handle_metric(mm, m[m.keys.first], true)
239
- end.join(",")
240
- else
241
- metric = handle_metric(compose_metric(stat_name, cluster, host), {}, true)
242
- end
243
- #################
244
-
245
- if label =~ /\*/
246
- # for this particular type of graph, don't display a legend,
247
- # and color with abandon
248
- url_opts[:hideLegend] = true
249
- z = Marshal.load(Marshal.dump(opts))
250
- z.delete(:color)
251
- # fixme proper labeling... maybe
252
- # With wildcards let graphite construct the legend (or not).
253
- # Since we're handling wildcards we don't know how many
254
- # hosts will match, so just put in the default color list.
255
- # technically we do know, so this can be fixed
256
- z.delete(:key)
257
- target << handle_metric(metric, z)
258
- colors.concat(@params[:default_colors]) if colors.empty?
259
- else
260
- z = Marshal.load(Marshal.dump(opts))
261
- z[:key] = "#{host}/#{cluster} #{z[:key]}"
262
- target << handle_metric(metric, z)
263
- if !@params[:use_color] ||
264
- (!opts[:color] && @params[:use_color])
265
- colors << next_color(colors, opts[:color])
266
- end
267
- end
268
- end
269
- end
270
- end # @params["targets"].each
271
- end # if opts[:sum]
272
-
273
- url_opts[:target] = target
274
- url_opts[:colorList] = colors.join(",")
275
-
276
- url = URI.join(@params[:graphite_url], "/render/?").to_s
277
- url_parts = []
278
- url_opts.each do |k, v|
279
- [v].flatten.each do |v|
280
- url_parts << "#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}"
281
- end
282
- end
283
- url += url_parts.join("&")
284
- return url
285
- end
286
-
287
- # return an array of all metrics matching the specifications in
288
- # @params["targets"]
289
- # metrics are arrays of fields (once delimited by periods)
290
- def expand
291
- url = URI.join(@params[:graphite_url], "/metrics/expand/?query=").to_s
292
- metrics = []
293
-
294
- @params["targets"].each do |metric|
295
- if metric.first.instance_of?(Array)
296
- metric.first.each do |m|
297
- composed = compose_metric(m.first.first, "*", "*")
298
- query = open("#{url}#{composed}").read
299
- metrics << JSON.parse(query)["results"]
300
- end
301
- else
302
- composed = compose_metric(metric.first.first, "*", "*")
303
- query = open("#{url}#{composed}").read
304
- metrics << JSON.parse(query)["results"]
305
- end
306
- end
307
-
308
- return metrics.flatten.map { |x| x.split(".") }
309
- end
310
-
311
- def hosts_clusters
312
- metrics = expand
313
- clusters = Set.new
314
-
315
- # find the indicies of the clusters and hosts
316
- f = @params[:metric_format].dup.split("%m")
317
- first = f.first.split(".")
318
- last = f.last.split(".")
319
- ci = hi = nil
320
- first.each_with_index do |v, i|
321
- ci = i if v.match("%c")
322
- hi = i if v.match("%h")
323
- end
324
- unless ci && hi
325
- last.reverse.each_with_index do |v, i|
326
- ci = -1 -i if v.match("%c")
327
- hi = -1 -i if v.match("%h")
328
- end
329
- end
330
- hosts = metrics.map do |m|
331
- Host.new(m[hi], m[ci], @params)
332
- end.uniq
333
-
334
- # filter by what matches the graph definition
335
- hosts = hosts.select { |h| h.multi_match(@params["hosts"]) }
336
- hosts.each { |h| clusters << h.cluster }
337
-
338
- return hosts, clusters
339
- end
340
-
341
- private
342
- def next_color(colors, preferred_color=nil)
343
- default_colors = @params[:default_colors].clone
344
-
345
- if preferred_color and !colors.member?(preferred_color)
346
- return preferred_color
347
- end
348
-
349
- if preferred_color and ! default_colors.member?(preferred_color)
350
- default_colors << preferred_color
351
- end
352
-
353
- weights = Hash.new(0)
354
- colors.each do |c|
355
- weights[c] += 1
356
- end
357
-
358
- i = 0
359
- loop do
360
- default_colors.each do |c|
361
- return c if weights[c] == i
362
- end
363
- i += 1
364
- end
365
- end
366
- end # Dash::Models::Graph
367
- end # Dash::Models
data/lib/models/host.rb DELETED
@@ -1,87 +0,0 @@
1
- require "models/base"
2
- require "models/graph"
3
-
4
- module Dash::Models
5
- class Host < Base
6
- attr_accessor :graphs
7
- attr_reader :cluster
8
-
9
- def initialize(name, cluster, params={})
10
- super(name, params)
11
- @cluster = cluster
12
- # hack for the case where colo{1,2}.host1 both exist
13
- @@objects[self.class.to_s].delete(name)
14
- @@objects[self.class.to_s]["#{cluster}#{name}"] = self
15
-
16
- @graphs = []
17
- Graph.each do |graph_name, graph|
18
- graph["hosts"].each do |h|
19
- if match(h)
20
- @graphs << graph
21
- break
22
- end
23
- end # graph["hosts"].each
24
- end # Graph.each
25
- end
26
-
27
- def self.find(name)
28
- return @@objects[self.name][key] rescue []
29
- end
30
-
31
- def key
32
- "#{@cluster}#{@name}"
33
- end
34
-
35
- def eql?(other)
36
- key == other.key
37
- end
38
-
39
- def ==(other)
40
- key == other.key
41
- end
42
-
43
- def <=>(other)
44
- if @params[:host_sort] == "builtin"
45
- return key <=> other.key
46
- elsif @params[:host_sort] == "numeric"
47
- regex = /\d+/
48
- match = @name.match(regex)
49
- match2 = other.name.match(regex)
50
- if match.pre_match != match2.pre_match
51
- return match.pre_match <=> match2.pre_match
52
- else
53
- return match[0].to_i <=> match2[0].to_i
54
- end
55
- else
56
- # http://www.bofh.org.uk/2007/12/16/comprehensible-sorting-in-ruby
57
- sensible = lambda do |k|
58
- k.to_s.split(
59
- /((?:(?:^|\s)[-+])?(?:\.\d+|\d+(?:\.\d+?(?:[eE]\d+)?(?:$|(?![eE\.])))?))/ms
60
- ).map { |v| Float(v) rescue v.downcase }
61
- end
62
- return sensible.call(self) <=> sensible.call(other)
63
- end
64
- end
65
-
66
- def hash
67
- key.hash
68
- end
69
-
70
- def self.find_by_name_and_cluster(name, cluster)
71
- Host.each do |host_name, host|
72
- next unless host.name == name
73
- return host if host.cluster == cluster
74
- end
75
- return nil
76
- end
77
-
78
- def self.find_by_cluster(cluster)
79
- ret = []
80
- Host.each do |name, host|
81
- ret << host if host.cluster == cluster
82
- end
83
- return ret
84
- end
85
-
86
- end # Dash::Models::Host
87
- end # Dash::Models
data/lib/models.rb DELETED
@@ -1,3 +0,0 @@
1
- require "models/dashboard"
2
- require "models/graph"
3
- require "models/host"
data/lib/namespace.rb DELETED
@@ -1,4 +0,0 @@
1
- module Dash
2
- module Models
3
- end
4
- end
data/lib/public/style.css DELETED
@@ -1,97 +0,0 @@
1
- h2 {
2
- color: #ADFF2F;
3
- }
4
-
5
- h3 {
6
- color: #32cd32;
7
- }
8
-
9
- .graphtitle {
10
- text-shadow: 1px 1px 1px #333333;
11
- }
12
-
13
- .dashlinks {
14
- color: green;
15
- font-size: small;
16
- }
17
-
18
- a {
19
- color: #15317E;
20
- }
21
-
22
- a:visited {
23
- color: #15317E;
24
- }
25
-
26
- .graphsection {
27
- border: dotted 2px #333333;
28
- width: 500;
29
- margin-left: 5px;
30
- margin-top: 10px;
31
- }
32
-
33
- div#wrap {
34
- width: 100%;
35
- margin-top: 10px;
36
- margin-bottom: 10px;
37
- margin-left: auto;
38
- margin-right: auto;
39
- padding: 0px;
40
- }
41
-
42
- div#header {
43
- padding: 15px;
44
- margin: 0px;
45
- margin-left: 23%;
46
- }
47
-
48
- div#nav {
49
- width: 20%;
50
- padding: 10px;
51
- margin-top: 1px;
52
- float: left;
53
- color: green;
54
- }
55
-
56
- div#main {
57
- margin-left: 23%;
58
- margin-top: 1px;
59
- padding: 10px;
60
- color: #4CBB17;
61
- }
62
-
63
- div#footer {
64
- padding: 15px;
65
- margin: 0px;
66
- border-top: thin solid #808080;
67
- }
68
-
69
- table {
70
- color: green;
71
- }
72
-
73
- input {
74
- border: solid 1px #15317E;
75
- color: green;
76
- background-color: #1f1f1f;
77
- font-size: small;
78
- }
79
-
80
- .invisible {
81
- display: none;
82
- }
83
-
84
- select {
85
- border: solid 1px #15317E;
86
- color: green;
87
- background-color: #1f1f1f;
88
- }
89
-
90
- .select2 {
91
- color: #4CBB17;
92
- font-size: large;
93
- }
94
-
95
- .error {
96
- color: red;
97
- }