Merge "New discover command to add new hosts to a cell"

This commit is contained in:
Jenkins
2016-08-30 14:21:09 +00:00
committed by Gerrit Code Review
3 changed files with 184 additions and 0 deletions

View File

@@ -1478,6 +1478,39 @@ class CellV2Commands(object):
mapping.cell_mapping.uuid))
return 0
@args('--cell_uuid', metavar='<cell_uuid>', dest='cell_uuid',
help='If provided only this cell will be searched for new hosts to '
'map.')
def discover_hosts(self, cell_uuid=None):
"""Searches cells, or a single cell, and maps found hosts.
When a new host is added to a deployment it will add a service entry
to the db it's configured to use. This command will check the db for
each cell, or a single one if passed in, and map any hosts which are
not currently mapped. If a host is already mapped nothing will be done.
"""
ctxt = context.RequestContext()
if cell_uuid:
cell_mappings = [objects.CellMapping.get_by_uuid(ctxt, cell_uuid)]
else:
cell_mappings = objects.CellMappingList.get_all(context)
for cell_mapping in cell_mappings:
# TODO(alaski): Factor this into helper method on CellMapping
if cell_mapping.uuid == cell_mapping.CELL0_UUID:
continue
with context.target_cell(ctxt, cell_mapping):
compute_nodes = objects.ComputeNodeList.get_all(ctxt)
for compute in compute_nodes:
try:
objects.HostMapping.get_by_host(ctxt, compute.host)
except exception.HostMappingNotFound:
host_mapping = objects.HostMapping(
ctxt, host=compute.host,
cell_mapping=cell_mapping)
host_mapping.create()
CATEGORIES = {
'account': AccountCommands,

View File

@@ -1210,3 +1210,129 @@ class CellV2CommandsTestCase(test.TestCase):
# and reasonably verify that path
self.assertEqual(1, self.commands.verify_instance(uuidsentinel.foo,
quiet=True))
def _return_compute_nodes(self, ctxt, num=1):
nodes = []
for i in range(num):
nodes.append(objects.ComputeNode(ctxt,
uuid=uuidutils.generate_uuid(),
host='fake',
vcpus=1,
memory_mb=1,
local_gb=1,
vcpus_used=0,
memory_mb_used=0,
local_gb_used=0,
hypervisor_type='',
hypervisor_version=1,
cpu_info=''))
return nodes
@mock.patch.object(context, 'target_cell')
@mock.patch.object(objects, 'HostMapping')
@mock.patch.object(objects.ComputeNodeList, 'get_all')
@mock.patch.object(objects.CellMappingList, 'get_all')
@mock.patch.object(objects.CellMapping, 'get_by_uuid')
def test_discover_hosts_single_cell(self, mock_cell_mapping_get_by_uuid,
mock_cell_mapping_get_all,
mock_compute_get_all,
mock_host_mapping, mock_target_cell):
host_mock = mock.MagicMock()
mock_host_mapping.return_value = host_mock
exc = exception.HostMappingNotFound(name='fake')
mock_host_mapping.get_by_host.side_effect = exc
ctxt = context.RequestContext()
compute_nodes = self._return_compute_nodes(ctxt)
mock_compute_get_all.return_value = objects.ComputeNodeList(
objects=compute_nodes)
cell_mapping = objects.CellMapping(uuid=uuidutils.generate_uuid())
mock_cell_mapping_get_by_uuid.return_value = cell_mapping
self.commands.discover_hosts(cell_uuid=cell_mapping.uuid)
mock_target_cell.assert_called_once_with(
test.MatchType(context.RequestContext), cell_mapping)
host_mock.create.assert_called_once()
mock_host_mapping.assert_called_once_with(
test.MatchType(context.RequestContext), host='fake',
cell_mapping=cell_mapping)
mock_cell_mapping_get_all.assert_not_called()
@mock.patch.object(context, 'target_cell')
@mock.patch.object(objects, 'HostMapping')
@mock.patch.object(objects.ComputeNodeList, 'get_all')
@mock.patch.object(objects.CellMappingList, 'get_all')
@mock.patch.object(objects.CellMapping, 'get_by_uuid')
def test_discover_hosts_single_cell_no_new_hosts(
self, mock_cell_mapping_get_by_uuid, mock_cell_mapping_get_all,
mock_compute_get_all, mock_host_mapping, mock_target_cell):
host_mock = mock.MagicMock()
mock_host_mapping.return_value = host_mock
ctxt = context.RequestContext()
compute_nodes = self._return_compute_nodes(ctxt)
mock_compute_get_all.return_value = objects.ComputeNodeList(
objects=compute_nodes)
cell_mapping = objects.CellMapping(uuid=uuidutils.generate_uuid())
mock_cell_mapping_get_by_uuid.return_value = cell_mapping
self.commands.discover_hosts(cell_uuid=cell_mapping.uuid)
mock_target_cell.assert_called_once_with(
test.MatchType(context.RequestContext), cell_mapping)
mock_host_mapping.assert_not_called()
mock_cell_mapping_get_all.assert_not_called()
@mock.patch.object(context, 'target_cell')
@mock.patch.object(objects, 'HostMapping')
@mock.patch.object(objects.ComputeNodeList, 'get_all')
@mock.patch.object(objects.CellMappingList, 'get_all')
@mock.patch.object(objects.CellMapping, 'get_by_uuid')
def test_discover_hosts_multiple_cells(self, mock_cell_mapping_get_by_uuid,
mock_cell_mapping_get_all,
mock_compute_get_all,
mock_host_mapping,
mock_target_cell):
host_mock = mock.MagicMock()
mock_host_mapping.return_value = host_mock
exc = exception.HostMappingNotFound(name='fake')
mock_host_mapping.get_by_host.side_effect = exc
ctxt = context.RequestContext()
compute_nodes = self._return_compute_nodes(ctxt, num=2)
mock_compute_get_all.side_effect = (
objects.ComputeNodeList(objects=compute_nodes[1:]),
objects.ComputeNodeList(objects=compute_nodes[:1]))
cell_mapping1 = objects.CellMapping(uuid=uuidutils.generate_uuid())
cell_mapping2 = objects.CellMapping(uuid=uuidutils.generate_uuid())
mock_cell_mapping_get_all.return_value = objects.CellMappingList(
objects=[cell_mapping1, cell_mapping2])
self.commands.discover_hosts()
self.assertEqual(2, mock_target_cell.call_count)
target_calls = [mock.call(test.MatchType(context.RequestContext),
cell_mapping1),
mock.call(test.MatchType(context.RequestContext),
cell_mapping2)]
self.assertEqual(target_calls, mock_target_cell.call_args_list)
self.assertEqual(2, host_mock.create.call_count)
self.assertEqual(2, mock_host_mapping.call_count)
host_mapping_calls = [mock.call(test.MatchType(context.RequestContext),
host=compute_nodes[0].host,
cell_mapping=cell_mapping1),
mock.call(test.MatchType(context.RequestContext),
host=compute_nodes[1].host,
cell_mapping=cell_mapping2)]
self.assertEqual(host_mapping_calls, mock_host_mapping.call_args_list)
mock_cell_mapping_get_by_uuid.assert_not_called()

View File

@@ -0,0 +1,25 @@
---
features:
- A new nova-manage command has been added to discover any new hosts that are
added to a cell. If a deployment has migrated to cellsv2 using either the
simple_cell_setup or the map_cell0/map_cell_and_hosts/map_instances combo
then anytime a new host is added to a cell this new
"nova-manage cell_v2 discover_hosts" needs to be run before instances can
be booted on that host. If multiple hosts are added at one time the command
only needs to be run one time to discover all of them.
Please note that adding a host to a cell and not running this command could
lead to build failures/reschedules if that host is selected by the
scheduler. The discover_hosts command is necessary to route requests to the
host but is not necessary in order for the scheduler to be aware of the
host. In order to avoid that it is advised that new compute hosts are
disabled until the discover command has been run.
issues:
- If a deployer has updated their deployment to using cellsv2 using either
the simple_cell_setup or the map_cell0/map_cell_and_hosts/map_instances
combo and they add a new host into the cell it may cause build failures
or reschedules until they run the "nova-manage cell_v2 discover_hosts"
command. This is because the scheduler will quickly become aware of the
host but nova-api will not know how to route the request to that host until
it has been "discovered". In order to avoid that it is advised that
new computes are disabled until the discover command has been run.