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.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/MIT-LICENSE.txt +20 -0
- data/README.md +132 -0
- data/Rakefile +5 -0
- data/bin/grapher +17 -0
- data/bin/gri +5 -0
- data/bin/gricast +17 -0
- data/bin/grispark +5 -0
- data/bin/griwalk +9 -0
- data/bin/trad +19 -0
- data/bin/trad-http +17 -0
- data/gri.gemspec +21 -0
- data/lib/fluent/plugin/out_gri.rb +56 -0
- data/lib/gri/api.rb +28 -0
- data/lib/gri/app_collector.rb +154 -0
- data/lib/gri/app_walker.rb +23 -0
- data/lib/gri/blank.rb +49 -0
- data/lib/gri/builtindefs.rb +211 -0
- data/lib/gri/cast.rb +84 -0
- data/lib/gri/cgraph.rb +37 -0
- data/lib/gri/clist.rb +163 -0
- data/lib/gri/collector.rb +284 -0
- data/lib/gri/config.rb +134 -0
- data/lib/gri/ds_list.rb +166 -0
- data/lib/gri/format_helper.rb +112 -0
- data/lib/gri/gparams.rb +43 -0
- data/lib/gri/graph.rb +239 -0
- data/lib/gri/grapher.rb +70 -0
- data/lib/gri/ldb.rb +160 -0
- data/lib/gri/list.rb +242 -0
- data/lib/gri/log.rb +140 -0
- data/lib/gri/loop.rb +109 -0
- data/lib/gri/ltsv.rb +58 -0
- data/lib/gri/main.rb +107 -0
- data/lib/gri/mlog.rb +22 -0
- data/lib/gri/mmsgpack.rb +57 -0
- data/lib/gri/msnmp.rb +601 -0
- data/lib/gri/page.rb +235 -0
- data/lib/gri/pcollector.rb +209 -0
- data/lib/gri/plugin.rb +75 -0
- data/lib/gri/plugin/bootstrap.rb +65 -0
- data/lib/gri/plugin/cisco.rb +98 -0
- data/lib/gri/plugin/exec_collector.rb +89 -0
- data/lib/gri/plugin/juniper.rb +5 -0
- data/lib/gri/plugin/netsnmp.rb +8 -0
- data/lib/gri/plugin/ucdavis.rb +176 -0
- data/lib/gri/plugin/writer_fluentd.rb +26 -0
- data/lib/gri/polling_unit.rb +88 -0
- data/lib/gri/q.rb +5 -0
- data/lib/gri/request.rb +29 -0
- data/lib/gri/rrd.rb +438 -0
- data/lib/gri/scheduler.rb +68 -0
- data/lib/gri/sgraph.rb +147 -0
- data/lib/gri/spark.rb +94 -0
- data/lib/gri/tra_collector.rb +80 -0
- data/lib/gri/trad.rb +170 -0
- data/lib/gri/updater.rb +201 -0
- data/lib/gri/util_daemon.rb +19 -0
- data/lib/gri/util_marshal.rb +13 -0
- data/lib/gri/utils.rb +63 -0
- data/lib/gri/vendor.rb +76 -0
- data/lib/gri/version.rb +3 -0
- data/lib/gri/wmain.rb +67 -0
- data/lib/gri/writer.rb +184 -0
- data/mcollector +47 -0
- data/test/mock.rb +60 -0
- data/test/root/gra/.sysdb/sysdb.txt +3 -0
- data/test/root/gra/testhost/.records.txt +2 -0
- data/test/root/if.def +2 -0
- data/test/root/test.conf +4 -0
- data/test/root/testtab +9 -0
- data/test/root/testtab2 +2 -0
- data/test/root/tra/testhost/_/20130614 +20 -0
- data/test/test_app.rb +58 -0
- data/test/test_builtindefs.rb +24 -0
- data/test/test_collector.rb +58 -0
- data/test/test_config.rb +62 -0
- data/test/test_ds_list.rb +48 -0
- data/test/test_exec_collector.rb +33 -0
- data/test/test_format_helper.rb +68 -0
- data/test/test_graph.rb +69 -0
- data/test/test_ldb.rb +29 -0
- data/test/test_list.rb +65 -0
- data/test/test_log.rb +16 -0
- data/test/test_loop.rb +35 -0
- data/test/test_ltsv.rb +38 -0
- data/test/test_main.rb +19 -0
- data/test/test_mmsgpack.rb +27 -0
- data/test/test_msnmp.rb +147 -0
- data/test/test_page.rb +51 -0
- data/test/test_pcollector.rb +71 -0
- data/test/test_plugin.rb +62 -0
- data/test/test_plugin_cisco.rb +23 -0
- data/test/test_polling_unit.rb +58 -0
- data/test/test_request.rb +26 -0
- data/test/test_rrd.rb +53 -0
- data/test/test_rrd_updater.rb +139 -0
- data/test/test_scheduler.rb +31 -0
- data/test/test_tra_collector.rb +40 -0
- data/test/test_trad.rb +33 -0
- data/test/test_util_marshal.rb +17 -0
- data/test/test_utils.rb +15 -0
- data/test/test_vendor.rb +40 -0
- data/test/test_writer.rb +33 -0
- data/test/unittest_helper.rb +27 -0
- 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
|
data/lib/gri/ds_list.rb
ADDED
@@ -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
|