summaryrefslogtreecommitdiff
path: root/ironic
diff options
context:
space:
mode:
Diffstat (limited to 'ironic')
-rw-r--r--ironic/conductor/deployments.py43
-rw-r--r--ironic/drivers/modules/agent_base.py9
-rw-r--r--ironic/drivers/modules/drac/management.py2
-rw-r--r--ironic/tests/unit/conductor/test_deployments.py33
-rw-r--r--ironic/tests/unit/drivers/modules/drac/test_management.py9
5 files changed, 64 insertions, 32 deletions
diff --git a/ironic/conductor/deployments.py b/ironic/conductor/deployments.py
index daff72826..6799f059a 100644
--- a/ironic/conductor/deployments.py
+++ b/ironic/conductor/deployments.py
@@ -265,6 +265,16 @@ def do_next_deploy_step(task, step_index):
{'step': step, 'node': node.uuid})
try:
result = interface.execute_deploy_step(task, step)
+ except exception.AgentInProgress as e:
+ LOG.info('Conductor attempted to process deploy step for '
+ 'node %(node)s. Agent indicated it is presently '
+ 'executing a command. Error: %(error)s',
+ {'node': task.node.uuid,
+ 'error': e})
+ driver_internal_info['skip_current_deploy_step'] = False
+ node.driver_internal_info = driver_internal_info
+ task.process_event('wait')
+ return
except exception.IronicException as e:
if isinstance(e, exception.AgentConnectionFailed):
if task.node.driver_internal_info.get('deployment_reboot'):
@@ -276,23 +286,17 @@ def do_next_deploy_step(task, step_index):
node.driver_internal_info = driver_internal_info
task.process_event('wait')
return
- if isinstance(e, exception.AgentInProgress):
- LOG.info('Conductor attempted to process deploy step for '
- 'node %(node)s. Agent indicated it is presently '
- 'executing a command. Error: %(error)s',
- {'node': task.node.uuid,
- 'error': e})
- driver_internal_info['skip_current_deploy_step'] = False
- node.driver_internal_info = driver_internal_info
- task.process_event('wait')
- return
- log_msg = ('Node %(node)s failed deploy step %(step)s. Error: '
- '%(err)s' %
- {'node': node.uuid, 'step': node.deploy_step, 'err': e})
- utils.deploying_error_handler(
- task, log_msg,
- _("Deploy step %(step)s failed: %(err)s.")
- % {'step': conductor_steps.step_id(step), 'err': e})
+
+ # Avoid double handling of failures. For example, set_failed_state
+ # from deploy_utils already calls deploying_error_handler.
+ if task.node.provision_state != states.DEPLOYFAIL:
+ log_msg = ('Node %(node)s failed deploy step %(step)s. Error: '
+ '%(err)s' % {'node': node.uuid,
+ 'step': node.deploy_step, 'err': e})
+ utils.deploying_error_handler(
+ task, log_msg,
+ _("Deploy step %(step)s failed: %(err)s.")
+ % {'step': conductor_steps.step_id(step), 'err': e})
return
except Exception as e:
log_msg = ('Node %(node)s failed deploy step %(step)s with '
@@ -300,7 +304,10 @@ def do_next_deploy_step(task, step_index):
{'node': node.uuid, 'step': node.deploy_step, 'err': e})
utils.deploying_error_handler(
task, log_msg,
- _("Failed to deploy. Exception: %s") % e, traceback=True)
+ _("Deploy step %(step)s failed with %(exc)s: %(err)s.")
+ % {'step': conductor_steps.step_id(step), 'err': e,
+ 'exc': e.__class__.__name__},
+ traceback=True)
return
if task.node.provision_state == states.DEPLOYFAIL:
diff --git a/ironic/drivers/modules/agent_base.py b/ironic/drivers/modules/agent_base.py
index 43b2ba853..51d96ec4d 100644
--- a/ironic/drivers/modules/agent_base.py
+++ b/ironic/drivers/modules/agent_base.py
@@ -292,6 +292,15 @@ def log_and_raise_deployment_error(task, msg, collect_logs=True, exc=None):
"""
log_traceback = (exc is not None
and not isinstance(exc, exception.IronicException))
+
+ # Replicate the logic in do_next_deploy_step to prepend the current step
+ step_id = (conductor_steps.step_id(task.node.deploy_step)
+ if task.node.deploy_step else None)
+ if step_id and step_id not in msg:
+ msg = _("Deploy step %(step)s failed: %(err)s") % {
+ 'step': step_id, 'err': msg
+ }
+
LOG.error(msg, exc_info=log_traceback)
deploy_utils.set_failed_state(task, msg, collect_logs=collect_logs)
raise exception.InstanceDeployFailure(msg)
diff --git a/ironic/drivers/modules/drac/management.py b/ironic/drivers/modules/drac/management.py
index db380167f..d329a419c 100644
--- a/ironic/drivers/modules/drac/management.py
+++ b/ironic/drivers/modules/drac/management.py
@@ -247,7 +247,7 @@ def set_boot_device(node, device, persistent=False):
client.delete_jobs(job_ids=[job.id for job in unfinished_jobs])
if validate_job_queue:
- drac_job.validate_job_queue(node)
+ drac_job.validate_job_queue(node, name_prefix="Configure: BIOS")
try:
drac_boot_devices = client.list_boot_devices()
diff --git a/ironic/tests/unit/conductor/test_deployments.py b/ironic/tests/unit/conductor/test_deployments.py
index 020735984..65bb1eca1 100644
--- a/ironic/tests/unit/conductor/test_deployments.py
+++ b/ironic/tests/unit/conductor/test_deployments.py
@@ -111,9 +111,9 @@ class DoNodeDeployTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
self.assertEqual(states.ACTIVE, node.target_provision_state)
self.assertIsNotNone(node.last_error)
if unexpected:
- self.assertIn('Exception', node.last_error)
+ self.assertIn(exc.__class__.__name__, node.last_error)
else:
- self.assertNotIn('Exception', node.last_error)
+ self.assertNotIn(exc.__class__.__name__, node.last_error)
mock_deploy.assert_called_once_with(mock.ANY, task)
@@ -636,20 +636,23 @@ class DoNextDeployStepTestCase(mgr_utils.ServiceSetUpMixin,
@mock.patch.object(conductor_utils, 'LOG', autospec=True)
@mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_deploy_step',
autospec=True)
- def _do_next_deploy_step_execute_fail(self, exc, traceback,
+ def _do_next_deploy_step_execute_fail(self, exc, traceback, handled,
mock_execute, mock_log):
# When a deploy step fails, go to DEPLOYFAIL
driver_internal_info = {'deploy_step_index': None,
'deploy_steps': self.deploy_steps}
self._start_service()
+
node = obj_utils.create_test_node(
self.context, driver='fake-hardware',
driver_internal_info=driver_internal_info,
+ provision_state=states.DEPLOYFAIL if handled else states.DEPLOYING,
+ target_provision_state=states.ACTIVE,
+ last_error='existing error' if handled else None,
deploy_step={})
mock_execute.side_effect = exc
task = task_manager.TaskManager(self.context, node.uuid)
- task.process_event('deploy')
deployments.do_next_deploy_step(task, 0)
@@ -657,20 +660,30 @@ class DoNextDeployStepTestCase(mgr_utils.ServiceSetUpMixin,
node.refresh()
self.assertEqual(states.DEPLOYFAIL, node.provision_state)
self.assertEqual(states.ACTIVE, node.target_provision_state)
- self.assertEqual({}, node.deploy_step)
- self.assertNotIn('deploy_step_index', node.driver_internal_info)
- self.assertIsNotNone(node.last_error)
+ if handled:
+ self.assertEqual('existing error', node.last_error)
+ else:
+ self.assertEqual({}, node.deploy_step)
+ self.assertNotIn('deploy_step_index', node.driver_internal_info)
+ self.assertIsNotNone(node.last_error)
+ self.assertIn(f"Deploy step deploy.{self.deploy_steps[0]['step']}",
+ node.last_error)
+ mock_log.error.assert_called_once_with(mock.ANY,
+ exc_info=traceback)
self.assertFalse(node.maintenance)
mock_execute.assert_called_once_with(mock.ANY, mock.ANY,
self.deploy_steps[0])
- mock_log.error.assert_called_once_with(mock.ANY, exc_info=traceback)
def test_do_next_deploy_step_execute_ironic_exception(self):
self._do_next_deploy_step_execute_fail(
- exception.IronicException('foo'), False)
+ exception.IronicException('foo'), False, False)
def test_do_next_deploy_step_execute_exception(self):
- self._do_next_deploy_step_execute_fail(Exception('foo'), True)
+ self._do_next_deploy_step_execute_fail(Exception('foo'), True, False)
+
+ def test_do_next_deploy_step_execute_handled_exception(self):
+ self._do_next_deploy_step_execute_fail(
+ exception.IronicException('foo'), False, True)
@mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_deploy_step',
autospec=True)
diff --git a/ironic/tests/unit/drivers/modules/drac/test_management.py b/ironic/tests/unit/drivers/modules/drac/test_management.py
index 9d5182e89..3807753ef 100644
--- a/ironic/tests/unit/drivers/modules/drac/test_management.py
+++ b/ironic/tests/unit/drivers/modules/drac/test_management.py
@@ -286,7 +286,8 @@ class DracManagementInternalMethodsTestCase(test_utils.BaseDracTest):
self.assertEqual(0, mock_list_unfinished_jobs.call_count)
self.assertEqual(0, mock_client.delete_jobs.call_count)
- mock_validate_job_queue.assert_called_once_with(self.node)
+ mock_validate_job_queue.assert_called_once_with(
+ self.node, name_prefix="Configure: BIOS")
mock_client.change_boot_device_order.assert_called_once_with(
'OneTime', 'BIOS.Setup.1-1#BootSeq#NIC.Embedded.1-1-1')
self.assertEqual(0, mock_client.set_bios_settings.call_count)
@@ -550,7 +551,8 @@ class DracManagementInternalMethodsTestCase(test_utils.BaseDracTest):
self.assertEqual(0, mock_list_unfinished_jobs.call_count)
self.assertEqual(0, mock_client.delete_jobs.call_count)
- mock_validate_job_queue.assert_called_once_with(self.node)
+ mock_validate_job_queue.assert_called_once_with(
+ self.node, name_prefix="Configure: BIOS")
@mock.patch.object(drac_job, 'validate_job_queue', spec_set=True,
autospec=True)
@@ -601,7 +603,8 @@ class DracManagementInternalMethodsTestCase(test_utils.BaseDracTest):
self.assertEqual(0, mock_list_unfinished_jobs.call_count)
self.assertEqual(0, mock_client.delete_jobs.call_count)
- mock_validate_job_queue.assert_called_once_with(self.node)
+ mock_validate_job_queue.assert_called_once_with(
+ self.node, name_prefix="Configure: BIOS")
@mock.patch.object(drac_mgmt, '_get_next_persistent_boot_mode',
spec_set=True, autospec=True)