Adds boot mode support to iLO management interface

This change adds 'get_boot_mode', 'set_boot_mode' and
'get_supported_boot_modes' methods to driver management interface of 'ilo'
and 'ilo5' hardware types.

Story: 2007827
Task: 40104
Change-Id: I34701b790ba91431b0b943ae8060a43d7ea9abbb
This commit is contained in:
Shivanand Tendulker 2020-06-17 11:19:36 -04:00
parent 1c0a9c8c28
commit e43aee3db8
5 changed files with 194 additions and 0 deletions

View File

@ -116,6 +116,15 @@ POST_INPOSTDISCOVERY_STATE = "InPostDiscoveryComplete"
POST_FINISHEDPOST_STATE = "FinishedPost"
""" Node is in FinishedPost post state."""
SUPPORTED_BOOT_MODE_LEGACY_BIOS_ONLY = 'legacy bios only'
""" Node supports only legacy BIOS boot mode."""
SUPPORTED_BOOT_MODE_UEFI_ONLY = 'uefi only'
""" Node supports only UEFI boot mode."""
SUPPORTED_BOOT_MODE_LEGACY_BIOS_AND_UEFI = 'legacy bios and uefi'
""" Node supports both legacy BIOS and UEFI boot mode."""
def copy_image_to_web_server(source_file_path, destination):
"""Copies the given image to the http web server.
@ -492,6 +501,24 @@ def set_boot_mode(node, boot_mode):
{'uuid': node.uuid, 'boot_mode': boot_mode})
def get_current_boot_mode(node):
"""Get the current boot mode for a node.
:param node: an ironic node object.
:raises: IloOperationError if failed to fetch boot mode.
:raises: IloOperationNotSupported if node does not support getting pending
boot mode.
"""
ilo_object = get_ilo_object(node)
operation = _("Get current boot mode")
try:
c_boot_mode = ilo_object.get_current_boot_mode()
return BOOT_MODE_ILO_TO_GENERIC[c_boot_mode.lower()]
except ilo_error.IloError as ilo_exception:
raise exception.IloOperationError(operation=operation,
error=ilo_exception)
def update_boot_mode(task):
"""Update instance_info with boot mode to be used for deploy.

View File

@ -24,6 +24,7 @@ from oslo_utils import excutils
from oslo_utils import importutils
from ironic.common import boot_devices
from ironic.common import boot_modes
from ironic.common import exception
from ironic.common.i18n import _
from ironic.common import states
@ -684,6 +685,59 @@ class IloManagement(base.ManagementInterface):
raise exception.IloOperationError(operation=operation,
error=ilo_exception)
def get_supported_boot_modes(self, task):
"""Get a list of the supported boot devices.
:param task: a task from TaskManager.
:raises: IloOperationError if any exception happens in proliantutils
:returns: A list with the supported boot devices defined
in :mod:`ironic.common.boot_devices`.
"""
node = task.node
ilo_object = ilo_common.get_ilo_object(node)
try:
modes = ilo_object.get_supported_boot_mode()
if modes == ilo_common.SUPPORTED_BOOT_MODE_LEGACY_BIOS_ONLY:
return [boot_modes.LEGACY_BIOS]
elif modes == ilo_common.SUPPORTED_BOOT_MODE_UEFI_ONLY:
return [boot_modes.UEFI]
elif modes == ilo_common.SUPPORTED_BOOT_MODE_LEGACY_BIOS_AND_UEFI:
return [boot_modes.UEFI, boot_modes.LEGACY_BIOS]
except ilo_error.IloError as ilo_exception:
operation = _("Get supported boot modes")
raise exception.IloOperationError(operation=operation,
error=ilo_exception)
@task_manager.require_exclusive_lock
def set_boot_mode(self, task, mode):
"""Set the boot mode for a node.
Set the boot mode to use on next reboot of the node.
:param task: A task from TaskManager.
:param mode: The boot mode, one of
:mod:`ironic.common.boot_modes`.
:raises: InvalidParameterValue if an invalid boot mode is
specified.
:raises: IloOperationError if setting boot mode failed.
"""
if mode not in self.get_supported_boot_modes(task):
raise exception.InvalidParameterValue(_(
"The given boot mode '%s' is not supported.") % mode)
ilo_common.set_boot_mode(task.node, mode)
def get_boot_mode(self, task):
"""Get the current boot mode for a node.
Provides the current boot mode of the node.
:param task: A task from TaskManager.
:raises: IloOperationError on an error from IloClient library.
:returns: The boot mode, one of :mod:`ironic.common.boot_mode` or
None if it is unknown.
"""
return ilo_common.get_current_boot_mode(task.node)
class Ilo5Management(IloManagement):

View File

@ -436,6 +436,29 @@ class IloCommonMethodsTestCase(BaseIloTest):
get_ilo_object_mock.assert_called_once_with(self.node)
get_pending_boot_mode_mock.assert_called_once_with()
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test_get_current_boot_mode(self, get_ilo_object_mock):
ilo_object_mock = get_ilo_object_mock.return_value
get_current_boot_mode_mock = ilo_object_mock.get_current_boot_mode
get_current_boot_mode_mock.return_value = 'LEGACY'
ret = ilo_common.get_current_boot_mode(self.node)
self.assertEqual('bios', ret)
get_ilo_object_mock.assert_called_once_with(self.node)
get_current_boot_mode_mock.assert_called_once_with()
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test_get_current_boot_mode_fail(self, get_ilo_object_mock):
ilo_object_mock = get_ilo_object_mock.return_value
get_current_boot_mode_mock = ilo_object_mock.get_current_boot_mode
exc = ilo_error.IloError('error')
get_current_boot_mode_mock.side_effect = exc
self.assertRaises(exception.IloOperationError,
ilo_common.get_current_boot_mode, self.node)
get_ilo_object_mock.assert_called_once_with(self.node)
get_current_boot_mode_mock.assert_called_once_with()
@mock.patch.object(ilo_common, 'set_boot_mode', spec_set=True,
autospec=True)
def test_update_boot_mode_instance_info_exists(self,

View File

@ -16,10 +16,12 @@
from unittest import mock
import ddt
from oslo_utils import importutils
from oslo_utils import uuidutils
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
@ -41,6 +43,7 @@ ilo_error = importutils.try_import('proliantutils.exception')
INFO_DICT = db_utils.get_test_ilo_info()
@ddt.ddt
class IloManagementTestCase(test_common.BaseIloTest):
def setUp(self):
@ -1181,6 +1184,88 @@ class IloManagementTestCase(test_common.BaseIloTest):
task.driver.management.inject_nmi,
task)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
@ddt.data((ilo_common.SUPPORTED_BOOT_MODE_LEGACY_BIOS_ONLY,
['bios']),
(ilo_common.SUPPORTED_BOOT_MODE_UEFI_ONLY,
['uefi']),
(ilo_common.SUPPORTED_BOOT_MODE_LEGACY_BIOS_AND_UEFI,
['uefi', 'bios']))
@ddt.unpack
def test_get_supported_boot_modes(self, boot_modes_val,
exp_boot_modes,
get_ilo_object_mock):
ilo_object_mock = get_ilo_object_mock.return_value
ilo_object_mock.get_supported_boot_mode.return_value = boot_modes_val
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
supported_boot_modes = (
task.driver.management.get_supported_boot_modes(task))
self.assertEqual(exp_boot_modes, supported_boot_modes)
@mock.patch.object(ilo_common, 'set_boot_mode', spec_set=True,
autospec=True)
@mock.patch.object(ilo_management.IloManagement,
'get_supported_boot_modes',
spec_set=True, autospec=True)
def test_set_boot_mode(self, supp_boot_modes_mock,
set_boot_mode_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
exp_boot_modes = [boot_modes.UEFI, boot_modes.LEGACY_BIOS]
supp_boot_modes_mock.return_value = exp_boot_modes
for mode in exp_boot_modes:
task.driver.management.set_boot_mode(task, mode=mode)
supp_boot_modes_mock.assert_called_once_with(mock.ANY, task)
set_boot_mode_mock.assert_called_once_with(task.node, mode)
set_boot_mode_mock.reset_mock()
supp_boot_modes_mock.reset_mock()
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
@mock.patch.object(ilo_management.IloManagement,
'get_supported_boot_modes',
spec_set=True, autospec=True)
def test_set_boot_mode_fail(self, supp_boot_modes_mock,
get_ilo_object_mock):
ilo_mock_obj = get_ilo_object_mock.return_value
ilo_mock_obj.get_pending_boot_mode.return_value = 'legacy'
exc = ilo_error.IloError('error')
ilo_mock_obj.set_pending_boot_mode.side_effect = exc
exp_boot_modes = [boot_modes.UEFI, boot_modes.LEGACY_BIOS]
supp_boot_modes_mock.return_value = exp_boot_modes
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
self.assertRaisesRegex(
exception.IloOperationError, 'uefi as boot mode failed',
task.driver.management.set_boot_mode, task, boot_modes.UEFI)
supp_boot_modes_mock.assert_called_once_with(mock.ANY, task)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test_get_boot_mode(self, get_ilo_object_mock):
expected = 'bios'
ilo_mock_obj = get_ilo_object_mock.return_value
ilo_mock_obj.get_current_boot_mode.return_value = 'LEGACY'
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
response = task.driver.management.get_boot_mode(task)
self.assertEqual(expected, response)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test_get_boot_mode_fail(self, get_ilo_object_mock):
ilo_mock_obj = get_ilo_object_mock.return_value
exc = ilo_error.IloError('error')
ilo_mock_obj.get_current_boot_mode.side_effect = exc
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertRaisesRegex(
exception.IloOperationError, 'Get current boot mode',
task.driver.management.get_boot_mode, task)
class Ilo5ManagementTestCase(db_base.DbTestCase):

View File

@ -0,0 +1,5 @@
---
features:
- |
Adds support for boot mode retrieval and setting with the ``ilo`` and
``ilo5`` hardware types.