#!/usr/bin/ruby
#
# Check for pending security updates, via `apt-get`.
#
# Thsi check is only used when `unattended-upgrades` is not available, as
# `apt_upgrade_check` is preferred.
#
#

require 'yaml'

#
# Allow access to our common-code.
#
$LOAD_PATH << '/usr/share/bytemark'
$LOAD_PATH << '../lib/bytemark' if ENV['TEST'] && ENV['TEST_PREFIX']

require 'healthcheck/command_output'


#
# Test to see if we have pending package upgrades.
#
# We only alert upon security upgrades.
#
class AptUpgrade

  #
  #  Is this a debian system?
  #
  def is_debian?
    File.exist?("/usr/bin/apt-get")  &&
      File.directory?("/var/lib/apt/lists")
  end


  #
  #  Return a hash of upgradable Debian packages.
  #
  #  The key contains the package-name, and the value contains the
  # origin of the upgrade.
  #
  def upgradable_packages
    ret = Hash.new

    out = Bytemark::Healthcheck::CommandWrapper.run_command( "apt-get upgrade --simulate" )
    out.split( "\n" ).each do |line|

      # Split the line which will look something like:
      #
      #   Inst tacacs+-sso [1.1] (1.1 Unknown:maker2.bytemark.co.uk [amd64])
      #   Inst postgresql-contrib-9.3 [9.3.9-1.pgdg70+1] (9.3.10-1.pgdg70+1 PostgreSQL for Debian/Ubuntu repository:wheezy-pgdg [amd64]) []
      #
      if ( line =~ /^Inst\s([^\s+]+)\s.*\(([^)]+)\)/ )
        package = $1.dup
        details = $2.dup


        #
        #  The details contains:
        #
        #   version some-long-string [arch]
        #
        #  For example:
        #
        #    0.11.0-1+deb7u2 Debian-Security:7.0/oldstable [amd64]
        #
        if ( details =~ /^([^\s]+)\s+([^\[]+)\[(.*)$/ )

          #
          # This is the "origin" of the upgrade.
          #
          details = $2.dup
        end

        #
        #  Save the details away to our caller.
        #
        ret[package]=details
      end
    end

    ret
  end

  #
  #  Calculate upgrades which are ONLY security upgrades
  #
  def security_upgrades
    all = upgradable_packages
    ret = {}

    all.each do |key,value|
      ret[key] = value if ( value =~ /security/i )
    end

    ret
  end

end



if __FILE__ ==  $PROGRAM_NAME

  def verbose(str)
    STDERR.puts(str)
  end

  to_raise = []

  #
  # See how many pending upgrades are present.
  #
  helper   = AptUpgrade.new()
  upgrades = helper.is_debian? ? helper.security_upgrades : nil

  #
  # If unattend-upgrades is installed then we're doing nothing here.
  #
  if ( File.exists?( "/usr/bin/unattended-upgrades" ) )
    verbose( "Disabling test - /usr/bin/unattended-upgrades is present")
    upgrades = nil unless ENV['TEST'] && ENV['TEST_PREFIX']

  end

  if ( ! upgrades.nil? && !upgrades.empty? )
    h = {}
    h[:id] = "apt-get-upgrade-low"
    h[:summary] = "There are #{upgrades.size} pending security-upgrades available."
    h[:detail] = "<p>The following packages are pending security upgrades:</p><pre>#{upgrades.keys.join( "\n" )}</pre>"

    to_raise.push(h)
  end

  #
  #  Show the output.
  #
  puts YAML.dump(to_raise)
  exit(0)
end
