thomis/sensu-plugins-oracle

View on GitHub
bin/check-oracle-query.rb

Summary

Maintainability
A
0 mins
Test Coverage
#! /usr/bin/env ruby
#
#   check-oracle-query
#
# DESCRIPTION:
#   This plugin attempts to execute defined query against provided
#   connection credential(s).
#
# OUTPUT:
#   plain text
#
# PLATFORMS:
#   Linux
#
# DEPENDENCIES:
#   gem: sensu-plugin
#   gem: ruby-oci8
#
# USAGE:
#   ./check-oracle-query.rb -u USERNAME -p PASSWORD -d DATABASE \
#                           -P PRIVILEGE -T TIMEOUT -f FILE \
#                           -q 'select foo from bar' \
#                           -w 'value > 5' -c 'value > 10'
#
# NOTES:
#
# LICENSE:
#   Copyright (c) 2016 Thomas Steiner
#   Released under the same terms as Sensu (the MIT license); see LICENSE
#   for details.
#

require 'sensu-plugins-oracle'
require 'sensu-plugin/check/cli'

# Check Oracle Query
class CheckOracleQuery < Sensu::Plugin::Check::CLI
  option :username,
         description: 'Oracle Username',
         short: '-u USERNAME',
         long: '--username USERNAME'

  option :password,
         description: 'Oracle Password',
         short: '-p PASSWORD',
         long: '--password PASSWORD'

  option :database,
         description: 'Database schema to connect to',
         short: '-d DATABASE',
         long: '--database DATABASE'

  option :module,
         description: 'Module that the oracle sessions will use',
         short: '-m',
         long: '--module MODULE'

  option :privilege,
         description: 'Connect to Oracle database by optional priviledge' \
                      ' (SYSDBA, SYSOPER, SYSASM,  , SYSDG or SYSKM)',
         short: '-P PRIVILEGE',
         long: '--privilege PRIVILEGE'

  option :timeout,
         description: 'Connection timeout (seconds)',
         short: '-T TIMEOUT',
         long: '--timeout TIMEOUT'

  option :file,
         description: 'File with connection strings to check',
         short: '-f FILE',
         long: '--file FILE'

  option :query,
         description: 'Database query to execute',
         short: '-q QUERY',
         long: '--query QUERY'
         # required: true

  option :warning,
         description: 'Warning threshold expression',
         short: '-w WARNING',
         long: '--warning WARNING',
         default: nil

  option :critical,
         description: 'Critical threshold expression',
         short: '-c CRITICAL',
         long: '--critical CRITICAL',
         default: nil

  option :tuples,
         description: 'Count the number of tuples (rows) returned by the query',
         short: '-t',
         long: '--tuples',
         boolean: true,
         default: false

  option :show,
         description: 'Show result records',
         short: '-s',
         long: '--show',
         boolean: true,
         default: false

  option :worker,
         description: 'Number of worker threads to execute query' \
                      ' against provided connections',
         short: '-W WORKER',
         long: '--worker WORKER',
         default: 1,
         proc: proc { |v| v.to_i.zero? ? 1 : v.to_i }

  option :limit,
         description: 'Limits output size in characters',
         short: '-l SIZE',
         long: '--limit SIZE',
         default: nil

  option :verbose,
         description: 'Shows console log messages',
         short: '-V',
         long: '--verbose',
         boolean: true,
         default: false

  option :version,
         description: 'Shows current version',
         short: '-v',
         long: '--version',
         boolean: true,
         default: false

  def run
    # handle OCI8 properties
    ::SensuPluginsOracle::Session.timeout_properties(config[:timeout])

    if config[:version]
      ok("Version #{SensuPluginsOracle::VERSION}")
      return
    end

    if config[:query].nil?
      warning("You must supply: -q QUERY")
      return
    end

    if config[:file]
      handle_connections_from_file
    else
      handle_connection
    end
  end

  private

  def handle_connection
    session = SensuPluginsOracle::Session.new(username: config[:username],
                                              password: config[:password],
                                              database: config[:database],
                                              privilege: config[:privilege],
                                              module: config[:module])

    if session.query(config[:query].to_s)
      method, message = session.handle_query_result(config)
      send(method, limit(message))
    else
      # issue with the query
      critical limit(session.error_message)
    end
  end

  def handle_connections_from_file
    sessions = ::SensuPluginsOracle::Session.parse_from_file(config[:file],
                                                             config[:module])
    ::SensuPluginsOracle::Session.handle_multiple(sessions: sessions,
                                                  method: :query,
                                                  config: config,
                                                  method_args: config[:query])

    results = Hash.new { |h, key| h[key] = [] }
    sessions.each do |session|
      message = session.error_message
      if message
        results[:critical] << message
      else
        type, message = session.handle_query_result(config)
        results[type] << message
      end
    end

    method, messages = summary(results, sessions.size)

    send(method, limit(messages.join("\n")))
  rescue => e
    unknown limit(e.to_s)
  end

  # returns summary based on header and detailed (warning & critical) messages
  def summary(results, session_count)
    # header
    method = :ok
    headers = ["Total: #{session_count}"]
    messages = []

    headers << "Ok: #{results[:ok].size}" unless results[:ok].empty?

    [:warning, :critical].each do |type|
      next if results[type].empty?
      method = type
      label = type.to_s.capitalize
      headers << "#{label}: #{results[type].size}"
      messages << [label, results[type].compact.sort.join("\n\n")]
    end

    [method, [headers, messages].flatten]
  end

  def limit(message)
    return message if config[:limit].nil?
    message[0..config[:limit].to_i]
  end
end