Add support for listing hosts in cellv2

Add a ``nova-manage cell_v2 list_hosts`` command for listing hosts
in one or all v2 cells.

Change-Id: Ie8eaa8701aafac10e030568107b8e6255a60434d
Closes-Bug: #1735687
This commit is contained in:
Hongbin Lu 2017-12-01 23:03:04 +00:00
parent 81544829d1
commit c7b51a63b0
7 changed files with 150 additions and 7 deletions

View File

@ -215,6 +215,13 @@ Nova Cells v2
found for the cell (cell not empty) without ``--force`` option, and 3
if there are instances mapped to the cell (cell not empty).
``nova-manage cell_v2 list_hosts [--cell_uuid <cell_uuid>]``
Lists the hosts in one or all v2 cells. By default hosts in all v2 cells
are listed. Use the --cell_uuid option to list hosts in a specific cell.
If the cell is not found by uuid, this command will return an exit code
of 1. Otherwise, the exit code will be 0.
``nova-manage cell_v2 update_cell --cell_uuid <cell_uuid> [--name <cell_name>] [--transport-url <transport_url>] [--database_connection <database_connection>]``
Updates the properties of a cell by the given uuid. If a

View File

@ -1837,6 +1837,34 @@ class CellV2Commands(object):
return 0
@args('--cell_uuid', metavar='<cell_uuid>', dest='cell_uuid',
help=_('The uuid of the cell.'))
def list_hosts(self, cell_uuid=None):
"""Lists the hosts in one or all v2 cells."""
ctxt = context.get_admin_context()
if cell_uuid:
# Find the CellMapping given the uuid.
try:
cell_mapping = objects.CellMapping.get_by_uuid(ctxt, cell_uuid)
except exception.CellMappingNotFound:
print(_('Cell with uuid %s was not found.') % cell_uuid)
return 1
host_mappings = objects.HostMappingList.get_by_cell_id(
ctxt, cell_mapping.id)
else:
host_mappings = objects.HostMappingList.get_all(ctxt)
field_names = [_('Cell Name'), _('Cell UUID'), _('Hostname')]
t = prettytable.PrettyTable(field_names)
for host in sorted(host_mappings, key=lambda _host: _host.host):
fields = [host.cell_mapping.name, host.cell_mapping.uuid,
host.host]
t.add_row(fields)
print(t)
return 0
@args('--cell_uuid', metavar='<cell_uuid>', dest='cell_uuid',
required=True, help=_('The uuid of the cell.'))
@args('--host', metavar='<host>', dest='host',

View File

@ -148,7 +148,8 @@ class HostMapping(base.NovaTimestampObject, base.NovaObject):
@base.NovaObjectRegistry.register
class HostMappingList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
VERSION = '1.0'
# Version 1.1: Add get_all method
VERSION = '1.1'
fields = {
'objects': fields.ListOfObjectsField('HostMapping'),
@ -156,14 +157,21 @@ class HostMappingList(base.ObjectListBase, base.NovaObject):
@staticmethod
@db_api.api_context_manager.reader
def _get_by_cell_id_from_db(context, cell_id):
return (context.session.query(api_models.HostMapping)
.options(joinedload('cell_mapping'))
.filter(api_models.HostMapping.cell_id == cell_id)).all()
def _get_from_db(context, cell_id=None):
query = (context.session.query(api_models.HostMapping)
.options(joinedload('cell_mapping')))
if cell_id:
query = query.filter(api_models.HostMapping.cell_id == cell_id)
return query.all()
@base.remotable_classmethod
def get_by_cell_id(cls, context, cell_id):
db_mappings = cls._get_by_cell_id_from_db(context, cell_id)
db_mappings = cls._get_from_db(context, cell_id)
return base.obj_make_list(context, cls(), HostMapping, db_mappings)
@base.remotable_classmethod
def get_all(cls, context):
db_mappings = cls._get_from_db(context)
return base.obj_make_list(context, cls(), HostMapping, db_mappings)

View File

@ -150,6 +150,35 @@ class TestRemoteHostMappingObject(test_objects._RemoteTest,
pass
class _TestHostMappingListObject(object):
def _check_cell_map_value(self, db_val, cell_obj):
self.assertEqual(db_val, cell_obj.id)
@mock.patch.object(host_mapping.HostMappingList, '_get_from_db')
def test_get_all(self, get_from_db):
fake_cell = test_cell_mapping.get_db_mapping(id=1)
db_mapping = get_db_mapping(mapped_cell=fake_cell)
get_from_db.return_value = [db_mapping]
mapping_obj = objects.HostMappingList.get_all(self.context)
get_from_db.assert_called_once_with(self.context)
self.compare_obj(mapping_obj.objects[0], db_mapping,
subs={'cell_mapping': 'cell_id'},
comparators={
'cell_mapping': self._check_cell_map_value})
class TestCellMappingListObject(test_objects._LocalTest,
_TestHostMappingListObject):
pass
class TestRemoteCellMappingListObject(test_objects._RemoteTest,
_TestHostMappingListObject):
pass
class TestHostMappingDiscovery(test.NoDBTestCase):
@mock.patch('nova.objects.CellMappingList.get_all')
@mock.patch('nova.objects.HostMapping.create')

View File

@ -1092,7 +1092,7 @@ object_data = {
'FloatingIP': '1.10-52a67d52d85eb8b3f324a5b7935a335b',
'FloatingIPList': '1.12-e4debd21fddb12cf40d36f737225fa9d',
'HostMapping': '1.0-1a3390a696792a552ab7bd31a77ba9ac',
'HostMappingList': '1.0-267d952a5d48361d6d7604f50775bc34',
'HostMappingList': '1.1-18ac2bfb8c1eb5545bed856da58a79bc',
'HyperVLiveMigrateData': '1.2-bcb6dad687369348ffe0f41da6888704',
'HVSpec': '1.2-de06bcec472a2f04966b855a49c46b41',
'IDEDeviceBus': '1.0-29d4c9f27ac44197f01b6ac1b7e16502',

View File

@ -1813,6 +1813,72 @@ class CellV2CommandsTestCase(test.NoDBTestCase):
output = self.output.getvalue().strip()
self.assertEqual('', output)
def test_list_hosts(self):
ctxt = context.get_admin_context()
# create the cell mapping
cm1 = objects.CellMapping(
context=ctxt, uuid='9e36a3ed-3eb6-4327', name='london',
database_connection='fake:///db', transport_url='fake:///mq')
cm1.create()
cm2 = objects.CellMapping(
context=ctxt, uuid='8a3c608c-b275-496c', name='dallas',
database_connection='fake:///db', transport_url='fake:///mq')
cm2.create()
# create a host mapping in another cell
hm1 = objects.HostMapping(
context=ctxt, host='fake-host-1', cell_mapping=cm1)
hm1.create()
hm2 = objects.HostMapping(
context=ctxt, host='fake-host-2', cell_mapping=cm2)
hm2.create()
self.assertEqual(0, self.commands.list_hosts())
output = self.output.getvalue().strip()
self.assertEqual('''\
+-----------+--------------------+-------------+
| Cell Name | Cell UUID | Hostname |
+-----------+--------------------+-------------+
| london | 9e36a3ed-3eb6-4327 | fake-host-1 |
| dallas | 8a3c608c-b275-496c | fake-host-2 |
+-----------+--------------------+-------------+''',
output)
def test_list_hosts_in_cell(self):
ctxt = context.get_admin_context()
# create the cell mapping
cm1 = objects.CellMapping(
context=ctxt, uuid='9e36a3ed-3eb6-4327', name='london',
database_connection='fake:///db', transport_url='fake:///mq')
cm1.create()
cm2 = objects.CellMapping(
context=ctxt, uuid='8a3c608c-b275-496c', name='dallas',
database_connection='fake:///db', transport_url='fake:///mq')
cm2.create()
# create a host mapping in another cell
hm1 = objects.HostMapping(
context=ctxt, host='fake-host-1', cell_mapping=cm1)
hm1.create()
hm2 = objects.HostMapping(
context=ctxt, host='fake-host-2', cell_mapping=cm2)
hm2.create()
self.assertEqual(0, self.commands.list_hosts(
cell_uuid='9e36a3ed-3eb6-4327'))
output = self.output.getvalue().strip()
self.assertEqual('''\
+-----------+--------------------+-------------+
| Cell Name | Cell UUID | Hostname |
+-----------+--------------------+-------------+
| london | 9e36a3ed-3eb6-4327 | fake-host-1 |
+-----------+--------------------+-------------+''',
output)
def test_list_hosts_cell_not_found(self):
"""Tests trying to delete a host but a specified cell is not found."""
self.assertEqual(1, self.commands.list_hosts(
cell_uuid=uuidsentinel.cell1))
output = self.output.getvalue().strip()
self.assertEqual(
'Cell with uuid %s was not found.' % uuidsentinel.cell1, output)
def test_delete_host_cell_not_found(self):
"""Tests trying to delete a host but a specified cell is not found."""
self.assertEqual(1, self.commands.delete_host(uuidsentinel.cell1,

View File

@ -0,0 +1,5 @@
---
features:
- |
Add a ``nova-manage cell_v2 list_hosts`` command for listing hosts
in one or all v2 cells.