in azurelinuxagent/common/utils/shellutil.py [0:0]
def run_command(command, input=None, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, log_error=False, encode_input=True, encode_output=True, track_process=True, timeout=None): # pylint:disable=W0622
"""
Executes the given command and returns its stdout.
If there are any errors executing the command it raises a RunCommandException; if 'log_error'
is True, it also logs details about the error.
If encode_output is True the stdout is returned as a string, otherwise it is returned as a bytes object.
If track_process is False the command is not added to list of running commands
This function is a thin wrapper around Popen/communicate in the subprocess module:
* The 'input' parameter corresponds to the same parameter in communicate
* The 'stdin' parameter corresponds to the same parameters in Popen
* Only one of 'input' and 'stdin' can be specified
* The 'stdout' and 'stderr' parameters correspond to the same parameters in Popen, except that they
default to subprocess.PIPE instead of None
* If the output of the command is redirected using the 'stdout' or 'stderr' parameters (i.e. if the
value for these parameters is anything other than the default (subprocess.PIPE)), then the corresponding
values returned by this function or the CommandError exception will be empty strings.
NOTE: The 'timeout' parameter is ignored on Python 2
NOTE: This is the preferred method to execute shell commands over `azurelinuxagent.common.utils.shellutil.run` function.
"""
if input is not None and stdin is not None:
raise ValueError("The input and stdin arguments are mutually exclusive")
def command_action():
popen_stdin = communicate_input = None
if input is not None:
popen_stdin = subprocess.PIPE
communicate_input = input.encode() if encode_input and isinstance(input, str) else input # communicate() needs an array of bytes
if stdin is not None:
popen_stdin = stdin
communicate_input = None
if track_process:
process = _popen(command, stdin=popen_stdin, stdout=stdout, stderr=stderr, shell=False)
else:
process = subprocess.Popen(command, stdin=popen_stdin, stdout=stdout, stderr=stderr, shell=False)
try:
if sys.version_info[0] == 2: # communicate() doesn't support timeout on Python 2
command_stdout, command_stderr = process.communicate(input=communicate_input)
else:
command_stdout, command_stderr = process.communicate(input=communicate_input, timeout=timeout)
except TimeoutExpired:
if log_error:
logger.error(u"Command [{0}] timed out", __format_command(command))
command_stdout, command_stderr = '', ''
try:
process.kill()
# try to get any output from the command, but ignore any errors if we can't
try:
command_stdout, command_stderr = process.communicate()
# W0702: No exception type(s) specified (bare-except)
except: # pylint: disable=W0702
pass
except Exception as exception:
if log_error:
logger.error(u"Can't terminate timed out process: {0}", ustr(exception))
raise CommandError(command=__format_command(command), return_code=-1, stdout=command_stdout, stderr="command timeout\n{0}".format(command_stderr))
if track_process:
_on_command_completed(process.pid)
return process.returncode, command_stdout, command_stderr
return __run_command(command_action=command_action, command=command, log_error=log_error, encode_output=encode_output)