Merge "Add 'deploy steps' for provisioning API"
This commit is contained in:
commit
17856e5d9f
@ -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__)
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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'
|
||||
|
@ -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)
|
||||
|
@ -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>`_.
|
||||
|
Loading…
Reference in New Issue
Block a user