Report node availability from "overcloud profiles list"

Closes-Bug: #1714965
Change-Id: Ic40b40050e87a450f88963ac88a1e06f323d2396
This commit is contained in:
Dmitry Tantsur 2017-09-04 16:38:16 +02:00
parent 4e366ec76c
commit 7bde737ab8
3 changed files with 104 additions and 14 deletions

View File

@ -0,0 +1,13 @@
---
features:
- |
Add ``--all`` argument to the ``overcloud profiles list`` command to
also display nodes that cannot be deployed on. A new ``Error`` column
is displayed when this argument is provided.
fixes:
- |
Exclude from the output of ``overcloud profiles list`` nodes that:
* have error power state
* do not have a matching hypervisor request
* have their compute service down.

View File

@ -102,23 +102,42 @@ class TestListProfiles(test_plugin.TestPluginV1):
self.cmd = overcloud_profiles.ListProfiles(self.app, None)
self.app.client_manager.tripleoclient = mock.Mock()
self.app.client_manager.baremetal = mock.Mock()
self.app.client_manager.compute = mock.Mock()
self.nodes = [
mock.Mock(uuid='uuid1', provision_state='active',
properties={}),
properties={}, maintenance=False),
mock.Mock(uuid='uuid2', provision_state='enroll',
properties={'capabilities': 'profile:compute'}),
properties={'capabilities': 'profile:compute'},
maintenance=False),
mock.Mock(uuid='uuid3', provision_state='available',
properties={'capabilities': 'profile:compute,'
'compute_profile:1,control_profile:true'}),
'compute_profile:1,control_profile:true'},
maintenance=False),
mock.Mock(uuid='uuid4', provision_state='available',
properties={'capabilities': 'profile:compute,'
'compute_profile:0'}),
'compute_profile:0'}, maintenance=False),
mock.Mock(uuid='uuid5', provision_state='available',
properties={}, maintenance=False),
mock.Mock(uuid='uuid6', provision_state='available',
properties={}, maintenance=False),
mock.Mock(uuid='uuid7', provision_state='active',
properties={}, maintenance=True),
]
self.hypervisors = [
mock.Mock(hypervisor_type='ironic',
hypervisor_hostname='uuid%d' % i,
status='enabled', state='up')
for i in range(1, 6)
]
self.hypervisors[-1].status = 'disabled'
self.bm_client = self.app.client_manager.baremetal
self.bm_client.node.list.return_value = self.nodes
self.compute_client = self.app.client_manager.compute
self.compute_client.hypervisors.list.return_value = self.hypervisors
def test_list(self):
result = self.cmd.take_action(None)
parsed_args = self.check_parser(self.cmd, [], [])
result = self.cmd.take_action(parsed_args)
self.assertEqual(5, len(result[0]))
self.assertEqual(
[('uuid1', self.nodes[0].name, 'active', None, ''),
@ -126,3 +145,22 @@ class TestListProfiles(test_plugin.TestPluginV1):
'compute, control'),
('uuid4', self.nodes[3].name, 'available', 'compute', '')],
result[1])
def test_all(self):
parsed_args = self.check_parser(self.cmd, ['--all'], [('all', True)])
result = self.cmd.take_action(parsed_args)
self.assertEqual(6, len(result[0]))
self.assertEqual(
[('uuid1', self.nodes[0].name, 'active', None, '', ''),
('uuid2', self.nodes[1].name, 'enroll', 'compute', '',
'Provision state enroll'),
('uuid3', self.nodes[2].name, 'available', 'compute',
'compute, control', ''),
('uuid4', self.nodes[3].name, 'available', 'compute', '', ''),
('uuid5', self.nodes[4].name, 'available', None, '',
'Compute service disabled'),
('uuid6', self.nodes[5].name, 'available', None, '',
'No hypervisor record'),
('uuid7', self.nodes[6].name, 'active', None, '',
'Maintenance')],
result[1])

View File

@ -90,14 +90,49 @@ class ListProfiles(command.Lister):
log = logging.getLogger(__name__ + ".ListProfiles")
def get_parser(self, prog_name):
parser = super(ListProfiles, self).get_parser(prog_name)
parser.add_argument(
'--all',
action='store_true',
default=False,
help=_('List all nodes, even those not available to Nova.')
)
utils.add_deployment_plan_arguments(parser)
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)" % parsed_args)
client = self.app.client_manager.baremetal
bm_client = self.app.client_manager.baremetal
compute_client = self.app.client_manager.compute
hypervisors = {h.hypervisor_hostname: h
for h in compute_client.hypervisors.list()
if h.hypervisor_type == 'ironic'}
result = []
for node in client.node.list(detail=True, maintenance=False):
maintenance = None if parsed_args.all else False
for node in bm_client.node.list(detail=True, maintenance=maintenance):
error = ''
if node.provision_state not in ('active', 'available'):
error = "Provision state %s" % node.provision_state
elif node.power_state in (None, 'error'):
error = "Power state %s" % node.power_state
elif node.maintenance:
error = "Maintenance"
else:
try:
hypervisor = hypervisors[node.uuid]
except KeyError:
error = 'No hypervisor record'
else:
if hypervisor.status != 'enabled':
error = 'Compute service disabled'
elif hypervisor.state != 'up':
error = 'Compute service down'
if error and not parsed_args.all:
continue
caps = utils.node_get_capabilities(node)
@ -108,11 +143,15 @@ class ListProfiles(command.Lister):
v.lower() in ('1', 'true')]
# sorting for convenient display and testing
possible_profiles.sort()
result.append((node.uuid, node.name or '', node.provision_state,
profile, ', '.join(possible_profiles)))
return (
("Node UUID", "Node Name", "Provision State", "Current Profile",
"Possible Profiles"),
result
)
record = (node.uuid, node.name or '', node.provision_state,
profile, ', '.join(possible_profiles))
if parsed_args.all:
record += (error,)
result.append(record)
cols = ("Node UUID", "Node Name", "Provision State", "Current Profile",
"Possible Profiles")
if parsed_args.all:
cols += ('Error',)
return (cols, result)