Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 49 additions & 32 deletions check_tableau_systeminfo
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/usr/bin/env ruby -w
#!/usr/bin/ruby -w

# Usage: check_tableau_systeminfo -H <hostname>|-f [<file.xml>]
# 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

Expand All @@ -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 } }
Expand All @@ -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']
Expand All @@ -36,69 +37,75 @@
# argument/options parsing and sanity checks
begin
options = {}

optparse = OptionParser.new do |opts|
opts.banner = "usage: check_tableau_systeminfo -H <hostname>|-f <file.xml>"
opts.banner = "usage: check_tableau_systeminfo -H <hostname>|-f <file.xml>|-S <systemname>"

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

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
Expand All @@ -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
Expand All @@ -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']
Expand Down
140 changes: 140 additions & 0 deletions check_tableau_systeminfo_9_0
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#!/usr/bin/env ruby

# Usage: check_tableau_systeminfo -H <hostname>|-f [<file.xml>]
# 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 <hostname>|-f <file.xml>"

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