Passing Parameteres to Interactive script programatically - perl

We have an interactive script(Script 1) which asks for an IP Address and continues it's execution process. Script 1 is called from script2.
As we know the IP address we want to pass IP Automatically to script so that manual intervention is not required
I looked into Expect Module. But i cannot install that module in PRODUCTION server.
Can someone suggest a way to overcome this issue.

Try this,
#script2.pl
use strict;
use warnings;
use Getopt::Long;
GetOptions (
"ipAddress=s" => \$ip,
) or die("Enter IP address");
my $cmd = "perl script1.pl --ip=$ip";
system($cmd);
.
#script1.pl
use strict;
use warnings;
use Getopt::Long;
GetOptions (
"ip=s" => \$ip,
) or die("Enter IP address");
print "IP address is $ip";
Execute like this.
perl script2.pl --ipAddress=10.11.12.13
If you want to execute script1 directly, can execute like this,
perl script1.pl --ip=10.11.12.13

Related

Perl socket, HP comware router

I'm trying to create a script in Perl that does the following
On a Windows 2008 R2 server, connects to a local OpenWRT router.
Send some commands to the router and save the output (interface brief)on a varaible
Edit the content of the variable (to keep the IP only)
Send the variable again to the router withinin another command
I created a socket but i dont seem to get any luck sending commands to the router. I'm not even sure if I'm logging in.
Here is my code:
use IO::Socket;
use strinct;
use warnings;
$iaddr = gethostbyname("192.168.1.237");
$ssh_port = 22;
$sin = sockaddr_in($ssh_port, $iaddr);
socket(DEV, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
connect(DEV, $sin) || die "Can't connect to EN4000: $!\n";
print DEV "user\n";
print DEV "password\n";
print DEV "echo test >> /etc/config/networkTest \n";
I run it, check the file /etc/config/networkTest but no modification is made
Have a look at Net::SSH::W32Perl
Here's a quick example;
#!/usr/bin/env perl
use strict;
use warnings;
use Net::SSH::W32Perl;
my $host='example.com';
my $user='john';
my $pass="pass";
# Connect
my $ssh = Net::SSH::W32Perl->new($host);
$ssh->login($user, $pass);
# Run command
my $cmd = q(echo test >> /etc/config/networkTest);
my($stdout, $stderr, $exit) = $ssh->cmd($cmd);

How can I get the port that Mojolicious::Lite chooses?

Joel Berger posted this little program to start a web server to serve local files, and it works great:
use Mojolicious::Lite;
#ARGV = qw(daemon);
use Cwd;
app->static->paths->[0] = getcwd;
any '/' => sub {
shift->render_static('index.html');
};
app->start;
I prepopulated the command line in #ARGV because I forget to do that. When it starts, it gives a message telling you which port it chose, using 3000 if it can:
$ perl ~/bin/mojo_cwd
[Fri Mar 29 19:14:09 2013] [info] Listening at "http://*:3000".
Server available at http://127.0.0.1:3000.
I'd like to get that port programmatically so a test suite can know where to look for it, and I'd prefer not to do it by scrapping output. None of my experiments for this were useful and I think I was always going in the wrong direction. It appears that it doesn't choose the port until it starts, and once I call start, that's the end of it.
I don't want to specify the port myself, either.
This isn't an urgent matter. I have a current solution to this with another simple HTTP framework, but I've been looking at replacing most of that stuff with Mojo if I can. Since the old stuff still works, this is really just something nice to have rather than something in my way.
You can't, but the daemon command only binds to port 3000 and will not try anything else unless you tell it to. If you're using Test::Mojo you don't need to know the port in advance anyway, for anything else you can always wrap your application in a little Mojo::Server::Daemon script.
use Mojolicious::Lite;
use Mojo::IOLoop;
use Mojo::Server::Daemon;
get '/' => {text => 'Hello World!'};
my $port = Mojo::IOLoop->generate_port;
my $daemon = Mojo::Server::Daemon->new(
app => app,
listen => ["http://*:$port"]
);
$daemon->run;
With the --listen param you specify to your app where to listen:
use Mojolicious::Lite;
#ARGV = qw(daemon --listen http://*:5000);
use Cwd;
app->static->paths->[0] = getcwd;
any '/' => sub {
shift->render_static('index.html');
};
app->start;
You can access the port number within the app with $self->tx->local_port:
#!/usr/bin/env perl
use Mojolicious::Lite;
#ARGV = qw(daemon --listen http://*:5000);
use Cwd;
app->static->paths->[0] = getcwd;
any '/' => sub {
my $self = shift;
$self->render_text('port: '. $self->tx->local_port);
};
app->start if $ENV{MOJO_MODE} ne 'test';
1;
I like to test Mojolicious apps with Test::Mojo because you get access to the running app, for example, in a file t/test_mojo.t:
use strict;
use warnings;
use feature 'say';
use Test::More;
use Test::Mojo;
$ENV{MOJO_MODE} = 'test';
require "$FindBin::Bin/../test_mojo.pl";
my $t = Test::Mojo->new;
$t->get_ok('/')->status_is(200)->content_is('port: '.$t->tx->remote_port);
say 'local port: '. $t->tx->local_port; #as seen from the user-agent's perspective
say 'remote port:'. $t->tx->remote_port;
done_testing();
I'm not sure I correctly understood what you are trying to accomplish, but I hope this helps you.

Display Output In Browser Perl CGI SSH

I'm executing remote commands using Net::OpenSSH using a web frontend. My commands return without failure on the command line, but I get nothing in a web browser. I've done a couple hour research to no avail--any ideas?
Here is some code to give you an example (some removed for obvious reasons).
#!/usr/bin/perl -w
use strict;
use CGI ':standard';
use Net::OpenSSH;
# Here in the code is just the header and standard tags
print "1";
print "2"; # both display
my $ssh = Net::OpenSSH->new($host, user => $uname, key_path => $key); # all works
$ssh- error and die "Can't ssh to host" . $ssh->error;
print "3";
$ssh->system("uname -a") or
die "remote command failed: " . $ssh->error;
my #lsa = $ssh->capture("ls -a");
$ssh->error and
die "remote ls command failed: ". $ssh->error;
print "4";
print "5";
print #lsa; # won't display in browser, just terminal/CLI
Cheers!
I maintain CGI.pm. I recommend these additions to your simple script:
Before you print anything else, print the standard HTTP header: print header();
Add this after the use CGI line: use CGI::Carp qw(fatalsToBrowser); ... that will display any run-time problems in the browser. If you don't get any output after these changes, check that the script compiles with perl -cw script.pl
Below is about the minimum Perl code that worked for me on Debian machine. I suggest you go through it and compare it to your actual code.
However, it did not work out-of-the box on my Debian, I had make some decisions most of which probably aren't very safe, but that's more about specific environment:
make home for user that server runs writable (/var/www)
add host to ~/.ssh/known_hosts beforehand
use the strict_mode => 0 to bypass Net::OpenSSH's security checks instead of finding proper
ctl_dir (Net::OpenSSH requires that the folder and all above folders are 0755 or more strict,
so /tmp I used is normally not good enough)
I believe there are much safer practices than that, but as I said, that's specific to environment.
So the code:
#!/usr/bin/perl
use strict;
use warnings;
use Net::OpenSSH;
use File::Temp qw/ tempdir /;
# necessary minimum for CGI
print "Content-type: text/plain\n\n";
# prepare temp dir
my $temp = tempdir("/tmp/sshme.pl-XXXXXXXX", CLEANUP => 1);
# open SSH session
my %opts = (
user => "user",
password => "password",
ctl_dir => $temp,
strict_mode => 0 ## NOT recommended - see my comments
);
my $ssh = Net::OpenSSH->new("host", %opts);
$ssh->error
and die "Couldn't establish SSH connection: ". $ssh->error;
# perform command and print output
my #lines = $ssh->capture("ls")
or die "remote command failed: " . $ssh->error;
print #lines;
Perhaps your errors get directed to standard error, not standard output. In that case, they'll usually end up in the server log, not the browser window. Perhaps you can use POSIX::dup2 to avoid this:
use POSIX;
# Make sure to send HTTP headers before redirecting streams!
POSIX::close(2); # close original stderr stream. No more output to apache logs!!!
POSIX::dup2(1,2); # redirect error stream to standard output, so errors will appear in browser.
Processes launched by perl, like e.g. some ssh binary, will inherit these streams.

How to capture both STDOUT and STDERR in two different variables using Backticks in Perl

Let's say I want to run an external program from my script with backticks and at the same time I want to capture both STDOUT and STDERR but in two different variables. How can I do that? For istance if I run this script...
my $cmd = `snmpwalk -v $version -c $community $hostname $oid`;
...if there is no error everything works just fine BUT if the command raise an error this error will be printed on the command line and I don't want that to happen. I want to capture the error as well. Nothing has to be printed on the screen. Any ideas?
You needn't go all the way to open3, which IIRC is only for when you need to read and write to an external command, and even then there are other methods.
For your problem I suggest using Capture::Tiny, which can capture (or even tee) the STDOUT and STDERR from anything run inside its block. For example, per your question:
#!/usr/bin/env perl
use strict;
use warnings;
use Capture::Tiny qw/capture/;
...
my ($stdout, $stderr) = capture {
system ( "snmpwalk -v $version -c $community $hostname $oid" );
};
For another example consider this functioning code:
#!/usr/bin/env perl
use strict;
use warnings;
use Capture::Tiny qw/capture/;
my ($stdout, $stderr) = capture {
system ( "echo 'hello'" );
system ( "date" );
warn "Arg1!";
};
print "STDOUT:\n$stdout";
print "STDERR:\n$stderr";
which just gave me:
STDOUT:
hello
Mon Dec 19 23:59:06 CST 2011
STDERR:
Arg1! at ./test.pl line 11.
The only way to do this with backticks is to redirect to a file inside the shell command:
my $cmd = `snmpwalk -v $version -c $community $hostname $oid 2>error.dat`;
If you want to capture the STDERR inside your script, you need IPC::Open3 instead of backticks
In the Perl FAQ you have different options depending how do you want to proceed:
http://perldoc.perl.org/perlfaq8.html#How-can-I-capture-STDERR-from-an-external-command%3f
IO::CaptureOutput
is a very convenient wrapper for what you want to do.

How can I tell if a Perl script is executing in CGI context?

I have a Perl script that will be run from the command line and as CGI. From within the Perl script, how can I tell how its being run?
The best choice is to check the GATEWAY_INTERFACE environment variable. It will contain the version of the CGI protocol the server is using, this is almost always CGI/1.1. The HTTP_HOST variable mentioned by Tony Miller (or any HTTP_* variable) is only set if the client supplies it. It's rare but not impossible for a client to omit the Host header leaving HTTP_HOST unset.
#!/usr/bin/perl
use strict;
use warnings;
use constant IS_CGI => exists $ENV{'GATEWAY_INTERFACE'};
If I'm expecting to run under mod_perl at some point I'll also check the MOD_PERL environment variable also, since it will be set when the script is first compiled.
#!/usr/bin/perl
use strict;
use warnings;
use constant IS_MOD_PERL => exists $ENV{'MOD_PERL'};
use constant IS_CGI => IS_MOD_PERL || exists $ENV{'GATEWAY_INTERFACE'};
You would best check the GI in the CGI.
use CGI qw( header );
my $is_cgi = defined $ENV{'GATEWAY_INTERFACE'};
print header("text/plain") if $is_cgi;
print "O HAI, ", $is_cgi ? "CGI\n" : "COMMAND LINE\n";
One possible way is to check environment variables that are set by web servers.
#!/usr/bin/perl
use strict;
use warnings;
our $IS_CGI = exists $ENV{'HTTP_HOST'};
See if your program is connected to a TTY or not:
my $where = -t() ? 'command line' : 'web server';