lib/nagiosharder.rb in nagiosharder-0.3.0 vs lib/nagiosharder.rb in nagiosharder-0.4.0.rc1

- old
+ new

@@ -1,10 +1,11 @@ require 'restclient' require 'nokogiri' require 'active_support' # fine, we'll just do all of activesupport instead of the parts I want. thank Rails 3 for shuffling requires around. require 'cgi' require 'hashie' +require 'nagiosharder/filters' # :( require 'active_support/version' # double and triplely ensure ActiveSupport::VERSION is around if ActiveSupport::VERSION::MAJOR > 2 require 'active_support/core_ext/array' @@ -22,50 +23,72 @@ class NagiosHarder class Site attr_accessor :nagios_url, :user, :password, :default_options, :default_cookies, :version, :nagios_time_format include HTTParty::ClassMethods - def initialize(nagios_url, user, password, version = 3) + def initialize(nagios_url, user, password, version = 3, nagios_time_format = nil) @nagios_url = nagios_url.gsub(/\/$/, '') @user = user @password = password @default_options = {} @default_cookies = {} @version = version + debug_output if ENV['DEBUG'] basic_auth(@user, @password) if @user && @password - - @nagios_time_format = if @version.to_i < 3 - "%m-%d-%Y %H:%M:%S" - else - "%Y-%m-%d %H:%M:%S" - end + @nagios_time_format = if nagios_time_format == 'us' + "%m-%d-%Y %H:%M:%S" + else + if @version.to_i < 3 + "%m-%d-%Y %H:%M:%S" + else + "%Y-%m-%d %H:%M:%S" + end + end + self end def acknowledge_service(host, service, comment) - # extra options: sticky_arg, send_notification, persistent - request = { :cmd_typ => 34, :cmd_mod => 2, :com_author => @user, :com_data => comment, :host => host, - :service => service + :service => service, + :send_notification => true, + :persistent => false, + :sticky_ack => true } response = post(cmd_url, :body => request) response.code == 200 && response.body =~ /successful/ end + def acknowledge_host(host, comment) + request = { + :cmd_typ => 33, + :cmd_mod => 2, + :com_author => @user, + :com_data => comment, + :host => host, + :send_notification => true, + :persistent => false, + :sticky_ack => true + } + + response = post(cmd_url, :body => request) + response.code == 200 && response.body =~ /successful/ + end + def unacknowledge_service(host, service) request = { :cmd_typ => 52, :cmd_mod => 2, :host => host, :service => service } - + response = post(cmd_url, :body => request) response.code == 200 && response.body =~ /successful/ end def schedule_service_downtime(host, service, options = {}) @@ -128,11 +151,11 @@ response = post(cmd_url, :body => request) response.code == 200 && response.body =~ /successful/ end - + def cancel_downtime(downtime_id, downtime_type = :host_downtime) downtime_types = { :host_downtime => 78, :service_downtime => 79 } @@ -141,11 +164,11 @@ :cmd_mod => 2, :down_id => downtime_id }) response.code == 200 && response.body =~ /successful/ end - + def schedule_host_check(host) response = post(cmd_url, :body => { :start_time => formatted_time_for(Time.now), :host => host, :force_check => true, @@ -165,69 +188,53 @@ :cmd_mod => 2 }) response.code == 200 && response.body =~ /successful/ end - def service_status(type, options = {}) - service_status_type = case type - when :ok then 2 - when :warning then 4 - when :unknown then 8 - when :critical then 16 - when :pending then 1 - when :all_problems then 28 - when :all then nil - else - raise "Unknown type" - end + def service_status(options = {}) + params = {} - sort_type = case options[:sort_type] - when :asc then 1 - when :desc then 2 - when nil then nil - else - raise "Invalid options[:sort_type]" - end + { + :host_status_types => :notification_host, + :service_status_types => :notification_service, + :sort_type => :sort, + :sort_option => :sort, + :host_props => :host, + :service_props => :service, + }.each do |key, val| + if options[key] && (options[key].is_a?(Array) || options[key].is_a?(Symbol)) + params[key.to_s.gsub(/_/, '')] = Nagiosharder::Filters.value(val, *options[key]) + end + end - sort_option = case options[:sort_option] - when :host then 1 - when :service then 2 - when :status then 3 - when :last_check then 4 - when :duration then 6 - when :attempts then 5 - when nil then nil - else - raise "Invalid options[:sort_option]" - end + # if any of the standard filter params are already integers, those win + %w( + :hoststatustypes, + :servicestatustypes, + :sorttype, + :sortoption, + :hostprops, + :serviceprops, + ).each do |key| + params[key.to_s] = options[:val] if !options[:val].nil? && options[:val].match(/^\d*$/) + end - service_group = options[:group] + if @version == 3 + params['servicegroup'] = options[:group] || 'all' + params['style'] = 'detail' + params['embedded'] = '1' + params['noheader'] = '1' + else + if options[:group] + params['servicegroup'] = options[:group] + params['style'] = 'detail' + else + params['host'] = 'all' + end + end - - params = { - 'hoststatustype' => 15, - 'servicestatustype' => service_status_type, - 'host' => 'all' - } - - - params = if @version == 3 - [ "servicegroup=all", "style=detail" ] - else - if service_group - ["servicegroup=#{service_group}", "style=detail"] - else - ["host=all"] - end - end - params += [ - service_status_type ? "servicestatustypes=#{service_status_type}" : nil, - sort_type ? "sorttype=#{sort_type}" : nil, - sort_option ? "sortoption=#{sort_option}" : nil, - "hoststatustypes=15" - ] - query = params.compact.join('&') + query = params.select {|k,v| v }.map {|k,v| "#{k}=#{v}" }.join('&') url = "#{status_url}?#{query}" response = get(url) raise "wtf #{url}? #{response.code}" unless response.code == 200 @@ -238,31 +245,37 @@ statuses end def host_status(host) - host_status_url = "#{status_url}?host=#{host}" + host_status_url = "#{status_url}?host=#{host}&embedded=1&noheader=1" response = get(host_status_url) raise "wtf #{host_status_url}? #{response.code}" unless response.code == 200 services = {} parse_status_html(response) do |status| services[status[:service]] = status end - + services end def disable_service_notifications(host, service, options = {}) request = { :cmd_mod => 2, - :cmd_typ => 23, - :host => host, - :service => service, + :host => host } + if service + request[:cmd_typ] = 23 + request[:service] = service + else + request[:cmd_typ] = 29 + request[:ahas] = true + end + response = post(cmd_url, :body => request) if response.code == 200 && response.body =~ /successful/ # TODO enable waiting. seems to hang intermittently #if options[:wait] # sleep(3) until service_notifications_disabled?(host, service) @@ -274,15 +287,21 @@ end def enable_service_notifications(host, service, options = {}) request = { :cmd_mod => 2, - :cmd_typ => 22, - :host => host, - :service => service, + :host => host } + if service + request[:cmd_typ] = 22 + request[:service] = service + else + request[:cmd_typ] = 28 + request[:ahas] = true + end + response = post(cmd_url, :body => request) if response.code == 200 && response.body =~ /successful/ # TODO enable waiting. seems to hang intermittently #if options[:wait] # sleep(3) while service_notifications_disabled?(host, service) @@ -290,16 +309,16 @@ true else false end end - + def service_notifications_disabled?(host, service) self.host_status(host)[service].notifications_disabled end - - + + def status_url "#{nagios_url}/status.cgi" end def cmd_url @@ -315,29 +334,32 @@ def formatted_time_for(time) time.strftime(nagios_time_format) end def parse_status_html(response) - doc = Nokogiri::HTML(response) + doc = Nokogiri::HTML(response.to_s) rows = doc.css('table.status > tr') last_host = nil rows.each do |row| columns = Nokogiri::HTML(row.inner_html).css('body > td').to_a if columns.any? - + + # Host column host = columns[0].inner_text.gsub(/\n/, '') # for a given host, the host details are blank after the first row if host != '' # remember it for next time last_host = host else # or save it for later host = last_host end + debug 'parsed host column' + # Service Column if columns[1] service_links = columns[1].css('td a') service_link, other_links = service_links[0], service_links[1..-1] if service_links.size > 1 comments_link = other_links.detect do |link| @@ -364,29 +386,45 @@ extra_service_notes_url = extra_service_notes_link.attribute('href').to_s if extra_service_notes_link end service = service_links[0].inner_html end - + debug 'parsed service column' + + # Status status = columns[2].inner_html if columns[2] + debug 'parsed status column' + + # Last Check last_check = if columns[3] && columns[3].inner_html != 'N/A' last_check_str = columns[3].inner_html - - DateTime.strptime(columns[3].inner_html, nagios_time_format).to_time + debug "Need to parse #{columns[3].inner_html} in #{nagios_time_format}" + DateTime.strptime(columns[3].inner_html, nagios_time_format).to_s end + debug 'parsed last check column' + + # Duration duration = columns[4].inner_html.squeeze(' ').gsub(/^ /, '') if columns[4] started_at = if duration && match_data = duration.match(/^\s*(\d+)d\s+(\d+)h\s+(\d+)m\s+(\d+)s\s*$/) ( match_data[1].to_i.days + match_data[2].to_i.hours + match_data[3].to_i.minutes + match_data[4].to_i.seconds ).ago end + debug 'parsed duration column' + + # Attempts attempts = columns[5].inner_html if columns[5] - status_info = columns[6].inner_html.gsub('&nbsp;', '') if columns[6] + debug 'parsed attempts column' + # Status info + status_info = columns[6].inner_html.gsub('&nbsp;', '').gsub("\302\240", '') if columns[6] + debug 'parsed status info column' + + if host && service && status && last_check && duration && attempts && started_at && status_info service_extinfo_url = "#{extinfo_url}?type=2&host=#{host}&service=#{CGI.escape(service)}" host_extinfo_url = "#{extinfo_url}?type=1&host=#{host}" status = Hashie::Mash.new :host => host, @@ -410,9 +448,12 @@ end end nil end - - end + def debug(*args) + $stderr.puts *args if ENV['DEBUG'] + end + + end end