From 10b07c9ccf5b2925858a48e124374adda267659f Mon Sep 17 00:00:00 2001
From: Thomas Herve <therve@redhat.com>
Date: Fri, 17 Feb 2017 16:14:24 +0100
Subject: [PATCH] Remove table creation from the SQL driver

Table creation must happen outside of API requests. This changes the
devstack plugin to create the tables properly.

Change-Id: I57c4fba06dc6725ea977477b777e4ffd6856adde
---
 devstack/plugin.sh                                |  4 ++++
 releasenotes/notes/sql_init-c9b3883241631f24.yaml |  7 +++++++
 zaqar/storage/sqlalchemy/driver.py                |  3 ---
 zaqar/tests/unit/storage/test_impl_sqlalchemy.py  | 15 +++++++++++----
 4 files changed, 22 insertions(+), 7 deletions(-)
 create mode 100644 releasenotes/notes/sql_init-c9b3883241631f24.yaml

diff --git a/devstack/plugin.sh b/devstack/plugin.sh
index bb98c7f81..8e076dc70 100755
--- a/devstack/plugin.sh
+++ b/devstack/plugin.sh
@@ -129,6 +129,8 @@ function configure_zaqar {
         iniset $ZAQAR_CONF 'drivers:management_store:sqlalchemy' uri `database_connection_url zaqar`
         iniset $ZAQAR_CONF 'drivers:management_store:sqlalchemy' database zaqar_mgmt
 
+        zaqar-sql-db-manage --config-file $ZAQAR_CONF upgrade head
+
         iniset $ZAQAR_CONF  drivers message_store redis
         iniset $ZAQAR_CONF 'drivers:message_store:redis' uri redis://localhost:6379
         iniset $ZAQAR_CONF 'drivers:message_store:redis' database zaqar
@@ -139,6 +141,8 @@ function configure_zaqar {
         iniset $ZAQAR_CONF 'drivers:management_store:sqlalchemy' uri `database_connection_url zaqar`
         iniset $ZAQAR_CONF 'drivers:management_store:sqlalchemy' database zaqar_mgmt
 
+        zaqar-sql-db-manage --config-file $ZAQAR_CONF upgrade head
+
         iniset $ZAQAR_CONF  drivers message_store swift
         iniset $ZAQAR_CONF 'drivers:message_store:swift' auth_url $KEYSTONE_AUTH_URI_V3
         iniset $ZAQAR_CONF 'drivers:message_store:swift' uri swift://zaqar:$SERVICE_PASSWORD@/service
diff --git a/releasenotes/notes/sql_init-c9b3883241631f24.yaml b/releasenotes/notes/sql_init-c9b3883241631f24.yaml
new file mode 100644
index 000000000..de1190654
--- /dev/null
+++ b/releasenotes/notes/sql_init-c9b3883241631f24.yaml
@@ -0,0 +1,7 @@
+---
+critical:
+  - |
+    When using the sqlalchemy driver, operators now are required to run
+    "zaqar-sql-db-manage upgrade" before making the service available. The
+    service previously tried to create the database on the first request, but
+    it was bound to race conditions.
diff --git a/zaqar/storage/sqlalchemy/driver.py b/zaqar/storage/sqlalchemy/driver.py
index 029311b9c..cd5520a22 100644
--- a/zaqar/storage/sqlalchemy/driver.py
+++ b/zaqar/storage/sqlalchemy/driver.py
@@ -23,7 +23,6 @@ from zaqar.common import decorators
 from zaqar import storage
 from zaqar.storage.sqlalchemy import controllers
 from zaqar.storage.sqlalchemy import options
-from zaqar.storage.sqlalchemy import tables
 
 
 class ControlDriver(storage.ControlDriverBase):
@@ -61,8 +60,6 @@ class ControlDriver(storage.ControlDriverBase):
             sa.event.listen(engine, 'connect',
                             self._mysql_on_connect)
 
-        tables.metadata.create_all(engine, checkfirst=True)
-
         if (self.conf.profiler.enabled and
                 self.conf.profiler.trace_message_store):
             sa_tracer.add_tracing(sa, engine, "db")
diff --git a/zaqar/tests/unit/storage/test_impl_sqlalchemy.py b/zaqar/tests/unit/storage/test_impl_sqlalchemy.py
index 27027511a..226a00d7d 100644
--- a/zaqar/tests/unit/storage/test_impl_sqlalchemy.py
+++ b/zaqar/tests/unit/storage/test_impl_sqlalchemy.py
@@ -16,33 +16,40 @@ import six
 
 from zaqar.storage import sqlalchemy
 from zaqar.storage.sqlalchemy import controllers
+from zaqar.storage.sqlalchemy import tables
 from zaqar.storage.sqlalchemy import utils
 from zaqar import tests as testing
 from zaqar.tests.unit.storage import base
 
 
-class SqlalchemyQueueTests(base.QueueControllerTest):
+class DBCreateMixin(object):
+
+    def _prepare_conf(self):
+        tables.metadata.create_all(self.driver.engine)
+
+
+class SqlalchemyQueueTests(DBCreateMixin, base.QueueControllerTest):
     driver_class = sqlalchemy.ControlDriver
     config_file = 'wsgi_sqlalchemy.conf'
     controller_class = controllers.QueueController
     control_driver_class = sqlalchemy.ControlDriver
 
 
-class SqlalchemyPoolsTest(base.PoolsControllerTest):
+class SqlalchemyPoolsTest(DBCreateMixin, base.PoolsControllerTest):
     config_file = 'wsgi_sqlalchemy.conf'
     driver_class = sqlalchemy.ControlDriver
     controller_class = controllers.PoolsController
     control_driver_class = sqlalchemy.ControlDriver
 
 
-class SqlalchemyCatalogueTest(base.CatalogueControllerTest):
+class SqlalchemyCatalogueTest(DBCreateMixin, base.CatalogueControllerTest):
     config_file = 'wsgi_sqlalchemy.conf'
     driver_class = sqlalchemy.ControlDriver
     controller_class = controllers.CatalogueController
     control_driver_class = sqlalchemy.ControlDriver
 
 
-class SqlalchemyFlavorsTest(base.FlavorsControllerTest):
+class SqlalchemyFlavorsTest(DBCreateMixin, base.FlavorsControllerTest):
     config_file = 'wsgi_sqlalchemy.conf'
     driver_class = sqlalchemy.ControlDriver
     controller_class = controllers.FlavorsController