Support for nova-manage placement heal_allocations --cell
Closes-bug: #1868531 Change-Id: I98b3280583a6d12461d8aa52e5714d7606b84369
This commit is contained in:
parent
d016d65cb9
commit
1a39ed9005
@ -546,7 +546,7 @@ Placement
|
||||
|
||||
.. _heal_allocations_cli:
|
||||
|
||||
``nova-manage placement heal_allocations [--max-count <max_count>] [--verbose] [--skip-port-allocations] [--dry-run] [--instance <instance_uuid>]``
|
||||
``nova-manage placement heal_allocations [--max-count <max_count>] [--verbose] [--skip-port-allocations] [--dry-run] [--instance <instance_uuid>] [--cell <cell_uuid]``
|
||||
Iterates over non-cell0 cells looking for instances which do not have
|
||||
allocations in the Placement service and which are not undergoing a task
|
||||
state transition. For each instance found, allocations are created against
|
||||
@ -603,6 +603,9 @@ Placement
|
||||
ports for each instance can be avoided with this flag.
|
||||
*(Since 20.0.0 Train)*
|
||||
|
||||
Specify ``--cell`` to process heal allocations within a specific cell.
|
||||
This is mutually exclusive with the ``--instance`` option.
|
||||
|
||||
This command requires that the
|
||||
:oslo.config:option:`api_database.connection` and
|
||||
:oslo.config:group:`placement` configuration options are set. Placement API
|
||||
|
@ -2089,7 +2089,8 @@ class PlacementCommands(object):
|
||||
'changes. The return code should be 4.')
|
||||
@args('--instance', metavar='<instance_uuid>', dest='instance_uuid',
|
||||
help='UUID of a specific instance to process. If specified '
|
||||
'--max-count has no effect.')
|
||||
'--max-count has no effect. '
|
||||
'The --cell and --instance options are mutually exclusive.')
|
||||
@args('--skip-port-allocations', action='store_true',
|
||||
dest='skip_port_allocations', default=False,
|
||||
help='Skip the healing of the resource allocations of bound ports. '
|
||||
@ -2098,8 +2099,12 @@ class PlacementCommands(object):
|
||||
'not use such a feature then the performance impact of '
|
||||
'querying neutron ports for each instance can be avoided with '
|
||||
'this flag.')
|
||||
@args('--cell', metavar='<cell_uuid>', dest='cell_uuid',
|
||||
help='Heal allocations within a specific cell. '
|
||||
'The --cell and --instance options are mutually exclusive.')
|
||||
def heal_allocations(self, max_count=None, verbose=False, dry_run=False,
|
||||
instance_uuid=None, skip_port_allocations=False):
|
||||
instance_uuid=None, skip_port_allocations=False,
|
||||
cell_uuid=None):
|
||||
"""Heals instance allocations in the Placement service
|
||||
|
||||
Return codes:
|
||||
@ -2116,7 +2121,6 @@ class PlacementCommands(object):
|
||||
* 127: Invalid input.
|
||||
"""
|
||||
# NOTE(mriedem): Thoughts on ways to expand this:
|
||||
# - allow passing a specific cell to heal
|
||||
# - allow filtering on enabled/disabled cells
|
||||
# - add a force option to force allocations for instances which have
|
||||
# task_state is not None (would get complicated during a migration);
|
||||
@ -2134,6 +2138,13 @@ class PlacementCommands(object):
|
||||
if verbose:
|
||||
output = lambda msg: print(msg)
|
||||
|
||||
# If user has provided both cell and instance
|
||||
# Throw an error
|
||||
if instance_uuid and cell_uuid:
|
||||
print(_('The --cell and --instance options '
|
||||
'are mutually exclusive.'))
|
||||
return 127
|
||||
|
||||
# TODO(mriedem): Rather than --max-count being both a total and batch
|
||||
# count, should we have separate options to be specific, i.e. --total
|
||||
# and --batch-size? Then --batch-size defaults to 50 and --total
|
||||
@ -2169,6 +2180,15 @@ class PlacementCommands(object):
|
||||
'"nova-manage cell_v2 map_instances".' %
|
||||
instance_uuid)
|
||||
return 127
|
||||
elif cell_uuid:
|
||||
try:
|
||||
# validate cell_uuid
|
||||
cell = objects.CellMapping.get_by_uuid(ctxt, cell_uuid)
|
||||
# create CellMappingList
|
||||
cells = objects.CellMappingList(objects=[cell])
|
||||
except exception.CellMappingNotFound:
|
||||
print(_('Cell with uuid %s was not found.') % cell_uuid)
|
||||
return 127
|
||||
else:
|
||||
cells = objects.CellMappingList.get_all(ctxt)
|
||||
if not cells:
|
||||
|
@ -746,6 +746,45 @@ class TestNovaManagePlacementHealAllocations(
|
||||
self.assertIn('Unable to find cell for instance %s, is it mapped?' %
|
||||
server['id'], output)
|
||||
|
||||
def test_heal_allocations_specific_cell(self):
|
||||
"""Tests the case that a specific cell is processed and only that
|
||||
cell even though there are two which require processing.
|
||||
"""
|
||||
# Create one that we won't process.
|
||||
server1, rp_uuid1 = self._boot_and_assert_no_allocations(
|
||||
self.flavor, 'cell1')
|
||||
# Create another that we will process specifically.
|
||||
server2, rp_uuid2 = self._boot_and_assert_no_allocations(
|
||||
self.flavor, 'cell2')
|
||||
|
||||
# Get Cell_id of cell2
|
||||
cell2_id = self.cell_mappings['cell2'].uuid
|
||||
|
||||
# First do a dry run to make sure two instances need processing.
|
||||
result = self.cli.heal_allocations(
|
||||
max_count=2, verbose=True, dry_run=True)
|
||||
# Nothing changed so the return code should be 4.
|
||||
self.assertEqual(4, result, self.output.getvalue())
|
||||
output = self.output.getvalue()
|
||||
self.assertIn('Found 1 candidate instances', output)
|
||||
|
||||
# Now run with our specific cell and it should be the only one
|
||||
# processed.
|
||||
result = self.cli.heal_allocations(verbose=True,
|
||||
cell_uuid=cell2_id)
|
||||
output = self.output.getvalue()
|
||||
self.assertEqual(0, result, self.output.getvalue())
|
||||
self.assertIn('Found 1 candidate instances', output)
|
||||
self.assertIn('Processed 1 instances.', output)
|
||||
|
||||
# Now run it again on the specific cell and it should be done.
|
||||
result = self.cli.heal_allocations(
|
||||
verbose=True, cell_uuid=cell2_id)
|
||||
output = self.output.getvalue()
|
||||
self.assertEqual(4, result, self.output.getvalue())
|
||||
self.assertIn('Found 1 candidate instances', output)
|
||||
self.assertIn('Processed 0 instances.', output)
|
||||
|
||||
|
||||
class TestNovaManagePlacementHealPortAllocations(
|
||||
test_servers.PortResourceRequestBasedSchedulingTestBase):
|
||||
|
@ -2346,6 +2346,24 @@ class TestNovaManagePlacement(test.NoDBTestCase):
|
||||
self.cli = manage.PlacementCommands()
|
||||
self.useFixture(fixtures.MockPatch('nova.network.neutron.get_client'))
|
||||
|
||||
def test_heal_allocations_with_cell_instance_id(self):
|
||||
"""Test heal allocation with both cell id and instance id"""
|
||||
cell_uuid = uuidutils.generate_uuid()
|
||||
instance_uuid = uuidutils.generate_uuid()
|
||||
self.assertEqual(127, self.cli.heal_allocations(
|
||||
instance_uuid=instance_uuid,
|
||||
cell_uuid=cell_uuid))
|
||||
self.assertIn('The --cell and --instance options',
|
||||
self.output.getvalue())
|
||||
|
||||
@mock.patch('nova.objects.CellMapping.get_by_uuid',
|
||||
side_effect=exception.CellMappingNotFound(uuid='fake'))
|
||||
def test_heal_allocations_with_cell_id_not_found(self, mock_get):
|
||||
"""Test the case where cell_id is not found"""
|
||||
self.assertEqual(127, self.cli.heal_allocations(cell_uuid='fake'))
|
||||
output = self.output.getvalue().strip()
|
||||
self.assertEqual('Cell with uuid fake was not found.', output)
|
||||
|
||||
@ddt.data(-1, 0, "one")
|
||||
def test_heal_allocations_invalid_max_count(self, max_count):
|
||||
self.assertEqual(127, self.cli.heal_allocations(max_count=max_count))
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- Add ``--cell`` option to the ``nova-manage placement heal_allocations``
|
||||
command. This option allows healing instance allocations within a specific cell.
|
Loading…
Reference in New Issue
Block a user