"Fossies" - the Fresh Open Source Software Archive

Member "ironic-16.0.3/ironic/tests/unit/conductor/test_cleaning.py" (18 Jan 2021, 49653 Bytes) of package /linux/misc/openstack/ironic-16.0.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_cleaning.py": 16.0.2_vs_16.0.3.

    1 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    2 #    not use this file except in compliance with the License. You may obtain
    3 #    a copy of the License at
    4 #
    5 #         http://www.apache.org/licenses/LICENSE-2.0
    6 #
    7 #    Unless required by applicable law or agreed to in writing, software
    8 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    9 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   10 #    License for the specific language governing permissions and limitations
   11 #    under the License.
   12 
   13 """Tests for cleaning bits."""
   14 
   15 from unittest import mock
   16 
   17 from oslo_config import cfg
   18 from oslo_utils import uuidutils
   19 
   20 from ironic.common import exception
   21 from ironic.common import faults
   22 from ironic.common import states
   23 from ironic.conductor import cleaning
   24 from ironic.conductor import steps as conductor_steps
   25 from ironic.conductor import task_manager
   26 from ironic.conductor import utils as conductor_utils
   27 from ironic.drivers.modules import fake
   28 from ironic.drivers.modules.network import flat as n_flat
   29 from ironic.tests.unit.db import base as db_base
   30 from ironic.tests.unit.objects import utils as obj_utils
   31 
   32 CONF = cfg.CONF
   33 
   34 
   35 class DoNodeCleanTestCase(db_base.DbTestCase):
   36     def setUp(self):
   37         super(DoNodeCleanTestCase, self).setUp()
   38         self.config(automated_clean=True, group='conductor')
   39         self.power_update = {
   40             'step': 'update_firmware', 'priority': 10, 'interface': 'power'}
   41         self.deploy_update = {
   42             'step': 'update_firmware', 'priority': 10, 'interface': 'deploy'}
   43         self.deploy_erase = {
   44             'step': 'erase_disks', 'priority': 20, 'interface': 'deploy'}
   45         # Automated cleaning should be executed in this order
   46         self.clean_steps = [self.deploy_erase, self.power_update,
   47                             self.deploy_update]
   48         self.next_clean_step_index = 1
   49         # Manual clean step
   50         self.deploy_raid = {
   51             'step': 'build_raid', 'priority': 0, 'interface': 'deploy'}
   52 
   53     def __do_node_clean_validate_fail(self, mock_validate, clean_steps=None):
   54         # InvalidParameterValue should cause node to go to CLEANFAIL
   55         mock_validate.side_effect = exception.InvalidParameterValue('error')
   56         tgt_prov_state = states.MANAGEABLE if clean_steps else states.AVAILABLE
   57         node = obj_utils.create_test_node(
   58             self.context, driver='fake-hardware',
   59             provision_state=states.CLEANING,
   60             target_provision_state=tgt_prov_state)
   61         with task_manager.acquire(
   62                 self.context, node.uuid, shared=False) as task:
   63             cleaning.do_node_clean(task, clean_steps=clean_steps)
   64         node.refresh()
   65         self.assertEqual(states.CLEANFAIL, node.provision_state)
   66         self.assertEqual(tgt_prov_state, node.target_provision_state)
   67         self.assertFalse(node.maintenance)
   68         self.assertIsNone(node.fault)
   69         mock_validate.assert_called_once_with(mock.ANY, mock.ANY)
   70 
   71     @mock.patch('ironic.drivers.modules.fake.FakePower.validate',
   72                 autospec=True)
   73     def test__do_node_clean_automated_power_validate_fail(self, mock_validate):
   74         self.__do_node_clean_validate_fail(mock_validate)
   75 
   76     @mock.patch('ironic.drivers.modules.fake.FakePower.validate',
   77                 autospec=True)
   78     def test__do_node_clean_manual_power_validate_fail(self, mock_validate):
   79         self.__do_node_clean_validate_fail(mock_validate, clean_steps=[])
   80 
   81     @mock.patch('ironic.drivers.modules.network.flat.FlatNetwork.validate',
   82                 autospec=True)
   83     def test__do_node_clean_automated_network_validate_fail(self,
   84                                                             mock_validate):
   85         self.__do_node_clean_validate_fail(mock_validate)
   86 
   87     @mock.patch('ironic.drivers.modules.network.flat.FlatNetwork.validate',
   88                 autospec=True)
   89     def test__do_node_clean_manual_network_validate_fail(self, mock_validate):
   90         self.__do_node_clean_validate_fail(mock_validate, clean_steps=[])
   91 
   92     @mock.patch.object(cleaning, 'LOG', autospec=True)
   93     @mock.patch.object(conductor_steps, 'set_node_cleaning_steps',
   94                        autospec=True)
   95     @mock.patch.object(cleaning, 'do_next_clean_step', autospec=True)
   96     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.prepare_cleaning',
   97                 autospec=True)
   98     @mock.patch('ironic.drivers.modules.network.flat.FlatNetwork.validate',
   99                 autospec=True)
  100     @mock.patch('ironic.drivers.modules.fake.FakeBIOS.cache_bios_settings',
  101                 autospec=True)
  102     def _test__do_node_clean_cache_bios(self, mock_bios, mock_validate,
  103                                         mock_prep, mock_next_step, mock_steps,
  104                                         mock_log, clean_steps=None,
  105                                         enable_unsupported=False,
  106                                         enable_exception=False):
  107         if enable_unsupported:
  108             mock_bios.side_effect = exception.UnsupportedDriverExtension('')
  109         elif enable_exception:
  110             mock_bios.side_effect = exception.IronicException('test')
  111         mock_prep.return_value = states.NOSTATE
  112         tgt_prov_state = states.MANAGEABLE if clean_steps else states.AVAILABLE
  113         node = obj_utils.create_test_node(
  114             self.context, driver='fake-hardware',
  115             provision_state=states.CLEANING,
  116             target_provision_state=tgt_prov_state)
  117         with task_manager.acquire(
  118                 self.context, node.uuid, shared=False) as task:
  119             cleaning.do_node_clean(task, clean_steps=clean_steps)
  120             node.refresh()
  121             mock_bios.assert_called_once_with(mock.ANY, task)
  122             if clean_steps:
  123                 self.assertEqual(states.CLEANING, node.provision_state)
  124                 self.assertEqual(tgt_prov_state, node.target_provision_state)
  125             else:
  126                 self.assertEqual(states.CLEANING, node.provision_state)
  127                 self.assertEqual(states.AVAILABLE, node.target_provision_state)
  128             mock_validate.assert_called_once_with(mock.ANY, task)
  129             if enable_exception:
  130                 mock_log.exception.assert_called_once_with(
  131                     'Caching of bios settings failed on node {}. '
  132                     'Continuing with node cleaning.'
  133                     .format(node.uuid))
  134 
  135     def test__do_node_clean_manual_cache_bios(self):
  136         self._test__do_node_clean_cache_bios(clean_steps=[self.deploy_raid])
  137 
  138     def test__do_node_clean_automated_cache_bios(self):
  139         self._test__do_node_clean_cache_bios()
  140 
  141     def test__do_node_clean_manual_cache_bios_exception(self):
  142         self._test__do_node_clean_cache_bios(clean_steps=[self.deploy_raid],
  143                                              enable_exception=True)
  144 
  145     def test__do_node_clean_automated_cache_bios_exception(self):
  146         self._test__do_node_clean_cache_bios(enable_exception=True)
  147 
  148     def test__do_node_clean_manual_cache_bios_unsupported(self):
  149         self._test__do_node_clean_cache_bios(clean_steps=[self.deploy_raid],
  150                                              enable_unsupported=True)
  151 
  152     def test__do_node_clean_automated_cache_bios_unsupported(self):
  153         self._test__do_node_clean_cache_bios(enable_unsupported=True)
  154 
  155     @mock.patch('ironic.drivers.modules.fake.FakePower.validate',
  156                 autospec=True)
  157     def test__do_node_clean_automated_disabled(self, mock_validate):
  158         self.config(automated_clean=False, group='conductor')
  159 
  160         node = obj_utils.create_test_node(
  161             self.context, driver='fake-hardware',
  162             provision_state=states.CLEANING,
  163             target_provision_state=states.AVAILABLE,
  164             last_error=None)
  165         with task_manager.acquire(
  166                 self.context, node.uuid, shared=False) as task:
  167             cleaning.do_node_clean(task)
  168         node.refresh()
  169 
  170         # Assert that the node was moved to available without cleaning
  171         self.assertFalse(mock_validate.called)
  172         self.assertEqual(states.AVAILABLE, node.provision_state)
  173         self.assertEqual(states.NOSTATE, node.target_provision_state)
  174         self.assertEqual({}, node.clean_step)
  175         self.assertNotIn('clean_steps', node.driver_internal_info)
  176         self.assertNotIn('clean_step_index', node.driver_internal_info)
  177 
  178     @mock.patch('ironic.drivers.modules.fake.FakePower.validate',
  179                 autospec=True)
  180     @mock.patch('ironic.drivers.modules.network.flat.FlatNetwork.validate',
  181                 autospec=True)
  182     def test__do_node_clean_automated_disabled_individual_enabled(
  183             self, mock_network, mock_validate):
  184         self.config(automated_clean=False, group='conductor')
  185 
  186         node = obj_utils.create_test_node(
  187             self.context, driver='fake-hardware',
  188             provision_state=states.CLEANING,
  189             target_provision_state=states.AVAILABLE,
  190             last_error=None, automated_clean=True)
  191         with task_manager.acquire(
  192                 self.context, node.uuid, shared=False) as task:
  193             cleaning.do_node_clean(task)
  194         node.refresh()
  195 
  196         # Assert that the node clean was called
  197         self.assertTrue(mock_validate.called)
  198         self.assertIn('clean_steps', node.driver_internal_info)
  199 
  200     @mock.patch('ironic.drivers.modules.fake.FakePower.validate',
  201                 autospec=True)
  202     def test__do_node_clean_automated_disabled_individual_disabled(
  203             self, mock_validate):
  204         self.config(automated_clean=False, group='conductor')
  205 
  206         node = obj_utils.create_test_node(
  207             self.context, driver='fake-hardware',
  208             provision_state=states.CLEANING,
  209             target_provision_state=states.AVAILABLE,
  210             last_error=None, automated_clean=False)
  211         with task_manager.acquire(
  212                 self.context, node.uuid, shared=False) as task:
  213             cleaning.do_node_clean(task)
  214         node.refresh()
  215 
  216         # Assert that the node was moved to available without cleaning
  217         self.assertFalse(mock_validate.called)
  218         self.assertEqual(states.AVAILABLE, node.provision_state)
  219         self.assertEqual(states.NOSTATE, node.target_provision_state)
  220         self.assertEqual({}, node.clean_step)
  221         self.assertNotIn('clean_steps', node.driver_internal_info)
  222         self.assertNotIn('clean_step_index', node.driver_internal_info)
  223 
  224     @mock.patch('ironic.drivers.modules.fake.FakePower.validate',
  225                 autospec=True)
  226     @mock.patch('ironic.drivers.modules.network.flat.FlatNetwork.validate',
  227                 autospec=True)
  228     def test__do_node_clean_automated_enabled(self, mock_validate,
  229                                               mock_network):
  230         self.config(automated_clean=True, group='conductor')
  231 
  232         node = obj_utils.create_test_node(
  233             self.context, driver='fake-hardware',
  234             provision_state=states.CLEANING,
  235             target_provision_state=states.AVAILABLE,
  236             last_error=None,
  237             driver_internal_info={'agent_url': 'url'})
  238         with task_manager.acquire(
  239                 self.context, node.uuid, shared=False) as task:
  240             cleaning.do_node_clean(task)
  241         node.refresh()
  242 
  243         # Assert that the node was cleaned
  244         self.assertTrue(mock_validate.called)
  245         self.assertIn('clean_steps', node.driver_internal_info)
  246         self.assertNotIn('agent_url', node.driver_internal_info)
  247 
  248     @mock.patch('ironic.drivers.modules.fake.FakePower.validate',
  249                 autospec=True)
  250     @mock.patch('ironic.drivers.modules.network.flat.FlatNetwork.validate',
  251                 autospec=True)
  252     def test__do_node_clean_automated_enabled_individual_enabled(
  253             self, mock_network, mock_validate):
  254         self.config(automated_clean=True, group='conductor')
  255 
  256         node = obj_utils.create_test_node(
  257             self.context, driver='fake-hardware',
  258             provision_state=states.CLEANING,
  259             target_provision_state=states.AVAILABLE,
  260             last_error=None, automated_clean=True)
  261         with task_manager.acquire(
  262                 self.context, node.uuid, shared=False) as task:
  263             cleaning.do_node_clean(task)
  264         node.refresh()
  265 
  266         # Assert that the node was cleaned
  267         self.assertTrue(mock_validate.called)
  268         self.assertIn('clean_steps', node.driver_internal_info)
  269 
  270     @mock.patch('ironic.drivers.modules.fake.FakePower.validate',
  271                 autospec=True)
  272     @mock.patch('ironic.drivers.modules.network.flat.FlatNetwork.validate',
  273                 autospec=True)
  274     def test__do_node_clean_automated_enabled_individual_none(
  275             self, mock_validate, mock_network):
  276         self.config(automated_clean=True, group='conductor')
  277 
  278         node = obj_utils.create_test_node(
  279             self.context, driver='fake-hardware',
  280             provision_state=states.CLEANING,
  281             target_provision_state=states.AVAILABLE,
  282             last_error=None, automated_clean=None)
  283         with task_manager.acquire(
  284                 self.context, node.uuid, shared=False) as task:
  285             cleaning.do_node_clean(task)
  286         node.refresh()
  287 
  288         # Assert that the node was cleaned
  289         self.assertTrue(mock_validate.called)
  290         self.assertIn('clean_steps', node.driver_internal_info)
  291 
  292     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.tear_down_cleaning',
  293                 autospec=True)
  294     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.prepare_cleaning',
  295                 autospec=True)
  296     def test__do_node_clean_maintenance(self, mock_prep, mock_tear_down):
  297         CONF.set_override('allow_provisioning_in_maintenance', False,
  298                           group='conductor')
  299         node = obj_utils.create_test_node(
  300             self.context, driver='fake-hardware',
  301             provision_state=states.CLEANING,
  302             target_provision_state=states.AVAILABLE,
  303             maintenance=True,
  304             maintenance_reason='Original reason')
  305         with task_manager.acquire(
  306                 self.context, node.uuid, shared=False) as task:
  307             cleaning.do_node_clean(task)
  308             node.refresh()
  309             self.assertEqual(states.CLEANFAIL, node.provision_state)
  310             self.assertEqual(states.AVAILABLE, node.target_provision_state)
  311             self.assertIn('is not allowed', node.last_error)
  312             self.assertTrue(node.maintenance)
  313             self.assertEqual('Original reason', node.maintenance_reason)
  314             self.assertIsNone(node.fault)  # no clean step running
  315         self.assertFalse(mock_prep.called)
  316         self.assertFalse(mock_tear_down.called)
  317 
  318     @mock.patch('ironic.drivers.modules.network.flat.FlatNetwork.validate',
  319                 autospec=True)
  320     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.prepare_cleaning',
  321                 autospec=True)
  322     def __do_node_clean_prepare_clean_fail(self, mock_prep, mock_validate,
  323                                            clean_steps=None):
  324         # Exception from task.driver.deploy.prepare_cleaning should cause node
  325         # to go to CLEANFAIL
  326         mock_prep.side_effect = exception.InvalidParameterValue('error')
  327         tgt_prov_state = states.MANAGEABLE if clean_steps else states.AVAILABLE
  328         node = obj_utils.create_test_node(
  329             self.context, driver='fake-hardware',
  330             provision_state=states.CLEANING,
  331             target_provision_state=tgt_prov_state)
  332         with task_manager.acquire(
  333                 self.context, node.uuid, shared=False) as task:
  334             cleaning.do_node_clean(task, clean_steps=clean_steps)
  335             node.refresh()
  336             self.assertEqual(states.CLEANFAIL, node.provision_state)
  337             self.assertEqual(tgt_prov_state, node.target_provision_state)
  338             mock_prep.assert_called_once_with(mock.ANY, task)
  339             mock_validate.assert_called_once_with(mock.ANY, task)
  340             self.assertFalse(node.maintenance)
  341             self.assertIsNone(node.fault)
  342 
  343     def test__do_node_clean_automated_prepare_clean_fail(self):
  344         self.__do_node_clean_prepare_clean_fail()
  345 
  346     def test__do_node_clean_manual_prepare_clean_fail(self):
  347         self.__do_node_clean_prepare_clean_fail(clean_steps=[self.deploy_raid])
  348 
  349     @mock.patch('ironic.drivers.modules.network.flat.FlatNetwork.validate',
  350                 autospec=True)
  351     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.prepare_cleaning',
  352                 autospec=True)
  353     def __do_node_clean_prepare_clean_wait(self, mock_prep, mock_validate,
  354                                            clean_steps=None):
  355         mock_prep.return_value = states.CLEANWAIT
  356         tgt_prov_state = states.MANAGEABLE if clean_steps else states.AVAILABLE
  357         node = obj_utils.create_test_node(
  358             self.context, driver='fake-hardware',
  359             provision_state=states.CLEANING,
  360             target_provision_state=tgt_prov_state)
  361         with task_manager.acquire(
  362                 self.context, node.uuid, shared=False) as task:
  363             cleaning.do_node_clean(task, clean_steps=clean_steps)
  364         node.refresh()
  365         self.assertEqual(states.CLEANWAIT, node.provision_state)
  366         self.assertEqual(tgt_prov_state, node.target_provision_state)
  367         mock_prep.assert_called_once_with(mock.ANY, mock.ANY)
  368         mock_validate.assert_called_once_with(mock.ANY, mock.ANY)
  369 
  370     def test__do_node_clean_automated_prepare_clean_wait(self):
  371         self.__do_node_clean_prepare_clean_wait()
  372 
  373     def test__do_node_clean_manual_prepare_clean_wait(self):
  374         self.__do_node_clean_prepare_clean_wait(clean_steps=[self.deploy_raid])
  375 
  376     @mock.patch.object(n_flat.FlatNetwork, 'validate', autospec=True)
  377     @mock.patch.object(conductor_steps, 'set_node_cleaning_steps',
  378                        autospec=True)
  379     def __do_node_clean_steps_fail(self, mock_steps, mock_validate,
  380                                    clean_steps=None, invalid_exc=True):
  381         if invalid_exc:
  382             mock_steps.side_effect = exception.InvalidParameterValue('invalid')
  383         else:
  384             mock_steps.side_effect = exception.NodeCleaningFailure('failure')
  385         tgt_prov_state = states.MANAGEABLE if clean_steps else states.AVAILABLE
  386         node = obj_utils.create_test_node(
  387             self.context, driver='fake-hardware',
  388             uuid=uuidutils.generate_uuid(),
  389             provision_state=states.CLEANING,
  390             target_provision_state=tgt_prov_state)
  391         with task_manager.acquire(
  392                 self.context, node.uuid, shared=False) as task:
  393             cleaning.do_node_clean(task, clean_steps=clean_steps)
  394             mock_validate.assert_called_once_with(mock.ANY, task)
  395         node.refresh()
  396         self.assertEqual(states.CLEANFAIL, node.provision_state)
  397         self.assertEqual(tgt_prov_state, node.target_provision_state)
  398         mock_steps.assert_called_once_with(mock.ANY)
  399         self.assertFalse(node.maintenance)
  400         self.assertIsNone(node.fault)
  401 
  402     def test__do_node_clean_automated_steps_fail(self):
  403         for invalid in (True, False):
  404             self.__do_node_clean_steps_fail(invalid_exc=invalid)
  405 
  406     def test__do_node_clean_manual_steps_fail(self):
  407         for invalid in (True, False):
  408             self.__do_node_clean_steps_fail(clean_steps=[self.deploy_raid],
  409                                             invalid_exc=invalid)
  410 
  411     @mock.patch.object(conductor_steps, 'set_node_cleaning_steps',
  412                        autospec=True)
  413     @mock.patch.object(cleaning, 'do_next_clean_step', autospec=True)
  414     @mock.patch('ironic.drivers.modules.network.flat.FlatNetwork.validate',
  415                 autospec=True)
  416     @mock.patch('ironic.drivers.modules.fake.FakePower.validate',
  417                 autospec=True)
  418     def __do_node_clean(self, mock_power_valid, mock_network_valid,
  419                         mock_next_step, mock_steps, clean_steps=None):
  420         if clean_steps:
  421             tgt_prov_state = states.MANAGEABLE
  422             driver_info = {}
  423         else:
  424             tgt_prov_state = states.AVAILABLE
  425             driver_info = {'clean_steps': self.clean_steps}
  426 
  427         node = obj_utils.create_test_node(
  428             self.context, driver='fake-hardware',
  429             provision_state=states.CLEANING,
  430             target_provision_state=tgt_prov_state,
  431             last_error=None,
  432             power_state=states.POWER_OFF,
  433             driver_internal_info=driver_info)
  434 
  435         with task_manager.acquire(
  436                 self.context, node.uuid, shared=False) as task:
  437             cleaning.do_node_clean(task, clean_steps=clean_steps)
  438 
  439             node.refresh()
  440 
  441             mock_power_valid.assert_called_once_with(mock.ANY, task)
  442             mock_network_valid.assert_called_once_with(mock.ANY, task)
  443             mock_next_step.assert_called_once_with(task, 0)
  444             mock_steps.assert_called_once_with(task)
  445             if clean_steps:
  446                 self.assertEqual(clean_steps,
  447                                  node.driver_internal_info['clean_steps'])
  448             self.assertFalse(node.maintenance)
  449 
  450         # Check that state didn't change
  451         self.assertEqual(states.CLEANING, node.provision_state)
  452         self.assertEqual(tgt_prov_state, node.target_provision_state)
  453 
  454     def test__do_node_clean_automated(self):
  455         self.__do_node_clean()
  456 
  457     def test__do_node_clean_manual(self):
  458         self.__do_node_clean(clean_steps=[self.deploy_raid])
  459 
  460     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_clean_step',
  461                 autospec=True)
  462     def _do_next_clean_step_first_step_async(self, return_state, mock_execute,
  463                                              clean_steps=None):
  464         # Execute the first async clean step on a node
  465         driver_internal_info = {'clean_step_index': None}
  466         if clean_steps:
  467             tgt_prov_state = states.MANAGEABLE
  468             driver_internal_info['clean_steps'] = clean_steps
  469         else:
  470             tgt_prov_state = states.AVAILABLE
  471             driver_internal_info['clean_steps'] = self.clean_steps
  472 
  473         node = obj_utils.create_test_node(
  474             self.context, driver='fake-hardware',
  475             provision_state=states.CLEANING,
  476             target_provision_state=tgt_prov_state,
  477             last_error=None,
  478             driver_internal_info=driver_internal_info,
  479             clean_step={})
  480         mock_execute.return_value = return_state
  481         expected_first_step = node.driver_internal_info['clean_steps'][0]
  482 
  483         with task_manager.acquire(
  484                 self.context, node.uuid, shared=False) as task:
  485             cleaning.do_next_clean_step(task, 0)
  486 
  487         node.refresh()
  488 
  489         self.assertEqual(states.CLEANWAIT, node.provision_state)
  490         self.assertEqual(tgt_prov_state, node.target_provision_state)
  491         self.assertEqual(expected_first_step, node.clean_step)
  492         self.assertEqual(0, node.driver_internal_info['clean_step_index'])
  493         mock_execute.assert_called_once_with(
  494             mock.ANY, mock.ANY, expected_first_step)
  495 
  496     def test_do_next_clean_step_automated_first_step_async(self):
  497         self._do_next_clean_step_first_step_async(states.CLEANWAIT)
  498 
  499     def test_do_next_clean_step_manual_first_step_async(self):
  500         self._do_next_clean_step_first_step_async(
  501             states.CLEANWAIT, clean_steps=[self.deploy_raid])
  502 
  503     @mock.patch('ironic.drivers.modules.fake.FakePower.execute_clean_step',
  504                 autospec=True)
  505     def _do_next_clean_step_continue_from_last_cleaning(self, return_state,
  506                                                         mock_execute,
  507                                                         manual=False):
  508         # Resume an in-progress cleaning after the first async step
  509         tgt_prov_state = states.MANAGEABLE if manual else states.AVAILABLE
  510 
  511         node = obj_utils.create_test_node(
  512             self.context, driver='fake-hardware',
  513             provision_state=states.CLEANING,
  514             target_provision_state=tgt_prov_state,
  515             last_error=None,
  516             driver_internal_info={'clean_steps': self.clean_steps,
  517                                   'clean_step_index': 0},
  518             clean_step=self.clean_steps[0])
  519         mock_execute.return_value = return_state
  520 
  521         with task_manager.acquire(
  522                 self.context, node.uuid, shared=False) as task:
  523             cleaning.do_next_clean_step(task, self.next_clean_step_index)
  524 
  525         node.refresh()
  526 
  527         self.assertEqual(states.CLEANWAIT, node.provision_state)
  528         self.assertEqual(tgt_prov_state, node.target_provision_state)
  529         self.assertEqual(self.clean_steps[1], node.clean_step)
  530         self.assertEqual(1, node.driver_internal_info['clean_step_index'])
  531         mock_execute.assert_called_once_with(
  532             mock.ANY, mock.ANY, self.clean_steps[1])
  533 
  534     def test_do_next_clean_step_continue_from_last_cleaning(self):
  535         self._do_next_clean_step_continue_from_last_cleaning(states.CLEANWAIT)
  536 
  537     def test_do_next_clean_step_manual_continue_from_last_cleaning(self):
  538         self._do_next_clean_step_continue_from_last_cleaning(states.CLEANWAIT,
  539                                                              manual=True)
  540 
  541     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_clean_step',
  542                 autospec=True)
  543     def _do_next_clean_step_last_step_noop(self, mock_execute, manual=False,
  544                                            retired=False, fast_track=False):
  545         if fast_track:
  546             self.config(fast_track=True, group='deploy')
  547         # Resume where last_step is the last cleaning step, should be noop
  548         tgt_prov_state = states.MANAGEABLE if manual else states.AVAILABLE
  549         info = {'clean_steps': self.clean_steps,
  550                 'clean_step_index': len(self.clean_steps) - 1,
  551                 'agent_url': 'test-url',
  552                 'agent_secret_token': 'token'}
  553 
  554         node = obj_utils.create_test_node(
  555             self.context, driver='fake-hardware',
  556             provision_state=states.CLEANING,
  557             target_provision_state=tgt_prov_state,
  558             last_error=None,
  559             driver_internal_info=info,
  560             clean_step=self.clean_steps[-1],
  561             retired=retired)
  562 
  563         with task_manager.acquire(
  564                 self.context, node.uuid, shared=False) as task:
  565             cleaning.do_next_clean_step(task, None)
  566 
  567         node.refresh()
  568 
  569         # retired nodes move to manageable upon cleaning
  570         if retired:
  571             tgt_prov_state = states.MANAGEABLE
  572 
  573         # Cleaning should be complete without calling additional steps
  574         self.assertEqual(tgt_prov_state, node.provision_state)
  575         self.assertEqual(states.NOSTATE, node.target_provision_state)
  576         self.assertEqual({}, node.clean_step)
  577         self.assertNotIn('clean_step_index', node.driver_internal_info)
  578         self.assertIsNone(node.driver_internal_info['clean_steps'])
  579         self.assertFalse(mock_execute.called)
  580         if fast_track:
  581             self.assertEqual('test-url',
  582                              node.driver_internal_info.get('agent_url'))
  583             self.assertIsNotNone(
  584                 node.driver_internal_info.get('agent_secret_token'))
  585         else:
  586             self.assertNotIn('agent_url', node.driver_internal_info)
  587             self.assertNotIn('agent_secret_token',
  588                              node.driver_internal_info)
  589 
  590     def test__do_next_clean_step_automated_last_step_noop(self):
  591         self._do_next_clean_step_last_step_noop()
  592 
  593     def test__do_next_clean_step_manual_last_step_noop(self):
  594         self._do_next_clean_step_last_step_noop(manual=True)
  595 
  596     def test__do_next_clean_step_retired_last_step_change_tgt_state(self):
  597         self._do_next_clean_step_last_step_noop(retired=True)
  598 
  599     def test__do_next_clean_step_last_step_noop_fast_track(self):
  600         self._do_next_clean_step_last_step_noop(fast_track=True)
  601 
  602     @mock.patch('ironic.drivers.utils.collect_ramdisk_logs', autospec=True)
  603     @mock.patch('ironic.drivers.modules.fake.FakePower.execute_clean_step',
  604                 autospec=True)
  605     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_clean_step',
  606                 autospec=True)
  607     def _do_next_clean_step_all(self, mock_deploy_execute,
  608                                 mock_power_execute, mock_collect_logs,
  609                                 manual=False):
  610         # Run all steps from start to finish (all synchronous)
  611         tgt_prov_state = states.MANAGEABLE if manual else states.AVAILABLE
  612 
  613         node = obj_utils.create_test_node(
  614             self.context, driver='fake-hardware',
  615             provision_state=states.CLEANING,
  616             target_provision_state=tgt_prov_state,
  617             last_error=None,
  618             driver_internal_info={'clean_steps': self.clean_steps,
  619                                   'clean_step_index': None},
  620             clean_step={})
  621 
  622         def fake_deploy(conductor_obj, task, step):
  623             driver_internal_info = task.node.driver_internal_info
  624             driver_internal_info['goober'] = 'test'
  625             task.node.driver_internal_info = driver_internal_info
  626             task.node.save()
  627 
  628         mock_deploy_execute.side_effect = fake_deploy
  629         mock_power_execute.return_value = None
  630 
  631         with task_manager.acquire(
  632                 self.context, node.uuid, shared=False) as task:
  633             cleaning.do_next_clean_step(task, 0)
  634 
  635         node.refresh()
  636 
  637         # Cleaning should be complete
  638         self.assertEqual(tgt_prov_state, node.provision_state)
  639         self.assertEqual(states.NOSTATE, node.target_provision_state)
  640         self.assertEqual({}, node.clean_step)
  641         self.assertNotIn('clean_step_index', node.driver_internal_info)
  642         self.assertEqual('test', node.driver_internal_info['goober'])
  643         self.assertIsNone(node.driver_internal_info['clean_steps'])
  644         mock_power_execute.assert_called_once_with(mock.ANY, mock.ANY,
  645                                                    self.clean_steps[1])
  646         mock_deploy_execute.assert_has_calls(
  647             [mock.call(mock.ANY, mock.ANY, self.clean_steps[0]),
  648              mock.call(mock.ANY, mock.ANY, self.clean_steps[2])])
  649         self.assertFalse(mock_collect_logs.called)
  650 
  651     def test_do_next_clean_step_automated_all(self):
  652         self._do_next_clean_step_all()
  653 
  654     def test_do_next_clean_step_manual_all(self):
  655         self._do_next_clean_step_all(manual=True)
  656 
  657     @mock.patch('ironic.drivers.utils.collect_ramdisk_logs', autospec=True)
  658     @mock.patch('ironic.drivers.modules.fake.FakePower.execute_clean_step',
  659                 autospec=True)
  660     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_clean_step',
  661                 autospec=True)
  662     def test_do_next_clean_step_collect_logs(self, mock_deploy_execute,
  663                                              mock_power_execute,
  664                                              mock_collect_logs):
  665         CONF.set_override('deploy_logs_collect', 'always', group='agent')
  666         # Run all steps from start to finish (all synchronous)
  667         tgt_prov_state = states.MANAGEABLE
  668 
  669         node = obj_utils.create_test_node(
  670             self.context, driver='fake-hardware',
  671             provision_state=states.CLEANING,
  672             target_provision_state=tgt_prov_state,
  673             last_error=None,
  674             driver_internal_info={'clean_steps': self.clean_steps,
  675                                   'clean_step_index': None},
  676             clean_step={})
  677 
  678         def fake_deploy(conductor_obj, task, step):
  679             driver_internal_info = task.node.driver_internal_info
  680             driver_internal_info['goober'] = 'test'
  681             task.node.driver_internal_info = driver_internal_info
  682             task.node.save()
  683 
  684         mock_deploy_execute.side_effect = fake_deploy
  685         mock_power_execute.return_value = None
  686 
  687         with task_manager.acquire(
  688                 self.context, node.uuid, shared=False) as task:
  689             cleaning.do_next_clean_step(task, 0)
  690 
  691         node.refresh()
  692 
  693         # Cleaning should be complete
  694         self.assertEqual(tgt_prov_state, node.provision_state)
  695         self.assertEqual(states.NOSTATE, node.target_provision_state)
  696         self.assertEqual({}, node.clean_step)
  697         self.assertNotIn('clean_step_index', node.driver_internal_info)
  698         self.assertEqual('test', node.driver_internal_info['goober'])
  699         self.assertIsNone(node.driver_internal_info['clean_steps'])
  700         mock_power_execute.assert_called_once_with(mock.ANY, mock.ANY,
  701                                                    self.clean_steps[1])
  702         mock_deploy_execute.assert_has_calls(
  703             [mock.call(mock.ANY, mock.ANY, self.clean_steps[0]),
  704              mock.call(mock.ANY, mock.ANY, self.clean_steps[2])])
  705         mock_collect_logs.assert_called_once_with(mock.ANY, label='cleaning')
  706 
  707     @mock.patch('ironic.drivers.utils.collect_ramdisk_logs', autospec=True)
  708     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_clean_step',
  709                 autospec=True)
  710     @mock.patch.object(fake.FakeDeploy, 'tear_down_cleaning', autospec=True)
  711     def _do_next_clean_step_execute_fail(self, tear_mock, mock_execute,
  712                                          mock_collect_logs, manual=False):
  713         # When a clean step fails, go to CLEANFAIL
  714         tgt_prov_state = states.MANAGEABLE if manual else states.AVAILABLE
  715 
  716         node = obj_utils.create_test_node(
  717             self.context, driver='fake-hardware',
  718             provision_state=states.CLEANING,
  719             target_provision_state=tgt_prov_state,
  720             last_error=None,
  721             driver_internal_info={'clean_steps': self.clean_steps,
  722                                   'clean_step_index': None},
  723             clean_step={})
  724         mock_execute.side_effect = Exception()
  725 
  726         with task_manager.acquire(
  727                 self.context, node.uuid, shared=False) as task:
  728             cleaning.do_next_clean_step(task, 0)
  729             tear_mock.assert_called_once_with(task.driver.deploy, task)
  730 
  731         node.refresh()
  732 
  733         # Make sure we go to CLEANFAIL, clear clean_steps
  734         self.assertEqual(states.CLEANFAIL, node.provision_state)
  735         self.assertEqual(tgt_prov_state, node.target_provision_state)
  736         self.assertEqual({}, node.clean_step)
  737         self.assertNotIn('clean_step_index', node.driver_internal_info)
  738         self.assertIsNotNone(node.last_error)
  739         self.assertTrue(node.maintenance)
  740         self.assertEqual(faults.CLEAN_FAILURE, node.fault)
  741         mock_execute.assert_called_once_with(
  742             mock.ANY, mock.ANY, self.clean_steps[0])
  743         mock_collect_logs.assert_called_once_with(mock.ANY, label='cleaning')
  744 
  745     def test__do_next_clean_step_automated_execute_fail(self):
  746         self._do_next_clean_step_execute_fail()
  747 
  748     def test__do_next_clean_step_manual_execute_fail(self):
  749         self._do_next_clean_step_execute_fail(manual=True)
  750 
  751     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_clean_step',
  752                 autospec=True)
  753     def test_do_next_clean_step_oob_reboot(self, mock_execute):
  754         # When a clean step fails, go to CLEANWAIT
  755         tgt_prov_state = states.MANAGEABLE
  756 
  757         node = obj_utils.create_test_node(
  758             self.context, driver='fake-hardware',
  759             provision_state=states.CLEANING,
  760             target_provision_state=tgt_prov_state,
  761             last_error=None,
  762             driver_internal_info={'clean_steps': self.clean_steps,
  763                                   'clean_step_index': None,
  764                                   'cleaning_reboot': True},
  765             clean_step={})
  766         mock_execute.side_effect = exception.AgentConnectionFailed(
  767             reason='failed')
  768 
  769         with task_manager.acquire(
  770                 self.context, node.uuid, shared=False) as task:
  771             cleaning.do_next_clean_step(task, 0)
  772 
  773         node.refresh()
  774 
  775         # Make sure we go to CLEANWAIT
  776         self.assertEqual(states.CLEANWAIT, node.provision_state)
  777         self.assertEqual(tgt_prov_state, node.target_provision_state)
  778         self.assertEqual(self.clean_steps[0], node.clean_step)
  779         self.assertEqual(0, node.driver_internal_info['clean_step_index'])
  780         self.assertFalse(node.driver_internal_info['skip_current_clean_step'])
  781         mock_execute.assert_called_once_with(
  782             mock.ANY, mock.ANY, self.clean_steps[0])
  783 
  784     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_clean_step',
  785                 autospec=True)
  786     def test_do_next_clean_step_oob_reboot_last_step(self, mock_execute):
  787         # Resume where last_step is the last cleaning step
  788         tgt_prov_state = states.MANAGEABLE
  789         info = {'clean_steps': self.clean_steps,
  790                 'cleaning_reboot': True,
  791                 'clean_step_index': len(self.clean_steps) - 1}
  792 
  793         node = obj_utils.create_test_node(
  794             self.context, driver='fake-hardware',
  795             provision_state=states.CLEANING,
  796             target_provision_state=tgt_prov_state,
  797             last_error=None,
  798             driver_internal_info=info,
  799             clean_step=self.clean_steps[-1])
  800 
  801         with task_manager.acquire(
  802                 self.context, node.uuid, shared=False) as task:
  803             cleaning.do_next_clean_step(task, None)
  804 
  805         node.refresh()
  806 
  807         # Cleaning should be complete without calling additional steps
  808         self.assertEqual(tgt_prov_state, node.provision_state)
  809         self.assertEqual(states.NOSTATE, node.target_provision_state)
  810         self.assertEqual({}, node.clean_step)
  811         self.assertNotIn('clean_step_index', node.driver_internal_info)
  812         self.assertNotIn('cleaning_reboot', node.driver_internal_info)
  813         self.assertIsNone(node.driver_internal_info['clean_steps'])
  814         self.assertFalse(mock_execute.called)
  815 
  816     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_clean_step',
  817                 autospec=True)
  818     @mock.patch.object(fake.FakeDeploy, 'tear_down_cleaning', autospec=True)
  819     def test_do_next_clean_step_oob_reboot_fail(self, tear_mock,
  820                                                 mock_execute):
  821         # When a clean step fails with no reboot requested go to CLEANFAIL
  822         tgt_prov_state = states.MANAGEABLE
  823 
  824         node = obj_utils.create_test_node(
  825             self.context, driver='fake-hardware',
  826             provision_state=states.CLEANING,
  827             target_provision_state=tgt_prov_state,
  828             last_error=None,
  829             driver_internal_info={'clean_steps': self.clean_steps,
  830                                   'clean_step_index': None},
  831             clean_step={})
  832         mock_execute.side_effect = exception.AgentConnectionFailed(
  833             reason='failed')
  834 
  835         with task_manager.acquire(
  836                 self.context, node.uuid, shared=False) as task:
  837             cleaning.do_next_clean_step(task, 0)
  838             tear_mock.assert_called_once_with(task.driver.deploy, task)
  839 
  840         node.refresh()
  841 
  842         # Make sure we go to CLEANFAIL, clear clean_steps
  843         self.assertEqual(states.CLEANFAIL, node.provision_state)
  844         self.assertEqual(tgt_prov_state, node.target_provision_state)
  845         self.assertEqual({}, node.clean_step)
  846         self.assertNotIn('clean_step_index', node.driver_internal_info)
  847         self.assertNotIn('skip_current_clean_step', node.driver_internal_info)
  848         self.assertIsNotNone(node.last_error)
  849         self.assertTrue(node.maintenance)
  850         mock_execute.assert_called_once_with(
  851             mock.ANY, mock.ANY, self.clean_steps[0])
  852 
  853     @mock.patch.object(conductor_utils, 'LOG', autospec=True)
  854     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_clean_step',
  855                 autospec=True)
  856     @mock.patch('ironic.drivers.modules.fake.FakePower.execute_clean_step',
  857                 autospec=True)
  858     @mock.patch.object(fake.FakeDeploy, 'tear_down_cleaning', autospec=True)
  859     def _do_next_clean_step_fail_in_tear_down_cleaning(
  860             self, tear_mock, power_exec_mock, deploy_exec_mock, log_mock,
  861             manual=True):
  862         tgt_prov_state = states.MANAGEABLE if manual else states.AVAILABLE
  863 
  864         node = obj_utils.create_test_node(
  865             self.context, driver='fake-hardware',
  866             provision_state=states.CLEANING,
  867             target_provision_state=tgt_prov_state,
  868             last_error=None,
  869             driver_internal_info={'clean_steps': self.clean_steps,
  870                                   'clean_step_index': None},
  871             clean_step={})
  872 
  873         deploy_exec_mock.return_value = None
  874         power_exec_mock.return_value = None
  875         tear_mock.side_effect = Exception('boom')
  876 
  877         with task_manager.acquire(
  878                 self.context, node.uuid, shared=False) as task:
  879             cleaning.do_next_clean_step(task, 0)
  880 
  881         node.refresh()
  882 
  883         # Make sure we go to CLEANFAIL, clear clean_steps
  884         self.assertEqual(states.CLEANFAIL, node.provision_state)
  885         self.assertEqual(tgt_prov_state, node.target_provision_state)
  886         self.assertEqual({}, node.clean_step)
  887         self.assertNotIn('clean_step_index', node.driver_internal_info)
  888         self.assertIsNotNone(node.last_error)
  889         self.assertEqual(1, tear_mock.call_count)
  890         self.assertFalse(node.maintenance)  # no step is running
  891         deploy_exec_calls = [
  892             mock.call(mock.ANY, mock.ANY, self.clean_steps[0]),
  893             mock.call(mock.ANY, mock.ANY, self.clean_steps[2]),
  894         ]
  895         self.assertEqual(deploy_exec_calls, deploy_exec_mock.call_args_list)
  896 
  897         power_exec_calls = [
  898             mock.call(mock.ANY, mock.ANY, self.clean_steps[1]),
  899         ]
  900         self.assertEqual(power_exec_calls, power_exec_mock.call_args_list)
  901         log_mock.error.assert_called_once_with(
  902             'Failed to tear down from cleaning for node {}, reason: boom'
  903             .format(node.uuid), exc_info=True)
  904 
  905     def test__do_next_clean_step_automated_fail_in_tear_down_cleaning(self):
  906         self._do_next_clean_step_fail_in_tear_down_cleaning()
  907 
  908     def test__do_next_clean_step_manual_fail_in_tear_down_cleaning(self):
  909         self._do_next_clean_step_fail_in_tear_down_cleaning(manual=True)
  910 
  911     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_clean_step',
  912                 autospec=True)
  913     def _do_next_clean_step_no_steps(self, mock_execute, manual=False,
  914                                      fast_track=False):
  915         if fast_track:
  916             self.config(fast_track=True, group='deploy')
  917 
  918         for info in ({'clean_steps': None, 'clean_step_index': None,
  919                       'agent_url': 'test-url', 'agent_secret_token': 'magic'},
  920                      {'clean_steps': None, 'agent_url': 'test-url',
  921                       'agent_secret_token': 'it_is_a_kind_of_magic'}):
  922             # Resume where there are no steps, should be a noop
  923             tgt_prov_state = states.MANAGEABLE if manual else states.AVAILABLE
  924 
  925             node = obj_utils.create_test_node(
  926                 self.context, driver='fake-hardware',
  927                 uuid=uuidutils.generate_uuid(),
  928                 provision_state=states.CLEANING,
  929                 target_provision_state=tgt_prov_state,
  930                 last_error=None,
  931                 driver_internal_info=info,
  932                 clean_step={})
  933 
  934             with task_manager.acquire(
  935                     self.context, node.uuid, shared=False) as task:
  936                 cleaning.do_next_clean_step(task, None)
  937 
  938             node.refresh()
  939 
  940             # Cleaning should be complete without calling additional steps
  941             self.assertEqual(tgt_prov_state, node.provision_state)
  942             self.assertEqual(states.NOSTATE, node.target_provision_state)
  943             self.assertEqual({}, node.clean_step)
  944             self.assertNotIn('clean_step_index', node.driver_internal_info)
  945             self.assertFalse(mock_execute.called)
  946             if fast_track:
  947                 self.assertEqual('test-url',
  948                                  node.driver_internal_info.get('agent_url'))
  949                 self.assertIsNotNone(
  950                     node.driver_internal_info.get('agent_secret_token'))
  951             else:
  952                 self.assertNotIn('agent_url', node.driver_internal_info)
  953                 self.assertNotIn('agent_secret_token',
  954                                  node.driver_internal_info)
  955             mock_execute.reset_mock()
  956 
  957     def test__do_next_clean_step_automated_no_steps(self):
  958         self._do_next_clean_step_no_steps()
  959 
  960     def test__do_next_clean_step_manual_no_steps(self):
  961         self._do_next_clean_step_no_steps(manual=True)
  962 
  963     def test__do_next_clean_step_fast_track(self):
  964         self._do_next_clean_step_no_steps(fast_track=True)
  965 
  966     @mock.patch('ironic.drivers.modules.fake.FakePower.execute_clean_step',
  967                 autospec=True)
  968     @mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_clean_step',
  969                 autospec=True)
  970     def _do_next_clean_step_bad_step_return_value(
  971             self, deploy_exec_mock, power_exec_mock, manual=False):
  972         # When a clean step fails, go to CLEANFAIL
  973         tgt_prov_state = states.MANAGEABLE if manual else states.AVAILABLE
  974 
  975         node = obj_utils.create_test_node(
  976             self.context, driver='fake-hardware',
  977             provision_state=states.CLEANING,
  978             target_provision_state=tgt_prov_state,
  979             last_error=None,
  980             driver_internal_info={'clean_steps': self.clean_steps,
  981                                   'clean_step_index': None},
  982             clean_step={})
  983         deploy_exec_mock.return_value = "foo"
  984 
  985         with task_manager.acquire(
  986                 self.context, node.uuid, shared=False) as task:
  987             cleaning.do_next_clean_step(task, 0)
  988 
  989         node.refresh()
  990 
  991         # Make sure we go to CLEANFAIL, clear clean_steps
  992         self.assertEqual(states.CLEANFAIL, node.provision_state)
  993         self.assertEqual(tgt_prov_state, node.target_provision_state)
  994         self.assertEqual({}, node.clean_step)
  995         self.assertNotIn('clean_step_index', node.driver_internal_info)
  996         self.assertIsNotNone(node.last_error)
  997         self.assertTrue(node.maintenance)  # the 1st clean step was running
  998         deploy_exec_mock.assert_called_once_with(mock.ANY, mock.ANY,
  999                                                  self.clean_steps[0])
 1000         # Make sure we don't execute any other step and return
 1001         self.assertFalse(power_exec_mock.called)
 1002 
 1003     def test__do_next_clean_step_automated_bad_step_return_value(self):
 1004         self._do_next_clean_step_bad_step_return_value()
 1005 
 1006     def test__do_next_clean_step_manual_bad_step_return_value(self):
 1007         self._do_next_clean_step_bad_step_return_value(manual=True)
 1008 
 1009 
 1010 class DoNodeCleanAbortTestCase(db_base.DbTestCase):
 1011     @mock.patch.object(fake.FakeDeploy, 'tear_down_cleaning', autospec=True)
 1012     def _test__do_node_clean_abort(self, step_name, tear_mock):
 1013         node = obj_utils.create_test_node(
 1014             self.context, driver='fake-hardware',
 1015             provision_state=states.CLEANFAIL,
 1016             target_provision_state=states.AVAILABLE,
 1017             clean_step={'step': 'foo', 'abortable': True},
 1018             driver_internal_info={
 1019                 'agent_url': 'some url',
 1020                 'agent_secret_token': 'token',
 1021                 'clean_step_index': 2,
 1022                 'cleaning_reboot': True,
 1023                 'cleaning_polling': True,
 1024                 'skip_current_clean_step': True})
 1025 
 1026         with task_manager.acquire(self.context, node.uuid) as task:
 1027             cleaning.do_node_clean_abort(task, step_name=step_name)
 1028             self.assertIsNotNone(task.node.last_error)
 1029             tear_mock.assert_called_once_with(task.driver.deploy, task)
 1030             if step_name:
 1031                 self.assertIn(step_name, task.node.last_error)
 1032             # assert node's clean_step and metadata was cleaned up
 1033             self.assertEqual({}, task.node.clean_step)
 1034             self.assertNotIn('clean_step_index',
 1035                              task.node.driver_internal_info)
 1036             self.assertNotIn('cleaning_reboot',
 1037                              task.node.driver_internal_info)
 1038             self.assertNotIn('cleaning_polling',
 1039                              task.node.driver_internal_info)
 1040             self.assertNotIn('skip_current_clean_step',
 1041                              task.node.driver_internal_info)
 1042             self.assertNotIn('agent_url',
 1043                              task.node.driver_internal_info)
 1044             self.assertNotIn('agent_secret_token',
 1045                              task.node.driver_internal_info)
 1046 
 1047     def test__do_node_clean_abort(self):
 1048         self._test__do_node_clean_abort(None)
 1049 
 1050     def test__do_node_clean_abort_with_step_name(self):
 1051         self._test__do_node_clean_abort('foo')
 1052 
 1053     @mock.patch.object(fake.FakeDeploy, 'tear_down_cleaning', autospec=True)
 1054     def test__do_node_clean_abort_tear_down_fail(self, tear_mock):
 1055         tear_mock.side_effect = Exception('Surprise')
 1056 
 1057         node = obj_utils.create_test_node(
 1058             self.context, driver='fake-hardware',
 1059             provision_state=states.CLEANFAIL,
 1060             target_provision_state=states.AVAILABLE,
 1061             clean_step={'step': 'foo', 'abortable': True})
 1062 
 1063         with task_manager.acquire(self.context, node.uuid) as task:
 1064             cleaning.do_node_clean_abort(task)
 1065             tear_mock.assert_called_once_with(task.driver.deploy, task)
 1066             self.assertIsNotNone(task.node.last_error)
 1067             self.assertIsNotNone(task.node.maintenance_reason)
 1068             self.assertTrue(task.node.maintenance)
 1069             self.assertEqual('clean failure', task.node.fault)