bin/check-bluepill-procs.rb
#! /usr/bin/env ruby
#
# check-bluepill-procs
#
# DESCRIPTION:
# This plugin monitors the status of applications and processes
# running under the bluepill process supervisor.
#
# Specify applications to monitor with -a [APP1,APP2]
# If this option is not provided, this check will monitor the processes
# of all the applications that bluepill has loaded.
#
# OUTPUT:
# plain text
# Returns CRITICAL if any process is down or if a manually specified
# application has no processes loaded
# Returns WARNING if any process is starting or unmonitored
# Returns OK if all processes for all specified applications are 'up'
# or bluepill is not in $PATH
#
# PLATFORMS:
# Linux
#
# DEPENDENCIES:
# gem: sensu-plugin
# gem: English
#
# USAGE:
#
# NOTES:
#
# LICENSE:
# James Legg mail@jameslegg.co.uk
# Matt Greensmith mgreensmith@cozy.co
# Released under the same terms as Sensu (the MIT license); see LICENSE
# for details.
#
require 'sensu-plugin/check/cli'
require 'English'
#
# Check application processes running under bluepill control
#
class CheckBluepill < Sensu::Plugin::Check::CLI
# a single application to monitor, or multiple applications, comma-separated.
# check all applications if option not provided.
option :apps,
short: '-a [APPS]',
long: '--applications [APPS]'
option :debug,
long: '--debug',
description: 'Verbose output'
option :sudo,
short: '-s',
long: '--sudo',
description: 'exec bluepill with sudo (needs passwordless)'
def merge_output(orig, add)
orig.each_key { |k| orig[k].push(*add[k]) }
orig
end
def bluepill_application_status(name)
out = { name: [], ok: [], warn: [], crit: [], err: [] }
app_status = `#{config[:sudo] ? 'sudo ' : nil }bluepill #{name} status 2<&1`
name = 'Unknown' if name == ''
out[:name] << name
puts "***** DEBUG: bluepill #{name} status *****\n#{app_status}" if config[:debug]
processes_found = 0
# #YELLOW
app_status.each_line do |line|
if line =~ /(pid:)/
processes_found += 1
case line
when /unmonitored$/
out[:warn] << "#{name}::#{line}".strip
next
when /starting$/
out[:warn] << "#{name}::#{line}".strip
next
when /down$/
out[:crit] << "#{name}::#{line}".strip
next
when /up$/
out[:ok] << "#{name}::#{line}".strip
next
end
end
end
out[:err] << name if processes_found.zero?
puts "***** DEBUG: bluepill #{name} status parsed ******\n#{out.inspect}" if config[:debug]
out
end
def parse_output(out)
puts "***** DEBUG: Full output hash ******\n#{out.inspect}" if config[:debug]
if !out[:crit].empty?
critical "Bluepill process(es) critical:\n#{out[:crit].join("\n")}"
elsif !out[:err].empty?
critical "Bluepill process(es) not found for applications: #{out[:err].join(',')}"
elsif !out[:warn].empty?
warning "Bluepill process(es) warning:\n#{out[:warn].join("\n")}"
else
ok "Bluepill normal, #{out[:name].count} application(s) with #{out[:ok].count} process(es) up."
end
end
def run
# Check if Bluepill is installed
`which bluepill`
# #YELLOW
unless $CHILD_STATUS.success?
ok 'bluepill not installed'
end
out = { name: [], ok: [], warn: [], crit: [], err: [] }
if config[:apps]
requested_apps = config[:apps].split(',').map(&:strip) || []
puts "***** DEBUG: requested applications: #{requested_apps}*****" if config[:debug]
requested_apps.each do |a|
out = merge_output(out, bluepill_application_status(a))
end
else
puts '***** DEBUG: checking all applications *****' if config[:debug]
bluepill_status = `#{config[:sudo] ? 'sudo ' : nil }bluepill status 2>&1`
if $CHILD_STATUS.success?
# we have only one application loaded and bluepill is
# 'helpfully' showing us only the status of that
# application's processes. We can't get the name of the
# application, however.
puts '***** DEBUG: bluepill status short-circuited to show status of a single unknown application *****' if config[:debug]
out = merge_output(out, bluepill_application_status(''))
else
# We either have multiple applications or no applications,
# or maybe bluepill is completely borked.
# (Returning non-zero when there are multiple applications
# loaded seems bizarre, but hey, that's just me.)
# We assume that no found applications is OK, since we only
# get here if -a option is unset.
# #YELLOW
bluepill_status.each_line do |line|
if line =~ /^\s \d\.\s/
app_name = line.split(/^\s \d\.\s/)[1].strip
# #YELLOW
puts "***** DEBUG: found an application: #{app_name} *****" if config[:debug] # rubocop:disable BlockNesting
out = merge_output(out, bluepill_application_status(app_name))
end
end
end
end
parse_output(out)
end
end