diff options
author | Cenne <cennedee+opendev@protonmail.com> | 2021-07-08 18:37:45 +0200 |
---|---|---|
committer | Cenne <cennedee+opendev@protonmail.com> | 2021-08-23 19:38:58 +0200 |
commit | bc95c92f7c122b1217459a1d7a125fae47749e6e (patch) | |
tree | 6ffd3cc271ac841e2a2a5fc72524ee2f1f625a37 /ironic/api | |
parent | 9f32ceda1a87ac83d4ac84faec16c01ba27c549e (diff) | |
download | ironic-bc95c92f7c122b1217459a1d7a125fae47749e6e.tar.gz |
Add api endpoints for changing boot_mode and secure_boot state
Done:
- Node API endpoints expose
- RPC methods
- Conductor Manager methods
- Conductor utils new methods
- RBAC new policies
- Node API tests
- Manager Tests (+ some testing for utils methods)
- RBAC tests
- Docs (api-ref)
- REST API version history
- Releasenotes
Story: 2008567
Task: 41709
Change-Id: I2d72389edf546b99c536c6b130ca85ababf80591
Diffstat (limited to 'ironic/api')
-rw-r--r-- | ironic/api/controllers/v1/node.py | 107 | ||||
-rw-r--r-- | ironic/api/controllers/v1/versions.py | 4 |
2 files changed, 110 insertions, 1 deletions
diff --git a/ironic/api/controllers/v1/node.py b/ironic/api/controllers/v1/node.py index 8a53c4fbb..e40743617 100644 --- a/ironic/api/controllers/v1/node.py +++ b/ironic/api/controllers/v1/node.py @@ -40,6 +40,7 @@ from ironic.api.controllers.v1 import versions from ironic.api.controllers.v1 import volume from ironic.api import method from ironic.common import args +from ironic.common import boot_modes from ironic.common import exception from ironic.common.i18n import _ from ironic.common import policy @@ -120,6 +121,9 @@ ALLOWED_TARGET_POWER_STATES = (ir_states.POWER_ON, ir_states.SOFT_REBOOT, ir_states.SOFT_POWER_OFF) +ALLOWED_TARGET_BOOT_MODES = (boot_modes.LEGACY_BIOS, + boot_modes.UEFI) + _NODE_DESCRIPTION_MAX_LENGTH = 4096 _NETWORK_DATA_SCHEMA = None @@ -710,6 +714,8 @@ def node_states_convert(rpc_node): class NodeStatesController(rest.RestController): _custom_actions = { + 'boot_mode': ['PUT'], + 'secure_boot': ['PUT'], 'power': ['PUT'], 'provision': ['PUT'], 'raid': ['PUT'], @@ -822,6 +828,107 @@ class NodeStatesController(rest.RestController): url_args = '/'.join([node_ident, 'states']) api.response.location = link.build_url('nodes', url_args) + @METRICS.timer('NodeStatesController.boot_mode') + @method.expose(status_code=http_client.ACCEPTED) + @args.validate(node_ident=args.uuid_or_name, target=args.string) + def boot_mode(self, node_ident, target): + """Asynchronous set the boot mode of the node. + + :param node_ident: the UUID or logical name of a node. + :param target: The desired boot_mode for the node. (uefi/bios) + :raises: NotFound (HTTP 404) if requested version of the API + is less than 1.76. + :raises: InvalidParameterValue (HTTP 400) if the requested target + state is not valid. + :raises: Conflict (HTTP 409) if a node is in adopting state or + another transient state. + + """ + rpc_node = api_utils.check_node_policy_and_retrieve( + 'baremetal:node:set_boot_mode', node_ident) + topic = api.request.rpcapi.get_topic_for(rpc_node) + + if (api.request.version.minor + < versions.MINOR_76_NODE_CHANGE_BOOT_MODE): + raise exception.NotFound( + (_("This endpoint is supported starting with the API version " + "1.%(min_version)s") % + {'min_version': versions.MINOR_76_NODE_CHANGE_BOOT_MODE})) + + if target not in ALLOWED_TARGET_BOOT_MODES: + msg = (_("Invalid boot mode %(mode)s requested for node. " + "Allowed boot modes are: " + "%(modes)s") % + {'mode': target, + 'modes': ', '.join(ALLOWED_TARGET_BOOT_MODES)}) + raise exception.InvalidParameterValue(msg) + + # NOTE(cenne): This currenly includes the ADOPTING state + if rpc_node.provision_state in ir_states.UNSTABLE_STATES: + msg = _("Node is in %(state)s state. Since node is transitioning, " + "the boot mode will not be set as this may interfere " + "with ongoing changes and result in erroneous modification" + ". Try again later.") + raise exception.Conflict(msg, + action=target, node=node_ident, + state=rpc_node.provision_state + ) + api.request.rpcapi.change_node_boot_mode(api.request.context, + rpc_node.uuid, target, + topic=topic) + # Set the HTTP Location Header + url_args = '/'.join([node_ident, 'states']) + api.response.location = link.build_url('nodes', url_args) + + @METRICS.timer('NodeStatesController.secure_boot') + @method.expose(status_code=http_client.ACCEPTED) + @args.validate(node_ident=args.uuid_or_name, target=args.boolean) + def secure_boot(self, node_ident, target): + """Asynchronous set the secure_boot state of the node. + + :param node_ident: the UUID or logical name of a node. + :param target: The desired secure_boot for the node. (True/False) + :raises: NotFound (HTTP 404) if requested version of the API + is less than 1.76. + :raises: InvalidParameterValue (HTTP 400) if the requested target + state is not valid. + :raises: Conflict (HTTP 409) if a node is in adopting state. + + """ + rpc_node = api_utils.check_node_policy_and_retrieve( + 'baremetal:node:set_secure_boot', node_ident) + topic = api.request.rpcapi.get_topic_for(rpc_node) + + if (api.request.version.minor + < versions.MINOR_76_NODE_CHANGE_BOOT_MODE): + raise exception.NotFound( + (_("This endpoint is supported starting with the API version " + "1.%(min_version)s") % + {'min_version': versions.MINOR_76_NODE_CHANGE_BOOT_MODE})) + # NOTE(cenne): This is to exclude target=None or other invalid values + if target not in (True, False): + msg = (_("Invalid secure_boot %(state)s requested for node. " + "Allowed secure_boot states are: True, False) ") % + {'state': target}) + raise exception.InvalidParameterValue(msg) + + # NOTE(cenne): This currenly includes the ADOPTING state + if rpc_node.provision_state in ir_states.UNSTABLE_STATES: + msg = _("Node is in %(state)s state. Since node is transitioning, " + "the boot mode will not be set as this may interfere " + "with ongoing changes and result in erroneous modification" + ". Try again later.") + raise exception.Conflict(msg, + action=target, node=node_ident, + state=rpc_node.provision_state + ) + api.request.rpcapi.change_node_secure_boot(api.request.context, + rpc_node.uuid, target, + topic=topic) + # Set the HTTP Location Header + url_args = '/'.join([node_ident, 'states']) + api.response.location = link.build_url('nodes', url_args) + def _do_provision_action(self, rpc_node, target, configdrive=None, clean_steps=None, deploy_steps=None, rescue_password=None, disable_ramdisk=None): diff --git a/ironic/api/controllers/v1/versions.py b/ironic/api/controllers/v1/versions.py index 1af83c431..9cd890e8f 100644 --- a/ironic/api/controllers/v1/versions.py +++ b/ironic/api/controllers/v1/versions.py @@ -113,6 +113,7 @@ BASE_VERSION = 1 # v1.73: Add support for deploy and undeploy verbs # v1.74: Add bios registry to /v1/nodes/{node}/bios/{setting} # v1.75: Add boot_mode, secure_boot fields to node object. +# v1.76: Add support for changing boot_mode and secure_boot state MINOR_0_JUNO = 0 MINOR_1_INITIAL_VERSION = 1 @@ -190,6 +191,7 @@ MINOR_72_HEARTBEAT_STATUS = 72 MINOR_73_DEPLOY_UNDEPLOY_VERBS = 73 MINOR_74_BIOS_REGISTRY = 74 MINOR_75_NODE_BOOT_MODE = 75 +MINOR_76_NODE_CHANGE_BOOT_MODE = 76 # When adding another version, update: # - MINOR_MAX_VERSION @@ -197,7 +199,7 @@ MINOR_75_NODE_BOOT_MODE = 75 # explanation of what changed in the new version # - common/release_mappings.py, RELEASE_MAPPING['master']['api'] -MINOR_MAX_VERSION = MINOR_75_NODE_BOOT_MODE +MINOR_MAX_VERSION = MINOR_76_NODE_CHANGE_BOOT_MODE # String representations of the minor and maximum versions _MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_1_INITIAL_VERSION) |