zmonitor 1.0.11
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/zmonitor +39 -0
- data/lib/zmonitor.rb +170 -0
- data/lib/zmonitor/api.rb +98 -0
- data/lib/zmonitor/api/event.rb +39 -0
- data/lib/zmonitor/api/trigger.rb +44 -0
- data/lib/zmonitor/api/user.rb +40 -0
- data/lib/zmonitor/misc.rb +31 -0
- metadata +64 -0
data/bin/zmonitor
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'zmonitor'
|
5
|
+
|
6
|
+
opts = {}
|
7
|
+
OptionParser.new do |o|
|
8
|
+
o.banner = "usage: zmonitor [options]"
|
9
|
+
o.on('--ack MATCH', '-a', "Acknowledge current events that match a pattern MATCH. No wildcards.") { |a| opts[:ack] = a.tr('^ A-Za-z0-9[]{}()|,-.', '') }
|
10
|
+
o.on('--disable-maintenance', '-m', "Filter out servers marked as being in maintenance.") { |m| opts[:maint] = 1 }
|
11
|
+
o.on('--minimum-severity PRIORITY', '-M', "Show events with a priority greater than M. Accepted values are 0 to 5. Default is 2.") { |ms| opts[:min_severity] = ms.tr('^0-5', '') }
|
12
|
+
o.on('--priority-list LIST', '-l', "Comma-delimited list of what priority events to show.") { |l| opts[:priority_list] = l.tr('^,0-5', '') }
|
13
|
+
o.on('--hide-acknowledged-alerts', '-H', "Don't show events that have already been acknowledged.") { |h| opts[:hideack] = 1 }
|
14
|
+
o.on('--print-once', '-1', "Only check Zabbix once and print out all alerts.") { |p| opts[:once] = 1 }
|
15
|
+
o.on('-h', 'Show this help') { puts '',o,''; exit }
|
16
|
+
o.parse!
|
17
|
+
end
|
18
|
+
|
19
|
+
monitor = Zabbix::Monitor.new()
|
20
|
+
monitor.hide_maintenance = opts[:maint] unless opts[:maint].nil?
|
21
|
+
monitor.hide_acknowledged_alerts = opts[:hideack] unless opts[:hideack].nil?
|
22
|
+
monitor.min_severity = opts[:min_severity] unless opts[:min_severity].nil? and opts[:min_severity] != ''
|
23
|
+
monitor.priority_list = opts[:priority_list] unless opts[:priority_list].nil?
|
24
|
+
|
25
|
+
if opts[:ack]
|
26
|
+
monitor.acknowledge(opts[:ack])
|
27
|
+
elsif opts[:once]
|
28
|
+
monitor.get_dashboard('full')
|
29
|
+
else
|
30
|
+
system "stty -echo"
|
31
|
+
Signal.trap("SIGINT") do
|
32
|
+
system "stty echo"
|
33
|
+
abort
|
34
|
+
end
|
35
|
+
while true
|
36
|
+
monitor.get_dashboard()
|
37
|
+
0.upto(20) { sleep 0.5 }
|
38
|
+
end
|
39
|
+
end
|
data/lib/zmonitor.rb
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'colored'
|
4
|
+
|
5
|
+
require 'zmonitor/api'
|
6
|
+
require 'zmonitor/misc'
|
7
|
+
|
8
|
+
module Zabbix
|
9
|
+
class Monitor
|
10
|
+
attr_accessor :api, :hide_maintenance, :hide_acknowledged_alerts, :min_severity, :priority_list
|
11
|
+
|
12
|
+
class EmptyFileError < StandardError
|
13
|
+
attr_reader :message
|
14
|
+
def initialize(reason, file)
|
15
|
+
@message = reason
|
16
|
+
puts "[INFO] Deleting #{file}"
|
17
|
+
File.delete(file)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
def initialize()
|
21
|
+
@hide_maintenance = 0
|
22
|
+
@hide_acknowledged_alerts = 0
|
23
|
+
@min_severity = '2'
|
24
|
+
@priority_list = ''
|
25
|
+
uri = self.check_uri()
|
26
|
+
@api = Zabbix::API.new(uri)
|
27
|
+
@api.token = self.check_login
|
28
|
+
end
|
29
|
+
def check_uri()
|
30
|
+
uri_path = File.expand_path("~/.zmonitor-server")
|
31
|
+
if File.exists?(uri_path)
|
32
|
+
uri = File.open(uri_path).read()
|
33
|
+
else
|
34
|
+
puts "Where is your Zabbix located? (please include https/http - for example, https://localhost)"
|
35
|
+
uri = "#{STDIN.gets.chomp()}/api_jsonrpc.php"
|
36
|
+
f = File.new(uri_path, "w+")
|
37
|
+
f.write(uri)
|
38
|
+
f.close
|
39
|
+
end
|
40
|
+
#if uri !=~ /^https?:\/\/.*\/api_jsonrpc\.php/
|
41
|
+
#puts "The URI we're using is invalid, sir. Resetting..."
|
42
|
+
#check_uri()
|
43
|
+
#end
|
44
|
+
#puts "Okay, using #{uri}."
|
45
|
+
raise EmptyFileError.new('URI is empty for some reason', uri_path) if uri == '' || uri.nil?
|
46
|
+
return uri
|
47
|
+
end
|
48
|
+
def check_login()
|
49
|
+
token_path = File.expand_path("~/.zmonitor-token")
|
50
|
+
if File.exists?(token_path)
|
51
|
+
token = File.open(token_path).read()
|
52
|
+
else
|
53
|
+
print "Please enter your Zabbix username: "
|
54
|
+
user = STDIN.gets.chomp()
|
55
|
+
print "Please enter your Zabbix password: "
|
56
|
+
begin
|
57
|
+
system "stty -echo"
|
58
|
+
password = gets.chomp
|
59
|
+
ensure
|
60
|
+
system "stty echo"
|
61
|
+
puts
|
62
|
+
end
|
63
|
+
token = @api.user.login(user, password).chomp
|
64
|
+
f = File.new(token_path, "w+")
|
65
|
+
f.write(token)
|
66
|
+
f.close
|
67
|
+
end
|
68
|
+
raise EmptyFileError.new("Token is empty!", token_path) if token == '' || token.nil?
|
69
|
+
return token
|
70
|
+
end
|
71
|
+
def get_events()
|
72
|
+
current_time = Time.now.to_i # to be used in getting event durations, but it really depends on the master
|
73
|
+
triggers = unacked_triggers = @api.trigger.get_active(@min_severity, @hide_maintenance, @hide_acknowledged_alerts, @priority_list) # Call the API for a list of active triggers
|
74
|
+
unacked_triggers = @api.trigger.get_active(@min_severity, @hide_maintenance, 1, @priority_list) if @hide_acknowledged_alerts == 0 # Call it again to get just those that are unacknowledged
|
75
|
+
current_events = []
|
76
|
+
triggers.each do |t|
|
77
|
+
next if t['hosts'][0]['status'] == '1' or t['items'][0]['status'] == '1' # skip disabled items/hosts that the api call returns
|
78
|
+
current_events << {
|
79
|
+
:id => t['triggerid'].to_i,
|
80
|
+
:time => t['lastchange'].to_i,
|
81
|
+
:fuzzytime => fuzz(current_time - t['lastchange'].to_i),
|
82
|
+
:severity => t['priority'].to_i,
|
83
|
+
:hostname => t['host'],
|
84
|
+
:description => t['description'].gsub(/ (on(| server) |to |)#{t['host']}/, '')#,
|
85
|
+
}
|
86
|
+
end
|
87
|
+
current_events.each do |e|
|
88
|
+
s = unacked_triggers.select{ |t| t['triggerid'] == "#{e[:id]}" }
|
89
|
+
e[:acknowledged] = s[0] ? 0 : 1
|
90
|
+
end
|
91
|
+
# Sort the events decreasing by severity, and then descending by duration (smaller timestamps at top)
|
92
|
+
return current_events.sort_by { |t| [ -t[:severity], t[:time] ] }
|
93
|
+
end
|
94
|
+
def get_dashboard(format = '')
|
95
|
+
max_lines = `tput lines`.to_i - 1
|
96
|
+
cols = `tput cols`.to_i
|
97
|
+
eventlist = self.get_events() #TODO: get_events(max_lines)
|
98
|
+
pretty_output = []
|
99
|
+
pretty_output << ["Last updated: %8s%#{cols-40}sZmonitor Dashboard".cyan_on_blue % [Time.now.strftime('%T'),'']] if format != 'full'
|
100
|
+
if eventlist.length != 0
|
101
|
+
max_hostlen = eventlist.each.max { |a,b| a[:hostname].length <=> b[:hostname].length }[:hostname].length
|
102
|
+
max_desclen = eventlist.each.max { |a,b| a[:description].length <=> b[:description].length }[:description].length
|
103
|
+
eventlist.each do |e|
|
104
|
+
break if pretty_output.length == max_lines and format != 'full'
|
105
|
+
ack = "N".red
|
106
|
+
ack = "Y".green if e[:acknowledged] == 1
|
107
|
+
pretty_output << "%s " % e[:fuzzytime] + "%-#{max_hostlen}s " % e[:hostname] +
|
108
|
+
"%-#{max_desclen}s".color_by_severity(e[:severity]) % e[:description] + " %s" % ack
|
109
|
+
end
|
110
|
+
else
|
111
|
+
pretty_output << ['',
|
112
|
+
'The API calls returned 0 results. Either your servers are very happy, or ZMonitor is not working correctly.',
|
113
|
+
'', "Please check your dashboard at #{@api.server.to_s.gsub(/\/api_jsonrpc.php/, '')} to verify activity.", '',
|
114
|
+
'ZMonitor will continue to refresh every ten seconds unless you interrupt it.']
|
115
|
+
end
|
116
|
+
print "\e[H\e[2J" if format != 'full' # clear terminal screen
|
117
|
+
puts pretty_output
|
118
|
+
end
|
119
|
+
def acknowledge(pattern = '')
|
120
|
+
puts 'Retrieving list of active unacknowledged triggers that match: '.bold.blue + '%s'.green % pattern, ''
|
121
|
+
filtered = []
|
122
|
+
eventlist = self.get_events()
|
123
|
+
eventlist.each do |e|
|
124
|
+
if e[:hostname] =~ /#{pattern}/ or e[:description] =~ /#{pattern}/
|
125
|
+
event = @api.event.get_last_by_trigger(e[:id])
|
126
|
+
e[:eventid] = event['eventid'].to_i
|
127
|
+
e[:acknowledged] = event['acknowledged'].to_i
|
128
|
+
filtered << e if e[:acknowledged] == 0
|
129
|
+
end
|
130
|
+
end
|
131
|
+
abort("No alerts found, so aborting".yellow) if filtered.length == 0
|
132
|
+
filtered.each.with_index do |a,i|
|
133
|
+
message = '%s - %s (%s)'.color_by_severity(a[:severity]) % [ a[:fuzzytime], a[:description], a[:hostname] ]
|
134
|
+
puts "%4d >".bold % (i+1) + message
|
135
|
+
end
|
136
|
+
|
137
|
+
puts '', ' Selection - enter "all", or a set of numbers listed above separated by spaces.'
|
138
|
+
print ' Sel > '.bold
|
139
|
+
input = STDIN.gets.chomp()
|
140
|
+
|
141
|
+
no_ack_msg = "Not acknowledging anything."
|
142
|
+
raise StandardError.new("No input. #{no_ack_msg}".green) if input == ''
|
143
|
+
to_ack = (1..filtered.length).to_a if input =~ /^\s*all\s*$/ # only string we'll accept
|
144
|
+
raise StandardError.new("Invalid input. #{no_ack_msg}".red) if to_ack.nil? and (input =~ /^([0-9 ]+)$/).nil?
|
145
|
+
to_ack = input.split.map(&:to_i).sort if to_ack.nil? # Split our input into a sorted array of integers
|
146
|
+
# Let's first check if a value greater than possible was given, to help prevent typos acknowledging the wrong thing
|
147
|
+
to_ack.each { |i| raise StandardError.new("You entered a value greater than %d! Please double check. #{no_ack_msg}".yellow % filtered.length) if i > filtered.length }
|
148
|
+
|
149
|
+
puts '', ' Message - enter an acknowledgement message below, or leave blank for the default.'
|
150
|
+
print ' Msg > '.bold
|
151
|
+
message = STDIN.gets.chomp()
|
152
|
+
puts
|
153
|
+
|
154
|
+
# Finally! Acknowledge EVERYTHING
|
155
|
+
to_ack.each do |a|
|
156
|
+
puts 'Acknowledging: '.green + '%s (%s)' % [ filtered[a-1][:description], filtered[a-1][:hostname] ]
|
157
|
+
if message == ''
|
158
|
+
@api.whoami = @api.user.get_fullname()
|
159
|
+
@api.event.acknowledge(filtered[a-1][:eventid])
|
160
|
+
else
|
161
|
+
@api.event.acknowledge(filtered[a-1][:eventid], message)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
# Save a time offset between the local computer and the Zabbix master
|
166
|
+
def calibrate()
|
167
|
+
#
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
data/lib/zmonitor/api.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'net/http'
|
5
|
+
require 'net/https'
|
6
|
+
|
7
|
+
abort("Could not load API libraries. Did you install a JSON library? (json / json_pure / json-jruby)") unless Object.const_defined?(:JSON)
|
8
|
+
|
9
|
+
# create the module/class stub so we can require the API class files properly
|
10
|
+
module Zabbix
|
11
|
+
class API
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# load up the different API classes and methods
|
16
|
+
require 'zmonitor/api/event'
|
17
|
+
require 'zmonitor/api/trigger'
|
18
|
+
require 'zmonitor/api/user'
|
19
|
+
|
20
|
+
module Zabbix
|
21
|
+
class API
|
22
|
+
attr_accessor :server, :verbose, :token, :whoami
|
23
|
+
|
24
|
+
attr_accessor :event, :trigger, :user # API classes
|
25
|
+
|
26
|
+
def initialize( server = "http://localhost", verbose = false)
|
27
|
+
# Parse the URL beforehand
|
28
|
+
@server = URI.parse(server)
|
29
|
+
@verbose = verbose
|
30
|
+
|
31
|
+
# set up API class methods
|
32
|
+
@user = Zabbix::User.new(self)
|
33
|
+
@event = Zabbix::Event.new(self)
|
34
|
+
@trigger = Zabbix::Trigger.new(self)
|
35
|
+
end
|
36
|
+
|
37
|
+
# More specific error names, may add extra handling procedures later
|
38
|
+
class ResponseCodeError < StandardError
|
39
|
+
end
|
40
|
+
class ResponseError < StandardError
|
41
|
+
end
|
42
|
+
class NotAuthorisedError < StandardError
|
43
|
+
end
|
44
|
+
|
45
|
+
def call_api(message)
|
46
|
+
# Finish preparing the JSON call
|
47
|
+
message['id'] = rand 65536 if message['id'].nil?
|
48
|
+
message['jsonrpc'] = '2.0'
|
49
|
+
# Check if we have authorization token if we're not logging in
|
50
|
+
if @token.nil? && message['method'] != 'user.login'
|
51
|
+
puts "[ERROR] Authorisation Token not initialised. message => #{message}"
|
52
|
+
raise NotAuthorisedError.new()
|
53
|
+
else
|
54
|
+
message['auth'] = @token if message['method'] != 'user.login'
|
55
|
+
end
|
56
|
+
|
57
|
+
json_message = JSON.generate(message) # Create a JSON string
|
58
|
+
|
59
|
+
# Open TCP connection to Zabbix master
|
60
|
+
connection = Net::HTTP.new(@server.host, @server.port)
|
61
|
+
connection.read_timeout = 300
|
62
|
+
# Check to see if we're connecting via SSL
|
63
|
+
if @server.scheme == 'https' then
|
64
|
+
connection.use_ssl = true
|
65
|
+
connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
66
|
+
end
|
67
|
+
|
68
|
+
# Prepare POST request for sending
|
69
|
+
request = Net::HTTP::Post.new(@server.request_uri)
|
70
|
+
request.add_field('Content-Type', 'application/json-rpc')
|
71
|
+
request.body = json_message
|
72
|
+
|
73
|
+
# Send request
|
74
|
+
begin
|
75
|
+
puts "[INFO] Attempting to send request => #{request}, request body => #{request.body}" if @verbose
|
76
|
+
response = connection.request(request)
|
77
|
+
rescue ::SocketError => e
|
78
|
+
puts "[ERROR] Could not complete request: SocketError => #{e.message}" if @verbose
|
79
|
+
raise SocketError.new(e.message)
|
80
|
+
rescue Timeout::Error => e
|
81
|
+
puts "[ERROR] Timed out from Zabbix master. Is it being funky? => #{e.message}"
|
82
|
+
exit
|
83
|
+
end
|
84
|
+
|
85
|
+
puts "[INFO] Received response: #{response}" if @verbose
|
86
|
+
raise ResponseCodeError.new("[ERROR] Did not receive 200 OK, but HTTP code #{response.code}") if response.code != "200"
|
87
|
+
|
88
|
+
# Check for an error, and return the parsed result if everything's fine
|
89
|
+
parsed_response = JSON.parse(response.body)
|
90
|
+
if error = parsed_response['error']
|
91
|
+
raise ResponseError.new("[ERROR] Received error response: code => #{error['code'].to_s}; message => #{error['message']}; data => #{error['data']}")
|
92
|
+
end
|
93
|
+
|
94
|
+
return parsed_response['result']
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# api.event functions
|
2
|
+
|
3
|
+
module Zabbix
|
4
|
+
class Event < API
|
5
|
+
attr_accessor :parent
|
6
|
+
def initialize(parent)
|
7
|
+
@parent = parent
|
8
|
+
@verbose = @parent.verbose
|
9
|
+
end
|
10
|
+
def call_api(message)
|
11
|
+
return @parent.call_api(message)
|
12
|
+
end
|
13
|
+
# General event.get
|
14
|
+
def get( options = {} )
|
15
|
+
request = { 'method' => 'event.get', 'params' => options }
|
16
|
+
return call_api(request)
|
17
|
+
end
|
18
|
+
# Get the most recent event's information for a particular trigger
|
19
|
+
def get_last_by_trigger( triggerid = '' )
|
20
|
+
request = {
|
21
|
+
'method' => 'event.get',
|
22
|
+
'params' =>
|
23
|
+
{
|
24
|
+
'triggerids' => [triggerid.to_s],
|
25
|
+
'sortfield' => 'clock',
|
26
|
+
'sortorder' => 'DESC',
|
27
|
+
'limit' => '1',
|
28
|
+
'output' => 'extend'
|
29
|
+
}
|
30
|
+
}
|
31
|
+
return call_api(request)[0]
|
32
|
+
end
|
33
|
+
# Mark an event acknowledged and leave a message
|
34
|
+
def acknowledge( events = [], message = "#{@parent.whoami} is working on this." )
|
35
|
+
request = { 'method' => 'event.acknowledge', 'params' => { 'eventids' => events, 'message' => message } }
|
36
|
+
call_api(request)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# api.trigger functions
|
2
|
+
|
3
|
+
module Zabbix
|
4
|
+
class Trigger < API
|
5
|
+
attr_accessor :parent
|
6
|
+
def initialize(parent)
|
7
|
+
@parent = parent
|
8
|
+
@verbose = @parent.verbose
|
9
|
+
end
|
10
|
+
def call_api(message)
|
11
|
+
return @parent.call_api(message)
|
12
|
+
end
|
13
|
+
# General trigger.get
|
14
|
+
def get( options = {} )
|
15
|
+
request = { 'method' => 'trigger.get', 'params' => options }
|
16
|
+
return call_api(request)
|
17
|
+
end
|
18
|
+
# Get a hash of all unresolved problem triggers
|
19
|
+
def get_active( min_severity = 2, maint = 0, lastack = 0, priority_list = '' )
|
20
|
+
request = {
|
21
|
+
'method' => 'trigger.get',
|
22
|
+
'params' => {
|
23
|
+
'sortfield' => 'priority,lastchange',
|
24
|
+
'sortorder' => 'desc',
|
25
|
+
'templated' => '0',
|
26
|
+
'filter' => { 'value' => '1', 'status' => '0' },
|
27
|
+
'expandData' => 'host',
|
28
|
+
'expandDescription' => '1',
|
29
|
+
'select_hosts' => 'extend',
|
30
|
+
'select_items' => 'extend',
|
31
|
+
'output' => 'extend'
|
32
|
+
}
|
33
|
+
}
|
34
|
+
request['params']['maintenance'] = 0 if maint == 1
|
35
|
+
request['params']['withLastEventUnacknowledged'] = 1 if lastack == 1
|
36
|
+
if priority_list == ''
|
37
|
+
request['params']['min_severity'] = min_severity.to_s
|
38
|
+
else
|
39
|
+
request['params']['filter']['priority'] = priority_list.split(",")
|
40
|
+
end
|
41
|
+
return call_api(request)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# api.user functions
|
2
|
+
|
3
|
+
module Zabbix
|
4
|
+
class User < API
|
5
|
+
attr_accessor :parent
|
6
|
+
def initialize(parent)
|
7
|
+
@parent = parent
|
8
|
+
@verbose = @parent.verbose
|
9
|
+
end
|
10
|
+
def call_api(message)
|
11
|
+
return @parent.call_api(message)
|
12
|
+
end
|
13
|
+
# General user.get
|
14
|
+
def get( options = {} )
|
15
|
+
request = { 'method' => 'user.get', 'params' => options }
|
16
|
+
return call_api(request)
|
17
|
+
end
|
18
|
+
# Get first and last name of currently logged in user
|
19
|
+
def get_fullname()
|
20
|
+
request = { 'method' => 'user.get', 'output' => 'extend' }
|
21
|
+
whoami = self.get({ 'output' => 'extend' })
|
22
|
+
return whoami[0]["name"] + " " + whoami[0]["surname"]
|
23
|
+
end
|
24
|
+
# Perform a login procedure
|
25
|
+
def login(user, password)
|
26
|
+
request = { 'method' => 'user.login', 'params' => { 'user' => user, 'password' => password, }, 'id' => 1 }
|
27
|
+
puts "[INFO] Logging in..." if @verbose
|
28
|
+
result = call_api(request)
|
29
|
+
puts "[INFO] Successfully logged in as #{user}! result => #{result}" if @verbose
|
30
|
+
return result
|
31
|
+
end
|
32
|
+
# Perform a logout
|
33
|
+
def logout()
|
34
|
+
request = { 'method' => 'user.logout' }
|
35
|
+
puts "[INFO] Logging out..." if @verbose
|
36
|
+
call_api(request)
|
37
|
+
puts "[INFO] Successfully logged out." if @verbose
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# Miscellaneous functions that aren't technically part of Zabbix, but are used in zabbixmon
|
4
|
+
|
5
|
+
def fuzz(t)
|
6
|
+
t = 0 if t < 0 # we don't need negative fuzzy times.
|
7
|
+
d = t / 86400
|
8
|
+
h = t % 86400 / 3600
|
9
|
+
m = t % 3600 / 60
|
10
|
+
s = t % 60
|
11
|
+
fuzzy = ['d', 'h', 'm', 's'].map do |unit|
|
12
|
+
amt = eval(unit)
|
13
|
+
"%3d#{unit}" % amt
|
14
|
+
end.join
|
15
|
+
return "#{fuzzy}"[8..-1] if h == 0
|
16
|
+
return "#{fuzzy}"[4..-5] if d == 0
|
17
|
+
return "#{fuzzy}"[0..-9]
|
18
|
+
end
|
19
|
+
|
20
|
+
class String
|
21
|
+
def color_by_severity( level = 0 )
|
22
|
+
case level
|
23
|
+
when 5; self.bold.red
|
24
|
+
when 4; self.yellow
|
25
|
+
when 3; self.green
|
26
|
+
when 2; self.cyan
|
27
|
+
when 1; self.bold.white
|
28
|
+
else self
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zmonitor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.11
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Musee Ullah
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-19 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: colored
|
16
|
+
requirement: &19182760 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *19182760
|
25
|
+
description: A command line interface for viewing alerts from a Zabbix instance.
|
26
|
+
email: milkteafuzz@gmail.com
|
27
|
+
executables:
|
28
|
+
- zmonitor
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- lib/zmonitor/api.rb
|
33
|
+
- lib/zmonitor/misc.rb
|
34
|
+
- lib/zmonitor/api/user.rb
|
35
|
+
- lib/zmonitor/api/event.rb
|
36
|
+
- lib/zmonitor/api/trigger.rb
|
37
|
+
- lib/zmonitor.rb
|
38
|
+
- bin/zmonitor
|
39
|
+
homepage: https://github.com/liliff/zonitor
|
40
|
+
licenses: []
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
none: false
|
47
|
+
requirements:
|
48
|
+
- - ! '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
requirements:
|
58
|
+
- json
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.8.17
|
61
|
+
signing_key:
|
62
|
+
specification_version: 3
|
63
|
+
summary: Zabbix CLI dashboard
|
64
|
+
test_files: []
|