# -*-perl-*-

# $Id$

# Check for un-scheduled host atom partitions

# $Log$
# Revision 1.1  2005/02/10 19:35:09  thomas
# New addition
#


package Sushi::Command::AuditHosts;

use strict;
use Data::Dumper;
# use DirHandle;
use Time::localtime;
use IO::Pipe;
use Net::hostent;
use XML::Simple;


sub main {

  my $class = shift;
  my $group = shift;

  my ($row, $pname, %policy, $csdbh, $sth, $href, %cpus, $h, $fh, $fn, %extras);
  my ($config, $current, $skip, $match, $attr, $a);

  # Read in the XML
  $config = XMLin ("/s/sushi-0.3.22/etc/audithosts.xml");

  # Read in the policy information
  foreach $row (@{Sushi::GenDB::fetch (
				       {},
				       {},
				       $::table_defs->{wspolicy}
				      )}) {
    $pname = "$row->{os}:$row->{dump_policy}";
    defined $policy{$pname} or $policy{$pname} = [];
    push @{$policy{$pname}}, {%$row};
  }

  # Read in the extra information
  foreach $row (@{Sushi::GenDB::fetch (
				       {},
				       {},
				       $::table_defs->{extra_atoms}
				      )}) {

    # This is a hack to only extract the host atoms from extras
    if ($row->{name} =~ /(\S*\.wisc\.edu)\:([^:]+)$/) {
      $extras{$1}->{$2} = 1;
    }
  }

  # Get list of hosts from csdb
  defined ($csdbh = Sushi::Misc::openCSDB)
    or die "Failed to open CSDB!\n";
  defined ($sth = $csdbh->prepare ('billtype'))
    or die "Can't fetch host/policy tuples from csdb!\n";
  $sth->execute;
  while (defined ($href = $sth->fetchrow_hashref)) {
    defined $href->{os} or next;
    defined $href->{bupolicy} or next;
    defined $href->{cpuname} or next;
    $pname = "$href->{os}:$href->{bupolicy}";
    defined $policy{$pname} or next;

    if (($h = gethost($href->{cpuname})) && $h->name ne $href->{cpuname}) {
      $::log->log (2, "Using " . $h->name . " for $href->{cpuname}\n");
      $href->{cpuname} = $h->name;
    }
    $cpus{$href->{cpuname}} = $href->{bupolicy};

    # Check correspondence between bill type and dump policy
    if ($href->{billtype} == 1 || $href->{billtype} == 4) {
      if ($href->{bupolicy} !~ /(normal)/) {
	$::log->log (1, "Check: $href->{cpuname}: Bill Type = $href->{billtype} but backup policy = $href->{bupolicy}!\n");
      }
    }
  }
  $csdbh->disconnect;
  $csdbh = undef;

  # Make the file of hosts for mssh
  $fn = "/tmp/ha.$$";
  $::log->log (1, "Writing host file $fn.\n");
  defined ($fh = new FileHandle $fn, 'w')
    or die "Failed to open $fn for writing!\n";
  foreach (sort keys %cpus) {
    print $fh "$_\n";
  }

  # Close down all the sockets before we go to fork madness
  # Read the data
  defined ($fh = new FileHandle "/s/lab/bin/mssh --force --threads 200 --timeout 120 --file $fn 'df -k'|")
    or die "Failed to start mssh!\n";
  DATA: while (<$fh>) {
    # Check for missing host
    if (/Warning\! Host.*was not found in DNS.  Removing from list!/) {
      print STDERR $_;
      next
    }

    # Skip timeouts
    if (/^(\S+\.wisc\.edu): TIMED OUT!!!!/) {
      $::log->log (3, "Timeout: $_");
      next;
    }

    # Skip the df -k header
    /\:Filesystem.*Mounted on/ and next;

    # Should have good data now
    if (/^(\S+.wisc\.edu):(\S+)\s+\d+\s+\d+\s+\d+\s+\d+\%\s+(\S+)\s*$/) {
      $current = {
		  host => $1,
		  device => $2,
		  mountpoint => $3,
		 };
      if ($current->{host} =~ 'norm') {
	my $foo = 1;
      }
      if ($extras{$current->{host}}->{$current->{mountpoint}}) {
	$::log->log (3, "Already in extras: $_");
	next;
      }

      # Now check it against the xml
      foreach $skip (@{$config->{skip}}) {
	$match = 1;
	foreach $attr (grep !/reason/, keys (%$skip)) {
	  $a = $skip->{$attr};
	  $current->{$attr} =~ m:$a: or ($match = 0,last);
	}
	if ($match == 1) {
	  $::log->log (3, "Ignore ($skip->{reason}): $_");
	  next DATA;
	}
      }
      $::log->log (1, "Check: $current->{host} $current->{device} $current->{mountpoint}\n");
      next;
    }

    $::log->log (0, "Unknown: $_");

  }


  return 0;
}

###############################################################################

sub Aliases {
  return ();
}

###############################################################################

sub shortHelp {
  return "Check hosts for atoms that aren't being backed up";
}

###############################################################################

sub help {
  my $help = <<__Eof__

audithosts

Checks all hosts currently backed up with any backup type other than 'none'
or 'fstab'.  List any unusual partitions that aren't being backed up.

__Eof__
    ;
}

###############################################################################

1;
