diff --git a/ironic/drivers/fake.py b/ironic/drivers/fake.py index f1ce9e1554..cc3953b382 100644 --- a/ironic/drivers/fake.py +++ b/ironic/drivers/fake.py @@ -27,6 +27,7 @@ from ironic.drivers.modules.amt import management as amt_mgmt from ironic.drivers.modules.amt import power as amt_power from ironic.drivers.modules.cimc import management as cimc_mgmt from ironic.drivers.modules.cimc import power as cimc_power +from ironic.drivers.modules.drac import deploy as drac_deploy from ironic.drivers.modules.drac import inspect as drac_inspect from ironic.drivers.modules.drac import management as drac_mgmt from ironic.drivers.modules.drac import power as drac_power @@ -200,7 +201,7 @@ class FakeDracDriver(base.BaseDriver): reason=_('Unable to import python-dracclient library')) self.power = drac_power.DracPower() - self.deploy = fake.FakeDeploy() + self.deploy = drac_deploy.DracDeploy() self.management = drac_mgmt.DracManagement() self.raid = drac_raid.DracRAID() self.vendor = drac_vendor.DracVendorPassthru() diff --git a/ironic/drivers/modules/drac/deploy.py b/ironic/drivers/modules/drac/deploy.py index 9c9b4d4742..eed3f14573 100644 --- a/ironic/drivers/modules/drac/deploy.py +++ b/ironic/drivers/modules/drac/deploy.py @@ -39,7 +39,7 @@ class DracDeploy(iscsi_deploy.ISCSIDeploy): node = task.node inband_steps = [step for step - in node.driver_internal_info['clean_steps'] + in node.driver_internal_info.get('clean_steps', []) if {'interface': step['interface'], 'step': step['step']} not in _OOB_CLEAN_STEPS] diff --git a/ironic/tests/unit/drivers/modules/drac/test_deploy.py b/ironic/tests/unit/drivers/modules/drac/test_deploy.py new file mode 100644 index 0000000000..03bec356e8 --- /dev/null +++ b/ironic/tests/unit/drivers/modules/drac/test_deploy.py @@ -0,0 +1,101 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +Test class for DRAC deploy interface +""" + +import mock + +from ironic.common import states +from ironic.conductor import task_manager +from ironic.drivers.modules import deploy_utils +from ironic.tests.unit.conductor import mgr_utils +from ironic.tests.unit.db import base as db_base +from ironic.tests.unit.db import utils as db_utils +from ironic.tests.unit.objects import utils as obj_utils + +INFO_DICT = db_utils.get_test_drac_info() + + +class DracDeployTestCase(db_base.DbTestCase): + + def setUp(self): + super(DracDeployTestCase, self).setUp() + mgr_utils.mock_the_extension_manager(driver='fake_drac') + self.node = obj_utils.create_test_node(self.context, + driver='fake_drac', + driver_info=INFO_DICT) + + @mock.patch.object(deploy_utils, 'prepare_inband_cleaning', spec_set=True, + autospec=True) + def test_prepare_cleaning_with_no_clean_step( + self, mock_prepare_inband_cleaning): + mock_prepare_inband_cleaning.return_value = states.CLEANWAIT + + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + res = task.driver.deploy.prepare_cleaning(task) + self.assertEqual(states.CLEANWAIT, res) + + mock_prepare_inband_cleaning.assert_called_once_with( + task, manage_boot=True) + + @mock.patch.object(deploy_utils, 'prepare_inband_cleaning', spec_set=True, + autospec=True) + def test_prepare_cleaning_with_inband_clean_step( + self, mock_prepare_inband_cleaning): + self.node.driver_internal_info['clean_steps'] = [ + {'step': 'erase_disks', 'priority': 20, 'interface': 'deploy'}] + mock_prepare_inband_cleaning.return_value = states.CLEANWAIT + + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + res = task.driver.deploy.prepare_cleaning(task) + self.assertEqual(states.CLEANWAIT, res) + + mock_prepare_inband_cleaning.assert_called_once_with( + task, manage_boot=True) + + @mock.patch.object(deploy_utils, 'prepare_inband_cleaning', spec_set=True, + autospec=True) + def test_prepare_cleaning_with_oob_clean_step_with_no_agent_cached_steps( + self, mock_prepare_inband_cleaning): + self.node.driver_internal_info['clean_steps'] = [ + {'interface': 'raid', 'step': 'create_configuration'}] + mock_prepare_inband_cleaning.return_value = states.CLEANWAIT + + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + res = task.driver.deploy.prepare_cleaning(task) + self.assertEqual(states.CLEANWAIT, res) + + mock_prepare_inband_cleaning.assert_called_once_with( + task, manage_boot=True) + + @mock.patch.object(deploy_utils, 'prepare_inband_cleaning', spec_set=True, + autospec=True) + def test_prepare_cleaning_with_oob_clean_step_with_agent_cached_steps( + self, mock_prepare_inband_cleaning): + self.node.driver_internal_info['agent_cached_clean_steps'] = [] + self.node.driver_internal_info['clean_steps'] = [ + {'interface': 'raid', 'step': 'create_configuration'}] + mock_prepare_inband_cleaning.return_value = states.CLEANWAIT + + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + res = task.driver.deploy.prepare_cleaning(task) + self.assertEqual(states.CLEANWAIT, res) + + mock_prepare_inband_cleaning.assert_called_once_with( + task, manage_boot=True) diff --git a/releasenotes/notes/drac-fix-prepare-cleaning-d74ba45135d84531.yaml b/releasenotes/notes/drac-fix-prepare-cleaning-d74ba45135d84531.yaml new file mode 100644 index 0000000000..15abcc0fc2 --- /dev/null +++ b/releasenotes/notes/drac-fix-prepare-cleaning-d74ba45135d84531.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - Fixes DRAC deploy interface failure when automated cleaning is called + without any clean step.