Class: Zabbix::Monitor

Inherits:
Object
  • Object
show all
Defined in:
lib/zmonitor.rb

Defined Under Namespace

Classes: EmptyFileError

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeMonitor

Returns a new instance of Monitor.



20
21
22
23
24
25
26
27
28
# File 'lib/zmonitor.rb', line 20

def initialize()
  @hide_maintenance = 0
  @hide_acknowledged_alerts = 0
  @min_severity = '2'
  @priority_list = ''
  uri = self.check_uri()
  @api = Zabbix::API.new(uri)
  @api.token = self.
end

Instance Attribute Details

#apiObject

Returns the value of attribute api.



10
11
12
# File 'lib/zmonitor.rb', line 10

def api
  @api
end

#hide_acknowledged_alertsObject

Returns the value of attribute hide_acknowledged_alerts.



10
11
12
# File 'lib/zmonitor.rb', line 10

def hide_acknowledged_alerts
  @hide_acknowledged_alerts
end

#hide_maintenanceObject

Returns the value of attribute hide_maintenance.



10
11
12
# File 'lib/zmonitor.rb', line 10

def hide_maintenance
  @hide_maintenance
end

#min_severityObject

Returns the value of attribute min_severity.



10
11
12
# File 'lib/zmonitor.rb', line 10

def min_severity
  @min_severity
end

#priority_listObject

Returns the value of attribute priority_list.



10
11
12
# File 'lib/zmonitor.rb', line 10

def priority_list
  @priority_list
end

Instance Method Details

#acknowledge(pattern = '') ⇒ Object

Raises:

  • (StandardError)


119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/zmonitor.rb', line 119

def acknowledge(pattern = '')
  puts 'Retrieving list of active unacknowledged triggers that match: '.bold.blue + '%s'.green % pattern, ''
  filtered = []
  eventlist = self.get_events()
  eventlist.each do |e|
    if e[:hostname] =~ /#{pattern}/ or e[:description] =~ /#{pattern}/
      event = @api.event.get_last_by_trigger(e[:id])
      e[:eventid] = event['eventid'].to_i
      e[:acknowledged] = event['acknowledged'].to_i
      filtered << e if e[:acknowledged] == 0
    end
  end
  abort("No alerts found, so aborting".yellow) if filtered.length == 0
  filtered.each.with_index do |a,i|
    message = '%s - %s (%s)'.color_by_severity(a[:severity]) % [ a[:fuzzytime], a[:description], a[:hostname] ]
    puts "%4d >".bold % (i+1) + message
  end

  puts '', '       Selection - enter "all", or a set of numbers listed above separated by spaces.'
  print ' Sel > '.bold
  input = STDIN.gets.chomp()

  no_ack_msg = "Not acknowledging anything."
  raise StandardError.new("No input. #{no_ack_msg}".green) if input == ''
  to_ack = (1..filtered.length).to_a if input =~ /^\s*all\s*$/ # only string we'll accept
  raise StandardError.new("Invalid input. #{no_ack_msg}".red) if to_ack.nil? and (input =~ /^([0-9 ]+)$/).nil?
  to_ack = input.split.map(&:to_i).sort if to_ack.nil? # Split our input into a sorted array of integers
  # Let's first check if a value greater than possible was given, to help prevent typos acknowledging the wrong thing
  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 }

  puts  '', '       Message   - enter an acknowledgement message below, or leave blank for the default.'
  print ' Msg > '.bold
  message = STDIN.gets.chomp()
  puts

  # Finally! Acknowledge EVERYTHING
  to_ack.each do |a|
    puts 'Acknowledging: '.green + '%s (%s)' % [ filtered[a-1][:description], filtered[a-1][:hostname] ]
    if message == ''
      @api.whoami = @api.user.get_fullname()
      @api.event.acknowledge(filtered[a-1][:eventid])
    else
      @api.event.acknowledge(filtered[a-1][:eventid], message)
    end
  end
end

#calibrateObject

Save a time offset between the local computer and the Zabbix master



166
167
168
# File 'lib/zmonitor.rb', line 166

def calibrate()
  #
end

#check_loginObject

Raises:



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/zmonitor.rb', line 48

def ()
  token_path = File.expand_path("~/.zmonitor-token")
  if File.exists?(token_path)
    token = File.open(token_path).read()
  else
    print "Please enter your Zabbix username: "
    user = STDIN.gets.chomp()
    print "Please enter your Zabbix password: "
    begin
      system "stty -echo"
      password = gets.chomp
    ensure
      system "stty echo"
      puts
    end
    token = @api.user.(user, password).chomp
    f = File.new(token_path, "w+")
    f.write(token)
    f.close
  end
  raise EmptyFileError.new("Token is empty!", token_path) if token == '' || token.nil?
  return token
end

#check_uriObject



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/zmonitor.rb', line 29

def check_uri()
  uri_path = File.expand_path("~/.zmonitor-server")
  if File.exists?(uri_path)
    uri = File.open(uri_path).read()
  else
    puts "Where is your Zabbix located? (please include https/http - for example, https://localhost)"
    uri = "#{STDIN.gets.chomp()}/api_jsonrpc.php"
    f = File.new(uri_path, "w+")
    f.write(uri)
    f.close
  end
  #if uri !=~ /^https?:\/\/.*\/api_jsonrpc\.php/
    #puts "The URI we're using is invalid, sir. Resetting..."
    #check_uri()
  #end
  #puts "Okay, using #{uri}."
  raise EmptyFileError.new('URI is empty for some reason', uri_path) if uri == '' || uri.nil?
  return uri
end

#get_dashboard(format = '') ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/zmonitor.rb', line 94

def get_dashboard(format = '')
  max_lines = `tput lines`.to_i - 1
  cols = `tput cols`.to_i
  eventlist = self.get_events() #TODO: get_events(max_lines)
  pretty_output = []
  pretty_output << ["Last updated: %8s%#{cols-40}sZmonitor Dashboard".cyan_on_blue % [Time.now.strftime('%T'),'']] if format != 'full'
  if eventlist.length != 0
    max_hostlen = eventlist.each.max { |a,b| a[:hostname].length <=> b[:hostname].length }[:hostname].length
    max_desclen = eventlist.each.max { |a,b| a[:description].length <=> b[:description].length }[:description].length
    eventlist.each do |e|
      break if pretty_output.length == max_lines and format != 'full'
      ack = "N".red
      ack = "Y".green if e[:acknowledged] == 1
      pretty_output << "%s " % e[:fuzzytime] + "%-#{max_hostlen}s " % e[:hostname] +
      "%-#{max_desclen}s".color_by_severity(e[:severity]) % e[:description] + " %s" % ack
    end
  else
    pretty_output << ['',
      'The API calls returned 0 results. Either your servers are very happy, or ZMonitor is not working correctly.',
      '', "Please check your dashboard at #{@api.server.to_s.gsub(/\/api_jsonrpc.php/, '')} to verify activity.", '',
      'ZMonitor will continue to refresh every ten seconds unless you interrupt it.']
  end
  print "\e[H\e[2J" if format != 'full' # clear terminal screen
  puts pretty_output
end

#get_eventsObject



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/zmonitor.rb', line 71

def get_events()
  current_time = Time.now.to_i # to be used in getting event durations, but it really depends on the master
  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
  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
  current_events = []
  triggers.each do |t|
    next if t['hosts'][0]['status'] == '1' or t['items'][0]['status'] == '1' # skip disabled items/hosts that the api call returns
    current_events << {
      :id => t['triggerid'].to_i,
      :time => t['lastchange'].to_i,
      :fuzzytime => fuzz(current_time - t['lastchange'].to_i),
      :severity => t['priority'].to_i,
      :hostname => t['host'],
      :description => t['description'].gsub(/ (on(| server) |to |)#{t['host']}/, '')#,
    }
  end
  current_events.each do |e|
    s = unacked_triggers.select{ |t| t['triggerid'] == "#{e[:id]}" }
    e[:acknowledged] = s[0] ? 0 : 1
  end
  # Sort the events decreasing by severity, and then descending by duration (smaller timestamps at top)
  return current_events.sort_by { |t| [ -t[:severity], t[:time] ] }
end