bin/check-service-consul.rb
#! /usr/bin/env ruby
# frozen_string_literal: true
#
# check-service-consul
#
# DESCRIPTION:
# This plugin checks if consul says a service is 'passing' or
# 'critical'
#
# OUTPUT:
# plain text
#
# PLATFORMS:
# Linux
#
# DEPENDENCIES:
# gem: sensu-plugin
# gem: diplomat
#
# USAGE:
# ./check-service-consul -s influxdb
# ./check-service-consul -a
#
# NOTES:
#
# LICENSE:
# Copyright 2015 Yieldbot, Inc. <Sensu-Plugins>
# Released under the same terms as Sensu (the MIT license); see LICENSE
# for details.
#
require 'sensu-plugin/check/cli'
require 'diplomat'
#
# Service Status
#
class ServiceStatus < Sensu::Plugin::Check::CLI
option :consul,
description: 'consul server',
long: '--consul SERVER',
default: 'http://localhost:8500'
option :service,
description: 'a service managed by consul',
short: '-s SERVICE',
long: '--service SERVICE',
default: 'consul'
option :tags,
description: 'filter services by a comma-separated list of tags (requires --service)',
short: '-t TAGS',
long: '--tags TAGS'
option :all,
description: 'get all services in a non-passing status (not compatible with --tags)',
short: '-a',
long: '--all'
option :fail_if_not_found,
description: 'fail if no service is found',
short: '-f',
long: '--fail-if-not-found'
option :token,
description: 'ACL token',
long: '--token ACL_TOKEN'
# Get the check data for the service from consul
#
def acquire_service_data
if config[:tags] && config[:service]
tags = config[:tags].split(',').to_set
services = []
Diplomat::Health.service(config[:service]).each do |s|
if s['Service']['Tags'].to_set.superset? tags
services.push(*s['Checks'])
end
end
return services
elsif config[:all]
Diplomat::Health.state('any')
else
Diplomat::Health.checks(config[:service])
end
rescue Faraday::ConnectionFailed => e
warning "Connection error occurred: #{e}"
rescue Diplomat::UnknownStatus => e
if e.message.include?('403')
critical %(ACL token is not authorized to access service "#{config[:service]}")
else
critical "Unhandled exception(#{e.class}) -- #{e.message}"
end
rescue Faraday::ClientError => e
if e.response[:status] == 403
critical %(ACL token is not authorized to access service "#{config[:service]}": #{e.response[:body]})
else
unknown "Exception occurred when checking consul service: #{e}"
end
rescue StandardError => e
unknown "Exception occurred when checking consul service: #{e}"
end
# Main function
#
def run
if config[:tags] && config[:all]
critical 'Cannot specify --tags and --all simultaneously (Consul health/service/ versus health/state/).'
end
Diplomat.configure do |dc|
dc.url = config[:consul]
dc.acl_token = config[:token]
dc.options = {
headers: {
'X-Consul-Token' => config[:token]
}
}
end
data = acquire_service_data
passing = []
failing = []
data.each do |d|
if d['Status'] == 'passing'
passing << {
'node' => d['Node'],
'service' => d['ServiceName'],
'service_id' => d['ServiceID'],
'notes' => d['Notes']
}
elsif d['Status'] == 'critical'
failing << {
'node' => d['Node'],
'service' => d['ServiceName'],
'service_id' => d['ServiceID'],
'notes' => d['Notes']
}
end
end
if failing.empty? && passing.empty?
msg = 'Could not find checks for any services'
if config[:service]
msg = "Could not find checks for service #{config[:service]}"
if config[:tags]
msg += " with tags #{config[:tags]}"
end
end
if config[:fail_if_not_found]
critical msg
else
unknown msg
end
end
critical failing unless failing.empty?
ok passing unless passing.empty?
end
end