From 6041572a4c95428f6b13a8d7569090b315a3abd1 Mon Sep 17 00:00:00 2001 From: Sylvain Bauza Date: Tue, 6 Jun 2017 23:28:59 +0200 Subject: [PATCH] Fix cell0 naming when QS params on the connection We had a problem when the nova connection string included parameters on the query string like charset encoding. Note that the connection string necessarly needs to be RFC1738 compliant as per Sqlalchemy rules, so it's totally safe to just unquote what the SQLA helper method gives us as a result. Also removed a tested connection string since it wasn't RFC1738 compatible. Change-Id: I45fe9b92e8d93a0099d33bb0070e9d4e540595ac Closes-Bug: #1696001 (cherry picked from commit 9a33092fa9b0c65b37b9fdc860f5a571908d7a69) --- nova/cmd/manage.py | 11 ++++------- nova/tests/unit/test_nova_manage.py | 15 ++++++++------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/nova/cmd/manage.py b/nova/cmd/manage.py index 00856c3637d4..b76029003e12 100644 --- a/nova/cmd/manage.py +++ b/nova/cmd/manage.py @@ -1152,19 +1152,16 @@ class CellV2Commands(object): # based on the database connection url. # The cell0 database will use the same database scheme and # netloc as the main database, with a related path. + # NOTE(sbauza): The URL has to be RFC1738 compliant in order to + # be usable by sqlalchemy. connection = CONF.database.connection # sqlalchemy has a nice utility for parsing database connection # URLs so we use that here to get the db name so we don't have to # worry about parsing and splitting a URL which could have special # characters in the password, which makes parsing a nightmare. 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 + url.database = url.database + '_cell0' + return urlparse.unquote(str(url)) dbc = database_connection or cell0_default_connection() ctxt = context.RequestContext() diff --git a/nova/tests/unit/test_nova_manage.py b/nova/tests/unit/test_nova_manage.py index d9208280009b..cc7cba3db240 100644 --- a/nova/tests/unit/test_nova_manage.py +++ b/nova/tests/unit/test_nova_manage.py @@ -1140,16 +1140,17 @@ class CellV2CommandsTestCase(test.NoDBTestCase): self.assertEqual('fake://netloc/nova_cell0', cell_mapping.database_connection) - @ddt.data('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') + @ddt.data('mysql+pymysql://nova:abcd0123:AB@controller/%s', + 'mysql+pymysql://nova:abcd0123?AB@controller/%s', + 'mysql+pymysql://nova:abcd0123@AB@controller/%s', + 'mysql+pymysql://nova:abcd0123/AB@controller/%s', + 'mysql+pymysql://test:abcd0123/AB@controller/%s?charset=utf8') def test_map_cell0_default_database_special_characters(self, - decoded_connection): + connection): """Tests that a URL with special characters, like in the credentials, is handled properly. """ + decoded_connection = connection % 'nova' self.flags(connection=decoded_connection, group='database') ctxt = context.RequestContext() self.commands.map_cell0() @@ -1158,7 +1159,7 @@ class CellV2CommandsTestCase(test.NoDBTestCase): self.assertEqual('cell0', cell_mapping.name) self.assertEqual('none:///', cell_mapping.transport_url) self.assertEqual( - decoded_connection + '_cell0', + connection % 'nova_cell0', cell_mapping.database_connection) # Delete the cell mapping for the next iteration. cell_mapping.destroy()