Skip to content

Commit

Permalink
in case of command failure, log the stdout and stderr and raise an ex…
Browse files Browse the repository at this point in the history
…ception
  • Loading branch information
pgombar committed Aug 8, 2019
1 parent 2347e0f commit dfb53d6
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 6 deletions.
12 changes: 6 additions & 6 deletions azurelinuxagent/common/utils/cryptutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,24 @@ def get_pubkey_from_prv(self, file_name):
if not os.path.exists(file_name):
raise IOError(errno.ENOENT, "File not found", file_name)
else:
cmd = "{0} pkey -in {1} -pubout 2>/dev/null".format(self.openssl_cmd, file_name)
pub = shellutil.run_get_output(cmd)[1]
cmd = "{0} pkey -in {1} -pubout".format(self.openssl_cmd, file_name)
pub = shellutil.run_command(cmd.split(" "))
return pub

def get_pubkey_from_crt(self, file_name):
if not os.path.exists(file_name):
raise IOError(errno.ENOENT, "File not found", file_name)
else:
cmd = "{0} x509 -in {1} -pubkey -noout 2>/dev/null".format(self.openssl_cmd, file_name)
pub = shellutil.run_get_output(cmd)[1]
cmd = "{0} x509 -in {1} -pubkey -noout".format(self.openssl_cmd, file_name)
pub = shellutil.run_command(cmd.split(" "))
return pub

def get_thumbprint_from_crt(self, file_name):
if not os.path.exists(file_name):
raise IOError(errno.ENOENT, "File not found", file_name)
else:
cmd = "{0} x509 -in {1} -fingerprint -noout 2>/dev/null".format(self.openssl_cmd, file_name)
thumbprint = shellutil.run_get_output(cmd)[1]
cmd = "{0} x509 -in {1} -fingerprint -noout".format(self.openssl_cmd, file_name)
thumbprint = shellutil.run_command(cmd.split(" "))
thumbprint = thumbprint.rstrip().split('=')[1].replace(':', '').upper()
return thumbprint

Expand Down
28 changes: 28 additions & 0 deletions azurelinuxagent/common/utils/shellutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,34 @@ def run_get_output(cmd, chk_err=True, log_cmd=True, expected_errors=[]):
return 0, output


def _encode_command_output(output):
return ustr(output, encoding='utf-8', errors="backslashreplace")


def run_command(command):
"""
Wrapper for subprocess.Popen.
Executes the given command and returns its stdout. Logs any errors executing the command and raises an exception.
"""
try:
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
stdout, stderr = process.communicate()
retcode = process.returncode

if retcode:
logger.error(u"Command: [{0}], return code: [{1}], "
u"stdout: [{2}] stderr: [{3}]".format(command,
retcode,
_encode_command_output(stdout),
_encode_command_output(stderr)))
raise subprocess.CalledProcessError(retcode, command)
except Exception as e:
logger.error(u"Command [{0}] raised unexpected exception: [{1}]".format(command, ustr(e)))
raise

return _encode_command_output(stdout)


def quote(word_list):
"""
Quote a list or tuple of strings for Unix Shell as words, using the
Expand Down
36 changes: 36 additions & 0 deletions tests/utils/test_shell_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import unittest
import os
import azurelinuxagent.common.utils.shellutil as shellutil
import subprocess
import test


Expand Down Expand Up @@ -142,5 +143,40 @@ def test_it_should_log_unexpected_errors_as_errors(self):
self.assertEquals(mock_logger.warn.call_count, 0)


class RunCommandTestCase(AgentTestCase):
def test_run_command_it_should_run_without_errors(self):
command = "echo 42".split(" ")

with patch("azurelinuxagent.common.utils.shellutil.logger", autospec=True) as mock_logger:
ret = shellutil.run_command(command)
self.assertEquals(ret, "42\n")
self.assertEquals(mock_logger.error.call_count, 0)

def test_run_command_it_should_raise_an_exception_file_not_found(self):
command = "ls nonexistent_file".split(" ")
expected_returncode = 2

with patch("azurelinuxagent.common.utils.shellutil.logger") as mock_logger:
with self.assertRaises(subprocess.CalledProcessError) as context_manager:
shellutil.run_command(command)

ex = context_manager.exception
self.assertEquals(subprocess.CalledProcessError, type(ex))
self.assertEquals((expected_returncode, ["ls", "nonexistent_file"]), ex.args)

self.assertEquals(mock_logger.error.call_count, 2)

logged_error_first = "Command: [{0}], return code: [{1}], " \
"stdout: [] stderr: [{2}]".format(command, expected_returncode,
"ls: cannot access 'nonexistent_file': "
"No such file or directory\n")
self.assertEquals(mock_logger.error.call_args_list[0][0][0], logged_error_first)

logged_error_second = "Command [{0}] raised unexpected exception: " \
"[Command '{0}' returned non-zero exit status {1}.]".format(command,
expected_returncode)
self.assertEquals(mock_logger.error.call_args_list[1][0][0], logged_error_second)


if __name__ == '__main__':
unittest.main()

0 comments on commit dfb53d6

Please sign in to comment.