require 'sensu-plugin/check/cli'
require 'pathname'

#
# Check Fstab Mounts
#
class CheckFstabMounts < Sensu::Plugin::Check::CLI
  option :fstypes,
         description: 'Filesystem types to check, comma-separated',
         short: '-t TYPES',
         long: '--types TYPES',
         proc: proc { |a| a.split(',') },
         required: false

  # Setup variables
  #
  def initialize
    super
    @fstab = IO.readlines '/etc/fstab'
    @mtab = IO.readlines '/etc/mtab'
    @swap_mounts = IO.readlines '/proc/swaps'
    @missing_mounts = []
  end

  def resolve_device(device)
    if device.start_with?('UUID=')
      uuid = device.split('=')[1]
      path = File.join('/', 'dev', 'disk', 'by-uuid', uuid)
      if File.exist?(path) && File.symlink?(path)
        return File.realpath(path)
      end
    end

    if device.start_with?('LABEL=')
      label = device.split('=')[1]
      path  = File.join('/', 'dev', 'disk', 'by-label', label)
      if File.exist?(path) && File.symlink?(path)
        return File.realpath(path)
      end
    end

    if device.start_with?('/dev/mapper')
      if File.symlink?(device)
        device = File.realpath(device, '/')
      end
    end

    device
  end

  # Check by mount destination (col 2 in fstab and proc/mounts)
  #
  def check_mounts
    @fstab.each do |line|
      next if line =~ /^\s*#/
      next if line =~ /^\s*$/

      fields = line.split(/\s+/)
      next if fields[1] == 'none' || (fields[3].include? 'noauto')
      next if config[:fstypes] && !config[:fstypes].include?(fields[2])

      if fields[2] != 'swap'
        @missing_mounts << fields[1] if @mtab.select { |m| m.split(/\s+/)[1] == fields[1] }.empty?
      else
        @missing_mounts << fields[1] if @swap_mounts.select { |m| m.split(/\s+/)[0] == resolve_device(fields[0]) }.empty? # rubocop:disable Style/IfInsideElse
      end
    end
  end

  # Main function
  #
  def run
    check_mounts
    if @missing_mounts.any?
      critical "Mountpoint(s) #{@missing_mounts.join(',')} not mounted!"
    else
      ok 'All mountpoints accounted for'
    end
  end
end
