Perl LFTP Pipe Using SSH Key - perl

I can currently connect to an SFTP server using a username/password combination:
print "Attempting connection...\n";
open( my $LFTP,'|-', "lftp -u $ftpuser,'$ftppwd' -e open -p $ftpport $ftpserver" ) or die "Cannot open lftp: $!";
print $LFTP <<"END";
ls
END
close($LFTP); # die unless lftp exit code is 0
exit 0;
How can change this code to connect to a different server using an SSH key which is encrypted with a passphrase?
This is what I've tried:
print "Attempting connection...\n";
# $ftppwd is blank now!
open( my $LFTP,'|-', "lftp -u $ftpuser,'$ftppwd' -e 'set sftp:connect-program \"ssh -a -x -i $keypath\"; open $ftpserver;'" ) or die "Cannot open lftp: $!";
print $LFTP <<"END";
ls
END
close($LFTP); # die unless lftp exit code is 0
exit 0;
The output is stuck at:
Attempting connection...
`ls' at 0 [Connecting...]
Thank you in advance for any help..

Add -u option to the open command inside -e argument and use the pass phrase as the password. You should also use url syntax to select the sftp protocol, e.g. sftp://user:phrase#server

Related

Perl script to check if possible to ssh into remote server

I have a perl script in which i want to first check if it possible to ssh into the server before i actually do ssh. So if it possible to ssh, then go ahead and ssh into that server, otherwise handle this exception appropriately.
So i have this script that goes through a textfile with a list of databases, and tries to ssh into each server to perform a bash command that checks if the server is performing MySQL SST or not:
#!/usr/bin/perl -w
use strict;
use warnings;
use 5.010;
use DBI;
use Encode;
use IO::File;
use JSON;
use utf8;
BEGIN {
binmode STDERR, ':utf8';
binmode STDIN, ':utf8';
binmode STDOUT, ':utf8';
}
my $time = localtime();
my $file = '/opt/db-servers/db.txt';
open my $info, $file or die "Could not open $file: $!";
while( my $hostname = <$info>) {
chomp( $hostname );
my $xtrabk_check = `ssh $hostname ps -ef |grep mysql | grep wsrep_sst_xtrabackup-v2`;
my $role_check = `ssh $hostname ps -ef |grep mysql | grep donor`;
my $error_log = `ssh $hostname ps -ef |grep mysql`;
if ( $xtrabk_check ne "" ){
if ( $role_check ne "" ){
my $cmd ="curl -vs -o /dev/null -X POST --data-urlencode 'payload={\"channel\": \"#db-wsrep-status-log\", \"username\": \"db-wsrep-status-log\", \"text\": \"$time: $hostname: --role Donor \n```$error_log```\", \"icon_emoji\": \":scorpion:\"}' 2>&1 /dev/null https://hooks.slack.com/services/GVadasdd/B6LSMF5GV/BIApnzoIldfdsrw343wf";
system($cmd);
}
else {
my $cmd ="curl -vs -o /dev/null -X POST --data-urlencode 'payload={\"channel\": \"#db-wsrep-status-log\", \"username\": \"db-wsrep-status-log\", \"text\": \"$time: $hostname: State transfer in progress, setting sleep higher mysqld \n```$error_log```\", \"icon_emoji\": \":scorpion:\"}' 2>&1 https://hooks.slack.com/services/GVadasdd/B6LSMF5GV/BIApnzoIldfdsrw343wf";
system($cmd);
}
}
}
close $info;
So probably before performing the three lines below, i want to be able to know if that server is down (hence cannot ssh into it) or not (then ssh into it with the commands below):
my $xtrabk_check = `ssh $hostname ps -ef |grep mysql | grep wsrep_sst_xtrabackup-v2`;
my $role_check = `ssh $hostname ps -ef |grep mysql | grep donor`;
my $error_log = `ssh $hostname ps -ef |grep mysql`;
How can i go about achieving this? By the way, the slack URL have been altered so security worries there.
By far the most reliable way to determine whether you can ssh into a server or not is to actually attempt to ssh into it. Just attempt to connect and, if it fails, report the failure and abort any further attempts:
use Try::Tiny;
# Declaring them here so they don't disappear at the end of the try block
my ($xtrabk_check, $role_check, $error_log);
try {
$xtrabk_check = `ssh $hostname ps -ef |grep mysql | grep wsrep_sst_xtrabackup-v2`;
$role_check = `ssh $hostname ps -ef |grep mysql | grep donor`;
$error_log = `ssh $hostname ps -ef |grep mysql`;
} catch {
die "Failed to connect to ssh: $_";
}
Instead of running ssh directly, use any of the Perl modules supporting SSH (for instance, Net::OpenSSH). That would allow you to connect to the remote host and run as many commands as you need over that single connection and it will detect any connection error and report it appropriately.
You can also parallelize the operation using Net::OpenSSH::Parallel.

Undefined subroutine &main::promt

I am sort of new to Perl. I was trying to write a script which will take a mysqldump and restore it in a new database. The main idea is to migrate a DB from one server to another.
Here's the scrip that I wrote:
#!/usr/bin/perl
use warnings;
print "Starting the migration process!\n";
print "Enter the source server address, make sure you enter the FQDN of the server";
$source_address = promt ("Source server address: ");
check_string($source_address);
print "Enter the destination server address, make sure you enter the FQDN of the server";
$destination_address = promt ("Destination server address:");
check_string($destination_address);
print "Enter the Source server password for the root user";
$source_password = promt ("Source server address:");
check_string($source_password);
print "Enter the destination server password for the root user";
$destination_password = promt ("Destination server address:");
check_string($destination_password);
$current_dir = cwd();
system("mysqldump --single-transaction -u root -p$source_password --force -h $source_address -A -R -E --triggers
--routines --max_allowed_packet=512M | gzip -c >$current_dir/old_db_dump.sql") or die "system call to create Mysqldump failed: $?";
system("pt-show-grants -uroot -p$source_password -h $source_address > $current_dir/old_grants.sql") or die "system call to create grant failed: $?";
system("mysql -u root -p$destination_password -h $destination_address < $current_dir/old_db_dump.sql") or die "System call to import the sqldump failed: $?";
system("mysql -u root -p$destination_password -h $destination_address < $current_dir/old_grants.sql") or die "System call to import the grants failed: $?";
# A function that checks if the passed string is null or not
sub check_string{
$string_to_check = $_[0];
if ($string_to_check eq '') {
print "The entered value is empty, the program will exit now, re-run the program";
exit 0;
}
}
sub prompt {
my ($text) = #_;
print $text;
my $answer = <STDIN>;
chomp $answer;
return $answer;
}
But when I try to execute the code, I end up with the following error:
Starting the migration process!
Undefined subroutine &main::promt called at migrate_mysql.pl line 26.
Enter the source server address, make sure you enter the FQDN of the server
For writing the Prompt function, I followed the tutorial mentioned in the post here: http://perlmaven.com/subroutines-and-functions-in-perl
I do not know why am I getting this error here. Do I have to include some packages?
Also it would be nice if you could comment on the system block of the code:
system("mysqldump --single-transaction -u root -p$source_password --force -h $source_address -A -R -E --triggers
--routines --max_allowed_packet=512M | gzip -c >$current_dir/old_db_dump.sql") or die "system call to create Mysqldump failed: $?";
system("pt-show-grants -uroot -p$source_password -h $source_address > $current_dir/old_grants.sql") or die "system call to create grant failed: $?";
system("mysql -u root -p$destination_password -h $destination_address < $current_dir/old_db_dump.sql") or die "System call to import the sqldump failed: $?";
system("mysql -u root -p$destination_password -h $destination_address < $current_dir/old_grants.sql") or die "System call to import the grants failed: $?";
Am I doing it in the right way? Am I passing the variable values in a correct manner?
From this error message:
Undefined subroutine &main::promt called at migrate_mysql.pl line 26.
You should look at line 26. Which is odd, because your error isn't on line 26, but here:
$source_address = promt ("Source server address: ");
If I run your code I get:
Undefined subroutine &main::promt called at line 9.
You've got "promt" not "prompt" which is a subroutine that is undefined.
You should really also add use strict; to your code, and then rejig it - it'll generate a lot more errors initially, but it'll avoid some real gotchas in future if you spell a variable incorrectly.
It's quite easy in your code - just put my in front of the first use of a variable - you've been good with scoping otherwise, but otherwise it means that once you first use $string_to_check it remains visible to the rest of the program, which is just a bit messy and can lead to some odd bugs.

How can i get process id of UNIX command i am triggering in a Perl script?

I am triggering a UNIX command in Perl script.
I need the process ID of the UNIX command.
For example if i trigger below UNIX command:
# padv -s adv.cfg > adv.out &
[1] 4550
My process ID is 4550.
# ps -ef | grep padv
root 4550 2810 0 16:28 pts/5 00:00:00 padv -s adv.cfg
root 4639 2810 0 16:29 pts/5 00:00:00 grep padv
How to capture that process ID in my Perl Script?
For example, i am triggering my command in Perl script like below:
#!/usr/bin/perl
use strict;
use warnings;
qx(padv -s adv.cfg > adv.out &);
You could use open()
Open returns nonzero on success, the undefined value otherwise. If the open involved a pipe, the return value happens to be the pid of the subprocess.
my $pid = open(my $ph, "-|", "padv -s adv.cfg > adv.out") or die $!;
reading output from $ph file handle instead of output redirect:
my $pid = open(my $ph, "-|", "padv -s adv.cfg") or die $!;
Call fork to create a child process. The process ID of the child process is returned to the parent process. The child process can then call exec to execute the program you want.

How to send commands to windows command prompt using a PERL script

I want to send some commands to windows command prompt using 'PERL' script.
the command is:
putty.exe -ssh -2 -l username -pw password "ip address"
this command will open an SSH session (console)to the mentioned ip address (server) for me.
after getting the new console, I want to pass commands to and perform operations in the new console.How can I do that as well?
Please help
You can use 'system' or 'exec' command.
system:
#args = ("command", "arg1", "arg2");
system(#args) == 0
or die "system #args failed: $?"
http://perldoc.perl.org/functions/system.html
exec:
exec '/bin/echo', 'Your arguments are: ', #ARGV;
exec "sort $outfile | uniq";
http://perldoc.perl.org/functions/exec.html
Please notice the difference between them.

Open file in perl with sudo

I'd like to write data to a file, but the file handle should be opened with sudo or else I get permission denied error. But looks like something like following is not possible in perl?
sudo open (FH, "> $filename") or die "$!\n";
sudo is a linux command, it is not a Perl function. You can run the whole Perl script with sudo (sudo perl script.pl), or you can change your user id in Perl by assigning to $< and $> special variables (see perlvar - Perl predefined variables) which will only be possible with extra privileges, anyway.
BTW, open sets $! on failure, not $#.
open(my $pipe_fh, '-|', 'sudo', 'cat', $filename) or die "Unable to open pipe: $!\n";
It creates another process to solve your problem that may be better solved by running the script with the correct rights.