#!/usr/bin/perl -w
# By:      john@stilen.com
# Date:    20100421
# Purpose: Run command on remote host over ssh, 
#          but gracefully don't hang the program
#          if there is a problem.
#---------------------------------
# Install Modules:
#   aptitude install libgmp3-dev
#   perl -MCPAN -e 'install Net::SSH::Perl'
#   perl -MCPAN -e 'install Math::BigInt::GMP'
#   perl -MCPAN -e 'install Math::GMP
#   perl -MCPAN -e '$ENV{FTP_PASSIVE} = 1; install Math::Pari'
# Test install:
#   perl -mMath::BigInt -e 1
#   perl -mMath::BigInt::Calc -e 1
#   perl -mMath::GMP -e 1
#   perl -mNet::SSH::Perl -e 1
#----------------------------------
# Usage:
#   use remote_command qw(&run_remote);
#   $remote_host="buildmac2.eng.msli.com";
#   $remote_user="build";
#   $remote_command="ls";
#   &run_remote($remote_host,$remote_user,$remote_command);
#----------------------------------
#
# Module Name
#
package remote_command;
#
# Loading phayse exports sub run_remote()
#
BEGIN {
    use Exporter;
    @ISA = qw(Exporter);
    @EXPORT = qw(&run_remote);
}
#
# Load dependent modules
#
use Net::SSH::Perl;
use Math::BigInt::GMP;     # Don't forget this!
use strict;
$|=1;                      # Do not buffer, send to stdout
#
# Takes a server, user, and command
# relys on sshkeys for authenticaiton
# stdout printed as command exectues ( $|=1 didn't work)
#
sub run_remote(){
    #
    # get the command to run
    # 
    my $server=shift();
    my $username=shift();
    my $command=shift();
    #
    # this is a hack ensures a $ssh exists in case Create object fails.
    #
    my $ssh;
    #
    # Create object, can fail for many reasons
    #
    eval{
      $ssh = Net::SSH::Perl->new($server) || die "NEW-UNK-ERR:$!\n";
    };
    if ($@){
        if( $@ =~ /Net::SSH: Bad host name/){
	    die "BAD_HOST\n"; # name resolution
        } elsif( $@ =~ /Connection refused at/){
	    die "CON_REFU\n"; # sshd port not responding
	} elsif( $@ =~ /No route to host/){
	    die "HOST_DWN\n"; # no host at IP
	} else {
            die $@;           # unanticipated error
        }
    }
    #
    # Log-in
    #
    eval{
      $ssh->login($username) || die "LOGIN-UNK-ERR:$!\n";
    };
    if ($@){
        if( $@ =~ /Permission denied/){
	    die "PRM_DENY";   # ssh key not authorized
        } elsif( $@ =~ /Too many authentication failures for/){
	    die "ATH_FAILL\n"; # too many authenticaton failures in little time
	} else {
            die $@;           # unanticipated error
        }
    }
    #
    # Print stdout as we get it
    #
    $ssh->register_handler( "stdout", 
                            sub {
                                  my($channel, $buffer) = @_;
                                  print $buffer->bytes;
                            }
    ) || die"REG-UNK-ERR";;
    #
    # Run the command
    #
    my ($stdout, $stderr, $exit) = $ssh->cmd($command); # Check output
}
return 1;
END { }

