Cannot do "sudo su - postgres" with subprocess.call - python

I try the following command:
subprocess.call(['sudo', 'su - postgres'], shell=True)
or
subprocess.call(['sudo', 'su', '-', 'postgres'], shell=True)
in Python2.7 (either by ipython manually writing the line, or python myfile.py being the line as part of the code), and get the sudo usage information:
usage: sudo [-D level] -h | -K | -k | -V
usage: sudo -v [-AknS] [-D level] [-g groupname|#gid] [-p prompt] [-u user
name|#uid]
usage: sudo -l[l] [-AknS] [-D level] [-g groupname|#gid] [-p prompt] [-U user
name] [-u user name|#uid] [-g groupname|#gid] [command]
usage: sudo [-AbEHknPS] [-C fd] [-D level] [-g groupname|#gid] [-p prompt] [-u
user name|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] [<command>]
usage: sudo -e [-AknS] [-C fd] [-D level] [-g groupname|#gid] [-p prompt] [-u
user name|#uid] file ...
I can run the command in the shell with no problems at all. Both times it is the same shell.
Q: What am I doing wrong?

From the subprocess docs:
args is required for all calls and should be a string, or a sequence of program arguments. Providing a sequence of arguments is generally preferred, as it allows the module to take care of any required escaping and quoting of arguments (e.g. to permit spaces in file names). If passing a single string, either shell must be True (see below) or else the string must simply name the program to be executed without specifying any arguments.
Therefore, your list is really a sequence. For a single command, just place the string, together, as there is no need to have it split:
subprocess.call(['sudo su - postgres'], shell=True)

Related

Execute python script with parameter

I try to use python for get VM name on VMware (vSphere) when I execute this python script:
https://github.com/vmware/pyvmomi-community-samples/blob/master/samples/get_vm_names.py
I have this message :
python3 test2.py --host ip_of_vmware
usage: test2.py [-h] -s HOST [-o PORT] -u USER [-p PASSWORD] [-S]
test2.py: error: the following arguments are required: -u/--user
I don't know how to execute this script.
I think this line which used to put in parameter:
si = SmartConnectNoSSL(host=args.host,
user=args.user,
pwd=args.password,
port=int(args.port))
atexit.register(Disconnect, si)
I want to know how to execute this script.
The arguments required for the program are built by setup_args function in that program which in turn appears to be constructed by this line:
parser = cli.build_arg_parser()
This is in a package I don't have so I can't see what it is doing.
Nevertheless the help message, without explicitly stating which arguments are mandatory, is hinting in that general direction. I believe the arguments in [ ] are optional and everything else is required, so you need at least -s HOST and -u USER
python3 test2.py -s HOST -u USER
or
python3 test2.py --host HOST --user USER
If you read message carefully it already tells how to use.
usage: test2.py [-h] -s HOST [-o PORT] -u USER [-p PASSWORD] [-S]
You need to pass all required arguments to run script successfully. Arguments given in [] means optional.
[-h] is to show the help message:
$ python get_vm_names.py -h
usage: get_vm_names.py [-h] -s HOST [-o PORT] -u USER [-p PASSWORD] [-nossl]
Arguments for talking to vCenter
options:
-h, --help show this help message and exit
standard arguments:
-s HOST, --host HOST vSphere service address to connect to
-o PORT, --port PORT Port to connect on
-u USER, --user USER User name to use when connecting to host
-p PASSWORD, --password PASSWORD
Password to use when connecting to host
-nossl, --disable-ssl-verification
Disable ssl host certificate verification
Look at the standard arguments in above message.
To run the script pass the arguments like this:
$ python get_vm_names.py -s <vSphere Server IP> -u <username> -p <Password>
or
$ python get_vm_names.py --host <vSphere Server IP> --user <username> --password <Password>
vSphere server IP, username and password are the same value which you use to connect to vSphere manually.

Running subprocess with spaces in options in python

I tried to search for an answer for a while, but I did not find anything so far for my specific case. I want to run command in python:
ssh -o ConnectTimeout=3 -o ProxyCommand="ssh -q -W %h:%p bastion.host.com" host.com "screen -dmS TEST /bin/bash --login -c 'yes | script.sh --option-1 value1 -option2 value2 2>&1 | tee output.log'"
this is my code:
import subprocess
server_command = "screen -dmS TEST /bin/bash --login -c 'yes | script.sh --option-1 value1 -option2 value2 2>&1 | tee output.log'"
command = ['ssh', '-o', 'ConnectTimeout=3', 'ProxyCommand="ssh -q -W %h:%p bastion.host.com"', 'host.com', server_command]
p = subprocess.Popen(command, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
stdout, stderr = p.communicate(input=None)
Everything was working (screen was spawned with script running) until I added option with spaces: ProxyCommand="ssh -q -W %h:%p bastion.host.com".
After that I get error:
>>> print(stderr)
b'ssh: Could not resolve hostname ProxyCommand="ssh -q -W %h:%p bastion.host.com": Name or service not known\r\n'
How can I please pass this option to my command?
Your SSH command contains invalid arguments: ProxyCommand is an option, so it needs to be preceded by -o, same as ConnectTimeout (and, as noted by Charles Duffy, the redundant quotes inside that option string need to be removed, since the command is not passed to the shell):
server_command = 'screen -dmS TEST /bin/bash --login -c \'yes | script.sh --option-1 value1 -option2 value2 2>&1 | tee output.log\''
command = ['ssh', '-o', 'ConnectTimeout=3', '-o', 'ProxyCommand=ssh -q -W %h:%p bastion.host.com', 'host.com', server_command]
In general when your command line contains spaces and/or quotes and is passed to another command, it may be necessary to shell-quote it. The Python function shlex.quote automates this. In your case it’s not necessary because you (correctly) manually quoted the command you’re passing to screen inside server_command. Alternatively you could have written the following:
script_command = 'yes | script.sh --option-1 value1 -option2 value2 2>&1 | tee output.log'
server_command = f'screen -dmS TEST /bin/bash --login -c {shlex.quote(script_command)}'
— Note the absence of manual quotes inside the shell command line. The advantage over manual quoting is that this will also work with nested levels of shell quoting, e.g. when nesting command invocations.

Output Test names in unittest discover

I'm running Python unittest using the discover mode:
% python -m unittest discover
The system prints a dot for each test, but I'd rather see a test name.
Is there an option that makes this happen?
The verbose flag (-v) is what you're looking for:
$ python -m unittest discover -v
test_a (tests.test_a.TestA) ... ok
test_b (tests.test_b.TestB) ... ok
...
For more options, check:
$ python -m unittest --help
usage: python -m unittest [-h] [-v] [-q] [--locals] [-f] [-c] [-b]
[tests [tests ...]]
positional arguments:
tests a list of any number of test modules, classes and test
methods.
optional arguments:
-h, --help show this help message and exit
-v, --verbose Verbose output
-q, --quiet Quiet output
--locals Show local variables in tracebacks
-f, --failfast Stop on first fail or error
-c, --catch Catch Ctrl-C and display results so far
-b, --buffer Buffer stdout and stderr during tests
...

How to override the cli name in argparse -h usage information?

I am bundling my python app into an .AppImage file. Now, when I run it with flag -h I would expect it to print something along these lines:
$ ./mytool.AppImage -h
usage: mytool [-h] [-d DIR] [-f] [-e] [BLA [BLA ...]]
...
But due to the nature of the AppImage bundling process I get:
$ ./mytool.AppImage -h
usage: AppRun [-h] [-d DIR] [-f] [-e] [BLA [BLA ...]]
...
That is, AppRun instead of mytool.
So my question is:
How can I force override the app name so that regardless of how the app is called it will always print the same name in the usage string?
As per hpaulj's comment, this can solved by simply setting the prog parameter of the argparse.ArgumentParser constructor:
parser = argparse.ArgumentParser(
prog='mytool',
description='Some description...'
)

how to load python script in interactive shell

I am trying sudo python get_gps.py -c and expecting it to load the script and then present the interactive shell to debug the script live as opposed to typing it in manually.
From the docs:
$ python --help
usage: /usr/bin/python2.7 [option] ... [-c cmd | -m mod | file | -] [arg] ...
Options and arguments (and corresponding environment variables):
-B : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x
-c cmd : program passed in as string (terminates option list)
-d : debug output from parser; also PYTHONDEBUG=x
-E : ignore PYTHON* environment variables (such as PYTHONPATH)
-h : print this help message and exit (also --help)
-i : inspect interactively after running script; forces a prompt even
if stdin does not appear to be a terminal; also PYTHONINSPECT=x
use -i option

Categories