#!/usr/bin/perl
#
# This script is a component of Warewulf,
# http://www.runlevelzero.net/greg/warewulf
#
#########################################################################
#
# Copyright (c) 2003, The Regents of the University of California, through
# Lawrence Berkeley National Laboratory (subject to receipt of any
# required approvals from the U.S. Dept. of Energy).  All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# The GNU GPL Document can be found at:
# http://www.gnu.org/copyleft/gpl.html
#
#########################################################################
#
# Written and maintained by:
#       Greg Kurtzer, <gmkurtzer@lbl.gov>

use lib "/usr/lib/warewulf/", "/usr/lib64/warewulf/";
use Warewulf::Config;
use Warewulf::Status;
use Warewulf::Util;
use Getopt::Long;
use Sys::Hostname;
use IO::Socket;
use strict;

Getopt::Long::Configure ("bundling");

my (
   $usage,
   $ready,
   $help,
   $lam,
   $mpi,
   $idle,
   $down,
   $quiet,
   $mine,
   $entry,
   $value,
   $nodename,
   %nodestatus,
   %nodes,
   %master,
   %node_ips,
   $type,
   $out_ready,
   $out_notready,
   %node_access,
   %filter,
   @nodes_ready,
   @nodes_unavailable,
   @nodes_down,
   @nodes_unknown,
   @nodes_sleeping,
   $node_count,
   $banners,
   $i,
   $mastername,
   %config,
   $master,
   $hostname,
   %masterinfo,
   $status,
   %nodes,
   $config,
   $show_cluster,
   $name,
   $remote_master,
   $cpus,
);

$usage = "USAGE: $0 [options] [hostname]
  About:
    wwlist shows a list of the currently running nodes in the cluster. You 
    can use it to make a MPI or PVM machine file, or just get a list of the 
    nodes in the current ready position.
  Options:
   -r, --ready      Only show nodes that are ready (shortcut for -s ready)
   -i, --idle       Only show nodes that are idle
   -d, --down       Only show nodes that are _NOT_ ready (shortcut again)
   -m, --mpi        Output a MPI compatiable file for the node list
   -l, --lam        Output a LAM MPI compatiable file for the node list
   -p, --pvm        Output a PVM compatiable file for the node list
   -c, --cluster    Display the cluster name in the output
   -s, --status     Only show nodes matching a particular status:
                     ready, down, unavailable, unknown
       --config     Show node configuration information from config:
                     desc, vnfs, group, group desc, user names, etc...
   -q, --quiet      Only show nodes that are up with no extra verbage
   -h, --help       Show this banner

  This tool is part of the Warewulf cluster distribution
     http://warewulf-cluster.org/
";

GetOptions(
   'quiet|q'     => \$quiet,
   's|status=s'  => \$status,
   'lam|l'       => \$lam,
   'mpi|m'       => \$mpi,
   'pvm|p'       => \$mpi,
   'idle|i'      => \$idle,
   'ready|r'     => \$ready,
   'down|d'      => \$down,
   'config=s'    => \$config,
   'c|cluster'   => \$show_cluster,
   'help|h'      => \$help,
);

if ( $ready ) {
   $status = "ready";
}
if ( $idle ) {
   $status = "ready";
}
if ( $down ) {
   $status = "(down|unknown|unavailable)";
}

if ( $help ) {
   print $usage;
   exit;
}

if ( $quiet ) {
   # clean up output
   $banners = '1';
}

if ( $lam and $mpi ) {
   die "You selected options that should not be mixed!\n" ;
}

%config = &client_config();
#if ( $ARGV[0] ) {
#   $master = $ARGV[0];
#} else {
#   $master = $config{'warewulf master'};
#}
if ( $ARGV[0] ) {
   $master = $hostname = $ARGV[0];
   $remote_master = '1';
} else {
   $master = $config{'warewulf master'};
   if ( $master eq "localhost" ) {
      $hostname = hostname();
   } else {
      $hostname = $config{'warewulf master'};
   }
}

$cpus = 0;

%nodestatus = &node_status($master);
%filter = &users_filter();

if ( -d "/etc/warewulf/nodes" ) {
   %nodes = &node_config();
}


if ( ! $remote_master ) {
   if ( $lam ) {
      chomp (my $master_hostname = `hostname`);
      print "# Master node\n";
      print "$master_hostname cpu=1\n\n";
   } elsif ( $mpi ) {
      chomp (my $master_hostname = `hostname`);
      print "# Master node\n";
      print "$master_hostname\n\n";
   }
}


foreach ( sort keys %nodestatus ) {
   if ( ! $filter{$_} and defined %filter ) {
      next;
   }
   if ( $idle and ( $nodestatus{$_}{USERPROC} > 0 or $nodestatus{$_}{CPUUTIL} >= 5 ) ) {
     next;
   }
   if ( $nodestatus{$_}{NODESTATUS} eq 'READY' ) {
      push(@nodes_ready, $_);
   } elsif ( $nodestatus{$_}{NODESTATUS} eq 'DOWN' ) {
      push(@nodes_down, $_);
   } elsif ( $nodestatus{$_}{NODESTATUS} eq 'ASLEEP' ) {
      push(@nodes_sleeping, $_);
   } elsif ( $nodestatus{$_}{NODESTATUS} eq 'unavailable' ) {
      push(@nodes_unavailable, $_);
   } else {
      push(@nodes_unknown, $_);
   }
   $node_count++;
}

if ( @nodes_ready and ( ! $status or "ready" =~ /$status/i ) ) {
   if ( $idle ) {
      print "# Nodes idle:\n" unless $banners;
   } else {
      print "# Nodes ready:\n" unless $banners;
   }
   foreach (sort @nodes_ready ) {
      if ( $show_cluster ) {
         $name = $_;
      } else {
         $name = $nodestatus{$_}{NODENAME};
      }
      if ( $lam ) {
         print "$name cpu=$nodestatus{$_}{CPUCOUNT}\n";
         $cpus += $nodestatus{$_}{CPUCOUNT};
      } elsif ( $mpi ) {
         for ($i=0; $i<$nodestatus{$_}{CPUCOUNT}; $i++) {
            print "$name\n";
            $cpus++;
         }
      } elsif ( $config) {
         print "$name\t", $nodes{$name}{"$config"}, "\n";
      } else {
         print "$name\n";
      }
   }
   print "\n" unless $banners;
}

if ( @nodes_unavailable and ( ! $status or "unavailable" =~ /$status/i ) ) {
   print "# Nodes unavailable:\n" unless $banners;
   foreach (sort @nodes_unavailable ) {
      if ( $show_cluster ) {
         $name = $_;
      } else {
         $name = $nodestatus{$_}{NODENAME};
      }
      if ( $lam or $mpi ) {
         print "#$name\n";
      } elsif ( $config) {
         print "$name\t", $nodes{$name}{"$config"}, "\n";
      } else {
         print "$name\n";
      }
   }
   print "\n" unless $banners;
}
if ( @nodes_down and ( ! $status or "down" =~ /$status/i ) ) {
   print "# Nodes down:\n" unless $banners;
   foreach (sort @nodes_down ) {
      if ( $show_cluster ) {
         $name = $_;
      } else {
         $name = $nodestatus{$_}{NODENAME};
      }
      if ( $lam or $mpi ) {
         print "#$name\n";
      } elsif ( $config) {
         print "$name\t", $nodes{$name}{"$config"}, "\n";
      } else {
         print "$name\n";
      }
   }
   print "\n" unless $banners;
}
if ( @nodes_sleeping and ( ! $status or "asleep" =~ /$status/i ) ) {
   print "# Nodes sleeping:\n" unless $banners;
   foreach (sort @nodes_sleeping ) {
      if ( $show_cluster ) {
         $name = $_;
      } else {
         $name = $nodestatus{$_}{NODENAME};
      }
      if ( $lam or $mpi ) {
         print "#$name\n";
      } elsif ( $config) {
         print "$name\t", $nodes{$name}{"$config"}, "\n";
      } else {
         print "$name\n";
      }
   }
   print "\n" unless $banners;
}
if ( @nodes_unknown and ( ! $status or "unknown" =~ /$status/i ) ) {
   print "# Nodes in unknown state:\n" unless $banners;
   foreach (sort @nodes_unknown ) {
      if ( $show_cluster ) {
         $name = $_;
      } else {
         $name = $nodestatus{$_}{NODENAME};
      }
      if ( $lam or $mpi ) {
         print "#$name\n";
      } elsif ( $config) {
         print "$name\t", $nodes{$name}{"$config"}, "\n";
      } else {
         print "$name\n";
      }
   }
   print "\n" unless $banners;
}

if ( $lam or $mpi ) {
   warn "# Total of $cpus processors listed\n";
}

exit;
