Add Service Steps to client
Change-Id: I46519120bcad8bdb369c455d73fafee914c20b00
This commit is contained in:
parent
2e8d526f0d
commit
8b9be99432
@ -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 = 86
|
||||
LAST_KNOWN_API_VERSION = 87
|
||||
LATEST_VERSION = '1.{}'.format(LAST_KNOWN_API_VERSION)
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -86,6 +86,9 @@ class ProvisionStateBaremetalNode(command.Command):
|
||||
deploy_steps = getattr(parsed_args, 'deploy_steps', None)
|
||||
deploy_steps = utils.handle_json_arg(deploy_steps, 'deploy steps')
|
||||
|
||||
service_steps = getattr(parsed_args, 'service_steps', None)
|
||||
service_steps = utils.handle_json_arg(service_steps, 'service steps')
|
||||
|
||||
config_drive = getattr(parsed_args, 'config_drive', None)
|
||||
if config_drive:
|
||||
try:
|
||||
@ -105,7 +108,8 @@ class ProvisionStateBaremetalNode(command.Command):
|
||||
configdrive=config_drive,
|
||||
cleansteps=clean_steps,
|
||||
deploysteps=deploy_steps,
|
||||
rescue_password=rescue_password)
|
||||
rescue_password=rescue_password,
|
||||
servicesteps=service_steps)
|
||||
|
||||
|
||||
class ProvisionStateWithWait(ProvisionStateBaremetalNode):
|
||||
@ -300,6 +304,29 @@ class CleanBaremetalNode(ProvisionStateWithWait):
|
||||
return parser
|
||||
|
||||
|
||||
class ServiceBaremetalNode(ProvisionStateWithWait):
|
||||
"""Set provision state of baremetal node to 'service'"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".ServiceBaremetalNode")
|
||||
PROVISION_STATE = 'service'
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ServiceBaremetalNode, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'--service-steps',
|
||||
metavar='<service-steps>',
|
||||
required=True,
|
||||
default=None,
|
||||
help=_("The service steps. May be the path to a YAML file "
|
||||
"containing the service steps; OR '-', with the service "
|
||||
" steps being read from standard input; OR a JSON string. "
|
||||
"The value should be a list of service-step dictionaries; "
|
||||
"each dictionary should have keys 'interface' and 'step', "
|
||||
"and optional key 'args'."))
|
||||
return parser
|
||||
|
||||
|
||||
class ConsoleDisableBaremetalNode(command.Command):
|
||||
"""Disable console access for a node"""
|
||||
|
||||
|
@ -59,7 +59,7 @@ class TestAbort(TestBaremetal):
|
||||
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'abort', cleansteps=None, configdrive=None,
|
||||
deploysteps=None, rescue_password=None)
|
||||
deploysteps=None, rescue_password=None, servicesteps=None)
|
||||
|
||||
|
||||
class TestAdopt(TestBaremetal):
|
||||
@ -83,7 +83,7 @@ class TestAdopt(TestBaremetal):
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'adopt',
|
||||
cleansteps=None, deploysteps=None, configdrive=None,
|
||||
rescue_password=None)
|
||||
rescue_password=None, servicesteps=None)
|
||||
self.baremetal_mock.node.wait_for_provision_state.assert_not_called()
|
||||
|
||||
def test_adopt_baremetal_provision_state_active_and_wait(self):
|
||||
@ -103,7 +103,7 @@ class TestAdopt(TestBaremetal):
|
||||
test_node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'adopt',
|
||||
cleansteps=None, deploysteps=None, configdrive=None,
|
||||
rescue_password=None)
|
||||
rescue_password=None, servicesteps=None)
|
||||
test_node.wait_for_provision_state.assert_called_once_with(
|
||||
['node_uuid'], expected_state='active',
|
||||
poll_interval=2, timeout=15)
|
||||
@ -125,7 +125,7 @@ class TestAdopt(TestBaremetal):
|
||||
test_node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'adopt',
|
||||
cleansteps=None, deploysteps=None, configdrive=None,
|
||||
rescue_password=None)
|
||||
rescue_password=None, servicesteps=None)
|
||||
test_node.wait_for_provision_state.assert_called_once_with(
|
||||
['node_uuid'], expected_state='active',
|
||||
poll_interval=2, timeout=0)
|
||||
@ -174,7 +174,43 @@ class TestClean(TestBaremetal):
|
||||
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'clean', cleansteps=steps_dict, configdrive=None,
|
||||
deploysteps=None, rescue_password=None)
|
||||
deploysteps=None, rescue_password=None, servicesteps=None)
|
||||
|
||||
|
||||
class TestService(TestBaremetal):
|
||||
def setUp(self):
|
||||
super(TestService, self).setUp()
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = baremetal_node.ServiceBaremetalNode(self.app, None)
|
||||
|
||||
def test_service_with_steps(self):
|
||||
steps_dict = {
|
||||
"service_steps": [{
|
||||
"interface": "raid",
|
||||
"step": "create_configuration",
|
||||
"args": {"create_nonroot_volumes": False}
|
||||
}, {
|
||||
"interface": "deploy",
|
||||
"step": "erase_devices"
|
||||
}]
|
||||
}
|
||||
steps_json = json.dumps(steps_dict)
|
||||
|
||||
arglist = ['--service-steps', steps_json, 'node_uuid']
|
||||
verifylist = [
|
||||
('service_steps', steps_json),
|
||||
('provision_state', 'service'),
|
||||
('nodes', ['node_uuid']),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'service', cleansteps=None, configdrive=None,
|
||||
deploysteps=None, rescue_password=None, servicesteps=steps_dict)
|
||||
|
||||
|
||||
class TestInspect(TestBaremetal):
|
||||
@ -197,7 +233,7 @@ class TestInspect(TestBaremetal):
|
||||
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'inspect', cleansteps=None, configdrive=None,
|
||||
deploysteps=None, rescue_password=None)
|
||||
deploysteps=None, rescue_password=None, servicesteps=None)
|
||||
|
||||
|
||||
class TestManage(TestBaremetal):
|
||||
@ -220,7 +256,7 @@ class TestManage(TestBaremetal):
|
||||
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'manage', cleansteps=None, configdrive=None,
|
||||
deploysteps=None, rescue_password=None)
|
||||
deploysteps=None, rescue_password=None, servicesteps=None)
|
||||
|
||||
|
||||
class TestProvide(TestBaremetal):
|
||||
@ -243,7 +279,7 @@ class TestProvide(TestBaremetal):
|
||||
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'provide', cleansteps=None, configdrive=None,
|
||||
deploysteps=None, rescue_password=None)
|
||||
deploysteps=None, rescue_password=None, servicesteps=None)
|
||||
|
||||
|
||||
class TestRebuild(TestBaremetal):
|
||||
@ -266,7 +302,7 @@ class TestRebuild(TestBaremetal):
|
||||
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'rebuild', cleansteps=None, configdrive=None,
|
||||
deploysteps=None, rescue_password=None)
|
||||
deploysteps=None, rescue_password=None, servicesteps=None)
|
||||
|
||||
|
||||
class TestUndeploy(TestBaremetal):
|
||||
@ -289,7 +325,7 @@ class TestUndeploy(TestBaremetal):
|
||||
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'deleted', cleansteps=None, configdrive=None,
|
||||
deploysteps=None, rescue_password=None)
|
||||
deploysteps=None, rescue_password=None, servicesteps=None)
|
||||
|
||||
|
||||
class TestBootdeviceSet(TestBaremetal):
|
||||
@ -1875,7 +1911,8 @@ class TestDeployBaremetalProvisionState(TestBaremetal):
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'active',
|
||||
cleansteps=None, deploysteps=[{"interface": "deploy"}],
|
||||
configdrive='path/to/drive', rescue_password=None)
|
||||
configdrive='path/to/drive', rescue_password=None,
|
||||
servicesteps=None)
|
||||
|
||||
def test_deploy_baremetal_provision_state_active_and_configdrive_dict(
|
||||
self):
|
||||
@ -1894,7 +1931,7 @@ class TestDeployBaremetalProvisionState(TestBaremetal):
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'active',
|
||||
cleansteps=None, deploysteps=None, configdrive={'meta_data': {}},
|
||||
rescue_password=None)
|
||||
rescue_password=None, servicesteps=None)
|
||||
|
||||
def test_deploy_no_wait(self):
|
||||
arglist = ['node_uuid']
|
||||
@ -1958,7 +1995,8 @@ class TestDeployBaremetalProvisionState(TestBaremetal):
|
||||
test_node = self.baremetal_mock.node
|
||||
test_node.set_provision_state.assert_has_calls([
|
||||
mock.call(n, 'active', cleansteps=None, deploysteps=None,
|
||||
configdrive=None, rescue_password=None)
|
||||
configdrive=None, rescue_password=None,
|
||||
servicesteps=None)
|
||||
for n in ['node_uuid', 'node_name']
|
||||
])
|
||||
test_node.wait_for_provision_state.assert_called_once_with(
|
||||
@ -2097,6 +2135,68 @@ class TestCleanBaremetalProvisionState(TestBaremetal):
|
||||
poll_interval=10, timeout=0)
|
||||
|
||||
|
||||
class TestServiceBaremetalProvisionState(TestBaremetal):
|
||||
def setUp(self):
|
||||
super(TestServiceBaremetalProvisionState, self).setUp()
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = baremetal_node.ServiceBaremetalNode(self.app, None)
|
||||
|
||||
def test_service_no_wait(self):
|
||||
arglist = ['node_uuid', '--service-steps', '-']
|
||||
verifylist = [
|
||||
('nodes', ['node_uuid']),
|
||||
('provision_state', 'service'),
|
||||
('service_steps', '-')
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.baremetal_mock.node.wait_for_provision_state.assert_not_called()
|
||||
|
||||
def test_service_baremetal_provision_state_manageable_and_wait(self):
|
||||
arglist = ['node_uuid',
|
||||
'--wait', '15',
|
||||
'--service-steps', '-']
|
||||
verifylist = [
|
||||
('nodes', ['node_uuid']),
|
||||
('provision_state', 'service'),
|
||||
('wait_timeout', 15),
|
||||
('service_steps', '-')
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
test_node = self.baremetal_mock.node
|
||||
test_node.wait_for_provision_state.assert_called_once_with(
|
||||
['node_uuid'], expected_state='active',
|
||||
poll_interval=10, timeout=15)
|
||||
|
||||
def test_service_baremetal_provision_state_default_wait(self):
|
||||
arglist = ['node_uuid',
|
||||
'--wait',
|
||||
'--service-steps', '-']
|
||||
verifylist = [
|
||||
('nodes', ['node_uuid']),
|
||||
('provision_state', 'service'),
|
||||
('wait_timeout', 0),
|
||||
('service_steps', '-')
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
test_node = self.baremetal_mock.node
|
||||
test_node.wait_for_provision_state.assert_called_once_with(
|
||||
['node_uuid'], expected_state='active',
|
||||
poll_interval=10, timeout=0)
|
||||
|
||||
|
||||
class TestRescueBaremetalProvisionState(TestBaremetal):
|
||||
def setUp(self):
|
||||
super(TestRescueBaremetalProvisionState, self).setUp()
|
||||
@ -2119,7 +2219,8 @@ class TestRescueBaremetalProvisionState(TestBaremetal):
|
||||
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'rescue', cleansteps=None, deploysteps=None,
|
||||
configdrive=None, rescue_password='supersecret')
|
||||
configdrive=None, rescue_password='supersecret',
|
||||
servicesteps=None)
|
||||
|
||||
def test_rescue_baremetal_provision_state_rescue_and_wait(self):
|
||||
arglist = ['node_uuid',
|
||||
@ -2310,7 +2411,8 @@ class TestRebuildBaremetalProvisionState(TestBaremetal):
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'rebuild',
|
||||
cleansteps=None, deploysteps=[{"interface": "deploy"}],
|
||||
configdrive='path/to/drive', rescue_password=None)
|
||||
configdrive='path/to/drive', rescue_password=None,
|
||||
servicesteps=None)
|
||||
|
||||
def test_rebuild_no_wait(self):
|
||||
arglist = ['node_uuid']
|
||||
@ -2326,7 +2428,7 @@ class TestRebuildBaremetalProvisionState(TestBaremetal):
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'rebuild',
|
||||
cleansteps=None, deploysteps=None, configdrive=None,
|
||||
rescue_password=None)
|
||||
rescue_password=None, servicesteps=None)
|
||||
|
||||
self.baremetal_mock.node.wait_for_provision_state.assert_not_called()
|
||||
|
||||
@ -2444,7 +2546,7 @@ class TestUnrescueBaremetalProvisionState(TestBaremetal):
|
||||
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'unrescue', cleansteps=None, deploysteps=None,
|
||||
configdrive=None, rescue_password=None)
|
||||
configdrive=None, rescue_password=None, servicesteps=None)
|
||||
|
||||
def test_unrescue_baremetal_provision_state_active_and_wait(self):
|
||||
arglist = ['node_uuid',
|
||||
@ -4559,7 +4661,7 @@ class TestUnholdBaremetalProvisionState(TestBaremetal):
|
||||
|
||||
self.baremetal_mock.node.set_provision_state.assert_called_once_with(
|
||||
'node_uuid', 'unhold', cleansteps=None, deploysteps=None,
|
||||
configdrive=None, rescue_password=None)
|
||||
configdrive=None, rescue_password=None, servicesteps=None)
|
||||
|
||||
|
||||
class TestListFirmwareComponents(TestBaremetal):
|
||||
|
@ -1778,6 +1778,17 @@ class NodeManagerTest(testtools.TestCase):
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
|
||||
def test_node_set_provision_state_with_servicesteps(self):
|
||||
servicesteps = [{"step": "magic", "interface": "deploy"}]
|
||||
target_state = 'service'
|
||||
self.mgr.set_provision_state(NODE1['uuid'], target_state,
|
||||
servicesteps=servicesteps)
|
||||
body = {'target': target_state, 'service_steps': servicesteps}
|
||||
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'
|
||||
|
@ -723,7 +723,8 @@ 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, deploysteps=None):
|
||||
global_request_id=None, deploysteps=None,
|
||||
servicesteps=None):
|
||||
"""Set the provision state for the node.
|
||||
|
||||
:param node_uuid: The UUID or name of the node.
|
||||
@ -757,6 +758,10 @@ class NodeManager(base.CreateManager):
|
||||
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'.
|
||||
:param servicesteps: The service steps as list of service-step
|
||||
dictionaries; each dictonary should have keys 'interface', 'step',
|
||||
and optional key 'args' when setting an 'active' nodes to
|
||||
'service'.
|
||||
:raises: InvalidAttribute if there was an error with the clean steps or
|
||||
deploy steps
|
||||
:returns: The status of the request
|
||||
@ -794,6 +799,9 @@ class NodeManager(base.CreateManager):
|
||||
if deploysteps:
|
||||
body['deploy_steps'] = deploysteps
|
||||
|
||||
if servicesteps:
|
||||
body['service_steps'] = servicesteps
|
||||
|
||||
return self.update(path, body, http_method='PUT',
|
||||
os_ironic_api_version=os_ironic_api_version,
|
||||
global_request_id=global_request_id)
|
||||
|
@ -47,6 +47,8 @@ PROVISION_ACTIONS = {
|
||||
'poll_interval': _LONG_ACTION_POLL_INTERVAL},
|
||||
'unrescue': {'expected_state': 'active',
|
||||
'poll_interval': _LONG_ACTION_POLL_INTERVAL},
|
||||
'service': {'expected_state': 'active',
|
||||
'poll_interval': _LONG_ACTION_POLL_INTERVAL},
|
||||
}
|
||||
|
||||
PROVISION_STATES = list(PROVISION_ACTIONS)
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Increments the supported API version to 1.87.
|
||||
- |
|
||||
Adds the ability to request Ironic execute service steps upon an
|
||||
``active`` node, utilizing the ``baremetal node service`` command.
|
@ -93,6 +93,7 @@ openstack.baremetal.v1 =
|
||||
baremetal_node_rescue = ironicclient.osc.v1.baremetal_node:RescueBaremetalNode
|
||||
baremetal_node_secure_boot_on = ironicclient.osc.v1.baremetal_node:SecurebootOnBaremetalNode
|
||||
baremetal_node_secure_boot_off = ironicclient.osc.v1.baremetal_node:SecurebootOffBaremetalNode
|
||||
baremetal_node_service = ironicclient.osc.v1.baremetal_node:ServiceBaremetalNode
|
||||
baremetal_node_set = ironicclient.osc.v1.baremetal_node:SetBaremetalNode
|
||||
baremetal_node_show = ironicclient.osc.v1.baremetal_node:ShowBaremetalNode
|
||||
baremetal_node_trait_list = ironicclient.osc.v1.baremetal_node:ListTraitsBaremetalNode
|
||||
|
Loading…
Reference in New Issue
Block a user