Don't depend on translated strings for error check

Currently, execute() may raise an exception that contains a *translated*
string that starts with 'Exit code: %(returncode)d...' if the returncode
of a process was not 0. find_child_pids() will then check if the
raised exception contains 'Exit code: 1' (to check if the returncode is
1), but in non-English locales this will fail as the 2 strings are not
encoded the same.

This patch adds a new ProcessExecutionError (which inherits from
RuntimeError, so as to not change all the code that currently depends on
execute() returning RuntimeError) which now accepts a returncode. This
can be changed explicitly without depending on the error message.

Later patches can move ProcessExecutionError to neutron-lib, if this is
needed - this patch intends to write the smallest piece of code that can
be backported.

Closes-Bug: #1638273
Change-Id: I85d3bec13e852918eb13e73c1367c70e1f4d34b1
This commit is contained in:
John Schwarz
2016-11-01 14:28:32 +02:00
parent 15d65607a4
commit 3c1bf8697b
2 changed files with 12 additions and 5 deletions

View File

@@ -45,6 +45,12 @@ from neutron import wsgi
LOG = logging.getLogger(__name__)
class ProcessExecutionError(RuntimeError):
def __init__(self, message, returncode):
super(ProcessExecutionError, self).__init__(message)
self.returncode = returncode
class RootwrapDaemonHelper(object):
__client = None
__lock = threading.Lock()
@@ -136,7 +142,7 @@ def execute(cmd, process_input=None, addl_env=None,
if log_fail_as_error:
LOG.error(msg)
if check_exit_code:
raise RuntimeError(msg)
raise ProcessExecutionError(msg, returncode=returncode)
else:
LOG.debug("Exit code: %d", returncode)
@@ -169,11 +175,11 @@ def find_child_pids(pid):
try:
raw_pids = execute(['ps', '--ppid', pid, '-o', 'pid='],
log_fail_as_error=False)
except RuntimeError as e:
except ProcessExecutionError as e:
# Unexpected errors are the responsibility of the caller
with excutils.save_and_reraise_exception() as ctxt:
# Exception has already been logged by execute
no_children_found = 'Exit code: 1' in str(e)
no_children_found = e.returncode == 1
if no_children_found:
ctxt.reraise = False
return []

View File

@@ -122,7 +122,7 @@ class AgentUtilsExecuteTest(base.BaseTestCase):
self.mock_popen.return_value = ('', '')
self.process.return_value.returncode = 1
with mock.patch.object(utils, 'LOG') as log:
self.assertRaises(RuntimeError, utils.execute,
self.assertRaises(utils.ProcessExecutionError, utils.execute,
['ls'], log_fail_as_error=False)
self.assertFalse(log.error.called)
@@ -185,7 +185,8 @@ class TestFindChildPids(base.BaseTestCase):
def test_returns_empty_list_for_exit_code_1(self):
with mock.patch.object(utils, 'execute',
side_effect=RuntimeError('Exit code: 1')):
side_effect=utils.ProcessExecutionError(
'', returncode=1)):
self.assertEqual([], utils.find_child_pids(-1))
def test_returns_empty_list_for_no_output(self):