Add support for changing 'boot_mode' and 'secure_boot' states
Story: 2008567 Task: 41709 depends-on: https://review.opendev.org/c/openstack/ironic/+/800084 Change-Id: I2937ea924ccc4ca6e9ab5599aa02e3c078c166b3
This commit is contained in:
parent
a5a3d4e442
commit
00808631c1
@ -37,7 +37,7 @@ from ironicclient import exc
|
|||||||
# http://specs.openstack.org/openstack/ironic-specs/specs/kilo/api-microversions.html # noqa
|
# http://specs.openstack.org/openstack/ironic-specs/specs/kilo/api-microversions.html # noqa
|
||||||
# for full details.
|
# for full details.
|
||||||
DEFAULT_VER = '1.9'
|
DEFAULT_VER = '1.9'
|
||||||
LAST_KNOWN_API_VERSION = 75
|
LAST_KNOWN_API_VERSION = 76
|
||||||
LATEST_VERSION = '1.{}'.format(LAST_KNOWN_API_VERSION)
|
LATEST_VERSION = '1.{}'.format(LAST_KNOWN_API_VERSION)
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
@ -242,6 +242,38 @@ class BootdeviceShowBaremetalNode(command.ShowOne):
|
|||||||
return zip(*sorted(info.items()))
|
return zip(*sorted(info.items()))
|
||||||
|
|
||||||
|
|
||||||
|
class BootmodeSetBaremetalNode(command.Command):
|
||||||
|
"""Set boot mode for baremetal node"""
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__ + ".BootmodeSetBaremetalNode")
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(BootmodeSetBaremetalNode, self).get_parser(prog_name)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'node',
|
||||||
|
metavar='<node>',
|
||||||
|
help=_("Name or UUID of the node.")
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'boot_mode',
|
||||||
|
choices=['uefi', 'bios'],
|
||||||
|
metavar='<boot_mode>',
|
||||||
|
help=_('The boot mode to set for node (uefi/bios)')
|
||||||
|
)
|
||||||
|
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
self.log.debug("take_action(%s)", parsed_args)
|
||||||
|
|
||||||
|
baremetal_client = self.app.client_manager.baremetal
|
||||||
|
|
||||||
|
baremetal_client.node.set_boot_mode(
|
||||||
|
parsed_args.node,
|
||||||
|
parsed_args.boot_mode)
|
||||||
|
|
||||||
|
|
||||||
class CleanBaremetalNode(ProvisionStateWithWait):
|
class CleanBaremetalNode(ProvisionStateWithWait):
|
||||||
"""Set provision state of baremetal node to 'clean'"""
|
"""Set provision state of baremetal node to 'clean'"""
|
||||||
|
|
||||||
@ -1086,6 +1118,50 @@ class RescueBaremetalNode(ProvisionStateWithWait):
|
|||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
class SecurebootOnBaremetalNode(command.Command):
|
||||||
|
"""Turn secure boot on"""
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__ + ".SecurebootOnBaremetalNode")
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(SecurebootOnBaremetalNode, self).get_parser(prog_name)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'node',
|
||||||
|
metavar='<node>',
|
||||||
|
help=_("Name or UUID of the node")
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
self.log.debug("take_action(%s)", parsed_args)
|
||||||
|
|
||||||
|
baremetal_client = self.app.client_manager.baremetal
|
||||||
|
baremetal_client.node.set_secure_boot(parsed_args.node, 'on')
|
||||||
|
|
||||||
|
|
||||||
|
class SecurebootOffBaremetalNode(command.Command):
|
||||||
|
"""Turn secure boot off"""
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__ + ".SecurebootOffBaremetalNode")
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(SecurebootOffBaremetalNode, self).get_parser(prog_name)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'node',
|
||||||
|
metavar='<node>',
|
||||||
|
help=_("Name or UUID of the node")
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
self.log.debug("take_action(%s)", parsed_args)
|
||||||
|
|
||||||
|
baremetal_client = self.app.client_manager.baremetal
|
||||||
|
baremetal_client.node.set_secure_boot(parsed_args.node, 'off')
|
||||||
|
|
||||||
|
|
||||||
class SetBaremetalNode(command.Command):
|
class SetBaremetalNode(command.Command):
|
||||||
"""Set baremetal properties"""
|
"""Set baremetal properties"""
|
||||||
|
|
||||||
|
@ -440,6 +440,69 @@ class TestConsoleShow(TestBaremetal):
|
|||||||
'node_uuid')
|
'node_uuid')
|
||||||
|
|
||||||
|
|
||||||
|
class TestSecurebootOff(TestBaremetal):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestSecurebootOff, self).setUp()
|
||||||
|
|
||||||
|
# Get the command object to test
|
||||||
|
self.cmd = baremetal_node.SecurebootOffBaremetalNode(self.app, None)
|
||||||
|
|
||||||
|
def test_secure_boot_off(self):
|
||||||
|
arglist = ['node_uuid']
|
||||||
|
verifylist = [('node', 'node_uuid')]
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
self.baremetal_mock.node.set_secure_boot.assert_called_once_with(
|
||||||
|
'node_uuid', 'off')
|
||||||
|
|
||||||
|
|
||||||
|
class TestSecurebootOn(TestBaremetal):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestSecurebootOn, self).setUp()
|
||||||
|
|
||||||
|
# Get the command object to test
|
||||||
|
self.cmd = baremetal_node.SecurebootOnBaremetalNode(self.app, None)
|
||||||
|
|
||||||
|
def test_console_enable(self):
|
||||||
|
arglist = ['node_uuid']
|
||||||
|
verifylist = [('node', 'node_uuid')]
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
self.baremetal_mock.node.set_secure_boot.assert_called_once_with(
|
||||||
|
'node_uuid', 'on')
|
||||||
|
|
||||||
|
|
||||||
|
class TestBootmodeSet(TestBaremetal):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestBootmodeSet, self).setUp()
|
||||||
|
|
||||||
|
# Get the command object to test
|
||||||
|
self.cmd = baremetal_node.BootmodeSetBaremetalNode(self.app, None)
|
||||||
|
|
||||||
|
def test_baremetal_boot_mode_bios(self):
|
||||||
|
arglist = ['node_uuid',
|
||||||
|
'bios']
|
||||||
|
verifylist = [
|
||||||
|
('node', 'node_uuid'),
|
||||||
|
('boot_mode', 'bios'),
|
||||||
|
]
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
self.baremetal_mock.node.set_boot_mode.assert_called_once_with(
|
||||||
|
'node_uuid',
|
||||||
|
'bios'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestBaremetalCreate(TestBaremetal):
|
class TestBaremetalCreate(TestBaremetal):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestBaremetalCreate, self).setUp()
|
super(TestBaremetalCreate, self).setUp()
|
||||||
|
@ -412,6 +412,13 @@ fake_responses = {
|
|||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
'/v1/nodes/%s/states/boot_mode' % NODE1['uuid']:
|
||||||
|
{
|
||||||
|
'PUT': (
|
||||||
|
{},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
},
|
||||||
'/v1/nodes/%s/states/power' % NODE1['uuid']:
|
'/v1/nodes/%s/states/power' % NODE1['uuid']:
|
||||||
{
|
{
|
||||||
'PUT': (
|
'PUT': (
|
||||||
@ -419,6 +426,13 @@ fake_responses = {
|
|||||||
POWER_STATE,
|
POWER_STATE,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
'/v1/nodes/%s/states/secure_boot' % NODE1['uuid']:
|
||||||
|
{
|
||||||
|
'PUT': (
|
||||||
|
{},
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
},
|
||||||
'/v1/nodes/%s/validate' % NODE1['uuid']:
|
'/v1/nodes/%s/validate' % NODE1['uuid']:
|
||||||
{
|
{
|
||||||
'GET': (
|
'GET': (
|
||||||
@ -1452,6 +1466,53 @@ class NodeManagerTest(testtools.TestCase):
|
|||||||
self.mgr.set_power_state,
|
self.mgr.set_power_state,
|
||||||
NODE1['uuid'], 'off', soft=False, timeout='a')
|
NODE1['uuid'], 'off', soft=False, timeout='a')
|
||||||
|
|
||||||
|
def test_node_set_boot_mode_bios(self):
|
||||||
|
target_state = 'bios'
|
||||||
|
self.mgr.set_boot_mode(NODE1['uuid'], target_state)
|
||||||
|
body = {'target': target_state}
|
||||||
|
expect = [
|
||||||
|
('PUT', '/v1/nodes/%s/states/boot_mode' % NODE1['uuid'], {}, body),
|
||||||
|
]
|
||||||
|
self.assertEqual(expect, self.api.calls)
|
||||||
|
|
||||||
|
def test_node_set_boot_mode_invalid(self):
|
||||||
|
self.assertRaises(ValueError, self.mgr.set_boot_mode,
|
||||||
|
NODE1['uuid'], 'ancient-bios')
|
||||||
|
|
||||||
|
def test_node_set_secure_boot_bool(self):
|
||||||
|
secure_boot = self.mgr.set_secure_boot(NODE1['uuid'], True)
|
||||||
|
body = {'target': True}
|
||||||
|
expect = [
|
||||||
|
('PUT', '/v1/nodes/%s/states/secure_boot' % NODE1['uuid'],
|
||||||
|
{}, body),
|
||||||
|
]
|
||||||
|
self.assertEqual(expect, self.api.calls)
|
||||||
|
self.assertIsNone(secure_boot)
|
||||||
|
|
||||||
|
def test_node_set_secure_boot_on(self):
|
||||||
|
secure_boot = self.mgr.set_secure_boot(NODE1['uuid'], 'on')
|
||||||
|
body = {'target': True}
|
||||||
|
expect = [
|
||||||
|
('PUT', '/v1/nodes/%s/states/secure_boot' % NODE1['uuid'],
|
||||||
|
{}, body),
|
||||||
|
]
|
||||||
|
self.assertEqual(expect, self.api.calls)
|
||||||
|
self.assertIsNone(secure_boot)
|
||||||
|
|
||||||
|
def test_node_set_secure_boot_off(self):
|
||||||
|
secure_boot = self.mgr.set_secure_boot(NODE1['uuid'], 'off')
|
||||||
|
body = {'target': False}
|
||||||
|
expect = [
|
||||||
|
('PUT', '/v1/nodes/%s/states/secure_boot' % NODE1['uuid'],
|
||||||
|
{}, body),
|
||||||
|
]
|
||||||
|
self.assertEqual(expect, self.api.calls)
|
||||||
|
self.assertIsNone(secure_boot)
|
||||||
|
|
||||||
|
def test_node_set_secure_boot_bad(self):
|
||||||
|
self.assertRaises(exc.InvalidAttribute, self.mgr.set_secure_boot,
|
||||||
|
NODE1['uuid'], 'band')
|
||||||
|
|
||||||
def test_set_target_raid_config(self):
|
def test_set_target_raid_config(self):
|
||||||
self.mgr.set_target_raid_config(
|
self.mgr.set_target_raid_config(
|
||||||
NODE1['uuid'], {'fake': 'config'})
|
NODE1['uuid'], {'fake': 'config'})
|
||||||
|
@ -590,6 +590,64 @@ class NodeManager(base.CreateManager):
|
|||||||
os_ironic_api_version=os_ironic_api_version,
|
os_ironic_api_version=os_ironic_api_version,
|
||||||
global_request_id=global_request_id)
|
global_request_id=global_request_id)
|
||||||
|
|
||||||
|
def set_boot_mode(self, node_id, state,
|
||||||
|
os_ironic_api_version=None, global_request_id=None):
|
||||||
|
"""Sets boot mode for a node.
|
||||||
|
|
||||||
|
:param node_id: Node identifier
|
||||||
|
:param state: One of target boot modes, 'uefi' or 'bios'
|
||||||
|
:param os_ironic_api_version: String version (e.g. "1.76") to use for
|
||||||
|
the request. If not specified, the client's default is used.
|
||||||
|
:param global_request_id: String containing global request ID header
|
||||||
|
value (in form "req-<UUID>") to use for the request.
|
||||||
|
|
||||||
|
:raises: ValueError if boot mode is not one of 'uefi' / 'bios'
|
||||||
|
:returns: The status of the request
|
||||||
|
"""
|
||||||
|
if state not in ('uefi', 'bios'):
|
||||||
|
raise ValueError(
|
||||||
|
_("Valid boot modes are 'uefi' or 'bios'"))
|
||||||
|
|
||||||
|
path = "%s/states/boot_mode" % node_id
|
||||||
|
target = state
|
||||||
|
body = {'target': target}
|
||||||
|
|
||||||
|
return self.update(path, body, http_method='PUT',
|
||||||
|
os_ironic_api_version=os_ironic_api_version,
|
||||||
|
global_request_id=global_request_id)
|
||||||
|
|
||||||
|
def set_secure_boot(self, node_id, state,
|
||||||
|
os_ironic_api_version=None, global_request_id=None):
|
||||||
|
"""Set the secure boot state for the node.
|
||||||
|
|
||||||
|
:param node_id: The UUID of the node.
|
||||||
|
:param state: the secure boot state; either a Boolean or a string
|
||||||
|
representation of a Boolean (eg, 'true', 'on', 'false',
|
||||||
|
'off'). True to turn secure boot on; False
|
||||||
|
to turn secure boot off.
|
||||||
|
:param os_ironic_api_version: String version (e.g. "1.76") to use for
|
||||||
|
the request. If not specified, the client's default is used.
|
||||||
|
:param global_request_id: String containing global request ID header
|
||||||
|
value (in form "req-<UUID>") to use for the request.
|
||||||
|
|
||||||
|
:raises: InvalidAttribute if state is an invalid string (that doesn't
|
||||||
|
represent a Boolean).
|
||||||
|
"""
|
||||||
|
if isinstance(state, bool):
|
||||||
|
target = state
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
target = strutils.bool_from_string(state, strict=True)
|
||||||
|
except ValueError as e:
|
||||||
|
raise exc.InvalidAttribute(_("Argument 'state': %(err)s") %
|
||||||
|
{'err': e})
|
||||||
|
path = "%s/states/secure_boot" % node_id
|
||||||
|
body = {'target': target}
|
||||||
|
|
||||||
|
return self.update(path, body, http_method='PUT',
|
||||||
|
os_ironic_api_version=os_ironic_api_version,
|
||||||
|
global_request_id=global_request_id)
|
||||||
|
|
||||||
def set_target_raid_config(
|
def set_target_raid_config(
|
||||||
self, node_ident, target_raid_config,
|
self, node_ident, target_raid_config,
|
||||||
os_ironic_api_version=None, global_request_id=None):
|
os_ironic_api_version=None, global_request_id=None):
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Adds support for changing node states ``boot_mode`` and ``secure_boot``
|
||||||
|
in sync with functionality introduced in API 1.76.
|
@ -63,6 +63,7 @@ openstack.baremetal.v1 =
|
|||||||
baremetal_node_bios_setting_show = ironicclient.osc.v1.baremetal_node:BIOSSettingShowBaremetalNode
|
baremetal_node_bios_setting_show = ironicclient.osc.v1.baremetal_node:BIOSSettingShowBaremetalNode
|
||||||
baremetal_node_boot_device_set = ironicclient.osc.v1.baremetal_node:BootdeviceSetBaremetalNode
|
baremetal_node_boot_device_set = ironicclient.osc.v1.baremetal_node:BootdeviceSetBaremetalNode
|
||||||
baremetal_node_boot_device_show = ironicclient.osc.v1.baremetal_node:BootdeviceShowBaremetalNode
|
baremetal_node_boot_device_show = ironicclient.osc.v1.baremetal_node:BootdeviceShowBaremetalNode
|
||||||
|
baremetal_node_boot_mode_set = ironicclient.osc.v1.baremetal_node:BootmodeSetBaremetalNode
|
||||||
baremetal_node_clean = ironicclient.osc.v1.baremetal_node:CleanBaremetalNode
|
baremetal_node_clean = ironicclient.osc.v1.baremetal_node:CleanBaremetalNode
|
||||||
baremetal_node_console_disable = ironicclient.osc.v1.baremetal_node:ConsoleDisableBaremetalNode
|
baremetal_node_console_disable = ironicclient.osc.v1.baremetal_node:ConsoleDisableBaremetalNode
|
||||||
baremetal_node_console_enable = ironicclient.osc.v1.baremetal_node:ConsoleEnableBaremetalNode
|
baremetal_node_console_enable = ironicclient.osc.v1.baremetal_node:ConsoleEnableBaremetalNode
|
||||||
@ -84,6 +85,8 @@ openstack.baremetal.v1 =
|
|||||||
baremetal_node_rebuild = ironicclient.osc.v1.baremetal_node:RebuildBaremetalNode
|
baremetal_node_rebuild = ironicclient.osc.v1.baremetal_node:RebuildBaremetalNode
|
||||||
baremetal_node_remove_trait = ironicclient.osc.v1.baremetal_node:RemoveTraitBaremetalNode
|
baremetal_node_remove_trait = ironicclient.osc.v1.baremetal_node:RemoveTraitBaremetalNode
|
||||||
baremetal_node_rescue = ironicclient.osc.v1.baremetal_node:RescueBaremetalNode
|
baremetal_node_rescue = ironicclient.osc.v1.baremetal_node:RescueBaremetalNode
|
||||||
|
baremetal_node_secure_boot_on = ironicclient.osc.v1.baremetal_node:SecurebootOnBaremetalNode
|
||||||
|
baremetal_node_secure_boot_off = ironicclient.osc.v1.baremetal_node:SecurebootOffBaremetalNode
|
||||||
baremetal_node_set = ironicclient.osc.v1.baremetal_node:SetBaremetalNode
|
baremetal_node_set = ironicclient.osc.v1.baremetal_node:SetBaremetalNode
|
||||||
baremetal_node_show = ironicclient.osc.v1.baremetal_node:ShowBaremetalNode
|
baremetal_node_show = ironicclient.osc.v1.baremetal_node:ShowBaremetalNode
|
||||||
baremetal_node_trait_list = ironicclient.osc.v1.baremetal_node:ListTraitsBaremetalNode
|
baremetal_node_trait_list = ironicclient.osc.v1.baremetal_node:ListTraitsBaremetalNode
|
||||||
|
Loading…
Reference in New Issue
Block a user