diff options
author | Dmitry Tantsur <dtantsur@protonmail.com> | 2020-09-25 14:21:29 +0200 |
---|---|---|
committer | Dmitry Tantsur <dtantsur@protonmail.com> | 2020-10-06 17:27:24 +0200 |
commit | 1dfb61dc4fe1e66743b83a08af96ef6ab1e6bf26 (patch) | |
tree | dfe2f9d1d256a5ccc056c8604e6b09a5117fbe70 | |
parent | c9c605d8b83270edbdb56c6e77d2a2ec339bba3e (diff) | |
download | ironic-1dfb61dc4fe1e66743b83a08af96ef6ab1e6bf26.tar.gz |
Refactoring: split away continue_node_deploy/clean
To be able to get rid of using RPC for continuing async steps
we need this code to be callable.
Change-Id: I87ec9c39fa00226b196605af97d528b268f304c7
-rw-r--r-- | ironic/conductor/cleaning.py | 45 | ||||
-rw-r--r-- | ironic/conductor/deployments.py | 36 | ||||
-rw-r--r-- | ironic/conductor/manager.py | 81 | ||||
-rw-r--r-- | ironic/conductor/utils.py | 30 | ||||
-rw-r--r-- | ironic/tests/unit/conductor/test_cleaning.py | 29 | ||||
-rw-r--r-- | ironic/tests/unit/conductor/test_deployments.py | 77 | ||||
-rw-r--r-- | ironic/tests/unit/conductor/test_manager.py | 189 |
7 files changed, 224 insertions, 263 deletions
diff --git a/ironic/conductor/cleaning.py b/ironic/conductor/cleaning.py index 399cdc1ee..c279e2fcd 100644 --- a/ironic/conductor/cleaning.py +++ b/ironic/conductor/cleaning.py @@ -266,3 +266,48 @@ def do_node_clean_abort(task, step_name=None): utils.wipe_cleaning_internal_info(task) node.save() LOG.info(info_message) + + +@utils.fail_on_error(utils.cleaning_error_handler, + _("Unexpected error when processing next clean step")) +@task_manager.require_exclusive_lock +def continue_node_clean(task): + """Continue cleaning after finishing an async clean step. + + This function calculates which step has to run next and passes control + into do_next_clean_step. + + :param task: a TaskManager instance with an exclusive lock + """ + node = task.node + + next_step_index = utils.update_next_step_index(task, 'clean') + + # If this isn't the final clean step in the cleaning operation + # and it is flagged to abort after the clean step that just + # finished, we abort the cleaning operation. + if node.clean_step.get('abort_after'): + step_name = node.clean_step['step'] + if next_step_index is not None: + LOG.debug('The cleaning operation for node %(node)s was ' + 'marked to be aborted after step "%(step)s ' + 'completed. Aborting now that it has completed.', + {'node': task.node.uuid, 'step': step_name}) + + if node.target_provision_state == states.MANAGEABLE: + target_state = states.MANAGEABLE + else: + target_state = None + + task.process_event('fail', target_state=target_state) + do_node_clean_abort(task, step_name) + return + + LOG.debug('The cleaning operation for node %(node)s was ' + 'marked to be aborted after step "%(step)s" ' + 'completed. However, since there are no more ' + 'clean steps after this, the abort is not going ' + 'to be done.', {'node': node.uuid, + 'step': step_name}) + + do_next_clean_step(task, next_step_index) diff --git a/ironic/conductor/deployments.py b/ironic/conductor/deployments.py index 9fdfe84cc..8758ae08d 100644 --- a/ironic/conductor/deployments.py +++ b/ironic/conductor/deployments.py @@ -323,6 +323,42 @@ def do_next_deploy_step(task, step_index): {'node': node.uuid, 'instance': node.instance_uuid}) +@utils.fail_on_error(utils.deploying_error_handler, + _("Unexpected error when processing next deploy step")) +@task_manager.require_exclusive_lock +def continue_node_deploy(task): + """Continue deployment after finishing an async deploy step. + + This function calculates which step has to run next and passes control + into do_next_deploy_step. On the first run, deploy steps and templates are + also validated. + + :param task: a TaskManager instance with an exclusive lock + """ + node = task.node + + # Agent is now running, we're ready to validate the remaining steps + if not node.driver_internal_info.get('steps_validated'): + try: + conductor_steps.validate_deploy_templates(task) + conductor_steps.set_node_deployment_steps( + task, reset_current=False) + except exception.IronicException as exc: + msg = _('Failed to validate the final deploy steps list ' + 'for node %(node)s: %(exc)s') % {'node': node.uuid, + 'exc': exc} + return utils.deploying_error_handler(task, msg) + + info = node.driver_internal_info + info['steps_validated'] = True + node.driver_internal_info = info + node.save() + + next_step_index = utils.update_next_step_index(task, 'deploy') + + do_next_deploy_step(task, next_step_index) + + def _get_configdrive_obj_name(node): """Generate the object name for the config drive.""" return 'configdrive-%s' % node.uuid diff --git a/ironic/conductor/manager.py b/ironic/conductor/manager.py index 406f6945f..7fcccec04 100644 --- a/ironic/conductor/manager.py +++ b/ironic/conductor/manager.py @@ -879,38 +879,6 @@ class ConductorManager(base_manager.BaseConductorManager): 'state': node.provision_state, 'deploy_state': ', '.join(expected_states)}) - save_required = False - info = node.driver_internal_info - - # Agent is now running, we're ready to validate the remaining steps - if not info.get('steps_validated'): - try: - conductor_steps.validate_deploy_templates(task) - conductor_steps.set_node_deployment_steps( - task, reset_current=False) - except exception.IronicException as exc: - msg = _('Failed to validate the final deploy steps list ' - 'for node %(node)s: %(exc)s') % {'node': node.uuid, - 'exc': exc} - return utils.deploying_error_handler(task, msg) - info['steps_validated'] = True - save_required = True - - try: - skip_current_step = info.pop('skip_current_deploy_step') - except KeyError: - skip_current_step = True - else: - save_required = True - if info.pop('deployment_polling', None) is not None: - save_required = True - if save_required: - node.driver_internal_info = info - node.save() - - next_step_index = utils.get_node_next_deploy_steps( - task, skip_current_step=skip_current_step) - # TODO(rloo): When deprecation period is over and node is in # states.DEPLOYWAIT only, delete the check and always 'resume'. if node.provision_state == states.DEPLOYING: @@ -927,8 +895,7 @@ class ConductorManager(base_manager.BaseConductorManager): task.node) task.spawn_after( self._spawn_worker, - deployments.do_next_deploy_step, - task, next_step_index) + deployments.continue_node_deploy, task) @METRICS.timer('ConductorManager.do_node_tear_down') @messaging.expected_exceptions(exception.NoFreeConductorWorker, @@ -1167,57 +1134,13 @@ class ConductorManager(base_manager.BaseConductorManager): 'state': node.provision_state, 'clean_state': states.CLEANWAIT}) - save_required = False - info = node.driver_internal_info - try: - skip_current_step = info.pop('skip_current_clean_step') - except KeyError: - skip_current_step = True - else: - save_required = True - if info.pop('cleaning_polling', None) is not None: - save_required = True - if save_required: - node.driver_internal_info = info - node.save() - - next_step_index = utils.get_node_next_clean_steps( - task, skip_current_step=skip_current_step) - - # If this isn't the final clean step in the cleaning operation - # and it is flagged to abort after the clean step that just - # finished, we abort the cleaning operation. - if node.clean_step.get('abort_after'): - step_name = node.clean_step['step'] - if next_step_index is not None: - LOG.debug('The cleaning operation for node %(node)s was ' - 'marked to be aborted after step "%(step)s ' - 'completed. Aborting now that it has completed.', - {'node': task.node.uuid, 'step': step_name}) - task.process_event( - 'abort', - callback=self._spawn_worker, - call_args=(cleaning.do_node_clean_abort, - task, step_name), - err_handler=utils.provisioning_error_handler, - target_state=target_state) - return - - LOG.debug('The cleaning operation for node %(node)s was ' - 'marked to be aborted after step "%(step)s" ' - 'completed. However, since there are no more ' - 'clean steps after this, the abort is not going ' - 'to be done.', {'node': node.uuid, - 'step': step_name}) - task.process_event('resume', target_state=target_state) task.set_spawn_error_hook(utils.spawn_cleaning_error_handler, task.node) task.spawn_after( self._spawn_worker, - cleaning.do_next_clean_step, - task, next_step_index) + cleaning.continue_node_clean, task) @task_manager.require_exclusive_lock def _do_node_verify(self, task): diff --git a/ironic/conductor/utils.py b/ironic/conductor/utils.py index dc52d33b0..b1a007223 100644 --- a/ironic/conductor/utils.py +++ b/ironic/conductor/utils.py @@ -1121,6 +1121,36 @@ def get_node_next_deploy_steps(task, skip_current_step=True): skip_current_step=skip_current_step) +def update_next_step_index(task, step_type): + """Calculate the next step index and update the node. + + :param task: A TaskManager object + :param step_type: The type of steps to process: 'clean' or 'deploy'. + :returns: Index of the next step. + """ + info = task.node.driver_internal_info + save_required = False + + try: + skip_current_step = info.pop('skip_current_%s_step' % step_type) + except KeyError: + skip_current_step = True + else: + save_required = True + + field = ('cleaning_polling' if step_type == 'clean' + else 'deployment_polling') + if info.pop(field, None) is not None: + save_required = True + + if save_required: + task.node.driver_internal_info = info + task.node.save() + + return _get_node_next_steps(task, step_type, + skip_current_step=skip_current_step) + + def add_secret_token(node, pregenerated=False): """Adds a secret token to driver_internal_info for IPA verification. diff --git a/ironic/tests/unit/conductor/test_cleaning.py b/ironic/tests/unit/conductor/test_cleaning.py index 6ed4bd270..0bcb1c77f 100644 --- a/ironic/tests/unit/conductor/test_cleaning.py +++ b/ironic/tests/unit/conductor/test_cleaning.py @@ -995,6 +995,35 @@ class DoNodeCleanTestCase(db_base.DbTestCase): def test__do_next_clean_step_manual_bad_step_return_value(self): self._do_next_clean_step_bad_step_return_value(manual=True) + @mock.patch.object(cleaning, 'do_next_clean_step', autospec=True) + def _continue_node_clean(self, mock_next_step, skip=True): + # test that skipping current step mechanism works + driver_info = {'clean_steps': self.clean_steps, + 'clean_step_index': 0, + 'cleaning_polling': 'value'} + if not skip: + driver_info['skip_current_clean_step'] = skip + node = obj_utils.create_test_node( + self.context, driver='fake-hardware', + provision_state=states.CLEANING, + target_provision_state=states.MANAGEABLE, + driver_internal_info=driver_info, + clean_step=self.clean_steps[0]) + with task_manager.acquire(self.context, node.uuid) as task: + cleaning.continue_node_clean(task) + expected_step_index = 1 if skip else 0 + self.assertNotIn( + 'skip_current_clean_step', task.node.driver_internal_info) + self.assertNotIn( + 'cleaning_polling', task.node.driver_internal_info) + mock_next_step.assert_called_once_with(task, expected_step_index) + + def test_continue_node_clean(self): + self._continue_node_clean(skip=True) + + def test_continue_node_clean_no_skip_step(self): + self._continue_node_clean(skip=False) + class DoNodeCleanAbortTestCase(db_base.DbTestCase): @mock.patch.object(fake.FakeDeploy, 'tear_down_cleaning', autospec=True) diff --git a/ironic/tests/unit/conductor/test_deployments.py b/ironic/tests/unit/conductor/test_deployments.py index bafe3363f..6cff78acb 100644 --- a/ironic/tests/unit/conductor/test_deployments.py +++ b/ironic/tests/unit/conductor/test_deployments.py @@ -428,6 +428,8 @@ class DoNextDeployStepTestCase(mgr_utils.ServiceSetUpMixin, self.deploy_end = { 'step': 'deploy_end', 'priority': 20, 'interface': 'deploy'} self.deploy_steps = [self.deploy_start, self.deploy_end] + self.in_band_step = { + 'step': 'deploy_middle', 'priority': 30, 'interface': 'deploy'} @mock.patch.object(deployments, 'LOG', autospec=True) def test__do_next_deploy_step_none(self, mock_log): @@ -811,6 +813,81 @@ class DoNextDeployStepTestCase(mgr_utils.ServiceSetUpMixin, mock_execute.assert_called_once_with( mock.ANY, mock.ANY, self.deploy_steps[0]) + @mock.patch.object(deployments, 'do_next_deploy_step', autospec=True) + def _continue_node_deploy(self, mock_next_step, skip=True): + driver_info = {'deploy_steps': self.deploy_steps, + 'deploy_step_index': 0, + 'deployment_polling': 'value'} + if not skip: + driver_info['skip_current_deploy_step'] = skip + node = obj_utils.create_test_node( + self.context, driver='fake-hardware', + provision_state=states.DEPLOYING, + driver_internal_info=driver_info, + deploy_step=self.deploy_steps[0]) + with task_manager.acquire(self.context, node.uuid) as task: + deployments.continue_node_deploy(task) + expected_step_index = None if skip else 0 + self.assertNotIn( + 'skip_current_deploy_step', task.node.driver_internal_info) + self.assertNotIn( + 'deployment_polling', task.node.driver_internal_info) + mock_next_step.assert_called_once_with(task, expected_step_index) + + def test_continue_node_deploy(self): + self._continue_node_deploy(skip=True) + + def test_continue_node_deploy_no_skip_step(self): + self._continue_node_deploy(skip=False) + + @mock.patch.object(deployments, 'do_next_deploy_step', autospec=True) + @mock.patch('ironic.drivers.modules.fake.FakeDeploy.get_deploy_steps', + autospec=True) + def test_continue_node_deploy_first_agent_boot(self, mock_get_steps, + mock_next_step): + new_steps = [self.deploy_start, self.in_band_step, self.deploy_end] + mock_get_steps.return_value = new_steps + driver_info = {'deploy_steps': self.deploy_steps, + 'deploy_step_index': 0} + node = obj_utils.create_test_node(self.context, driver='fake-hardware', + provision_state=states.DEPLOYING, + target_provision_state=states.ACTIVE, + last_error=None, + driver_internal_info=driver_info, + deploy_step=self.deploy_steps[0]) + with task_manager.acquire(self.context, node.uuid) as task: + deployments.continue_node_deploy(task) + self.assertEqual(states.DEPLOYING, task.node.provision_state) + self.assertTrue(task.node.driver_internal_info['steps_validated']) + self.assertEqual(new_steps, + task.node.driver_internal_info['deploy_steps']) + mock_next_step.assert_called_once_with(task, 1) + + @mock.patch.object(deployments, 'do_next_deploy_step', autospec=True) + @mock.patch.object(conductor_steps, 'validate_deploy_templates', + autospec=True) + def test_continue_node_steps_validation(self, mock_validate, + mock_next_step): + tgt_prv_state = states.ACTIVE + mock_validate.side_effect = exception.InvalidParameterValue('boom') + driver_info = {'deploy_steps': self.deploy_steps, + 'deploy_step_index': 0, + 'steps_validated': False} + node = obj_utils.create_test_node(self.context, driver='fake-hardware', + provision_state=states.DEPLOYING, + target_provision_state=tgt_prv_state, + last_error=None, + driver_internal_info=driver_info, + deploy_step=self.deploy_steps[0]) + with task_manager.acquire(self.context, node.uuid) as task: + deployments.continue_node_deploy(task) + self.assertEqual(states.DEPLOYFAIL, task.node.provision_state) + self.assertIn('Failed to validate the final deploy steps', + task.node.last_error) + self.assertIn('boom', task.node.last_error) + self.assertEqual(tgt_prv_state, node.target_provision_state) + self.assertFalse(mock_next_step.called) + @mock.patch.object(swift, 'SwiftAPI', autospec=True) class StoreConfigDriveTestCase(db_base.DbTestCase): diff --git a/ironic/tests/unit/conductor/test_manager.py b/ironic/tests/unit/conductor/test_manager.py index 485e73665..648e86c98 100644 --- a/ironic/tests/unit/conductor/test_manager.py +++ b/ironic/tests/unit/conductor/test_manager.py @@ -1718,8 +1718,6 @@ class ContinueNodeDeployTestCase(mgr_utils.ServiceSetUpMixin, 'step': 'deploy_start', 'priority': 50, 'interface': 'deploy'} self.deploy_end = { 'step': 'deploy_end', 'priority': 20, 'interface': 'deploy'} - self.in_band_step = { - 'step': 'deploy_middle', 'priority': 30, 'interface': 'deploy'} self.deploy_steps = [self.deploy_start, self.deploy_end] @mock.patch('ironic.conductor.manager.ConductorManager._spawn_worker', @@ -1771,14 +1769,10 @@ class ContinueNodeDeployTestCase(mgr_utils.ServiceSetUpMixin, # test a node can continue deploying via RPC prv_state = states.DEPLOYWAIT tgt_prv_state = states.ACTIVE - driver_info = {'deploy_steps': self.deploy_steps, - 'deploy_step_index': 0, - 'steps_validated': True} node = obj_utils.create_test_node(self.context, driver='fake-hardware', provision_state=prv_state, target_provision_state=tgt_prv_state, last_error=None, - driver_internal_info=driver_info, deploy_step=self.deploy_steps[0]) self._start_service() self.service.continue_node_deploy(self.context, node.uuid) @@ -1787,38 +1781,8 @@ class ContinueNodeDeployTestCase(mgr_utils.ServiceSetUpMixin, self.assertEqual(states.DEPLOYING, node.provision_state) self.assertEqual(tgt_prv_state, node.target_provision_state) mock_spawn.assert_called_with(mock.ANY, - deployments.do_next_deploy_step, - mock.ANY, 1) - - @mock.patch('ironic.drivers.modules.fake.FakeDeploy.get_deploy_steps', - autospec=True) - @mock.patch('ironic.conductor.manager.ConductorManager._spawn_worker', - autospec=True) - def test_continue_node_deploy_first_agent_boot(self, mock_spawn, - mock_get_steps): - new_steps = [self.deploy_start, self.in_band_step, self.deploy_end] - mock_get_steps.return_value = new_steps - prv_state = states.DEPLOYWAIT - tgt_prv_state = states.ACTIVE - driver_info = {'deploy_steps': self.deploy_steps, - 'deploy_step_index': 0} - node = obj_utils.create_test_node(self.context, driver='fake-hardware', - provision_state=prv_state, - target_provision_state=tgt_prv_state, - last_error=None, - driver_internal_info=driver_info, - deploy_step=self.deploy_steps[0]) - self._start_service() - self.service.continue_node_deploy(self.context, node.uuid) - self._stop_service() - node.refresh() - self.assertEqual(states.DEPLOYING, node.provision_state) - self.assertEqual(tgt_prv_state, node.target_provision_state) - self.assertTrue(node.driver_internal_info['steps_validated']) - self.assertEqual(new_steps, node.driver_internal_info['deploy_steps']) - mock_spawn.assert_called_with(mock.ANY, - deployments.do_next_deploy_step, - mock.ANY, 1) + deployments.continue_node_deploy, + mock.ANY) @mock.patch.object(task_manager.TaskManager, 'process_event', autospec=True) @@ -1847,95 +1811,10 @@ class ContinueNodeDeployTestCase(mgr_utils.ServiceSetUpMixin, self.assertEqual(states.DEPLOYING, node.provision_state) self.assertEqual(tgt_prv_state, node.target_provision_state) mock_spawn.assert_called_with(mock.ANY, - deployments.do_next_deploy_step, - mock.ANY, 1) + deployments.continue_node_deploy, + mock.ANY) self.assertFalse(mock_event.called) - @mock.patch('ironic.conductor.manager.ConductorManager._spawn_worker', - autospec=True) - def _continue_node_deploy_skip_step(self, mock_spawn, skip=True): - # test that skipping current step mechanism works - driver_info = {'deploy_steps': self.deploy_steps, - 'deploy_step_index': 0, - 'steps_validated': True} - if not skip: - driver_info['skip_current_deploy_step'] = skip - node = obj_utils.create_test_node( - self.context, driver='fake-hardware', - provision_state=states.DEPLOYWAIT, - target_provision_state=states.MANAGEABLE, - driver_internal_info=driver_info, deploy_step=self.deploy_steps[0]) - self._start_service() - self.service.continue_node_deploy(self.context, node.uuid) - self._stop_service() - node.refresh() - if skip: - expected_step_index = 1 - else: - self.assertNotIn( - 'skip_current_deploy_step', node.driver_internal_info) - expected_step_index = 0 - mock_spawn.assert_called_with(mock.ANY, - deployments.do_next_deploy_step, - mock.ANY, expected_step_index) - - def test_continue_node_deploy_skip_step(self): - self._continue_node_deploy_skip_step() - - def test_continue_node_deploy_no_skip_step(self): - self._continue_node_deploy_skip_step(skip=False) - - @mock.patch('ironic.conductor.manager.ConductorManager._spawn_worker', - autospec=True) - def test_continue_node_deploy_polling(self, mock_spawn): - # test that deployment_polling flag is cleared - driver_info = {'deploy_steps': self.deploy_steps, - 'deploy_step_index': 0, - 'deployment_polling': True, - 'steps_validated': True} - node = obj_utils.create_test_node( - self.context, driver='fake-hardware', - provision_state=states.DEPLOYWAIT, - target_provision_state=states.MANAGEABLE, - driver_internal_info=driver_info, deploy_step=self.deploy_steps[0]) - self._start_service() - self.service.continue_node_deploy(self.context, node.uuid) - self._stop_service() - node.refresh() - self.assertNotIn('deployment_polling', node.driver_internal_info) - mock_spawn.assert_called_with(mock.ANY, - deployments.do_next_deploy_step, - mock.ANY, 1) - - @mock.patch.object(conductor_steps, 'validate_deploy_templates', - autospec=True) - @mock.patch('ironic.conductor.manager.ConductorManager._spawn_worker', - autospec=True) - def test_continue_node_steps_validation(self, mock_spawn, mock_validate): - prv_state = states.DEPLOYWAIT - tgt_prv_state = states.ACTIVE - mock_validate.side_effect = exception.InvalidParameterValue('boom') - driver_info = {'deploy_steps': self.deploy_steps, - 'deploy_step_index': 0, - 'steps_validated': False} - node = obj_utils.create_test_node(self.context, driver='fake-hardware', - provision_state=prv_state, - target_provision_state=tgt_prv_state, - last_error=None, - driver_internal_info=driver_info, - deploy_step=self.deploy_steps[0]) - self._start_service() - mock_spawn.reset_mock() - self.service.continue_node_deploy(self.context, node.uuid) - self._stop_service() - node.refresh() - self.assertEqual(states.DEPLOYFAIL, node.provision_state) - self.assertIn('Failed to validate the final deploy steps', - node.last_error) - self.assertIn('boom', node.last_error) - self.assertEqual(tgt_prv_state, node.target_provision_state) - self.assertFalse(mock_spawn.called) - @mgr_utils.mock_record_keepalive class CheckTimeoutsTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase): @@ -2627,13 +2506,10 @@ class DoNodeCleanTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase): # test a node can continue cleaning via RPC prv_state = return_state tgt_prv_state = states.MANAGEABLE if manual else states.AVAILABLE - driver_info = {'clean_steps': self.clean_steps, - 'clean_step_index': 0} node = obj_utils.create_test_node(self.context, driver='fake-hardware', provision_state=prv_state, target_provision_state=tgt_prv_state, last_error=None, - driver_internal_info=driver_info, clean_step=self.clean_steps[0]) self._start_service() self.service.continue_node_clean(self.context, node.uuid) @@ -2642,8 +2518,7 @@ class DoNodeCleanTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase): self.assertEqual(states.CLEANING, node.provision_state) self.assertEqual(tgt_prv_state, node.target_provision_state) mock_spawn.assert_called_with(self.service, - cleaning.do_next_clean_step, - mock.ANY, self.next_clean_step_index) + cleaning.continue_node_clean, mock.ANY) def test_continue_node_clean_automated(self): self._continue_node_clean(states.CLEANWAIT) @@ -2651,60 +2526,6 @@ class DoNodeCleanTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase): def test_continue_node_clean_manual(self): self._continue_node_clean(states.CLEANWAIT, manual=True) - @mock.patch('ironic.conductor.manager.ConductorManager._spawn_worker', - autospec=True) - def _continue_node_clean_skip_step(self, mock_spawn, skip=True): - # test that skipping current step mechanism works - driver_info = {'clean_steps': self.clean_steps, - 'clean_step_index': 0} - if not skip: - driver_info['skip_current_clean_step'] = skip - node = obj_utils.create_test_node( - self.context, driver='fake-hardware', - provision_state=states.CLEANWAIT, - target_provision_state=states.MANAGEABLE, - driver_internal_info=driver_info, clean_step=self.clean_steps[0]) - self._start_service() - self.service.continue_node_clean(self.context, node.uuid) - self._stop_service() - node.refresh() - if skip: - expected_step_index = 1 - else: - self.assertNotIn( - 'skip_current_clean_step', node.driver_internal_info) - expected_step_index = 0 - mock_spawn.assert_called_with(self.service, - cleaning.do_next_clean_step, - mock.ANY, expected_step_index) - - def test_continue_node_clean_skip_step(self): - self._continue_node_clean_skip_step() - - def test_continue_node_clean_no_skip_step(self): - self._continue_node_clean_skip_step(skip=False) - - @mock.patch('ironic.conductor.manager.ConductorManager._spawn_worker', - autospec=True) - def test_continue_node_clean_polling(self, mock_spawn): - # test that cleaning_polling flag is cleared - driver_info = {'clean_steps': self.clean_steps, - 'clean_step_index': 0, - 'cleaning_polling': True} - node = obj_utils.create_test_node( - self.context, driver='fake-hardware', - provision_state=states.CLEANWAIT, - target_provision_state=states.MANAGEABLE, - driver_internal_info=driver_info, clean_step=self.clean_steps[0]) - self._start_service() - self.service.continue_node_clean(self.context, node.uuid) - self._stop_service() - node.refresh() - self.assertNotIn('cleaning_polling', node.driver_internal_info) - mock_spawn.assert_called_with(self.service, - cleaning.do_next_clean_step, - mock.ANY, 1) - def _continue_node_clean_abort(self, manual=False): last_clean_step = self.clean_steps[0] last_clean_step['abortable'] = False |