summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2017-09-05 21:37:13 +0000
committerGerrit Code Review <review@openstack.org>2017-09-05 21:37:14 +0000
commitdfa2fb6dcd4e5030d5e1cac52ddbf43c9a181950 (patch)
tree70726393da5c2283a758987aa0c9b4addec41081
parentcefee3da4e77ffc5c3120d27d02b741c3b60ceab (diff)
parentf68f92a917bd50ea21bd000287b8dd8d829b7a01 (diff)
Merge "Fix DRAC classic driver double manage/provide" into stable/ocata7.0.3
-rw-r--r--ironic/drivers/drac.py4
-rw-r--r--ironic/drivers/fake.py3
-rw-r--r--ironic/drivers/modules/drac/deploy.py54
-rw-r--r--ironic/tests/unit/drivers/modules/drac/test_deploy.py101
-rw-r--r--ironic/tests/unit/drivers/test_drac.py108
-rw-r--r--releasenotes/notes/drac-fix-double-manage-provide-cycle-6ac8a427068f87fe.yaml8
6 files changed, 119 insertions, 159 deletions
diff --git a/ironic/drivers/drac.py b/ironic/drivers/drac.py
index 811a5da..ea0abb0 100644
--- a/ironic/drivers/drac.py
+++ b/ironic/drivers/drac.py
@@ -20,13 +20,13 @@ from oslo_utils import importutils
20from ironic.common import exception 20from ironic.common import exception
21from ironic.common.i18n import _ 21from ironic.common.i18n import _
22from ironic.drivers import base 22from ironic.drivers import base
23from ironic.drivers.modules.drac import deploy
24from ironic.drivers.modules.drac import inspect as drac_inspect 23from ironic.drivers.modules.drac import inspect as drac_inspect
25from ironic.drivers.modules.drac import management 24from ironic.drivers.modules.drac import management
26from ironic.drivers.modules.drac import power 25from ironic.drivers.modules.drac import power
27from ironic.drivers.modules.drac import raid 26from ironic.drivers.modules.drac import raid
28from ironic.drivers.modules.drac import vendor_passthru 27from ironic.drivers.modules.drac import vendor_passthru
29from ironic.drivers.modules import inspector 28from ironic.drivers.modules import inspector
29from ironic.drivers.modules import iscsi_deploy
30from ironic.drivers.modules import pxe 30from ironic.drivers.modules import pxe
31 31
32 32
@@ -41,7 +41,7 @@ class PXEDracDriver(base.BaseDriver):
41 41
42 self.power = power.DracPower() 42 self.power = power.DracPower()
43 self.boot = pxe.PXEBoot() 43 self.boot = pxe.PXEBoot()
44 self.deploy = deploy.DracDeploy() 44 self.deploy = iscsi_deploy.ISCSIDeploy()
45 self.management = management.DracManagement() 45 self.management = management.DracManagement()
46 self.raid = raid.DracRAID() 46 self.raid = raid.DracRAID()
47 self.vendor = vendor_passthru.DracVendorPassthru() 47 self.vendor = vendor_passthru.DracVendorPassthru()
diff --git a/ironic/drivers/fake.py b/ironic/drivers/fake.py
index e926aaa..df1b112 100644
--- a/ironic/drivers/fake.py
+++ b/ironic/drivers/fake.py
@@ -25,7 +25,6 @@ from ironic.drivers import base
25from ironic.drivers.modules import agent 25from ironic.drivers.modules import agent
26from ironic.drivers.modules.cimc import management as cimc_mgmt 26from ironic.drivers.modules.cimc import management as cimc_mgmt
27from ironic.drivers.modules.cimc import power as cimc_power 27from ironic.drivers.modules.cimc import power as cimc_power
28from ironic.drivers.modules.drac import deploy as drac_deploy
29from ironic.drivers.modules.drac import inspect as drac_inspect 28from ironic.drivers.modules.drac import inspect as drac_inspect
30from ironic.drivers.modules.drac import management as drac_mgmt 29from ironic.drivers.modules.drac import management as drac_mgmt
31from ironic.drivers.modules.drac import power as drac_power 30from ironic.drivers.modules.drac import power as drac_power
@@ -176,7 +175,7 @@ class FakeDracDriver(base.BaseDriver):
176 reason=_('Unable to import python-dracclient library')) 175 reason=_('Unable to import python-dracclient library'))
177 176
178 self.power = drac_power.DracPower() 177 self.power = drac_power.DracPower()
179 self.deploy = drac_deploy.DracDeploy() 178 self.deploy = iscsi_deploy.ISCSIDeploy()
180 self.management = drac_mgmt.DracManagement() 179 self.management = drac_mgmt.DracManagement()
181 self.raid = drac_raid.DracRAID() 180 self.raid = drac_raid.DracRAID()
182 self.vendor = drac_vendor.DracVendorPassthru() 181 self.vendor = drac_vendor.DracVendorPassthru()
diff --git a/ironic/drivers/modules/drac/deploy.py b/ironic/drivers/modules/drac/deploy.py
deleted file mode 100644
index 722fa94..0000000
--- a/ironic/drivers/modules/drac/deploy.py
+++ /dev/null
@@ -1,54 +0,0 @@
1#
2# Licensed under the Apache License, Version 2.0 (the "License"); you may
3# not use this file except in compliance with the License. You may obtain
4# a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11# License for the specific language governing permissions and limitations
12# under the License.
13
14"""
15DRAC deploy interface
16"""
17
18from ironic_lib import metrics_utils
19
20from ironic.drivers.modules import deploy_utils
21from ironic.drivers.modules import iscsi_deploy
22
23_OOB_CLEAN_STEPS = [
24 {'interface': 'raid', 'step': 'create_configuration'},
25 {'interface': 'raid', 'step': 'delete_configuration'}
26]
27
28METRICS = metrics_utils.get_metrics_logger(__name__)
29
30
31class DracDeploy(iscsi_deploy.ISCSIDeploy):
32
33 @METRICS.timer('DracDeploy.prepare_cleaning')
34 def prepare_cleaning(self, task):
35 """Prepare environment for cleaning
36
37 Boot into the agent to prepare for cleaning if in-band cleaning step
38 is requested.
39
40 :param task: a TaskManager instance containing the node to act on.
41 :returns: states.CLEANWAIT if there is any in-band clean step to
42 signify an asynchronous prepare.
43 """
44 node = task.node
45
46 inband_steps = [step for step
47 in node.driver_internal_info.get('clean_steps', [])
48 if {'interface': step['interface'],
49 'step': step['step']} not in _OOB_CLEAN_STEPS]
50
51 if ('agent_cached_clean_steps' not in node.driver_internal_info or
52 inband_steps):
53 return deploy_utils.prepare_inband_cleaning(task,
54 manage_boot=True)
diff --git a/ironic/tests/unit/drivers/modules/drac/test_deploy.py b/ironic/tests/unit/drivers/modules/drac/test_deploy.py
deleted file mode 100644
index 03bec35..0000000
--- a/ironic/tests/unit/drivers/modules/drac/test_deploy.py
+++ /dev/null
@@ -1,101 +0,0 @@
1#
2# Licensed under the Apache License, Version 2.0 (the "License"); you may
3# not use this file except in compliance with the License. You may obtain
4# a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11# License for the specific language governing permissions and limitations
12# under the License.
13
14"""
15Test class for DRAC deploy interface
16"""
17
18import mock
19
20from ironic.common import states
21from ironic.conductor import task_manager
22from ironic.drivers.modules import deploy_utils
23from ironic.tests.unit.conductor import mgr_utils
24from ironic.tests.unit.db import base as db_base
25from ironic.tests.unit.db import utils as db_utils
26from ironic.tests.unit.objects import utils as obj_utils
27
28INFO_DICT = db_utils.get_test_drac_info()
29
30
31class DracDeployTestCase(db_base.DbTestCase):
32
33 def setUp(self):
34 super(DracDeployTestCase, self).setUp()
35 mgr_utils.mock_the_extension_manager(driver='fake_drac')
36 self.node = obj_utils.create_test_node(self.context,
37 driver='fake_drac',
38 driver_info=INFO_DICT)
39
40 @mock.patch.object(deploy_utils, 'prepare_inband_cleaning', spec_set=True,
41 autospec=True)
42 def test_prepare_cleaning_with_no_clean_step(
43 self, mock_prepare_inband_cleaning):
44 mock_prepare_inband_cleaning.return_value = states.CLEANWAIT
45
46 with task_manager.acquire(self.context, self.node.uuid,
47 shared=False) as task:
48 res = task.driver.deploy.prepare_cleaning(task)
49 self.assertEqual(states.CLEANWAIT, res)
50
51 mock_prepare_inband_cleaning.assert_called_once_with(
52 task, manage_boot=True)
53
54 @mock.patch.object(deploy_utils, 'prepare_inband_cleaning', spec_set=True,
55 autospec=True)
56 def test_prepare_cleaning_with_inband_clean_step(
57 self, mock_prepare_inband_cleaning):
58 self.node.driver_internal_info['clean_steps'] = [
59 {'step': 'erase_disks', 'priority': 20, 'interface': 'deploy'}]
60 mock_prepare_inband_cleaning.return_value = states.CLEANWAIT
61
62 with task_manager.acquire(self.context, self.node.uuid,
63 shared=False) as task:
64 res = task.driver.deploy.prepare_cleaning(task)
65 self.assertEqual(states.CLEANWAIT, res)
66
67 mock_prepare_inband_cleaning.assert_called_once_with(
68 task, manage_boot=True)
69
70 @mock.patch.object(deploy_utils, 'prepare_inband_cleaning', spec_set=True,
71 autospec=True)
72 def test_prepare_cleaning_with_oob_clean_step_with_no_agent_cached_steps(
73 self, mock_prepare_inband_cleaning):
74 self.node.driver_internal_info['clean_steps'] = [
75 {'interface': 'raid', 'step': 'create_configuration'}]
76 mock_prepare_inband_cleaning.return_value = states.CLEANWAIT
77
78 with task_manager.acquire(self.context, self.node.uuid,
79 shared=False) as task:
80 res = task.driver.deploy.prepare_cleaning(task)
81 self.assertEqual(states.CLEANWAIT, res)
82
83 mock_prepare_inband_cleaning.assert_called_once_with(
84 task, manage_boot=True)
85
86 @mock.patch.object(deploy_utils, 'prepare_inband_cleaning', spec_set=True,
87 autospec=True)
88 def test_prepare_cleaning_with_oob_clean_step_with_agent_cached_steps(
89 self, mock_prepare_inband_cleaning):
90 self.node.driver_internal_info['agent_cached_clean_steps'] = []
91 self.node.driver_internal_info['clean_steps'] = [
92 {'interface': 'raid', 'step': 'create_configuration'}]
93 mock_prepare_inband_cleaning.return_value = states.CLEANWAIT
94
95 with task_manager.acquire(self.context, self.node.uuid,
96 shared=False) as task:
97 res = task.driver.deploy.prepare_cleaning(task)
98 self.assertEqual(states.CLEANWAIT, res)
99
100 mock_prepare_inband_cleaning.assert_called_once_with(
101 task, manage_boot=True)
diff --git a/ironic/tests/unit/drivers/test_drac.py b/ironic/tests/unit/drivers/test_drac.py
new file mode 100644
index 0000000..4d37947
--- /dev/null
+++ b/ironic/tests/unit/drivers/test_drac.py
@@ -0,0 +1,108 @@
1# Copyright (c) 2017 Dell Inc. or its subsidiaries.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import inspect
16
17import mock
18
19from oslo_utils import importutils
20
21from ironic.common import exception
22from ironic.drivers import drac as drac_drivers
23from ironic.drivers.modules import drac
24from ironic.drivers.modules import inspector
25from ironic.drivers.modules import iscsi_deploy
26from ironic.drivers.modules.network import flat as flat_net
27from ironic.drivers.modules import pxe
28from ironic.drivers.modules.storage import noop as noop_storage
29from ironic.tests.unit.db import base as db_base
30
31
32class BaseIDRACTestCase(db_base.DbTestCase):
33
34 def setUp(self):
35 super(BaseIDRACTestCase, self).setUp()
36
37 def _validate_interfaces(self, driver, **kwargs):
38 self.assertIsInstance(
39 driver.boot,
40 kwargs.get('boot', pxe.PXEBoot))
41 self.assertIsInstance(
42 driver.deploy,
43 kwargs.get('deploy', iscsi_deploy.ISCSIDeploy))
44 self.assertIsInstance(
45 driver.management,
46 kwargs.get('management', drac.management.DracManagement))
47 self.assertIsInstance(
48 driver.power,
49 kwargs.get('power', drac.power.DracPower))
50
51 # Console interface of iDRAC classic drivers is None.
52 console_interface = kwargs.get('console', None)
53
54 # None is not a class or type.
55 if inspect.isclass(console_interface):
56 self.assertIsInstance(driver.console, console_interface)
57 else:
58 self.assertIs(driver.console, console_interface)
59
60 self.assertIsInstance(
61 driver.inspect,
62 kwargs.get('inspect', drac.inspect.DracInspect))
63
64 # iDRAC classic drivers do not have a network interface.
65 if 'network' in driver.all_interfaces:
66 self.assertIsInstance(
67 driver.network,
68 kwargs.get('network', flat_net.FlatNetwork))
69
70 self.assertIsInstance(
71 driver.raid,
72 kwargs.get('raid', drac.raid.DracRAID))
73
74 # iDRAC classic drivers do not have a storage interface.
75 if 'storage' in driver.all_interfaces:
76 self.assertIsInstance(
77 driver.storage,
78 kwargs.get('storage', noop_storage.NoopStorage))
79
80 self.assertIsInstance(
81 driver.vendor,
82 kwargs.get('vendor', drac.vendor_passthru.DracVendorPassthru))
83
84
85@mock.patch.object(importutils, 'try_import', spec_set=True, autospec=True)
86class DracClassicDriversTestCase(BaseIDRACTestCase):
87
88 def setUp(self):
89 super(DracClassicDriversTestCase, self).setUp()
90
91 def test_pxe_drac_driver(self, mock_try_import):
92 mock_try_import.return_value = True
93
94 driver = drac_drivers.PXEDracDriver()
95 self._validate_interfaces(driver)
96
97 def test___init___try_import_dracclient_failure(self, mock_try_import):
98 mock_try_import.return_value = False
99
100 self.assertRaises(exception.DriverLoadError,
101 drac_drivers.PXEDracDriver)
102
103 def test_pxe_drac_inspector_driver(self, mock_try_import):
104 self.config(enabled=True, group='inspector')
105 mock_try_import.return_value = True
106
107 driver = drac_drivers.PXEDracInspectorDriver()
108 self._validate_interfaces(driver, inspect=inspector.Inspector)
diff --git a/releasenotes/notes/drac-fix-double-manage-provide-cycle-6ac8a427068f87fe.yaml b/releasenotes/notes/drac-fix-double-manage-provide-cycle-6ac8a427068f87fe.yaml
new file mode 100644
index 0000000..20d13f2
--- /dev/null
+++ b/releasenotes/notes/drac-fix-double-manage-provide-cycle-6ac8a427068f87fe.yaml
@@ -0,0 +1,8 @@
1---
2fixes:
3 - Fixes an issue that caused a node using a Dell EMC integrated Dell Remote
4 Access Controller (iDRAC) *classic driver*, ``pxe_drac`` or
5 ``pxe_drac_inspector``, to be placed in the ``clean failed`` state after a
6 double ``manage``/``provide`` cycle, instead of the ``available`` state.
7 For more information, see `bug 1676387
8 <https://bugs.launchpad.net/ironic/+bug/1676387>`_.