22725754 Keystone needs to support MySQL Cluster
authorOctave Orgeron <octave.orgeron@oracle.com>
Fri, 29 Jul 2016 14:41:14 -0600
changeset 6530 c9012715dd1d
parent 6528 6d9a715f15ca
child 6531 090f9e873dbb
22725754 Keystone needs to support MySQL Cluster 22725850 Cinder needs to support MySQL Cluster 22725863 Glance needs to support MySQL Cluster 22725887 Heat needs to support MySQL Cluster 22726240 Ironic needs to support MySQL Cluster 22726251 Neutron needs to support MySQL Cluster 22726259 Nova needs to support MySQL Cluster 23033470 oslo.db needs a database option to support MySQL Cluster
components/openstack/cinder/files/cinder.conf
components/openstack/cinder/patches/15-mysql_cluster_support.patch
components/openstack/glance/files/glance-api.conf
components/openstack/glance/files/glance-registry.conf
components/openstack/glance/patches/15-mysql_cluster_support.patch
components/openstack/heat/files/heat.conf
components/openstack/heat/patches/08-mysql_cluster_support.patch
components/openstack/ironic/files/ironic.conf
components/openstack/ironic/patches/05-mysql_cluster_support.patch
components/openstack/keystone/files/keystone.conf
components/openstack/keystone/patches/mysql_cluster_support.patch
components/openstack/neutron/files/neutron.conf
components/openstack/neutron/patches/11-mysql_cluster_support.patch
components/openstack/nova/files/nova.conf
components/openstack/nova/patches/13-mysql_cluster_support.patch
components/python/oslo.db/patches/mysql_cluster_support.patch
--- a/components/openstack/cinder/files/cinder.conf	Fri Jul 29 11:02:37 2016 -0700
+++ b/components/openstack/cinder/files/cinder.conf	Fri Jul 29 14:41:14 2016 -0600
@@ -2555,6 +2555,12 @@
 # value)
 #mysql_sql_mode=TRADITIONAL
 
+# This configures the MySQL storage engine. This allows for OpenStack to
+# support different storage engines such as InnoDB, NDB, etc. By Default,
+# this value will be set to InnoDB. For MySQL Cluster, set to NDBCLUSTER.
+# Example: mysql_storage_engine=(string value)
+#mysql_storage_engine = InnoDB
+
 # Timeout before idle SQL connections are reaped. (integer
 # value)
 # Deprecated group/name - [DEFAULT]/sql_idle_timeout
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openstack/cinder/patches/15-mysql_cluster_support.patch	Fri Jul 29 14:41:14 2016 -0600
@@ -0,0 +1,758 @@
+This patchset is for bug:
+
+22725850 - Cinder needs to support MySQL Cluster
+
+This fixes the following aspects of Cinder:
+1. Implementation of an oslo.db configuration parameter to specify the MySQL
+   storage engine (mysql_storage_engine).
+2. Replacement of hardcoded SQL statements that set the engine to "InnoDB"
+   to the above configuration value.
+3. Logic to handle SQL differences between MySQL InnoDB and MySQL Cluster (NDB).
+   This includes column lengths, constraints, foreign keys, and indexes.
+
+This has not been committed upstream, but has been filed in launchpad:
+
+https://bugs.launchpad.net/cinder/+bug/1564110 
+
+
+--- cinder-2015.1.2/cinder/tests/test_migrations.py.orig	2016-07-29 11:00:01.187925033 -0600
++++ cinder-2015.1.2/cinder/tests/test_migrations.py	2016-07-29 11:04:05.631912887 -0600
+@@ -24,6 +24,7 @@ import uuid
+ 
+ from migrate.versioning import api as migration_api
+ from migrate.versioning import repository
++from oslo_config import cfg
+ from oslo_db.sqlalchemy import test_base
+ from oslo_db.sqlalchemy import test_migrations
+ from oslo_db.sqlalchemy import utils as db_utils
+@@ -32,6 +33,7 @@ import sqlalchemy
+ from cinder.db import migration
+ import cinder.db.sqlalchemy.migrate_repo
+ 
++CONF = cfg.CONF
+ 
+ class MigrationsMixin(test_migrations.WalkVersionsMixin):
+     """Test sqlalchemy-migrate migrations."""
+@@ -850,8 +852,9 @@ class TestMysqlMigrations(test_base.MySQ
+             "SELECT count(*) "
+             "from information_schema.TABLES "
+             "where TABLE_SCHEMA='openstack_citest' "
+-            "and ENGINE!='InnoDB' "
+-            "and TABLE_NAME!='migrate_version'")
++            "and ENGINE!='%(mysql_storage_engine)s' "
++            "and TABLE_NAME!='migrate_version'" %
++             dict(mysql_storage_engine=CONF.database.mysql_storage_engine))
+         count = noninnodb.scalar()
+         self.assertEqual(count, 0, "%d non InnoDB tables created" % count)
+ 
+--- cinder-2015.1.2/cinder/db/sqlalchemy/models.py.orig	2016-07-29 11:00:10.501447650 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/models.py	2016-07-28 13:42:21.527353348 -0600
+@@ -36,7 +36,7 @@ class CinderBase(models.TimestampMixin,
+                  models.ModelBase):
+     """Base class for Cinder Models."""
+ 
+-    __table_args__ = {'mysql_engine': 'InnoDB'}
++    __table_args__ = {'mysql_engine': CONF.database.mysql_storage_engine }
+ 
+     # TODO(rpodolyaka): reuse models.SoftDeleteMixin in the next stage
+     #                   of implementing of BP db-cleanup
+@@ -488,7 +488,7 @@ class IscsiTarget(BASE, CinderBase):
+     """Represents an iscsi target for a given host."""
+     __tablename__ = 'iscsi_targets'
+     __table_args__ = (schema.UniqueConstraint("target_num", "host"),
+-                      {'mysql_engine': 'InnoDB'})
++                      {'mysql_engine': CONF.database.mysql_storage_engine })
+     id = Column(Integer, primary_key=True)
+     target_num = Column(Integer)
+     host = Column(String(255))
+@@ -576,7 +576,7 @@ class DriverInitiatorData(BASE, models.T
+     __tablename__ = 'driver_initiator_data'
+     __table_args__ = (
+         schema.UniqueConstraint("initiator", "namespace", "key"),
+-        {'mysql_engine': 'InnoDB'}
++        {'mysql_engine': CONF.database.mysql_storage_engine }
+     )
+     id = Column(Integer, primary_key=True, nullable=False)
+     initiator = Column(String(255), index=True, nullable=False)
+--- cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/038_add_driver_initiator_data_table.py.orig	2016-07-29 11:00:18.420463823 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/038_add_driver_initiator_data_table.py	2016-07-29 11:05:16.443295143 -0600
+@@ -10,6 +10,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from oslo_log import log as logging
+ from sqlalchemy import Column, DateTime, Integer
+ from sqlalchemy import MetaData, String, Table, UniqueConstraint
+@@ -18,6 +19,7 @@ from cinder.i18n import _LE
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -34,7 +36,7 @@ def upgrade(migrate_engine):
+         Column('key', String(length=255), nullable=False),
+         Column('value', String(length=255)),
+         UniqueConstraint('initiator', 'namespace', 'key'),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+--- cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/020_add_volume_admin_metadata_table.py.orig	2016-07-29 11:00:26.045131176 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/020_add_volume_admin_metadata_table.py	2016-07-29 11:05:59.377263934 -0600
+@@ -10,6 +10,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from oslo_log import log as logging
+ from sqlalchemy import Boolean, Column, DateTime
+ from sqlalchemy import Integer, MetaData, String, Table, ForeignKey
+@@ -18,6 +19,7 @@ from cinder.i18n import _
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -37,7 +39,7 @@ def upgrade(migrate_engine):
+                nullable=False),
+         Column('key', String(length=255)),
+         Column('value', String(length=255)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+--- cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/040_add_volume_attachment.py.orig	2016-07-29 11:00:33.982622176 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/040_add_volume_attachment.py	2016-07-29 11:06:48.928094250 -0600
+@@ -16,6 +16,7 @@
+ import datetime
+ import uuid
+ 
++from oslo_config import cfg
+ from oslo_log import log as logging
+ import six
+ from sqlalchemy import Boolean, Column, DateTime
+@@ -27,6 +28,7 @@ LOG = logging.getLogger(__name__)
+ 
+ CREATED_AT = datetime.datetime.now()  # noqa
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     """Add volume multi attachment table."""
+@@ -56,7 +58,7 @@ def upgrade(migrate_engine):
+         Column('detach_time', DateTime),
+         Column('attach_mode', String(length=36)),
+         Column('attach_status', String(length=255)),
+-        mysql_engine='InnoDB'
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     try:
+--- cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/003_glance_metadata.py.orig	2016-07-29 11:00:44.515262427 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/003_glance_metadata.py	2016-07-29 11:07:29.288662336 -0600
+@@ -12,6 +12,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from oslo_log import log as logging
+ from sqlalchemy import Column, DateTime, Text, Boolean
+ from sqlalchemy import MetaData, Integer, String, Table, ForeignKey
+@@ -20,6 +21,7 @@ from cinder.i18n import _
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -31,11 +33,11 @@ def upgrade(migrate_engine):
+     Table('volumes',
+           meta,
+           Column('id', Integer(), primary_key=True, nullable=False),
+-          mysql_engine='InnoDB')
++          mysql_engine=CONF.database.mysql_storage_engine)
+     Table('snapshots',
+           meta,
+           Column('id', Integer(), primary_key=True, nullable=False),
+-          mysql_engine='InnoDB')
++          mysql_engine=CONF.database.mysql_storage_engine)
+     # Create new table
+     volume_glance_metadata = Table(
+         'volume_glance_metadata',
+@@ -50,7 +52,7 @@ def upgrade(migrate_engine):
+                ForeignKey('snapshots.id')),
+         Column('key', String(255)),
+         Column('value', Text),
+-        mysql_engine='InnoDB'
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     try:
+--- cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/008_add_backup.py.orig	2016-07-29 11:00:53.408609592 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/008_add_backup.py	2016-07-29 11:07:52.389988927 -0600
+@@ -13,6 +13,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from oslo_log import log as logging
+ from sqlalchemy import Boolean, Column, DateTime
+ from sqlalchemy import MetaData, Integer, String, Table
+@@ -21,6 +22,7 @@ from cinder.i18n import _
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -48,7 +50,7 @@ def upgrade(migrate_engine):
+         Column('service', String(length=255)),
+         Column('size', Integer()),
+         Column('object_count', Integer()),
+-        mysql_engine='InnoDB'
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     try:
+--- cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/015_drop_migrations_table.py.orig	2016-07-29 11:01:00.740311806 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/015_drop_migrations_table.py	2016-07-29 11:08:17.460343611 -0600
+@@ -10,6 +10,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from oslo_log import log as logging
+ from sqlalchemy import Boolean, Column, DateTime, Integer
+ from sqlalchemy import MetaData, String, Table
+@@ -18,6 +19,7 @@ from cinder.i18n import _LE
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
+ 
+ TABLE_NAME = 'migrations'
+ 
+@@ -52,7 +54,7 @@ def downgrade(migrate_engine):
+         Column('new_instance_type_id', Integer),
+         Column('instance_uuid', String(length=255), nullable=True),
+         Column('status', String(length=255)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+--- cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/025_add_consistencygroup.py.orig	2016-07-29 11:01:06.931319374 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/025_add_consistencygroup.py	2016-07-29 11:08:57.529967194 -0600
+@@ -13,6 +13,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from migrate import ForeignKeyConstraint
+ from oslo_log import log as logging
+ from sqlalchemy import Boolean, Column, DateTime
+@@ -22,6 +23,7 @@ from cinder.i18n import _
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -43,7 +45,7 @@ def upgrade(migrate_engine):
+         Column('description', String(length=255)),
+         Column('volume_type_id', String(length=255)),
+         Column('status', String(length=255)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8',
+     )
+ 
+@@ -69,7 +71,7 @@ def upgrade(migrate_engine):
+         Column('name', String(length=255)),
+         Column('description', String(length=255)),
+         Column('status', String(length=255)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8',
+     )
+ 
+--- cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/002_quota_class.py.orig	2016-07-29 11:01:13.333257167 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/002_quota_class.py	2016-07-29 11:09:26.907320861 -0600
+@@ -12,6 +12,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from migrate import ForeignKeyConstraint
+ from oslo_log import log as logging
+ from sqlalchemy import Boolean, Column, DateTime
+@@ -21,6 +22,7 @@ from cinder.i18n import _LE
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -40,7 +42,7 @@ def upgrade(migrate_engine):
+                           Column('resource',
+                                  String(length=255)),
+                           Column('hard_limit', Integer(), nullable=True),
+-                          mysql_engine='InnoDB',
++                          mysql_engine=CONF.database.mysql_storage_engine,
+                           mysql_charset='utf8',
+                           )
+ 
+@@ -65,7 +67,7 @@ def upgrade(migrate_engine):
+                          Column('in_use', Integer(), nullable=False),
+                          Column('reserved', Integer(), nullable=False),
+                          Column('until_refresh', Integer(), nullable=True),
+-                         mysql_engine='InnoDB',
++                         mysql_engine=CONF.database.mysql_storage_engine,
+                          mysql_charset='utf8',
+                          )
+ 
+@@ -96,7 +98,7 @@ def upgrade(migrate_engine):
+                                 String(length=255)),
+                          Column('delta', Integer(), nullable=False),
+                          Column('expire', DateTime(timezone=False)),
+-                         mysql_engine='InnoDB',
++                         mysql_engine=CONF.database.mysql_storage_engine,
+                          mysql_charset='utf8',
+                          )
+ 
+--- cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/032_add_volume_type_projects.py.orig	2016-07-29 11:01:19.787463555 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/032_add_volume_type_projects.py	2016-07-29 11:09:52.305137688 -0600
+@@ -10,6 +10,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from oslo_log import log as logging
+ from sqlalchemy import Boolean, Column, DateTime, UniqueConstraint
+ from sqlalchemy import Integer, MetaData, String, Table, ForeignKey
+@@ -18,6 +19,7 @@ from cinder.i18n import _
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -44,7 +46,7 @@ def upgrade(migrate_engine):
+         Column('project_id', String(length=255)),
+         Column('deleted', Boolean(create_constraint=True, name=None)),
+         UniqueConstraint('volume_type_id', 'project_id', 'deleted'),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+     )
+ 
+     try:
+--- cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/016_drop_sm_tables.py.orig	2016-07-29 11:01:27.964276573 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/016_drop_sm_tables.py	2016-07-29 11:10:16.404751177 -0600
+@@ -12,6 +12,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from oslo_log import log as logging
+ from sqlalchemy import Boolean, Column, DateTime, ForeignKey
+ from sqlalchemy import Integer, MetaData, String, Table
+@@ -20,6 +21,7 @@ from cinder.i18n import _
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -58,7 +60,7 @@ def downgrade(migrate_engine):
+         Column('sr_uuid', String(length=255)),
+         Column('sr_type', String(length=255)),
+         Column('config_params', String(length=2047)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -71,7 +73,7 @@ def downgrade(migrate_engine):
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('label', String(length=255)),
+         Column('description', String(length=255)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -88,7 +90,7 @@ def downgrade(migrate_engine):
+         Column('backend_id', Integer, ForeignKey('sm_backend_config.id'),
+                nullable=False),
+         Column('vdi_uuid', String(length=255)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+--- cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/010_add_transfers_table.py.orig	2016-07-29 11:01:37.572002193 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/010_add_transfers_table.py	2016-07-29 11:10:53.099824733 -0600
+@@ -10,6 +10,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from oslo_log import log as logging
+ from sqlalchemy import Boolean, Column, DateTime
+ from sqlalchemy import MetaData, String, Table, ForeignKey
+@@ -18,6 +19,7 @@ from cinder.i18n import _
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -39,7 +41,7 @@ def upgrade(migrate_engine):
+         Column('salt', String(length=255)),
+         Column('crypt_hash', String(length=255)),
+         Column('expires_at', DateTime(timezone=False)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+--- cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/009_add_snapshot_metadata_table.py.orig	2016-07-29 11:01:45.740057328 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/009_add_snapshot_metadata_table.py	2016-07-29 11:11:37.227187391 -0600
+@@ -10,6 +10,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from oslo_log import log as logging
+ from sqlalchemy import Boolean, Column, DateTime
+ from sqlalchemy import Integer, MetaData, String, Table, ForeignKey
+@@ -18,6 +19,7 @@ from cinder.i18n import _
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -37,7 +39,7 @@ def upgrade(migrate_engine):
+                nullable=False),
+         Column('key', String(length=255)),
+         Column('value', String(length=255)),
+-        mysql_engine='InnoDB'
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     try:
+--- cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/018_add_qos_specs.py.orig	2016-07-29 11:01:52.386692827 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/018_add_qos_specs.py	2016-07-29 11:12:05.698971502 -0600
+@@ -14,6 +14,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from oslo_log import log as logging
+ from sqlalchemy import Boolean, Column, DateTime
+ from sqlalchemy import ForeignKey, MetaData, String, Table
+@@ -23,6 +24,7 @@ from cinder.i18n import _
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     """Add volume_type_rate_limit table."""
+@@ -40,7 +42,7 @@ def upgrade(migrate_engine):
+                ForeignKey('quality_of_service_specs.id')),
+         Column('key', String(255)),
+         Column('value', String(255)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+--- cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/017_add_encryption_information.py.orig	2016-07-29 11:01:59.835986722 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/017_add_encryption_information.py	2016-07-29 11:12:38.107548537 -0600
+@@ -13,15 +13,16 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from oslo_log import log as logging
+ from sqlalchemy import Column, ForeignKey, MetaData, Table
+ from sqlalchemy import Boolean, DateTime, Integer, String
+ 
+ from cinder.i18n import _
+ 
+-
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData(bind=migrate_engine)
+@@ -69,9 +70,9 @@ def upgrade(migrate_engine):
+         # scheme unless each volume type is associated with at most one
+         # encryption scheme.
+         Column('volume_type_id', String(length=36),
+-               ForeignKey(volume_types.c.id),
++               ForeignKey(volume_types.c.id, name='encryption_ibfk_1'),
+                primary_key=True, nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+--- cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/001_cinder_init.py.orig	2016-07-29 11:02:08.740069069 -0600
++++ cinder-2015.1.2/cinder/db/sqlalchemy/migrate_repo/versions/001_cinder_init.py	2016-07-29 11:13:11.172896165 -0600
+@@ -12,15 +12,21 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from oslo_log import log as logging
+ from sqlalchemy import Boolean, Column, DateTime, ForeignKey
+ from sqlalchemy import Integer, MetaData, String, Table
+ 
+ from cinder.i18n import _
+ 
+-
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
++
++if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++    db_string_length = 128
++else:
++    db_string_length = 255
+ 
+ def define_tables(meta):
+     migrations = Table(
+@@ -30,14 +36,14 @@ def define_tables(meta):
+         Column('deleted_at', DateTime),
+         Column('deleted', Boolean),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('source_compute', String(length=255)),
+-        Column('dest_compute', String(length=255)),
+-        Column('dest_host', String(length=255)),
+-        Column('status', String(length=255)),
+-        Column('instance_uuid', String(length=255)),
++        Column('source_compute', String(length=db_string_length)),
++        Column('dest_compute', String(length=db_string_length)),
++        Column('dest_host', String(length=db_string_length)),
++        Column('status', String(length=db_string_length)),
++        Column('instance_uuid', String(length=db_string_length)),
+         Column('old_instance_type_id', Integer),
+         Column('new_instance_type_id', Integer),
+-        mysql_engine='InnoDB'
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     services = Table(
+@@ -47,13 +53,13 @@ def define_tables(meta):
+         Column('deleted_at', DateTime),
+         Column('deleted', Boolean),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('host', String(length=255)),
+-        Column('binary', String(length=255)),
+-        Column('topic', String(length=255)),
++        Column('host', String(length=db_string_length)),
++        Column('binary', String(length=db_string_length)),
++        Column('topic', String(length=db_string_length)),
+         Column('report_count', Integer, nullable=False),
+         Column('disabled', Boolean),
+-        Column('availability_zone', String(length=255)),
+-        mysql_engine='InnoDB'
++        Column('availability_zone', String(length=db_string_length)),
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     sm_flavors = Table(
+@@ -63,9 +69,9 @@ def define_tables(meta):
+         Column('deleted_at', DateTime),
+         Column('deleted', Boolean),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('label', String(length=255)),
+-        Column('description', String(length=255)),
+-        mysql_engine='InnoDB'
++        Column('label', String(length=db_string_length)),
++        Column('description', String(length=db_string_length)),
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     sm_backend_config = Table(
+@@ -77,10 +83,10 @@ def define_tables(meta):
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('flavor_id', Integer, ForeignKey('sm_flavors.id'),
+                nullable=False),
+-        Column('sr_uuid', String(length=255)),
+-        Column('sr_type', String(length=255)),
++        Column('sr_uuid', String(length=db_string_length)),
++        Column('sr_type', String(length=db_string_length)),
+         Column('config_params', String(length=2047)),
+-        mysql_engine='InnoDB'
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     sm_volume = Table(
+@@ -95,8 +101,8 @@ def define_tables(meta):
+                nullable=False),
+         Column('backend_id', Integer, ForeignKey('sm_backend_config.id'),
+                nullable=False),
+-        Column('vdi_uuid', String(length=255)),
+-        mysql_engine='InnoDB'
++        Column('vdi_uuid', String(length=db_string_length)),
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     snapshots = Table(
+@@ -107,15 +113,15 @@ def define_tables(meta):
+         Column('deleted', Boolean),
+         Column('id', String(length=36), primary_key=True, nullable=False),
+         Column('volume_id', String(length=36), nullable=False),
+-        Column('user_id', String(length=255)),
+-        Column('project_id', String(length=255)),
+-        Column('status', String(length=255)),
+-        Column('progress', String(length=255)),
++        Column('user_id', String(length=db_string_length)),
++        Column('project_id', String(length=db_string_length)),
++        Column('status', String(length=db_string_length)),
++        Column('progress', String(length=db_string_length)),
+         Column('volume_size', Integer),
+         Column('scheduled_at', DateTime),
+-        Column('display_name', String(length=255)),
+-        Column('display_description', String(length=255)),
+-        mysql_engine='InnoDB'
++        Column('display_name', String(length=db_string_length)),
++        Column('display_description', String(length=db_string_length)),
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     volume_types = Table(
+@@ -125,8 +131,8 @@ def define_tables(meta):
+         Column('deleted_at', DateTime),
+         Column('deleted', Boolean),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('name', String(length=255)),
+-        mysql_engine='InnoDB'
++        Column('name', String(length=db_string_length)),
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     volume_metadata = Table(
+@@ -138,9 +144,9 @@ def define_tables(meta):
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('volume_id', String(length=36), ForeignKey('volumes.id'),
+                nullable=False),
+-        Column('key', String(length=255)),
+-        Column('value', String(length=255)),
+-        mysql_engine='InnoDB'
++        Column('key', String(length=db_string_length)),
++        Column('value', String(length=db_string_length)),
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     volume_type_extra_specs = Table(
+@@ -152,9 +158,9 @@ def define_tables(meta):
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('volume_type_id', Integer, ForeignKey('volume_types.id'),
+                nullable=False),
+-        Column('key', String(length=255)),
+-        Column('value', String(length=255)),
+-        mysql_engine='InnoDB'
++        Column('key', String(length=db_string_length)),
++        Column('value', String(length=db_string_length)),
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     volumes = Table(
+@@ -164,27 +170,27 @@ def define_tables(meta):
+         Column('deleted_at', DateTime),
+         Column('deleted', Boolean),
+         Column('id', String(length=36), primary_key=True, nullable=False),
+-        Column('ec2_id', String(length=255)),
+-        Column('user_id', String(length=255)),
+-        Column('project_id', String(length=255)),
+-        Column('host', String(length=255)),
++        Column('ec2_id', String(length=db_string_length)),
++        Column('user_id', String(length=db_string_length)),
++        Column('project_id', String(length=db_string_length)),
++        Column('host', String(length=db_string_length)),
+         Column('size', Integer),
+-        Column('availability_zone', String(length=255)),
++        Column('availability_zone', String(length=db_string_length)),
+         Column('instance_uuid', String(length=36)),
+-        Column('mountpoint', String(length=255)),
+-        Column('attach_time', String(length=255)),
+-        Column('status', String(length=255)),
+-        Column('attach_status', String(length=255)),
++        Column('mountpoint', String(length=db_string_length)),
++        Column('attach_time', String(length=db_string_length)),
++        Column('status', String(length=db_string_length)),
++        Column('attach_status', String(length=db_string_length)),
+         Column('scheduled_at', DateTime),
+         Column('launched_at', DateTime),
+         Column('terminated_at', DateTime),
+-        Column('display_name', String(length=255)),
+-        Column('display_description', String(length=255)),
++        Column('display_name', String(length=db_string_length)),
++        Column('display_description', String(length=db_string_length)),
+         Column('provider_location', String(length=256)),
+         Column('provider_auth', String(length=256)),
+         Column('snapshot_id', String(length=36)),
+         Column('volume_type_id', Integer),
+-        mysql_engine='InnoDB'
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     quotas = Table(
+@@ -194,10 +200,10 @@ def define_tables(meta):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('deleted', Boolean),
+-        Column('project_id', String(length=255)),
+-        Column('resource', String(length=255), nullable=False),
++        Column('project_id', String(length=db_string_length)),
++        Column('resource', String(length=db_string_length), nullable=False),
+         Column('hard_limit', Integer),
+-        mysql_engine='InnoDB'
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     iscsi_targets = Table(
+@@ -208,10 +214,10 @@ def define_tables(meta):
+         Column('deleted', Boolean),
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('target_num', Integer),
+-        Column('host', String(length=255)),
++        Column('host', String(length=db_string_length)),
+         Column('volume_id', String(length=36), ForeignKey('volumes.id'),
+                nullable=True),
+-        mysql_engine='InnoDB'
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+     return [sm_flavors,
+             sm_backend_config,
+@@ -266,7 +272,8 @@ def upgrade(migrate_engine):
+         migrate_engine.execute(
+             "ALTER DATABASE %s DEFAULT CHARACTER SET utf8" %
+             migrate_engine.url.database)
+-        migrate_engine.execute("ALTER TABLE %s Engine=InnoDB" % table)
++        migrate_engine.execute("ALTER TABLE %(db_table)s Engine=%(mysql_storage_engine)s" % 
++                               dict(db_table=table, mysql_storage_engine=CONF.database.mysql_storage_engine))
+ 
+ 
+ def downgrade(migrate_engine):
--- a/components/openstack/glance/files/glance-api.conf	Fri Jul 29 11:02:37 2016 -0700
+++ b/components/openstack/glance/files/glance-api.conf	Fri Jul 29 14:41:14 2016 -0600
@@ -514,6 +514,12 @@
 # Example: mysql_sql_mode= (string value)
 #mysql_sql_mode = TRADITIONAL
 
+# This configures the MySQL storage engine. This allows for OpenStack to
+# support different storage engines such as InnoDB, NDB, etc. By Default,
+# this value will be set to InnoDB. For MySQL Cluster, set to NDBCLUSTER.
+# Example: mysql_storage_engine=(string value)
+#mysql_storage_engine = InnoDB
+
 # Timeout before idle SQL connections are reaped. (integer value)
 # Deprecated group/name - [DEFAULT]/sql_idle_timeout
 # Deprecated group/name - [DATABASE]/sql_idle_timeout
--- a/components/openstack/glance/files/glance-registry.conf	Fri Jul 29 11:02:37 2016 -0700
+++ b/components/openstack/glance/files/glance-registry.conf	Fri Jul 29 14:41:14 2016 -0600
@@ -352,6 +352,12 @@
 # Example: mysql_sql_mode= (string value)
 #mysql_sql_mode = TRADITIONAL
 
+# This configures the MySQL storage engine. This allows for OpenStack to
+# support different storage engines such as InnoDB, NDB, etc. By Default,
+# this value will be set to InnoDB. For MySQL Cluster, set to NDBCLUSTER.
+# Example: mysql_storage_engine=(string value)
+#mysql_storage_engine = InnoDB
+
 # Timeout before idle SQL connections are reaped. (integer value)
 # Deprecated group/name - [DEFAULT]/sql_idle_timeout
 # Deprecated group/name - [DATABASE]/sql_idle_timeout
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openstack/glance/patches/15-mysql_cluster_support.patch	Fri Jul 29 14:41:14 2016 -0600
@@ -0,0 +1,1215 @@
+This patchset is for bug:
+
+22725863 - Glance needs to support MySQL Cluster
+
+This fixes the following aspects of Glance:
+1. Implementation of an oslo.db configuration parameter to specify the MySQL
+   storage engine (mysql_storage_engine).
+2. Replacement of hardcoded SQL statements that set the engine to "InnoDB"
+   to the above configuration value.
+3. Logic to handle SQL differences between MySQL InnoDB and MySQL Cluster (NDB).
+   This includes column lengths, constraints, foreign keys, and indexes.
+
+This has not been committed upstream, but has been filed in launchpad:
+
+https://bugs.launchpad.net/glance/+bug/1564110
+
+
+--- glance-2015.1.2/glance/tests/unit/test_migrations.py.orig	2016-07-29 11:30:42.506075746 -0600
++++ glance-2015.1.2/glance/tests/unit/test_migrations.py	2016-07-28 18:16:26.555277376 -0600
+@@ -127,7 +127,7 @@ class MigrationsMixin(test_migrations.Wa
+                                                         sqlalchemy.Boolean(),
+                                                         nullable=False,
+                                                         default=False),
+-                                      mysql_engine='InnoDB')
++                                      mysql_engine=CONF.database.mysql_storage_engine)
+         images_001.create()
+ 
+     def test_version_control_existing_db(self):
+@@ -1650,10 +1650,10 @@ class TestMysqlMigrations(test_base.MySQ
+         noninnodb = self.migrate_engine.execute(
+             "SELECT count(*) "
+             "FROM information_schema.TABLES "
+-            "WHERE TABLE_SCHEMA='%s' "
+-            "AND ENGINE!='InnoDB' "
++            "WHERE TABLE_SCHEMA='%(table_schema)s' "
++            "AND ENGINE!='%(mysql_storage_engine)s' "
+             "AND TABLE_NAME!='migrate_version'"
+-            % self.migrate_engine.url.database)
++            % dict(table_schema=self.migrate_engine.url.database, mysql_storage_engine=CONF.database.mysql_storage_engine))
+         count = noninnodb.scalar()
+         self.assertEqual(count, 0, "%d non InnoDB tables created" % count)
+ 
+--- glance-2015.1.2/glance/db/sqlalchemy/models_metadef.py.orig	2016-07-29 11:30:50.672701806 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/models_metadef.py	2016-07-29 11:37:23.040809599 -0600
+@@ -16,6 +16,7 @@
+ SQLAlchemy models for glance metadata schema
+ """
+ 
++from oslo_config import cfg
+ from oslo_db.sqlalchemy import models
+ from oslo_utils import timeutils
+ from sqlalchemy import Boolean
+@@ -31,6 +32,7 @@ from sqlalchemy import Text
+ 
+ from glance.db.sqlalchemy.models import JSONEncodedDict
+ 
++CONF = cfg.CONF
+ 
+ class DictionaryBase(models.ModelBase):
+     metadata = None
+@@ -48,7 +50,7 @@ BASE_DICT = declarative_base(cls=Diction
+ class GlanceMetadefBase(models.TimestampMixin):
+     """Base class for Glance Metadef Models."""
+ 
+-    __table_args__ = {'mysql_engine': 'InnoDB'}
++    __table_args__ = {'mysql_engine': CONF.database.mysql_storage_engine}
+     __table_initialized__ = False
+     __protected_attributes__ = set(["created_at", "updated_at"])
+ 
+--- glance-2015.1.2/glance/db/sqlalchemy/models_artifacts.py.orig	2016-07-29 11:30:58.519236555 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/models_artifacts.py	2016-07-28 18:16:26.556002509 -0600
+@@ -14,6 +14,8 @@
+ 
+ import uuid
+ 
++from oslo_config import cfg
++from oslo_db import options as db_options
+ from oslo_db.sqlalchemy import models
+ from oslo_utils import timeutils
+ from sqlalchemy import BigInteger
+@@ -36,6 +38,9 @@ from glance.common import semver_db
+ from glance import i18n
+ from oslo_log import log as os_logging
+ 
++CONF = cfg.CONF
++db_options.set_defaults(CONF)
++
+ BASE = declarative.declarative_base()
+ LOG = os_logging.getLogger(__name__)
+ _LW = i18n._LW
+@@ -44,7 +49,7 @@ _LW = i18n._LW
+ class ArtifactBase(models.ModelBase, models.TimestampMixin):
+     """Base class for Artifact Models."""
+ 
+-    __table_args__ = {'mysql_engine': 'InnoDB'}
++    __table_args__ = {'mysql_engine': CONF.database.mysql_storage_engine}
+     __table_initialized__ = False
+     __protected_attributes__ = set([
+         "created_at", "updated_at"])
+@@ -102,7 +107,7 @@ class Artifact(BASE, ArtifactBase):
+         Index('ix_artifact_state', 'state'),
+         Index('ix_artifact_owner', 'owner'),
+         Index('ix_artifact_visibility', 'visibility'),
+-        {'mysql_engine': 'InnoDB'})
++        {'mysql_engine': CONF.database.mysql_storage_engine})
+ 
+     __protected_attributes__ = ArtifactBase.__protected_attributes__.union(
+         set(['published_at', 'deleted_at']))
+@@ -219,7 +224,7 @@ class ArtifactDependency(BASE, ArtifactB
+                             'artifact_dest'),
+                       Index('ix_artifact_dependencies_direct_dependencies',
+                             'artifact_source', 'is_direct'),
+-                      {'mysql_engine': 'InnoDB'})
++                      {'mysql_engine': CONF.database.mysql_storage_engine})
+ 
+     id = Column(String(36), primary_key=True, nullable=False,
+                 default=lambda: str(uuid.uuid4()))
+@@ -248,7 +253,7 @@ class ArtifactTag(BASE, ArtifactBase):
+     __table_args__ = (Index('ix_artifact_tags_artifact_id', 'artifact_id'),
+                       Index('ix_artifact_tags_artifact_id_tag_value',
+                             'artifact_id', 'value'),
+-                      {'mysql_engine': 'InnoDB'},)
++                      {'mysql_engine': CONF.database.mysql_storage_engine},)
+ 
+     id = Column(String(36), primary_key=True, nullable=False,
+                 default=lambda: str(uuid.uuid4()))
+@@ -265,7 +270,7 @@ class ArtifactProperty(BASE, ArtifactBas
+     __table_args__ = (
+         Index('ix_artifact_properties_artifact_id', 'artifact_id'),
+         Index('ix_artifact_properties_name', 'name'),
+-        {'mysql_engine': 'InnoDB'},)
++        {'mysql_engine': CONF.database.mysql_storage_engine},)
+     id = Column(String(36), primary_key=True, nullable=False,
+                 default=lambda: str(uuid.uuid4()))
+     artifact_id = Column(String(36), ForeignKey('artifacts.id'),
+@@ -287,7 +292,7 @@ class ArtifactBlob(BASE, ArtifactBase):
+     __table_args__ = (
+         Index('ix_artifact_blobs_artifact_id', 'artifact_id'),
+         Index('ix_artifact_blobs_name', 'name'),
+-        {'mysql_engine': 'InnoDB'},)
++        {'mysql_engine': CONF.database.mysql_storage_engine},)
+     id = Column(String(36), primary_key=True, nullable=False,
+                 default=lambda: str(uuid.uuid4()))
+     artifact_id = Column(String(36), ForeignKey('artifacts.id'),
+@@ -306,7 +311,7 @@ class ArtifactBlobLocation(BASE, Artifac
+     __tablename__ = 'artifact_blob_locations'
+     __table_args__ = (Index('ix_artifact_blob_locations_blob_id',
+                             'blob_id'),
+-                      {'mysql_engine': 'InnoDB'})
++                      {'mysql_engine': CONF.database.mysql_storage_engine})
+ 
+     id = Column(String(36), primary_key=True, nullable=False,
+                 default=lambda: str(uuid.uuid4()))
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/007_add_owner.py.orig	2016-07-29 11:31:06.067376033 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/007_add_owner.py	2016-07-29 11:38:21.570131052 -0600
+@@ -14,12 +14,14 @@
+ #    under the License.
+ 
+ from migrate.changeset import *  # noqa
++from oslo_config import cfg
+ from sqlalchemy import *  # noqa
+ 
+ from glance.db.sqlalchemy.migrate_repo.schema import (
+     Boolean, DateTime, BigInteger, Integer, String,
+     Text, from_migration_import)  # noqa
+ 
++CONF = cfg.CONF
+ 
+ def get_images_table(meta):
+     """
+@@ -50,7 +52,7 @@ def get_images_table(meta):
+                           index=True),
+                    Column('checksum', String(32)),
+                    Column('owner', String(255)),
+-                   mysql_engine='InnoDB',
++                   mysql_engine=CONF.database.mysql_storage_engine,
+                    extend_existing=True)
+ 
+     return images
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/003_add_disk_format.py.orig	2016-07-29 11:31:13.058662840 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/003_add_disk_format.py	2016-07-29 11:38:43.705439106 -0600
+@@ -14,11 +14,13 @@
+ #    under the License.
+ 
+ from migrate.changeset import *  # noqa
++from oslo_config import cfg
+ from sqlalchemy import *  # noqa
+ 
+ from glance.db.sqlalchemy.migrate_repo.schema import (
+     Boolean, DateTime, Integer, String, Text, from_migration_import)  # noqa
+ 
++CONF = cfg.CONF
+ 
+ def get_images_table(meta):
+     """
+@@ -47,7 +49,7 @@ def get_images_table(meta):
+                           nullable=False,
+                           default=False,
+                           index=True),
+-                   mysql_engine='InnoDB',
++                   mysql_engine=CONF.database.mysql_storage_engine,
+                    extend_existing=True)
+ 
+     return images
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/005_size_big_integer.py.orig	2016-07-29 11:31:20.152951372 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/005_size_big_integer.py	2016-07-29 11:39:04.202176317 -0600
+@@ -14,12 +14,14 @@
+ #    under the License.
+ 
+ from migrate.changeset import *  # noqa
++from oslo_config import cfg
+ from sqlalchemy import *  # noqa
+ 
+ from glance.db.sqlalchemy.migrate_repo.schema import (
+     Boolean, DateTime, BigInteger, Integer, String,
+     Text, from_migration_import)  # noqa
+ 
++CONF = cfg.CONF
+ 
+ def get_images_table(meta):
+     """
+@@ -48,7 +50,7 @@ def get_images_table(meta):
+                           nullable=False,
+                           default=False,
+                           index=True),
+-                   mysql_engine='InnoDB',
++                   mysql_engine=CONF.database.mysql_storage_engine,
+                    extend_existing=True)
+ 
+     return images
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/022_image_member_index.py.orig	2016-07-29 11:31:30.015287184 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/022_image_member_index.py	2016-07-29 11:39:26.850998479 -0600
+@@ -16,11 +16,13 @@
+ import re
+ 
+ from migrate.changeset import UniqueConstraint
++from oslo_config import cfg
+ from oslo_db import exception as db_exception
+ from sqlalchemy import and_, func, orm
+ from sqlalchemy import MetaData, Table
+ from sqlalchemy.exc import OperationalError, ProgrammingError
+ 
++CONF = cfg.CONF
+ 
+ NEW_KEYNAME = 'image_members_image_id_member_deleted_at_key'
+ ORIGINAL_KEYNAME_RE = re.compile('image_members_image_id.*_key')
+@@ -28,21 +30,24 @@ ORIGINAL_KEYNAME_RE = re.compile('image_
+ 
+ def upgrade(migrate_engine):
+     image_members = _get_image_members_table(migrate_engine)
+-
+-    if migrate_engine.name in ('mysql', 'postgresql'):
+-        try:
+-            UniqueConstraint('image_id',
+-                             name=_get_original_keyname(migrate_engine.name),
+-                             table=image_members).drop()
+-        except (OperationalError, ProgrammingError, db_exception.DBError):
+-            UniqueConstraint('image_id',
+-                             name=_infer_original_keyname(image_members),
+-                             table=image_members).drop()
+-        UniqueConstraint('image_id',
+-                         'member',
+-                         'deleted_at',
+-                         name=NEW_KEYNAME,
+-                         table=image_members).create()
++    # MySQL Cluster, a.k.a. NDB does not support the original constraint and index.
++    # Only if we are not using MySQL Cluster, will the index be dropped.
++    if CONF.database.mysql_storage_engine != "NDBCLUSTER":
++        if migrate_engine.name in ('mysql', 'postgresql'):
++            try:
++                UniqueConstraint('image_id',
++                                 name=_get_original_keyname(migrate_engine.name),
++                                 table=image_members).drop()
++            except (OperationalError, ProgrammingError, db_exception.DBError):
++                UniqueConstraint('image_id',
++                                 name=_infer_original_keyname(image_members),
++                                 table=image_members).drop()
++        
++    UniqueConstraint('image_id',
++                     'member',
++                     'deleted_at',
++                     name=NEW_KEYNAME,
++                     table=image_members).create()
+ 
+ 
+ def downgrade(migrate_engine):
+@@ -53,10 +58,13 @@ def downgrade(migrate_engine):
+         UniqueConstraint('image_id',
+                          name=NEW_KEYNAME,
+                          table=image_members).drop()
+-        UniqueConstraint('image_id',
+-                         'member',
+-                         name=_get_original_keyname(migrate_engine.name),
+-                         table=image_members).create()
++        # MySQL Cluster, a.k.a. NDB does not support the original constraint and index.
++        # Only if we are not using MySQL Cluster, will the index be created.
++        if CONF.database.mysql_storage_engine != "NDBCLUSTER":
++            UniqueConstraint('image_id',
++                             'member',
++                             name=_get_original_keyname(migrate_engine.name),
++                             table=image_members).create()
+ 
+ 
+ def _get_image_members_table(migrate_engine):
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/040_add_changes_to_satisfy_metadefs_tags.py.orig	2016-07-29 11:31:37.098719056 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/040_add_changes_to_satisfy_metadefs_tags.py	2016-07-29 11:40:01.035865900 -0600
+@@ -10,15 +10,18 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
+-
++from oslo_config import cfg
+ import sqlalchemy
+ from sqlalchemy import (Table, Index)
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     if migrate_engine.name == 'mysql':
+         meta = sqlalchemy.MetaData()
+         meta.bind = migrate_engine
+         metadef_tags = Table('metadef_tags', meta, autoload=True)
+-        Index('namespace_id', metadef_tags.c.namespace_id,
+-              metadef_tags.c.name).drop()
++        # MySQL Cluster, a.k.a NDB, does not support this index drop.
++        if CONF.database.mysql_storage_engine != "NDBCLUSTER":
++            Index('namespace_id', metadef_tags.c.namespace_id,
++                  metadef_tags.c.name).drop()
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/001_add_images_table.py.orig	2016-07-29 11:31:43.878178070 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/001_add_images_table.py	2016-07-29 11:40:32.274838992 -0600
+@@ -13,11 +13,13 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy.schema import (Column, MetaData, Table)
+ 
+ from glance.db.sqlalchemy.migrate_repo.schema import (
+     Boolean, DateTime, Integer, String, Text, create_tables, drop_tables)  # noqa
+ 
++CONF = cfg.CONF
+ 
+ def define_images_table(meta):
+     images = Table('images',
+@@ -41,7 +43,7 @@ def define_images_table(meta):
+                           nullable=False,
+                           default=False,
+                           index=True),
+-                   mysql_engine='InnoDB',
++                   mysql_engine=CONF.database.mysql_storage_engine,
+                    extend_existing=True)
+ 
+     return images
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/014_add_image_tags_table.py.orig	2016-07-29 11:31:50.742219079 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/014_add_image_tags_table.py	2016-07-29 11:40:52.393996743 -0600
+@@ -13,10 +13,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import schema
+ 
+ from glance.db.sqlalchemy.migrate_repo import schema as glance_schema
+ 
++CONF = cfg.CONF
+ 
+ def define_image_tags_table(meta):
+     # Load the images table so the foreign key can be set up properly
+@@ -46,7 +48,7 @@ def define_image_tags_table(meta):
+                                             glance_schema.Boolean(),
+                                             nullable=False,
+                                             default=False),
+-                              mysql_engine='InnoDB')
++                              mysql_engine=CONF.database.mysql_storage_engine)
+ 
+     schema.Index('ix_image_tags_image_id',
+                  image_tags.c.image_id)
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/038_add_metadef_tags_table.py.orig	2016-07-29 11:31:57.299857482 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/038_add_metadef_tags_table.py	2016-07-29 11:41:20.227494209 -0600
+@@ -12,28 +12,46 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy.schema import (
+     Column, Index, MetaData, Table, UniqueConstraint)  # noqa
+ 
+ from glance.db.sqlalchemy.migrate_repo.schema import (
+     DateTime, Integer, String, create_tables, drop_tables)  # noqa
+ 
++CONF = cfg.CONF
+ 
+ def define_metadef_tags_table(meta):
+     _constr_kwargs = {}
+-    metadef_tags = Table('metadef_tags',
+-                         meta,
+-                         Column('id', Integer(), primary_key=True,
+-                                nullable=False),
+-                         Column('namespace_id', Integer(),
+-                                nullable=False),
+-                         Column('name', String(80), nullable=False),
+-                         Column('created_at', DateTime(), nullable=False),
+-                         Column('updated_at', DateTime()),
+-                         UniqueConstraint('namespace_id', 'name',
+-                                          **_constr_kwargs),
+-                         mysql_engine='InnoDB',
+-                         extend_existing=False)
++    
++    # MySQL Cluster, a.k.a. NDB, does not support this constraint.
++    # If MySQL Cluster is enabled, the constraint will not be configured.
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        metadef_tags = Table('metadef_tags',
++                             meta,
++                             Column('id', Integer(), primary_key=True,
++                                    nullable=False),
++                             Column('namespace_id', Integer(),
++                                    nullable=False),
++                             Column('name', String(80), nullable=False),
++                             Column('created_at', DateTime(), nullable=False),
++                             Column('updated_at', DateTime()),
++                             mysql_engine=CONF.database.mysql_storage_engine,
++                             extend_existing=False)
++    else:
++        metadef_tags = Table('metadef_tags',
++                             meta,
++                             Column('id', Integer(), primary_key=True,
++                                    nullable=False),
++                             Column('namespace_id', Integer(),
++                                    nullable=False),
++                             Column('name', String(80), nullable=False),
++                             Column('created_at', DateTime(), nullable=False),
++                             Column('updated_at', DateTime()),
++                             UniqueConstraint('namespace_id', 'name',
++                                              **_constr_kwargs),
++                             mysql_engine=CONF.database.mysql_storage_engine,
++                             extend_existing=False)
+ 
+     if meta.bind.name != 'ibm_db_sa':
+         Index('ix_tags_namespace_id_name',
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/006_key_to_name.py.orig	2016-07-29 11:32:03.190044222 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/006_key_to_name.py	2016-07-29 11:41:49.183401048 -0600
+@@ -14,11 +14,13 @@
+ #    under the License.
+ 
+ from migrate.changeset import *  # noqa
++from oslo_config import cfg
+ from sqlalchemy import *  # noqa
+ 
+ from glance.db.sqlalchemy.migrate_repo.schema import (
+     Boolean, DateTime, Integer, String, Text, from_migration_import)  # noqa
+ 
++CONF = cfg.CONF
+ 
+ def get_images_table(meta):
+     """
+@@ -63,7 +65,7 @@ def get_image_properties_table(meta):
+                                     default=False,
+                                     index=True),
+                              UniqueConstraint('image_id', 'name'),
+-                             mysql_engine='InnoDB',
++                             mysql_engine=CONF.database.mysql_storage_engine,
+                              extend_existing=True)
+ 
+     return image_properties
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/030_add_tasks_table.py.orig	2016-07-29 11:32:09.114402435 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/030_add_tasks_table.py	2016-07-29 11:42:12.979551894 -0600
+@@ -14,11 +14,13 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy.schema import (Column, MetaData, Table, Index)
+ 
+ from glance.db.sqlalchemy.migrate_repo.schema import (
+     Boolean, DateTime, String, Text, create_tables, drop_tables)  # noqa
+ 
++CONF = cfg.CONF
+ 
+ def define_tasks_table(meta):
+     tasks = Table('tasks',
+@@ -38,7 +40,7 @@ def define_tasks_table(meta):
+                          Boolean(),
+                          nullable=False,
+                          default=False),
+-                  mysql_engine='InnoDB',
++                  mysql_engine=CONF.database.mysql_storage_engine,
+                   extend_existing=True)
+ 
+     Index('ix_tasks_type', tasks.c.type)
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/039_add_changes_to_satisfy_models_metadef.py.orig	2016-07-29 11:32:16.102449889 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/039_add_changes_to_satisfy_models_metadef.py	2016-07-29 11:42:34.666058988 -0600
+@@ -11,11 +11,13 @@
+ #    under the License.
+ 
+ import migrate
++from oslo_config import cfg
+ import sqlalchemy
+ from sqlalchemy import inspect
+ from sqlalchemy import (Table, Index, UniqueConstraint)
+ from sqlalchemy.schema import (AddConstraint, DropConstraint)
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = sqlalchemy.MetaData()
+@@ -36,10 +38,17 @@ def upgrade(migrate_engine):
+     Index('ix_objects_namespace_id_name', metadef_objects.c.namespace_id,
+           metadef_objects.c.name).drop()
+ 
++    fkc = migrate.ForeignKeyConstraint([metadef_properties.c.namespace_id],
++                                       [metadef_namespaces.c.id],
++                                       name='metadef_properties_ibfk_1')
++    fkc.drop()
++
+     Index('ix_metadef_properties_namespace_id_name',
+           metadef_properties.c.namespace_id,
+           metadef_properties.c.name).drop()
+ 
++    fkc.create()
++
+     fkc = migrate.ForeignKeyConstraint([metadef_tags.c.namespace_id],
+                                        [metadef_namespaces.c.id])
+     fkc.create()
+@@ -57,9 +66,16 @@ def upgrade(migrate_engine):
+                                       metadef_tags.c.name)
+         uc.create()
+ 
++    fkc = migrate.ForeignKeyConstraint([metadef_tags.c.namespace_id],
++                                       [metadef_namespaces.c.id],
++                                       name='metadef_tags_namespace_id_fkey')
++    fkc.drop()
++
+     Index('ix_tags_namespace_id_name', metadef_tags.c.namespace_id,
+           metadef_tags.c.name).drop()
+ 
++    fkc.create()
++
+     Index('ix_metadef_tags_name', metadef_tags.c.name).create()
+ 
+     Index('ix_metadef_tags_namespace_id', metadef_tags.c.namespace_id,
+@@ -190,7 +206,6 @@ def downgrade(migrate_engine):
+         fkc = migrate.ForeignKeyConstraint([metadef_tags.c.namespace_id],
+                                            [metadef_namespaces.c.id])
+         fkc.drop()
+-
+         Index('ix_tags_namespace_id_name', metadef_tags.c.namespace_id,
+               metadef_tags.c.name).create()
+     else:
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/008_add_image_members_table.py.orig	2016-07-29 11:32:22.100185363 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/008_add_image_members_table.py	2016-07-29 11:42:54.820310263 -0600
+@@ -14,12 +14,14 @@
+ #    under the License.
+ 
+ from migrate.changeset import *  # noqa
++from oslo_config import cfg
+ from sqlalchemy import *  # noqa
+ 
+ from glance.db.sqlalchemy.migrate_repo.schema import (
+     Boolean, DateTime, Integer, String, create_tables,
+     drop_tables, from_migration_import)  # noqa
+ 
++CONF = cfg.CONF
+ 
+ def get_images_table(meta):
+     """
+@@ -45,40 +47,71 @@ def get_image_properties_table(meta):
+ 
+ def get_image_members_table(meta):
+     images = get_images_table(meta)  # noqa
+-
+-    image_members = Table('image_members',
+-                          meta,
+-                          Column('id',
+-                                 Integer(),
+-                                 primary_key=True,
+-                                 nullable=False),
+-                          Column('image_id',
+-                                 Integer(),
+-                                 ForeignKey('images.id'),
+-                                 nullable=False,
+-                                 index=True),
+-                          Column('member', String(255), nullable=False),
+-                          Column('can_share',
+-                                 Boolean(),
+-                                 nullable=False,
+-                                 default=False),
+-                          Column('created_at', DateTime(), nullable=False),
+-                          Column('updated_at', DateTime()),
+-                          Column('deleted_at', DateTime()),
+-                          Column('deleted',
+-                                 Boolean(),
+-                                 nullable=False,
+-                                 default=False,
+-                                 index=True),
+-                          UniqueConstraint('image_id', 'member'),
+-                          mysql_engine='InnoDB',
+-                          extend_existing=True)
++    
++    # MySQL Cluster, a.k.a. NDB, does not support this constraint and index.
++    # If MySQl Cluster is being used, the constraint and index will not be created.
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        image_members = Table('image_members',
++                              meta,
++                              Column('id',
++                                     Integer(),
++                                     primary_key=True,
++                                     nullable=False),
++                              Column('image_id',
++                                     Integer(),
++                                     ForeignKey('images.id'),
++                                     nullable=False,
++                                     index=True),
++                              Column('member', String(255), nullable=False),
++                              Column('can_share',
++                                     Boolean(),
++                                     nullable=False,
++                                     default=False),
++                              Column('created_at', DateTime(), nullable=False),
++                              Column('updated_at', DateTime()),
++                              Column('deleted_at', DateTime()),
++                              Column('deleted',
++                                     Boolean(),
++                                     nullable=False,
++                                     default=False,
++                                     index=True),
++                              mysql_engine=CONF.database.mysql_storage_engine,
++                              extend_existing=True)
++    else:
++        image_members = Table('image_members',
++                              meta,
++                              Column('id',
++                                     Integer(),
++                                     primary_key=True,
++                                     nullable=False),
++                              Column('image_id',
++                                     Integer(),
++                                     ForeignKey('images.id'),
++                                     nullable=False,
++                                     index=True),
++                              Column('member', String(255), nullable=False),
++                              Column('can_share',
++                                     Boolean(),
++                                     nullable=False,
++                                     default=False),
++                              Column('created_at', DateTime(), nullable=False),
++                              Column('updated_at', DateTime()),
++                              Column('deleted_at', DateTime()),
++                              Column('deleted',
++                                     Boolean(),
++                                     nullable=False,
++                                     default=False,
++                                     index=True),
++                              UniqueConstraint('image_id', 'member'),
++                              mysql_engine=CONF.database.mysql_storage_engine,
++                              extend_existing=True)
+ 
+     # DB2: an index has already been created for the UniqueConstraint option
+     # specified on the Table() statement above.
+-    if meta.bind.name != "ibm_db_sa":
+-        Index('ix_image_members_image_id_member', image_members.c.image_id,
+-              image_members.c.member)
++    if CONF.database.mysql_storage_engine != "NDBCLUSTER":
++        if meta.bind.name != "ibm_db_sa":
++            Index('ix_image_members_image_id_member', image_members.c.image_id,
++                  image_members.c.member)
+ 
+     return image_members
+ 
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/002_add_image_properties_table.py.orig	2016-07-29 11:32:28.641283394 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/002_add_image_properties_table.py	2016-07-29 11:43:17.467512143 -0600
+@@ -13,6 +13,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy.schema import (
+     Column, ForeignKey, Index, MetaData, Table, UniqueConstraint)
+ 
+@@ -20,6 +21,7 @@ from glance.db.sqlalchemy.migrate_repo.s
+     Boolean, DateTime, Integer, String, Text, create_tables, drop_tables,
+     from_migration_import)  # noqa
+ 
++CONF = cfg.CONF
+ 
+ def define_image_properties_table(meta):
+     (define_images_table,) = from_migration_import(
+@@ -36,31 +38,58 @@ def define_image_properties_table(meta):
+     if meta.bind.name == 'ibm_db_sa':
+         constr_kwargs['name'] = 'ix_image_properties_image_id_key'
+ 
+-    image_properties = Table('image_properties',
+-                             meta,
+-                             Column('id',
+-                                    Integer(),
+-                                    primary_key=True,
+-                                    nullable=False),
+-                             Column('image_id',
+-                                    Integer(),
+-                                    ForeignKey('images.id'),
+-                                    nullable=False,
+-                                    index=True),
+-                             Column('key', String(255), nullable=False),
+-                             Column('value', Text()),
+-                             Column('created_at', DateTime(), nullable=False),
+-                             Column('updated_at', DateTime()),
+-                             Column('deleted_at', DateTime()),
+-                             Column('deleted',
+-                                    Boolean(),
+-                                    nullable=False,
+-                                    default=False,
+-                                    index=True),
+-                             UniqueConstraint('image_id', 'key',
+-                                              **constr_kwargs),
+-                             mysql_engine='InnoDB',
+-                             extend_existing=True)
++    # MySQL Cluster, a.k.a. NDB, does not support the constraint here. 
++    # This will remove the constraint if MySQL Cluster is being used.
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        image_properties = Table('image_properties',
++                                 meta,
++                                 Column('id',
++                                        Integer(),
++                                        primary_key=True,
++                                        nullable=False),
++                                 Column('image_id',
++                                        Integer(),
++                                        ForeignKey('images.id'),
++                                        nullable=False,
++                                        index=True),
++                                 Column('key', String(255), nullable=False),
++                                 Column('value', Text()),
++                                 Column('created_at', DateTime(), nullable=False),
++                                 Column('updated_at', DateTime()),
++                                 Column('deleted_at', DateTime()),
++                                 Column('deleted',
++                                        Boolean(),
++                                        nullable=False,
++                                        default=False,
++                                        index=True),
++                                 mysql_engine=CONF.database.mysql_storage_engine,
++                                 extend_existing=True)
++    else:
++        image_properties = Table('image_properties',
++                                 meta,
++                                 Column('id',
++                                        Integer(),
++                                        primary_key=True,
++                                        nullable=False),
++                                 Column('image_id',
++                                        Integer(),
++                                        ForeignKey('images.id'),
++                                        nullable=False,
++                                        index=True),
++                                 Column('key', String(255), nullable=False),
++                                 Column('value', Text()),
++                                 Column('created_at', DateTime(), nullable=False),
++                                 Column('updated_at', DateTime()),
++                                 Column('deleted_at', DateTime()),
++                                 Column('deleted',
++                                        Boolean(),
++                                        nullable=False,
++                                        default=False,
++                                        index=True),
++                                 UniqueConstraint('image_id', 'key',
++                                                  **constr_kwargs),
++                                 mysql_engine=CONF.database.mysql_storage_engine,
++                                 extend_existing=True)
+ 
+     if meta.bind.name != 'ibm_db_sa':
+         Index('ix_image_properties_image_id_key',
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/035_add_metadef_tables.py.orig	2016-07-29 11:32:34.891435682 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/035_add_metadef_tables.py	2016-07-29 11:43:39.940493840 -0600
+@@ -12,6 +12,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from oslo_utils import timeutils
+ import sqlalchemy
+ from sqlalchemy.schema import (
+@@ -21,6 +22,7 @@ from glance.db.sqlalchemy.migrate_repo.s
+     Boolean, DateTime, Integer, String, Text, create_tables,
+     drop_tables)  # noqa
+ 
++CONF = cfg.CONF
+ 
+ RESOURCE_TYPES = [u'OS::Glance::Image', u'OS::Cinder::Volume',
+                   u'OS::Nova::Flavor', u'OS::Nova::Aggregate',
+@@ -65,7 +67,7 @@ def define_metadef_namespaces_table(meta
+                        Column('created_at', DateTime(), nullable=False),
+                        Column('updated_at', DateTime()),
+                        UniqueConstraint('namespace', **_constr_kwargs),
+-                       mysql_engine='InnoDB',
++                       mysql_engine=CONF.database.mysql_storage_engine,
+                        extend_existing=True)
+ 
+     if meta.bind.name != 'ibm_db_sa':
+@@ -80,22 +82,41 @@ def define_metadef_objects_table(meta):
+     if meta.bind.name == 'ibm_db_sa':
+         _constr_kwargs['name'] = 'ix_objects_namespace_id_name'
+ 
+-    objects = Table('metadef_objects',
+-                    meta,
+-                    Column('id', Integer(), primary_key=True, nullable=False),
+-                    Column('namespace_id', Integer(),
+-                           ForeignKey('metadef_namespaces.id'),
+-                           nullable=False),
+-                    Column('name', String(80), nullable=False),
+-                    Column('description', Text()),
+-                    Column('required', Text()),
+-                    Column('schema', Text(), nullable=False),
+-                    Column('created_at', DateTime(), nullable=False),
+-                    Column('updated_at', DateTime()),
+-                    UniqueConstraint('namespace_id', 'name',
+-                                     **_constr_kwargs),
+-                    mysql_engine='InnoDB',
+-                    extend_existing=True)
++    # MySQL Cluster, a.k.a. NDB, requires explicit foreign key names
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        objects = Table('metadef_objects',
++                        meta,
++                        Column('id', Integer(), primary_key=True, nullable=False),
++                        Column('namespace_id', Integer(),
++                               ForeignKey('metadef_namespaces.id', name='metadef_objects_ibfk_1'),
++                               nullable=False),
++                        Column('name', String(80), nullable=False),
++                        Column('description', Text()),
++                        Column('required', Text()),
++                        Column('schema', Text(), nullable=False),
++                        Column('created_at', DateTime(), nullable=False),
++                        Column('updated_at', DateTime()),
++                        UniqueConstraint('namespace_id', 'name',
++                                         **_constr_kwargs),
++                        mysql_engine=CONF.database.mysql_storage_engine,
++                        extend_existing=True)
++    else:
++        objects = Table('metadef_objects',
++                        meta,
++                        Column('id', Integer(), primary_key=True, nullable=False),
++                        Column('namespace_id', Integer(),
++                               ForeignKey('metadef_namespaces.id'),
++                               nullable=False),
++                        Column('name', String(80), nullable=False),
++                        Column('description', Text()),
++                        Column('required', Text()),
++                        Column('schema', Text(), nullable=False),
++                        Column('created_at', DateTime(), nullable=False),
++                        Column('updated_at', DateTime()),
++                        UniqueConstraint('namespace_id', 'name',
++                                         **_constr_kwargs),
++                        mysql_engine=CONF.database.mysql_storage_engine,
++                        extend_existing=True)
+ 
+     if meta.bind.name != 'ibm_db_sa':
+         Index('ix_objects_namespace_id_name',
+@@ -111,19 +132,35 @@ def define_metadef_properties_table(meta
+     if meta.bind.name == 'ibm_db_sa':
+         _constr_kwargs['name'] = 'ix_metadef_properties_namespace_id_name'
+ 
+-    metadef_properties = Table(
+-        'metadef_properties',
+-        meta,
+-        Column('id', Integer(), primary_key=True, nullable=False),
+-        Column('namespace_id', Integer(), ForeignKey('metadef_namespaces.id'),
+-               nullable=False),
+-        Column('name', String(80), nullable=False),
+-        Column('schema', Text(), nullable=False),
+-        Column('created_at', DateTime(), nullable=False),
+-        Column('updated_at', DateTime()),
+-        UniqueConstraint('namespace_id', 'name', **_constr_kwargs),
+-        mysql_engine='InnoDB',
+-        extend_existing=True)
++    # MySQL Cluster, a.k.a. NDB, requires explicit foreign key names
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        metadef_properties = Table(
++            'metadef_properties',
++            meta,
++            Column('id', Integer(), primary_key=True, nullable=False),
++            Column('namespace_id', Integer(), ForeignKey('metadef_namespaces.id', name='metadef_properties_ibfk_1'),
++                   nullable=False),
++            Column('name', String(80), nullable=False),
++            Column('schema', Text(), nullable=False),
++            Column('created_at', DateTime(), nullable=False),
++            Column('updated_at', DateTime()),
++            UniqueConstraint('namespace_id', 'name', **_constr_kwargs),
++            mysql_engine=CONF.database.mysql_storage_engine,
++            extend_existing=True)
++    else:
++        metadef_properties = Table(
++            'metadef_properties',
++            meta,
++            Column('id', Integer(), primary_key=True, nullable=False),
++            Column('namespace_id', Integer(), ForeignKey('metadef_namespaces.id'),
++                   nullable=False),
++            Column('name', String(80), nullable=False),
++            Column('schema', Text(), nullable=False),
++            Column('created_at', DateTime(), nullable=False),
++            Column('updated_at', DateTime()),
++            UniqueConstraint('namespace_id', 'name', **_constr_kwargs),
++            mysql_engine=CONF.database.mysql_storage_engine,
++            extend_existing=True)
+ 
+     if meta.bind.name != 'ibm_db_sa':
+         Index('ix_metadef_properties_namespace_id_name',
+@@ -148,7 +185,7 @@ def define_metadef_resource_types_table(
+         Column('created_at', DateTime(), nullable=False),
+         Column('updated_at', DateTime()),
+         UniqueConstraint('name', **_constr_kwargs),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         extend_existing=True)
+ 
+     if meta.bind.name != 'ibm_db_sa':
+@@ -164,23 +201,41 @@ def define_metadef_namespace_resource_ty
+     if meta.bind.name == 'ibm_db_sa':
+         _constr_kwargs['name'] = 'ix_metadef_ns_res_types_res_type_id_ns_id'
+ 
+-    metadef_associations = Table(
+-        'metadef_namespace_resource_types',
+-        meta,
+-        Column('resource_type_id', Integer(),
+-               ForeignKey('metadef_resource_types.id'),
+-               primary_key=True, nullable=False),
+-        Column('namespace_id', Integer(),
+-               ForeignKey('metadef_namespaces.id'),
+-               primary_key=True, nullable=False),
+-        Column('properties_target', String(80)),
+-        Column('prefix', String(80)),
+-        Column('created_at', DateTime(), nullable=False),
+-        Column('updated_at', DateTime()),
+-        UniqueConstraint('resource_type_id', 'namespace_id',
+-                         **_constr_kwargs),
+-        mysql_engine='InnoDB',
+-        extend_existing=True)
++    # MySQL Cluster, a.k.a. NDB, does not support these foreign keys, which are later removed.
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        metadef_associations = Table(
++            'metadef_namespace_resource_types',
++            meta,
++            Column('resource_type_id', Integer(),
++                   primary_key=True, nullable=False),
++            Column('namespace_id', Integer(),
++                   primary_key=True, nullable=False),
++            Column('properties_target', String(80)),
++            Column('prefix', String(80)),
++            Column('created_at', DateTime(), nullable=False),
++            Column('updated_at', DateTime()),
++            UniqueConstraint('resource_type_id', 'namespace_id',
++                             **_constr_kwargs),
++            mysql_engine=CONF.database.mysql_storage_engine,
++            extend_existing=True)
++    else:
++        metadef_associations = Table(
++            'metadef_namespace_resource_types',
++            meta,
++            Column('resource_type_id', Integer(),
++                   ForeignKey('metadef_resource_types.id'),
++                   primary_key=True, nullable=False),
++            Column('namespace_id', Integer(),
++                   ForeignKey('metadef_namespaces.id'),
++                   primary_key=True, nullable=False),
++            Column('properties_target', String(80)),
++            Column('prefix', String(80)),
++            Column('created_at', DateTime(), nullable=False),
++            Column('updated_at', DateTime()),
++            UniqueConstraint('resource_type_id', 'namespace_id',
++                             **_constr_kwargs),
++            mysql_engine=CONF.database.mysql_storage_engine,
++            extend_existing=True)
+ 
+     if meta.bind.name != 'ibm_db_sa':
+         Index('ix_metadef_ns_res_types_res_type_id_ns_id',
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/037_add_changes_to_satisfy_models.py.orig	2016-07-29 11:32:40.844072755 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/037_add_changes_to_satisfy_models.py	2016-07-29 11:44:01.300274699 -0600
+@@ -10,6 +10,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ import sqlalchemy
+ from sqlalchemy import Table, Index, UniqueConstraint, Sequence
+ from sqlalchemy.schema import (AddConstraint, DropConstraint, CreateIndex,
+@@ -17,6 +18,7 @@ from sqlalchemy.schema import (AddConstr
+ from sqlalchemy import sql
+ from sqlalchemy import update
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = sqlalchemy.MetaData()
+@@ -74,10 +76,14 @@ def upgrade(migrate_engine):
+ 
+         images.c.id.alter(server_default=None)
+     if migrate_engine.name == 'mysql':
+-        constraint = UniqueConstraint(image_properties.c.image_id,
+-                                      image_properties.c.name,
+-                                      name='image_id')
+-        migrate_engine.execute(DropConstraint(constraint))
++        # MySQL Cluster, a.k.a. NDB, does not support the constraint here. 
++        # This will only add the constraint if MySQL Cluster is not being used.
++        if CONF.database.mysql_storage_engine != "NDBCLUSTER":
++            constraint = UniqueConstraint(image_properties.c.image_id,
++                                          image_properties.c.name,
++                                          name='image_id')
++            migrate_engine.execute(DropConstraint(constraint))
++
+         image_locations = Table('image_locations', meta, autoload=True)
+         if len(image_locations.foreign_keys) == 0:
+             migrate_engine.execute(AddConstraint(ForeignKeyConstraint(
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/009_add_mindisk_and_minram.py.orig	2016-07-29 11:32:47.075511757 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/009_add_mindisk_and_minram.py	2016-07-29 11:44:23.917127924 -0600
+@@ -14,11 +14,13 @@
+ #    under the License.
+ 
+ from migrate.changeset import *  # noqa
++from oslo_config import cfg
+ from sqlalchemy import *  # noqa
+ 
+ from glance.db.sqlalchemy.migrate_repo.schema import (
+     Boolean, DateTime, Integer, String, Text, from_migration_import)  # noqa
+ 
++CONF = cfg.CONF
+ 
+ def get_images_table(meta):
+     """
+@@ -51,7 +53,7 @@ def get_images_table(meta):
+                    Column('owner', String(255)),
+                    Column('min_disk', Integer(), default=0),
+                    Column('min_ram', Integer(), default=0),
+-                   mysql_engine='InnoDB',
++                   mysql_engine=CONF.database.mysql_storage_engine,
+                    extend_existing=True)
+ 
+     return images
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/032_add_task_info_table.py.orig	2016-07-29 11:32:53.180994551 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/032_add_task_info_table.py	2016-07-29 11:44:45.316686633 -0600
+@@ -13,6 +13,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy.schema import (Column, ForeignKey, MetaData, Table)
+ 
+ from glance.db.sqlalchemy.migrate_repo.schema import (String,
+@@ -22,6 +23,7 @@ from glance.db.sqlalchemy.migrate_repo.s
+ 
+ TASKS_MIGRATE_COLUMNS = ['input', 'message', 'result']
+ 
++CONF = cfg.CONF
+ 
+ def define_task_info_table(meta):
+     Table('tasks', meta, autoload=True)
+@@ -37,7 +39,7 @@ def define_task_info_table(meta):
+                       Column('input', Text()),
+                       Column('result', Text()),
+                       Column('message', Text()),
+-                      mysql_engine='InnoDB')
++                      mysql_engine=CONF.database.mysql_storage_engine)
+ 
+     return task_info
+ 
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/004_add_checksum.py.orig	2016-07-29 11:32:58.755972142 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/004_add_checksum.py	2016-07-29 11:45:04.732540072 -0600
+@@ -14,11 +14,13 @@
+ #    under the License.
+ 
+ from migrate.changeset import *  # noqa
++from oslo_config import cfg
+ from sqlalchemy import *  # noqa
+ 
+ from glance.db.sqlalchemy.migrate_repo.schema import (
+     Boolean, DateTime, Integer, String, Text, from_migration_import)  # noqa
+ 
++CONF = cfg.CONF
+ 
+ def get_images_table(meta):
+     """
+@@ -48,7 +50,7 @@ def get_images_table(meta):
+                           default=False,
+                           index=True),
+                    Column('checksum', String(32)),
+-                   mysql_engine='InnoDB',
++                   mysql_engine=CONF.database.mysql_storage_engine,
+                    extend_existing=True)
+ 
+     return images
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/021_set_engine_mysql_innodb.py.orig	2016-07-29 11:33:05.406762219 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/021_set_engine_mysql_innodb.py	2016-07-29 11:45:30.188972755 -0600
+@@ -14,21 +14,24 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import MetaData
+ 
+ tables = ['image_locations']
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+     meta.bind = migrate_engine
+     if migrate_engine.name == "mysql":
+-        d = migrate_engine.execute("SHOW TABLE STATUS WHERE Engine!='InnoDB';")
++        d = migrate_engine.execute("SHOW TABLE STATUS WHERE Engine!='%s';" % 
++                                   CONF.database.mysql_storage_engine)
+         for row in d.fetchall():
+             table_name = row[0]
+             if table_name in tables:
+-                migrate_engine.execute("ALTER TABLE %s Engine=InnoDB" %
+-                                       table_name)
++                migrate_engine.execute("ALTER TABLE %(db_table)s Engine=%(mysql_storage_engine)s" %
++                                       dict(db_table=table_name, mysql_storage_engine=CONF.database.mysql_storage_engine))
+ 
+ 
+ def downgrade(migrate_engine):
+--- glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/041_add_artifact_tables.py.orig	2016-07-29 11:33:13.687025321 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/migrate_repo/versions/041_add_artifact_tables.py	2016-07-29 11:45:55.382385404 -0600
+@@ -12,6 +12,7 @@
+ # License for the specific language governing permissions and limitations
+ # under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy.schema import (Column, ForeignKey, Index, MetaData, Table)
+ 
+ 
+@@ -19,6 +20,7 @@ from glance.db.sqlalchemy.migrate_repo.s
+     BigInteger, Boolean, DateTime, Integer, Numeric, String, Text,
+     create_tables)  # noqa
+ 
++CONF = cfg.CONF
+ 
+ def define_artifacts_table(meta):
+     artifacts = Table('artifacts',
+@@ -43,7 +45,7 @@ def define_artifacts_table(meta):
+                              nullable=False),
+                       Column('deleted_at', DateTime()),
+                       Column('published_at', DateTime()),
+-                      mysql_engine='InnoDB',
++                      mysql_engine=CONF.database.mysql_storage_engine,
+                       extend_existing=True)
+ 
+     Index('ix_artifact_name_and_version', artifacts.c.name,
+@@ -68,7 +70,7 @@ def define_artifact_tags_table(meta):
+                           Column('created_at', DateTime(), nullable=False),
+                           Column('updated_at', DateTime(),
+                                  nullable=False),
+-                          mysql_engine='InnoDB',
++                          mysql_engine=CONF.database.mysql_storage_engine,
+                           extend_existing=True)
+ 
+     Index('ix_artifact_tags_artifact_id', artifact_tags.c.artifact_id)
+@@ -100,7 +102,7 @@ def define_artifact_dependencies_table(m
+                                          nullable=False),
+                                   Column('updated_at', DateTime(),
+                                          nullable=False),
+-                                  mysql_engine='InnoDB',
++                                  mysql_engine=CONF.database.mysql_storage_engine,
+                                   extend_existing=True)
+ 
+     Index('ix_artifact_dependencies_source_id',
+@@ -131,7 +133,7 @@ def define_artifact_blobs_table(meta):
+                            Column('created_at', DateTime(), nullable=False),
+                            Column('updated_at', DateTime(),
+                                   nullable=False),
+-                           mysql_engine='InnoDB',
++                           mysql_engine=CONF.database.mysql_storage_engine,
+                            extend_existing=True)
+     Index('ix_artifact_blobs_artifact_id',
+           artifact_blobs.c.artifact_id)
+@@ -161,7 +163,7 @@ def define_artifact_properties_table(met
+                                 Column('updated_at', DateTime(),
+                                        nullable=False),
+                                 Column('position', Integer()),
+-                                mysql_engine='InnoDB',
++                                mysql_engine=CONF.database.mysql_storage_engine,
+                                 extend_existing=True)
+     Index('ix_artifact_properties_artifact_id',
+           artifact_properties.c.artifact_id)
+@@ -186,7 +188,7 @@ def define_artifact_blob_locations_table
+                                     Column('position', Integer()),
+                                     Column('status', String(36),
+                                            nullable=True),
+-                                    mysql_engine='InnoDB',
++                                    mysql_engine=CONF.database.mysql_storage_engine,
+                                     extend_existing=True)
+     Index('ix_artifact_blob_locations_blob_id',
+           artifact_blob_locations.c.blob_id)
+--- glance-2015.1.2/glance/db/sqlalchemy/models.py.orig	2016-07-29 11:33:19.907591270 -0600
++++ glance-2015.1.2/glance/db/sqlalchemy/models.py	2016-07-29 11:46:37.517783749 -0600
+@@ -21,6 +21,7 @@ SQLAlchemy models for glance data
+ import uuid
+ 
+ from oslo.serialization import jsonutils
++from oslo_config import cfg
+ from oslo_db.sqlalchemy import models
+ from oslo_utils import timeutils
+ from sqlalchemy import BigInteger
+@@ -39,6 +40,7 @@ from sqlalchemy import Text
+ from sqlalchemy.types import TypeDecorator
+ from sqlalchemy import UniqueConstraint
+ 
++CONF = cfg.CONF
+ 
+ BASE = declarative_base()
+ 
+@@ -67,7 +69,7 @@ class JSONEncodedDict(TypeDecorator):
+ class GlanceBase(models.ModelBase, models.TimestampMixin):
+     """Base class for Glance Models."""
+ 
+-    __table_args__ = {'mysql_engine': 'InnoDB'}
++    __table_args__ = {'mysql_engine': CONF.database.mysql_storage_engine}
+     __table_initialized__ = False
+     __protected_attributes__ = set([
+         "created_at", "updated_at", "deleted_at", "deleted"])
--- a/components/openstack/heat/files/heat.conf	Fri Jul 29 11:02:37 2016 -0700
+++ b/components/openstack/heat/files/heat.conf	Fri Jul 29 14:41:14 2016 -0600
@@ -727,6 +727,12 @@
 # (string value)
 #mysql_sql_mode = TRADITIONAL
 
+# This configures the MySQL storage engine. This allows for OpenStack to
+# support different storage engines such as InnoDB, NDB, etc. By Default,
+# this value will be set to InnoDB. For MySQL Cluster, set to NDBCLUSTER.
+# Example: mysql_storage_engine=(string value)
+#mysql_storage_engine = InnoDB
+
 # Timeout before idle SQL connections are reaped. (integer value)
 # Deprecated group/name - [DEFAULT]/sql_idle_timeout
 # Deprecated group/name - [DATABASE]/sql_idle_timeout
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openstack/heat/patches/08-mysql_cluster_support.patch	Fri Jul 29 14:41:14 2016 -0600
@@ -0,0 +1,307 @@
+This patchset is for bug:
+
+22725887 - Heat needs to support MySQL Cluster
+
+This fixes the following aspects of Heat:
+1. Implementation of an oslo.db configuration parameter to specify the MySQL
+   storage engine (mysql_storage_engine).
+2. Replacement of hardcoded SQL statements that set the engine to "InnoDB"
+   to the above configuration value.
+3. Logic to handle SQL differences between MySQL InnoDB and MySQL Cluster (NDB).
+   This includes column lengths, constraints, foreign keys, and indexes.
+
+This has not been committed upstream, but has been filed in launchpad:
+
+https://bugs.launchpad.net/heat/+bug/1564110
+
+
+--- heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/054_stack_tags_table.py.orig	2016-07-29 12:03:45.066916862 -0600
++++ heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/054_stack_tags_table.py	2016-07-29 12:08:17.012890454 -0600
+@@ -11,10 +11,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ import sqlalchemy
+ 
+ from heat.db.sqlalchemy import types as heat_db_types
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = sqlalchemy.MetaData(bind=migrate_engine)
+@@ -35,7 +37,7 @@ def upgrade(migrate_engine):
+                           sqlalchemy.String(36),
+                           sqlalchemy.ForeignKey('stack.id'),
+                           nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+     stack_tag.create()
+--- heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/015_grizzly.py.orig	2016-07-29 12:03:53.884104708 -0600
++++ heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/015_grizzly.py	2016-07-29 12:08:35.264920866 -0600
+@@ -11,8 +11,10 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ import sqlalchemy
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = sqlalchemy.MetaData()
+@@ -25,7 +27,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.Column('created_at', sqlalchemy.DateTime),
+         sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
+         sqlalchemy.Column('template', sqlalchemy.Text),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -44,7 +46,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.Column('aws_auth_url', sqlalchemy.Text),
+         sqlalchemy.Column('tenant_id', sqlalchemy.String(256)),
+         sqlalchemy.Column('aws_creds', sqlalchemy.Text),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -71,7 +73,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.Column('tenant', sqlalchemy.String(256)),
+         sqlalchemy.Column('disable_rollback', sqlalchemy.Boolean,
+                           nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -88,7 +90,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.Column('stack_id', sqlalchemy.String(36),
+                           sqlalchemy.ForeignKey('stack.id'), nullable=False),
+         sqlalchemy.Column('rsrc_metadata', sqlalchemy.Text),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -106,7 +108,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.Column('resource_status_reason', sqlalchemy.String(255)),
+         sqlalchemy.Column('resource_type', sqlalchemy.String(255)),
+         sqlalchemy.Column('resource_properties', sqlalchemy.PickleType),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -122,7 +124,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.Column('last_evaluated', sqlalchemy.DateTime),
+         sqlalchemy.Column('stack_id', sqlalchemy.String(36),
+                           sqlalchemy.ForeignKey('stack.id'), nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -136,7 +138,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.Column('watch_rule_id', sqlalchemy.Integer,
+                           sqlalchemy.ForeignKey('watch_rule.id'),
+                           nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+--- heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/059_sync_point.py.orig	2016-07-29 12:04:02.707922940 -0600
++++ heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/059_sync_point.py	2016-07-29 12:09:00.649161442 -0600
+@@ -11,10 +11,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ import sqlalchemy
+ 
+ from heat.db.sqlalchemy import types as heat_db_types
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = sqlalchemy.MetaData()
+@@ -41,7 +43,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.ForeignKeyConstraint(['stack_id'], ['stack.id'],
+                                         name='fk_stack_id'),
+ 
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+     sync_point.create()
+--- heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/033_software_config.py.orig	2016-07-29 12:04:10.260632439 -0600
++++ heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/033_software_config.py	2016-07-29 12:09:20.089705318 -0600
+@@ -11,10 +11,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ import sqlalchemy
+ 
+ from heat.db.sqlalchemy import types
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = sqlalchemy.MetaData()
+@@ -34,7 +36,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.Column('tenant', sqlalchemy.String(64),
+                           nullable=False,
+                           index=True),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+     software_config.create()
+@@ -63,7 +65,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.Column('tenant', sqlalchemy.String(64),
+                           nullable=False,
+                           index=True),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+     software_deployment.create()
+--- heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/057_resource_uuid_to_id.py.orig	2016-07-29 12:04:19.750231791 -0600
++++ heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/057_resource_uuid_to_id.py	2016-07-28 14:01:17.581307597 -0600
+@@ -194,10 +194,11 @@ def upgrade_resource_data_post(migrate_e
+         name = inspector.get_indexes('resource_data')[0]['name']
+         sqlalchemy.Index(name, rd_table.c.resource_id).drop()
+ 
++    # Change column before it becomes a foreign key
++    rd_table.c.resource_id.alter(nullable=False)
+     cons = migrate.ForeignKeyConstraint(columns=[rd_table.c.resource_id],
+                                         refcolumns=[res_table.c.id])
+     cons.create()
+-    rd_table.c.resource_id.alter(nullable=False)
+ 
+     rd_table.c.tmp_res_uuid.drop()
+ 
+--- heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/044_snapshots.py.orig	2016-07-29 12:04:27.749158504 -0600
++++ heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/044_snapshots.py	2016-07-29 12:10:54.210544287 -0600
+@@ -11,10 +11,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ import sqlalchemy
+ 
+ from heat.db.sqlalchemy import types
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = sqlalchemy.MetaData()
+@@ -38,7 +40,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.Column('tenant', sqlalchemy.String(64),
+                           nullable=False,
+                           index=True),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+     sqlalchemy.Table('stack', meta, autoload=True)
+--- heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/051_service.py.orig	2016-07-29 12:04:36.470596083 -0600
++++ heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/051_service.py	2016-07-29 12:11:18.330506769 -0600
+@@ -15,8 +15,10 @@
+ 
+ import uuid
+ 
++from oslo_config import cfg
+ import sqlalchemy
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = sqlalchemy.MetaData()
+@@ -36,7 +38,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.Column('created_at', sqlalchemy.DateTime),
+         sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
+         sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+     service.create()
+--- heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/021_resource_data.py.orig	2016-07-29 12:04:51.248485607 -0600
++++ heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/021_resource_data.py	2016-07-29 12:11:47.651134656 -0600
+@@ -11,8 +11,10 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ import sqlalchemy
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = sqlalchemy.MetaData()
+@@ -33,7 +35,7 @@ def upgrade(migrate_engine):
+                           sqlalchemy.String(36),
+                           sqlalchemy.ForeignKey('resource.id'),
+                           nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+     sqlalchemy.Table('resource', meta, autoload=True)
+--- heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/031_stack_lock.py.orig	2016-07-29 12:04:59.100720052 -0600
++++ heat-2015.1.2/heat/db/sqlalchemy/migrate_repo/versions/031_stack_lock.py	2016-07-29 12:12:03.834952665 -0600
+@@ -11,8 +11,10 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ import sqlalchemy
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = sqlalchemy.MetaData()
+@@ -27,7 +29,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.Column('created_at', sqlalchemy.DateTime),
+         sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
+         sqlalchemy.Column('engine_id', sqlalchemy.String(length=36)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+     sqlalchemy.Table('stack', meta, autoload=True)
+--- heat-2015.1.2/heat/db/sqlalchemy/models.py.orig	2016-07-29 12:05:08.842912688 -0600
++++ heat-2015.1.2/heat/db/sqlalchemy/models.py	2016-07-29 12:15:35.087392556 -0600
+@@ -16,6 +16,7 @@ SQLAlchemy models for heat data.
+ 
+ import uuid
+ 
++from oslo_config import cfg
+ from oslo_db.sqlalchemy import models
+ from oslo_utils import timeutils
+ import six
+@@ -27,6 +28,8 @@ from sqlalchemy.orm import session as or
+ 
+ from heat.db.sqlalchemy import types
+ 
++CONF = cfg.CONF
++
+ BASE = declarative.declarative_base()
+ 
+ 
+@@ -37,7 +40,7 @@ def get_session():
+ 
+ class HeatBase(models.ModelBase, models.TimestampMixin):
+     """Base class for Heat Models."""
+-    __table_args__ = {'mysql_engine': 'InnoDB'}
++    __table_args__ = CONF.database.mysql_storage_engine
+ 
+     def expire(self, session=None, attrs=None):
+         """Expire this object ()."""
--- a/components/openstack/ironic/files/ironic.conf	Fri Jul 29 11:02:37 2016 -0700
+++ b/components/openstack/ironic/files/ironic.conf	Fri Jul 29 14:41:14 2016 -0600
@@ -635,6 +635,12 @@
 # value)
 #mysql_sql_mode=TRADITIONAL
 
+# This configures the MySQL storage engine. This allows for OpenStack to
+# support different storage engines such as InnoDB, NDB, etc. By Default,
+# this value will be set to InnoDB. For MySQL Cluster, set to NDBCLUSTER.
+# Example: mysql_storage_engine=(string value)
+#mysql_storage_engine = InnoDB
+
 # Timeout before idle SQL connections are reaped. (integer
 # value)
 # Deprecated group/name - [DEFAULT]/sql_idle_timeout
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openstack/ironic/patches/05-mysql_cluster_support.patch	Fri Jul 29 14:41:14 2016 -0600
@@ -0,0 +1,111 @@
+This patchset is for bug:
+
+22726240 - Ironic needs to support MySQL Cluster
+
+This fixes the following aspects of Ironic:
+1. Implementation of an oslo.db configuration parameter to specify the MySQL
+   storage engine (mysql_storage_engine).
+2. Replacement of hardcoded SQL statements that set the engine to "InnoDB"
+   to the above configuration value.
+3. Logic to handle SQL differences between MySQL InnoDB and MySQL Cluster (NDB).
+   This includes column lengths, constraints, foreign keys, and indexes.
+4. Changes the conductor table column "online" to "online_status" to make it
+   more portable. "online" is a reserved word in MySQL and other databases.
+
+This has not been committed upstream, but has been filed in launchpad:
+
+https://bugs.launchpad.net/ironic/+bug/1564110
+
+
+--- ironic-2015.1.2/ironic/db/sqlalchemy/models.py.orig	2016-07-29 12:25:49.797916170 -0600
++++ ironic-2015.1.2/ironic/db/sqlalchemy/models.py	2016-07-28 14:06:28.682668208 -0600
+@@ -49,8 +49,12 @@ db_options.set_defaults(cfg.CONF, _DEFAU
+ def table_args():
+     engine_name = urlparse.urlparse(cfg.CONF.database.connection).scheme
+     if engine_name == 'mysql':
+-        return {'mysql_engine': cfg.CONF.database.mysql_engine,
+-                'mysql_charset': "utf8"}
++        if cfg.CONF.database.mysql_storage_engine == "NDBCLUSTER":
++            return {'mysql_engine': cfg.CONF.database.mysql_storage_engine,
++                    'mysql_charset': "utf8"}
++        else:
++            return {'mysql_engine': cfg.CONF.database.mysql_engine,
++                    'mysql_charset': "utf8"}
+     return None
+ 
+ 
+@@ -135,7 +139,7 @@ class Conductor(Base):
+     id = Column(Integer, primary_key=True)
+     hostname = Column(String(255), nullable=False)
+     drivers = Column(JSONEncodedList)
+-    online = Column(Boolean, default=True)
++    online = Column('online', Boolean, default=True, quote=True)
+ 
+ 
+ class Node(Base):
+--- ironic-2015.1.2/ironic/db/sqlalchemy/alembic/versions/2581ebaf0cb2_initial_migration.py.orig	2016-07-29 12:25:57.319572657 -0600
++++ ironic-2015.1.2/ironic/db/sqlalchemy/alembic/versions/2581ebaf0cb2_initial_migration.py	2016-07-29 12:27:49.354646151 -0600
+@@ -24,8 +24,10 @@ revision = '2581ebaf0cb2'
+ down_revision = None
+ 
+ from alembic import op
++from oslo_config import cfg
+ import sqlalchemy as sa
+ 
++CONF = cfg.CONF
+ 
+ def upgrade():
+     # commands auto generated by Alembic - please adjust!
+@@ -38,7 +40,7 @@ def upgrade():
+         sa.Column('drivers', sa.Text(), nullable=True),
+         sa.PrimaryKeyConstraint('id'),
+         sa.UniqueConstraint('hostname', name='uniq_conductors0hostname'),
+-        mysql_ENGINE='InnoDB',
++        mysql_ENGINE=CONF.database.mysql_storage_engine,
+         mysql_DEFAULT_CHARSET='UTF8'
+     )
+     op.create_table(
+@@ -51,7 +53,7 @@ def upgrade():
+         sa.Column('description', sa.String(length=255), nullable=True),
+         sa.PrimaryKeyConstraint('id'),
+         sa.UniqueConstraint('uuid', name='uniq_chassis0uuid'),
+-        mysql_ENGINE='InnoDB',
++        mysql_ENGINE=CONF.database.mysql_storage_engine,
+         mysql_DEFAULT_CHARSET='UTF8'
+     )
+     op.create_table(
+@@ -77,7 +79,7 @@ def upgrade():
+         sa.ForeignKeyConstraint(['chassis_id'], ['chassis.id'], ),
+         sa.PrimaryKeyConstraint('id'),
+         sa.UniqueConstraint('uuid', name='uniq_nodes0uuid'),
+-        mysql_ENGINE='InnoDB',
++        mysql_ENGINE=CONF.database.mysql_storage_engine,
+         mysql_DEFAULT_CHARSET='UTF8'
+     )
+     op.create_index('node_instance_uuid', 'nodes', ['instance_uuid'],
+@@ -95,7 +97,7 @@ def upgrade():
+         sa.PrimaryKeyConstraint('id'),
+         sa.UniqueConstraint('address', name='uniq_ports0address'),
+         sa.UniqueConstraint('uuid', name='uniq_ports0uuid'),
+-        mysql_ENGINE='InnoDB',
++        mysql_ENGINE=CONF.database.mysql_storage_engine,
+         mysql_DEFAULT_CHARSET='UTF8'
+     )
+     # end Alembic commands
+--- ironic-2015.1.2/ironic/db/sqlalchemy/alembic/versions/487deb87cc9d_add_conductor_affinity_and_online.py.orig	2016-07-29 12:26:04.346647881 -0600
++++ ironic-2015.1.2/ironic/db/sqlalchemy/alembic/versions/487deb87cc9d_add_conductor_affinity_and_online.py	2016-07-28 14:06:28.683182607 -0600
+@@ -29,7 +29,7 @@ import sqlalchemy as sa
+ def upgrade():
+     op.add_column(
+         'conductors',
+-        sa.Column('online', sa.Boolean(), default=True))
++        sa.Column('online', sa.Boolean(), default=True, quote=True))
+     op.add_column(
+         'nodes',
+         sa.Column('conductor_affinity', sa.Integer(),
+@@ -42,4 +42,4 @@ def downgrade():
+     op.drop_constraint('nodes_conductor_affinity_fk', 'nodes',
+             type_='foreignkey')
+     op.drop_column('nodes', 'conductor_affinity')
+-    op.drop_column('conductors', 'online')
++    op.drop_column('conductors', 'online', quote=True)
--- a/components/openstack/keystone/files/keystone.conf	Fri Jul 29 11:02:37 2016 -0700
+++ b/components/openstack/keystone/files/keystone.conf	Fri Jul 29 14:41:14 2016 -0600
@@ -427,6 +427,12 @@
 # (string value)
 #mysql_sql_mode = TRADITIONAL
 
+# This configures the MySQL storage engine. This allows for OpenStack to
+# support different storage engines such as InnoDB, NDB, etc. By Default,
+# this value will be set to InnoDB. For MySQL Cluster, set to NDBCLUSTER.
+# Example: mysql_storage_engine=(string value)
+#mysql_storage_engine = InnoDB
+
 # Timeout before idle SQL connections are reaped. (integer value)
 # Deprecated group/name - [DEFAULT]/sql_idle_timeout
 # Deprecated group/name - [DATABASE]/sql_idle_timeout
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openstack/keystone/patches/mysql_cluster_support.patch	Fri Jul 29 14:41:14 2016 -0600
@@ -0,0 +1,348 @@
+This patchset is for bug:
+
+22725754 - Keystone needs to support MySQL Cluster
+
+This fixes the following aspects of Keystone:
+1. Implementation of an oslo.db configuration parameter to specify the MySQL 
+   storage engine (mysql_storage_engine).
+2. Replacement of hardcoded SQL statements that set the engine to "InnoDB" 
+   to the above configuration value.
+3. Logic to handle SQL differences between MySQL InnoDB and MySQL Cluster (NDB). 
+   This includes column lengths, constraints, foreign keys, and indexes.
+
+This has not been committed upstream, but has been filed in launchpad:
+
+https://bugs.launchpad.net/keystone/+bug/1564110
+
+
+--- keystone-2015.1.2/keystone/contrib/endpoint_policy/migrate_repo/versions/001_add_endpoint_policy_table.py.orig	2016-02-17 11:31:28.370731100 -0700
++++ keystone-2015.1.2/keystone/contrib/endpoint_policy/migrate_repo/versions/001_add_endpoint_policy_table.py	2016-02-19 13:15:20.604166480 -0700
+@@ -13,7 +13,9 @@
+ # under the License.
+ 
+ import sqlalchemy as sql
++from oslo_config import cfg
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     # Upgrade operations go here. Don't create your own engine; bind
+@@ -34,7 +36,7 @@ def upgrade(migrate_engine):
+         sql.Column('region_id', sql.String(64),
+                    nullable=True),
+         sql.UniqueConstraint('endpoint_id', 'service_id', 'region_id'),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     endpoint_policy_table.create(migrate_engine, checkfirst=True)
+--- keystone-2015.1.2/keystone/contrib/federation/migrate_repo/versions/001_add_identity_provider_table.py.orig	2016-02-17 11:31:28.364528948 -0700
++++ keystone-2015.1.2/keystone/contrib/federation/migrate_repo/versions/001_add_identity_provider_table.py	2016-02-19 13:14:23.091304897 -0700
+@@ -11,7 +11,9 @@
+ # under the License.
+ 
+ import sqlalchemy as sql
++from oslo_config import cfg
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = sql.MetaData()
+@@ -23,7 +25,7 @@ def upgrade(migrate_engine):
+         sql.Column('id', sql.String(64), primary_key=True),
+         sql.Column('enabled', sql.Boolean, nullable=False),
+         sql.Column('description', sql.Text(), nullable=True),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     idp_table.create(migrate_engine, checkfirst=True)
+@@ -36,7 +38,7 @@ def upgrade(migrate_engine):
+                    sql.ForeignKey('identity_provider.id', ondelete='CASCADE'),
+                    primary_key=True),
+         sql.Column('mapping_id', sql.String(64), nullable=True),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     federation_protocol_table.create(migrate_engine, checkfirst=True)
+--- keystone-2015.1.2/keystone/contrib/federation/migrate_repo/versions/007_add_remote_id_table.py.orig	2016-02-17 11:31:28.369152519 -0700
++++ keystone-2015.1.2/keystone/contrib/federation/migrate_repo/versions/007_add_remote_id_table.py	2016-02-19 13:14:36.794647452 -0700
+@@ -11,7 +11,9 @@
+ # under the License.
+ 
+ import sqlalchemy as orm
++from oslo_config import cfg
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = orm.MetaData()
+@@ -27,7 +29,7 @@ def upgrade(migrate_engine):
+         orm.Column('remote_id',
+                    orm.String(255),
+                    primary_key=True),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     remote_id_table.create(migrate_engine, checkfirst=True)
+--- keystone-2015.1.2/keystone/contrib/federation/migrate_repo/versions/005_add_service_provider_table.py.orig	2016-02-17 11:31:28.366074588 -0700
++++ keystone-2015.1.2/keystone/contrib/federation/migrate_repo/versions/005_add_service_provider_table.py	2016-02-19 13:16:25.569156414 -0700
+@@ -11,7 +11,9 @@
+ # under the License.
+ 
+ import sqlalchemy as sql
++from oslo_config import cfg
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = sql.MetaData()
+@@ -25,7 +27,7 @@ def upgrade(migrate_engine):
+         sql.Column('enabled', sql.Boolean, nullable=False),
+         sql.Column('description', sql.Text(), nullable=True),
+         sql.Column('sp_url', sql.String(256), nullable=True),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     sp_table.create(migrate_engine, checkfirst=True)
+--- keystone-2015.1.2/keystone/contrib/federation/migrate_repo/versions/002_add_mapping_tables.py.orig	2016-02-17 11:31:28.367627604 -0700
++++ keystone-2015.1.2/keystone/contrib/federation/migrate_repo/versions/002_add_mapping_tables.py	2016-02-19 13:14:46.042762324 -0700
+@@ -11,7 +11,9 @@
+ # under the License.
+ 
+ import sqlalchemy as sql
++from oslo_config import cfg
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = sql.MetaData()
+@@ -22,6 +24,6 @@ def upgrade(migrate_engine):
+         meta,
+         sql.Column('id', sql.String(64), primary_key=True),
+         sql.Column('rules', sql.Text(), nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine ,
+         mysql_charset='utf8')
+     mapping_table.create(migrate_engine, checkfirst=True)
+--- keystone-2015.1.2/keystone/common/sql/migration_helpers.py.orig	2016-02-17 11:31:28.355333466 -0700
++++ keystone-2015.1.2/keystone/common/sql/migration_helpers.py	2016-02-19 10:15:36.520071425 -0700
+@@ -164,9 +164,9 @@ def _fix_federation_tables(engine):
+         # alter table to execute
+         engine.execute("SET foreign_key_checks = 0")
+         # * Make the tables using InnoDB engine
+-        engine.execute("ALTER TABLE identity_provider Engine=InnoDB")
+-        engine.execute("ALTER TABLE federation_protocol Engine=InnoDB")
+-        engine.execute("ALTER TABLE mapping Engine=InnoDB")
++        engine.execute("ALTER TABLE identity_provider Engine=%s" % CONF.database.mysql_storage_engine)
++        engine.execute("ALTER TABLE federation_protocol Engine=%s" % CONF.database.mysql_storage_engine)
++        engine.execute("ALTER TABLE mapping Engine=%s" % CONF.database.mysql_storage_engine)
+         # * Make the tables using utf8 encoding
+         engine.execute("ALTER TABLE identity_provider "
+                        "CONVERT TO CHARACTER SET utf8")
+--- keystone-2015.1.2/keystone/common/sql/migrate_repo/versions/051_add_id_mapping.py.orig	2016-02-17 11:31:28.357606093 -0700
++++ keystone-2015.1.2/keystone/common/sql/migrate_repo/versions/051_add_id_mapping.py	2016-02-19 13:10:31.212704447 -0700
+@@ -13,9 +13,10 @@
+ # under the License.
+ 
+ import sqlalchemy as sql
+-
+ from keystone.identity.mapping_backends import mapping
++from oslo_config import cfg
+ 
++CONF = cfg.CONF
+ 
+ MAPPING_TABLE = 'id_mapping'
+ 
+@@ -36,6 +37,6 @@ def upgrade(migrate_engine):
+             name='entity_type'),
+             nullable=False),
+         sql.UniqueConstraint('domain_id', 'local_id', 'entity_type'),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+     mapping_table.create(migrate_engine, checkfirst=True)
+--- keystone-2015.1.2/keystone/common/sql/migrate_repo/versions/044_icehouse.py.orig	2016-02-17 11:31:28.359732657 -0700
++++ keystone-2015.1.2/keystone/common/sql/migrate_repo/versions/044_icehouse.py	2016-02-19 13:12:49.670971345 -0700
+@@ -47,7 +47,7 @@ def upgrade(migrate_engine):
+         sql.Column('blob', ks_sql.JsonBlob, nullable=False),
+         sql.Column('type', sql.String(length=255), nullable=False),
+         sql.Column('extra', ks_sql.JsonBlob.impl),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     domain = sql.Table(
+@@ -56,7 +56,7 @@ def upgrade(migrate_engine):
+         sql.Column('name', sql.String(length=64), nullable=False),
+         sql.Column('enabled', sql.Boolean, default=True, nullable=False),
+         sql.Column('extra', ks_sql.JsonBlob.impl),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     endpoint = sql.Table(
+@@ -70,7 +70,7 @@ def upgrade(migrate_engine):
+         sql.Column('extra', ks_sql.JsonBlob.impl),
+         sql.Column('enabled', sql.Boolean, nullable=False, default=True,
+                    server_default='1'),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     group = sql.Table(
+@@ -80,7 +80,7 @@ def upgrade(migrate_engine):
+         sql.Column('name', sql.String(length=64), nullable=False),
+         sql.Column('description', sql.Text),
+         sql.Column('extra', ks_sql.JsonBlob.impl),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     policy = sql.Table(
+@@ -89,7 +89,7 @@ def upgrade(migrate_engine):
+         sql.Column('type', sql.String(length=255), nullable=False),
+         sql.Column('blob', ks_sql.JsonBlob, nullable=False),
+         sql.Column('extra', ks_sql.JsonBlob.impl),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     project = sql.Table(
+@@ -100,7 +100,7 @@ def upgrade(migrate_engine):
+         sql.Column('description', sql.Text),
+         sql.Column('enabled', sql.Boolean),
+         sql.Column('domain_id', sql.String(length=64), nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     role = sql.Table(
+@@ -108,7 +108,7 @@ def upgrade(migrate_engine):
+         sql.Column('id', sql.String(length=64), primary_key=True),
+         sql.Column('name', sql.String(length=255), nullable=False),
+         sql.Column('extra', ks_sql.JsonBlob.impl),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     service = sql.Table(
+@@ -118,7 +118,7 @@ def upgrade(migrate_engine):
+         sql.Column('enabled', sql.Boolean, nullable=False, default=True,
+                    server_default='1'),
+         sql.Column('extra', ks_sql.JsonBlob.impl),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     token = sql.Table(
+@@ -129,7 +129,7 @@ def upgrade(migrate_engine):
+         sql.Column('valid', sql.Boolean, default=True, nullable=False),
+         sql.Column('trust_id', sql.String(length=64)),
+         sql.Column('user_id', sql.String(length=64)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     trust = sql.Table(
+@@ -143,7 +143,7 @@ def upgrade(migrate_engine):
+         sql.Column('expires_at', sql.DateTime),
+         sql.Column('remaining_uses', sql.Integer, nullable=True),
+         sql.Column('extra', ks_sql.JsonBlob.impl),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     trust_role = sql.Table(
+@@ -152,7 +152,7 @@ def upgrade(migrate_engine):
+                    nullable=False),
+         sql.Column('role_id', sql.String(length=64), primary_key=True,
+                    nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     user = sql.Table(
+@@ -164,14 +164,14 @@ def upgrade(migrate_engine):
+         sql.Column('enabled', sql.Boolean),
+         sql.Column('domain_id', sql.String(length=64), nullable=False),
+         sql.Column('default_project_id', sql.String(length=64)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     user_group_membership = sql.Table(
+         'user_group_membership', meta,
+         sql.Column('user_id', sql.String(length=64), primary_key=True),
+         sql.Column('group_id', sql.String(length=64), primary_key=True),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     region = sql.Table(
+@@ -181,7 +181,7 @@ def upgrade(migrate_engine):
+         sql.Column('description', sql.String(255), nullable=False),
+         sql.Column('parent_region_id', sql.String(64), nullable=True),
+         sql.Column('extra', sql.Text()),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     assignment = sql.Table(
+@@ -199,7 +199,7 @@ def upgrade(migrate_engine):
+         sql.Column('role_id', sql.String(64), nullable=False),
+         sql.Column('inherited', sql.Boolean, default=False, nullable=False),
+         sql.PrimaryKeyConstraint('type', 'actor_id', 'target_id', 'role_id'),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     # create all tables
+--- keystone-2015.1.2/keystone/common/sql/migrate_repo/versions/065_add_domain_config.py.orig	2016-02-17 11:31:28.361388817 -0700
++++ keystone-2015.1.2/keystone/common/sql/migrate_repo/versions/065_add_domain_config.py	2016-02-19 13:10:34.283121353 -0700
+@@ -11,8 +11,10 @@
+ # under the License.
+ 
+ import sqlalchemy as sql
+-
+ from keystone.common import sql as ks_sql
++from oslo_config import cfg
++
++CONF = cfg.CONF
+ 
+ WHITELIST_TABLE = 'whitelisted_config'
+ SENSITIVE_TABLE = 'sensitive_config'
+@@ -29,7 +31,7 @@ def upgrade(migrate_engine):
+         sql.Column('group', sql.String(255), primary_key=True),
+         sql.Column('option', sql.String(255), primary_key=True),
+         sql.Column('value', ks_sql.JsonBlob.impl, nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+     whitelist_table.create(migrate_engine, checkfirst=True)
+ 
+@@ -40,6 +42,6 @@ def upgrade(migrate_engine):
+         sql.Column('group', sql.String(255), primary_key=True),
+         sql.Column('option', sql.String(255), primary_key=True),
+         sql.Column('value', ks_sql.JsonBlob.impl, nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+     sensitive_table.create(migrate_engine, checkfirst=True)
+--- keystone-2015.1.2/keystone/tests/unit/test_sql_upgrade.py.orig	2016-02-17 11:31:28.362966631 -0700
++++ keystone-2015.1.2/keystone/tests/unit/test_sql_upgrade.py	2016-02-19 10:47:11.044395387 -0700
+@@ -663,9 +663,9 @@ class SqlUpgradeTests(SqlMigrateBase):
+         noninnodb = connection.execute("SELECT table_name "
+                                        "from information_schema.TABLES "
+                                        "where TABLE_SCHEMA='%(database)s' "
+-                                       "and ENGINE!='InnoDB' "
++                                       "and ENGINE!='%(mysql_storage_engine)s' "
+                                        "and TABLE_NAME!='migrate_version'" %
+-                                       dict(database=database))
++                                       dict(database=database, mysql_storage_engine=CONF.database.mysql_storage_engine))
+         names = [x[0] for x in noninnodb]
+         self.assertEqual([], names,
+                          "Non-InnoDB tables exist")
--- a/components/openstack/neutron/files/neutron.conf	Fri Jul 29 11:02:37 2016 -0700
+++ b/components/openstack/neutron/files/neutron.conf	Fri Jul 29 14:41:14 2016 -0600
@@ -736,6 +736,12 @@
 # The SQLAlchemy connection string used to connect to the slave database
 # slave_connection =
 
+# This configures the MySQL storage engine. This allows for OpenStack to
+# support different storage engines such as InnoDB, NDB, etc. By Default,
+# this value will be set to InnoDB. For MySQL Cluster, set to NDBCLUSTER.
+# Example: mysql_storage_engine=(string value)
+#mysql_storage_engine = InnoDB
+
 # Database reconnection retry times - in event connectivity is lost
 # set to -1 implies an infinite retry count
 # max_retries = 10
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openstack/neutron/patches/11-mysql_cluster_support.patch	Fri Jul 29 14:41:14 2016 -0600
@@ -0,0 +1,1172 @@
+This patchset is for bug:
+
+22726251 - Neutron needs to support MySQL Cluster
+
+This fixes the following aspects of Neutron:
+1. Implementation of an oslo.db configuration parameter to specify the MySQL
+   storage engine (mysql_storage_engine).
+2. Replacement of hardcoded SQL statements that set the engine to "InnoDB"
+   to the above configuration value.
+3. Logic to handle SQL differences between MySQL InnoDB and MySQL Cluster (NDB).
+   This includes column lengths, constraints, foreign keys, and indexes.
+
+This has not been committed upstream, but has been filed in launchpad:
+
+https://bugs.launchpad.net/neutron/+bug/1564110
+
+
+--- neutron-2015.1.2/neutron/db/model_base.py.orig	2016-07-29 13:15:07.909806102 -0600
++++ neutron-2015.1.2/neutron/db/model_base.py	2016-07-29 13:27:41.817140969 -0600
+@@ -13,15 +13,24 @@
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ 
++from oslo_config import cfg
+ from oslo_db.sqlalchemy import models
+ from sqlalchemy.ext import declarative
+ from sqlalchemy import orm
+ 
++# Attempt to determine the context that this module is being used.
++# If via neutron-db-manage and cli.py, import global variable. If not,
++# use oslo_config.
++try:
++     from neutron.db.migration.cli import mysql_storage_eng_type
++except ImportError:
++     CONF = cfg.CONF
++     mysql_storage_eng_type = CONF.database.mysql_storage_engine
+ 
+ class NeutronBase(models.ModelBase):
+     """Base class for Neutron Models."""
+ 
+-    __table_args__ = {'mysql_engine': 'InnoDB'}
++    __table_args__ = {'mysql_engine': mysql_storage_eng_type}
+ 
+     def __iter__(self):
+         self._i = iter(orm.object_mapper(self).columns)
+--- neutron-2015.1.2/neutron/db/api.py.orig	2016-07-29 13:15:14.380329905 -0600
++++ neutron-2015.1.2/neutron/db/api.py	2016-07-28 14:15:31.186601900 -0600
+@@ -19,7 +19,6 @@ from oslo_config import cfg
+ from oslo_db.sqlalchemy import session
+ from sqlalchemy import exc
+ 
+-
+ _FACADE = None
+ 
+ MAX_RETRIES = 10
+@@ -50,10 +49,30 @@ def get_session(autocommit=True, expire_
+ @contextlib.contextmanager
+ def autonested_transaction(sess):
+     """This is a convenience method to not bother with 'nested' parameter."""
++    # Attempt to determine the context that this module is being used.
++    # If via neutron-db-manage and cli.py, import global variable. If not,
++    # use oslo_config.
+     try:
+-        session_context = sess.begin_nested()
+-    except exc.InvalidRequestError:
+-        session_context = sess.begin(subtransactions=True)
+-    finally:
+-        with session_context as tx:
+-            yield tx
++        from neutron.db.migration.cli import mysql_storage_eng_type
++    except ImportError:
++        CONF = cfg.CONF
++        mysql_storage_eng_type = CONF.database.mysql_storage_engine
++
++    # MySQL Cluster NDB does not support nested transactions
++    # TODO (oorgeron) Look into making this workable.
++    if mysql_storage_eng_type == "NDBCLUSTER":
++        try:
++            session_context = sess.begin(subtransactions=True, nested=False)
++        except exc.InvalidRequestError:
++            session_context = sess.begin(subtransactions=False, nested=False)
++        finally:
++            with session_context as tx:
++                yield tx
++    else:
++        try:
++            session_context = sess.begin_nested()
++        except exc.InvalidRequestError:
++            session_context = sess.begin(subtransactions=True)
++        finally:
++            with session_context as tx:
++                yield tx
+--- neutron-2015.1.2/neutron/db/db_base_plugin_v2.py.orig	2016-07-29 13:15:20.388338380 -0600
++++ neutron-2015.1.2/neutron/db/db_base_plugin_v2.py	2016-07-28 14:15:31.187095505 -0600
+@@ -46,6 +46,15 @@ from neutron.plugins.common import const
+ 
+ LOG = logging.getLogger(__name__)
+ 
++# Attempt to determine the context that this module is being used.
++# If via neutron-db-manage and cli.py, import global variable. If not,
++# use oslo_config.
++try:
++     from neutron.db.migration.cli import mysql_storage_eng_type
++except ImportError:
++     CONF = cfg.CONF
++     mysql_storage_eng_type = CONF.database.mysql_storage_engine
++
+ # Ports with the following 'device_owner' values will not prevent
+ # network deletion.  If delete_network() finds that all ports on a
+ # network have these owners, it will explicitly delete each port
+@@ -1443,16 +1452,26 @@ class NeutronDbPluginV2(neutron_plugin_b
+                                                    port_id=port['id'],
+                                                    ip_address=ip_address,
+                                                    subnet_id=subnet['id'])
+-                try:
+-                    # Do the insertion of each IP allocation entry within
+-                    # the context of a nested transaction, so that the entry
+-                    # is rolled back independently of other entries whenever
+-                    # the corresponding port has been deleted.
+-                    with context.session.begin_nested():
+-                        context.session.add(allocated)
+-                except db_exc.DBReferenceError:
+-                    LOG.debug("Port %s was deleted while updating it with an "
+-                              "IPv6 auto-address. Ignoring.", port['id'])
++                # MySQL Cluster NDB does not support nested transactions
++                # TODO (oorgeron) Look into making this workable.
++                if mysql_storage_eng_type == "NDBCLUSTER":
++                    try:
++                        with context.session.begin(subtransactions=True):
++                            context.session.add(allocated)
++                    except db_exc.DBReferenceError:
++                        LOG.debug("Port %s was deleted while updating it with an "
++                                  "IPv6 auto-address. Ignoring.", port['id'])
++                else:
++                    try:
++                        # Do the insertion of each IP allocation entry within
++                        # the context of a nested transaction, so that the entry
++                        # is rolled back independently of other entries whenever
++                        # the corresponding port has been deleted.
++                        with context.session.begin_nested():
++                            context.session.add(allocated)
++                    except db_exc.DBReferenceError:
++                        LOG.debug("Port %s was deleted while updating it with an "
++                                  "IPv6 auto-address. Ignoring.", port['id'])
+ 
+     def _update_subnet_dns_nameservers(self, context, id, s):
+         old_dns_list = self._get_dns_by_subnet(context, id)
+@@ -1797,8 +1816,16 @@ class NeutronDbPluginV2(neutron_plugin_b
+                 # within a transaction, so that it can be rolled back to the
+                 # point before its failure while maintaining the enclosing
+                 # transaction
+-                return self._create_port_with_mac(
+-                    context, network_id, port_data, mac, nested=True)
++
++                # MySQL Cluster NDB does not support nested transactions
++                # TODO (oorgeron) Look into making this workable.
++                if mysql_storage_eng_type == "NDBCLUSTER":
++                    return self._create_port_with_mac(
++                        context, network_id, port_data, mac, nested=False)
++                else:
++                    return self._create_port_with_mac(
++                        context, network_id, port_data, mac, nested=True)
++
+             except n_exc.MacAddressInUse:
+                 LOG.debug('Generated mac %(mac_address)s exists on '
+                           'network %(network_id)s',
+--- neutron-2015.1.2/neutron/db/migration/cli.py.orig	2016-07-29 13:15:27.041205822 -0600
++++ neutron-2015.1.2/neutron/db/migration/cli.py	2016-07-28 14:15:31.187312338 -0600
+@@ -59,6 +59,9 @@ _db_opts = [
+     cfg.StrOpt('engine',
+                default='',
+                help=_('Database engine')),
++    cfg.StrOpt('mysql_storage_engine',
++               default='',
++               help=_('MySQL Storage Engine')),
+ ]
+ 
+ CONF = cfg.ConfigOpts()
+@@ -234,5 +237,11 @@ def main():
+     config = get_alembic_config()
+     config.neutron_config = CONF
+ 
++    # Make global variable available for modules that will be called
++    # by neutron-db-manage. This will prevent namespace collisions
++    # between oslo_config and albemic_config
++    global mysql_storage_eng_type
++    mysql_storage_eng_type = CONF.database.mysql_storage_engine
++
+     #TODO(gongysh) enable logging
+     CONF.command.func(config, CONF.command.name)
+--- neutron-2015.1.2/neutron/db/migration/models/frozen.py.orig	2016-07-29 13:15:33.940472370 -0600
++++ neutron-2015.1.2/neutron/db/migration/models/frozen.py	2016-07-29 13:29:33.819709706 -0600
+@@ -22,7 +22,8 @@ Based on this comparison database can be
+ Current HEAD commit is 59da928e945ec58836d34fd561d30a8a446e2728
+ """
+ 
+-
++from alembic import context
++from oslo_config import cfg
+ import sqlalchemy as sa
+ from sqlalchemy.ext import declarative
+ from sqlalchemy.ext.orderinglist import ordering_list
+@@ -32,6 +33,8 @@ from sqlalchemy import schema
+ from neutron.db import model_base
+ from neutron.openstack.common import uuidutils
+ 
++config = context.config
++CONF = config.neutron_config
+ 
+ # Dictionary of all tables that was renamed:
+ # {new_table_name: old_table_name}
+@@ -77,6 +80,10 @@ DHCPV6_STATELESS = 'dhcpv6-stateless'
+ 
+ BASEV2 = declarative.declarative_base(cls=model_base.NeutronBaseV2)
+ 
++if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++   db_string_length = 128
++else:
++   db_string_length = 256
+ 
+ #neutron/db/models_v2.py
+ class HasTenant(object):
+@@ -218,17 +225,30 @@ class Agent(BASEV2, HasId):
+                             name='uniq_agents0agent_type0host'),
+     )
+ 
+-    agent_type = sa.Column(sa.String(255), nullable=False)
+-    binary = sa.Column(sa.String(255), nullable=False)
+-    topic = sa.Column(sa.String(255), nullable=False)
+-    host = sa.Column(sa.String(255), nullable=False)
+-    admin_state_up = sa.Column(sa.Boolean, default=True,
+-                               server_default=sa.sql.true(), nullable=False)
+-    created_at = sa.Column(sa.DateTime, nullable=False)
+-    started_at = sa.Column(sa.DateTime, nullable=False)
+-    heartbeat_timestamp = sa.Column(sa.DateTime, nullable=False)
+-    description = sa.Column(sa.String(255))
+-    configurations = sa.Column(sa.String(4095), nullable=False)
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        agent_type = sa.Column(sa.String(db_string_length), nullable=False)
++        binary = sa.Column(sa.String(db_string_length), nullable=False)
++        topic = sa.Column(sa.String(db_string_length), nullable=False)
++        host = sa.Column(sa.String(db_string_length), nullable=False)
++        admin_state_up = sa.Column(sa.Boolean, default=True,
++                                   server_default=sa.sql.true(), nullable=False)
++        created_at = sa.Column(sa.DateTime, nullable=False)
++        started_at = sa.Column(sa.DateTime, nullable=False)
++        heartbeat_timestamp = sa.Column(sa.DateTime, nullable=False)
++        description = sa.Column(sa.String(db_string_length))
++        configurations = sa.Column(sa.Text(4095), nullable=False)
++    else:
++        agent_type = sa.Column(sa.String(db_string_length), nullable=False)
++        binary = sa.Column(sa.String(db_string_length), nullable=False)
++        topic = sa.Column(sa.String(db_string_length), nullable=False)
++        host = sa.Column(sa.String(db_string_length), nullable=False)
++        admin_state_up = sa.Column(sa.Boolean, default=True,
++                                   server_default=sa.sql.true(), nullable=False)
++        created_at = sa.Column(sa.DateTime, nullable=False)
++        started_at = sa.Column(sa.DateTime, nullable=False)
++        heartbeat_timestamp = sa.Column(sa.DateTime, nullable=False)
++        description = sa.Column(sa.String(db_string_length))
++        configurations = sa.Column(sa.String(4095), nullable=False)
+ 
+ 
+ #neutron/db/agentschedulers_db.py
+@@ -431,10 +451,15 @@ class Vip(BASEV2, HasId, HasTenant, HasS
+ 
+ #neutron/db/loadbalancer/loadbalancer_db.py
+ class Member(BASEV2, HasId, HasTenant, HasStatusDescription):
+-    __table_args__ = (
+-        sa.schema.UniqueConstraint('pool_id', 'address', 'protocol_port',
+-                                   name='uniq_member0pool_id0address0port'),
+-    )
++    
++    # MySQL Cluster NDB does not support this constraint.
++    # TODO (oorgeron) Look into making this workable.
++    if CONF.database.mysql_storage_engine != "NDBCLUSTER":
++        __table_args__ = (
++            sa.schema.UniqueConstraint('pool_id', 'address', 'protocol_port',
++                                       name='uniq_member0pool_id0address0port'),
++        )
++
+     pool_id = sa.Column(sa.String(36), sa.ForeignKey("pools.id"),
+                         nullable=False)
+     address = sa.Column(sa.String(64), nullable=False)
+@@ -1229,8 +1254,15 @@ class PortBinding(BASEV2):
+     profile = sa.Column(sa.String(BINDING_PROFILE_LEN), nullable=False,
+                         default='', server_default='')
+     vif_type = sa.Column(sa.String(64), nullable=False)
+-    vif_details = sa.Column(sa.String(4095), nullable=False, default='',
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        vif_details = sa.Column(sa.Text(4095), nullable=False)
++        profile = sa.Column(sa.Text(length=4095),nullable=False)
++    else:
++        vif_details = sa.Column(sa.String(4095), nullable=False,
++                                server_default='')
++        profile = sa.Column(sa.String(length=4095),nullable=False,
+                             server_default='')
++
+     driver = sa.Column(sa.String(64))
+     segment = sa.Column(sa.String(36),
+                         sa.ForeignKey('ml2_network_segments.id',
+@@ -1827,10 +1859,17 @@ class PoolPort(BASEV2):
+ class IdentifierMap(BASEV2, HasTenant):
+     __tablename__ = 'cisco_csr_identifier_map'
+ 
+-    ipsec_site_conn_id = sa.Column(sa.String(64),
+-                                   sa.ForeignKey('ipsec_site_connections.id',
+-                                                 ondelete="CASCADE"),
+-                                   primary_key=True)
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        ipsec_site_conn_id = sa.Column(sa.String(36),
++                                       sa.ForeignKey('ipsec_site_connections.id',
++                                                     ondelete="CASCADE"),
++                                       primary_key=True)
++    else:
++        ipsec_site_conn_id = sa.Column(sa.String(64),
++                                       sa.ForeignKey('ipsec_site_connections.id',
++                                                     ondelete="CASCADE"),
++                                       primary_key=True)
++
+     csr_tunnel_id = sa.Column(sa.Integer, nullable=False)
+     csr_ike_policy_id = sa.Column(sa.Integer, nullable=False)
+     csr_ipsec_policy_id = sa.Column(sa.Integer, nullable=False)
+--- neutron-2015.1.2/neutron/db/migration/alembic_migrations/agent_init_ops.py.orig	2016-07-29 13:15:57.799898995 -0600
++++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/agent_init_ops.py	2016-07-29 13:30:30.011137004 -0600
+@@ -17,26 +17,49 @@
+ # This module only manages the 'agents' table. Binding tables are created
+ # in the modules for relevant resources
+ 
+-
++from alembic import context
+ from alembic import op
+ import sqlalchemy as sa
+ 
++config = context.config
++CONF = config.neutron_config
++
++if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++   db_string_length = 128
++else:
++   db_string_length = 256
+ 
+ def upgrade():
+     bind = op.get_bind()
+     insp = sa.engine.reflection.Inspector.from_engine(bind)
+     if 'agents' not in insp.get_table_names():
+-        op.create_table(
+-        'agents',
+-        sa.Column('id', sa.String(length=36), nullable=False),
+-        sa.Column('agent_type', sa.String(length=255), nullable=False),
+-        sa.Column('binary', sa.String(length=255), nullable=False),
+-        sa.Column('topic', sa.String(length=255), nullable=False),
+-        sa.Column('host', sa.String(length=255), nullable=False),
+-        sa.Column('admin_state_up', sa.Boolean(), nullable=False),
+-        sa.Column('created_at', sa.DateTime(), nullable=False),
+-        sa.Column('started_at', sa.DateTime(), nullable=False),
+-        sa.Column('heartbeat_timestamp', sa.DateTime(), nullable=False),
+-        sa.Column('description', sa.String(length=255), nullable=True),
+-        sa.Column('configurations', sa.String(length=4095), nullable=False),
+-        sa.PrimaryKeyConstraint('id'))
++        if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++            op.create_table(
++                'agents',
++                sa.Column('id', sa.String(length=36), nullable=False),
++                sa.Column('agent_type', sa.String(length=db_string_length), nullable=False),
++                sa.Column('binary', sa.String(length=db_string_length), nullable=False),
++                sa.Column('topic', sa.String(length=db_string_length), nullable=False),
++                sa.Column('host', sa.String(length=db_string_length), nullable=False),
++                sa.Column('admin_state_up', sa.Boolean(), nullable=False),
++                sa.Column('created_at', sa.DateTime(), nullable=False),
++                sa.Column('started_at', sa.DateTime(), nullable=False),
++                sa.Column('heartbeat_timestamp', sa.DateTime(), nullable=False),
++                sa.Column('description', sa.String(length=db_string_length), nullable=True),
++                sa.Column('configurations', sa.Text(length=4095), nullable=False),
++                sa.PrimaryKeyConstraint('id'))
++        else:
++            op.create_table(
++                'agents',
++                sa.Column('id', sa.String(length=36), nullable=False),
++                sa.Column('agent_type', sa.String(length=db_string_length), nullable=False),
++                sa.Column('binary', sa.String(length=db_string_length), nullable=False),
++                sa.Column('topic', sa.String(length=db_string_length), nullable=False),
++                sa.Column('host', sa.String(length=db_string_length), nullable=False),
++                sa.Column('admin_state_up', sa.Boolean(), nullable=False),
++                sa.Column('created_at', sa.DateTime(), nullable=False),
++                sa.Column('started_at', sa.DateTime(), nullable=False),
++                sa.Column('heartbeat_timestamp', sa.DateTime(), nullable=False),
++                sa.Column('description', sa.String(length=db_string_length), nullable=True),
++                sa.Column('configurations', sa.String(length=4095), nullable=False),
++                sa.PrimaryKeyConstraint('id'))
+--- neutron-2015.1.2/neutron/db/migration/alembic_migrations/heal_script.py.orig	2016-07-29 13:16:06.570595984 -0600
++++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/heal_script.py	2016-07-29 13:31:36.373228770 -0600
+@@ -19,6 +19,7 @@ import alembic
+ from alembic import autogenerate as autogen
+ from alembic import context
+ from alembic import op
++from oslo_config import cfg
+ 
+ import sqlalchemy
+ from sqlalchemy import schema as sa_schema
+@@ -29,6 +30,9 @@ from sqlalchemy import types
+ from neutron.db.migration.models import frozen as frozen_models
+ from neutron.i18n import _LI, _LW
+ 
++config = context.config
++CONF = config.neutron_config
++
+ LOG = logging.getLogger(__name__)
+ 
+ METHODS = {}
+@@ -70,7 +74,10 @@ def heal():
+         'compare_server_default': _compare_server_default,
+     }
+     mc = alembic.migration.MigrationContext.configure(op.get_bind(), opts=opts)
+-    set_storage_engine(op.get_bind(), "InnoDB")
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        set_storage_engine(op.get_bind(), 'NDBCLUSTER')
++    else:
++        set_storage_engine(op.get_bind(), 'InnoDB')
+     diff = autogen.compare_metadata(mc, models_metadata)
+     for el in diff:
+         execute_alembic_command(el)
+@@ -286,4 +293,6 @@ def set_storage_engine(bind, engine):
+     if bind.dialect.name == 'mysql':
+         for table in insp.get_table_names():
+             if insp.get_table_options(table)['mysql_engine'] != engine:
+-                op.execute("ALTER TABLE %s ENGINE=%s" % (table, engine))
++                op.execute("ALTER TABLE %(db_table)s Engine=%(mysql_storage_engine)s"
++                           % dict(db_table=table,
++                           mysql_storage_engine=CONF.database.mysql_storage_engine))
+--- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/157a5d299379_ml2_binding_profile.py.orig	2016-07-29 13:16:13.971296279 -0600
++++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/157a5d299379_ml2_binding_profile.py	2016-07-29 13:32:20.859598698 -0600
+@@ -25,14 +25,24 @@ Create Date: 2014-02-13 23:48:25.147279
+ revision = '157a5d299379'
+ down_revision = '50d5ba354c23'
+ 
++from alembic import context
+ from alembic import op
+ import sqlalchemy as sa
+ 
+ from neutron.db import migration
+ 
++config = context.config
++CONF = config.neutron_config
+ 
+ def upgrade():
+     if migration.schema_has_table('ml2_port_bindings'):
+-        op.add_column('ml2_port_bindings',
+-                      sa.Column('profile', sa.String(length=4095),
+-                                nullable=False, server_default=''))
++        # MySQL Cluster (NDB) does not support rows longer than 14000.
++        # This configures the profile column as TEXT to keep the row size down.
++        if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++            op.add_column('ml2_port_bindings',
++                          sa.Column('profile', sa.Text(length=4095),
++                                    nullable=False))
++        else:
++            op.add_column('ml2_port_bindings',
++                          sa.Column('profile', sa.String(length=4095),
++                                    nullable=False, server_default=''))
+--- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/50d5ba354c23_ml2_binding_vif_details.py.orig	2016-07-29 13:16:20.121107758 -0600
++++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/50d5ba354c23_ml2_binding_vif_details.py	2016-07-29 13:32:42.870041087 -0600
+@@ -25,11 +25,14 @@ Create Date: 2014-02-11 23:21:59.577972
+ revision = '50d5ba354c23'
+ down_revision = '27cc183af192'
+ 
++from alembic import context
+ from alembic import op
+ import sqlalchemy as sa
+ 
+ from neutron.db import migration
+ 
++config = context.config
++CONF = config.neutron_config
+ 
+ def upgrade():
+ 
+@@ -38,9 +41,17 @@ def upgrade():
+         # did not create the ml2_port_bindings table.
+         return
+ 
+-    op.add_column('ml2_port_bindings',
+-                  sa.Column('vif_details', sa.String(length=4095),
+-                            nullable=False, server_default=''))
++    # MySQL Cluster (NDB) does not support rows longer than 14000.
++    # This converts vif_details to TEXT to keep the row size down.
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        op.add_column('ml2_port_bindings',
++                      sa.Column('vif_details', sa.Text(length=4095),
++                                nullable=False))
++    else:
++        op.add_column('ml2_port_bindings',
++                      sa.Column('vif_details', sa.String(length=4095),
++                                nullable=False, server_default=''))
++
+     if op.get_bind().engine.name == 'ibm_db_sa':
+         op.execute(
+             "UPDATE ml2_port_bindings SET"
+--- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/e197124d4b9_add_unique_constrain.py.orig	2016-07-29 13:16:26.541620109 -0600
++++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/e197124d4b9_add_unique_constrain.py	2016-07-29 13:33:26.620005420 -0600
+@@ -25,16 +25,27 @@ Create Date: 2013-11-17 10:09:37.728903
+ revision = 'e197124d4b9'
+ down_revision = 'havana'
+ 
++from alembic import context
+ from alembic import op
++from oslo_config import cfg
+ 
+ from neutron.db import migration
+ 
++config = context.config
++CONF = config.neutron_config
+ 
+ CONSTRAINT_NAME = 'uniq_member0pool_id0address0port'
+ TABLE_NAME = 'members'
+ 
+ 
+ def upgrade():
++
++    # MySQL Cluster, a.k.a. NDB, does not support this migration step.
++    # This test will skip this migration.
++    # TODO (oorgeron) Look into making this workable.
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        return
++
+     if migration.schema_has_table(TABLE_NAME):
+         op.create_unique_constraint(
+             name=CONSTRAINT_NAME,
+--- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/86d6d9776e2b_cisco_apic_driver_update_l3.py.orig	2016-07-29 13:16:33.520954213 -0600
++++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/86d6d9776e2b_cisco_apic_driver_update_l3.py	2016-07-29 13:34:14.398075900 -0600
+@@ -25,19 +25,31 @@ Create Date: 2014-04-23 09:27:08.177021
+ revision = '86d6d9776e2b'
+ down_revision = '236b90af57ab'
+ 
+-
++from alembic import context
+ from alembic import op
++from oslo_config import cfg
+ import sqlalchemy as sa
+ 
++config = context.config
++CONF = config.neutron_config
++
+ 
+ def upgrade():
+ 
+     op.drop_table('cisco_ml2_apic_contracts')
+     op.drop_table('cisco_ml2_apic_epgs')
+ 
+-    op.create_table(
+-        'cisco_ml2_apic_contracts',
+-        sa.Column('tenant_id', sa.String(length=255)),
+-        sa.Column('router_id', sa.String(length=64), nullable=False),
+-        sa.ForeignKeyConstraint(['router_id'], ['routers.id']),
+-        sa.PrimaryKeyConstraint('router_id'))
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        op.create_table(
++            'cisco_ml2_apic_contracts',
++            sa.Column('tenant_id', sa.String(length=255)),
++            sa.Column('router_id', sa.String(length=36), nullable=False),
++            sa.ForeignKeyConstraint(['router_id'], ['routers.id']),
++            sa.PrimaryKeyConstraint('router_id'))
++    else:
++        op.create_table(
++            'cisco_ml2_apic_contracts',
++            sa.Column('tenant_id', sa.String(length=255)),
++            sa.Column('router_id', sa.String(length=64), nullable=False),
++            sa.ForeignKeyConstraint(['router_id'], ['routers.id']),
++            sa.PrimaryKeyConstraint('router_id'))
+--- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/24c7ea5160d7_cisco_csr_vpnaas.py.orig	2016-07-29 13:16:40.087477384 -0600
++++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/24c7ea5160d7_cisco_csr_vpnaas.py	2016-07-29 13:34:49.694936881 -0600
+@@ -23,25 +23,43 @@
+ revision = '24c7ea5160d7'
+ down_revision = '492a106273f8'
+ 
++from alembic import context
+ from alembic import op
++from oslo_config import cfg
+ import sqlalchemy as sa
+ 
+ from neutron.db import migration
+ 
++config = context.config
++CONF = config.neutron_config
+ 
+ def upgrade():
+     if not migration.schema_has_table('ipsec_site_connections'):
+         # The vpnaas service plugin was not configured.
+         return
+-    op.create_table(
+-        'cisco_csr_identifier_map',
+-        sa.Column('tenant_id', sa.String(length=255), nullable=True),
+-        sa.Column('ipsec_site_conn_id', sa.String(length=64),
+-                  primary_key=True),
+-        sa.Column('csr_tunnel_id', sa.Integer(), nullable=False),
+-        sa.Column('csr_ike_policy_id', sa.Integer(), nullable=False),
+-        sa.Column('csr_ipsec_policy_id', sa.Integer(), nullable=False),
+-        sa.ForeignKeyConstraint(['ipsec_site_conn_id'],
+-                                ['ipsec_site_connections.id'],
+-                                ondelete='CASCADE')
+-    )
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        op.create_table(
++            'cisco_csr_identifier_map',
++            sa.Column('tenant_id', sa.String(length=255), nullable=True),
++            sa.Column('ipsec_site_conn_id', sa.String(length=36),
++                      primary_key=True),
++            sa.Column('csr_tunnel_id', sa.Integer(), nullable=False),
++            sa.Column('csr_ike_policy_id', sa.Integer(), nullable=False),
++            sa.Column('csr_ipsec_policy_id', sa.Integer(), nullable=False),
++            sa.ForeignKeyConstraint(['ipsec_site_conn_id'],
++                                    ['ipsec_site_connections.id'],
++                                    ondelete='CASCADE')
++        )
++    else:  
++        op.create_table(
++            'cisco_csr_identifier_map',
++            sa.Column('tenant_id', sa.String(length=255), nullable=True),
++            sa.Column('ipsec_site_conn_id', sa.String(length=64),
++                      primary_key=True),
++            sa.Column('csr_tunnel_id', sa.Integer(), nullable=False),
++            sa.Column('csr_ike_policy_id', sa.Integer(), nullable=False),
++            sa.Column('csr_ipsec_policy_id', sa.Integer(), nullable=False),
++            sa.ForeignKeyConstraint(['ipsec_site_conn_id'],
++                                    ['ipsec_site_connections.id'],
++                                    ondelete='CASCADE')
++        )
+--- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/16cdf118d31d_extra_dhcp_options_ipv6_support.py.orig	2016-07-29 13:16:46.865282929 -0600
++++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/16cdf118d31d_extra_dhcp_options_ipv6_support.py	2016-07-29 13:35:19.078239546 -0600
+@@ -25,11 +25,16 @@ Create Date: 2014-10-23 17:04:19.796731
+ revision = '16cdf118d31d'
+ down_revision = '14be42f3d0a5'
+ 
++from alembic import context
+ from alembic import op
++from oslo_config import cfg
+ import sqlalchemy as sa
+ 
+ from neutron.db import migration
+ 
++config = context.config
++CONF = config.neutron_config
++
+ CONSTRAINT_NAME_OLD = 'uidx_portid_optname'
+ CONSTRAINT_NAME_NEW = 'uniq_extradhcpopts0portid0optname0ipversion'
+ TABLE_NAME = 'extradhcpopts'
+@@ -47,8 +52,11 @@ def upgrade():
+                   server_default='4', nullable=False))
+         op.execute("UPDATE extradhcpopts SET ip_version = 4")
+ 
+-    op.create_unique_constraint(
+-        name=CONSTRAINT_NAME_NEW,
+-        source='extradhcpopts',
+-        local_cols=['port_id', 'opt_name', 'ip_version']
+-    )
++    # MySQL Cluster NDB does not support this constraint.
++    # TODO (oorgeron) Look into making this workable.
++    if CONF.database.mysql_storage_engine != "NDBCLUSTER":
++        op.create_unique_constraint(
++            name=CONSTRAINT_NAME_NEW,
++            source='extradhcpopts',
++            local_cols=['port_id', 'opt_name', 'ip_version']
++        )
+--- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/327ee5fde2c7_set_innodb_engine.py.orig	2016-07-29 13:16:54.825004264 -0600
++++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/327ee5fde2c7_set_innodb_engine.py	2016-07-29 13:35:50.605636987 -0600
+@@ -26,7 +26,12 @@ revision = '327ee5fde2c7'
+ down_revision = '4eba2f05c2f4'
+ 
+ 
++from alembic import context
+ from alembic import op
++from oslo_config import cfg
++
++config = context.config
++CONF = config.neutron_config
+ 
+ # This list contain tables that could be deployed before change that converts
+ # all tables to InnoDB appeared
+@@ -37,4 +42,6 @@ TABLES = ['router_extra_attributes', 'dv
+ def upgrade():
+     if op.get_bind().dialect.name == 'mysql':
+         for table in TABLES:
+-            op.execute("ALTER TABLE %s ENGINE=InnoDB" % table)
++            op.execute("ALTER TABLE %(db_table)s ENGINE=%(mysql_storage_engine)s"
++                       % dict(db_table=table,
++                       mysql_storage_engine=CONF.database.mysql_storage_engine))
+--- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/20c469a5f920_add_index_for_port.py.orig	2016-07-29 13:17:00.753891761 -0600
++++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/20c469a5f920_add_index_for_port.py	2016-07-29 13:36:19.221516843 -0600
+@@ -25,11 +25,16 @@ Create Date: 2015-04-01 04:12:49.898443
+ revision = '20c469a5f920'
+ down_revision = '28a09af858a8'
+ 
++from alembic import context
+ from alembic import op
+ 
++config = context.config
++CONF = config.neutron_config
+ 
+ def upgrade():
+-    op.create_index(op.f('ix_ports_network_id_device_owner'),
+-                    'ports', ['network_id', 'device_owner'], unique=False)
+-    op.create_index(op.f('ix_ports_network_id_mac_address'),
+-                    'ports', ['network_id', 'mac_address'], unique=False)
++    # MySQL Cluster (NDB) does not support these indexes via alembic
++    if CONF.database.mysql_storage_engine != "NDBCLUSTER":
++        op.create_index(op.f('ix_ports_network_id_device_owner'),
++                        'ports', ['network_id', 'device_owner'], unique=False)
++        op.create_index(op.f('ix_ports_network_id_mac_address'),
++                        'ports', ['network_id', 'mac_address'], unique=False)
+--- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/2a1ee2fb59e0_add_mac_address_unique_constraint.py.orig	2016-07-29 13:17:07.106004816 -0600
++++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/2a1ee2fb59e0_add_mac_address_unique_constraint.py	2016-07-29 13:36:52.862356573 -0600
+@@ -25,15 +25,26 @@ Create Date: 2015-01-10 11:44:27.550349
+ revision = '2a1ee2fb59e0'
+ down_revision = '41662e32bce2'
+ 
++from alembic import context
+ from alembic import op
++from oslo_config import cfg
++
++config = context.config
++CONF = config.neutron_config
+ 
+ TABLE_NAME = 'ports'
+ CONSTRAINT_NAME = 'uniq_ports0network_id0mac_address'
+ 
+ 
+ def upgrade():
+-    op.create_unique_constraint(
+-        name=CONSTRAINT_NAME,
+-        source=TABLE_NAME,
+-        local_cols=['network_id', 'mac_address']
+-    )
++
++    # MySQL Cluster NDB does not support this constraint.
++    # TODO (oorgeron) Look into making this workable.
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        return
++    else:
++        op.create_unique_constraint(
++            name=CONSTRAINT_NAME,
++            source=TABLE_NAME,
++            local_cols=['network_id', 'mac_address']
++        )
+--- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/2026156eab2f_l2_dvr_models.py.orig	2016-07-29 13:17:16.553516359 -0600
++++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/2026156eab2f_l2_dvr_models.py	2016-07-29 13:37:31.406649583 -0600
+@@ -26,37 +26,73 @@ revision = '2026156eab2f'
+ down_revision = '3927f7f7c456'
+ 
+ 
++from alembic import context
+ from alembic import op
+ import sqlalchemy as sa
+ 
++config = context.config
++CONF = config.neutron_config
+ 
+ def upgrade():
+-    op.create_table(
+-        'dvr_host_macs',
+-        sa.Column('host', sa.String(length=255), nullable=False),
+-        sa.Column('mac_address', sa.String(length=32),
+-                  nullable=False, unique=True),
+-        sa.PrimaryKeyConstraint('host')
+-    )
+-    op.create_table(
+-        'ml2_dvr_port_bindings',
+-        sa.Column('port_id', sa.String(length=36), nullable=False),
+-        sa.Column('host', sa.String(length=255), nullable=False),
+-        sa.Column('router_id', sa.String(length=36), nullable=True),
+-        sa.Column('vif_type', sa.String(length=64), nullable=False),
+-        sa.Column('vif_details', sa.String(length=4095),
+-                  nullable=False, server_default=''),
+-        sa.Column('vnic_type', sa.String(length=64),
+-                  nullable=False, server_default='normal'),
+-        sa.Column('profile', sa.String(length=4095),
+-                  nullable=False, server_default=''),
+-        sa.Column('cap_port_filter', sa.Boolean(), nullable=False),
+-        sa.Column('driver', sa.String(length=64), nullable=True),
+-        sa.Column('segment', sa.String(length=36), nullable=True),
+-        sa.Column(u'status', sa.String(16), nullable=False),
+-        sa.ForeignKeyConstraint(['port_id'], ['ports.id'],
+-                                ondelete='CASCADE'),
+-        sa.ForeignKeyConstraint(['segment'], ['ml2_network_segments.id'],
+-                                ondelete='SET NULL'),
+-        sa.PrimaryKeyConstraint('port_id', 'host')
+-    )
++    # MySQL Cluster (NDB) does not support rows longer than 14000.
++    # This reduces the size of columns or converts them to TEXT to keep the row size down.
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        op.create_table(
++            'dvr_host_macs',
++            sa.Column('host', sa.String(length=128), nullable=False),
++            sa.Column('mac_address', sa.String(length=32),
++                      nullable=False, unique=True),
++            sa.PrimaryKeyConstraint('host')
++        )
++        op.create_table(
++            'ml2_dvr_port_bindings',
++            sa.Column('port_id', sa.String(length=36), nullable=False),
++            sa.Column('host', sa.String(length=128), nullable=False),
++            sa.Column('router_id', sa.String(length=36), nullable=True),
++            sa.Column('vif_type', sa.String(length=64), nullable=False),
++            sa.Column('vif_details', sa.Text(length=4095),
++                      nullable=False, server_default=''),
++            sa.Column('vnic_type', sa.String(length=64),
++                      nullable=False, server_default='normal'),
++            sa.Column('profile', sa.Text(length=4095),
++                      nullable=False, server_default=''),
++            sa.Column('cap_port_filter', sa.Boolean(), nullable=False),
++            sa.Column('driver', sa.String(length=64), nullable=True),
++            sa.Column('segment', sa.String(length=36), nullable=True),
++            sa.Column(u'status', sa.String(16), nullable=False),
++            sa.ForeignKeyConstraint(['port_id'], ['ports.id'],
++                                    ondelete='CASCADE'),
++            sa.ForeignKeyConstraint(['segment'], ['ml2_network_segments.id'],
++                                    ondelete='SET NULL'),
++            sa.PrimaryKeyConstraint('port_id', 'host')
++        )
++    else:
++        op.create_table(
++            'dvr_host_macs',
++            sa.Column('host', sa.String(length=255), nullable=False),
++            sa.Column('mac_address', sa.String(length=32),
++                      nullable=False, unique=True),
++            sa.PrimaryKeyConstraint('host')
++        )
++        op.create_table(
++            'ml2_dvr_port_bindings',
++            sa.Column('port_id', sa.String(length=36), nullable=False),
++            sa.Column('host', sa.String(length=255), nullable=False),
++            sa.Column('router_id', sa.String(length=36), nullable=True),
++            sa.Column('vif_type', sa.String(length=64), nullable=False),
++            sa.Column('vif_details', sa.String(length=4095),
++                      nullable=False, server_default=''),
++            sa.Column('vnic_type', sa.String(length=64),
++                      nullable=False, server_default='normal'),
++            sa.Column('profile', sa.String(length=4095),
++                      nullable=False, server_default=''),
++            sa.Column('cap_port_filter', sa.Boolean(), nullable=False),
++            sa.Column('driver', sa.String(length=64), nullable=True),
++            sa.Column('segment', sa.String(length=36), nullable=True),
++            sa.Column(u'status', sa.String(16), nullable=False),
++            sa.ForeignKeyConstraint(['port_id'], ['ports.id'],
++                                    ondelete='CASCADE'),
++            sa.ForeignKeyConstraint(['segment'], ['ml2_network_segments.id'],
++                                    ondelete='SET NULL'),
++            sa.PrimaryKeyConstraint('port_id', 'host')
++        )
+--- neutron-2015.1.2/neutron/db/extradhcpopt_db.py.orig	2016-07-29 13:17:23.118174498 -0600
++++ neutron-2015.1.2/neutron/db/extradhcpopt_db.py	2016-07-29 13:38:57.088142872 -0600
+@@ -13,6 +13,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from oslo_log import log as logging
+ import sqlalchemy as sa
+ from sqlalchemy import orm
+@@ -23,36 +24,67 @@ from neutron.db import model_base
+ from neutron.db import models_v2
+ from neutron.extensions import extra_dhcp_opt as edo_ext
+ 
++# Attempt to determine the context that this module is being used.
++# If via neutron-db-manage and cli.py, import global variable. If not,
++# use oslo_config.
++try:
++     from neutron.db.migration.cli import mysql_storage_eng_type
++except ImportError:
++     CONF = cfg.CONF
++     mysql_storage_eng_type = CONF.database.mysql_storage_engine
+ 
+ LOG = logging.getLogger(__name__)
+ 
+-
+-class ExtraDhcpOpt(model_base.BASEV2, models_v2.HasId):
+-    """Represent a generic concept of extra options associated to a port.
+-
+-    Each port may have none to many dhcp opts associated to it that can
+-    define specifically different or extra options to DHCP clients.
+-    These will be written to the <network_id>/opts files, and each option's
+-    tag will be referenced in the <network_id>/host file.
+-    """
+-    port_id = sa.Column(sa.String(36),
+-                        sa.ForeignKey('ports.id', ondelete="CASCADE"),
+-                        nullable=False)
+-    opt_name = sa.Column(sa.String(64), nullable=False)
+-    opt_value = sa.Column(sa.String(255), nullable=False)
+-    ip_version = sa.Column(sa.Integer, server_default='4', nullable=False)
+-    __table_args__ = (sa.UniqueConstraint(
+-        'port_id',
+-        'opt_name',
+-        'ip_version',
+-        name='uniq_extradhcpopts0portid0optname0ipversion'),
+-                      model_base.BASEV2.__table_args__,)
+-
+-    # Add a relationship to the Port model in order to instruct SQLAlchemy to
+-    # eagerly load extra_dhcp_opts bindings
+-    ports = orm.relationship(
+-        models_v2.Port,
+-        backref=orm.backref("dhcp_opts", lazy='joined', cascade='delete'))
++# MySQL Cluster NDB does not support this constraint.
++# TODO (oorgeron) Look into making this workable.
++if mysql_storage_eng_type == "NDBCLUSTER":
++    class ExtraDhcpOpt(model_base.BASEV2, models_v2.HasId):
++        """Represent a generic concept of extra options associated to a port.
++
++        Each port may have none to many dhcp opts associated to it that can
++        define specifically different or extra options to DHCP clients.
++        These will be written to the <network_id>/opts files, and each option's
++        tag will be referenced in the <network_id>/host file.
++        """
++        port_id = sa.Column(sa.String(36),
++                            sa.ForeignKey('ports.id', ondelete="CASCADE"),
++                            nullable=False)
++        opt_name = sa.Column(sa.String(64), nullable=False)
++        opt_value = sa.Column(sa.String(255), nullable=False)
++        ip_version = sa.Column(sa.Integer, server_default='4', nullable=False)
++
++        # Add a relationship to the Port model in order to instruct SQLAlchemy to
++        # eagerly load extra_dhcp_opts bindings
++        ports = orm.relationship(
++            models_v2.Port,
++            backref=orm.backref("dhcp_opts", lazy='joined', cascade='delete'))
++else:
++    class ExtraDhcpOpt(model_base.BASEV2, models_v2.HasId):
++        """Represent a generic concept of extra options associated to a port.
++
++        Each port may have none to many dhcp opts associated to it that can
++        define specifically different or extra options to DHCP clients.
++        These will be written to the <network_id>/opts files, and each option's
++        tag will be referenced in the <network_id>/host file.
++        """
++        port_id = sa.Column(sa.String(36),
++                            sa.ForeignKey('ports.id', ondelete="CASCADE"),
++                            nullable=False)
++        opt_name = sa.Column(sa.String(64), nullable=False)
++        opt_value = sa.Column(sa.String(255), nullable=False)
++        ip_version = sa.Column(sa.Integer, server_default='4', nullable=False)
++        __table_args__ = (sa.UniqueConstraint(
++            'port_id',
++            'opt_name',
++            'ip_version',
++            name='uniq_extradhcpopts0portid0optname0ipversion'),
++                          model_base.BASEV2.__table_args__,)
++
++        # Add a relationship to the Port model in order to instruct SQLAlchemy to
++        # eagerly load extra_dhcp_opts bindings
++        ports = orm.relationship(
++            models_v2.Port,
++            backref=orm.backref("dhcp_opts", lazy='joined', cascade='delete'))
+ 
+ 
+ class ExtraDhcpOptMixin(object):
+--- neutron-2015.1.2/neutron/db/models_v2.py.orig	2016-07-29 13:17:29.114096786 -0600
++++ neutron-2015.1.2/neutron/db/models_v2.py	2016-07-29 13:40:10.416011760 -0600
+@@ -13,6 +13,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ import sqlalchemy as sa
+ from sqlalchemy import orm
+ 
+@@ -21,6 +22,14 @@ from neutron.common import constants
+ from neutron.db import model_base
+ from neutron.openstack.common import uuidutils
+ 
++# Attempt to determine the context that this module is being used.
++# If via neutron-db-manage and cli.py, import global variable. If not,
++# use oslo_config.
++try:
++     from neutron.db.migration.cli import mysql_storage_eng_type
++except ImportError:
++     CONF = cfg.CONF
++     mysql_storage_eng_type = CONF.database.mysql_storage_engine
+ 
+ class HasTenant(object):
+     """Tenant mixin, add to subclasses that have a tenant."""
+@@ -126,47 +135,89 @@ class SubnetRoute(model_base.BASEV2, Rou
+                           primary_key=True)
+ 
+ 
+-class Port(model_base.BASEV2, HasId, HasTenant):
+-    """Represents a port on a Neutron v2 network."""
++# MySQL Cluster NDB does not support this constraint.
++# TODO (oorgeron) Look into making this workable.
++if mysql_storage_eng_type == "NDBCLUSTER":
++    class Port(model_base.BASEV2, HasId, HasTenant):
++        """Represents a port on a Neutron v2 network."""
++
++        name = sa.Column(sa.String(attr.NAME_MAX_LEN))
++        network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id"),
++                               nullable=False)
++        fixed_ips = orm.relationship(IPAllocation, backref='ports', lazy='joined')
++        mac_address = sa.Column(sa.String(32), nullable=False)
++        admin_state_up = sa.Column(sa.Boolean(), nullable=False)
++        status = sa.Column(sa.String(16), nullable=False)
++        device_id = sa.Column(sa.String(attr.DEVICE_ID_MAX_LEN), nullable=False)
++        device_owner = sa.Column(sa.String(attr.DEVICE_OWNER_MAX_LEN),
++                                 nullable=False)
++        __table_args__ = (
++            sa.Index(
++                'ix_ports_network_id_mac_address', 'network_id', 'mac_address'),
++            sa.Index(
++                'ix_ports_network_id_device_owner', 'network_id', 'device_owner'),
++            model_base.BASEV2.__table_args__
++        )
++
++        def __init__(self, id=None, tenant_id=None, name=None, network_id=None,
++                     mac_address=None, admin_state_up=None, status=None,
++                     device_id=None, device_owner=None, fixed_ips=None):
++            self.id = id
++            self.tenant_id = tenant_id
++            self.name = name
++            self.network_id = network_id
++            self.mac_address = mac_address
++            self.admin_state_up = admin_state_up
++            self.device_owner = device_owner
++            self.device_id = device_id
++            # Since this is a relationship only set it if one is passed in.
++            if fixed_ips:
++                self.fixed_ips = fixed_ips
++
++            # NOTE(arosen): status must be set last as an event is triggered on!
++            self.status = status            
++else:
++    class Port(model_base.BASEV2, HasId, HasTenant):
++        """Represents a port on a Neutron v2 network."""
++
++        name = sa.Column(sa.String(attr.NAME_MAX_LEN))
++        network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id"),
++                               nullable=False)
++        fixed_ips = orm.relationship(IPAllocation, backref='ports', lazy='joined')
++        mac_address = sa.Column(sa.String(32), nullable=False)
++        admin_state_up = sa.Column(sa.Boolean(), nullable=False)
++        status = sa.Column(sa.String(16), nullable=False)
++        device_id = sa.Column(sa.String(attr.DEVICE_ID_MAX_LEN), nullable=False)
++        device_owner = sa.Column(sa.String(attr.DEVICE_OWNER_MAX_LEN),
++                                 nullable=False)
++        __table_args__ = (
++            sa.Index(
++                'ix_ports_network_id_mac_address', 'network_id', 'mac_address'),
++            sa.Index(
++                'ix_ports_network_id_device_owner', 'network_id', 'device_owner'),
++            sa.UniqueConstraint(
++                network_id, mac_address,
++                name='uniq_ports0network_id0mac_address'),
++            model_base.BASEV2.__table_args__
++        )
++
++        def __init__(self, id=None, tenant_id=None, name=None, network_id=None,
++                     mac_address=None, admin_state_up=None, status=None,
++                     device_id=None, device_owner=None, fixed_ips=None):
++            self.id = id
++            self.tenant_id = tenant_id
++            self.name = name
++            self.network_id = network_id
++            self.mac_address = mac_address
++            self.admin_state_up = admin_state_up
++            self.device_owner = device_owner
++            self.device_id = device_id
++            # Since this is a relationship only set it if one is passed in.
++            if fixed_ips:
++                self.fixed_ips = fixed_ips
+ 
+-    name = sa.Column(sa.String(attr.NAME_MAX_LEN))
+-    network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id"),
+-                           nullable=False)
+-    fixed_ips = orm.relationship(IPAllocation, backref='ports', lazy='joined')
+-    mac_address = sa.Column(sa.String(32), nullable=False)
+-    admin_state_up = sa.Column(sa.Boolean(), nullable=False)
+-    status = sa.Column(sa.String(16), nullable=False)
+-    device_id = sa.Column(sa.String(attr.DEVICE_ID_MAX_LEN), nullable=False)
+-    device_owner = sa.Column(sa.String(attr.DEVICE_OWNER_MAX_LEN),
+-                             nullable=False)
+-    __table_args__ = (
+-        sa.Index(
+-            'ix_ports_network_id_mac_address', 'network_id', 'mac_address'),
+-        sa.Index(
+-            'ix_ports_network_id_device_owner', 'network_id', 'device_owner'),
+-        sa.UniqueConstraint(
+-            network_id, mac_address,
+-            name='uniq_ports0network_id0mac_address'),
+-        model_base.BASEV2.__table_args__
+-    )
+-
+-    def __init__(self, id=None, tenant_id=None, name=None, network_id=None,
+-                 mac_address=None, admin_state_up=None, status=None,
+-                 device_id=None, device_owner=None, fixed_ips=None):
+-        self.id = id
+-        self.tenant_id = tenant_id
+-        self.name = name
+-        self.network_id = network_id
+-        self.mac_address = mac_address
+-        self.admin_state_up = admin_state_up
+-        self.device_owner = device_owner
+-        self.device_id = device_id
+-        # Since this is a relationship only set it if one is passed in.
+-        if fixed_ips:
+-            self.fixed_ips = fixed_ips
+-
+-        # NOTE(arosen): status must be set last as an event is triggered on!
+-        self.status = status
++            # NOTE(arosen): status must be set last as an event is triggered on!
++            self.status = status
+ 
+ 
+ class DNSNameServer(model_base.BASEV2):
+--- neutron-2015.1.2/neutron/tests/functional/db/test_migrations.py.orig	2016-07-29 13:17:35.264552054 -0600
++++ neutron-2015.1.2/neutron/tests/functional/db/test_migrations.py	2016-07-29 13:41:12.657034516 -0600
+@@ -19,6 +19,7 @@ import pprint
+ import alembic
+ import alembic.autogenerate
+ import alembic.migration
++from alembic import context
+ from alembic import script as alembic_script
+ import mock
+ from oslo_config import cfg
+@@ -35,6 +36,9 @@ LOG = logging.getLogger(__name__)
+ 
+ cfg.CONF.import_opt('core_plugin', 'neutron.common.config')
+ 
++config = context.config
++CONF = config.neutron_config
++
+ CORE_PLUGIN = 'neutron.plugins.ml2.plugin.Ml2Plugin'
+ 
+ # These tables are still in the neutron database, but their models have moved
+@@ -195,7 +199,7 @@ class _TestModelsMigrations(test_migrati
+         self.assertTrue(len(tables) > 0,
+                         "No tables found. Wrong schema?")
+         noninnodb = [table for table in tables if
+-                     insp.get_table_options(table)['mysql_engine'] != 'InnoDB'
++                     insp.get_table_options(table)['mysql_engine'] != CONF.database.mysql_storage_engine
+                      and table != 'alembic_version']
+         self.assertEqual(0, len(noninnodb), "%s non InnoDB tables created" %
+                                             noninnodb)
+--- neutron-2015.1.2/neutron/plugins/ml2/drivers/cisco/apic/apic_model.py.orig	2016-07-29 13:17:41.409730731 -0600
++++ neutron-2015.1.2/neutron/plugins/ml2/drivers/cisco/apic/apic_model.py	2016-07-29 13:41:57.002278572 -0600
+@@ -13,6 +13,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from alembic import context
+ import sqlalchemy as sa
+ from sqlalchemy import orm
+ 
+@@ -22,6 +23,13 @@ from neutron.db import model_base
+ from neutron.db import models_v2
+ from neutron.plugins.ml2 import models as models_ml2
+ 
++config = context.config
++CONF = config.neutron_config
++
++if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++    router_string_length = 64
++else:
++    router_string_length = 36
+ 
+ class RouterContract(model_base.BASEV2, models_v2.HasTenant):
+ 
+@@ -34,8 +42,8 @@ class RouterContract(model_base.BASEV2,
+ 
+     __tablename__ = 'cisco_ml2_apic_contracts'
+ 
+-    router_id = sa.Column(sa.String(64), sa.ForeignKey('routers.id',
+-                                                       ondelete='CASCADE'),
++    router_id = sa.Column(sa.String(router_string_length), 
++                          sa.ForeignKey('routers.id', ondelete='CASCADE'),
+                           primary_key=True)
+ 
+ 
--- a/components/openstack/nova/files/nova.conf	Fri Jul 29 11:02:37 2016 -0700
+++ b/components/openstack/nova/files/nova.conf	Fri Jul 29 14:41:14 2016 -0600
@@ -2268,6 +2268,12 @@
 # value)
 #mysql_sql_mode=TRADITIONAL
 
+# This configures the MySQL storage engine. This allows for OpenStack to
+# support different storage engines such as InnoDB, NDB, etc. By Default,
+# this value will be set to InnoDB. For MySQL Cluster, set to NDBCLUSTER.
+# Example: mysql_storage_engine=(string value)
+#mysql_storage_engine = InnoDB
+
 # Timeout before idle SQL connections are reaped. (integer
 # value)
 # Deprecated group/name - [DEFAULT]/sql_idle_timeout
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openstack/nova/patches/13-mysql_cluster_support.patch	Fri Jul 29 14:41:14 2016 -0600
@@ -0,0 +1,1336 @@
+This patchset is for bug:
+
+22726259 - Nova needs to support MySQL Cluster
+
+This fixes the following aspects of Nova:
+1. Implementation of an oslo.db configuration parameter to specify the MySQL
+   storage engine (mysql_storage_engine).
+2. Replacement of hardcoded SQL statements that set the engine to "InnoDB"
+   to the above configuration value.
+3. Logic to handle SQL differences between MySQL InnoDB and MySQL Cluster (NDB).
+   This includes column lengths, constraints, foreign keys, and indexes.
+
+This has not been committed upstream, but has been filed in launchpad:
+
+https://bugs.launchpad.net/nova/+bug/1564110
+
+
+--- nova-2015.1.2/nova/tests/unit/db/test_migrations.py.orig	2016-07-29 13:51:34.115901218 -0600
++++ nova-2015.1.2/nova/tests/unit/db/test_migrations.py	2016-07-29 13:53:48.790397898 -0600
+@@ -42,6 +42,7 @@ import os
+ from migrate import UniqueConstraint
+ from migrate.versioning import repository
+ import mock
++from oslo_config import cfg
+ from oslo_db.sqlalchemy import test_base
+ from oslo_db.sqlalchemy import test_migrations
+ from oslo_db.sqlalchemy import utils as oslodbutils
+@@ -59,6 +60,7 @@ from nova import exception
+ from nova import test
+ from nova.tests import fixtures as nova_fixtures
+ 
++CONF = cfg.CONF
+ 
+ LOG = logging.getLogger(__name__)
+ 
+@@ -905,9 +907,10 @@ class TestNovaMigrationsMySQL(NovaMigrat
+             "SELECT count(*) "
+             "FROM information_schema.TABLES "
+             "WHERE TABLE_SCHEMA='%(database)s' "
+-            "AND ENGINE != 'InnoDB' "
++            "AND ENGINE != '%(mysql_storage_engine)s' "
+             "AND TABLE_NAME != 'migrate_version'" %
+-            {'database': self.migrate_engine.url.database})
++            {'database': self.migrate_engine.url.database, 
++             'mysql_storage_engine': CONF.database.mysql_storage_engine})
+         count = noninnodb.scalar()
+         self.assertEqual(count, 0, "%d non InnoDB tables created" % count)
+ 
+--- nova-2015.1.2/nova/db/sqlalchemy/utils.py.orig	2016-07-29 13:51:41.029493681 -0600
++++ nova-2015.1.2/nova/db/sqlalchemy/utils.py	2016-07-29 13:54:14.407369463 -0600
+@@ -13,6 +13,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from oslo_db import exception as db_exc
+ from oslo_db.sqlalchemy import utils as oslodbutils
+ from oslo_log import log as logging
+@@ -27,6 +28,7 @@ from nova.db.sqlalchemy import api as db
+ from nova import exception
+ from nova.i18n import _, _LE
+ 
++CONF = cfg.CONF
+ 
+ LOG = logging.getLogger(__name__)
+ 
+@@ -120,7 +122,7 @@ def create_shadow_table(migrate_engine,
+ 
+     shadow_table_name = db._SHADOW_TABLE_PREFIX + table.name
+     shadow_table = Table(shadow_table_name, meta, *columns,
+-                         mysql_engine='InnoDB')
++                         mysql_engine=CONF.database.mysql_storage_engine)
+     try:
+         shadow_table.create()
+         return shadow_table
+--- nova-2015.1.2/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/002_instance_mapping.py.orig	2016-07-29 13:51:47.583967956 -0600
++++ nova-2015.1.2/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/002_instance_mapping.py	2016-07-29 13:54:43.606798707 -0600
+@@ -12,6 +12,7 @@
+ 
+ from migrate.changeset.constraint import ForeignKeyConstraint
+ from migrate import UniqueConstraint
++from oslo_config import cfg
+ from sqlalchemy import Column
+ from sqlalchemy import DateTime
+ from sqlalchemy import Index
+@@ -20,6 +21,7 @@ from sqlalchemy import MetaData
+ from sqlalchemy import String
+ from sqlalchemy import Table
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -39,7 +41,7 @@ def upgrade(migrate_engine):
+         Index('project_id_idx', 'project_id'),
+         ForeignKeyConstraint(columns=['cell_id'],
+             refcolumns=[cell_mappings.c.id]),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+     instance_mappings.create(checkfirst=True)
+--- nova-2015.1.2/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/001_cell_mapping.py.orig	2016-07-29 13:51:54.363393063 -0600
++++ nova-2015.1.2/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/001_cell_mapping.py	2016-07-29 13:55:04.323468924 -0600
+@@ -11,6 +11,7 @@
+ #    under the License.
+ 
+ from migrate import UniqueConstraint
++from oslo_config import cfg
+ from sqlalchemy import Column
+ from sqlalchemy import DateTime
+ from sqlalchemy import Index
+@@ -20,6 +21,7 @@ from sqlalchemy import String
+ from sqlalchemy import Table
+ from sqlalchemy import Text
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -35,7 +37,7 @@ def upgrade(migrate_engine):
+         Column('database_connection', Text()),
+         UniqueConstraint('uuid', name='uniq_cell_mappings0uuid'),
+         Index('uuid_idx', 'uuid'),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+--- nova-2015.1.2/nova/db/sqlalchemy/migrate_repo/versions/252_add_instance_extra_table.py.orig	2016-07-29 13:52:02.695258383 -0600
++++ nova-2015.1.2/nova/db/sqlalchemy/migrate_repo/versions/252_add_instance_extra_table.py	2016-07-29 13:55:22.831394957 -0600
+@@ -12,6 +12,7 @@
+ 
+ 
+ from migrate import ForeignKeyConstraint
++from oslo_config import cfg
+ from sqlalchemy import Column
+ from sqlalchemy import DateTime
+ from sqlalchemy import Index
+@@ -21,6 +22,7 @@ from sqlalchemy import String
+ from sqlalchemy import Table
+ from sqlalchemy import Text
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -42,7 +44,7 @@ def upgrade(migrate_engine):
+             continue
+         _columns = tuple([Column(*args, **kwargs)
+                           for args, kwargs in columns])
+-        table = Table(basename, meta, *_columns, mysql_engine='InnoDB',
++        table = Table(basename, meta, *_columns, mysql_engine=CONF.database.mysql_storage_engine,
+                       mysql_charset='utf8')
+         table.create()
+ 
+--- nova-2015.1.2/nova/db/sqlalchemy/migrate_repo/versions/267_instance_uuid_non_nullable.py.orig	2016-07-29 13:52:09.293242604 -0600
++++ nova-2015.1.2/nova/db/sqlalchemy/migrate_repo/versions/267_instance_uuid_non_nullable.py	2016-07-29 13:55:48.275094037 -0600
+@@ -13,6 +13,7 @@
+ #    under the License.
+ 
+ from migrate import UniqueConstraint
++from oslo_config import cfg
+ from oslo_db.sqlalchemy import utils
+ from oslo_log import log as logging
+ from sqlalchemy import MetaData
+@@ -23,6 +24,8 @@ from nova.i18n import _
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
++
+ UC_NAME = 'uniq_instances0uuid'
+ 
+ 
+@@ -90,6 +93,12 @@ def process_null_records(meta, scan=True
+ 
+ 
+ def upgrade(migrate_engine):
++
++    # MySQL Cluster, a.k.a. NDB, has non-NULL records from the beginning.
++    # If we are using NDB, we will return without migrating as it is not required.
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        return
++
+     # NOTE(mriedem): We're going to load up all of the tables so we can find
+     # any with an instance_uuid column since those may be foreign keys back
+     # to the instances table and we want to cleanup those records first. We
+--- nova-2015.1.2/nova/db/sqlalchemy/migrate_repo/versions/250_remove_instance_groups_metadata.py.orig	2016-07-29 13:52:16.483979825 -0600
++++ nova-2015.1.2/nova/db/sqlalchemy/migrate_repo/versions/250_remove_instance_groups_metadata.py	2016-07-29 13:56:16.551643868 -0600
+@@ -13,10 +13,11 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
+-
++from oslo_config import cfg
+ from sqlalchemy import MetaData, Table, Column, DateTime, Integer, String, \
+     ForeignKey
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     """Remove the instance_group_metadata table."""
+@@ -49,7 +50,7 @@ def downgrade(migrate_engine):
+             Column('value', String(length=255)),
+             Column('group_id', Integer, ForeignKey('instance_groups.id'),
+                    nullable=False),
+-            mysql_engine='InnoDB',
++            mysql_engine=CONF.database.mysql_storage_engine,
+             mysql_charset='utf8',
+             )
+         group_metadata.create()
+@@ -65,7 +66,7 @@ def downgrade(migrate_engine):
+             Column('group_id', Integer,
+                    ForeignKey('shadow_instance_groups.id'),
+                    nullable=False),
+-            mysql_engine='InnoDB',
++            mysql_engine=CONF.database.mysql_storage_engine,
+             mysql_charset='utf8',
+             )
+         shadow_group_metadata.create()
+--- nova-2015.1.2/nova/db/sqlalchemy/migrate_repo/versions/216_havana.py.orig	2016-07-29 13:52:30.458310285 -0600
++++ nova-2015.1.2/nova/db/sqlalchemy/migrate_repo/versions/216_havana.py	2016-07-29 14:00:50.939986347 -0600
+@@ -14,6 +14,7 @@
+ 
+ from migrate.changeset import UniqueConstraint
+ from migrate import ForeignKeyConstraint
++from oslo_config import cfg
+ from oslo_log import log as logging
+ from sqlalchemy import Boolean, BigInteger, Column, DateTime, Enum, Float
+ from sqlalchemy import dialects
+@@ -25,6 +26,13 @@ from nova.i18n import _LE
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
++
++if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++    db_string_length = 128
++else:
++    db_string_length = 255
++
+ 
+ # Note on the autoincrement flag: this is defaulted for primary key columns
+ # of integral type, so is no longer set explicitly in such cases.
+@@ -76,7 +84,7 @@ def _create_shadow_tables(migrate_engine
+ 
+         shadow_table_name = 'shadow_' + table_name
+         shadow_table = Table(shadow_table_name, meta, *columns,
+-                             mysql_engine='InnoDB')
++                             mysql_engine=CONF.database.mysql_storage_engine)
+         try:
+             shadow_table.create()
+         except Exception:
+@@ -167,7 +175,7 @@ def _create_dump_tables(migrate_engine):
+             else:
+                 columns.append(column.copy())
+         table_dump = Table(dump_table_name, meta, *columns,
+-                           mysql_engine='InnoDB')
++                           mysql_engine=CONF.database.mysql_storage_engine)
+         table_dump.create()
+ 
+ 
+@@ -180,14 +188,14 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('hypervisor', String(length=255)),
+-        Column('os', String(length=255)),
+-        Column('architecture', String(length=255)),
+-        Column('version', String(length=255)),
+-        Column('url', String(length=255)),
+-        Column('md5hash', String(length=255)),
++        Column('hypervisor', String(length=db_string_length)),
++        Column('os', String(length=db_string_length)),
++        Column('architecture', String(length=db_string_length)),
++        Column('version', String(length=db_string_length)),
++        Column('url', String(length=db_string_length)),
++        Column('md5hash', String(length=db_string_length)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -196,11 +204,11 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('host', String(length=255)),
++        Column('host', String(length=db_string_length)),
+         Column('aggregate_id', Integer, ForeignKey('aggregates.id'),
+               nullable=False),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -211,10 +219,10 @@ def upgrade(migrate_engine):
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('aggregate_id', Integer, ForeignKey('aggregates.id'),
+               nullable=False),
+-        Column('key', String(length=255), nullable=False),
+-        Column('value', String(length=255), nullable=False),
++        Column('key', String(length=db_string_length), nullable=False),
++        Column('value', String(length=db_string_length), nullable=False),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -223,9 +231,9 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('name', String(length=255)),
++        Column('name', String(length=db_string_length)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -234,7 +242,7 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('device_name', String(length=255), nullable=True),
++        Column('device_name', String(length=db_string_length), nullable=True),
+         Column('delete_on_termination', Boolean),
+         Column('snapshot_id', String(length=36), nullable=True),
+         Column('volume_id', String(length=36), nullable=True),
+@@ -243,14 +251,14 @@ def upgrade(migrate_engine):
+         Column('connection_info', MediumText()),
+         Column('instance_uuid', String(length=36)),
+         Column('deleted', Integer),
+-        Column('source_type', String(length=255), nullable=True),
+-        Column('destination_type', String(length=255), nullable=True),
+-        Column('guest_format', String(length=255), nullable=True),
+-        Column('device_type', String(length=255), nullable=True),
+-        Column('disk_bus', String(length=255), nullable=True),
++        Column('source_type', String(length=db_string_length), nullable=True),
++        Column('destination_type', String(length=db_string_length), nullable=True),
++        Column('guest_format', String(length=db_string_length), nullable=True),
++        Column('device_type', String(length=db_string_length), nullable=True),
++        Column('disk_bus', String(length=db_string_length), nullable=True),
+         Column('boot_index', Integer),
+         Column('image_id', String(length=36), nullable=True),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -263,12 +271,12 @@ def upgrade(migrate_engine):
+         Column('last_refreshed', DateTime),
+         Column('bw_in', BigInteger),
+         Column('bw_out', BigInteger),
+-        Column('mac', String(length=255)),
++        Column('mac', String(length=db_string_length)),
+         Column('uuid', String(length=36)),
+         Column('last_ctr_in', BigInteger()),
+         Column('last_ctr_out', BigInteger()),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -277,14 +285,14 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('api_url', String(length=255)),
++        Column('api_url', String(length=db_string_length)),
+         Column('weight_offset', Float),
+         Column('weight_scale', Float),
+-        Column('name', String(length=255)),
++        Column('name', String(length=db_string_length)),
+         Column('is_parent', Boolean),
+         Column('deleted', Integer),
+-        Column('transport_url', String(length=255), nullable=False),
+-        mysql_engine='InnoDB',
++        Column('transport_url', String(length=db_string_length), nullable=False),
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -293,11 +301,11 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('user_id', String(length=255)),
+-        Column('project_id', String(length=255)),
+-        Column('file_name', String(length=255)),
++        Column('user_id', String(length=db_string_length)),
++        Column('project_id', String(length=db_string_length)),
++        Column('file_name', String(length=db_string_length)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -307,10 +315,10 @@ def upgrade(migrate_engine):
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('compute_node_id', Integer, nullable=False),
+-        Column('key', String(length=255), nullable=False),
+-        Column('value', String(length=255)),
++        Column('key', String(length=db_string_length), nullable=False),
++        Column('value', String(length=db_string_length)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -334,12 +342,12 @@ def upgrade(migrate_engine):
+         Column('free_disk_gb', Integer),
+         Column('current_workload', Integer),
+         Column('running_vms', Integer),
+-        Column('hypervisor_hostname', String(length=255)),
++        Column('hypervisor_hostname', String(length=db_string_length)),
+         Column('deleted', Integer),
+         Column('host_ip', InetSmall()),
+         Column('supported_instances', Text),
+         Column('pci_stats', Text, nullable=True),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -349,14 +357,14 @@ def upgrade(migrate_engine):
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('address', InetSmall()),
+-        Column('username', String(length=255)),
+-        Column('password', String(length=255)),
+-        Column('console_type', String(length=255)),
+-        Column('public_hostname', String(length=255)),
+-        Column('host', String(length=255)),
+-        Column('compute_host', String(length=255)),
++        Column('username', String(length=db_string_length)),
++        Column('password', String(length=db_string_length)),
++        Column('console_type', String(length=db_string_length)),
++        Column('public_hostname', String(length=db_string_length)),
++        Column('host', String(length=db_string_length)),
++        Column('compute_host', String(length=db_string_length)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -365,15 +373,15 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('instance_name', String(length=255)),
+-        Column('password', String(length=255)),
++        Column('instance_name', String(length=db_string_length)),
++        Column('password', String(length=db_string_length)),
+         Column('port', Integer),
+         Column('pool_id', Integer, ForeignKey('console_pools.id')),
+         Column('instance_uuid', String(length=36),
+                ForeignKey('instances.uuid',
+                           name='consoles_instance_uuid_fkey')),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -382,11 +390,11 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('deleted', Boolean),
+-        Column('domain', String(length=255), primary_key=True, nullable=False),
+-        Column('scope', String(length=255)),
+-        Column('availability_zone', String(length=255)),
+-        Column('project_id', String(length=255)),
+-        mysql_engine='InnoDB',
++        Column('domain', String(length=db_string_length), primary_key=True, nullable=False),
++        Column('scope', String(length=db_string_length)),
++        Column('availability_zone', String(length=db_string_length)),
++        Column('project_id', String(length=db_string_length)),
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -401,10 +409,10 @@ def upgrade(migrate_engine):
+         Column('leased', Boolean),
+         Column('reserved', Boolean),
+         Column('virtual_interface_id', Integer),
+-        Column('host', String(length=255)),
++        Column('host', String(length=db_string_length)),
+         Column('instance_uuid', String(length=36)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -415,13 +423,13 @@ def upgrade(migrate_engine):
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('address', InetSmall()),
+         Column('fixed_ip_id', Integer),
+-        Column('project_id', String(length=255)),
+-        Column('host', String(length=255)),
++        Column('project_id', String(length=db_string_length)),
++        Column('host', String(length=db_string_length)),
+         Column('auto_assigned', Boolean),
+-        Column('pool', String(length=255)),
+-        Column('interface', String(length=255)),
++        Column('pool', String(length=db_string_length)),
++        Column('interface', String(length=db_string_length)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -436,7 +444,7 @@ def upgrade(migrate_engine):
+         Column('details', MediumText()),
+         Column('host', String(length=255)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -447,7 +455,7 @@ def upgrade(migrate_engine):
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('uuid', String(36), nullable=False),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -459,7 +467,7 @@ def upgrade(migrate_engine):
+         Column('network_info', MediumText()),
+         Column('instance_uuid', String(length=36), nullable=False),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -469,13 +477,13 @@ def upgrade(migrate_engine):
+         Column('deleted_at', DateTime),
+         Column('deleted', Integer),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('user_id', String(length=255)),
+-        Column('project_id', String(length=255)),
++        Column('user_id', String(length=db_string_length)),
++        Column('project_id', String(length=db_string_length)),
+         Column('uuid', String(length=36), nullable=False),
+-        Column('name', String(length=255)),
++        Column('name', String(length=db_string_length)),
+         UniqueConstraint('uuid', 'deleted',
+                          name='uniq_instance_groups0uuid0deleted'),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8',
+     )
+ 
+@@ -485,11 +493,11 @@ def upgrade(migrate_engine):
+         Column('deleted_at', DateTime),
+         Column('deleted', Integer),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('key', String(length=255)),
+-        Column('value', String(length=255)),
++        Column('key', String(length=db_string_length)),
++        Column('value', String(length=db_string_length)),
+         Column('group_id', Integer, ForeignKey('instance_groups.id'),
+                nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8',
+     )
+ 
+@@ -499,10 +507,10 @@ def upgrade(migrate_engine):
+         Column('deleted_at', DateTime),
+         Column('deleted', Integer),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('policy', String(length=255)),
++        Column('policy', String(length=db_string_length)),
+         Column('group_id', Integer, ForeignKey('instance_groups.id'),
+                nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8',
+     )
+ 
+@@ -512,10 +520,10 @@ def upgrade(migrate_engine):
+         Column('deleted_at', DateTime),
+         Column('deleted', Integer),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('instance_id', String(length=255)),
++        Column('instance_id', String(length=db_string_length)),
+         Column('group_id', Integer, ForeignKey('instance_groups.id'),
+                nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8',
+     )
+ 
+@@ -528,7 +536,7 @@ def upgrade(migrate_engine):
+         Column('value', String(length=255)),
+         Column('instance_uuid', String(length=36), nullable=True),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -541,7 +549,7 @@ def upgrade(migrate_engine):
+         Column('key', String(length=255), nullable=False),
+         Column('value', String(length=255)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -555,7 +563,7 @@ def upgrade(migrate_engine):
+         Column('key', String(length=255)),
+         Column('value', String(length=255)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -565,9 +573,9 @@ def upgrade(migrate_engine):
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('instance_type_id', Integer, nullable=False),
+-        Column('project_id', String(length=255)),
++        Column('project_id', String(length=db_string_length)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -575,20 +583,20 @@ def upgrade(migrate_engine):
+         Column('created_at', DateTime),
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+-        Column('name', String(length=255)),
++        Column('name', String(length=db_string_length)),
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('memory_mb', Integer, nullable=False),
+         Column('vcpus', Integer, nullable=False),
+         Column('swap', Integer, nullable=False),
+         Column('vcpu_weight', Integer),
+-        Column('flavorid', String(length=255)),
++        Column('flavorid', String(length=db_string_length)),
+         Column('rxtx_factor', Float),
+         Column('root_gb', Integer),
+         Column('ephemeral_gb', Integer),
+         Column('disabled', Boolean),
+         Column('is_public', Boolean),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -599,54 +607,54 @@ def upgrade(migrate_engine):
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('internal_id', Integer),
+-        Column('user_id', String(length=255)),
+-        Column('project_id', String(length=255)),
+-        Column('image_ref', String(length=255)),
+-        Column('kernel_id', String(length=255)),
+-        Column('ramdisk_id', String(length=255)),
++        Column('user_id', String(length=db_string_length)),
++        Column('project_id', String(length=db_string_length)),
++        Column('image_ref', String(length=db_string_length)),
++        Column('kernel_id', String(length=db_string_length)),
++        Column('ramdisk_id', String(length=db_string_length)),
+         Column('launch_index', Integer),
+-        Column('key_name', String(length=255)),
++        Column('key_name', String(length=db_string_length)),
+         Column('key_data', MediumText()),
+         Column('power_state', Integer),
+-        Column('vm_state', String(length=255)),
++        Column('vm_state', String(length=db_string_length)),
+         Column('memory_mb', Integer),
+         Column('vcpus', Integer),
+-        Column('hostname', String(length=255)),
+-        Column('host', String(length=255)),
++        Column('hostname', String(length=db_string_length)),
++        Column('host', String(length=db_string_length)),
+         Column('user_data', MediumText()),
+-        Column('reservation_id', String(length=255)),
++        Column('reservation_id', String(length=db_string_length)),
+         Column('scheduled_at', DateTime),
+         Column('launched_at', DateTime),
+         Column('terminated_at', DateTime),
+-        Column('display_name', String(length=255)),
+-        Column('display_description', String(length=255)),
+-        Column('availability_zone', String(length=255)),
++        Column('display_name', String(length=db_string_length)),
++        Column('display_description', String(length=db_string_length)),
++        Column('availability_zone', String(length=db_string_length)),
+         Column('locked', Boolean),
+-        Column('os_type', String(length=255)),
++        Column('os_type', String(length=db_string_length)),
+         Column('launched_on', MediumText()),
+         Column('instance_type_id', Integer),
+-        Column('vm_mode', String(length=255)),
+-        Column('uuid', String(length=36)),
+-        Column('architecture', String(length=255)),
+-        Column('root_device_name', String(length=255)),
++        Column('vm_mode', String(length=db_string_length)),
++        Column('uuid', String(length=36), nullable=False),
++        Column('architecture', String(length=db_string_length)),
++        Column('root_device_name', String(length=db_string_length)),
+         Column('access_ip_v4', InetSmall()),
+         Column('access_ip_v6', InetSmall()),
+-        Column('config_drive', String(length=255)),
+-        Column('task_state', String(length=255)),
+-        Column('default_ephemeral_device', String(length=255)),
+-        Column('default_swap_device', String(length=255)),
++        Column('config_drive', String(length=db_string_length)),
++        Column('task_state', String(length=db_string_length)),
++        Column('default_ephemeral_device', String(length=db_string_length)),
++        Column('default_swap_device', String(length=db_string_length)),
+         Column('progress', Integer),
+         Column('auto_disk_config', Boolean),
+         Column('shutdown_terminate', Boolean),
+         Column('disable_terminate', Boolean),
+         Column('root_gb', Integer),
+         Column('ephemeral_gb', Integer),
+-        Column('cell_name', String(length=255)),
+-        Column('node', String(length=255)),
++        Column('cell_name', String(length=db_string_length)),
++        Column('node', String(length=db_string_length)),
+         Column('deleted', Integer),
+         Column('locked_by', inst_lock_enum),
+         Column('cleaned', Integer, default=0),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -655,16 +663,16 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('action', String(length=255)),
++        Column('action', String(length=db_string_length)),
+         Column('instance_uuid', String(length=36)),
+-        Column('request_id', String(length=255)),
+-        Column('user_id', String(length=255)),
+-        Column('project_id', String(length=255)),
++        Column('request_id', String(length=db_string_length)),
++        Column('user_id', String(length=db_string_length)),
++        Column('project_id', String(length=db_string_length)),
+         Column('start_time', DateTime),
+         Column('finish_time', DateTime),
+-        Column('message', String(length=255)),
++        Column('message', String(length=db_string_length)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8',
+     )
+ 
+@@ -673,14 +681,14 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('event', String(length=255)),
++        Column('event', String(length=db_string_length)),
+         Column('action_id', Integer, ForeignKey('instance_actions.id')),
+         Column('start_time', DateTime),
+         Column('finish_time', DateTime),
+-        Column('result', String(length=255)),
++        Column('result', String(length=db_string_length)),
+         Column('traceback', Text),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8',
+     )
+ 
+@@ -690,10 +698,10 @@ def upgrade(migrate_engine):
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('target_num', Integer),
+-        Column('host', String(length=255)),
++        Column('host', String(length=db_string_length)),
+         Column('volume_id', String(length=36), nullable=True),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -702,12 +710,12 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('name', String(length=255)),
+-        Column('user_id', String(length=255)),
+-        Column('fingerprint', String(length=255)),
++        Column('name', String(length=db_string_length)),
++        Column('user_id', String(length=db_string_length)),
++        Column('fingerprint', String(length=db_string_length)),
+         Column('public_key', MediumText()),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -716,17 +724,17 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('source_compute', String(length=255)),
+-        Column('dest_compute', String(length=255)),
+-        Column('dest_host', String(length=255)),
+-        Column('status', String(length=255)),
++        Column('source_compute', String(length=db_string_length)),
++        Column('dest_compute', String(length=db_string_length)),
++        Column('dest_host', String(length=db_string_length)),
++        Column('status', String(length=db_string_length)),
+         Column('instance_uuid', String(length=36)),
+         Column('old_instance_type_id', Integer),
+         Column('new_instance_type_id', Integer),
+-        Column('source_node', String(length=255)),
+-        Column('dest_node', String(length=255)),
++        Column('source_node', String(length=db_string_length)),
++        Column('dest_node', String(length=db_string_length)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -738,7 +746,7 @@ def upgrade(migrate_engine):
+         Column('injected', Boolean),
+         Column('cidr', Inet()),
+         Column('netmask', InetSmall()),
+-        Column('bridge', String(length=255)),
++        Column('bridge', String(length=db_string_length)),
+         Column('gateway', InetSmall()),
+         Column('broadcast', InetSmall()),
+         Column('dns1', InetSmall()),
+@@ -747,20 +755,20 @@ def upgrade(migrate_engine):
+         Column('vpn_public_port', Integer),
+         Column('vpn_private_address', InetSmall()),
+         Column('dhcp_start', InetSmall()),
+-        Column('project_id', String(length=255)),
+-        Column('host', String(length=255)),
++        Column('project_id', String(length=db_string_length)),
++        Column('host', String(length=db_string_length)),
+         Column('cidr_v6', Inet()),
+         Column('gateway_v6', InetSmall()),
+-        Column('label', String(length=255)),
++        Column('label', String(length=db_string_length)),
+         Column('netmask_v6', InetSmall()),
+-        Column('bridge_interface', String(length=255)),
++        Column('bridge_interface', String(length=db_string_length)),
+         Column('multi_host', Boolean),
+         Column('dns2', InetSmall()),
+         Column('uuid', String(length=36)),
+         Column('priority', Integer),
+         Column('rxtx_base', Integer),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -776,8 +784,8 @@ def upgrade(migrate_engine):
+         Column('product_id', String(4)),
+         Column('vendor_id', String(4)),
+         Column('dev_type', String(8)),
+-        Column('dev_id', String(255)),
+-        Column('label', String(255), nullable=False),
++        Column('dev_id', String(db_string_length)),
++        Column('label', String(db_string_length), nullable=False),
+         Column('status', String(36), nullable=False),
+         Column('extra_info', Text, nullable=True),
+         Column('instance_uuid', String(36), nullable=True),
+@@ -788,7 +796,7 @@ def upgrade(migrate_engine):
+         UniqueConstraint('compute_node_id',
+                         'address', 'deleted',
+                         name=pci_devices_uc_name),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     provider_fw_rules = Table('provider_fw_rules', meta,
+@@ -801,7 +809,7 @@ def upgrade(migrate_engine):
+         Column('to_port', Integer),
+         Column('cidr', Inet()),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -810,11 +818,11 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('class_name', String(length=255)),
+-        Column('resource', String(length=255)),
++        Column('class_name', String(length=db_string_length)),
++        Column('resource', String(length=db_string_length)),
+         Column('hard_limit', Integer),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -823,14 +831,14 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('project_id', String(length=255)),
+-        Column('resource', String(length=255)),
++        Column('project_id', String(length=db_string_length)),
++        Column('resource', String(length=db_string_length)),
+         Column('in_use', Integer, nullable=False),
+         Column('reserved', Integer, nullable=False),
+         Column('until_refresh', Integer),
+         Column('deleted', Integer),
+-        Column('user_id', String(length=255)),
+-        mysql_engine='InnoDB',
++        Column('user_id', String(length=db_string_length)),
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -839,11 +847,11 @@ def upgrade(migrate_engine):
+         Column('created_at', DateTime),
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+-        Column('project_id', String(length=255)),
+-        Column('resource', String(length=255), nullable=False),
++        Column('project_id', String(length=db_string_length)),
++        Column('resource', String(length=db_string_length), nullable=False),
+         Column('hard_limit', Integer),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -856,18 +864,18 @@ def upgrade(migrate_engine):
+                         Column('deleted_at', DateTime),
+                         Column('deleted', Integer),
+                         Column('user_id',
+-                               String(length=255),
++                               String(length=db_string_length),
+                                nullable=False),
+                         Column('project_id',
+-                               String(length=255),
++                               String(length=db_string_length),
+                                nullable=False),
+                         Column('resource',
+-                               String(length=255),
++                               String(length=db_string_length),
+                                nullable=False),
+                         Column('hard_limit', Integer, nullable=True),
+                         UniqueConstraint('user_id', 'project_id', 'resource',
+                                          'deleted', name=uniq_name),
+-                        mysql_engine='InnoDB',
++                        mysql_engine=CONF.database.mysql_storage_engine,
+                         mysql_charset='utf8',
+                         )
+ 
+@@ -878,13 +886,13 @@ def upgrade(migrate_engine):
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('uuid', String(length=36), nullable=False),
+         Column('usage_id', Integer, nullable=False),
+-        Column('project_id', String(length=255)),
+-        Column('resource', String(length=255)),
++        Column('project_id', String(length=db_string_length)),
++        Column('resource', String(length=db_string_length)),
+         Column('delta', Integer, nullable=False),
+         Column('expire', DateTime),
+         Column('deleted', Integer),
+-        Column('user_id', String(length=255)),
+-        mysql_engine='InnoDB',
++        Column('user_id', String(length=db_string_length)),
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -895,7 +903,7 @@ def upgrade(migrate_engine):
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('uuid', String(length=36), nullable=False),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -908,7 +916,7 @@ def upgrade(migrate_engine):
+         Column('security_group_id', Integer),
+         Column('instance_uuid', String(length=36)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -918,13 +926,13 @@ def upgrade(migrate_engine):
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('parent_group_id', Integer, ForeignKey('security_groups.id')),
+-        Column('protocol', String(length=255)),
++        Column('protocol', String(length=db_string_length)),
+         Column('from_port', Integer),
+         Column('to_port', Integer),
+         Column('cidr', Inet()),
+         Column('group_id', Integer, ForeignKey('security_groups.id')),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -933,12 +941,12 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('name', String(length=255)),
+-        Column('description', String(length=255)),
+-        Column('user_id', String(length=255)),
+-        Column('project_id', String(length=255)),
++        Column('name', String(length=db_string_length)),
++        Column('description', String(length=db_string_length)),
++        Column('user_id', String(length=db_string_length)),
++        Column('project_id', String(length=db_string_length)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -952,7 +960,7 @@ def upgrade(migrate_engine):
+         Column('from_port', Integer),
+         Column('to_port', Integer),
+         Column('cidr', Inet()),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8',
+     )
+ 
+@@ -961,14 +969,14 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('host', String(length=255)),
+-        Column('binary', String(length=255)),
+-        Column('topic', String(length=255)),
++        Column('host', String(length=db_string_length)),
++        Column('binary', String(length=db_string_length)),
++        Column('topic', String(length=db_string_length)),
+         Column('report_count', Integer, nullable=False),
+         Column('disabled', Boolean),
+         Column('deleted', Integer),
+-        Column('disabled_reason', String(length=255)),
+-        mysql_engine='InnoDB',
++        Column('disabled_reason', String(length=db_string_length)),
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -979,7 +987,7 @@ def upgrade(migrate_engine):
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('uuid', String(length=36), nullable=False),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -989,16 +997,16 @@ def upgrade(migrate_engine):
+         Column('deleted_at', DateTime),
+         Column('id', String(length=36), primary_key=True, nullable=False),
+         Column('volume_id', String(length=36), nullable=False),
+-        Column('user_id', String(length=255)),
+-        Column('project_id', String(length=255)),
+-        Column('status', String(length=255)),
+-        Column('progress', String(length=255)),
++        Column('user_id', String(length=db_string_length)),
++        Column('project_id', String(length=db_string_length)),
++        Column('status', String(length=db_string_length)),
++        Column('progress', String(length=db_string_length)),
+         Column('volume_size', Integer),
+         Column('scheduled_at', DateTime),
+-        Column('display_name', String(length=255)),
+-        Column('display_description', String(length=255)),
++        Column('display_name', String(length=db_string_length)),
++        Column('display_description', String(length=db_string_length)),
+         Column('deleted', String(length=36)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -1007,16 +1015,16 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('task_name', String(length=255), nullable=False),
+-        Column('state', String(length=255), nullable=False),
+-        Column('host', String(length=255), nullable=False),
++        Column('task_name', String(length=db_string_length), nullable=False),
++        Column('state', String(length=db_string_length), nullable=False),
++        Column('host', String(length=db_string_length), nullable=False),
+         Column('period_beginning', DateTime, nullable=False),
+         Column('period_ending', DateTime, nullable=False),
+-        Column('message', String(length=255), nullable=False),
++        Column('message', String(length=db_string_length), nullable=False),
+         Column('task_items', Integer),
+         Column('errors', Integer),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -1025,12 +1033,12 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', Integer, primary_key=True, nullable=False),
+-        Column('address', String(length=255)),
++        Column('address', String(length=db_string_length)),
+         Column('network_id', Integer),
+         Column('uuid', String(length=36)),
+         Column('instance_uuid', String(length=36), nullable=True),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -1041,7 +1049,7 @@ def upgrade(migrate_engine):
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('uuid', String(length=36), nullable=False),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -1050,20 +1058,20 @@ def upgrade(migrate_engine):
+         Column('updated_at', DateTime),
+         Column('deleted_at', DateTime),
+         Column('id', String(length=36), primary_key=True, nullable=False),
+-        Column('ec2_id', String(length=255)),
+-        Column('user_id', String(length=255)),
+-        Column('project_id', String(length=255)),
+-        Column('host', String(length=255)),
++        Column('ec2_id', String(length=db_string_length)),
++        Column('user_id', String(length=db_string_length)),
++        Column('project_id', String(length=db_string_length)),
++        Column('host', String(length=db_string_length)),
+         Column('size', Integer),
+-        Column('availability_zone', String(length=255)),
+-        Column('mountpoint', String(length=255)),
+-        Column('status', String(length=255)),
+-        Column('attach_status', String(length=255)),
++        Column('availability_zone', String(length=db_string_length)),
++        Column('mountpoint', String(length=db_string_length)),
++        Column('status', String(length=db_string_length)),
++        Column('attach_status', String(length=db_string_length)),
+         Column('scheduled_at', DateTime),
+         Column('launched_at', DateTime),
+         Column('terminated_at', DateTime),
+-        Column('display_name', String(length=255)),
+-        Column('display_description', String(length=255)),
++        Column('display_name', String(length=db_string_length)),
++        Column('display_description', String(length=db_string_length)),
+         Column('provider_location', String(length=256)),
+         Column('provider_auth', String(length=256)),
+         Column('snapshot_id', String(length=36)),
+@@ -1071,7 +1079,7 @@ def upgrade(migrate_engine):
+         Column('instance_uuid', String(length=36)),
+         Column('attach_time', DateTime),
+         Column('deleted', String(length=36)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -1095,8 +1103,8 @@ def upgrade(migrate_engine):
+             Column("instance_uuid", String(length=36)),
+             Column("project_id", String(length=36)),
+             Column("user_id", String(length=36)),
+-            Column("availability_zone", String(length=255)),
+-            mysql_engine='InnoDB',
++            Column("availability_zone", String(length=db_string_length)),
++            mysql_engine=CONF.database.mysql_storage_engine,
+             mysql_charset='utf8'
+     )
+ 
+@@ -1223,15 +1231,19 @@ def upgrade(migrate_engine):
+                      table=aggregate_hosts,
+                      name=uc_name).create()
+ 
+-    uc_name = 'uniq_aggregate_metadata0aggregate_id0key0deleted'
+-    UniqueConstraint('aggregate_id', 'key', 'deleted',
+-                     table=aggregate_metadata,
+-                     name=uc_name).create()
+-
+-    uc_name = 'uniq_instance_type_extra_specs0instance_type_id0key0deleted'
+-    UniqueConstraint('instance_type_id', 'key', 'deleted',
+-                     table=instance_type_extra_specs,
+-                     name=uc_name).create()
++    # Constraint does not work in MySQL Cluster, a.k.a NDB.
++    if CONF.database.mysql_storage_engine != "NDBCLUSTER":
++        uc_name = 'uniq_aggregate_metadata0aggregate_id0key0deleted'
++        UniqueConstraint('aggregate_id', 'key', 'deleted',
++                         table=aggregate_metadata,
++                         name=uc_name).create()
++
++    # Constraint does not work in MySQL Cluster, a.k.a NDB.
++    if CONF.database.mysql_storage_engine != "NDBCLUSTER":
++        uc_name = 'uniq_instance_type_extra_specs0instance_type_id0key0deleted'
++        UniqueConstraint('instance_type_id', 'key', 'deleted',
++                         table=instance_type_extra_specs,
++                         name=uc_name).create()
+ 
+     # created first (to preserve ordering for schema diffs)
+     mysql_pre_indexes = [
+--- nova-2015.1.2/nova/db/sqlalchemy/migrate_repo/versions/266_add_instance_tags.py.orig	2016-07-29 13:52:37.502198001 -0600
++++ nova-2015.1.2/nova/db/sqlalchemy/migrate_repo/versions/266_add_instance_tags.py	2016-07-29 13:57:00.720993583 -0600
+@@ -10,8 +10,10 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ import sqlalchemy as sa
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     meta = sa.MetaData(bind=migrate_engine)
+@@ -22,7 +24,7 @@ def upgrade(migrate_engine):
+                     sa.Column('tag', sa.Unicode(80), primary_key=True,
+                               nullable=False),
+                     sa.Index('tags_tag_idx', 'tag'),
+-                    mysql_engine='InnoDB',
++                    mysql_engine=CONF.database.mysql_storage_engine,
+                     mysql_charset='utf8')
+     tags.create()
+ 
+--- nova-2015.1.2/nova/db/sqlalchemy/migrate_repo/versions/233_add_stats_in_compute_nodes.py.orig	2016-07-29 13:52:44.501555489 -0600
++++ nova-2015.1.2/nova/db/sqlalchemy/migrate_repo/versions/233_add_stats_in_compute_nodes.py	2016-07-29 13:57:22.617030985 -0600
+@@ -14,6 +14,7 @@
+ #    under the License.
+ 
+ 
++from oslo_config import cfg
+ from oslo_utils import timeutils
+ from sqlalchemy import Column
+ from sqlalchemy import DateTime
+@@ -25,6 +26,7 @@ from sqlalchemy import String
+ from sqlalchemy import Table
+ from sqlalchemy import Text
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(engine):
+     meta = MetaData()
+@@ -73,7 +75,7 @@ def downgrade(engine):
+                 index=True),
+             Index('compute_node_stats_node_id_and_deleted_idx',
+                   'compute_node_id', 'deleted'),
+-            mysql_engine='InnoDB',
++            mysql_engine=CONF.database.mysql_storage_engine,
+             mysql_charset='utf8'
+     )
+     table.create()
+@@ -88,7 +90,7 @@ def downgrade(engine):
+             Column('key', String(255), nullable=False),
+             Column('value', String(255), nullable=True),
+             Column('compute_node_id', Integer),
+-            mysql_engine='InnoDB',
++            mysql_engine=CONF.database.mysql_storage_engine,
+             mysql_charset='utf8'
+     )
+     table.create()
+--- nova-2015.1.2/nova/db/sqlalchemy/migrate_repo/versions/249_remove_duplicate_index.py.orig	2016-07-29 13:52:51.444080181 -0600
++++ nova-2015.1.2/nova/db/sqlalchemy/migrate_repo/versions/249_remove_duplicate_index.py	2016-07-29 14:01:52.610985774 -0600
+@@ -13,10 +13,9 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
+-
++from migrate.changeset.constraint import ForeignKeyConstraint
+ from sqlalchemy import MetaData, Table
+ 
+-
+ INDEX_NAME = 'block_device_mapping_instance_uuid_virtual_name_device_name_idx'
+ 
+ 
+@@ -25,11 +24,20 @@ def upgrade(migrate_engine):
+ 
+     meta = MetaData(bind=migrate_engine)
+ 
++    # Remove the foreign key so that the index can be removed correctly
++    block_device_mapping = Table('block_device_mapping', meta, autoload=True)
++    instances = Table('instances', meta, autoload=True)
++    fkey = ForeignKeyConstraint(columns=[block_device_mapping.c.instance_uuid],
++                                refcolumns=[instances.c.uuid])
++    fkey.drop()
++
+     bdm = Table('block_device_mapping', meta, autoload=True)
+     for index in bdm.indexes:
+         if index.name == INDEX_NAME:
+             index.drop()
+ 
++    # Recreate foreign key
++    fkey.create()
+ 
+ def downgrade(migrate_engine):
+     # Unnecessary to re-add duplicate index when downgrading
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/python/oslo.db/patches/mysql_cluster_support.patch	Fri Jul 29 14:41:14 2016 -0600
@@ -0,0 +1,28 @@
+This patchset is for bug:
+
+23033470 - oslo.db needs a database option to support MySQL Cluster
+
+This fixes the following aspects of Oslo.db:
+1. Implementation of an oslo.db configuration parameter to specify the MySQL 
+   storage engine (mysql_storage_engine).
+
+This has not been committed upstream, but has been filed in launchpad:
+
+https://bugs.launchpad.net/oslo.db/+bug/1564110
+
+
+--- oslo.db-1.7.2/oslo_db/options.py.orig	2016-02-17 14:56:11.276310637 -0700
++++ oslo.db-1.7.2/oslo_db/options.py	2016-02-19 10:32:20.551188376 -0700
+@@ -50,6 +50,12 @@ database_opts = [
+                     'server-set SQL mode. To use whatever SQL mode '
+                     'is set by the server configuration, '
+                     'set this to no value. Example: mysql_sql_mode='),
++    cfg.StrOpt('mysql_storage_engine',
++               default='InnoDB',
++               help='This configures the MySQL storage engine. '
++               'This allows for OpenStack to support different storage engines '
++               'such as InnoDB, NDB, etc. For MySQL Cluster, set to NDBCLUSTER. '
++               'Example: mysql_storage_engine=NDBCLUSTER'),
+     cfg.IntOpt('idle_timeout',
+                default=3600,
+                deprecated_opts=[cfg.DeprecatedOpt('sql_idle_timeout',