From 00a610ebac49ede5860228ffe5227e355c99b532 Mon Sep 17 00:00:00 2001 From: Julia Kreger Date: Thu, 14 Sep 2023 14:33:42 -0700 Subject: [PATCH] [baremetal] Add support for service steps Adds support for baremetal nodes to receive a service command which is used to modify a node in an active state. Also adds service_step to the node object to allow API consumers to understand where the service step operation is at. Change-Id: I0c1e46a209d83d8c641a0f39302330f3d61d8cdf --- openstack/baremetal/v1/_common.py | 1 + openstack/baremetal/v1/node.py | 16 +++++++++++++++- openstack/tests/unit/baremetal/v1/test_node.py | 17 +++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/openstack/baremetal/v1/_common.py b/openstack/baremetal/v1/_common.py index f6ad15b1c..787e9b23e 100644 --- a/openstack/baremetal/v1/_common.py +++ b/openstack/baremetal/v1/_common.py @@ -32,6 +32,7 @@ PROVISIONING_VERSIONS = { 'rescue': 38, 'unrescue': 38, 'unhold': 85, + 'service': 87, } """API microversions introducing provisioning verbs.""" diff --git a/openstack/baremetal/v1/node.py b/openstack/baremetal/v1/node.py index 877275650..c8d03add6 100644 --- a/openstack/baremetal/v1/node.py +++ b/openstack/baremetal/v1/node.py @@ -100,7 +100,7 @@ class Node(_common.ListMixin, resource.Resource): ) # Ability to have a firmware_interface on a node. - _max_microversion = '1.86' + _max_microversion = '1.87' # Properties #: The UUID of the allocation associated with this node. Added in API @@ -201,6 +201,9 @@ class Node(_common.ListMixin, resource.Resource): #: A string to be used by external schedulers to identify this node as a #: unit of a specific type of resource. Added in API microversion 1.21. resource_class = resource.Body("resource_class") + #: A string represents the current service step being executed upon. + #: Added in API microversion 1.87. + service_step = resource.Body("service_step") #: A string indicating the shard this node belongs to. Added in API #: microversion 1,82. shard = resource.Body("shard") @@ -399,6 +402,7 @@ class Node(_common.ListMixin, resource.Resource): wait=False, timeout=None, deploy_steps=None, + service_steps=None, ): """Run an action modifying this node's provision state. @@ -421,6 +425,8 @@ class Node(_common.ListMixin, resource.Resource): reached. If ``None``, wait without timeout. :param deploy_steps: Deploy steps to execute, only valid for ``active`` and ``rebuild`` target. + :param service_steps: Service steps to execute, only valid for + ``service`` target. :return: This :class:`Node` instance. :raises: ValueError if ``config_drive``, ``clean_steps``, @@ -474,6 +480,14 @@ class Node(_common.ListMixin, resource.Resource): ) body['deploy_steps'] = deploy_steps + if service_steps is not None: + if target != 'service': + raise ValueError( + 'Service steps can only be provided with ' + '"service" target' + ) + body['service_steps'] = service_steps + if rescue_password is not None: if target != 'rescue': raise ValueError( diff --git a/openstack/tests/unit/baremetal/v1/test_node.py b/openstack/tests/unit/baremetal/v1/test_node.py index 0c82da05f..a47eec1dc 100644 --- a/openstack/tests/unit/baremetal/v1/test_node.py +++ b/openstack/tests/unit/baremetal/v1/test_node.py @@ -75,6 +75,7 @@ FAKE = { "raid_config": {}, "reservation": None, "resource_class": None, + "service_step": {}, "secure_boot": True, "shard": "TestShard", "states": [ @@ -148,6 +149,7 @@ class TestNode(base.TestCase): self.assertEqual(FAKE['raid_config'], sot.raid_config) self.assertEqual(FAKE['reservation'], sot.reservation) self.assertEqual(FAKE['resource_class'], sot.resource_class) + self.assertEqual(FAKE['service_step'], sot.service_step) self.assertEqual(FAKE['secure_boot'], sot.is_secure_boot) self.assertEqual(FAKE['states'], sot.states) self.assertEqual( @@ -397,6 +399,21 @@ class TestNodeSetProvisionState(base.TestCase): retriable_status_codes=_common.RETRIABLE_STATUS_CODES, ) + def test_set_provision_state_service(self): + service_steps = [{'interface': 'deploy', 'step': 'hold'}] + result = self.node.set_provision_state( + self.session, 'service', service_steps=service_steps + ) + + self.assertIs(result, self.node) + self.session.put.assert_called_once_with( + 'nodes/%s/states/provision' % self.node.id, + json={'target': 'service', 'service_steps': service_steps}, + headers=mock.ANY, + microversion='1.87', + retriable_status_codes=_common.RETRIABLE_STATUS_CODES, + ) + @mock.patch.object(node.Node, '_translate_response', mock.Mock()) @mock.patch.object(node.Node, '_get_session', lambda self, x: x)