Handle special characters in database connection URL netloc
When calling "nova-manage cell_v2 simple_cell_setup" or "nova-manage cell_v2 map_cell0" without passing in the --database_connection option, we read the [database]/connection URL from nova.conf, try to split the URL and then create a default connection based on the name of the original connection, so if you're cell database's name is 'nova' you'd end up with 'nova_cell0' for the cell0 database name in the URL. The problem is the database connection URL has credentials in the netloc and if the password has special characters in it, those can mess up the URL split, like splitting on ? which is normally denoting the beginning of the path in a URL. This change handles special characters in the password by using a nice DB connection URL parsing utility method available in sqlalchemy to get the database name out of the connection URL string so we can replace it properly with the _cell0 suffix. Adds a release note as this bug causes issues when upgrading. Conflicts: nova/tests/unit/test_nova_manage.py NOTE(mriedem): The conflict is due to ddt not being used in Newton. Change-Id: I7a7678e4af8160e6f48b96095154fca6ca48ff09 Closes-Bug: #1673613 (cherry picked from commit9a9a620ea2
) (cherry picked from commitb501fa7a92
)
This commit is contained in:
parent
f9a3c3fcff
commit
e3076f5ff6
@ -68,6 +68,7 @@ from oslo_utils import importutils
|
|||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
import six
|
import six
|
||||||
import six.moves.urllib.parse as urlparse
|
import six.moves.urllib.parse as urlparse
|
||||||
|
from sqlalchemy.engine import url as sqla_url
|
||||||
|
|
||||||
from nova.api.ec2 import ec2utils
|
from nova.api.ec2 import ec2utils
|
||||||
from nova import availability_zones
|
from nova import availability_zones
|
||||||
@ -1275,12 +1276,19 @@ class CellV2Commands(object):
|
|||||||
# based on the database connection url.
|
# based on the database connection url.
|
||||||
# The cell0 database will use the same database scheme and
|
# The cell0 database will use the same database scheme and
|
||||||
# netloc as the main database, with a related path.
|
# netloc as the main database, with a related path.
|
||||||
scheme, netloc, path, query, fragment = \
|
connection = CONF.database.connection
|
||||||
urlparse.urlsplit(CONF.database.connection)
|
# sqlalchemy has a nice utility for parsing database connection
|
||||||
root, ext = os.path.splitext(path)
|
# URLs so we use that here to get the db name so we don't have to
|
||||||
path = root + "_cell0" + ext
|
# worry about parsing and splitting a URL which could have special
|
||||||
return urlparse.urlunsplit((scheme, netloc, path, query,
|
# characters in the password, which makes parsing a nightmare.
|
||||||
fragment))
|
url = sqla_url.make_url(connection)
|
||||||
|
cell0_db_name = url.database + '_cell0'
|
||||||
|
# We need to handle multiple occurrences of the substring, e.g. if
|
||||||
|
# the username and db name are both 'nova' we need to only replace
|
||||||
|
# the last one, which is the database name in the URL, not the
|
||||||
|
# username.
|
||||||
|
connection = connection.rstrip(url.database)
|
||||||
|
return connection + cell0_db_name
|
||||||
|
|
||||||
dbc = database_connection or cell0_default_connection()
|
dbc = database_connection or cell0_default_connection()
|
||||||
ctxt = context.RequestContext()
|
ctxt = context.RequestContext()
|
||||||
|
@ -1125,6 +1125,29 @@ class CellV2CommandsTestCase(test.TestCase):
|
|||||||
self.assertEqual('fake://netloc/nova_cell0',
|
self.assertEqual('fake://netloc/nova_cell0',
|
||||||
cell_mapping.database_connection)
|
cell_mapping.database_connection)
|
||||||
|
|
||||||
|
def test_map_cell0_default_database_special_characters(self):
|
||||||
|
"""Tests that a URL with special characters, like in the credentials,
|
||||||
|
is handled properly.
|
||||||
|
"""
|
||||||
|
for decoded_connection in (
|
||||||
|
'mysql+pymysql://nova:abcd0123:AB@controller/nova',
|
||||||
|
'mysql+pymysql://nova:abcd0123?AB@controller/nova',
|
||||||
|
'mysql+pymysql://nova:abcd0123@AB@controller/nova',
|
||||||
|
'mysql+pymysql://nova:abcd0123/AB@controller/nova',
|
||||||
|
'mysql+pymysql://test:abcd0123%AB@controller/nova'):
|
||||||
|
self.flags(connection=decoded_connection, group='database')
|
||||||
|
ctxt = context.RequestContext()
|
||||||
|
self.commands.map_cell0()
|
||||||
|
cell_mapping = objects.CellMapping.get_by_uuid(
|
||||||
|
ctxt, objects.CellMapping.CELL0_UUID)
|
||||||
|
self.assertEqual('cell0', cell_mapping.name)
|
||||||
|
self.assertEqual('none:///', cell_mapping.transport_url)
|
||||||
|
self.assertEqual(
|
||||||
|
decoded_connection + '_cell0',
|
||||||
|
cell_mapping.database_connection)
|
||||||
|
# Delete the cell mapping for the next iteration.
|
||||||
|
cell_mapping.destroy()
|
||||||
|
|
||||||
def _test_migrate_simple_command(self, cell0_sync_fail=False):
|
def _test_migrate_simple_command(self, cell0_sync_fail=False):
|
||||||
ctxt = context.RequestContext()
|
ctxt = context.RequestContext()
|
||||||
CONF.set_default('connection',
|
CONF.set_default('connection',
|
||||||
|
9
releasenotes/notes/bug-1673613-7357d40ba9ab1fa6.yaml
Normal file
9
releasenotes/notes/bug-1673613-7357d40ba9ab1fa6.yaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Includes the fix for `bug 1673613`_ which could cause issues when upgrading
|
||||||
|
and running ``nova-manage cell_v2 simple_cell_setup`` or
|
||||||
|
``nova-manage cell_v2 map_cell0`` where the database connection is read
|
||||||
|
from config and has special characters in the URL.
|
||||||
|
|
||||||
|
.. _bug 1673613: https://launchpad.net/bugs/1673613
|
Loading…
Reference in New Issue
Block a user