I am connecting to a remote host and executing a command which does not exit (tail -f logfile)
I am registering a handler and writing the output to a log file. This is working fine But I want to press Control+C on the main program and it should stop the command on remote machine and close the ssh connection gracefully
So I am registering a signal handler for SIGINT
Need the code which I need to put in the subroutine
The below code is inside a function which is called from forked child
#!/ats/bin/perl
use Net::SSH::Perl;
use File::Path;
use Text::CSV_XS;
chomp ($progName = `basename $0`);
if (@ARGV != 1 ) {
print "usage: perl $progName <tc_id>\n";
exit;
}
$tc_id = shift;
$file = "config.prop";
$log_dir = "logs/";
#$SIG{INT}=\&close_write;
sub close_write
{
#-- write it to file
print "\nInside END block\n";
#open FH, ">$log_file";
#print $log_file;
#print FH @out;
#$thr->kill('INT');
#close $ssh->sock;
#undef $ssh;
exit 1;
}
# Read the configuration file and populate the Hash
$index = 0;
my $csv = Text::CSV_XS->new ({ binary => 1, eol => $/ });
open my $io, "<", $file or die "$file: $!";
while (my $row = $csv->getline ($io)) {
next if (${$row}[0] =~ m/^#/); #Ignore comments
next if (${$row}[0] =~ m/^\s*$/); #Ignore blank lines
($logHashArray->[$index]->{host}, $logHashArray->[$index]->{user}, $logHashArray->[$index]->{pass}, $logHashArray->[$index]->{cmd}, $logHashArray->[$index]->{log_file}) = @$row;
$index++;
}
# Append "/" at the end of the directory if it does not exist
unless ($log_dir =~ m/\/$/) {
$log_dir = $log_dir . "/";
print "LogDir: $log_dir\n";
}
# Check if the log directory exists, if not, create it
if (-e $log_dir) {
unless (-d $log_dir) {
die "File exists but is not directory";
}
}
else {
# don't forget to check mkdir's failure
print "Directory $log_dir does not exist... Creating it\n";
mkpath($log_dir, 0777) or die "Can't make directory: $!";
}
foreach $logHash (@{$logHashArray}){
#print "LogHash Index $logHash\n";
$logHash->{log_file} = $tc_id . "_" . $logHash->{host} . "_" .$logHash->{log_file};
$logHash->{cmd} = $logHash->{cmd} . " | tee /tmp/" . $logHash->{log_file};
$logHash->{log_dir} = $log_dir;
#$logHash->{thr}=threads->new(\&connect_get_logs, $logHash);
$logHash->{pid} = fork();
if ($logHash->{pid}){
# Parent
push(@childs, $logHash->{pid});
}
elsif ($pid == 0){
# Child
connect_get_logs($logHash);
}
else {
die "couldn’t fork: $!\n";
}
while (($key, $value) = each(%{$logHash})){
print $key."=>".$value."\n";
}
}
#$SIG{INT}=\&close_write;
#$thr=threads->new(\&connect_get_logs, $logHash);
foreach (@childs) {
waitpid($_, 0);
}
#print "Waiting...";
#while(1) {sleep 1;}
#$thr->join;
sub connect_get_logs{
$SIG{INT}= sub {
print "Inside INT block\n"; ### Need proper code here
close $ssh->sock;
undef $ssh;
};
my $logHash = shift;
while (($key, $value) = each(%{$logHash})){
print $key."=>".$value."\n";
}
my $stdout;
my $stderr;
my $exit;
#-- setup a new connection
print "Logging in to $logHash->{host}...";
my $ssh = Net::SSH::Perl->new($logHash->{host}, debug => 0, protocol => '2', options => ["PasswordAuthentication yes", "BatchMode yes",
"PubkeyAuthenticaion no", "RhostsAuthentication no", "RhostsRSAAuthentication no", "RSAAuthentication no", "DSAAuthentication no"]);
#-- authenticate
$ssh->login($logHash->{user}, $logHash->{pass});
print "Logged In\n";
#-- Create or Overwrite the log files
open LOG_FILE, ">", "$logHash->{log_dir}$logHash->{log_file}" or die $!;
#-- register a handler
$ssh->register_handler("stdout", sub {
my($channel, $buffer) = @_;
$str = $buffer->bytes;
#push @out, $str;
print LOG_FILE $str;
#print $str;
});
#$SIG{INT}=\&close_write;
#-- execute the command
($stdout, $stderr, $exit) = $ssh->cmd($logHash->{cmd});
print "Error: $stderr";
}
create a config.prop file in the csv format
host/ip,username,password,command (tail -F /full/path/to/logfile),filename to save as
The trick is invoking ssh with -t
(or possibly -tt
).
By default, ssh allocates a pty on the remote machine only for interactive login shells (ie, not when invoking a command on the remote). -t
forces ssh to allocate a pty, even when executing a remote command. You can see the effect:
$ ssh starquake tty
not a tty
vs
$ ssh -t starquake tty
/dev/pts/1
Connection to starquake closed.
ssh apparently will pass on signals to the remote process when attached to the terminal, but not otherwise.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With