[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
This commit is contained in:
Julia Kreger
2023-09-14 14:33:42 -07:00
parent 3742f2ce35
commit 00a610ebac
3 changed files with 33 additions and 1 deletions

View File

@@ -32,6 +32,7 @@ PROVISIONING_VERSIONS = {
'rescue': 38,
'unrescue': 38,
'unhold': 85,
'service': 87,
}
"""API microversions introducing provisioning verbs."""

View File

@@ -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(

View File

@@ -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)