diff --git a/ironic_python_agent/extensions/base.py b/ironic_python_agent/extensions/base.py index 93adfe932..23e47c466 100644 --- a/ironic_python_agent/extensions/base.py +++ b/ironic_python_agent/extensions/base.py @@ -79,6 +79,17 @@ class BaseCommandResult(encoding.SerializableComparable): """:returns: result of completed command.""" return self + def wait(self): + """Join the result and extract its value. + + Raises if the command failed. + """ + self.join() + if self.command_error is not None: + raise self.command_error + else: + return self.command_result + class SyncCommandResult(BaseCommandResult): """A result from a command that executes synchronously.""" diff --git a/ironic_python_agent/hardware.py b/ironic_python_agent/hardware.py index 3724effb6..f8107b555 100644 --- a/ironic_python_agent/hardware.py +++ b/ironic_python_agent/hardware.py @@ -2139,7 +2139,7 @@ class GenericHardwareManager(HardwareManager): ext = ext_base.get_extension('standby') cmd = ext.prepare_image(image_info=image_info, configdrive=configdrive) # The result is asynchronous, wait here. - cmd.join() + return cmd.wait() def generate_tls_certificate(self, ip_address): """Generate a TLS certificate for the IP address.""" diff --git a/ironic_python_agent/tests/unit/extensions/test_base.py b/ironic_python_agent/tests/unit/extensions/test_base.py index f609e5809..2bc4c75b4 100644 --- a/ironic_python_agent/tests/unit/extensions/test_base.py +++ b/ironic_python_agent/tests/unit/extensions/test_base.py @@ -149,6 +149,12 @@ class TestExtensionDecorators(test_base.IronicAgentTest): result.command_result) self.agent.force_heartbeat.assert_called_once_with() + def test_wait_async_command_success(self): + result = self.extension.execute('fake_async_command', param='v1') + self.assertIsInstance(result, base.AsyncCommandResult) + result = result.wait() + self.assertEqual({'result': 'fake_async_command: v1'}, result) + def test_async_command_success_without_agent(self): extension = FakeExtension(agent=None) result = extension.execute('fake_async_command', param='v1') @@ -182,6 +188,11 @@ class TestExtensionDecorators(test_base.IronicAgentTest): self.assertIsNone(result.command_result) self.agent.force_heartbeat.assert_called_once_with() + def test_wait_async_command_execution_failure(self): + result = self.extension.execute('fake_async_command', param='v2') + self.assertIsInstance(result, base.AsyncCommandResult) + self.assertRaises(ExecutionError, result.wait) + def test_async_command_name(self): self.assertEqual( 'other_async_name', diff --git a/releasenotes/notes/prepare-image-49744276cef719d5.yaml b/releasenotes/notes/prepare-image-49744276cef719d5.yaml new file mode 100644 index 000000000..88e0d6d5d --- /dev/null +++ b/releasenotes/notes/prepare-image-49744276cef719d5.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fixes the ``write_image`` deploy step to actually check and return any + errors during its execution.