I'm running into a strange situation with getting incorrect
returncodes / exit status from python subprocess.call. I'm using a
python script (runtime 2.6.1 on windows) to automate the deploy of
java applications to glassfish application server. Below is an example
of using a subprocess call to test the success / failure of the
glassfish CLI tool "asadmin"
Example.py:
----------------------
import sys
from subprocess import *
try:
retcode = call("c:/glassfish/bin/asadmin.bat " + "list-system-
properties --host mydomain --port 4848 --user admin server-01",
shell=True)
if retcode < 0:
print >>sys.stderr, "Child was terminated by signal", -retcode
else:
print >>sys.stderr, "Child returned", retcode
except OSError, e:
print >>sys.stderr, "Execution failed:", e
----------------------
However, when I execute it, it gets the same returncode whether it
fails or succeeds (0).
---------------------
C:\>python z:\bin\example.py
Please enter the admin password> ***Enters Good Password***
IIOP_SSL_MUTUALAUTH_PORT=33920
JMX_SYSTEM_CONNECTOR_PORT=38686
IIOP_LISTENER_PORT=33700
IIOP_SSL_LISTENER_PORT=33820
HTTP_LISTENER_PORT=38080
AJP_INSTANCE_NAME=WebReporting-01
HTTP_SSL_LISTENER_PORT=38181
JMS_PROVIDER_PORT=37676
AJP_PORT=18009
Command list-system-properties executed successfully.
Child returned 0
C:\>python z:\bin\example.py
Please enter the admin password>***Enters BAD PASSWORD***
Invalid user or password
CLI137 Command list-system-properties failed.
Child returned 0
C:\>
------------------------------------------------
When I execute this manually from the cmd.exe and I check the
%errorlevel% it returns the correct levels:
-----------------------------------------------
C:\>c:\glassfish\bin\asadmin.bat list-system-properties --host
mydomain --port 4848 --user admin server-01
Please enter the admin password>***GOOD PASSWORD***
IIOP_SSL_MUTUALAUTH_PORT=33920
JMX_SYSTEM_CONNECTOR_PORT=38686
IIOP_LISTENER_PORT=33700
IIOP_SSL_LISTENER_PORT=33820
HTTP_LISTENER_PORT=38080
AJP_INSTANCE_NAME=WebReporting-01
HTTP_SSL_LISTENER_PORT=38181
JMS_PROVIDER_PORT=37676
AJP_PORT=18009
Command list-system-properties executed successfully.
C:\>echo %errorlevel%
0
C:\>c:\glassfish\bin\asadmin.bat list-system-properties --host
mydomain --port 4848 --user admin server-01
Please enter the admin password>***BAD PASSWORD***
Invalid user or password
CLI137 Command list-system-properties failed.
C:\>echo %errorlevel%
1
C:\>
-------------------------------------
I'm guessing that returncode isn't the same thing as exit status? Is
there a way to get exit status using a subprocess function instead of
returncode? Is this the right way to go about this?
Thanks for any direction / advice you can provide.
Andrew
Don't use shell=True! Instead use a list of arguments without shell=True:
call(["c:/glassfish/bin/asadmin.bat", "list-system-properties", "--host
mydomain", "--port 4848", "--user admin", "server-01"])
That should solve your quoting issues on Windows and fix your code.
shell=True is considered evil and should be avoided whenever possible.
Christian
Thanks Christian,
I've removed shell=True, unfortunately, if I structure the call like:
call(["c:/glassfish/bin/asadmin.bat", "list-system-properties", "--
host
mydomain", "--port 4848", "--user admin", "server-01"])
It doesn't seem to recognize any arguments after list-system-
properties. If I structure it like:
call("c:/glassfish/bin/asadmin.bat "+"list-system-properties --host
mydomain --port 4848 --user admin server-01")
Then it executes correctly but still gives invalid returncode of 0
when it fails instead of 1.
Andrew
Should be:
call(["c:/glassfish/bin/asadmin.bat", "list-system-properties", "--host",
"mydomain", "--port", "4848", "--user", "admin", "server-01"])
*Every* argument should be an item in the list (your way, "--port 4848"
becomes a single argument, not two: option plus value)
(This is independent of your other issue)
> If I structure it like:
>
> call("c:/glassfish/bin/asadmin.bat "+"list-system-properties --host
> mydomain --port 4848 --user admin server-01")
>
> Then it executes correctly but still gives invalid returncode of 0
> when it fails instead of 1.
A similar example works fine for me:
C:\temp>type ret.c
#include <stdlib.h>
int main(int argc, char* argv[])
{
return atoi(argv[1]);
}
C:\temp>ret 5
C:\temp>echo %errorlevel%
5
C:\temp>type testret.bat
ret %1
C:\temp>testret 3
C:\temp>ret 3
C:\temp>echo %errorlevel%
3
C:\temp>type testret.py
from subprocess import call
ret = call(["testret.bat", "42"])
print "testret.bat exit code =", ret
C:\temp>python testret.py
C:\temp>ret 42
testret.bat exit code = 42
C:\temp>python -V
Python 2.6
C:\temp>ver
Microsoft Windows XP [Versión 5.1.2600]
--
Gabriel Genellina
I've tried this several ways now. It seems to be something specific
with python and asadmin.bat.
I've tried the following manually in the cmd.exe prompt:
------
C:\temp>c:\glassfish\bin\asadmin.bat list-system-properties
Instance-01
....
properties here
....
Command list-system-properties executed successfully.
C:\temp>echo %errorlevel%
0
C:\temp>c:\glassfish\bin\asadmin.bat list-system-properties
Instance-05 //note that Instance-05 does not exist
Cannot determine type for target : Instance-05
CLI137 Command list-system-properties failed.
C:\temp>echo %errorlevel%
1
C:\temp>ping 019293.com
Ping request could not find host 019293.com. Please check the name and
try again
.
C:\temp>echo %errorlevel%
1
C:\temp>ping google.com
Pinging google.com [74.125.45.100] with 32 bytes of data:
Reply from 74.125.45.100: bytes=32 time=48ms TTL=234
Reply from 74.125.45.100: bytes=32 time=66ms TTL=234
Reply from 74.125.45.100: bytes=32 time=63ms TTL=234
Reply from 74.125.45.100: bytes=32 time=44ms TTL=234
Ping statistics for 74.125.45.100:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 44ms, Maximum = 66ms, Average = 55ms
C:\temp>echo %errorlevel%
0
----------------------------------------
Then I tried the following in python (2.6.1)
---script---
import subprocess
import sys
try:
retcode = subprocess.call(["ping","019293.com"])
if retcode < 0:
print >>sys.stderr, "Child was terminated by signal", -retcode
else:
print >>sys.stderr, "Child returned", retcode
except OSError, e:
print >>sys.stderr, "Execution failed:", e
try:
retcode = subprocess.call(["ping","google.com"])
if retcode < 0:
print >>sys.stderr, "Child was terminated by signal", -retcode
else:
print >>sys.stderr, "Child returned", retcode
except OSError, e:
print >>sys.stderr, "Execution failed:", e
try:
retcode = subprocess.call(["c:/glassfish/bin/asadmin.bat","list-
system-properties","Instance-01"], shell=False)
if retcode < 0:
print >>sys.stderr, "Child was terminated by signal", -retcode
else:
print >>sys.stderr, "Child returned", retcode
except OSError, e:
print >>sys.stderr, "Execution failed:", e
try:
retcode = subprocess.call(["c:/glassfish/bin/asadmin.bat","list-
system-properties","Instance-05"], shell=False)
if retcode < 0:
print >>sys.stderr, "Child was terminated by signal", -retcode
else:
print >>sys.stderr, "Child returned", retcode
except OSError, e:
print >>sys.stderr, "Execution failed:", e
---script---
Executed Output:
---output---
C:\temp>c:\Python26\python.exe example2.py
Ping request could not find host 019293.com. Please check the name and
try again.
Child returned 1
Pinging google.com [74.125.67.100] with 32 bytes of data:
Reply from 74.125.67.100: bytes=32 time=244ms TTL=239
Reply from 74.125.67.100: bytes=32 time=244ms TTL=239
Reply from 74.125.67.100: bytes=32 time=191ms TTL=234
Reply from 74.125.67.100: bytes=32 time=59ms TTL=239
Ping statistics for 74.125.67.100:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 59ms, Maximum = 244ms, Average = 184ms
Child returned 0
...glassfish properties for Instance-01 display here...
Command list-system-properties executed successfully.
Child returned 0
Cannot determine type for target : Instance-05
CLI137 Command list-system-properties failed.
Child returned 0
C:\temp>
---output---
Notice how python never gets the correct returncode from asadmin.bat
but I can get the correct returncode from the shell every time. Can
anyone tell me why Python wouldn't be able to get the correct
returncode for asadmin?
TIA,
Andrew
I think the problem will be that cmd.exe doesn't return the exit code to
*its* caller correctly. You can often work around this by avoiding the
use of cmd.exe to spawn the child process, but obviously you do need it
with a .bat file. I'm not aware of an easy work-around.
Cheers,
Mark
> On Dec 16 2008, 5:11 pm, "Gabriel Genellina" <gagsl-...@yahoo.com.ar>
> wrote:
>> En Tue, 16 Dec 2008 17:21:35 -0200, Andrew <andrew.replo...@gmail.com>
>> escribió:
>>
>>
>>
>> > On Dec 16, 12:50 pm, Christian Heimes <li...@cheimes.de> wrote:
>> >> Andrew schrieb:
>>
>> >> > I'm running into a strange situation with getting incorrect
>> >> > returncodes / exit status from python subprocess.call. I'm using a
>> >> > python script (runtime 2.6.1 on windows) to automate the deploy of
>> >> > java applications to glassfish application server. Below is an >>
>> > example
> I've tried this several ways now. It seems to be something specific
> with python and asadmin.bat.
>
> I've tried the following manually in the cmd.exe prompt:
[examples showing %ERRORLEVEL% correctly set when running from the command
line, but subprocess.call doesn't get it]
> Notice how python never gets the correct returncode from asadmin.bat
> but I can get the correct returncode from the shell every time. Can
> anyone tell me why Python wouldn't be able to get the correct
> returncode for asadmin?
The last exit code set by a command *should* propagate as the exit code of
the whole .bat, then as the exit code of the cmd.exe instance that runs
it, and finally Python *should* receive that value. Some old Windows
versions didn't behave like that, but AFAIK XP does the right thing here.
Unless asadmin.bat is playing tricks with %ERRORLEVEL% or something.
Can you post the contents of asadmin.bat?
Without looking into it, I can think of a few alternatives:
- rewrite asadmin.bat in Python, if feasible. Some scripts just check/set
a few environment variables and execute some process at the end, and
that's all; in this case it should be easy to emulate the same thing in
Python.
- try using another layer of your own, e.g., my_asadmin.bat:
call asadmin.bat %*
exit /b %ERRORLEVEL%
- variation: write the exit code somewhere:
call asadmin.bat %*
echo %ERRORLEVEL% > asadmin.err
and read asadmin.err from Python. (I've used something like this in a
chain Win32 process --> 16 bits GUI application --> .bat script --> old
DOS executable)
--
Gabriel Genellina
Thanks Gabriel,
Someone on the glassfish forums also pointed out the "exit /B
%ERRORLEVEL%" for the bottom of the batch file and that corrected the
issue for me. As well as not using that and removing "endlocal" which
I admit I have no clue what that does. Removing endlocal seems to
cause the batch script to pass out the correct returncode.
Thanks everyone for your input and assistance =]
Andrew
> As well as not using that and removing "endlocal" which
> I admit I have no clue what that does.
Python isn't the only system in the world to include a help command.
C:\>help endlocal
Ends localization of environment changes in a batch file.
Environment changes made after ENDLOCAL has been issued are
not local to the batch file; the previous settings are not
restored on termination of the batch file.
ENDLOCAL
If Command Extensions are enabled ENDLOCAL changes as follows:
If the corresponding SETLOCAL enable or disabled command extensions
using the new ENABLEEXTENSIONS or DISABLEEXTENSIONS options, then
after the ENDLOCAL, the enabled/disabled state of command extensions
will be restored to what it was prior to the matching SETLOCAL
command execution.