diff --git a/check_tableau_systeminfo b/check_tableau_systeminfo index 9907833..a9cd451 100644 --- a/check_tableau_systeminfo +++ b/check_tableau_systeminfo @@ -1,9 +1,9 @@ -#!/usr/bin/env ruby -w +#!/usr/bin/ruby -w # Usage: check_tableau_systeminfo -H |-f [] # Description: check_tableau_systeminfo parses Tableau's systeminfo and reports Nagios status # for Tableau server (http://www.tableausoftware.com/products/server) -# + CRITICAL: any service instance that is DOWN +# + CRITICAL: any service instance that is DOWN # + WARNING: too many BUSY instances (per busy_thres) # Author: gerir_at_ning_dot_com @@ -12,7 +12,7 @@ require 'net/http' require 'uri' require 'xmlsimple' - + # busy thresholds # generates warning if n busy serviceinstances for service busy_thres = { 'W' => { 'serverwebapplication' => 12, 'vizqlserver' => 6 } } @@ -23,10 +23,11 @@ 'C' => { 'f' => nil, 'm' => '' , 'e' => 2, 's' => 'CRITICAL' }, 'U' => { 'f' => nil, 'm' => '' , 'e' => 3, 's' => 'UNKNOWN' } } - + $host = '' + # plugin output and exit code def nagiosMessageExit(status,message=nil) - unless message : message = $ns[status]['m'] end + message = $ns[status]['m'] unless message message.strip! puts "#{$ns[status]['s']}: #{message}" exit $ns[status]['e'] @@ -36,33 +37,35 @@ # argument/options parsing and sanity checks begin options = {} - + optparse = OptionParser.new do |opts| - opts.banner = "usage: check_tableau_systeminfo -H |-f " - + opts.banner = "usage: check_tableau_systeminfo -H |-f |-S " + options[:hostname] = nil opts.on( '-H', '--hostname HOSTNAME', 'Hostname' ) do |hostname| options[:hostname] = hostname - end - + $host = /([^.]+)\..*/.match(hostname) + end + options[:filename] = nil opts.on( '-f', '--filename FILENAME', 'Filename' ) do |filename| options[:filename] = filename + $host = /([^.]+)\..*/.match(filename) end - + options[:verbose] = nil opts.on( '-v', '--verbose', 'Verbose' ) do options[:verbose] = true end - + opts.on( '-h', '--help', 'Help' ) do puts opts exit end end - + optparse.parse! - + unless (options[:hostname] or options[:filename]) nagiosMessageExit('U', "unable to parse arguments (none provided)") end @@ -70,35 +73,39 @@ if options[:hostname] and options[:filename] nagiosMessageExit('U', "--hostname and --filename are mutually exclusive options") end - + rescue OptionParser::InvalidOption nagiosMessageExit('U', "error parsing options: #{$!}") - + rescue RuntimeError nagiosMessageExit('U', "#{$!}") - + end # fetch systeminfo # filename (useful for debugging) if options[:filename] - if options[:verbose] : puts "reading file #{options[:filename]}" end - begin + puts "reading file #{options[:filename]}" if options[:verbose] + begin + puts "#{$host[1]}" if options[:verbose] systeminfo = XmlSimple.xml_in(options[:filename], { 'KeyAttr' => 'name' }) rescue ArgumentError nagiosMessageExit('U', "#{$!}") end # hostname elsif options[:hostname] - if options[:verbose] : puts "contacting host #{options[:hostname]}" end + puts "contacting host #{options[:hostname]}" if options[:verbose] +# host = /([^.]+)\..*/.match(#{options[:hostname]}) begin - url = URI.parse("http://#{options[:hostname]}/admin/systeminfo") + url = URI.parse("http://#{options[:hostname]}/admin/systeminfo.xml") req = Net::HTTP::Get.new(url.path) res = Net::HTTP.start(url.host, url.port) {|http| http.request(req) } - if options[:verbose] : puts "parsing systeminfo\n#{res.body}" end + puts "parsing systeminfo\n#{res.body}" if options[:verbose] systeminfo = XmlSimple.xml_in(res.body, { 'KeyAttr' => 'name' }) + rescue Timeout::Error + nagiosMessageExit('C', "#{$!}") rescue Errno::ECONNREFUSED nagiosMessageExit('C', "#{$!}") rescue REXML::ParseException @@ -108,21 +115,31 @@ end end -# analyze systeminfo +# systeminfo["machines"][0]["machine"]["Primary"].each do |service| +# analyze systeminfo if systeminfo["machines"] - systeminfo["machines"][0]["machine"]["Primary"].each do |service| + systeminfo["machines"][0]["machine"]["#{$host[1]}"].each do |service| busy_c = 0 service[1].each do |serviceinstance| - if (serviceinstance["status"].casecmp "down") == 0 - $ns['C']['m'] += "#{service[0]} #{serviceinstance["worker"]} is DOWN! " - $ns['C']['f'] = true - break - elsif (serviceinstance["status"].casecmp "busy") == 0 - busy_c += 1 + puts "service #{service[0]} #{serviceinstance["status"]}" if options[:verbose] + if (service[0] == "filestore") + if (serviceinstance["failedTransfers"].to_i >0) + $ns['C']['m'] += "filestore failedTransfers >0 " + $ns['C']['f'] = true + end + end + if (serviceinstance["status"].casecmp("Active") < 0) + if (serviceinstance["status"].casecmp("busy")) == 0 + busy_c += 1 + else + $ns['C']['m'] += "#{service[0]} is DOWN! " + $ns['C']['f'] = true + break + end end end break if $ns['C']['f'] - + if busy_thres['W'][service[0]] if busy_c >= busy_thres['W'][service[0]] $ns['W']['f'] = true @@ -134,7 +151,7 @@ nagiosMessageExit('U', "unable to parse systeminfo") end -# report status +# report status if $ns['C']['f'] nagiosMessageExit('C') elsif $ns['W']['f'] diff --git a/check_tableau_systeminfo_9_0 b/check_tableau_systeminfo_9_0 new file mode 100755 index 0000000..44a814c --- /dev/null +++ b/check_tableau_systeminfo_9_0 @@ -0,0 +1,140 @@ +#!/usr/bin/env ruby + +# Usage: check_tableau_systeminfo -H |-f [] +# Description: check_tableau_systeminfo parses Tableau's systeminfo and reports Nagios status +# for Tableau server (http://www.tableausoftware.com/products/server) +# + CRITICAL: any service instance that is DOWN +# + WARNING: too many BUSY instances (per busy_thres) +# Author: gerir_at_ning_dot_com + + require 'rubygems' + require 'optparse' + require 'net/http' + require 'uri' + require 'xmlsimple' + + # busy thresholds + # generates warning if n busy serviceinstances for service + busy_thres = { 'W' => { 'serverwebapplication' => 12, 'vizqlserver' => 6 } } + + # global indeed; apologies + $ns = { 'O' => { 'f' => nil, 'm' => 'systeminfo OK', 'e' => 0, 's' => 'OK' }, + 'W' => { 'f' => nil, 'm' => '' , 'e' => 1, 's' => 'WARNING' }, + 'C' => { 'f' => nil, 'm' => '' , 'e' => 2, 's' => 'CRITICAL' }, + 'U' => { 'f' => nil, 'm' => '' , 'e' => 3, 's' => 'UNKNOWN' } + } + + # plugin output and exit code + def nagiosMessageExit(status,message=nil) + unless message : message = $ns[status]['m'] end + message.strip! + puts "#{$ns[status]['s']}: #{message}" + exit $ns[status]['e'] + end + + +# argument/options parsing and sanity checks + begin + options = {} + + optparse = OptionParser.new do |opts| + opts.banner = "usage: check_tableau_systeminfo -H |-f " + + options[:hostname] = nil + opts.on( '-H', '--hostname HOSTNAME', 'Hostname' ) do |hostname| + options[:hostname] = hostname + end + + options[:filename] = nil + opts.on( '-f', '--filename FILENAME', 'Filename' ) do |filename| + options[:filename] = filename + end + + options[:verbose] = nil + opts.on( '-v', '--verbose', 'Verbose' ) do + options[:verbose] = true + end + + opts.on( '-h', '--help', 'Help' ) do + puts opts + exit + end + end + + optparse.parse! + + unless (options[:hostname] or options[:filename]) + nagiosMessageExit('U', "unable to parse arguments (none provided)") + end + + if options[:hostname] and options[:filename] + nagiosMessageExit('U', "--hostname and --filename are mutually exclusive options") + end + + rescue OptionParser::InvalidOption + nagiosMessageExit('U', "error parsing options: #{$!}") + + rescue RuntimeError + nagiosMessageExit('U', "#{$!}") + + end + +# fetch systeminfo + # filename (useful for debugging) + if options[:filename] + if options[:verbose] : puts "reading file #{options[:filename]}" end + begin + systeminfo = XmlSimple.xml_in(options[:filename], { 'KeyAttr' => 'name' }) + rescue ArgumentError + nagiosMessageExit('U', "#{$!}") + end + # hostname + elsif options[:hostname] + if options[:verbose] : puts "contacting host #{options[:hostname]}" end + begin + url = URI.parse("http://#{options[:hostname]}/admin/systeminfo.xml") + req = Net::HTTP::Get.new(url.path) + res = Net::HTTP.start(url.host, url.port) {|http| + http.request(req) + } + if options[:verbose] : puts "parsing systeminfo\n#{res.body}" end + systeminfo = XmlSimple.xml_in(res.body, { 'KeyAttr' => 'name' }) + rescue Errno::ECONNREFUSED + nagiosMessageExit('C', "#{$!}") + rescue REXML::ParseException + nagiosMessageExit('U', "unable to parse systeminfo") + rescue + nagiosMessageExit('U', "#{$!}") + end + end +#parse XML + begin + sysinfo = systeminfo["machines"][0]["machine"] + serinfo = systeminfo["service"] + for system in sysinfo.keys() + for app in sysinfo[system].keys() + for status in sysinfo[system][app] + if status.keys().include?("status") + if not (status["status"] == "Active" or status["status"] == "Standby") + nagiosMessageExit('C',"Non OK or Standby status in: #{system}:#{app}:#{status}") + end + end + end + end + end + rescue + nagiosMessageExit('C', "Error parsing tableau state. systeminfo is: #{systeminfo}") + end + # parse service + if not serinfo[0]["status"] == "Active" + nagiosMessageExit('C',"Service status not Active: #{serinfo[0]["status"]}") + end + +# report status + if $ns['C']['f'] + nagiosMessageExit('C') + elsif $ns['W']['f'] + nagiosMessageExit('W') + else + nagiosMessageExit('O') + end