#!/usr/bin/perl
#
# Subcluster-wide push command
#
# $Id: scpush,v 1.4 2005/12/01 12:50:35 focht Exp $
# (c) 2004 NEC EHPCTC, Erich Focht


use strict;
use lib "/usr/lib/systeminstaller";
use HPCL::Subcluster;
use SIS::Image;
use SIS::DB;
use Getopt::Long;
use Data::Dumper;

log_entry();
my $progname = $0;
$progname =~ s:^.*/::g;

# configure command line options parsing
Getopt::Long::Configure("ignore_case"); # ignore case
Getopt::Long::Configure("bundling");    # allow -a -b or -ab
Getopt::Long::Configure("auto_abbrev"); # allow abbreviated input

# set default option values
my ($verbose, $check, $writeimg, $onlyimg) = (0,0,0,0);

# parse command line options
my %options = ( 'check' => 1 );
GetOptions( \%options,
	    'all|a',
	    'image|i=s@',
            'domain|d=s@',
            'nodelist|n=s',
	    'check|c!',
            'verbose|v!',
            'writeimg|w',
            'onlyimg|o',
	    )
    || usage(3);

my ($src, $tgt) = @ARGV;
if (!$src) {
    usage(1,"You must specify at least the source path of the file you want to push");
}
if (-d $src && !$tgt) {
    usage(1,"When pushing a directory, the target should be defined!");
}

# save options and delete the simple ones
$verbose = $options{verbose};
delete $options{verbose};
$check = $options{check};
delete $options{check};
$writeimg = $options{writeimg};
delete $options{writeimg};
$onlyimg = $options{onlyimg};
delete $options{onlyimg};
$writeimg = 1 if ($onlyimg);

# now only the subcluster-defining keys should be left in %options


if (!scalar(keys(%options))) {
    usage(1,"You must use one of the options --image, --domain, --nodelist or --all");
}
if (scalar(keys(%options)) > 1) {
    usage(1,"You should use only one type of the subcluster selection options");
}

if (defined($options{image})) {
    print "image:\n".Dumper(@{$options{image}});
}
if (defined($options{domain})) {
    print "domain:\n".Dumper(@{$options{domain}});
}

# if --all was chosen, pass all defined images as argument
if (defined($options{all})) {
    delete $options{all};
    $options{image} = ();
    my @img = list_image();
    foreach my $i (@img) {
	push @{$options{image}}, $i->name;
    }
}


push_sc(join("",keys(%options)));

exit 0;

#############################################
##  Function definitions only below this line
#############################################

sub usage {
    my ( $exit, @error ) = @_;
    print <<USAGE;

Usage: $progname [--image image_name | --domain domain_name | \
		  --nodelist "nodename nodename ..."]         \
		 --[no]check --writeimg                       \
                 source [target]

   Subcluster definition options (use exactly one type!)
    --image image_name     : all nodes which are assigned to image imagename
    --domain domain_name   : all nodes which have the given domainname
    --nodelist "node1 node2 ..." : list of nodes. Don't forget the quotes!
    --all                  : subcluster defined by all available images
   Options:
    --[no]check | -c : don't check for offline nodes (default: check)
    --writeimg | -w  : write source data also to the image on disk (default: off)
                       works only with the --image option
    --onlyimg | -o   : write only to the image, not to the hosts
                       works only with the --image option
    --verbose | -v   : verbose output (default: off)
           
USAGE
    if (@error) {
	print "\n";
	warn shift @error while @error;
    }
}

sub vprint {
    print @_ if ($verbose);
}

sub log_entry {
    my $logfile1 = "/var/log/sc_cmds.log";
    my $logfile2 = "$ENV{HOME}/.sc_cmds.log";
    my ($sec,$min,$hour,$mday,$mth,$year) = (localtime)[0..5];
    $year -= 100;
    my $o = sprintf("%02d%02d%02d-%02d%02d%02d",$year,$mth+1,$mday+1,
		       $hour,$min,$sec);
    $o .= ":" . $0 . " ";
    for (my $i=0; $i<=$#ARGV; $i++) {
	my $s = $ARGV[$i];
	if ($s =~ m/\s/) {
	    $o .= " \"" . $s . "\"";
	} else {
	    $o .= " $s";
	}
    }
    open LOG,">> $logfile1" or open LOG, ">> $logfile2" or return 1;
    print LOG $o . "\n";
    close LOG;
    return 0;
}

sub push_sc {
    my ($type) = @_;

    vprint("Subcluster type: $type !!!\n");

    my @arr;
    if ($type =~ m/^(image|domain)$/) {
	@arr = @{$options{$type}};
    } else {
	# nodelists are special
	@arr = ( $options{$type} );
    }

    foreach my $i (@arr) {
	print "---------------\n";
	my $sc = new HPCL::Subcluster( $type => $i );
	if (!defined($sc)) {
	    print "Subcluster defined by $type $i wasn't validated!\n";
	    print "... skipping it ...\n";
	    next;
	} else {
	    vprint("Subcluster $type $i is valid\n");
	    if ($verbose) {
		$sc->verbose(1);
	    }
	}
	if (!$onlyimg) {
	    if ($check) {
		my %status = $sc->status();
		vprint("Online: " . $status{online} . "\n");
		vprint("Offline: " . $status{offline} . "\n");
		if ($status{offline}) {
		    print "WARNING: There are offline nodes in subcluster $i\n";
		    print "Offline: $status{offline}\n";
		}
	    }
	    # do the pushing
	    my $err = $sc->cpush($src, $tgt);
	    print "cpush returned $err on subcluster $i\n" if ($err);
	}

	# push to image, if required
	if ($type eq "image" && $writeimg) {
	    my $imgdir = $sc->imgpath();
	    if (! -d $imgdir) {
		print "ERROR: Image path $imgdir could not be found!\n";
		exit 1;
	    } else {
		my $pwd;
		# need pwd for relative target path
		if ((!$tgt && $src !~ /^\//) || $tgt !~ /^\//) {
		    $pwd = $ENV{PWD} . "/";
		}
		if (!$tgt) {
		    $tgt = $src;
		}
		my $cmd = "/bin/cp -prdf $src $imgdir/$pwd$tgt";
		vprint "Copy: $cmd\n";
		system($cmd);
	    }
	}
    }
}
