summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2021-02-12 16:02:01 +0000
committerGerrit Code Review <review@openstack.org>2021-02-12 16:02:01 +0000
commit17856e5d9fdb5f02a4bb95f328e1f42927b38ab8 (patch)
tree47be4d3f642de070ed4854e696225ea3b9e16023
parent1e02b3e5eb0ee8ee05ef8c6056dc88524985f249 (diff)
parent8df29e00a28b5b619f31355dca8be08ab975333a (diff)
downloadpython-ironicclient-17856e5d9fdb5f02a4bb95f328e1f42927b38ab8.tar.gz
Merge "Add 'deploy steps' for provisioning API"
-rw-r--r--ironicclient/common/http.py2
-rwxr-xr-xironicclient/osc/v1/baremetal_node.py28
-rw-r--r--ironicclient/tests/unit/osc/v1/test_baremetal_node.py30
-rw-r--r--ironicclient/tests/unit/v1/test_node.py25
-rw-r--r--ironicclient/v1/node.py13
-rw-r--r--releasenotes/notes/add-deploy-steps-arg-0b127e29c8cf976d.yaml15
6 files changed, 97 insertions, 16 deletions
diff --git a/ironicclient/common/http.py b/ironicclient/common/http.py
index 9f2cd81..c12a626 100644
--- a/ironicclient/common/http.py
+++ b/ironicclient/common/http.py
@@ -37,7 +37,7 @@ from ironicclient import exc
# http://specs.openstack.org/openstack/ironic-specs/specs/kilo/api-microversions.html # noqa
# for full details.
DEFAULT_VER = '1.9'
-LAST_KNOWN_API_VERSION = 67
+LAST_KNOWN_API_VERSION = 69
LATEST_VERSION = '1.{}'.format(LAST_KNOWN_API_VERSION)
LOG = logging.getLogger(__name__)
diff --git a/ironicclient/osc/v1/baremetal_node.py b/ironicclient/osc/v1/baremetal_node.py
index fe08859..ffdfd74 100755
--- a/ironicclient/osc/v1/baremetal_node.py
+++ b/ironicclient/osc/v1/baremetal_node.py
@@ -81,6 +81,9 @@ class ProvisionStateBaremetalNode(command.Command):
clean_steps = getattr(parsed_args, 'clean_steps', None)
clean_steps = utils.handle_json_arg(clean_steps, 'clean steps')
+ deploy_steps = getattr(parsed_args, 'deploy_steps', None)
+ deploy_steps = utils.handle_json_arg(deploy_steps, 'deploy steps')
+
config_drive = getattr(parsed_args, 'config_drive', None)
if config_drive:
try:
@@ -98,6 +101,7 @@ class ProvisionStateBaremetalNode(command.Command):
parsed_args.provision_state,
configdrive=config_drive,
cleansteps=clean_steps,
+ deploysteps=deploy_steps,
rescue_password=rescue_password)
@@ -561,6 +565,18 @@ class DeployBaremetalNode(ProvisionStateWithWait):
metavar='<config-drive>',
default=None,
help=CONFIG_DRIVE_ARG_HELP)
+
+ parser.add_argument(
+ '--deploy-steps',
+ metavar='<deploy-steps>',
+ required=False,
+ default=None,
+ help=_("The deploy steps in JSON format. May be the path to a "
+ "file containing the deploy steps; OR '-', with the deploy "
+ "steps being read from standard input; OR a string. The "
+ "value should be a list of deploy-step dictionaries; each "
+ "dictionary should have keys 'interface', 'step', "
+ "'priority' and optional key 'args'."))
return parser
@@ -1036,6 +1052,18 @@ class RebuildBaremetalNode(ProvisionStateWithWait):
metavar='<config-drive>',
default=None,
help=CONFIG_DRIVE_ARG_HELP)
+
+ parser.add_argument(
+ '--deploy-steps',
+ metavar='<deploy-steps>',
+ required=False,
+ default=None,
+ help=_("The deploy steps in JSON format. May be the path to a "
+ "file containing the deploy steps; OR '-', with the deploy "
+ "steps being read from standard input; OR a string. The "
+ "value should be a list of deploy-step dictionaries; each "
+ "dictionary should have keys 'interface', 'step', "
+ "'priority' and optional key 'args'."))
return parser
diff --git a/ironicclient/tests/unit/osc/v1/test_baremetal_node.py b/ironicclient/tests/unit/osc/v1/test_baremetal_node.py
index b69373a..c09f541 100644
--- a/ironicclient/tests/unit/osc/v1/test_baremetal_node.py
+++ b/ironicclient/tests/unit/osc/v1/test_baremetal_node.py
@@ -56,7 +56,8 @@ class TestAdopt(TestBaremetal):
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
'node_uuid', 'adopt',
- cleansteps=None, configdrive=None, rescue_password=None)
+ cleansteps=None, deploysteps=None, configdrive=None,
+ rescue_password=None)
def test_adopt_no_wait(self):
arglist = ['node_uuid']
@@ -1446,11 +1447,13 @@ class TestDeployBaremetalProvisionState(TestBaremetal):
def test_deploy_baremetal_provision_state_active_and_configdrive(self):
arglist = ['node_uuid',
- '--config-drive', 'path/to/drive']
+ '--config-drive', 'path/to/drive',
+ '--deploy-steps', '[{"interface":"deploy"}]']
verifylist = [
('node', 'node_uuid'),
('provision_state', 'active'),
('config_drive', 'path/to/drive'),
+ ('deploy_steps', '[{"interface":"deploy"}]')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1459,7 +1462,8 @@ class TestDeployBaremetalProvisionState(TestBaremetal):
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
'node_uuid', 'active',
- cleansteps=None, configdrive='path/to/drive', rescue_password=None)
+ cleansteps=None, deploysteps=[{"interface": "deploy"}],
+ configdrive='path/to/drive', rescue_password=None)
def test_deploy_baremetal_provision_state_active_and_configdrive_dict(
self):
@@ -1477,7 +1481,7 @@ class TestDeployBaremetalProvisionState(TestBaremetal):
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
'node_uuid', 'active',
- cleansteps=None, configdrive={'meta_data': {}},
+ cleansteps=None, deploysteps=None, configdrive={'meta_data': {}},
rescue_password=None)
def test_deploy_no_wait(self):
@@ -1679,8 +1683,8 @@ class TestRescueBaremetalProvisionState(TestBaremetal):
self.cmd.take_action(parsed_args)
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
- 'node_uuid', 'rescue', cleansteps=None, configdrive=None,
- rescue_password='supersecret')
+ 'node_uuid', 'rescue', cleansteps=None, deploysteps=None,
+ configdrive=None, rescue_password='supersecret')
def test_rescue_baremetal_provision_state_rescue_and_wait(self):
arglist = ['node_uuid',
@@ -1855,11 +1859,13 @@ class TestRebuildBaremetalProvisionState(TestBaremetal):
def test_rebuild_baremetal_provision_state_active_and_configdrive(self):
arglist = ['node_uuid',
- '--config-drive', 'path/to/drive']
+ '--config-drive', 'path/to/drive',
+ '--deploy-steps', '[{"interface":"deploy"}]']
verifylist = [
('node', 'node_uuid'),
('provision_state', 'rebuild'),
('config_drive', 'path/to/drive'),
+ ('deploy_steps', '[{"interface":"deploy"}]')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -1868,8 +1874,8 @@ class TestRebuildBaremetalProvisionState(TestBaremetal):
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
'node_uuid', 'rebuild',
- cleansteps=None, configdrive='path/to/drive',
- rescue_password=None)
+ cleansteps=None, deploysteps=[{"interface": "deploy"}],
+ configdrive='path/to/drive', rescue_password=None)
def test_rebuild_no_wait(self):
arglist = ['node_uuid']
@@ -1884,7 +1890,7 @@ class TestRebuildBaremetalProvisionState(TestBaremetal):
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
'node_uuid', 'rebuild',
- cleansteps=None, configdrive=None,
+ cleansteps=None, deploysteps=None, configdrive=None,
rescue_password=None)
self.baremetal_mock.node.wait_for_provision_state.assert_not_called()
@@ -2002,8 +2008,8 @@ class TestUnrescueBaremetalProvisionState(TestBaremetal):
self.cmd.take_action(parsed_args)
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
- 'node_uuid', 'unrescue', cleansteps=None, configdrive=None,
- rescue_password=None)
+ 'node_uuid', 'unrescue', cleansteps=None, deploysteps=None,
+ configdrive=None, rescue_password=None)
def test_unrescue_baremetal_provision_state_active_and_wait(self):
arglist = ['node_uuid',
diff --git a/ironicclient/tests/unit/v1/test_node.py b/ironicclient/tests/unit/v1/test_node.py
index 47347ef..4a6c344 100644
--- a/ironicclient/tests/unit/v1/test_node.py
+++ b/ironicclient/tests/unit/v1/test_node.py
@@ -1564,6 +1564,31 @@ class NodeManagerTest(testtools.TestCase):
]
self.assertEqual(expect, self.api.calls)
+ def test_node_set_provision_state_with_deploysteps(self):
+ deploysteps = [{"step": "upgrade", "interface": "deploy"}]
+ target_state = 'active'
+ self.mgr.set_provision_state(NODE1['uuid'], target_state,
+ deploysteps=deploysteps)
+ body = {'target': target_state, 'deploy_steps': deploysteps}
+ expect = [
+ ('PUT', '/v1/nodes/%s/states/provision' % NODE1['uuid'], {}, body),
+ ]
+ self.assertEqual(expect, self.api.calls)
+
+ def test_node_set_provision_state_with_configdrive_and_deploysteps(self):
+ deploysteps = [{"step": "upgrade", "interface": "deploy"}]
+ target_state = 'active'
+ self.mgr.set_provision_state(NODE1['uuid'], target_state,
+ configdrive={'user_data': ''},
+ deploysteps=deploysteps)
+ body = {'target': target_state,
+ 'configdrive': {'user_data': ''},
+ 'deploy_steps': deploysteps}
+ expect = [
+ ('PUT', '/v1/nodes/%s/states/provision' % NODE1['uuid'], {}, body),
+ ]
+ self.assertEqual(expect, self.api.calls)
+
def test_node_set_provision_state_with_rescue_password(self):
rescue_password = 'supersecret'
target_state = 'rescue'
diff --git a/ironicclient/v1/node.py b/ironicclient/v1/node.py
index 5fb3872..88879f0 100644
--- a/ironicclient/v1/node.py
+++ b/ironicclient/v1/node.py
@@ -619,7 +619,7 @@ class NodeManager(base.CreateManager):
def set_provision_state(
self, node_uuid, state, configdrive=None, cleansteps=None,
rescue_password=None, os_ironic_api_version=None,
- global_request_id=None):
+ global_request_id=None, deploysteps=None):
"""Set the provision state for the node.
:param node_uuid: The UUID or name of the node.
@@ -644,8 +644,12 @@ class NodeManager(base.CreateManager):
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 there was an error with the clean steps
+ :param deploysteps: The deploy steps as a list of deploy-step
+ dictionaries; each dictionary should have keys 'interface', 'step',
+ 'priority', and optional key 'args'. This is optional and is
+ only valid when setting provision-state to 'active' or 'rebuild'.
+ :raises: InvalidAttribute if there was an error with the clean steps or
+ deploy steps
:returns: The status of the request
"""
@@ -671,6 +675,9 @@ class NodeManager(base.CreateManager):
elif rescue_password:
body['rescue_password'] = rescue_password
+ if deploysteps:
+ body['deploy_steps'] = deploysteps
+
return self.update(path, body, http_method='PUT',
os_ironic_api_version=os_ironic_api_version,
global_request_id=global_request_id)
diff --git a/releasenotes/notes/add-deploy-steps-arg-0b127e29c8cf976d.yaml b/releasenotes/notes/add-deploy-steps-arg-0b127e29c8cf976d.yaml
new file mode 100644
index 0000000..f6a2e3d
--- /dev/null
+++ b/releasenotes/notes/add-deploy-steps-arg-0b127e29c8cf976d.yaml
@@ -0,0 +1,15 @@
+---
+features:
+ - |
+ Adds support for providing optional deploy steps when deploying or
+ rebuilding; available with ironic-api-version 1.69 or higher. Baremetal CLI
+ is ``baremetal node <provision-state> <node> --deploy-steps
+ <deploy-steps>`` where ``<provision-state>`` is 'deploy' or 'rebuild' and
+ ``<deploy-steps>`` are deploy steps in JSON format. May be path to a file
+ containing deploy steps; OR '-', with the deploy steps being read from
+ standard input; OR a string. The value should be a list of deploy-step
+ dictionaries; each dictionary should have keys 'interface', 'step' and
+ 'priority', and optional key 'args'. When overlapping, these steps override
+ deploy template and driver steps. For more information see
+ `Deploy Steps in Node Deployment documentation <https://docs.openstack.org/ironic/latest/admin/node-deployment.html#id3>`_.
+