Add 'openstack overcloud node introspect' command
Change-Id: I1c58d9c825543cf402ff417d1fd05e89759e3ecd Partial-Bug: #1595205
This commit is contained in:
@@ -67,6 +67,7 @@ openstack.tripleoclient.v1 =
|
|||||||
overcloud_image_build = tripleoclient.v1.overcloud_image:BuildOvercloudImage
|
overcloud_image_build = tripleoclient.v1.overcloud_image:BuildOvercloudImage
|
||||||
overcloud_image_upload = tripleoclient.v1.overcloud_image:UploadOvercloudImage
|
overcloud_image_upload = tripleoclient.v1.overcloud_image:UploadOvercloudImage
|
||||||
overcloud_node_delete = tripleoclient.v1.overcloud_node:DeleteNode
|
overcloud_node_delete = tripleoclient.v1.overcloud_node:DeleteNode
|
||||||
|
overcloud_node_introspect = tripleoclient.v1.overcloud_node:IntrospectNode
|
||||||
overcloud_node_provide = tripleoclient.v1.overcloud_node:ProvideNode
|
overcloud_node_provide = tripleoclient.v1.overcloud_node:ProvideNode
|
||||||
overcloud_profiles_match = tripleoclient.v1.overcloud_profiles:MatchProfiles
|
overcloud_profiles_match = tripleoclient.v1.overcloud_profiles:MatchProfiles
|
||||||
overcloud_profiles_list = tripleoclient.v1.overcloud_profiles:ListProfiles
|
overcloud_profiles_list = tripleoclient.v1.overcloud_profiles:ListProfiles
|
||||||
|
|||||||
@@ -128,3 +128,109 @@ class TestProvideNode(fakes.TestOvercloudNode):
|
|||||||
self.assertRaises(test_utils.ParserException,
|
self.assertRaises(test_utils.ParserException,
|
||||||
self.check_parser,
|
self.check_parser,
|
||||||
self.cmd, argslist, verifylist)
|
self.cmd, argslist, verifylist)
|
||||||
|
|
||||||
|
|
||||||
|
class TestIntrospectNode(fakes.TestOvercloudNode):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestIntrospectNode, self).setUp()
|
||||||
|
|
||||||
|
self.workflow = self.app.client_manager.workflow_engine
|
||||||
|
client = self.app.client_manager.tripleoclient
|
||||||
|
self.websocket = client.messaging_websocket()
|
||||||
|
|
||||||
|
# Get the command object to test
|
||||||
|
self.cmd = overcloud_node.IntrospectNode(self.app, None)
|
||||||
|
|
||||||
|
def _check_introspect_all_manageable(self, parsed_args, provide=False):
|
||||||
|
self.websocket.wait_for_message.return_value = {
|
||||||
|
"status": "SUCCESS",
|
||||||
|
"message": "Success",
|
||||||
|
"introspected_nodes": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
call_list = [mock.call(
|
||||||
|
'tripleo.baremetal.v1.introspect_manageable_nodes',
|
||||||
|
workflow_input={'queue_name': 'UUID4'}
|
||||||
|
)]
|
||||||
|
|
||||||
|
if provide:
|
||||||
|
call_list.append(mock.call(
|
||||||
|
'tripleo.baremetal.v1.provide_manageable_nodes',
|
||||||
|
workflow_input={'queue_name': 'UUID4'}
|
||||||
|
))
|
||||||
|
|
||||||
|
self.workflow.executions.create.assert_has_calls(call_list)
|
||||||
|
self.assertEqual(self.workflow.executions.create.call_count,
|
||||||
|
2 if provide else 1)
|
||||||
|
|
||||||
|
def _check_introspect_nodes(self, parsed_args, nodes, provide=False):
|
||||||
|
self.websocket.wait_for_message.return_value = {
|
||||||
|
"status": "SUCCESS",
|
||||||
|
"message": "Success",
|
||||||
|
"introspected_nodes": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
call_list = [mock.call(
|
||||||
|
'tripleo.baremetal.v1.introspect', workflow_input={
|
||||||
|
'node_uuids': nodes,
|
||||||
|
'queue_name': 'UUID4'}
|
||||||
|
)]
|
||||||
|
|
||||||
|
if provide:
|
||||||
|
call_list.append(mock.call(
|
||||||
|
'tripleo.baremetal.v1.provide', workflow_input={
|
||||||
|
'node_uuids': nodes,
|
||||||
|
'queue_name': 'UUID4'}
|
||||||
|
))
|
||||||
|
|
||||||
|
self.workflow.executions.create.assert_has_calls(call_list)
|
||||||
|
self.assertEqual(self.workflow.executions.create.call_count,
|
||||||
|
2 if provide else 1)
|
||||||
|
|
||||||
|
def test_introspect_all_manageable_nodes_without_provide(self):
|
||||||
|
parsed_args = self.check_parser(self.cmd,
|
||||||
|
['--all-manageable'],
|
||||||
|
[('all_manageable', True)])
|
||||||
|
self._check_introspect_all_manageable(parsed_args, provide=False)
|
||||||
|
|
||||||
|
def test_introspect_all_manageable_nodes_with_provide(self):
|
||||||
|
parsed_args = self.check_parser(self.cmd,
|
||||||
|
['--all-manageable', '--provide'],
|
||||||
|
[('all_manageable', True),
|
||||||
|
('provide', True)])
|
||||||
|
self._check_introspect_all_manageable(parsed_args, provide=True)
|
||||||
|
|
||||||
|
def test_introspect_nodes_without_provide(self):
|
||||||
|
nodes = ['node_uuid1', 'node_uuid2']
|
||||||
|
parsed_args = self.check_parser(self.cmd,
|
||||||
|
nodes,
|
||||||
|
[('node_uuids', nodes)])
|
||||||
|
self._check_introspect_nodes(parsed_args, nodes, provide=False)
|
||||||
|
|
||||||
|
def test_introspect_nodes_with_provide(self):
|
||||||
|
nodes = ['node_uuid1', 'node_uuid2']
|
||||||
|
argslist = nodes + ['--provide']
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(self.cmd,
|
||||||
|
argslist,
|
||||||
|
[('node_uuids', nodes),
|
||||||
|
('provide', True)])
|
||||||
|
self._check_introspect_nodes(parsed_args, nodes, provide=True)
|
||||||
|
|
||||||
|
def test_introspect_no_node_or_flag_specified(self):
|
||||||
|
self.assertRaises(test_utils.ParserException,
|
||||||
|
self.check_parser,
|
||||||
|
self.cmd, [], [])
|
||||||
|
|
||||||
|
def test_introspect_uuids_and_all_both_specified(self):
|
||||||
|
argslist = ['node_id1', 'node_id2', '--all-manageable']
|
||||||
|
verifylist = [('node_uuids', ['node_id1', 'node_id2']),
|
||||||
|
('all_manageable', True)]
|
||||||
|
self.assertRaises(test_utils.ParserException,
|
||||||
|
self.check_parser,
|
||||||
|
self.cmd, argslist, verifylist)
|
||||||
|
|||||||
@@ -120,6 +120,45 @@ class TestBaremetalWorkflows(utils.TestCommand):
|
|||||||
'queue_name': "QUEUE_NAME"
|
'queue_name': "QUEUE_NAME"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def test_introspect_success(self):
|
||||||
|
|
||||||
|
self.websocket.wait_for_message.return_value = {
|
||||||
|
"status": "SUCCESS",
|
||||||
|
"introspected_nodes": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
baremetal.introspect(self.app.client_manager, node_uuids=[],
|
||||||
|
queue_name="QUEUE_NAME")
|
||||||
|
|
||||||
|
self.workflow.executions.create.assert_called_once_with(
|
||||||
|
'tripleo.baremetal.v1.introspect',
|
||||||
|
workflow_input={
|
||||||
|
'node_uuids': [],
|
||||||
|
'queue_name': "QUEUE_NAME"
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_introspect_error(self):
|
||||||
|
|
||||||
|
self.websocket.wait_for_message.return_value = {
|
||||||
|
"status": "FAIL",
|
||||||
|
"message": "Failed",
|
||||||
|
"introspected_nodes": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.IntrospectionError,
|
||||||
|
baremetal.introspect,
|
||||||
|
self.app.client_manager,
|
||||||
|
node_uuids=[],
|
||||||
|
queue_name="QUEUE_NAME")
|
||||||
|
|
||||||
|
self.workflow.executions.create.assert_called_once_with(
|
||||||
|
'tripleo.baremetal.v1.introspect',
|
||||||
|
workflow_input={
|
||||||
|
'node_uuids': [],
|
||||||
|
'queue_name': "QUEUE_NAME"
|
||||||
|
})
|
||||||
|
|
||||||
def test_introspect_manageable_nodes_success(self):
|
def test_introspect_manageable_nodes_success(self):
|
||||||
|
|
||||||
self.websocket.wait_for_message.return_value = {
|
self.websocket.wait_for_message.return_value = {
|
||||||
|
|||||||
@@ -241,13 +241,19 @@ class ImportBaremetal(command.Command):
|
|||||||
|
|
||||||
|
|
||||||
class StartBaremetalIntrospectionBulk(command.Command):
|
class StartBaremetalIntrospectionBulk(command.Command):
|
||||||
"""Start bulk introspection on all baremetal nodes"""
|
"""Start bulk introspection on all baremetal nodes (Deprecated).
|
||||||
|
|
||||||
|
Please use 'openstack overcloud node introspect' instead.
|
||||||
|
"""
|
||||||
|
|
||||||
log = logging.getLogger(__name__ + ".StartBaremetalIntrospectionBulk")
|
log = logging.getLogger(__name__ + ".StartBaremetalIntrospectionBulk")
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
|
|
||||||
self.log.debug("take_action(%s)" % parsed_args)
|
self.log.debug("take_action(%s)" % parsed_args)
|
||||||
|
self.log.warning('This command is deprecated. Please use "openstack '
|
||||||
|
'overcloud node introspect" to introspect manageable '
|
||||||
|
'nodes instead.\n')
|
||||||
|
|
||||||
queue_name = str(uuid.uuid4())
|
queue_name = str(uuid.uuid4())
|
||||||
clients = self.app.client_manager
|
clients = self.app.client_manager
|
||||||
|
|||||||
@@ -98,3 +98,51 @@ class ProvideNode(command.Command):
|
|||||||
else:
|
else:
|
||||||
baremetal.provide_manageable_nodes(self.app.client_manager,
|
baremetal.provide_manageable_nodes(self.app.client_manager,
|
||||||
queue_name=queue_name)
|
queue_name=queue_name)
|
||||||
|
|
||||||
|
|
||||||
|
class IntrospectNode(command.Command):
|
||||||
|
"""Introspect specified nodes or all nodes in 'manageable' state."""
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__ + ".IntrospectNode")
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(IntrospectNode, self).get_parser(prog_name)
|
||||||
|
group = parser.add_mutually_exclusive_group(required=True)
|
||||||
|
group.add_argument('node_uuids',
|
||||||
|
nargs="*",
|
||||||
|
metavar="<node_uuid>",
|
||||||
|
default=[],
|
||||||
|
help=_('Ironic UUIDs for the node(s) to be '
|
||||||
|
'introspected'))
|
||||||
|
group.add_argument("--all-manageable",
|
||||||
|
action='store_true',
|
||||||
|
help=_("Introspect all nodes currently in "
|
||||||
|
"'manageable' state"))
|
||||||
|
parser.add_argument('--provide',
|
||||||
|
action='store_true',
|
||||||
|
help=_('Provide (make available) the nodes once '
|
||||||
|
'introspected'))
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
self.log.debug("take_action(%s)" % parsed_args)
|
||||||
|
|
||||||
|
queue_name = str(uuid.uuid4())
|
||||||
|
nodes = parsed_args.node_uuids
|
||||||
|
|
||||||
|
if nodes:
|
||||||
|
baremetal.introspect(self.app.client_manager,
|
||||||
|
node_uuids=nodes,
|
||||||
|
queue_name=queue_name)
|
||||||
|
else:
|
||||||
|
baremetal.introspect_manageable_nodes(self.app.client_manager,
|
||||||
|
queue_name=queue_name)
|
||||||
|
|
||||||
|
if parsed_args.provide:
|
||||||
|
if nodes:
|
||||||
|
baremetal.provide(self.app.client_manager,
|
||||||
|
node_uuids=nodes,
|
||||||
|
queue_name=queue_name)
|
||||||
|
else:
|
||||||
|
baremetal.provide_manageable_nodes(self.app.client_manager,
|
||||||
|
queue_name=queue_name)
|
||||||
|
|||||||
@@ -70,6 +70,37 @@ def provide(clients, **workflow_input):
|
|||||||
payload['message']))
|
payload['message']))
|
||||||
|
|
||||||
|
|
||||||
|
def introspect(clients, **workflow_input):
|
||||||
|
"""Introspect Baremetal Nodes
|
||||||
|
|
||||||
|
Run the tripleo.baremetal.v1.introspect Mistral workflow.
|
||||||
|
"""
|
||||||
|
|
||||||
|
workflow_client = clients.workflow_engine
|
||||||
|
tripleoclients = clients.tripleoclient
|
||||||
|
queue_name = workflow_input['queue_name']
|
||||||
|
|
||||||
|
execution = workflow_client.executions.create(
|
||||||
|
'tripleo.baremetal.v1.introspect',
|
||||||
|
workflow_input={'node_uuids': workflow_input['node_uuids'],
|
||||||
|
'queue_name': queue_name}
|
||||||
|
)
|
||||||
|
|
||||||
|
print("Waiting for introspection to finish...")
|
||||||
|
|
||||||
|
with tripleoclients.messaging_websocket(queue_name) as ws:
|
||||||
|
payload = ws.wait_for_message(execution.id)
|
||||||
|
|
||||||
|
if payload['status'] == 'SUCCESS':
|
||||||
|
print('Successfully introspected all nodes.')
|
||||||
|
else:
|
||||||
|
raise exceptions.IntrospectionError(
|
||||||
|
"Introspection completed with errors:\n%s" % '\n'
|
||||||
|
.join(msg for msg in payload['message'] if msg))
|
||||||
|
|
||||||
|
print("Introspection completed.")
|
||||||
|
|
||||||
|
|
||||||
def introspect_manageable_nodes(clients, **workflow_input):
|
def introspect_manageable_nodes(clients, **workflow_input):
|
||||||
"""Introspect all manageable nodes
|
"""Introspect all manageable nodes
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user