Add 'overcloud node discover' command
This is the frontend for discover_and_enroll_nodes workflow. Change-Id: I822ec89add3742020262c091e79ff94f92ef92e7 Depends-On: I158f0b8f5251d9d94e7e57b3fe24362316d26599 Implements: blueprint node-discovery-by-range
This commit is contained in:
parent
933b4fa422
commit
c86212cb76
5
releasenotes/notes/ipmi-discovery-aaee9fb7082ffac4.yaml
Normal file
5
releasenotes/notes/ipmi-discovery-aaee9fb7082ffac4.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Add new command ``openstack overcloud node discover`` for nodes discovery
|
||||||
|
by probing a range of IP addresses for accessible BMCs.
|
@ -76,6 +76,7 @@ openstack.tripleoclient.v1 =
|
|||||||
overcloud_node_import = tripleoclient.v1.overcloud_node:ImportNode
|
overcloud_node_import = tripleoclient.v1.overcloud_node:ImportNode
|
||||||
overcloud_node_introspect = tripleoclient.v1.overcloud_node:IntrospectNode
|
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_node_discover = tripleoclient.v1.overcloud_node:DiscoverNode
|
||||||
overcloud_parameters_set = tripleoclient.v1.overcloud_parameters:SetParameters
|
overcloud_parameters_set = tripleoclient.v1.overcloud_parameters:SetParameters
|
||||||
overcloud_plan_create = tripleoclient.v1.overcloud_plan:CreatePlan
|
overcloud_plan_create = tripleoclient.v1.overcloud_plan:CreatePlan
|
||||||
overcloud_plan_delete = tripleoclient.v1.overcloud_plan:DeletePlan
|
overcloud_plan_delete = tripleoclient.v1.overcloud_plan:DeletePlan
|
||||||
|
@ -639,3 +639,100 @@ class TestConfigureNode(fakes.TestOvercloudNode):
|
|||||||
'tripleo.baremetal.v1.configure',
|
'tripleo.baremetal.v1.configure',
|
||||||
workflow_input=self.workflow_input
|
workflow_input=self.workflow_input
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestDiscoverNode(fakes.TestOvercloudNode):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestDiscoverNode, self).setUp()
|
||||||
|
|
||||||
|
self.workflow = self.app.client_manager.workflow_engine
|
||||||
|
client = self.app.client_manager.tripleoclient
|
||||||
|
self.websocket = client.messaging_websocket()
|
||||||
|
|
||||||
|
self.cmd = overcloud_node.DiscoverNode(self.app, None)
|
||||||
|
|
||||||
|
self.websocket.wait_for_messages.return_value = [{
|
||||||
|
"status": "SUCCESS",
|
||||||
|
"message": "Success",
|
||||||
|
"registered_nodes": [{
|
||||||
|
"uuid": "MOCK_NODE_UUID"
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
|
||||||
|
def test_with_ip_range(self):
|
||||||
|
argslist = ['--range', '10.0.0.0/24',
|
||||||
|
'--credentials', 'admin:password']
|
||||||
|
verifylist = [('ip_addresses', '10.0.0.0/24'),
|
||||||
|
('credentials', ['admin:password'])]
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(self.cmd, argslist, verifylist)
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
self.workflow.executions.create.assert_called_once_with(
|
||||||
|
'tripleo.baremetal.v1.discover_and_enroll_nodes',
|
||||||
|
workflow_input={'ip_addresses': '10.0.0.0/24',
|
||||||
|
'credentials': [['admin', 'password']],
|
||||||
|
'queue_name': mock.ANY,
|
||||||
|
'kernel_name': 'bm-deploy-kernel',
|
||||||
|
'ramdisk_name': 'bm-deploy-ramdisk',
|
||||||
|
'instance_boot_option': 'local'}
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_with_address_list(self):
|
||||||
|
argslist = ['--ip', '10.0.0.1', '--ip', '10.0.0.2',
|
||||||
|
'--credentials', 'admin:password']
|
||||||
|
verifylist = [('ip_addresses', ['10.0.0.1', '10.0.0.2']),
|
||||||
|
('credentials', ['admin:password'])]
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(self.cmd, argslist, verifylist)
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
self.workflow.executions.create.assert_called_once_with(
|
||||||
|
'tripleo.baremetal.v1.discover_and_enroll_nodes',
|
||||||
|
workflow_input={'ip_addresses': ['10.0.0.1', '10.0.0.2'],
|
||||||
|
'credentials': [['admin', 'password']],
|
||||||
|
'queue_name': mock.ANY,
|
||||||
|
'kernel_name': 'bm-deploy-kernel',
|
||||||
|
'ramdisk_name': 'bm-deploy-ramdisk',
|
||||||
|
'instance_boot_option': 'local'}
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_with_all_options(self):
|
||||||
|
argslist = ['--range', '10.0.0.0/24',
|
||||||
|
'--credentials', 'admin:password',
|
||||||
|
'--credentials', 'admin2:password2',
|
||||||
|
'--port', '623', '--port', '6230',
|
||||||
|
'--introspect', '--provide', '--run-validations',
|
||||||
|
'--no-deploy-image', '--instance-boot-option', 'netboot']
|
||||||
|
verifylist = [('ip_addresses', '10.0.0.0/24'),
|
||||||
|
('credentials', ['admin:password', 'admin2:password2']),
|
||||||
|
('port', [623, 6230]),
|
||||||
|
('introspect', True),
|
||||||
|
('run_validations', True),
|
||||||
|
('provide', True),
|
||||||
|
('no_deploy_image', True),
|
||||||
|
('instance_boot_option', 'netboot')]
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(self.cmd, argslist, verifylist)
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
workflows_calls = [
|
||||||
|
mock.call('tripleo.baremetal.v1.discover_and_enroll_nodes',
|
||||||
|
workflow_input={'ip_addresses': '10.0.0.0/24',
|
||||||
|
'credentials': [['admin', 'password'],
|
||||||
|
['admin2', 'password2']],
|
||||||
|
'ports': [623, 6230],
|
||||||
|
'queue_name': mock.ANY,
|
||||||
|
'kernel_name': None,
|
||||||
|
'ramdisk_name': None,
|
||||||
|
'instance_boot_option': 'netboot'}),
|
||||||
|
mock.call('tripleo.baremetal.v1.introspect',
|
||||||
|
workflow_input={'node_uuids': ['MOCK_NODE_UUID'],
|
||||||
|
'run_validations': True,
|
||||||
|
'queue_name': mock.ANY}),
|
||||||
|
mock.call('tripleo.baremetal.v1.provide',
|
||||||
|
workflow_input={'node_uuids': ['MOCK_NODE_UUID'],
|
||||||
|
'queue_name': mock.ANY}),
|
||||||
|
]
|
||||||
|
self.workflow.executions.create.assert_has_calls(workflows_calls)
|
||||||
|
@ -316,3 +316,83 @@ class ConfigureNode(command.Command):
|
|||||||
overwrite_root_device_hints=(
|
overwrite_root_device_hints=(
|
||||||
parsed_args.overwrite_root_device_hints)
|
parsed_args.overwrite_root_device_hints)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DiscoverNode(command.Command):
|
||||||
|
"""Discover overcloud nodes by polling their BMCs."""
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__ + ".DiscoverNode")
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(DiscoverNode, self).get_parser(prog_name)
|
||||||
|
ip_group = parser.add_mutually_exclusive_group(required=True)
|
||||||
|
ip_group.add_argument('--ip', action='append',
|
||||||
|
dest='ip_addresses', metavar='<ips>',
|
||||||
|
help=_('IP address(es) to probe'))
|
||||||
|
ip_group.add_argument('--range', dest='ip_addresses',
|
||||||
|
metavar='<range>', help=_('IP range to probe'))
|
||||||
|
parser.add_argument('--credentials', metavar='<key:value>',
|
||||||
|
action='append', required=True,
|
||||||
|
help=_('Key/value pairs of possible credentials'))
|
||||||
|
parser.add_argument('--port', action='append', metavar='<ports>',
|
||||||
|
type=int, help=_('BMC port(s) to probe'))
|
||||||
|
parser.add_argument('--introspect', action='store_true',
|
||||||
|
help=_('Introspect the imported nodes'))
|
||||||
|
parser.add_argument('--run-validations', action='store_true',
|
||||||
|
default=False,
|
||||||
|
help=_('Run the pre-deployment validations. These '
|
||||||
|
'external validations are from the TripleO '
|
||||||
|
'Validations project.'))
|
||||||
|
parser.add_argument('--provide', action='store_true',
|
||||||
|
help=_('Provide (make available) the nodes'))
|
||||||
|
parser.add_argument('--no-deploy-image', action='store_true',
|
||||||
|
help=_('Skip setting the deploy kernel and '
|
||||||
|
'ramdisk.'))
|
||||||
|
parser.add_argument('--instance-boot-option',
|
||||||
|
choices=['local', 'netboot'], default='local',
|
||||||
|
help=_('Whether to set instances for booting from '
|
||||||
|
'local hard drive (local) or network '
|
||||||
|
'(netboot).'))
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
self.log.debug("take_action(%s)" % parsed_args)
|
||||||
|
|
||||||
|
queue_name = str(uuid.uuid4())
|
||||||
|
|
||||||
|
if parsed_args.no_deploy_image:
|
||||||
|
deploy_kernel = None
|
||||||
|
deploy_ramdisk = None
|
||||||
|
else:
|
||||||
|
deploy_kernel = 'bm-deploy-kernel'
|
||||||
|
deploy_ramdisk = 'bm-deploy-ramdisk'
|
||||||
|
|
||||||
|
credentials = [list(x.split(':', 1)) for x in parsed_args.credentials]
|
||||||
|
kwargs = {}
|
||||||
|
# Leave it up to the workflow to figure out the defaults
|
||||||
|
if parsed_args.port:
|
||||||
|
kwargs['ports'] = parsed_args.port
|
||||||
|
|
||||||
|
nodes = baremetal.discover_and_enroll(
|
||||||
|
self.app.client_manager,
|
||||||
|
ip_addresses=parsed_args.ip_addresses,
|
||||||
|
credentials=credentials,
|
||||||
|
queue_name=queue_name,
|
||||||
|
kernel_name=deploy_kernel,
|
||||||
|
ramdisk_name=deploy_ramdisk,
|
||||||
|
instance_boot_option=parsed_args.instance_boot_option,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
nodes_uuids = [node['uuid'] for node in nodes]
|
||||||
|
|
||||||
|
if parsed_args.introspect:
|
||||||
|
baremetal.introspect(self.app.client_manager,
|
||||||
|
node_uuids=nodes_uuids,
|
||||||
|
run_validations=parsed_args.run_validations,
|
||||||
|
queue_name=queue_name)
|
||||||
|
|
||||||
|
if parsed_args.provide:
|
||||||
|
baremetal.provide(self.app.client_manager,
|
||||||
|
node_uuids=nodes_uuids,
|
||||||
|
queue_name=queue_name)
|
||||||
|
@ -296,3 +296,34 @@ def create_raid_configuration(clients, **workflow_input):
|
|||||||
else:
|
else:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
'Failed to create RAID: {}'.format(payload['message']))
|
'Failed to create RAID: {}'.format(payload['message']))
|
||||||
|
|
||||||
|
|
||||||
|
def discover_and_enroll(clients, **workflow_input):
|
||||||
|
"""Discover nodes.
|
||||||
|
|
||||||
|
Run the tripleo.baremetal.v1.discover_and_enroll_nodes Mistral workflow.
|
||||||
|
"""
|
||||||
|
|
||||||
|
workflow_client = clients.workflow_engine
|
||||||
|
tripleoclients = clients.tripleoclient
|
||||||
|
queue_name = workflow_input['queue_name']
|
||||||
|
|
||||||
|
with tripleoclients.messaging_websocket(queue_name) as ws:
|
||||||
|
execution = base.start_workflow(
|
||||||
|
workflow_client,
|
||||||
|
'tripleo.baremetal.v1.discover_and_enroll_nodes',
|
||||||
|
workflow_input=workflow_input
|
||||||
|
)
|
||||||
|
|
||||||
|
for payload in base.wait_for_messages(workflow_client, ws, execution):
|
||||||
|
if payload.get('message'):
|
||||||
|
print(payload['message'])
|
||||||
|
|
||||||
|
if payload['status'] == 'SUCCESS':
|
||||||
|
registered_nodes = payload['registered_nodes']
|
||||||
|
for nd in registered_nodes:
|
||||||
|
print('Successfully registered node UUID %s' % nd['uuid'])
|
||||||
|
return registered_nodes
|
||||||
|
else:
|
||||||
|
raise exceptions.RegisterOrUpdateError(
|
||||||
|
'Exception discovering nodes: {}'.format(payload['message']))
|
||||||
|
Loading…
Reference in New Issue
Block a user