gri 10.0.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.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/MIT-LICENSE.txt +20 -0
  4. data/README.md +132 -0
  5. data/Rakefile +5 -0
  6. data/bin/grapher +17 -0
  7. data/bin/gri +5 -0
  8. data/bin/gricast +17 -0
  9. data/bin/grispark +5 -0
  10. data/bin/griwalk +9 -0
  11. data/bin/trad +19 -0
  12. data/bin/trad-http +17 -0
  13. data/gri.gemspec +21 -0
  14. data/lib/fluent/plugin/out_gri.rb +56 -0
  15. data/lib/gri/api.rb +28 -0
  16. data/lib/gri/app_collector.rb +154 -0
  17. data/lib/gri/app_walker.rb +23 -0
  18. data/lib/gri/blank.rb +49 -0
  19. data/lib/gri/builtindefs.rb +211 -0
  20. data/lib/gri/cast.rb +84 -0
  21. data/lib/gri/cgraph.rb +37 -0
  22. data/lib/gri/clist.rb +163 -0
  23. data/lib/gri/collector.rb +284 -0
  24. data/lib/gri/config.rb +134 -0
  25. data/lib/gri/ds_list.rb +166 -0
  26. data/lib/gri/format_helper.rb +112 -0
  27. data/lib/gri/gparams.rb +43 -0
  28. data/lib/gri/graph.rb +239 -0
  29. data/lib/gri/grapher.rb +70 -0
  30. data/lib/gri/ldb.rb +160 -0
  31. data/lib/gri/list.rb +242 -0
  32. data/lib/gri/log.rb +140 -0
  33. data/lib/gri/loop.rb +109 -0
  34. data/lib/gri/ltsv.rb +58 -0
  35. data/lib/gri/main.rb +107 -0
  36. data/lib/gri/mlog.rb +22 -0
  37. data/lib/gri/mmsgpack.rb +57 -0
  38. data/lib/gri/msnmp.rb +601 -0
  39. data/lib/gri/page.rb +235 -0
  40. data/lib/gri/pcollector.rb +209 -0
  41. data/lib/gri/plugin.rb +75 -0
  42. data/lib/gri/plugin/bootstrap.rb +65 -0
  43. data/lib/gri/plugin/cisco.rb +98 -0
  44. data/lib/gri/plugin/exec_collector.rb +89 -0
  45. data/lib/gri/plugin/juniper.rb +5 -0
  46. data/lib/gri/plugin/netsnmp.rb +8 -0
  47. data/lib/gri/plugin/ucdavis.rb +176 -0
  48. data/lib/gri/plugin/writer_fluentd.rb +26 -0
  49. data/lib/gri/polling_unit.rb +88 -0
  50. data/lib/gri/q.rb +5 -0
  51. data/lib/gri/request.rb +29 -0
  52. data/lib/gri/rrd.rb +438 -0
  53. data/lib/gri/scheduler.rb +68 -0
  54. data/lib/gri/sgraph.rb +147 -0
  55. data/lib/gri/spark.rb +94 -0
  56. data/lib/gri/tra_collector.rb +80 -0
  57. data/lib/gri/trad.rb +170 -0
  58. data/lib/gri/updater.rb +201 -0
  59. data/lib/gri/util_daemon.rb +19 -0
  60. data/lib/gri/util_marshal.rb +13 -0
  61. data/lib/gri/utils.rb +63 -0
  62. data/lib/gri/vendor.rb +76 -0
  63. data/lib/gri/version.rb +3 -0
  64. data/lib/gri/wmain.rb +67 -0
  65. data/lib/gri/writer.rb +184 -0
  66. data/mcollector +47 -0
  67. data/test/mock.rb +60 -0
  68. data/test/root/gra/.sysdb/sysdb.txt +3 -0
  69. data/test/root/gra/testhost/.records.txt +2 -0
  70. data/test/root/if.def +2 -0
  71. data/test/root/test.conf +4 -0
  72. data/test/root/testtab +9 -0
  73. data/test/root/testtab2 +2 -0
  74. data/test/root/tra/testhost/_/20130614 +20 -0
  75. data/test/test_app.rb +58 -0
  76. data/test/test_builtindefs.rb +24 -0
  77. data/test/test_collector.rb +58 -0
  78. data/test/test_config.rb +62 -0
  79. data/test/test_ds_list.rb +48 -0
  80. data/test/test_exec_collector.rb +33 -0
  81. data/test/test_format_helper.rb +68 -0
  82. data/test/test_graph.rb +69 -0
  83. data/test/test_ldb.rb +29 -0
  84. data/test/test_list.rb +65 -0
  85. data/test/test_log.rb +16 -0
  86. data/test/test_loop.rb +35 -0
  87. data/test/test_ltsv.rb +38 -0
  88. data/test/test_main.rb +19 -0
  89. data/test/test_mmsgpack.rb +27 -0
  90. data/test/test_msnmp.rb +147 -0
  91. data/test/test_page.rb +51 -0
  92. data/test/test_pcollector.rb +71 -0
  93. data/test/test_plugin.rb +62 -0
  94. data/test/test_plugin_cisco.rb +23 -0
  95. data/test/test_polling_unit.rb +58 -0
  96. data/test/test_request.rb +26 -0
  97. data/test/test_rrd.rb +53 -0
  98. data/test/test_rrd_updater.rb +139 -0
  99. data/test/test_scheduler.rb +31 -0
  100. data/test/test_tra_collector.rb +40 -0
  101. data/test/test_trad.rb +33 -0
  102. data/test/test_util_marshal.rb +17 -0
  103. data/test/test_utils.rb +15 -0
  104. data/test/test_vendor.rb +40 -0
  105. data/test/test_writer.rb +33 -0
  106. data/test/unittest_helper.rb +27 -0
  107. metadata +208 -0
@@ -0,0 +1,284 @@
1
+ #require 'gri/utils'
2
+ require 'gri/msnmp'
3
+ require 'gri/vendor'
4
+ require 'gri/polling_unit'
5
+
6
+ module GRI
7
+ class Collector
8
+ TYPES = {}
9
+
10
+ attr_reader :host, :options
11
+ attr_reader :loop, :attached_at
12
+ attr_accessor :interval, :timeout
13
+
14
+ def self.create col_type, host, options, fake_descr_hash={}, &cb
15
+ if (klass = TYPES[col_type])
16
+ klass.new host, options, fake_descr_hash, &cb
17
+ end
18
+ end
19
+
20
+ def initialize host, options, fake_descr_hash, &cb
21
+ @host = host
22
+ @options = options
23
+ @cname = @options['cname']
24
+ @hostname = @options['hostname'] || @options['alias']
25
+ @fake_descr_hash = fake_descr_hash || {}
26
+ @cb = cb
27
+ @buffers = []
28
+ @results = []
29
+ @on_error = nil
30
+ @on_retry = nil
31
+ on_init
32
+ end
33
+
34
+ def sync?; true; end
35
+
36
+ def on_init
37
+ end
38
+
39
+ def attach loop
40
+ @loop = loop
41
+ on_attach
42
+ end
43
+
44
+ def on_attach
45
+ end
46
+
47
+ def on_detach
48
+ end
49
+
50
+ def on_timeout
51
+ end
52
+
53
+ def on_error &block
54
+ @on_error = block
55
+ end
56
+
57
+ def on_retry &block
58
+ @on_retry = block
59
+ end
60
+ end
61
+
62
+ class SNMPCollector < Collector
63
+ TYPES['snmp'] = self
64
+ SYSOIDS = BER.enc_oid_list(['sysDescr', 'sysName', 'sysObjectID',
65
+ 'sysUpTime', 'sysLocation'].map {|n|
66
+ oid = SNMP::OIDS[n] + '.0'
67
+ SNMP.add_oid n + '.0', oid
68
+ oid})
69
+
70
+ def sync?; false; end
71
+
72
+ def on_attach
73
+ now = Time.now
74
+ now_i = now.to_i
75
+ @attached_at = now
76
+ @results.clear
77
+ @tout = 5
78
+ @preq = nil
79
+ @snmp = SNMP.new(@cname || @host, options['port'])
80
+ @snmp.version = options['ver'] if options['ver']
81
+ @snmp.community = options['community'] if options['community']
82
+
83
+ varbind = SYSOIDS
84
+ get(varbind) {|results|
85
+ sysinfo = {'_host'=>(@hostname || host),
86
+ '_key'=>'SYS', '_time'=>now_i, '_mtime'=>now_i}
87
+ results.each {|enoid, tag, val|
88
+ (k = SNMP::ROIDS[enoid]) and sysinfo[k.sub(/\.0$/, '')] = val
89
+ }
90
+ sysinfo['sysDescr'] and sysinfo['sysDescr'].gsub!("\n", ' ')
91
+
92
+ vendor = Vendor.check sysinfo, options
93
+ puts "snmp: #{host} (#{vendor.name}): #{vendor.options.inspect}" if $debug
94
+ @snmp.version = vendor.options['ver'] if vendor.options['ver']
95
+ punits = vendor.get_punits
96
+ punits_d = punits.dup
97
+ @workhash = punits.inject({}) {|h, pu| h[pu.cat] = {}; h}
98
+ poll1(punits) {
99
+ if !options.has_key?('SYS') or options['SYS']
100
+ sysinfo.delete 'sysObjectID'
101
+ records = [sysinfo]
102
+ else
103
+ records = []
104
+ end
105
+ hfdh = @fake_descr_hash[host]
106
+
107
+ @workhash[:interfaces] = @workhash[''] #
108
+ for pu in punits_d
109
+ join_cat, join_key = pu.defs[:join]
110
+ if join_cat
111
+ for cat, wh in @workhash[pu.cat]
112
+ if wh and @workhash[join_cat]
113
+ join_hash = @workhash[join_cat][wh[join_key]]
114
+ wh.merge! join_hash if join_hash
115
+ end
116
+ end
117
+ end
118
+ pu.fix_workhash @workhash
119
+ end
120
+ @workhash.delete :interfaces #
121
+
122
+ for cat, wh in @workhash
123
+ (specs = DEFS.get_specs cat) and
124
+ (index_key = specs[:index_key] || specs[:named_index])
125
+ for ind, h in wh
126
+ h['_host'] = @hostname || host
127
+ h['_key'] = if index_key
128
+ next if h[index_key].to_s.empty?
129
+ "#{cat}_#{key_encode h[index_key]}"
130
+ elsif ind.kind_of? Integer
131
+ "#{cat}#{ind}"
132
+ elsif ind.kind_of? Array
133
+ "#{cat}_#{ind.join(',')}"
134
+ else
135
+ "#{cat}_#{ind}"
136
+ end
137
+ h['_interval'] = @interval
138
+ h['_time'] = now_i
139
+ if hfdh and (f_descr = hfdh[h['_key']]) and
140
+ (prop = specs[:prop]) and (descr_k = prop[:description])
141
+ h[descr_k] = f_descr
142
+ end
143
+ puts " record #{h.inspect}" if h['_d']
144
+ records.push h
145
+ end
146
+ end
147
+ @cb.call records
148
+ @loop.detach self
149
+ }
150
+ }
151
+ end
152
+
153
+ def on_detach
154
+ @snmp.close rescue nil
155
+ end
156
+
157
+ def key_encode s
158
+ s.to_s.gsub(/[:\/]/, '-').gsub(/[ =]/, '_').gsub(/[^-a-zA-Z0-9_.]/) { #/
159
+ "%02X"%$&.unpack('C').first}
160
+ end
161
+
162
+ def poll1 punits, &cb
163
+ if punits.empty?
164
+ cb.call
165
+ else
166
+ pu = punits.shift
167
+ puts " poll #{host} #{pu.name}" if $debug
168
+ @get_oid_buf = []
169
+ oids = pu.oids.dup
170
+ walk1(pu, oids) {poll1 punits, &cb}
171
+ end
172
+ end
173
+
174
+ def walk1 pu, oids, &cb
175
+ wh = @workhash[pu.cat]
176
+ if oids.empty?
177
+ if @get_oid_buf.empty?
178
+ cb.call
179
+ else
180
+ varbind = BER.cat_enoid @get_oid_buf
181
+ get(varbind) {|results|
182
+ results.each {|enoid, tag, val| pu.feed wh, enoid, tag, val}
183
+ cb.call
184
+ }
185
+ end
186
+ else
187
+ if (req_enoid = oids.shift) and req_enoid.getbyte(-1) == 0
188
+ @get_oid_buf.push req_enoid
189
+ walk1 pu, oids, &cb
190
+ else
191
+ walk(req_enoid) {|results|
192
+ results.each {|enoid, tag, val| pu.feed wh, enoid, tag, val}
193
+ walk1 pu, oids, &cb
194
+ }
195
+ end
196
+ end
197
+ end
198
+
199
+ def walk enoid, &cb
200
+ @results.clear
201
+ @retry_count = 0
202
+ @poll_cb = cb
203
+ @snmp.connect unless @snmp.sock
204
+ @snmp.walk_start(enoid) {|*res| @results.push res}
205
+ send_req enoid
206
+ rescue SocketError
207
+ @loop.detach self
208
+ @on_error.call if @on_error
209
+ Log.error "#{host}: error"
210
+ end
211
+
212
+ def get varbind, &cb
213
+ @results.clear
214
+ @retry_count = 0
215
+ @poll_cb = cb
216
+ @snmp.connect unless @snmp.sock
217
+ @snmp.get_start(varbind) {|*res| @results.push res}
218
+ send_req varbind
219
+ rescue SocketError
220
+ @loop.detach self
221
+ @on_error.call if @on_error
222
+ Log.error "#{host}: error"
223
+ end
224
+
225
+ def send_req arg
226
+ @preq = [@snmp.state, arg]
227
+ s = @snmp.make_req @snmp.state, arg
228
+ if @retry_count > 0
229
+ Log.debug "retry send_req, #{@buffers.size}"
230
+ end
231
+ @buffers.push s
232
+ loop.watch @snmp.sock, :w, @tout, self
233
+ end
234
+
235
+ def retry
236
+ if (@retry_count += 1) > 3
237
+ @loop.detach self
238
+ @on_error.call if @on_error
239
+ Log.error "#{host}: error"
240
+ elsif @preq
241
+ Log.warn "#{host}: retry #{@retry_count}"
242
+ @on_retry.call if @on_retry
243
+ @buffers.push @preq.last
244
+ loop.watch @snmp.sock, :w, @tout, self
245
+ else
246
+ @loop.detach self
247
+ @on_error.call if @on_error
248
+ Log.error "#{host}: cannot retry: #{@retry_count}"
249
+ end
250
+ end
251
+
252
+ def on_writable io=nil
253
+ unless @buffers.empty?
254
+ @snmp.sock.send @buffers.join(''), 0
255
+ @buffers.clear
256
+ loop.watch @snmp.sock, :r, @tout, self
257
+ end
258
+ end
259
+
260
+ def on_readable io=nil
261
+ msg = @snmp.sock.recv 2000, 0
262
+ arg = @snmp.recv_msg msg
263
+ if arg
264
+ @snmp.state = :SUCCESS if @snmp.state == :GET_REQ
265
+ end
266
+ if @snmp.state == :SUCCESS
267
+ @poll_cb.call @results
268
+ @preq = nil
269
+ elsif @snmp.state != :IDLE
270
+ send_req arg if arg
271
+ end
272
+ rescue SystemCallError
273
+ @snmp.state = :IDLE
274
+ Log.error "#{@host}: ERROR: #{$!}"
275
+ @loop.detach self
276
+ @on_error.call if @on_error
277
+ end
278
+
279
+ def on_timeout
280
+ Log.error "#{@host}: ERROR: timeout"
281
+ @on_error.call if @on_error
282
+ end
283
+ end
284
+ end
data/lib/gri/config.rb ADDED
@@ -0,0 +1,134 @@
1
+ module GRI
2
+ class Config
3
+ ROOT_PATH = '/usr/local/gri'
4
+ DEFAULT_PATH = ROOT_PATH + '/gri.conf'
5
+
6
+ def initialize
7
+ @h = {}
8
+ end
9
+
10
+ def setvar key, value
11
+ @h[key] = (Array === value) ? value : [value]
12
+ end
13
+
14
+ def getvar key
15
+ @h[key]
16
+ end
17
+
18
+ def []=(key, value)
19
+ (@h[key] ||= []).push value
20
+ end
21
+
22
+ def [](key)
23
+ (Array === (v = @h[key])) ? v.last : v
24
+ end
25
+
26
+ def keys
27
+ @h.keys
28
+ end
29
+
30
+ def has_key? key
31
+ @h.has_key? key
32
+ end
33
+
34
+ def to_h
35
+ @h.inject({}) {|h, item|
36
+ k, v = item
37
+ h[k] = (item.last.size > 1) ? v : v.first
38
+ h
39
+ }
40
+ end
41
+
42
+ def self.load_from_file path
43
+ conf = self.new
44
+ if File.exist? path
45
+ File.open(path) {|f|
46
+ while line = f.gets
47
+ line.chomp!
48
+ next if line =~ /^\s*(#|$)/
49
+ if line =~ /^\s*(\S+)\s+(.*)/
50
+ key, value = $1, $2
51
+ conf[key] = value
52
+ end
53
+ end
54
+ }
55
+ end
56
+ conf
57
+ end
58
+
59
+ def self.init path=nil
60
+ @config = path ? load_from_file(path) : new
61
+ end
62
+
63
+ def self.setvar key, value
64
+ @config.setvar key, value
65
+ end
66
+
67
+ def self.getvar key
68
+ @config.getvar key
69
+ end
70
+
71
+ def self.[]=(key, value)
72
+ @config[key] = value
73
+ end
74
+
75
+ def self.[](key)
76
+ @config[key]
77
+ end
78
+
79
+ def self.keys
80
+ @config.keys
81
+ end
82
+
83
+ def self.has_key? key
84
+ @config.has_key? key
85
+ end
86
+
87
+ def self.parse_options(*strs)
88
+ options = {}
89
+ for s in strs
90
+ next unless s
91
+ for var, value in s.scan(/([^=\s]+)(?:=((?:`[^`]+`)|(?:"[^"]+")|\S+))?/)
92
+ if value
93
+ if value =~ /^[`"]([^`"]+)[`"]/
94
+ value = $1
95
+ end
96
+ options[var] = value
97
+ else
98
+ if var =~ /^no-/
99
+ options[$~.post_match] = false
100
+ else
101
+ options[var] = var
102
+ end
103
+ end
104
+ end
105
+ end
106
+ options
107
+ end
108
+
109
+ def self.option_if_match matchstr, varname, config
110
+ h = {}
111
+ if (varlines = config.getvar varname)
112
+ for line in varlines
113
+ pat, *optstr = line.split
114
+ if matchstr =~ Regexp.new(pat)
115
+ h.merge!(parse_options(*optstr))
116
+ end
117
+ end
118
+ end
119
+ h
120
+ end
121
+
122
+ def self.get_targets_from_lines lines
123
+ targets = []
124
+ for line in lines
125
+ if line =~ /^\s*(\w\S*)(?:\s+(.*))?/
126
+ host, remain = $1, $2
127
+ options = parse_options remain
128
+ targets.push [host, options]
129
+ end
130
+ end
131
+ targets
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,166 @@
1
+ require 'gri/utils'
2
+ require 'gri/builtindefs'
3
+ require 'gri/format_helper'
4
+
5
+ module GRI
6
+ class DSList
7
+ include Utils
8
+ include FormatHelper
9
+ SORT_PROC = {
10
+ :by_name=>Proc.new {|a, b|
11
+ (cmp = a.first.to_s.gsub(/(\d+)/) {"%06d"%$1.to_i} <=>
12
+ b.first.to_s.gsub(/(\d+)/) {"%06d"%$1.to_i}).zero? ?
13
+ a.first <=> b.first : cmp
14
+ }
15
+ }
16
+
17
+ def initialize options={}
18
+ @options = options
19
+ end
20
+
21
+ def call env
22
+ req = Rack::Request.new env
23
+ dirs = @options[:dirs]
24
+
25
+ list_item = env['PATH_INFO'] || ''
26
+ host = File.basename list_item
27
+ gra_dir, records = search_records dirs, host
28
+ return [404, {}, ['Not Found']] unless gra_dir
29
+ dir = gra_dir + list_item
30
+ sysinfo = records['SYS'] || {}
31
+ data_hash = get_data_hash records
32
+ data_names = data_hash.keys.sort
33
+
34
+ @title = host
35
+ body = render(Grapher.layout) {render template, binding}
36
+ [200, {'Content-type' => 'text/html'}, [body]]
37
+ end
38
+
39
+ def get_data_hash records
40
+ h = {}
41
+ for key, record in records
42
+ next if !key or key == 'SYS'
43
+ data_name, index = parse_key key
44
+ next unless data_name
45
+ specs = DEFS.get_specs data_name
46
+ next unless specs and (specs[:list] or specs[:list_text])
47
+ next if specs[:hidden?] and specs[:hidden?].call(record)
48
+ record['_index'] = index; record[:key] = index
49
+ if specs[:prop]
50
+ specs[:prop].each {|k1, k2| record[k1] = record[k2] if record[k2]}
51
+ record[:name] ||= specs[:prop][:name]
52
+ end
53
+ h[data_name] ||= []
54
+ h[data_name] << [key, record, nil]
55
+ end
56
+ h
57
+ end
58
+
59
+ def format_data_list dir, data_name, items
60
+ host = File.basename dir
61
+ specs = DEFS.get_specs data_name
62
+ hdstr, pat = specs[:list] || specs[:list_text]
63
+ hds = (Array === hdstr) ? hdstr : hdstr.split(',')
64
+ formats = (pat || '%N').split(',')
65
+
66
+ p0 = ((hds.size == formats.size) ?
67
+ [hds.map {|hd| td(h(hd), :head=>true)}] :
68
+ [[td(h(hds.join('.')), :head=>true, :colspan=>formats.size)]])
69
+ ckeys = []
70
+ p1 = items.sort(&SORT_PROC[:by_name]).map {|key, prop|
71
+ host_key = "#{host}_#{key}"
72
+ href = File.exist?("#{dir}/#{host_key}.rrd") ?
73
+ (ckeys.push key; url_to("?r=#{host_key}")) : nil
74
+ format_tr formats, prop, :href=>href
75
+ }
76
+ if specs[:composite] and p1.size > 1
77
+ links = mk_comp_links specs[:composite], host, ckeys
78
+ p1.push [td(links.join(' | '), :colspan=>formats.size)]
79
+ end
80
+ p0 + p1
81
+ end
82
+
83
+ CMNAME = {'s'=>'stack', 'v'=>'overlay', ''=>'sum', 't'=>'tile'}
84
+ def mk_comp_links comps, host, ckeys
85
+ links = []
86
+ for cm in comps
87
+ href_fp = url_to "?p=#{cm}&"
88
+ href = href_fp + ckeys.map {|k| "r=#{host}_#{k}"}.join('&')
89
+ links.push mk_tag('a', {:href=>href}, CMNAME[cm])
90
+ end
91
+ links
92
+ end
93
+
94
+ def format_tr formats, prop, options={}
95
+ formats.map {|format|
96
+ format = format.gsub(/\\(\w)/) {
97
+ case $1
98
+ when 'r'; options[:class] = 'text-right'
99
+ end
100
+ ''
101
+ }
102
+ format_cell format, prop, options
103
+ }
104
+ end
105
+
106
+ def format_cell f, prop, options={}
107
+ str = f.gsub(/%([\.\/a-z\d][\.\/A-Za-z_\d]*)?([%A-Z])/) {
108
+ case $2
109
+ when 'D'
110
+ prop[:description]
111
+ when 'N'
112
+ name = prop[:name]
113
+ (href = options[:href]) ? "<a href=\"#{h href}\">#{h name}</a>" : name
114
+ when 'I'
115
+ addrs = (prop[:ipaddr] || '').split(',').map {|item|
116
+ if item =~ %r{^(\d+\.\d+\.\d+\.\d+)/(\d+\.\d+\.\d+\.\d+)}
117
+ ipaddr = $1
118
+ int, = $2.split('.').map {|s|s.to_i}.pack('C4').unpack('N')
119
+ mask = 32 - Integer(Math.log((int ^ 0xffffffff) + 1) / Math.log(2))
120
+ ipaddr + '/' + mask.to_s
121
+ else
122
+ item
123
+ end
124
+ }.join('</br>')
125
+ when 'L'
126
+ if $1
127
+ base, mag = $1.split('/')
128
+ base = base.to_i
129
+ end
130
+ #mag = (mag || 1).to_f
131
+ to_scalestr(prop[:lastvalue], base)
132
+ when 'S'
133
+ (prop[:astatus].to_i == 2) ? 'AdminDown' :
134
+ ((prop[:ostatus].to_i == 2) ? 'Down' : '')
135
+ when 'U'
136
+ to_scalestr(prop[:ub], $1.to_i)
137
+ else
138
+ ''
139
+ end
140
+ }
141
+ td str, :class=>options[:class]
142
+ end
143
+
144
+ def template
145
+ <<'EOS'
146
+ <span class="large"><%=h host %></span>
147
+ <small><%=h sysinfo['_sysdescr'] || '' %></small><br/>
148
+ <hr/>
149
+
150
+ <table>
151
+ <% for data_name in data_names -%>
152
+ <tr><td>
153
+ <table class="table ds" width="100%">
154
+ <% for row in format_data_list dir, data_name, data_hash[data_name] -%>
155
+ <tr>
156
+ <%= row.join('') %>
157
+ </tr>
158
+ <% end -%>
159
+ </table>
160
+ </td></tr>
161
+ <% end -%>
162
+ </table>
163
+ EOS
164
+ end
165
+ end
166
+ end