zmonitor 1.0.11
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|