Explicitly use pymysql sqlalchemy driver for Stein+

The sqlalchemy package has switched back to using mysqldb as the
default driver for the mysql dialect in Ubuntu Disco (Stein). For
Icehouse -> Rocky, OpenStack packages will successfully use the
default sqlalchemy driver [1] when only 'mysql' is specified in the
connection string. For Stein, the mysqldb driver must be overridden
with 'mysql+pymysql' in connection strings.

[1] Based on the OpenStack release, the sqlalchemy package defaults
to the following drivers:
  Stein+: mysqldb
  Mitaka-Rocky: pymysql
  Icehouse: mysqldb

Change-Id: I1ccc7080f54eda1c12b51a24a488666f793d038e
This commit is contained in:
Corey Bryant 2019-02-05 18:43:41 +00:00
parent 982ae33054
commit 341b879cc1
3 changed files with 55 additions and 18 deletions

View File

@ -392,6 +392,7 @@ class DatabaseRelationAdapter(OpenStackRelationAdapter):
def __init__(self, relation):
add_accessors = ['password', 'username', 'database']
super(DatabaseRelationAdapter, self).__init__(relation, add_accessors)
self.config = hookenv.config()
@property
def host(self):
@ -405,15 +406,23 @@ class DatabaseRelationAdapter(OpenStackRelationAdapter):
return 'mysql'
def get_uri(self, prefix=None):
driver = 'mysql'
release = ch_utils.get_os_codename_install_source(
self.config['openstack-origin'])
if (ch_utils.OPENSTACK_RELEASES.index(release) >=
ch_utils.OPENSTACK_RELEASES.index('stein')):
driver = 'mysql+pymysql'
if prefix:
uri = 'mysql://{}:{}@{}/{}'.format(
uri = '{}://{}:{}@{}/{}'.format(
driver,
self.relation.username(prefix=prefix),
self.relation.password(prefix=prefix),
self.host,
self.relation.database(prefix=prefix),
)
else:
uri = 'mysql://{}:{}@{}/{}'.format(
uri = '{}://{}:{}@{}/{}'.format(
driver,
self.username,
self.password,
self.host,

View File

@ -67,6 +67,9 @@ charmhelpers.contrib.openstack.utils.OPENSTACK_RELEASES = (
'newton',
'ocata',
'pike',
'queens',
'rocky',
'stein',
)
# charms.reactive uses hookenv.charm_dir which must return a directory

View File

@ -334,22 +334,47 @@ class SSLDatabaseRelationAdapter(adapters.DatabaseRelationAdapter):
class TestDatabaseRelationAdapter(unittest.TestCase):
def test_class(self):
fake = FakeDatabaseRelation()
db = adapters.DatabaseRelationAdapter(fake)
self.assertEqual(db.host, 'host1')
self.assertEqual(db.type, 'mysql')
self.assertEqual(db.password, 'password1')
self.assertEqual(db.username, 'username1')
self.assertEqual(db.database, 'database1')
self.assertEqual(db.uri, 'mysql://username1:password1@host1/database1')
self.assertEqual(db.get_uri('x'),
'mysql://username1x:password1x@host1/database1x')
# test the ssl feature of the base class
db = SSLDatabaseRelationAdapter(fake)
self.assertEqual(db.uri,
'mysql://username1:password1@host1/database1'
'?ssl_ca=my-ca'
'&ssl_cert=my-cert&ssl_key=my-key')
with mock.patch.object(adapters.ch_utils,
'get_os_codename_install_source',
return_value='rocky'):
fake = FakeDatabaseRelation()
db = adapters.DatabaseRelationAdapter(fake)
self.assertEqual(db.host, 'host1')
self.assertEqual(db.type, 'mysql')
self.assertEqual(db.password, 'password1')
self.assertEqual(db.username, 'username1')
self.assertEqual(db.database, 'database1')
self.assertEqual(
db.uri,
'mysql://username1:password1@host1/database1')
self.assertEqual(
db.get_uri('x'),
'mysql://username1x:password1x@host1/database1x')
# test the ssl feature of the base class
db = SSLDatabaseRelationAdapter(fake)
self.assertEqual(
db.uri,
'mysql://username1:password1@host1/database1'
'?ssl_ca=my-ca'
'&ssl_cert=my-cert&ssl_key=my-key')
with mock.patch.object(adapters.ch_utils,
'get_os_codename_install_source',
return_value='stein'):
fake = FakeDatabaseRelation()
db = adapters.DatabaseRelationAdapter(fake)
self.assertEqual(
db.uri,
'mysql+pymysql://username1:password1@host1/database1')
self.assertEqual(
db.get_uri('x'),
'mysql+pymysql://username1x:password1x@host1/database1x')
# test the ssl feature of the base class
db = SSLDatabaseRelationAdapter(fake)
self.assertEqual(
db.uri,
'mysql+pymysql://username1:password1@host1/database1'
'?ssl_ca=my-ca'
'&ssl_cert=my-cert&ssl_key=my-key')
class TestConfigurationAdapter(unittest.TestCase):