Provide container name when raising exceptions

Currently exceptions thrown during image builds only output the
Future object as a string. This is not very helpful as it does
not give any information on what container build threw the
exception. This patch uses the mapping created between the
Futures and container names to provide more detailed information.

Change-Id: Idb3e2ce893f8e493144ab9101fec9a13b375cf33
(cherry picked from commit cce0729710)
This commit is contained in:
Mike Turek 2019-11-22 16:54:02 +00:00 committed by Emilien Macchi
parent a868f4b64e
commit d60c5db663
2 changed files with 39 additions and 43 deletions

View File

@ -207,21 +207,26 @@ class BuildahBuilder(base.BaseBuilder):
# but not executed a SystemError will be raised.
for job in done:
if job._exception:
raise SystemError(job._exception)
raise SystemError("%(container)s raised %(exception)s" %
{'container': future_to_build[job],
'exception': job._exception})
else:
if not_done:
error_msg = ('The following jobs were '
'incomplete: {}'.format(not_done))
'incomplete: {}'.format(
[future_to_build[job] for job
in not_done]))
exceptions_raised = [job._exception for job in not_done
if job._exception]
if exceptions_raised:
error_msg = error_msg + os.linesep + (
"%(raised_count)d of the incomplete "
"jobs threw exceptions: %(exceptions)s" %
{'raised_count': len(exceptions_raised),
'exceptions': exceptions_raised})
jobs_with_exceptions = [{
'container': future_to_build[job],
'exception': job._exception}
for job in not_done if job._exception]
if jobs_with_exceptions:
for job_with_exception in jobs_with_exceptions:
error_msg = error_msg + os.linesep + (
"%(container)s raised the following "
"exception: %(exception)s" %
job_with_exception)
raise SystemError(error_msg)

View File

@ -51,32 +51,21 @@ class ThreadPoolExecutorReturnSuccess(object):
_exception = False
# Return values for the ThreadPoolExecutor
R_FAILED = (
(
ThreadPoolExecutorReturnSuccess,
ThreadPoolExecutorReturnSuccess,
ThreadPoolExecutorReturnFailed
),
set()
)
R_OK = (
(
ThreadPoolExecutorReturnSuccess,
ThreadPoolExecutorReturnSuccess,
ThreadPoolExecutorReturnSuccess
),
set()
)
R_BROKEN = (
(
ThreadPoolExecutorReturnSuccess,
),
(
ThreadPoolExecutorReturn,
ThreadPoolExecutorReturn
)
)
# Iterable version of the return values for predictable submit() returns
R_FAILED_LIST = [ThreadPoolExecutorReturnSuccess(),
ThreadPoolExecutorReturnSuccess(),
ThreadPoolExecutorReturnFailed()]
R_OK_LIST = [ThreadPoolExecutorReturnSuccess(),
ThreadPoolExecutorReturnSuccess(),
ThreadPoolExecutorReturnSuccess()]
R_BROKEN_LISTS = [[ThreadPoolExecutorReturnSuccess()],
[ThreadPoolExecutorReturn(),
ThreadPoolExecutorReturn()]]
# Return values as done and not_done sets for the ThreadPoolExecutor
R_FAILED = (set(R_FAILED_LIST), set())
R_OK = (set(R_OK_LIST), set())
R_BROKEN = (set(R_BROKEN_LISTS[0]), set(R_BROKEN_LISTS[1]))
class TestBuildahBuilder(base.TestCase):
@ -180,7 +169,8 @@ class TestBuildahBuilder(base.TestCase):
@mock.patch.object(tpe, 'submit', autospec=True)
@mock.patch.object(futures, 'wait', autospec=True, return_value=R_BROKEN)
@mock.patch.object(process, 'execute', autospec=True)
def test_build_all_list_broken(self, mock_submit, mock_wait, mock_build):
def test_build_all_list_broken(self, mock_build, mock_wait, mock_submit):
mock_submit.side_effect = R_BROKEN_LISTS[0] + R_BROKEN_LISTS[1]
_b = bb(WORK_DIR, DEPS)
self.assertRaises(
SystemError,
@ -191,7 +181,8 @@ class TestBuildahBuilder(base.TestCase):
@mock.patch.object(tpe, 'submit', autospec=True)
@mock.patch.object(futures, 'wait', autospec=True, return_value=R_FAILED)
@mock.patch.object(process, 'execute', autospec=True)
def test_build_all_list_failed(self, mock_submit, mock_wait, mock_build):
def test_build_all_list_failed(self, mock_build, mock_wait, mock_submit):
mock_submit.side_effect = R_FAILED_LIST
_b = bb(WORK_DIR, DEPS)
self.assertRaises(
SystemError,
@ -202,23 +193,23 @@ class TestBuildahBuilder(base.TestCase):
@mock.patch.object(tpe, 'submit', autospec=True)
@mock.patch.object(futures, 'wait', autospec=True, return_value=R_OK)
@mock.patch.object(process, 'execute', autospec=True)
def test_build_all_list_ok(self, mock_submit, mock_wait, mock_build):
def test_build_all_list_ok(self, mock_build, mock_wait, mock_submit):
bb(WORK_DIR, DEPS).build_all(deps=BUILD_ALL_LIST_CONTAINERS)
@mock.patch.object(tpe, 'submit', autospec=True)
@mock.patch.object(futures, 'wait', autospec=True, return_value=R_OK)
@mock.patch.object(process, 'execute', autospec=True)
def test_build_all_ok_no_deps(self, mock_submit, mock_wait, mock_build):
def test_build_all_ok_no_deps(self, mock_build, mock_wait, mock_submit):
bb(WORK_DIR, DEPS).build_all()
@mock.patch.object(tpe, 'submit', autospec=True)
@mock.patch.object(futures, 'wait', autospec=True, return_value=R_OK)
@mock.patch.object(process, 'execute', autospec=True)
def test_build_all_dict_ok(self, mock_submit, mock_wait, mock_build):
def test_build_all_dict_ok(self, mock_build, mock_wait, mock_submit):
bb(WORK_DIR, DEPS).build_all(deps=BUILD_ALL_DICT_CONTAINERS)
@mock.patch.object(tpe, 'submit', autospec=True)
@mock.patch.object(futures, 'wait', autospec=True, return_value=R_OK)
@mock.patch.object(process, 'execute', autospec=True)
def test_build_all_str_ok(self, mock_submit, mock_wait, mock_build):
def test_build_all_str_ok(self, mock_build, mock_wait, mock_submit):
bb(WORK_DIR, DEPS).build_all(deps=BUILD_ALL_STR_CONTAINER)