exec power shell script having corrective action every time - powershell

Getting the corrective action for exec while using Powershell to ADD usersand groups to local admin group. Please note I am not a scripting guy, not sure what wrong I am doing.
Notice: /

By default, an Exec resource is applied on every run. That is mediated, where desired, by the resource's unless, onlyif, and / or creates parameters, as described in that resource type's documentation.
The creates parameter is probably not appropriate for this particular case, so choose one of unless or onlyif. Each one is expected to specify a command for Puppet to run, whose success or failure (as judged by its exit status) determines whether the Exec should be applied. These two parameters differ primarily in how they interpret the exit status:
unless interprets exit status 0 (success) as indicating that the Exec's main command should not be run
onlyif interprets exit statuses other than 0 (success) as indicating that the Exec's main command should not be run
I cannot advise you about the specific command to use here, but the general form of the resource declaration would be:
exec { 'Add-LocalGroupMember Administrators built-in':
command => '... PowerShell command to do the work ...',
unless => '... PowerShell command that exits with status 0 if the work is already done ...',
provider => 'powershell',
}
(That assumes that the puppetlabs-powershell module is installed, which I take to be the case for you based on details presented in the question.)
I see your comment on the question claiming that you tried this approach without success, but this is the answer. If your attempts to implement this were unsuccessful then you'll need to look more deeply into what went wrong with those. You haven't presented any of those details, and I'm anyway not fluent in PowerShell, but my first guess would be that the exit status of your unless or onlyif script was computed wrongly.
Additionally, you probably should set the Exec's refresh property to a command that succeeds without doing anything. I'm not sure what the would be on Windows, but on most other systems that Puppet supports, /bin/true would be idiomatic. (That's not correct for Windows; I give it only as an example of the kind of thing I mean.) This will prevent running the main command twice in the same Puppet run in the event that the Exec receives an event.

Related

How to fix 'script returned exit code 1' when running Powershell script through Jenkins?

I have a Powershell script which runs some Unity unit tests. On fail, this returns code 1, which Jenkins interprets as a fail and stops the current build. How do I avoid this behavior?
NOTE: This question is almost identical to this one, but that one uses bash, so I cannot apply it to my problem. In other words, how do I mimic the set +e behavior in Powershell? Alternatively, how do I tell Jenkins to ignore these script return codes and to continue the build anyway?
how do I mimic the set +e behavior in Powershell
You don't have to - it's the default behavior in that calls to external programs never[1] cause execution to stop prematurely, even if they report nonzero exit codes.
Alternatively, how do I tell Jenkins to ignore these script return codes and to continue the build anyway?
Ensuring that your script always terminates with exit 0 is indeed the correct way to ensure that Jenkins doesn't consider the script call failed (though you'll lose the information as to whether or not the tests failed).
[1] It can happen accidentally, due to flawed behavior up to PowerShell 7.1: If you use a 2> redirection and $ErrorActionPreference = 'Stop' happens to be effect, a script-terminating error occurs when stderr output is actually received. There is also pending RFC #277, which suggests introducing an opt-in mechanism for properly integrating external-program calls into PowerShell's error handling.

Does a background process complete if its parent finishes first?

I am not sure if this question is specific to Perl, but it is the language I am using. Say I launch a background process to save a web page to a local file like this:
system("curl http://google.com > output_file.html &");
I know this will launch a background process, though I'm not totally sure of the details (for example does it get its own PID?). But what's particularly important to me is, what happens if the process that launched it terminates before curl finishes downloading? Will curl be allowed to continue, or will it terminate too?
Is there any reason the solution wouldn't be to prepend the above command with nohup (nohup curl ...)? See http://linux.101hacks.com/unix/nohup-command/
Yes, your backgrounded process should complete even if the script exits first.
The system call forks, what means that at that point a new, independent, process is created as a near clone of the parent. That process is then replaced by the command to run, or by a shell that will run the command.† The system then waits for the child process to complete.
The & in the command makes sure that it is a shell that is run by the system, which then executes the command. The shell itself forks a process (subshell), in which the command is executed, and doesn't wait for it but returns right away.
At that point system's job is done and it returns control to the script.
The fate of the process forked by the shell has nothing more to do with the shell, or with your script, and the process will run to its completion.
The parent may well exit right away. See this with
use warnings;
use strict;
use feature 'say';
system("(sleep 5; echo hi) &");
say "Parent exiting.";
or, from a terminal
perl -wE'system("(sleep 3; echo me)&"); say "done"'
Once in the shell, the () starts a sub-shell, used here to put multiple commands in the background for this example (and representing your command). Keep that in mind when tracking process IDs via bash internal variables $BASHPID, $$, $PPID (here $$ differs from $BASHPID)
perl -wE'say $$; system("
( sleep 30; echo \$BASHPID; echo \$PPID; echo \$\$ ) &
"); say "done"'
Then view processes while this sleeps (by ps aux on my system, with | tail -n 10).
Most of the time the PID of a system-run command will be by two greater than that of the script, as there is a shell between them (for a backgrounded process as well, on my system). In the example above it should be greater by 3, because of an additional () subshell with mulitple commands.
This assumes that the /bin/sh which system uses does get relegated to bash.
Note: when the parent exits first the child is re-parented by init and all is well (no zombies).
† From system
Does exactly the same thing as exec, except that a fork is done first and the parent process waits for the child process to exit. Note that argument processing varies depending on the number of arguments. If there is more than one argument in LIST, or if LIST is an array with more than one value, starts the program given by the first element of the list with arguments given by the rest of the list. If there is only one scalar argument, the argument is checked for shell metacharacters, and if there are any, the entire argument is passed to the system's command shell for parsing (this is /bin/sh -c on Unix platforms, but varies on other platforms). If there are no shell metacharacters in the argument, it is split into words and passed directly to execvp, which is more efficient. ...
The "... starts the program given by the first element ..." also means by execvp, see exec.

extend runtime limit for a USUSP job

when I doing a calculation halfway, I just found the runtime limit 50:00 may not be sufficient. So I use $bstop 1234 to stop the job 1234 and try to modify the old runtime -W 50:00 to -W 100:00
Can you suggest a command to do so?
I tried
$ bmod -W 100:00 1234
Please request for a minimum of 32 cores!
For more information, please contact XXX#XXX.
Request aborted by esub. Job not modified.
$ bmod [-W 100:00| -Wn ] 1234
-bash: -Wn]: command not found
100:00[8217]: Illegal job ID.
. Job not modified.
according to
[-W [hour:]minute[/host_name | /host_model] | -Wn]
from http://www.cisl.ucar.edu/docs/LSF/7.0.3/command_reference/bmod.cmdref.html
I don't quite understand the syntax, -Wn does it mean Wall time new
Many thanks for your help!
The first command fails because LSF calls a the mandatory esub defined by your administrator to do some preprocessing on the command line, and this is returning an error. Here's the relevant quote from the page you linked:
Like bsub, bmod calls the master esub (mesub), which invokes any
mandatory esub executables configured by an LSF administrator, and any
executable named esub (without .application) if it exists in
LSF_SERVERDIR.
You're going to have to come up with a bmod command line that passes the esub checks, but that might cause other problems because some parameters (like -n I believe) can't be changed at runtime by default so bmod will reject the request if you specify it.
The -Wn option is used to remove the run limit from the job entirely rather than change it to a different value.

What does the EC2 command line say when a machine won't start?

When starting an instance on Amazon EC2, how would I detect a failure, for instance, if there's no machine available to fulfill my request? I'm using one of the less-common machine types and am concerned it won't start up, but am having trouble finding out what message to look for to detect this.
I'm using the EC2 commandline tools to do this. I know I can look for 'running' when I do ec2-describe-instance to see if the machine is up, but don't know what to look for to see if the startup failed.
Thanks!
The output from ec2-start-instances only returns you stopped pending, and as you say you need to use ec2-describe-instances to retrieve the state.
For that, you have a couple of choices; you can either use a loop to check for instance-state-name, looking for a result of running or stopped; alternatively you could look at either the reason or state-reason-code fields; unfortunately you'll need to trigger the failure you're worried about, to obtain the values that indicate failure.
The batch file I use to wait for a successful startup (fill in the underscores):
#echo off
set EC2_HOME=C:\tools\ec2-api-tools
set EC2_PRIVATE_KEY=C:\_\pk-_.pem
set EC2_CERT=C:\_\cert-_.pem
set JAVA_HOME=C:\Program Files (x86)\Java\jre6
%EC2_HOME%\bin\ec2-start-instances i-_
:docheck
%EC2_HOME%\bin\ec2-describe-instances | C:\tools\gnuwin32\bin\grep.exe -c stopped > %EC2_HOME%\temp.txt
findstr /m "1" %EC2_HOME%\temp.txt > nul
if %errorlevel%==0 (c:\tools\gnuwin32\bin\echo -n "."
goto docheck)
del temp.txt
ec2-start-instances will return you the previous state (after last command to instance) and the current state (after your command). ec2-stop instances does the same thing. THE PROBLEM IS, if you are scripting and you use -start- on a 'stopping' instance -OR- you use a -stop- on a 'pending' instance. These will cause exceptions in the command line tool and NASTILY exit your scripts all the way to the original console (VERY BAD BEHVIOR, AMAZON). So you have to go all the way through parsing the ec2-describe-instances [instance-id] result. HOWVER, that still leaves you vulnerable to that tiny little bit of time between when you GET the status from your instance and you APPLY A COMMAND. If someone else, or Amazon, puts you into pending or stopping, and you then do 'stop' or 'start respectively, your script will break. I really don't know how to catch such an exception with script. Bad Amazon AWS, BAD DOG!

how to use a shell script to supervise a program?

I've searched around but haven't quite found what I'm looking for. In a nutshell I have created a bash script to run in a infinite while loop, sleeping and checking if a process is running. The only problem is even if the process is running, it says it is not and opens another instance.
I know I should check by process name and not process id, since another process could jump in and take the id. However all perl programs are named Perl5.10.0 on my system, and I intend on having multiple instances of the same perl program open.
The following "if" always returns false, what am I doing wrong here???
while true; do
if [ ps -p $pid ]; then
echo "Program running fine"
sleep 10
else
echo "Program being restarted\n"
perl program_name.pl &
sleep 5
read -r pid < "${filename}_pid.txt"
fi
done
Get rid of the square brackets. It should be:
if ps -p $pid; then
The square brackets are syntactic sugar for the test command. This is an entirely different beast and does not invoke ps at all:
if test ps -p $pid; then
In fact that yields "-bash: [: -p: binary operator expected" when I run it.
Aside from the syntax error already pointed out, this is a lousy way to ensure that a process stays alive.
First, you should find out why your program is dying in the first place; this script doesn't fix a bug, it tries to hide one.
Secondly, if it is so important that a program remain running, why do you expect your (at least once already) buggy shell script will do the job? Use a system facility that is specifically designed to restart server processes. If you say what platform you are using and the nature of your server process. I can offer more concrete advice.
added in response to comment:
Sure, there are engineering exigencies, but as the OP noted in the OP, there is still a bug in this attempt at a solution:
I know I should check by process name
and not process id, since another
process could jump in and take the id.
So now you are left with a PID tracking script, not a process "nanny". Although the chances are small, the script as it now stands has a ten second window in which
the "monitored" process fails
I start up my week long emacs process which grabs the same PID
the nanny script continues on blissfully unaware that its dependent has failed
The script isn't merely buggy, it is invalid because it presumes that PIDs are stable identifiers of a process. There are ways that this could be better handled even at the shell script level. The simplest is to never detach the execution of perl from the script since the script is doing nothing other than watching the subprocess. For example:
while true ; do
if perl program_name.pl ; then
echo "program_name terminated normally, restarting"
else
echo "oops program_name died again, restarting"
fi
done
Which is not only shorter and simpler, but it actually blocks for the condition that you are really interested in: the run-state of the perl program. The original script repeatedly checks a bad proxy indication of the run state condition (the PID) and so can get it wrong. And, since the whole purpose of this nanny script is to handle faults, it would be bad if it were faulty itself by design.
I totally agree that fiddling with the PID is nearly always a bad idea. The while true ; do ... done script is quite good, however for production systems there a couple of process supervisors which do exactly this and much more, e.g.
enable you to send signals to the supervised process (without knowing it's PID)
check how long a service has been up or down
capturing its output and write it to a log file
Examples of such process supervisors are daemontools or runit. For a more elaborate discussion and examples see Init scripts considered harmful. Don't be disturbed by the title: Traditional init scripts suffer from exactly the same problem like you do (they start a daemon, keep it's PID in a file and then leave the daemon alone).
I agree that you should find out why your program is dying in the first place. However, an ever running shell script is probably not a good idea. What if this supervising shell script dies? (And yes, get rid of the square braces around ps -p $pid. You want the exit status of ps -p $pid command. The square brackets are a replacement for the test command.)
There are two possible solutions:
Use cron to run your "supervising" shell script to see if the process you're supervising is still running, and if it isn't, restart it. The supervised process can output it's PID into a file. Your supervising program can then cat this file and get the PID to check.
If the program you're supervising is providing a service upon a particular port, make it an inetd service. This way, it isn't running at all until there is a request upon that port. If you set it up correctly, it will terminate when not needed and restart when needed. Takes less resources and the OS will handle everything for you.
That's what kill -0 $pid is for. It returns success if a process with pid $pid exists.