Remove 'nova-manage cell' commands

These are no longer necessary with the removal of cells v1. A check for
cells v1 in 'nova-manage cell_v2 simple_cell_setup' is also removed,
meaning this can no longer return the '2' exit code.

Part of blueprint remove-cells-v1

Change-Id: I8c2bfb31224300bc639d5089c4dfb62143d04b7f
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
This commit is contained in:
Stephen Finucane 2019-04-04 13:36:57 +01:00
parent 025e9294dd
commit 7954b2714e
4 changed files with 13 additions and 316 deletions

View File

@ -184,13 +184,11 @@ Nova Cells v2
~~~~~~~~~~~~~
``nova-manage cell_v2 simple_cell_setup [--transport-url <transport_url>]``
Setup a fresh cells v2 environment; this should not be used if you
currently have a cells v1 environment. If a transport_url is not
Setup a fresh cells v2 environment. If a ``transport_url`` is not
specified, it will use the one defined by ``[DEFAULT]/transport_url``
in the configuration file. Returns 0 if setup is completed
(or has already been done), 1 if no hosts are reporting (and cannot be
mapped), 1 if the transport url is missing or invalid, and 2 if run in a
cells v1 environment.
mapped) and 1 if the transport url is missing or invalid.
``nova-manage cell_v2 map_cell0 [--database_connection <database_connection>]``
Create a cell mapping to the database connection for the cell0 database.

View File

@ -891,159 +891,6 @@ class ApiDbCommands(object):
print(migration.db_version(database='api'))
class CellCommands(object):
"""Commands for managing cells v1 functionality."""
# TODO(stephenfin): Remove this when cells v1 is removed
description = ('DEPRECATED: The cell commands, which configure cells v1 '
'functionality, are deprecated as Cells v1 itself has '
'been deprecated. They will be removed in an upcoming '
'release.')
@staticmethod
def _parse_server_string(server_str):
"""Parses the given server_string and returns a tuple of host and port.
If it's not a combination of host part and port, the port element is an
empty string. If the input is invalid expression, return a tuple of two
empty strings.
"""
try:
# First of all, exclude pure IPv6 address (w/o port).
if netaddr.valid_ipv6(server_str):
return (server_str, '')
# Next, check if this is IPv6 address with a port number
# combination.
if server_str.find("]:") != -1:
(address, port) = server_str.replace('[', '', 1).split(']:')
return (address, port)
# Third, check if this is a combination of an address and a port
if server_str.find(':') == -1:
return (server_str, '')
# This must be a combination of an address and a port
(address, port) = server_str.split(':')
return (address, port)
except (ValueError, netaddr.AddrFormatError):
print('Invalid server_string: %s' % server_str)
return ('', '')
def _create_transport_hosts(self, username, password,
broker_hosts=None, hostname=None, port=None):
"""Returns a list of oslo.messaging.TransportHost objects."""
transport_hosts = []
# Either broker-hosts or hostname should be set
if broker_hosts:
hosts = broker_hosts.split(',')
for host in hosts:
host = host.strip()
broker_hostname, broker_port = self._parse_server_string(host)
if not broker_port:
msg = _('Invalid broker_hosts value: %s. It should be'
' in hostname:port format') % host
raise ValueError(msg)
try:
broker_port = int(broker_port)
except ValueError:
msg = _('Invalid port value: %s. It should be '
'an integer') % broker_port
raise ValueError(msg)
transport_hosts.append(
messaging.TransportHost(
hostname=broker_hostname,
port=broker_port,
username=username,
password=password))
else:
try:
port = int(port)
except ValueError:
msg = _("Invalid port value: %s. Should be an integer") % port
raise ValueError(msg)
transport_hosts.append(
messaging.TransportHost(
hostname=hostname,
port=port,
username=username,
password=password))
return transport_hosts
@args('--name', metavar='<name>', help='Name for the new cell')
@args('--cell_type', metavar='<parent|api|child|compute>',
help='Whether the cell is parent/api or child/compute')
@args('--username', metavar='<username>',
help='Username for the message broker in this cell')
@args('--password', metavar='<password>',
help='Password for the message broker in this cell')
@args('--broker_hosts', metavar='<broker_hosts>',
help='Comma separated list of message brokers in this cell. '
'Each Broker is specified as hostname:port with both '
'mandatory. This option overrides the --hostname '
'and --port options (if provided). ')
@args('--hostname', metavar='<hostname>',
help='Address of the message broker in this cell')
@args('--port', metavar='<number>',
help='Port number of the message broker in this cell')
@args('--virtual_host', metavar='<virtual_host>',
help='The virtual host of the message broker in this cell')
@args('--woffset', metavar='<float>')
@args('--wscale', metavar='<float>')
def create(self, name, cell_type='child', username=None, broker_hosts=None,
password=None, hostname=None, port=None, virtual_host=None,
woffset=None, wscale=None):
if cell_type not in ['parent', 'child', 'api', 'compute']:
print("Error: cell type must be 'parent'/'api' or "
"'child'/'compute'")
return 2
# Set up the transport URL
transport_hosts = self._create_transport_hosts(
username, password,
broker_hosts, hostname,
port)
transport_url = rpc.get_transport_url()
transport_url.hosts.extend(transport_hosts)
transport_url.virtual_host = virtual_host
is_parent = False
if cell_type in ['api', 'parent']:
is_parent = True
values = {'name': name,
'is_parent': is_parent,
'transport_url': urlparse.unquote(str(transport_url)),
'weight_offset': float(woffset),
'weight_scale': float(wscale)}
ctxt = context.get_admin_context()
db.cell_create(ctxt, values)
@args('--cell_name', metavar='<cell_name>',
help='Name of the cell to delete')
def delete(self, cell_name):
ctxt = context.get_admin_context()
db.cell_delete(ctxt, cell_name)
def list(self):
ctxt = context.get_admin_context()
cells = db.cell_get_all(ctxt)
fmt = "%3s %-10s %-6s %-10s %-15s %-5s %-10s"
print(fmt % ('Id', 'Name', 'Type', 'Username', 'Hostname',
'Port', 'VHost'))
print(fmt % ('-' * 3, '-' * 10, '-' * 6, '-' * 10, '-' * 15,
'-' * 5, '-' * 10))
for cell in cells:
url = rpc.get_transport_url(cell.transport_url)
host = url.hosts[0] if url.hosts else messaging.TransportHost()
print(fmt % (cell.id, cell.name,
'parent' if cell.is_parent else 'child',
host.username, host.hostname,
host.port, url.virtual_host))
print(fmt % ('-' * 3, '-' * 10, '-' * 6, '-' * 10, '-' * 15,
'-' * 5, '-' * 10))
class CellV2Commands(object):
"""Commands for managing cells v2."""
@ -1085,14 +932,10 @@ class CellV2Commands(object):
"""Simple cellsv2 setup.
This simplified command is for use by existing non-cells users to
configure the default environment. If you are using CellsV1, this
will not work for you. Returns 0 if setup is completed (or has
already been done), 1 if no hosts are reporting (and this cannot
be mapped) and 2 if run in a CellsV1 environment.
configure the default environment. Returns 0 if setup is completed (or
has already been done) and 1 if no hosts are reporting (and this cannot
be mapped).
"""
if CONF.cells.enable:
print('CellsV1 users cannot use this simplified setup command')
return 2
transport_url = self._validate_transport_url(transport_url)
if not transport_url:
return 1
@ -2332,7 +2175,6 @@ class PlacementCommands(object):
CATEGORIES = {
'api_db': ApiDbCommands,
'cell': CellCommands,
'cell_v2': CellV2Commands,
'db': DbCommands,
'floating': FloatingIpCommands,

View File

@ -879,149 +879,6 @@ class ApiDbCommandsTestCase(test.NoDBTestCase):
version=4, database='api')
class CellCommandsTestCase(test.NoDBTestCase):
def setUp(self):
super(CellCommandsTestCase, self).setUp()
self.output = StringIO()
self.useFixture(fixtures.MonkeyPatch('sys.stdout', self.output))
self.commands = manage.CellCommands()
def test_create_transport_hosts_multiple(self):
"""Test the _create_transport_hosts method
when broker_hosts is set.
"""
brokers = "127.0.0.1:5672,127.0.0.2:5671"
thosts = self.commands._create_transport_hosts(
'guest', 'devstack',
broker_hosts=brokers)
self.assertEqual(2, len(thosts))
self.assertEqual('127.0.0.1', thosts[0].hostname)
self.assertEqual(5672, thosts[0].port)
self.assertEqual('127.0.0.2', thosts[1].hostname)
self.assertEqual(5671, thosts[1].port)
def test_create_transport_hosts_single(self):
"""Test the _create_transport_hosts method when hostname is passed."""
thosts = self.commands._create_transport_hosts('guest', 'devstack',
hostname='127.0.0.1',
port=80)
self.assertEqual(1, len(thosts))
self.assertEqual('127.0.0.1', thosts[0].hostname)
self.assertEqual(80, thosts[0].port)
def test_create_transport_hosts_single_broker(self):
"""Test the _create_transport_hosts method for single broker_hosts."""
thosts = self.commands._create_transport_hosts(
'guest', 'devstack',
broker_hosts='127.0.0.1:5672')
self.assertEqual(1, len(thosts))
self.assertEqual('127.0.0.1', thosts[0].hostname)
self.assertEqual(5672, thosts[0].port)
def test_create_transport_hosts_both(self):
"""Test the _create_transport_hosts method when both broker_hosts
and hostname/port are passed.
"""
thosts = self.commands._create_transport_hosts(
'guest', 'devstack',
broker_hosts='127.0.0.1:5672',
hostname='127.0.0.2', port=80)
self.assertEqual(1, len(thosts))
self.assertEqual('127.0.0.1', thosts[0].hostname)
self.assertEqual(5672, thosts[0].port)
def test_create_transport_hosts_wrong_val(self):
"""Test the _create_transport_hosts method when broker_hosts
is wrongly specified
"""
self.assertRaises(ValueError,
self.commands._create_transport_hosts,
'guest', 'devstack',
broker_hosts='127.0.0.1:5672,127.0.0.1')
def test_create_transport_hosts_wrong_port_val(self):
"""Test the _create_transport_hosts method when port in
broker_hosts is wrongly specified
"""
self.assertRaises(ValueError,
self.commands._create_transport_hosts,
'guest', 'devstack',
broker_hosts='127.0.0.1:')
def test_create_transport_hosts_wrong_port_arg(self):
"""Test the _create_transport_hosts method when port
argument is wrongly specified
"""
self.assertRaises(ValueError,
self.commands._create_transport_hosts,
'guest', 'devstack',
hostname='127.0.0.1', port='ab')
@mock.patch.object(context, 'get_admin_context')
@mock.patch.object(db, 'cell_create')
def test_create_broker_hosts(self, mock_db_cell_create, mock_ctxt):
"""Test the create function when broker_hosts is
passed
"""
cell_tp_url = "fake://guest:devstack@127.0.0.1:5432"
cell_tp_url += ",guest:devstack@127.0.0.2:9999/"
ctxt = mock.sentinel
mock_ctxt.return_value = mock.sentinel
self.commands.create("test",
broker_hosts='127.0.0.1:5432,127.0.0.2:9999',
woffset=0, wscale=0,
username="guest", password="devstack")
exp_values = {'name': "test",
'is_parent': False,
'transport_url': cell_tp_url,
'weight_offset': 0.0,
'weight_scale': 0.0}
mock_db_cell_create.assert_called_once_with(ctxt, exp_values)
@mock.patch.object(context, 'get_admin_context')
@mock.patch.object(db, 'cell_create')
def test_create_broker_hosts_with_url_decoding_fix(self,
mock_db_cell_create,
mock_ctxt):
"""Test the create function when broker_hosts is
passed
"""
cell_tp_url = "fake://the=user:the=password@127.0.0.1:5432/"
ctxt = mock.sentinel
mock_ctxt.return_value = mock.sentinel
self.commands.create("test",
broker_hosts='127.0.0.1:5432',
woffset=0, wscale=0,
username="the=user",
password="the=password")
exp_values = {'name': "test",
'is_parent': False,
'transport_url': cell_tp_url,
'weight_offset': 0.0,
'weight_scale': 0.0}
mock_db_cell_create.assert_called_once_with(ctxt, exp_values)
@mock.patch.object(context, 'get_admin_context')
@mock.patch.object(db, 'cell_create')
def test_create_hostname(self, mock_db_cell_create, mock_ctxt):
"""Test the create function when hostname and port is
passed
"""
cell_tp_url = "fake://guest:devstack@127.0.0.1:9999/"
ctxt = mock.sentinel
mock_ctxt.return_value = mock.sentinel
self.commands.create("test",
hostname='127.0.0.1', port="9999",
woffset=0, wscale=0,
username="guest", password="devstack")
exp_values = {'name': "test",
'is_parent': False,
'transport_url': cell_tp_url,
'weight_offset': 0.0,
'weight_scale': 0.0}
mock_db_cell_create.assert_called_once_with(ctxt, exp_values)
@ddt.ddt
class CellV2CommandsTestCase(test.NoDBTestCase):
USES_DB_SELF = True
@ -1560,10 +1417,6 @@ class CellV2CommandsTestCase(test.NoDBTestCase):
self._test_migrate_simple_command()
self._test_migrate_simple_command()
def test_simple_command_cellsv1(self):
self.flags(enable=True, group='cells')
self.assertEqual(2, self.commands.simple_cell_setup('foo'))
def test_instance_verify_no_mapping(self):
r = self.commands.verify_instance(uuidsentinel.instance)
self.assertEqual(1, r)

View File

@ -2,10 +2,14 @@
upgrade:
- |
The *cells v1* feature has been deprecated since the 16.0.0 Pike release
and has now been removed. The ``nova-cells`` service has been removed. The
*cells v1* specific REST APIs have been removed along with their related
policy rules. Calling these APIs will now result in a ``410 (Gone)`` error
response.
and has now been removed. The ``nova-cells`` service and ``nova-manage
cells`` commands have been removed, while the ``nova-manage cell_v2
simple_cell_setup`` command will no longer check if cells v1 is enabled and
therefore can no longer exit with ``2``.
The *cells v1* specific REST APIs have
been removed along with their related policy rules. Calling these APIs will
now result in a ``410 (Gone)`` error response.
* ``GET /os-cells``
* ``POST /os-cells``