Skip to content

Instantly share code, notes, and snippets.

@rodjek
Last active December 19, 2015 03:18
Show Gist options
  • Save rodjek/5889073 to your computer and use it in GitHub Desktop.
Save rodjek/5889073 to your computer and use it in GitHub Desktop.
check_puppet_run_health

check_puppet_run_health

A Nagios check that connects to PuppetDB and determines the Puppet agent run health on a host.

Requires

  • PuppetDB
  • A puppetmaster configured to send reports to PuppetDB

States

Unknown

The check will return an UNKNOWN state if there are no reports stored in PuppetDB for the specified host.

Critical

The check will return a CRITICAL state if there are resources in the latest report for the specified host that are failing to apply.

Warning

The check will return a WARNING state if there are resources that have applied the same change in the last two reports for the specified host (e.g. an Exec that isn't guarded by creates, unless or onlyif).

Usage

$ check_puppet_run_health -d <puppetdb host> -p <puppetdb port> --[no-]ssl -h <host to check>
$ check_puppet_run_health -d localhost -p 8080 -s -h testnode.example.com
CRITICAL: 1 failing actions, 1 recurring actions

FAILING ACTIONS
---------------
Package[whatever]/ensure: changed from 'purged' to 'installed' failed

RECURRING ACTIONS
-----------------
Service[foo]/ensure: changed from 'stopped' to 'running'
#!/usr/bin/env ruby
require 'rubygems'
require 'json'
require 'net/http'
require 'net/https'
require 'optparse'
class CheckPuppetRunHealth
def self.run
options = {}
OptionParser.new do |opts|
opts.banner = 'check_puppet_run_health'
opts.on '-h', '--host HOST' do |val|
options[:host] = val
end
opts.on '-d', '--puppetdb HOST' do |val|
options[:puppetdb_host] = val
end
opts.on '-p', '--port PORT' do |val|
options[:puppetdb_port] = val.to_i
end
opts.on '-s', '--[no-]ssl' do |val|
options[:ssl] = val
end
end.parse!
api = PuppetDB.new :host => options[:puppetdb_host],
:port => options[:puppetdb_port],
:ssl => options[:ssl]
reports = api.reports(options[:host]).first(2)
if reports.empty?
puts "UNKNOWN - This host has no reports stored in PuppetDB"
return 3
end
current_report = api.events(reports.first['hash'])
failing_events = current_report.select do |event|
event['status'] != 'success'
end
if reports.count == 2
old_report = api.events(reports.last['hash'])
else
old_report = []
end
recurring_events = (current_report & old_report) - failing_events
if !failing_events.empty?
status = 'CRITICAL'
exit_code = 2
elsif !recurring_events.empty?
status = 'WARNING'
exit_code = 1
else
status = 'OK'
exit_code = 0
end
puts "#{status}: #{failing_events.count} failing actions, #{recurring_events.count} recurring actions"
unless failing_events.empty?
puts "\nFAILING EVENTS"
puts "--------------"
failing_events.each do |event|
puts [
"#{event['resource-type']}[#{event['resource-title']}]/#{event['property']}:",
event['message'],
].join(' ')
end
end
unless recurring_events.empty?
puts "\nRECURRING EVENTS"
puts "----------------"
recurring_events.each do |event|
puts [
"#{event['resource-type']}[#{event['resource-title']}]/#{event['property']}:",
event['message'],
].join(' ')
end
end
return exit_code
end
class PuppetDB
def initialize(opts)
@host = opts[:host]
@port = opts[:port]
@ssl = opts[:ssl] || false
end
def query(uri, *params)
http = Net::HTTP.new(@host, @port)
http.use_ssl = @ssl
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new uri, 'Accept' => 'application/json'
request.set_form_data 'query' => params.inspect
response = http.request(request)
JSON.parse(response.body)
end
def reports(host)
query '/experimental/reports', '=', 'certname', host
end
def events(report)
events = query '/experimental/events', 'and',
['=', 'report', report],
['not',
['or',
['=', 'status', 'skipped'],
['=', 'status', 'noop'],
],
]
# strip out the report id and timestamp so we can easily diff the array
events.map do |event|
event.delete 'report'
event.delete 'timestamp'
event
end
end
end
end
exit CheckPuppetRunHealth.run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment