Add support for changing baremetal node's boot_mode and secure_boot states

depends-on: https://review.opendev.org/c/openstack/ironic/+/800084
Story: 2008567
Task: 41709
Change-Id: I941a84f36ce79c4cbd0968f4120c66d59091fdd9
This commit is contained in:
Cenne 2021-08-13 16:34:58 +02:00
parent 4d4eafa761
commit 116d875c04
5 changed files with 140 additions and 2 deletions

View File

@ -79,6 +79,9 @@ CONFIG_DRIVE_DICT_VERSION = '1.56'
DEPLOY_STEPS_VERSION = '1.69'
"""API version in which deploy_steps was added to node provisioning."""
CHANGE_BOOT_MODE_VERSION = '1.76'
"""API version in which boot_mode and secure_boot states can be changed"""
class ListMixin:

View File

@ -408,6 +408,27 @@ class Proxy(proxy.Proxy):
res = self._get_resource(_node.Node, node)
return res.set_boot_device(self, boot_device, persistent=persistent)
def set_node_boot_mode(self, node, target):
"""Make a request to change node's boot mode
:param node: The value can be the name or ID of a node or a
:class:`~openstack.baremetal.v1.node.Node` instance.
:param target: Boot mode to set for node, one of either 'uefi'/'bios'.
"""
res = self._get_resource(_node.Node, node)
return res.set_boot_mode(self, target)
def set_node_secure_boot(self, node, target):
"""Make a request to change node's secure boot state
:param node: The value can be the name or ID of a node or a
:class:`~openstack.baremetal.v1.node.Node` instance.
:param target: Boolean indicating secure boot state to set.
True/False corresponding to 'on'/'off' respectively.
"""
res = self._get_resource(_node.Node, node)
return res.set_secure_boot(self, target)
def wait_for_nodes_provision_state(self, nodes, expected_state,
timeout=None,
abort_on_failed_state=True,

View File

@ -91,8 +91,8 @@ class Node(_common.ListMixin, resource.Resource):
is_maintenance='maintenance',
)
# Node states boot_mode and secure_boot introduced in 1.75 (Xena).
_max_microversion = '1.75'
# Ability to change boot_mode and secure_boot, introduced in 1.76 (Xena).
_max_microversion = '1.76'
# Properties
#: The UUID of the allocation associated with this node. Added in API
@ -853,6 +853,67 @@ class Node(_common.ListMixin, resource.Resource):
.format(node=self.id))
exceptions.raise_from_response(response, error_message=msg)
def set_boot_mode(self, session, target):
"""Make a request to change node's boot mode
This call is asynchronous, it will return success as soon as the Bare
Metal service acknowledges the request.
:param session: The session to use for making this request.
:param target: Boot mode to set for node, one of either 'uefi'/'bios'.
:raises: ValueError if ``target`` is not one of 'uefi or 'bios'.
"""
session = self._get_session(session)
version = utils.pick_microversion(session,
_common.CHANGE_BOOT_MODE_VERSION)
request = self._prepare_request(requires_id=True)
request.url = utils.urljoin(request.url, 'states', 'boot_mode')
if target not in ('uefi', 'bios'):
raise ValueError("Unrecognized boot mode %s."
"Boot mode should be one of 'uefi' or 'bios'."
% target)
body = {'target': target}
response = session.put(
request.url, json=body,
headers=request.headers, microversion=version,
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
msg = ("Failed to change boot mode for node {node}"
.format(node=self.id))
exceptions.raise_from_response(response, error_message=msg)
def set_secure_boot(self, session, target):
"""Make a request to change node's secure boot state
This call is asynchronous, it will return success as soon as the Bare
Metal service acknowledges the request.
:param session: The session to use for making this request.
:param bool target: Boolean indicating secure boot state to set.
True/False corresponding to 'on'/'off' respectively.
:raises: ValueError if ``target`` is not boolean.
"""
session = self._get_session(session)
version = utils.pick_microversion(session,
_common.CHANGE_BOOT_MODE_VERSION)
request = self._prepare_request(requires_id=True)
request.url = utils.urljoin(request.url, 'states', 'secure_boot')
if not isinstance(target, bool):
raise ValueError("Invalid target %s. It should be True or False "
"corresponding to secure boot state 'on' or 'off'"
% target)
body = {'target': target}
response = session.put(
request.url, json=body,
headers=request.headers, microversion=version,
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
msg = ("Failed to change secure boot state for {node}"
.format(node=self.id))
exceptions.raise_from_response(response, error_message=msg)
def add_trait(self, session, trait):
"""Add a trait to a node.

View File

@ -764,6 +764,54 @@ class TestNodeSetBootDevice(base.TestCase):
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
@mock.patch.object(utils, 'pick_microversion', lambda session, v: v)
@mock.patch.object(node.Node, 'fetch', lambda self, session: self)
@mock.patch.object(exceptions, 'raise_from_response', mock.Mock())
class TestNodeSetBootMode(base.TestCase):
def setUp(self):
super(TestNodeSetBootMode, self).setUp()
self.node = node.Node(**FAKE)
self.session = mock.Mock(spec=adapter.Adapter,
default_microversion='1.1')
def test_node_set_boot_mode(self):
self.node.set_boot_mode(self.session, 'uefi')
self.session.put.assert_called_once_with(
'nodes/%s/states/boot_mode' % self.node.id,
json={'target': 'uefi'},
headers=mock.ANY, microversion=mock.ANY,
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
def test_node_set_boot_mode_invalid_mode(self):
self.assertRaises(ValueError,
self.node.set_boot_mode, self.session, 'invalid-efi')
@mock.patch.object(utils, 'pick_microversion', lambda session, v: v)
@mock.patch.object(node.Node, 'fetch', lambda self, session: self)
@mock.patch.object(exceptions, 'raise_from_response', mock.Mock())
class TestNodeSetSecureBoot(base.TestCase):
def setUp(self):
super(TestNodeSetSecureBoot, self).setUp()
self.node = node.Node(**FAKE)
self.session = mock.Mock(spec=adapter.Adapter,
default_microversion='1.1')
def test_node_set_secure_boot(self):
self.node.set_secure_boot(self.session, True)
self.session.put.assert_called_once_with(
'nodes/%s/states/secure_boot' % self.node.id,
json={'target': True},
headers=mock.ANY, microversion=mock.ANY,
retriable_status_codes=_common.RETRIABLE_STATUS_CODES)
def test_node_set_secure_boot_invalid_none(self):
self.assertRaises(ValueError,
self.node.set_secure_boot, self.session, None)
@mock.patch.object(utils, 'pick_microversion', lambda session, v: v)
@mock.patch.object(node.Node, 'fetch', lambda self, session: self)
@mock.patch.object(exceptions, 'raise_from_response', mock.Mock())

View File

@ -0,0 +1,5 @@
---
features:
- |
Add support for changing node states ``boot_mode`` and ``secure_boot``
in sync with functionality introduced in API 1.76.