sensu-plugins/sensu-plugins-sftp

View on GitHub
bin/check-sftp.rb

Summary

Maintainability
A
0 mins
Test Coverage
#! /usr/bin/env ruby
# frozen_string_literal: false

#
#   check-sftp
#
# DESCRIPTION:
#   Provides checks against an sFTP site.
#
#   1)  SFTP Connection Testing
#   2)  File Writes
#   3)  File Count Exceeding
#   4)  Files Older Than
#
# OUTPUT:
#   plain text, metric data, etc
#
# PLATFORMS:
#   Linux, Windows, BSD, Solaris, etc
#
# DEPENDENCIES:
#   gem: sensu-plugin
#   gem: net-sftp
#
# USAGE:
#   #YELLOW
#
# NOTES:
#
# LICENSE:
#   Charles Cooke   <charles@coupa.com>
#   Released under the same terms as Sensu (the MIT license); see LICENSE
#   for details.
#

require 'sensu-plugin/check/cli'
require 'net/sftp'

# Checks sFTP site
class CheckSftp < Sensu::Plugin::Check::CLI
  option :host,
         short: '-h HOST',
         long: '--host HOST',
         description: 'Sftp Host',
         required: true

  option :port,
         short: '-P PORT',
         long: '--port PORT',
         description: 'Sftp Port',
         proc: proc(&:to_i),
         default: 22

  option :username,
         short: '-u USERNAME',
         long: '--user USERNAME',
         description: 'Sftp Username',
         required: true

  option :password,
         short: '-s PASSWORD',
         long: '--pass PASSWORD',
         description: 'Sftp Password',
         default: '',
         required: true

  option :timeout,
         short: '-t TIMEOUT',
         long: '--timeout TIMEOUT',
         proc: proc(&:to_i),
         description: 'Sftp Timeout',
         default: 60

  option :directory,
         short: '-d DIRECTORY',
         long: '--directory DIRECTORY',
         description: 'Directory to use for file checks',
         default: '/'

  option :match,
         short: '-m MATCH',
         long: '--match MATCH',
         description: 'Match files with this pattern for counting/file aging checks (**, **/*).'

  option :check_prefix,
         short: '-x PREFIX',
         description: 'Prefix for temporary file write check. Blank for none.'

  option :check_count,
         short: '-n COUNT',
         long: '--number COUNT',
         proc: proc(&:to_i),
         description: 'Alert if files > COUNT in directory'

  option :check_older,
         short: '-o OLDER_THAN',
         long: '--older_than OLDER_THAN',
         proc: proc(&:to_i),
         description: 'Alert if any file age > OLDER_THAN seconds'

  def run
    if sftp
      check_file_write
      check_file_count
      check_file_age
    end

    ok
  rescue SocketError => e
    critical "Could not connect: #{e.inspect}"
  rescue Net::SSH::AuthenticationFailed
    critical "Failed authentication with #{config[:username]}"
  rescue Net::SFTP::StatusException => e
    critical "SFTP Error - #{e.message}"
  rescue => e # rubocop: disable Style/RescueStandardError
    critical "Unexpected error; #{e.inspect}"
  end

  private

  def check_file_write
    if config[:check_prefix]
      io = StringIO.new('Generated from Sensu at ' + Time.now.to_s)
      remote_path = File.join('', config[:directory], config[:check_prefix] + "_#{Time.now.to_i}.txt")
      sftp.upload!(io, remote_path)
      sftp.remove!(remote_path)
    end
  end

  def check_file_count
    if config[:check_count]
      critical "Too many files - #{config[:directory]} has #{matching_files.count} matching files" if matching_files.count > config[:check_count]
    end
  end

  def check_file_age
    if config[:check_older]
      run_at    = Time.now
      old_files = matching_files.select { |f| (run_at.to_i - f.attributes.mtime) > config[:check_older] }
      unless old_files.empty?
        critical "Files too old - #{config[:directory]} has #{old_files.count} matching files older than #{config[:check_older]}s"
      end
    end
  end

  def matching_files
    @matching_files ||= sftp.dir.glob(config[:directory], config[:match]).select { |f| f.attributes.file? }
  end

  def sftp
    @sftp ||= Net::SFTP.start(config[:host], config[:username], password: config[:password],
                                                                timeout: config[:timeout],
                                                                port: config[:port],
                                                                auth_methods: %w[publickey password])
  end
end