Perl expect - how to control timeout on target machine - perl

I am a newbie to perl. I am using perl expect module to spawn to a remote system. Execute a set of commands there one after another using the send module(like $exp->send("my command as string goes here\n"). The problem is the commands that I execute take some time for processing . And before all the command finish the remote machine gets timed out and I come back to my host machine prompt. Can you please help me how to handle this.?
I have one more question. I have a command which returns 2 values after execution(say I am doing a print for 2 values on remote machine). I want to capture these 2 values and pass as argument to the next command using send module. How do I do this.
Pls help me with this problem.
Thanks.
I just found out something about the expect module. There is an undef option that can be used with expect like $exp->expect(undef). This will wait indefinitely and lets all commands finish their processing. But the problem is that, it does not return back the control to the host machine. There is one more option of using expect with eof which will wait until it encounters an eof and then returns to the host machine. Although no idea precisely how to use it. An elegant solution that I found is to use ssh to run commands on remote machine rather than using expect in which case we do not have to deal with timeouts. :)

I just found out something about the expect module. There is an undef option that can be used with expect like $exp->expect(undef). This will wait indefinitely and lets all commands finish their processing. But the problem is that, it does not return back the control to the host machine. There is one more option of using expect with eof which will wait until it encounters an eof and then returns to the host machine. Although no idea precisely how to use it. An elegant solution that I found is to use ssh to run commands on remote machine rather than using expect in which case we do not have to deal with timeouts. :)

Related

How to run powershell script remotely using chef?

I have powershell script which is present on chef server to run on remote windows server, how can i run this powershell script from chef server on remote windows server.
Chef doesn't do anything like this. First, Chef Server can never remotely access servers directly, all it does is stores data. Second, Chef doesn't really do "run a thing in a place right now". We offer workstation tools like knife ssh and knife winrm as simplistic wrappers but they aren't made for anything complex. The Chef-y way to do this would be to make a recipe and run your script using the the powershell_script resource.
Does it mean chef is also running on Windows server ?
If yes, why not to use psexec from Windows Ps tools ?
https://learn.microsoft.com/en-us/sysinternals/downloads/psexec
Here is my understanding of what you are trying to achieve. If I'm wrong then please correct me in a comment and I will update my answer.
You have a powershell script that you need to run on a specific server or set of servers.
It would be convenient to have a central management solution for running this script instead of logging into each server and running it manually.
Ergo you either need to run this script in many places when a condition isn't filled, such as a file is missing, or you need to run this script often, or you need this script to be run with a certain timing in regards to other processes you have going on.
Without knowing precisely what you're trying to achieve with your script the best solution I know of is to write a cookbook and do one of the following
If your script is complex place it in your cookbook/files folder (assuming the script will be identical on all computers it runs on) or in your cookbook/templates folder (if you will need to inject information into it at write time). You can then write the .ps file to the local computer during a Chef converge with the following code snippet. After you write it to disk you will also have to call it with one of the commands in the next bullet.
Monomorphic file:
cookbook_file '<destination>' do
source '<filename.ps>'
<other options>
end
Options can be found at https://docs.chef.io/resource_cookbook_file.html
Polymorphic file:
template '<destination>' do
source '<template.ps.erb>'
variables {<hash of variables and values>}
<other options>
end
Options can be found at https://docs.chef.io/resource_template.html
If your script is a simple one-liner you can instead use powershell_script, powershell_out! or execute. powershell_out! has all the same options and features as the shell_out! command and the added advantage that your converge will pause until it receives an exit status for the command, if that is desirable. The documentation on using it is a bit more spotty though so spend time experimenting with it and googling.
https://docs.chef.io/resource_powershell_script.html
https://docs.chef.io/resource_execute.html
Which ever option you end up going with you will probably want to guard your resource with conditions on when it should not run, such as when a file already exists, a registry key is set or what ever else your script changes that you can use. If you truly want the script to execute every single converge then you can skip this step, but that is a code smell and I urge you to reconsider your plans.
https://docs.chef.io/resource_common.html#guards
It's important to note that this is not an exhaustive list of how to run a powershell script on your nodes, just a collection of common patterns I've seen.
Hope this helped.

CGI script to connect to unix host and trigger perl script and report back the status

I need some heads up here. I need to write a CGI script which has to connect unix host and execute set of perl scripts.
I am new to CGI world and I have couple of questions in my mind for which I don't know perl solution.
How will connect to Unix host from CGI script. I believe using Net::SSH ,is there any better module to do this ?
Lets assume I have connected to the server , now how would I execute the script and how would I now the status (running/success/failure)
of the script.
a. When its running I would like to see the output that gets generated. Is it possible to view the script output in realtime?
b. If its a failure then I should be notified and reason for failure and should not trigger the next script in sequence.
If someone has similar setup already available and ready to show the code/setup , I would be much happier :)

How to handle interactive commands in Perl?

I have a perl script which calls a command which before executing asks for confirmation. How do I handle this in Perl?
For example let say in my perl script I am doing the following
`ssh myServer`;
Before connecting I get a prompt asking to proceed or not. I have to provide yes as my next command. How can I achieve this? Any code snippet would be useful.
If you are looking at interactive you can use Expect on the CPAN...
"Expect is a generic tool for talking to processes that normally require
user interaction. This might be running an ftp client to grab a file,
telnetting to a router to grab statistics or reset an interface. Or, as in the
case of a place I recently administered, to start up a secure webserver without
having to be physically at the machine to enter the super secret password."
However, there are other (better) methods to automate SSH login. I.e. by using ssh-keygen
From Net::SSH :
interactive
Set to a true value if you're using Net::SSH::Perl interactively. This is used in determining whether or not to display password prompts, for example. It's basically the inverse of the BatchMode parameter in ssh configuration.
Defaults to false.

Spawn external process from a CGI script

I've searched and found several very similar questions to mine but nothing in those answers have worked for me yet.
I have a perl CGI script that accepts a file upload. It looks at the file and determines how it should be processed and then calls a second non-CGI script to do the actual processing. At least, that's how it should work.
This is running on Windows with Apache 2.0.59 and ActiveState Perl 5.8.8. The file uploading part works fine but I can't seem to get the upload.cgi script to run the second script that does the actual processing. The second script doesn't communicate in any way with the user that sent the file (other than it sends an email when it's done). I want the CGI script to run the second script (in a separate process) and then 'go away'.
So far I've tried exec, system (passing a 1 as the first parameter), system (without using 1 as first parameter and calling 'start'), and Win32::Process. Using system with 1 as the first parameter gave me errors in the Apache log:
'1' is not recognized as an internal or external command,\r, referer: http://my.server.com/cgi-bin/upload.cgi
Nothing else has given me any errors but they just don't seem to work. The second script logs a message to the Windows event log as one of the first things it does. No log entry is being created.
It works fine on my local machine under Omni webserver but not on the actual server machine running Apache. Is there an Apache config that could be affecting this? The upload.cgi script resides in the d:\wwwroot\test\cgi-bin dir but the other script is elsewhere on the same machine (d:\wwwroot\scripts).
There may be a security related problem, but it should be apparent in the logs.
This won't exactly answer your question but it may give you other implementation ideas where you will not face with potential security and performance problems.
I don't quite like mixing my web server environment with system() calls. Instead, I create an application server (with POE usually) which accepts the relevant parameters from the web server, processes the job, and notifies the web server upon completion. (well, the notification part may not be straightforward but that's another topic.)

What are the advantages of rsh versus Perl's Expect.pm?

I have a Perl Expect.pm script that does some moderately complex stuff like packaging applications, deploying the application, checking for logs, etc. on multiple remote unix hosts.
My predecessor had written similar scripts using rsh.
Is there a better approach between the two? Or should I use something all together different?
I am guessing somebody will bring up SSH; it's basically replacement for rsh, right? Unfortunately, however SSH is not an option for me right now.
Another thing I should add is that after logging in I need to be able to SUDO to a particular user to do most of the actions on the remote hosts.
Another thing I should add is that after logging in I need to be able to SUDO to a particular user to do most of the actions on the remote hosts.
To address this one particular point: using rsh (or ssh) you can specify which user to become in the remote session:
$ rsh -l username hostname
There's no need to use sudo in this case. Now would definitely be the time to look into ssh due to security issues. The syntax is the same, but ssh also allows a slightly different (and I'd say better) syntax:
$ ssh username#hostname
I found expect to be too finicky, but my experience with it is not substantial.
They do different things. Expect is a way to script what would otherwise be manual responses. rsh -- remote shell, not restricted shell, an unfortunate name clash -- allows you to run commands remotely on another system.
That said, the security holes and other disadvantages of using rsh to do remote commands, run sudo, etc, are immense.
I can see multiple ways of doing this:
Expect over telnet, rsh, or ssh
pros: single connection, fewer escaping issues
cons: fragility in a changing environment
rsh/ssh each command individually
pros: fewer escaping issues, more reliable in a changing environment
cons: each connection takes time for authentication, and, for ssh, handshaking the encryption
rsh/ssh all commands at once
pros: single connection (less overhead), more reliable than expect
cons: fragility in maintenance especially as you get more than a handful of statements in there, escaping issues are more prevalent (escape in perl so that it's still escaped by rsh/ssh so that it's still escaped by the remote shell so that it's properly handled by the sudo'd remote shell?)
rsh/ssh and run a script
pros: single connection, more reliable, more maintainable
cons: finding a way to get it over there (rcp/scp work, NFS works, you need to determine the best way for you).
All things considered, this is the most minor con as you could simply do something like
open my $fh, "|ssh user#host 'cat > /tmp/myscript'";
print $fh $script;
system qw(ssh user#host), "chmod u+x /tmp/myscript; /tmp/myscript; rm /tmp/myscript";
Of course, you'd add in some error handling (failed open, what if /tmp/myscript exists, etc.), but that's the idea.
Given a choice between rsh and telnet via expect, I would chose rsh. Expect scripts are fragile. All it takes to break one is someone changing the value of PS1 on the remote machine. Using rsh also prepares you for the day you will finally enter the '90s and start using ssh (since you can mostly just change rcp to scp and rsh to ssh and everything still works).