summaryrefslogtreecommitdiff
path: root/ironic/tests/unit
diff options
context:
space:
mode:
authorIlya Etingof <etingof@gmail.com>2017-12-07 17:13:59 +0100
committerJulia Kreger <juliaashleykreger@gmail.com>2018-06-15 15:19:41 +0000
commit5e8f2e39d4f3508b2189dc09d6eecc9492c42f0c (patch)
tree840c898c5dbe2788f9fdcc4a3a8828374a05168a /ironic/tests/unit
parent643422b4d6d7db9dd062bd443a0b272d24c05f61 (diff)
downloadironic-5e8f2e39d4f3508b2189dc09d6eecc9492c42f0c.tar.gz
Adds boot mode support to ManagementInterface
This change introduces optional boot mode get/set methods to driver management interface [1] [2] alongside existing get/set boot device calls. The management interface is called at deploy time to synchronize BM machine boot mode setting with Ironic node configuration whenever needed. Also, this change introduces common exception class to be eventually used by the drivers to communicate their runtime errors to Ironic code in a uniformed way. 1. http://eavesdrop.openstack.org/irclogs/%23openstack-ironic/%23openstack-ironic.2018-01-09.log.html#t2018-01-09T15:54:16 2. http://eavesdrop.openstack.org/irclogs/%23openstack-ironic/%23openstack-ironic.2018-05-11.log.html#t2018-05-11T12:47:12 Story: 1734131 Task: 10640 Change-Id: If3db6ab8d3fae35d17808a231b7eecf11cf58327
Diffstat (limited to 'ironic/tests/unit')
-rw-r--r--ironic/tests/unit/conductor/test_utils.py72
-rw-r--r--ironic/tests/unit/drivers/modules/irmc/test_boot.py3
-rw-r--r--ironic/tests/unit/drivers/modules/test_pxe.py132
-rw-r--r--ironic/tests/unit/drivers/test_base.py21
-rw-r--r--ironic/tests/unit/drivers/test_fake_hardware.py8
5 files changed, 229 insertions, 7 deletions
diff --git a/ironic/tests/unit/conductor/test_utils.py b/ironic/tests/unit/conductor/test_utils.py
index c09db144d..428012e8a 100644
--- a/ironic/tests/unit/conductor/test_utils.py
+++ b/ironic/tests/unit/conductor/test_utils.py
@@ -14,6 +14,7 @@ import mock
from oslo_config import cfg
from oslo_utils import uuidutils
+from ironic.common import boot_modes
from ironic.common import exception
from ironic.common import network
from ironic.common import states
@@ -77,6 +78,77 @@ class NodeSetBootDeviceTestCase(db_base.DbTestCase):
self.assertFalse(mock_sbd.called)
+class NodeGetBootModeTestCase(db_base.DbTestCase):
+
+ def setUp(self):
+ super(NodeGetBootModeTestCase, self).setUp()
+ self.node = obj_utils.create_test_node(self.context,
+ uuid=uuidutils.generate_uuid())
+ self.task = task_manager.TaskManager(self.context, self.node.uuid)
+
+ @mock.patch.object(fake.FakeManagement, 'get_boot_mode', autospec=True)
+ def test_node_get_boot_mode_valid(self, mock_gbm):
+ mock_gbm.return_value = 'bios'
+ boot_mode = conductor_utils.node_get_boot_mode(self.task)
+ self.assertEqual(boot_mode, 'bios')
+ mock_gbm.assert_called_once_with(mock.ANY, self.task)
+
+ @mock.patch.object(fake.FakeManagement, 'get_boot_mode', autospec=True)
+ def test_node_get_boot_mode_unsupported(self, mock_gbm):
+ mock_gbm.side_effect = exception.UnsupportedDriverExtension(
+ driver=self.task.node.driver, extension='get_boot_mode')
+ self.assertRaises(exception.UnsupportedDriverExtension,
+ conductor_utils.node_get_boot_mode, self.task)
+
+
+class NodeSetBootModeTestCase(db_base.DbTestCase):
+
+ def setUp(self):
+ super(NodeSetBootModeTestCase, self).setUp()
+ self.node = obj_utils.create_test_node(self.context,
+ uuid=uuidutils.generate_uuid())
+ self.task = task_manager.TaskManager(self.context, self.node.uuid)
+
+ @mock.patch.object(fake.FakeManagement, 'get_supported_boot_modes',
+ autospec=True)
+ def test_node_set_boot_mode_non_existent_mode(self, mock_gsbm):
+
+ mock_gsbm.return_value = [boot_modes.LEGACY_BIOS]
+
+ self.assertRaises(exception.InvalidParameterValue,
+ conductor_utils.node_set_boot_mode,
+ self.task,
+ mode='non-existing')
+
+ @mock.patch.object(fake.FakeManagement, 'set_boot_mode', autospec=True)
+ @mock.patch.object(fake.FakeManagement, 'get_supported_boot_modes',
+ autospec=True)
+ def test_node_set_boot_mode_valid(self, mock_gsbm, mock_sbm):
+ mock_gsbm.return_value = [boot_modes.LEGACY_BIOS]
+
+ conductor_utils.node_set_boot_mode(self.task,
+ mode=boot_modes.LEGACY_BIOS)
+ mock_sbm.assert_called_once_with(mock.ANY, self.task,
+ mode=boot_modes.LEGACY_BIOS)
+
+ @mock.patch.object(fake.FakeManagement, 'set_boot_mode', autospec=True)
+ @mock.patch.object(fake.FakeManagement, 'get_supported_boot_modes',
+ autospec=True)
+ def test_node_set_boot_mode_adopting(self, mock_gsbm, mock_sbm):
+ mock_gsbm.return_value = [boot_modes.LEGACY_BIOS]
+
+ old_provision_state = self.task.node.provision_state
+ self.task.node.provision_state = states.ADOPTING
+ try:
+ conductor_utils.node_set_boot_mode(self.task,
+ mode=boot_modes.LEGACY_BIOS)
+
+ finally:
+ self.task.node.provision_state = old_provision_state
+
+ self.assertFalse(mock_sbm.called)
+
+
class NodePowerActionTestCase(db_base.DbTestCase):
@mock.patch.object(fake.FakePower, 'get_power_state', autospec=True)
def test_node_power_action_power_on(self, get_power_mock):
diff --git a/ironic/tests/unit/drivers/modules/irmc/test_boot.py b/ironic/tests/unit/drivers/modules/irmc/test_boot.py
index 284655b77..138262482 100644
--- a/ironic/tests/unit/drivers/modules/irmc/test_boot.py
+++ b/ironic/tests/unit/drivers/modules/irmc/test_boot.py
@@ -1905,6 +1905,9 @@ class IRMCPXEBootBasicTestCase(test_pxe.PXEBootTestCase):
driver = 'pxe_irmc'
boot_interface = None
+ # NOTE(etingof): add driver-specific configuration
+ driver_info = dict(test_pxe.PXEBootTestCase.driver_info)
+ driver_info.update(PARSED_IFNO)
def test_get_properties(self):
with task_manager.acquire(self.context, self.node.uuid,
diff --git a/ironic/tests/unit/drivers/modules/test_pxe.py b/ironic/tests/unit/drivers/modules/test_pxe.py
index ba14c04d2..b82de3d0f 100644
--- a/ironic/tests/unit/drivers/modules/test_pxe.py
+++ b/ironic/tests/unit/drivers/modules/test_pxe.py
@@ -26,6 +26,7 @@ from oslo_utils import fileutils
from oslo_utils import uuidutils
from ironic.common import boot_devices
+from ironic.common import boot_modes
from ironic.common import dhcp_factory
from ironic.common import exception
from ironic.common.glance_service import base_image_service
@@ -752,6 +753,8 @@ class PXEBootTestCase(db_base.DbTestCase):
driver = 'fake-hardware'
boot_interface = 'pxe'
+ driver_info = DRV_INFO_DICT
+ driver_internal_info = DRV_INTERNAL_INFO_DICT
def setUp(self):
super(PXEBootTestCase, self).setUp()
@@ -776,8 +779,8 @@ class PXEBootTestCase(db_base.DbTestCase):
vendor_interface=('no-vendor' if self.driver == 'fake-hardware'
else None),
instance_info=instance_info,
- driver_info=DRV_INFO_DICT,
- driver_internal_info=DRV_INTERNAL_INFO_DICT)
+ driver_info=self.driver_info,
+ driver_internal_info=self.driver_internal_info)
self.port = obj_utils.create_test_port(self.context,
node_id=self.node.id)
self.config(group='conductor', api_url='http://127.0.0.1:1234/')
@@ -908,6 +911,7 @@ class PXEBootTestCase(db_base.DbTestCase):
self.assertRaises(exception.InvalidParameterValue,
task.driver.boot.validate, task)
+ @mock.patch.object(manager_utils, 'node_get_boot_mode', autospec=True)
@mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True)
@mock.patch.object(dhcp_factory, 'DHCPFactory')
@mock.patch.object(pxe, '_get_instance_image_info', autospec=True)
@@ -921,11 +925,13 @@ class PXEBootTestCase(db_base.DbTestCase):
mock_instance_img_info,
dhcp_factory_mock,
set_boot_device_mock,
+ get_boot_mode_mock,
uefi=False,
cleaning=False,
ipxe_use_swift=False,
whole_disk_image=False,
- mode='deploy'):
+ mode='deploy',
+ node_boot_mode=None):
mock_build_pxe.return_value = {}
kernel_label = '%s_kernel' % mode
ramdisk_label = '%s_ramdisk' % mode
@@ -939,6 +945,7 @@ class PXEBootTestCase(db_base.DbTestCase):
mock_cache_r_k.return_value = None
provider_mock = mock.MagicMock()
dhcp_factory_mock.return_value = provider_mock
+ get_boot_mode_mock.return_value = node_boot_mode
driver_internal_info = self.node.driver_internal_info
driver_internal_info['is_whole_disk_image'] = whole_disk_image
self.node.driver_internal_info = driver_internal_info
@@ -952,6 +959,8 @@ class PXEBootTestCase(db_base.DbTestCase):
task.driver.boot.prepare_ramdisk(task, {'foo': 'bar'})
mock_deploy_img_info.assert_called_once_with(task.node, mode=mode)
provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts)
+ if self.node.provision_state == states.DEPLOYING:
+ get_boot_mode_mock.assert_called_once_with(task)
set_boot_device_mock.assert_called_once_with(task,
boot_devices.PXE,
persistent=False)
@@ -1097,6 +1106,104 @@ class PXEBootTestCase(db_base.DbTestCase):
self.node.save()
self._test_prepare_ramdisk(cleaning=True)
+ @mock.patch.object(manager_utils, 'node_set_boot_mode', autospec=True)
+ def test_prepare_ramdisk_set_boot_mode_on_bm(
+ self, set_boot_mode_mock):
+ self.node.provision_state = states.DEPLOYING
+ properties = self.node.properties
+ properties['capabilities'] = 'boot_mode:uefi'
+ self.node.properties = properties
+ self.node.save()
+ self._test_prepare_ramdisk(uefi=True)
+ set_boot_mode_mock.assert_called_once_with(mock.ANY, boot_modes.UEFI)
+
+ @mock.patch.object(manager_utils, 'node_set_boot_mode', autospec=True)
+ def test_prepare_ramdisk_set_boot_mode_on_ironic(
+ self, set_boot_mode_mock):
+ self.node.provision_state = states.DEPLOYING
+ self.node.save()
+ self._test_prepare_ramdisk(node_boot_mode=boot_modes.LEGACY_BIOS)
+
+ with task_manager.acquire(self.context, self.node.uuid) as task:
+ driver_internal_info = task.node.driver_internal_info
+ self.assertIn('deploy_boot_mode', driver_internal_info)
+ self.assertEqual(boot_modes.LEGACY_BIOS,
+ driver_internal_info['deploy_boot_mode'])
+ self.assertEqual(set_boot_mode_mock.call_count, 0)
+
+ @mock.patch.object(manager_utils, 'node_set_boot_mode', autospec=True)
+ def test_prepare_ramdisk_set_default_boot_mode_on_ironic_bios(
+ self, set_boot_mode_mock):
+ self.node.provision_state = states.DEPLOYING
+ self.node.save()
+
+ self.config(default_boot_mode=boot_modes.LEGACY_BIOS, group='deploy')
+
+ self._test_prepare_ramdisk()
+
+ with task_manager.acquire(self.context, self.node.uuid) as task:
+ driver_internal_info = task.node.driver_internal_info
+ self.assertIn('deploy_boot_mode', driver_internal_info)
+ self.assertEqual(boot_modes.LEGACY_BIOS,
+ driver_internal_info['deploy_boot_mode'])
+ self.assertEqual(set_boot_mode_mock.call_count, 1)
+
+ @mock.patch.object(manager_utils, 'node_set_boot_mode', autospec=True)
+ def test_prepare_ramdisk_set_default_boot_mode_on_ironic_uefi(
+ self, set_boot_mode_mock):
+ self.node.provision_state = states.DEPLOYING
+ self.node.save()
+
+ self.config(default_boot_mode=boot_modes.UEFI, group='deploy')
+
+ self._test_prepare_ramdisk(uefi=True)
+
+ with task_manager.acquire(self.context, self.node.uuid) as task:
+ driver_internal_info = task.node.driver_internal_info
+ self.assertIn('deploy_boot_mode', driver_internal_info)
+ self.assertEqual(boot_modes.UEFI,
+ driver_internal_info['deploy_boot_mode'])
+ self.assertEqual(set_boot_mode_mock.call_count, 1)
+
+ @mock.patch.object(manager_utils, 'node_set_boot_mode', autospec=True)
+ def test_prepare_ramdisk_conflicting_boot_modes(
+ self, set_boot_mode_mock):
+ self.node.provision_state = states.DEPLOYING
+ properties = self.node.properties
+ properties['capabilities'] = 'boot_mode:uefi'
+ self.node.properties = properties
+ self.node.save()
+ self._test_prepare_ramdisk(uefi=True,
+ node_boot_mode=boot_modes.LEGACY_BIOS)
+ set_boot_mode_mock.assert_called_once_with(mock.ANY, boot_modes.UEFI)
+
+ @mock.patch.object(manager_utils, 'node_set_boot_mode', autospec=True)
+ def test_prepare_ramdisk_conflicting_boot_modes_set_unsupported(
+ self, set_boot_mode_mock):
+ self.node.provision_state = states.DEPLOYING
+ properties = self.node.properties
+ properties['capabilities'] = 'boot_mode:uefi'
+ self.node.properties = properties
+ self.node.save()
+ set_boot_mode_mock.side_effect = exception.UnsupportedDriverExtension(
+ extension='management', driver='test-driver'
+ )
+ self.assertRaises(exception.UnsupportedDriverExtension,
+ self._test_prepare_ramdisk,
+ uefi=True, node_boot_mode=boot_modes.LEGACY_BIOS)
+
+ @mock.patch.object(manager_utils, 'node_set_boot_mode', autospec=True)
+ def test_prepare_ramdisk_set_boot_mode_not_called(
+ self, set_boot_mode_mock):
+ self.node.provision_state = states.DEPLOYING
+ self.node.save()
+ properties = self.node.properties
+ properties['capabilities'] = 'boot_mode:uefi'
+ self.node.properties = properties
+ self.node.save()
+ self._test_prepare_ramdisk(uefi=True, node_boot_mode=boot_modes.UEFI)
+ self.assertEqual(set_boot_mode_mock.call_count, 0)
+
@mock.patch.object(pxe, '_clean_up_pxe_env', autospec=True)
@mock.patch.object(pxe, '_get_image_info', autospec=True)
def _test_clean_up_ramdisk(self, get_image_info_mock,
@@ -1290,6 +1397,7 @@ class PXEBootTestCase(db_base.DbTestCase):
dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
pxe_config_path = pxe_utils.get_pxe_config_file_path(
task.node.uuid)
+ task.node.properties['capabilities'] = 'boot_mode:bios'
task.driver.boot.prepare_instance(task)
self.assertFalse(get_image_info_mock.called)
self.assertFalse(cache_mock.called)
@@ -1297,7 +1405,8 @@ class PXEBootTestCase(db_base.DbTestCase):
create_pxe_config_mock.assert_called_once_with(
task, mock.ANY, CONF.pxe.pxe_config_template)
switch_pxe_config_mock.assert_called_once_with(
- pxe_config_path, None, None, False, iscsi_boot=True)
+ pxe_config_path, None, boot_modes.LEGACY_BIOS, False,
+ iscsi_boot=True)
set_boot_device_mock.assert_called_once_with(task,
boot_devices.PXE,
persistent=True)
@@ -1307,7 +1416,10 @@ class PXEBootTestCase(db_base.DbTestCase):
def test_prepare_instance_localboot(self, clean_up_pxe_config_mock,
set_boot_device_mock):
with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node.instance_info['capabilities'] = {'boot_option': 'local'}
+ instance_info = task.node.instance_info
+ instance_info['capabilities'] = {'boot_option': 'local'}
+ task.node.instance_info = instance_info
+ task.node.save()
task.driver.boot.prepare_instance(task)
clean_up_pxe_config_mock.assert_called_once_with(task)
set_boot_device_mock.assert_called_once_with(task,
@@ -1319,7 +1431,10 @@ class PXEBootTestCase(db_base.DbTestCase):
def test_is_force_persistent_boot_device_enabled(
self, clean_up_pxe_config_mock, set_boot_device_mock):
with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node.instance_info['capabilities'] = {'boot_option': 'local'}
+ instance_info = task.node.instance_info
+ instance_info['capabilities'] = {'boot_option': 'local'}
+ task.node.instance_info = instance_info
+ task.node.save()
task.driver.boot.prepare_instance(task)
clean_up_pxe_config_mock.assert_called_once_with(task)
driver_info = task.node.driver_info
@@ -1336,7 +1451,10 @@ class PXEBootTestCase(db_base.DbTestCase):
self.node.provision_state = states.ACTIVE
self.node.save()
with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node.instance_info['capabilities'] = {'boot_option': 'local'}
+ instance_info = task.node.instance_info
+ instance_info['capabilities'] = {'boot_option': 'local'}
+ task.node.instance_info = instance_info
+ task.node.save()
task.driver.boot.prepare_instance(task)
clean_up_pxe_config_mock.assert_called_once_with(task)
self.assertFalse(set_boot_device_mock.called)
diff --git a/ironic/tests/unit/drivers/test_base.py b/ironic/tests/unit/drivers/test_base.py
index 49a40f2c4..015ba8e21 100644
--- a/ironic/tests/unit/drivers/test_base.py
+++ b/ironic/tests/unit/drivers/test_base.py
@@ -478,6 +478,27 @@ class TestManagementInterface(base.TestCase):
self.assertRaises(exception.UnsupportedDriverExtension,
management.inject_nmi, task_mock)
+ def test_get_supported_boot_modes_default_impl(self):
+ management = fake.FakeManagement()
+ task_mock = mock.MagicMock(spec_set=['node'])
+
+ self.assertRaises(exception.UnsupportedDriverExtension,
+ management.get_supported_boot_modes, task_mock)
+
+ def test_set_boot_mode_default_impl(self):
+ management = fake.FakeManagement()
+ task_mock = mock.MagicMock(spec_set=['node'])
+
+ self.assertRaises(exception.UnsupportedDriverExtension,
+ management.set_boot_mode, task_mock, 'whatever')
+
+ def test_get_boot_mode_default_impl(self):
+ management = fake.FakeManagement()
+ task_mock = mock.MagicMock(spec_set=['node'])
+
+ self.assertRaises(exception.UnsupportedDriverExtension,
+ management.get_boot_mode, task_mock)
+
class TestBaseDriver(base.TestCase):
diff --git a/ironic/tests/unit/drivers/test_fake_hardware.py b/ironic/tests/unit/drivers/test_fake_hardware.py
index 7091db4a5..792940de0 100644
--- a/ironic/tests/unit/drivers/test_fake_hardware.py
+++ b/ironic/tests/unit/drivers/test_fake_hardware.py
@@ -19,6 +19,7 @@
from ironic.common import boot_devices
+from ironic.common import boot_modes
from ironic.common import exception
from ironic.common import states
from ironic.conductor import task_manager
@@ -111,6 +112,13 @@ class FakeHardwareTestCase(db_base.DbTestCase):
self.assertEqual(expected,
self.driver.management.get_boot_device(self.task))
+ def test_management_interface_set_boot_mode_good(self):
+ self.assertRaises(
+ exception.UnsupportedDriverExtension,
+ self.driver.management.set_boot_mode,
+ self.task, boot_modes.LEGACY_BIOS
+ )
+
def test_inspect_interface(self):
self.assertEqual({}, self.driver.inspect.get_properties())
self.driver.inspect.validate(self.task)