Add 'delete_host' command in 'nova-manage cell_v2'
Add 'delete_host' command in 'nova-manage cell_v2'. Add an optional 'force' option in 'nova-manage cell_v2 delete_cell'. If specifying the 'force' option, a cell can be deleted even if the cell has hosts. Change-Id: I8cd7826c2c03687c6b85731519778f09d542b236 Closes-Bug: #1721179
This commit is contained in:
parent
8b238774dd
commit
f4f17b364e
@ -204,11 +204,13 @@ Nova Cells v2
|
||||
uuid are shown. Use the --verbose option to see transport url and database
|
||||
connection details.
|
||||
|
||||
``nova-manage cell_v2 delete_cell --cell_uuid <cell_uuid>``
|
||||
``nova-manage cell_v2 delete_cell [--force] --cell_uuid <cell_uuid>``
|
||||
|
||||
Delete an empty cell by the given uuid. Returns 0 if the empty cell is
|
||||
found and deleted successfully, 1 if a cell with that uuid could not be
|
||||
found, 2 if host mappings were found for the cell (cell not empty), and 3
|
||||
Delete a cell by the given uuid. Returns 0 if the empty cell is
|
||||
found and deleted successfully or the cell that has hosts is found and
|
||||
the cell and the hosts are deleted successfully with ``--force`` option,
|
||||
1 if a cell with that uuid could not be found, 2 if host mappings were
|
||||
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 update_cell --cell_uuid <cell_uuid> [--name <cell_name>] [--transport-url <transport_url>] [--database_connection <database_connection>]``
|
||||
@ -228,6 +230,14 @@ Nova Cells v2
|
||||
running system will NOT result in all nodes immediately using the new
|
||||
values. Use caution when changing these values.
|
||||
|
||||
``nova-manage cell_v2 delete_host --cell_uuid <cell_uuid> --host <host>``
|
||||
|
||||
Delete a host by the given host name and the given cell uuid. Returns 0
|
||||
if the empty host is found and deleted successfully, 1 if a cell with
|
||||
that uuid could not be found, 2 if a host with that name could not be
|
||||
found, 3 if a host with that name is not in a cell with that uuid, 4 if
|
||||
a host with that name has instances (host not empty).
|
||||
|
||||
Nova Logs
|
||||
~~~~~~~~~
|
||||
|
||||
|
@ -1721,15 +1721,26 @@ class CellV2Commands(object):
|
||||
print(t)
|
||||
return 0
|
||||
|
||||
@args('--force', action='store_true', default=False,
|
||||
help=_('Delete hosts that belong to the cell as well.'))
|
||||
@args('--cell_uuid', metavar='<cell_uuid>', dest='cell_uuid',
|
||||
required=True, help=_('The uuid of the cell to delete.'))
|
||||
def delete_cell(self, cell_uuid):
|
||||
def delete_cell(self, cell_uuid, force=False):
|
||||
"""Delete an empty cell by the given uuid.
|
||||
|
||||
If the cell is not found by uuid or it is not empty (it has host or
|
||||
instance mappings) this command will return a non-zero exit code.
|
||||
This command will return a non-zero exit code in the following cases.
|
||||
|
||||
Returns 0 if the empty cell is found and deleted successfully.
|
||||
* The cell is not found by uuid.
|
||||
* It has hosts and force is False.
|
||||
* It has instance mappings.
|
||||
|
||||
If force is True and the cell has host, hosts are deleted as well.
|
||||
|
||||
Returns 0 in the following cases.
|
||||
|
||||
* The empty cell is found and deleted successfully.
|
||||
* The cell has hosts and force is True and the cell and the hosts are
|
||||
deleted successfully.
|
||||
"""
|
||||
ctxt = context.get_admin_context()
|
||||
# Find the CellMapping given the uuid.
|
||||
@ -1742,7 +1753,7 @@ class CellV2Commands(object):
|
||||
# Check to see if there are any HostMappings for this cell.
|
||||
host_mappings = objects.HostMappingList.get_by_cell_id(
|
||||
ctxt, cell_mapping.id)
|
||||
if host_mappings:
|
||||
if host_mappings and not force:
|
||||
print(_('There are existing hosts mapped to cell with uuid %s.') %
|
||||
cell_uuid)
|
||||
return 2
|
||||
@ -1755,6 +1766,10 @@ class CellV2Commands(object):
|
||||
'uuid %s.') % cell_uuid)
|
||||
return 3
|
||||
|
||||
# Delete hosts mapped to the cell.
|
||||
for host_mapping in host_mappings:
|
||||
host_mapping.destroy()
|
||||
|
||||
# There are no hosts or instances mapped to the cell so delete it.
|
||||
cell_mapping.destroy()
|
||||
return 0
|
||||
@ -1808,6 +1823,52 @@ class CellV2Commands(object):
|
||||
|
||||
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',
|
||||
required=True, help=_('The host to delete.'))
|
||||
def delete_host(self, cell_uuid, host):
|
||||
"""Delete a host in a cell (host mappings) by the given host name
|
||||
|
||||
This command will return a non-zero exit code in the following cases.
|
||||
|
||||
* The cell is not found by uuid.
|
||||
* The host is not found by host name.
|
||||
* The host is not in the cell.
|
||||
* The host has instances.
|
||||
|
||||
Returns 0 if the host is deleted successfully.
|
||||
"""
|
||||
ctxt = context.get_admin_context()
|
||||
# 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
|
||||
|
||||
try:
|
||||
host_mapping = objects.HostMapping.get_by_host(ctxt, host)
|
||||
except exception.HostMappingNotFound:
|
||||
print(_('The host %s was not found.') % host)
|
||||
return 2
|
||||
|
||||
if host_mapping.cell_mapping.uuid != cell_mapping.uuid:
|
||||
print(_('The host %(host)s was not found '
|
||||
'in the cell %(cell_uuid)s.') % {'host': host,
|
||||
'cell_uuid': cell_uuid})
|
||||
return 3
|
||||
|
||||
with context.target_cell(ctxt, cell_mapping) as cctxt:
|
||||
instances = objects.InstanceList.get_by_host(cctxt, host)
|
||||
|
||||
if instances:
|
||||
print(_('There are instances on the host %s.') % host)
|
||||
return 4
|
||||
|
||||
host_mapping.destroy()
|
||||
return 0
|
||||
|
||||
|
||||
CATEGORIES = {
|
||||
'account': AccountCommands,
|
||||
|
@ -1643,7 +1643,7 @@ class CellV2CommandsTestCase(test.NoDBTestCase):
|
||||
output = self.output.getvalue().strip()
|
||||
self.assertIn('There are existing instances mapped to cell', output)
|
||||
|
||||
def test_delete_cell_success(self):
|
||||
def test_delete_cell_success_without_host_mappings(self):
|
||||
"""Tests trying to delete an empty cell."""
|
||||
cell_uuid = uuidutils.generate_uuid()
|
||||
ctxt = context.get_admin_context()
|
||||
@ -1656,6 +1656,28 @@ class CellV2CommandsTestCase(test.NoDBTestCase):
|
||||
output = self.output.getvalue().strip()
|
||||
self.assertEqual('', output)
|
||||
|
||||
@mock.patch.object(objects.HostMapping, 'destroy')
|
||||
@mock.patch.object(objects.CellMapping, 'destroy')
|
||||
def test_delete_cell_success_with_host_mappings(self, mock_cell_destroy,
|
||||
mock_hm_destroy):
|
||||
"""Tests trying to delete a cell with host."""
|
||||
ctxt = context.get_admin_context()
|
||||
# create the cell mapping
|
||||
cm = objects.CellMapping(
|
||||
context=ctxt, uuid=uuidsentinel.cell1,
|
||||
database_connection='fake:///db', transport_url='fake:///mq')
|
||||
cm.create()
|
||||
# create a host mapping in this cell
|
||||
hm = objects.HostMapping(
|
||||
context=ctxt, host='fake-host', cell_mapping=cm)
|
||||
hm.create()
|
||||
self.assertEqual(0, self.commands.delete_cell(uuidsentinel.cell1,
|
||||
force=True))
|
||||
output = self.output.getvalue().strip()
|
||||
self.assertEqual('', output)
|
||||
mock_hm_destroy.assert_called_once_with()
|
||||
mock_cell_destroy.assert_called_once_with()
|
||||
|
||||
def test_update_cell_not_found(self):
|
||||
self.assertEqual(1, self.commands.update_cell(
|
||||
uuidsentinel.cell1, 'foo', 'fake://new', 'fake:///new'))
|
||||
@ -1704,6 +1726,97 @@ class CellV2CommandsTestCase(test.NoDBTestCase):
|
||||
output = self.output.getvalue().strip()
|
||||
self.assertEqual('', 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,
|
||||
'fake-host'))
|
||||
output = self.output.getvalue().strip()
|
||||
self.assertEqual(
|
||||
'Cell with uuid %s was not found.' % uuidsentinel.cell1, output)
|
||||
|
||||
def test_delete_host_host_not_found(self):
|
||||
"""Tests trying to delete a host but the host is not found."""
|
||||
ctxt = context.get_admin_context()
|
||||
# create the cell mapping
|
||||
cm = objects.CellMapping(
|
||||
context=ctxt, uuid=uuidsentinel.cell1,
|
||||
database_connection='fake:///db', transport_url='fake:///mq')
|
||||
cm.create()
|
||||
self.assertEqual(2, self.commands.delete_host(uuidsentinel.cell1,
|
||||
'fake-host'))
|
||||
output = self.output.getvalue().strip()
|
||||
self.assertEqual('The host fake-host was not found.', output)
|
||||
|
||||
def test_delete_host_host_not_in_cell(self):
|
||||
"""Tests trying to delete a host
|
||||
but the host does not belongs to a specified cell.
|
||||
"""
|
||||
ctxt = context.get_admin_context()
|
||||
# create the cell mapping
|
||||
cm1 = objects.CellMapping(
|
||||
context=ctxt, uuid=uuidsentinel.cell1,
|
||||
database_connection='fake:///db', transport_url='fake:///mq')
|
||||
cm1.create()
|
||||
cm2 = objects.CellMapping(
|
||||
context=ctxt, uuid=uuidsentinel.cell2,
|
||||
database_connection='fake:///db', transport_url='fake:///mq')
|
||||
cm2.create()
|
||||
# create a host mapping in another cell
|
||||
hm = objects.HostMapping(
|
||||
context=ctxt, host='fake-host', cell_mapping=cm2)
|
||||
hm.create()
|
||||
self.assertEqual(3, self.commands.delete_host(uuidsentinel.cell1,
|
||||
'fake-host'))
|
||||
output = self.output.getvalue().strip()
|
||||
self.assertEqual(('The host fake-host was not found in the cell %s.' %
|
||||
uuidsentinel.cell1), output)
|
||||
|
||||
@mock.patch.object(objects.InstanceList, 'get_by_host')
|
||||
def test_delete_host_instances_exist(self, mock_get_by_host):
|
||||
"""Tests trying to delete a host but the host has instances."""
|
||||
ctxt = context.get_admin_context()
|
||||
# create the cell mapping
|
||||
cm1 = objects.CellMapping(
|
||||
context=ctxt, uuid=uuidsentinel.cell1,
|
||||
database_connection='fake:///db', transport_url='fake:///mq')
|
||||
cm1.create()
|
||||
# create a host mapping in the cell
|
||||
hm = objects.HostMapping(
|
||||
context=ctxt, host='fake-host', cell_mapping=cm1)
|
||||
hm.create()
|
||||
mock_get_by_host.return_value = [objects.Instance(
|
||||
ctxt, uuid=uuidsentinel.instance)]
|
||||
self.assertEqual(4, self.commands.delete_host(uuidsentinel.cell1,
|
||||
'fake-host'))
|
||||
output = self.output.getvalue().strip()
|
||||
self.assertEqual('There are instances on the host fake-host.', output)
|
||||
mock_get_by_host.assert_called_once_with(
|
||||
test.MatchType(context.RequestContext), 'fake-host')
|
||||
|
||||
@mock.patch.object(objects.InstanceList, 'get_by_host',
|
||||
return_value=[])
|
||||
@mock.patch.object(objects.HostMapping, 'destroy')
|
||||
def test_delete_host_success(self, mock_destroy, mock_get_by_host):
|
||||
"""Tests trying to delete a host that has not instances."""
|
||||
ctxt = context.get_admin_context()
|
||||
# create the cell mapping
|
||||
cm1 = objects.CellMapping(
|
||||
context=ctxt, uuid=uuidsentinel.cell1,
|
||||
database_connection='fake:///db', transport_url='fake:///mq')
|
||||
cm1.create()
|
||||
# create a host mapping in the cell
|
||||
hm = objects.HostMapping(
|
||||
context=ctxt, host='fake-host', cell_mapping=cm1)
|
||||
hm.create()
|
||||
|
||||
self.assertEqual(0, self.commands.delete_host(uuidsentinel.cell1,
|
||||
'fake-host'))
|
||||
output = self.output.getvalue().strip()
|
||||
self.assertEqual('', output)
|
||||
mock_get_by_host.assert_called_once_with(
|
||||
test.MatchType(context.RequestContext), 'fake-host')
|
||||
mock_destroy.assert_called_once_with()
|
||||
|
||||
|
||||
class TestNovaManageMain(test.NoDBTestCase):
|
||||
"""Tests the nova-manage:main() setup code."""
|
||||
|
8
releasenotes/notes/bug-1721179-87bc7b64215944c0.yaml
Normal file
8
releasenotes/notes/bug-1721179-87bc7b64215944c0.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
The ``delete_host`` command has been added in ``nova-manage cell_v2``
|
||||
to delete a host from a cell (host mappings).
|
||||
The ``force`` option has been added in ``nova-manage cell_v2 delete_cell``.
|
||||
If the ``force`` option is specified, a cell can be deleted
|
||||
even if the cell has hosts.
|
Loading…
Reference in New Issue
Block a user