24394524 MySQL Cluster support for Cinder must be ported to Mitaka
authorOctave Orgeron <octave.orgeron@oracle.com>
Thu, 08 Sep 2016 13:16:06 -0600
changeset 6866 4c1935f5ec9a
parent 6865 1cc50ab79b8c
child 6867 87f7fd05f888
24394524 MySQL Cluster support for Cinder must be ported to Mitaka 24394534 MySQL Cluster support for Glance must be ported to Mitaka 24394543 MySQL Cluster support for Heat must be ported to Mitaka 24394552 MySQL Cluster support for Ironic must be ported to Mitaka 24394567 MySQL Cluster support for Keystone must be ported to Mitaka 24394574 MySQL Cluster support for Neutron must be ported to Mitaka 24394587 MySQL Cluster support for Nova must be ported to Mitaka 24409419 MySQL Cluster support for oslo.db must be ported to Mitaka
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-glare.conf
components/openstack/glance/files/glance-manage.conf
components/openstack/glance/files/glance-registry.conf
components/openstack/glance/files/glance-scrubber.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	Thu Sep 08 12:41:54 2016 -0700
+++ b/components/openstack/cinder/files/cinder.conf	Thu Sep 08 13:16:06 2016 -0600
@@ -2885,6 +2885,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/cinder/patches/15-mysql_cluster_support.patch	Thu Sep 08 13:16:06 2016 -0600
@@ -0,0 +1,715 @@
+This patchset is for bug:
+
+24394524 Mitaka Cinder should 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-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/001_cinder_init.py.orig	2016-08-25 08:57:00.626583510 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/001_cinder_init.py	2016-08-25 09:53:31.239234646 -0700
+@@ -12,8 +12,17 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import Boolean, Column, DateTime, ForeignKey
++from sqlalchemy import dialects
+ from sqlalchemy import Integer, MetaData, String, Table
++from sqlalchemy import Text
++
++CONF = cfg.CONF
++
++
++def TinyText():
++    return Text().with_variant(dialects.mysql.TINYTEXT(), 'mysql')
+ 
+ 
+ def define_tables(meta):
+@@ -31,7 +40,7 @@ def define_tables(meta):
+         Column('instance_uuid', String(length=255)),
+         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,7 +56,7 @@ def define_tables(meta):
+         Column('report_count', Integer, nullable=False),
+         Column('disabled', Boolean),
+         Column('availability_zone', String(length=255)),
+-        mysql_engine='InnoDB'
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     sm_flavors = Table(
+@@ -59,7 +68,7 @@ def define_tables(meta):
+         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
+     )
+ 
+     sm_backend_config = Table(
+@@ -74,7 +83,7 @@ def define_tables(meta):
+         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
+     )
+ 
+     sm_volume = Table(
+@@ -90,7 +99,7 @@ def define_tables(meta):
+         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
+     )
+ 
+     snapshots = Table(
+@@ -109,7 +118,7 @@ def define_tables(meta):
+         Column('scheduled_at', DateTime),
+         Column('display_name', String(length=255)),
+         Column('display_description', String(length=255)),
+-        mysql_engine='InnoDB'
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     volume_types = Table(
+@@ -120,7 +129,7 @@ def define_tables(meta):
+         Column('deleted', Boolean),
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('name', String(length=255)),
+-        mysql_engine='InnoDB'
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     volume_metadata = Table(
+@@ -134,7 +143,7 @@ def define_tables(meta):
+                nullable=False),
+         Column('key', String(length=255)),
+         Column('value', String(length=255)),
+-        mysql_engine='InnoDB'
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     volume_type_extra_specs = Table(
+@@ -148,38 +157,69 @@ def define_tables(meta):
+                nullable=False),
+         Column('key', String(length=255)),
+         Column('value', String(length=255)),
+-        mysql_engine='InnoDB'
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+-    volumes = Table(
+-        'volumes', meta,
+-        Column('created_at', DateTime),
+-        Column('updated_at', DateTime),
+-        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('size', Integer),
+-        Column('availability_zone', String(length=255)),
+-        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('scheduled_at', DateTime),
+-        Column('launched_at', DateTime),
+-        Column('terminated_at', DateTime),
+-        Column('display_name', String(length=255)),
+-        Column('display_description', String(length=255)),
+-        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'
+-    )
++    if CONF.database.mysql_storage_engine == 'NDBCLUSTER':
++        volumes = Table(
++            'volumes', meta,
++            Column('created_at', DateTime),
++            Column('updated_at', DateTime),
++            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('size', Integer),
++            Column('availability_zone', TinyText()),
++            Column('instance_uuid', String(length=36)),
++            Column('mountpoint', TinyText()),
++            Column('attach_time', TinyText()),
++            Column('status', String(length=64)),
++            Column('attach_status', String(length=64)),
++            Column('scheduled_at', DateTime),
++            Column('launched_at', DateTime),
++            Column('terminated_at', DateTime),
++            Column('display_name', String(length=255)),
++            Column('display_description', TinyText()),
++            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=CONF.database.mysql_storage_engine
++        )
++    else:
++        volumes = Table(
++            'volumes', meta,
++            Column('created_at', DateTime),
++            Column('updated_at', DateTime),
++            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('size', Integer),
++            Column('availability_zone', String(length=255)),
++            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('scheduled_at', DateTime),
++            Column('launched_at', DateTime),
++            Column('terminated_at', DateTime),
++            Column('display_name', String(length=255)),
++            Column('display_description', String(length=255)),
++            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=CONF.database.mysql_storage_engine
++        )
+ 
+     quotas = Table(
+         'quotas', meta,
+@@ -191,7 +231,7 @@ def define_tables(meta):
+         Column('project_id', String(length=255)),
+         Column('resource', String(length=255), nullable=False),
+         Column('hard_limit', Integer),
+-        mysql_engine='InnoDB'
++        mysql_engine=CONF.database.mysql_storage_engine
+     )
+ 
+     iscsi_targets = Table(
+@@ -205,7 +245,7 @@ def define_tables(meta):
+         Column('host', String(length=255)),
+         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,
+@@ -255,4 +295,5 @@ 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))
+--- cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/002_quota_class.py.orig	2016-08-25 08:57:08.652633578 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/002_quota_class.py	2016-08-25 08:56:32.039341151 -0700
+@@ -12,9 +12,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import Boolean, Column, DateTime
+ from sqlalchemy import MetaData, Integer, String, Table, ForeignKey
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -34,7 +37,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',
+                           )
+ 
+@@ -55,7 +58,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',
+                          )
+ 
+@@ -82,7 +85,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-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/003_glance_metadata.py.orig	2016-08-25 08:57:16.312610448 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/003_glance_metadata.py	2016-08-25 08:56:32.040239306 -0700
+@@ -12,9 +12,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import Column, DateTime, Text, Boolean
+ from sqlalchemy import MetaData, Integer, String, Table, ForeignKey
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -26,11 +29,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',
+@@ -45,7 +48,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-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/008_add_backup.py.orig	2016-08-25 08:57:23.692681043 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/008_add_backup.py	2016-08-25 08:56:32.041089963 -0700
+@@ -13,9 +13,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import Boolean, Column, DateTime
+ from sqlalchemy import MetaData, Integer, String, Table
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -43,7 +46,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
+     )
+ 
+     backups.create()
+--- cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/009_add_snapshot_metadata_table.py.orig	2016-08-25 08:57:30.092571835 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/009_add_snapshot_metadata_table.py	2016-08-25 08:56:32.041930428 -0700
+@@ -10,9 +10,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import Boolean, Column, DateTime
+ from sqlalchemy import Integer, MetaData, String, Table, ForeignKey
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -32,7 +35,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
+     )
+ 
+     snapshot_metadata.create()
+--- cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/010_add_transfers_table.py.orig	2016-08-25 08:57:36.677754626 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/010_add_transfers_table.py	2016-08-25 08:56:32.042766768 -0700
+@@ -10,9 +10,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import Boolean, Column, DateTime
+ from sqlalchemy import MetaData, String, Table, ForeignKey
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -34,7 +37,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-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/017_add_encryption_information.py.orig	2016-08-25 08:57:43.340435246 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/017_add_encryption_information.py	2016-08-25 08:56:32.043630671 -0700
+@@ -13,9 +13,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import Column, ForeignKey, MetaData, Table
+ from sqlalchemy import Boolean, DateTime, Integer, String
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData(bind=migrate_engine)
+@@ -51,9 +54,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-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/018_add_qos_specs.py.orig	2016-08-25 08:57:51.329501203 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/018_add_qos_specs.py	2016-08-25 08:56:32.044466643 -0700
+@@ -14,9 +14,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import Boolean, Column, DateTime
+ from sqlalchemy import ForeignKey, MetaData, String, Table
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     """Add volume_type_rate_limit table."""
+@@ -34,7 +37,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-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/020_add_volume_admin_metadata_table.py.orig	2016-08-25 08:58:01.270351421 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/020_add_volume_admin_metadata_table.py	2016-08-25 08:56:32.045303898 -0700
+@@ -10,9 +10,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import Boolean, Column, DateTime
+ from sqlalchemy import Integer, MetaData, String, Table, ForeignKey
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -32,7 +35,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-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/025_add_consistencygroup.py.orig	2016-08-25 08:58:07.982189985 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/025_add_consistencygroup.py	2016-08-25 08:56:32.046312221 -0700
+@@ -13,9 +13,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import Boolean, Column, DateTime
+ from sqlalchemy import ForeignKey, MetaData, String, Table
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -37,7 +40,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',
+     )
+ 
+@@ -59,7 +62,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-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/032_add_volume_type_projects.py.orig	2016-08-25 08:58:14.732428526 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/032_add_volume_type_projects.py	2016-08-25 08:56:32.047162211 -0700
+@@ -10,9 +10,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import Boolean, Column, DateTime, UniqueConstraint
+ from sqlalchemy import Integer, MetaData, String, Table, ForeignKey
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -35,7 +38,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,
+     )
+ 
+     volume_type_projects.create()
+--- cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/038_add_driver_initiator_data_table.py.orig	2016-08-25 08:58:22.055008365 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/038_add_driver_initiator_data_table.py	2016-08-25 08:56:32.048168233 -0700
+@@ -10,9 +10,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import Column, DateTime, Integer
+ from sqlalchemy import MetaData, String, Table, UniqueConstraint
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -29,7 +32,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-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/040_add_volume_attachment.py.orig	2016-08-25 08:58:30.054762283 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/040_add_volume_attachment.py	2016-08-25 08:56:32.049123043 -0700
+@@ -16,11 +16,13 @@
+ import datetime
+ import uuid
+ 
++from oslo_config import cfg
+ import six
+ from sqlalchemy import Boolean, Column, DateTime
+ from sqlalchemy import ForeignKey, MetaData, String, Table
+ 
+ CREATED_AT = datetime.datetime.now()  # noqa
++CONF = cfg.CONF
+ 
+ 
+ def upgrade(migrate_engine):
+@@ -51,7 +53,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
+     )
+ 
+     volume_attachment.create()
+--- cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/055_add_image_volume_cache_table.py.orig	2016-08-25 08:58:37.835313620 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/055_add_image_volume_cache_table.py	2016-08-25 08:56:32.049959998 -0700
+@@ -12,9 +12,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import Column, DateTime, Integer
+ from sqlalchemy import MetaData, String, Table
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -30,7 +33,7 @@ def upgrade(migrate_engine):
+         Column('volume_id', String(length=36), nullable=False),
+         Column('size', Integer, nullable=False),
+         Column('last_used', DateTime, nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+--- cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/067_readd_iscsi_targets_table.py.orig	2016-08-25 08:58:44.335850305 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/migrate_repo/versions/067_readd_iscsi_targets_table.py	2016-08-25 08:56:32.050821951 -0700
+@@ -10,9 +10,12 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ from sqlalchemy import Boolean, Column, DateTime, ForeignKey
+ from sqlalchemy import Integer, MetaData, String, Table
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -30,7 +33,7 @@ def upgrade(migrate_engine):
+         Column('host', String(length=255)),
+         Column('volume_id', String(length=36), ForeignKey('volumes.id'),
+                nullable=True),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+--- cinder-8.0.0/cinder/db/sqlalchemy/models.py.orig	2016-08-25 08:58:53.030663246 -0700
++++ cinder-8.0.0/cinder/db/sqlalchemy/models.py	2016-08-25 10:02:19.406765223 -0700
+@@ -24,6 +24,7 @@ from oslo_config import cfg
+ from oslo_db.sqlalchemy import models
+ from oslo_utils import timeutils
+ from sqlalchemy import Column, Integer, String, Text, schema
++from sqlalchemy import dialects
+ from sqlalchemy.ext.declarative import declarative_base
+ from sqlalchemy import ForeignKey, DateTime, Boolean
+ from sqlalchemy.orm import relationship, backref, validates
+@@ -33,11 +34,15 @@ CONF = cfg.CONF
+ BASE = declarative_base()
+ 
+ 
++def TinyText():
++            return Text().with_variant(dialects.mysql.TINYTEXT(), 'mysql')
++
++
+ 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
+@@ -150,9 +155,16 @@ class Volume(BASE, CinderBase):
+ 
+     host = Column(String(255))  # , ForeignKey('hosts.id'))
+     size = Column(Integer)
+-    availability_zone = Column(String(255))  # TODO(vish): foreign key?
+-    status = Column(String(255))  # TODO(vish): enum?
+-    attach_status = Column(String(255))  # TODO(vish): enum
++
++    if CONF.database.mysql_storage_engine == 'NDBCLUSTER':
++        availability_zone = Column(TinyText())
++        status = Column(String(64))
++        attach_status = Column(String(64))
++    else:
++        availability_zone = Column(String(255))  # TODO(vish): foreign key?
++        status = Column(String(255))  # TODO(vish): enum?
++        attach_status = Column(String(255))  # TODO(vish): enum
++
+     migration_status = Column(String(255))
+ 
+     scheduled_at = Column(DateTime)
+@@ -160,7 +172,11 @@ class Volume(BASE, CinderBase):
+     terminated_at = Column(DateTime)
+ 
+     display_name = Column(String(255))
+-    display_description = Column(String(255))
++
++    if CONF.database.mysql_storage_engine == 'NDBCLUSTER':
++        display_description = Column(TinyText())
++    else:
++        display_description = Column(String(255))
+ 
+     provider_location = Column(String(255))
+     provider_auth = Column(String(255))
+@@ -592,7 +608,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-8.0.0/cinder/tests/unit/test_migrations.py.orig	2016-08-25 08:59:01.630728551 -0700
++++ cinder-8.0.0/cinder/tests/unit/test_migrations.py	2016-08-25 08:56:32.054462196 -0700
+@@ -25,6 +25,7 @@ import uuid
+ import fixtures
+ 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
+@@ -33,6 +34,8 @@ 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."""
+@@ -842,8 +845,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)
+ 
--- a/components/openstack/glance/files/glance-api.conf	Thu Sep 08 12:41:54 2016 -0700
+++ b/components/openstack/glance/files/glance-api.conf	Thu Sep 08 13:16:06 2016 -0600
@@ -650,6 +650,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-glare.conf	Thu Sep 08 12:41:54 2016 -0700
+++ b/components/openstack/glance/files/glance-glare.conf	Thu Sep 08 13:16:06 2016 -0600
@@ -384,6 +384,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-manage.conf	Thu Sep 08 12:41:54 2016 -0700
+++ b/components/openstack/glance/files/glance-manage.conf	Thu Sep 08 13:16:06 2016 -0600
@@ -140,6 +140,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	Thu Sep 08 12:41:54 2016 -0700
+++ b/components/openstack/glance/files/glance-registry.conf	Thu Sep 08 13:16:06 2016 -0600
@@ -451,6 +451,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-scrubber.conf	Thu Sep 08 12:41:54 2016 -0700
+++ b/components/openstack/glance/files/glance-scrubber.conf	Thu Sep 08 13:16:06 2016 -0600
@@ -384,6 +384,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	Thu Sep 08 13:16:06 2016 -0600
@@ -0,0 +1,1033 @@
+This patchset is for bug:
+
+24394534 Mitaka Glance should 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-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/001_add_images_table.py.orig	2016-08-10 09:36:22.622664972 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/001_add_images_table.py	2016-08-10 09:34:27.421171908 -0700
+@@ -13,11 +13,14 @@
+ #    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 +44,7 @@ def define_images_table(meta):
+                           nullable=False,
+                           default=False,
+                           index=True),
+-                   mysql_engine='InnoDB',
++                   mysql_engine=CONF.database.mysql_storage_engine,
+                    mysql_charset='utf8',
+                    extend_existing=True)
+ 
+--- glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/002_add_image_properties_table.py.orig	2016-08-10 09:36:22.630165670 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/002_add_image_properties_table.py	2016-08-10 09:34:27.422389893 -0700
+@@ -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,8 @@ 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(
+@@ -44,7 +47,8 @@ def define_image_properties_table(meta):
+                                     nullable=False),
+                              Column('image_id',
+                                     Integer(),
+-                                    ForeignKey('images.id'),
++                                    ForeignKey('images.id',
++                                               name='image_properties_ibfk_1'),
+                                     nullable=False,
+                                     index=True),
+                              Column('key', String(255), nullable=False),
+@@ -59,7 +63,7 @@ def define_image_properties_table(meta):
+                                     index=True),
+                              UniqueConstraint('image_id', 'key',
+                                               **constr_kwargs),
+-                             mysql_engine='InnoDB',
++                             mysql_engine=CONF.database.mysql_storage_engine,
+                              mysql_charset='utf8',
+                              extend_existing=True)
+ 
+--- glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/003_add_disk_format.py.orig	2016-08-10 09:36:22.637028552 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/003_add_disk_format.py	2016-08-10 09:34:27.423147663 -0700
+@@ -14,11 +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, Text, from_migration_import)  # noqa
+ 
++CONF = cfg.CONF
++
+ 
+ def get_images_table(meta):
+     """
+@@ -47,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-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/004_add_checksum.py.orig	2016-08-10 09:36:22.643321775 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/004_add_checksum.py	2016-08-10 09:34:27.423839815 -0700
+@@ -14,11 +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, Text, from_migration_import)  # noqa
+ 
++CONF = cfg.CONF
++
+ 
+ def get_images_table(meta):
+     """
+@@ -48,7 +51,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-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/005_size_big_integer.py.orig	2016-08-10 09:36:22.650608190 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/005_size_big_integer.py	2016-08-10 09:34:27.424528158 -0700
+@@ -14,12 +14,15 @@
+ #    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 +51,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-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/006_key_to_name.py.orig	2016-08-10 09:36:22.657538722 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/006_key_to_name.py	2016-08-10 09:34:27.425360155 -0700
+@@ -14,11 +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, Text, from_migration_import)  # noqa
+ 
++CONF = cfg.CONF
++
+ 
+ def get_images_table(meta):
+     """
+@@ -49,7 +52,8 @@ def get_image_properties_table(meta):
+                                     nullable=False),
+                              Column('image_id',
+                                     Integer(),
+-                                    ForeignKey('images.id'),
++                                    ForeignKey('images.id',
++                                               name='image_properties_ibfk_1'),
+                                     nullable=False,
+                                     index=True),
+                              Column('name', String(255), nullable=False),
+@@ -63,7 +67,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-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/007_add_owner.py.orig	2016-08-10 09:36:22.664818540 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/007_add_owner.py	2016-08-10 09:34:27.427318330 -0700
+@@ -14,12 +14,15 @@
+ #    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 +53,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-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/008_add_image_members_table.py.orig	2016-08-10 09:36:22.672154268 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/008_add_image_members_table.py	2016-08-10 09:34:27.428348883 -0700
+@@ -14,12 +14,15 @@
+ #    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):
+     """
+@@ -54,7 +57,8 @@ def get_image_members_table(meta):
+                                  nullable=False),
+                           Column('image_id',
+                                  Integer(),
+-                                 ForeignKey('images.id'),
++                                 ForeignKey('images.id',
++                                            name='image_members_image_id_fkey'),
+                                  nullable=False,
+                                  index=True),
+                           Column('member', String(255), nullable=False),
+@@ -72,7 +76,7 @@ def get_image_members_table(meta):
+                                  index=True),
+                           UniqueConstraint('image_id', 'member'),
+                           mysql_charset='utf8',
+-                          mysql_engine='InnoDB',
++                          mysql_engine=CONF.database.mysql_storage_engine,
+                           extend_existing=True)
+ 
+     # DB2: an index has already been created for the UniqueConstraint option
+--- glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/009_add_mindisk_and_minram.py.orig	2016-08-10 09:36:22.678770092 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/009_add_mindisk_and_minram.py	2016-08-10 09:34:27.454363865 -0700
+@@ -14,11 +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, Text, from_migration_import)  # noqa
+ 
++CONF = cfg.CONF
++
+ 
+ def get_images_table(meta):
+     """
+@@ -51,7 +54,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-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/014_add_image_tags_table.py.orig	2016-08-10 09:36:22.685172827 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/014_add_image_tags_table.py	2016-08-10 09:34:27.456082973 -0700
+@@ -13,10 +13,13 @@
+ #    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
+@@ -30,7 +33,8 @@ def define_image_tags_table(meta):
+                                             nullable=False),
+                               schema.Column('image_id',
+                                             glance_schema.String(36),
+-                                            schema.ForeignKey('images.id'),
++                                            schema.ForeignKey('images.id',
++                                                              name='image_tags_ibfk_1'),
+                                             nullable=False),
+                               schema.Column('value',
+                                             glance_schema.String(255),
+@@ -46,7 +50,7 @@ def define_image_tags_table(meta):
+                                             glance_schema.Boolean(),
+                                             nullable=False,
+                                             default=False),
+-                              mysql_engine='InnoDB',
++                              mysql_engine=CONF.database.mysql_storage_engine,
+                               mysql_charset='utf8')
+ 
+     schema.Index('ix_image_tags_image_id',
+--- glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/018_add_image_locations_table.py.orig	2016-08-10 09:36:22.691935092 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/018_add_image_locations_table.py	2016-08-10 09:34:27.457534530 -0700
+@@ -13,10 +13,13 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ import sqlalchemy
+ 
+ from glance.db.sqlalchemy.migrate_repo import schema
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = sqlalchemy.schema.MetaData(migrate_engine)
+@@ -32,7 +35,8 @@ def upgrade(migrate_engine):
+                           nullable=False),
+         sqlalchemy.Column('image_id',
+                           schema.String(36),
+-                          sqlalchemy.ForeignKey('images.id'),
++                          sqlalchemy.ForeignKey('images.id',
++                                                name='image_locations_ibfk_1'),
+                           nullable=False,
+                           index=True),
+         sqlalchemy.Column('value',
+@@ -50,7 +54,7 @@ def upgrade(migrate_engine):
+                           nullable=False,
+                           default=False,
+                           index=True),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8',
+     )
+ 
+--- glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/021_set_engine_mysql_innodb.py.orig	2016-08-10 09:36:22.698690410 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/021_set_engine_mysql_innodb.py	2016-08-10 09:34:27.458291445 -0700
+@@ -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-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/022_image_member_index.py.orig	2016-08-10 09:36:22.705922240 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/022_image_member_index.py	2016-08-10 09:34:27.459101595 -0700
+@@ -15,6 +15,7 @@
+ 
+ import re
+ 
++from migrate.changeset.constraint import ForeignKeyConstraint
+ from migrate.changeset import UniqueConstraint
+ from oslo_db import exception as db_exception
+ from sqlalchemy import and_, func, orm
+@@ -28,6 +29,12 @@ ORIGINAL_KEYNAME_RE = re.compile('image_
+ 
+ def upgrade(migrate_engine):
+     image_members = _get_image_members_table(migrate_engine)
++    images = _get_images_table(migrate_engine)
++    # Drop foreign key first
++    fkc = ForeignKeyConstraint([image_members.c.image_id],
++                               [images.c.id],
++                               name='image_members_image_id_fkey')
++    fkc.drop()
+ 
+     if migrate_engine.name in ('mysql', 'postgresql'):
+         try:
+@@ -44,6 +51,9 @@ def upgrade(migrate_engine):
+                          name=NEW_KEYNAME,
+                          table=image_members).create()
+ 
++    # Add foreign key back
++    fkc.create()
++
+ 
+ def downgrade(migrate_engine):
+     image_members = _get_image_members_table(migrate_engine)
+@@ -65,6 +75,12 @@ def _get_image_members_table(migrate_eng
+     return Table('image_members', meta, autoload=True)
+ 
+ 
++def _get_images_table(migrate_engine):
++    meta = MetaData()
++    meta.bind = migrate_engine
++    return Table('images', meta, autoload=True)
++
++
+ def _get_original_keyname(db):
+     return {'mysql': 'image_id',
+             'postgresql': 'image_members_image_id_member_key'}[db]
+--- glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/030_add_tasks_table.py.orig	2016-08-10 09:36:22.712553022 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/030_add_tasks_table.py	2016-08-10 09:34:27.460669890 -0700
+@@ -14,11 +14,14 @@
+ #    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 +41,7 @@ def define_tasks_table(meta):
+                          Boolean(),
+                          nullable=False,
+                          default=False),
+-                  mysql_engine='InnoDB',
++                  mysql_engine=CONF.database.mysql_storage_engine,
+                   mysql_charset='utf8',
+                   extend_existing=True)
+ 
+--- glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/032_add_task_info_table.py.orig	2016-08-10 09:36:22.719716648 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/032_add_task_info_table.py	2016-08-10 09:34:27.471154455 -0700
+@@ -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,
+@@ -21,6 +22,7 @@ from glance.db.sqlalchemy.migrate_repo.s
+                                                       drop_tables)  # noqa
+ 
+ TASKS_MIGRATE_COLUMNS = ['input', 'message', 'result']
++CONF = cfg.CONF
+ 
+ 
+ def define_task_info_table(meta):
+@@ -31,13 +33,14 @@ def define_task_info_table(meta):
+     task_info = Table('task_info',
+                       meta,
+                       Column('task_id', String(36),
+-                             ForeignKey('tasks.id'),
++                             ForeignKey('tasks.id',
++                             name='task_info_ibfk_1'),
+                              primary_key=True,
+                              nullable=False),
+                       Column('input', Text()),
+                       Column('result', Text()),
+                       Column('message', Text()),
+-                      mysql_engine='InnoDB',
++                      mysql_engine=CONF.database.mysql_storage_engine,
+                       mysql_charset='utf8')
+ 
+     return task_info
+--- glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/035_add_metadef_tables.py.orig	2016-08-10 09:36:22.726515825 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/035_add_metadef_tables.py	2016-08-10 09:34:27.472707375 -0700
+@@ -12,6 +12,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ import sqlalchemy
+ from sqlalchemy.schema import (
+     Column, ForeignKey, Index, MetaData, Table, UniqueConstraint)  # noqa
+@@ -25,6 +26,7 @@ from glance.db.sqlalchemy.migrate_repo.s
+ RESOURCE_TYPES = [u'OS::Glance::Image', u'OS::Cinder::Volume',
+                   u'OS::Nova::Flavor', u'OS::Nova::Aggregate',
+                   u'OS::Nova::Server']
++CONF = cfg.CONF
+ 
+ 
+ def _get_metadef_resource_types_table(meta):
+@@ -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,
+                        mysql_charset='utf8',
+                        extend_existing=True)
+ 
+@@ -85,7 +87,8 @@ def define_metadef_objects_table(meta):
+                     meta,
+                     Column('id', Integer(), primary_key=True, nullable=False),
+                     Column('namespace_id', Integer(),
+-                           ForeignKey('metadef_namespaces.id'),
++                           ForeignKey('metadef_namespaces.id',
++                           name='metadef_objects_ibfk_1'),
+                            nullable=False),
+                     Column('name', String(80), nullable=False),
+                     Column('description', Text()),
+@@ -95,7 +98,7 @@ def define_metadef_objects_table(meta):
+                     Column('updated_at', DateTime()),
+                     UniqueConstraint('namespace_id', 'name',
+                                      **_constr_kwargs),
+-                    mysql_engine='InnoDB',
++                    mysql_engine=CONF.database.mysql_storage_engine,
+                     mysql_charset='utf8',
+                     extend_existing=True)
+ 
+@@ -117,14 +120,15 @@ def define_metadef_properties_table(meta
+         'metadef_properties',
+         meta,
+         Column('id', Integer(), primary_key=True, nullable=False),
+-        Column('namespace_id', Integer(), ForeignKey('metadef_namespaces.id'),
++        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='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8',
+         extend_existing=True)
+ 
+@@ -151,7 +155,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,
+         mysql_charset='utf8',
+         extend_existing=True)
+ 
+@@ -172,10 +176,12 @@ def define_metadef_namespace_resource_ty
+         'metadef_namespace_resource_types',
+         meta,
+         Column('resource_type_id', Integer(),
+-               ForeignKey('metadef_resource_types.id'),
++               ForeignKey('metadef_resource_types.id',
++               name='metadef_namespace_resource_types_ibfk_1'),
+                primary_key=True, nullable=False),
+         Column('namespace_id', Integer(),
+-               ForeignKey('metadef_namespaces.id'),
++               ForeignKey('metadef_namespaces.id',
++               name='metadef_namespace_resource_types_ibfk_2'),
+                primary_key=True, nullable=False),
+         Column('properties_target', String(80)),
+         Column('prefix', String(80)),
+@@ -183,7 +189,7 @@ def define_metadef_namespace_resource_ty
+         Column('updated_at', DateTime()),
+         UniqueConstraint('resource_type_id', 'namespace_id',
+                          **_constr_kwargs),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8',
+         extend_existing=True)
+ 
+--- glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/037_add_changes_to_satisfy_models.py.orig	2016-08-10 09:36:22.732852195 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/037_add_changes_to_satisfy_models.py	2016-08-10 09:34:27.473457502 -0700
+@@ -81,7 +81,8 @@ def upgrade(migrate_engine):
+         image_locations = Table('image_locations', meta, autoload=True)
+         if len(image_locations.foreign_keys) == 0:
+             migrate_engine.execute(AddConstraint(ForeignKeyConstraint(
+-                [image_locations.c.image_id], [images.c.id])))
++                [image_locations.c.image_id], [images.c.id],
++                name='image_locations_ibfk_1')))
+ 
+ 
+ def downgrade(migrate_engine):
+--- glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/038_add_metadef_tags_table.py.orig	2016-08-10 09:36:22.739351950 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/038_add_metadef_tags_table.py	2016-08-10 09:34:27.474322102 -0700
+@@ -12,12 +12,15 @@
+ #    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 = {}
+@@ -32,7 +35,7 @@ def define_metadef_tags_table(meta):
+                          Column('updated_at', DateTime()),
+                          UniqueConstraint('namespace_id', 'name',
+                                           **_constr_kwargs),
+-                         mysql_engine='InnoDB',
++                         mysql_engine=CONF.database.mysql_storage_engine,
+                          mysql_charset='utf8',
+                          extend_existing=False)
+ 
+--- glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/039_add_changes_to_satisfy_models_metadef.py.orig	2016-08-10 09:36:22.745773757 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/039_add_changes_to_satisfy_models_metadef.py	2016-08-10 09:41:20.008006522 -0700
+@@ -63,15 +63,25 @@ def upgrade(migrate_engine):
+     else:
+         Index('ix_namespaces_namespace', metadef_namespaces.c.namespace).drop()
+ 
++        # Drop foreign key first
++        fkc = migrate.ForeignKeyConstraint([metadef_objects.c.namespace_id],
++                                           [metadef_namespaces.c.id],
++                                           name='metadef_objects_ibfk_1')
++        fkc.drop()
++
+         Index('ix_objects_namespace_id_name', metadef_objects.c.namespace_id,
+               metadef_objects.c.name).drop()
+ 
++        # Add foreign key back
++        fkc.create()
++
+         Index('ix_metadef_properties_namespace_id_name',
+               metadef_properties.c.namespace_id,
+               metadef_properties.c.name).drop()
+ 
+     fkc = migrate.ForeignKeyConstraint([metadef_tags.c.namespace_id],
+-                                       [metadef_namespaces.c.id])
++                                       [metadef_namespaces.c.id],
++                                       name='metadef_tags_ibfk_1')
+     fkc.create()
+ 
+     # `migrate` module removes unique constraint after adding
+@@ -88,8 +98,13 @@ def upgrade(migrate_engine):
+         uc.create()
+ 
+     if meta.bind.name != "ibm_db_sa":
++        fkc = migrate.ForeignKeyConstraint([metadef_tags.c.namespace_id],
++                                           [metadef_namespaces.c.id],
++                                           name='metadef_tags_ibfk_1')
++        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()
+ 
+@@ -120,10 +135,15 @@ def upgrade(migrate_engine):
+         migrate_engine.execute(DropConstraint(constraint))
+         fkc.create()
+ 
++        fkc = migrate.ForeignKeyConstraint([metadef_ns_res_types.c.resource_type_id],
++                                           [metadef_resource_types.c.id],
++                                           name='metadef_namespace_resource_types_ibfk_1')
++        fkc.drop()
+         constraint = UniqueConstraint(metadef_ns_res_types.c.resource_type_id,
+                                       metadef_ns_res_types.c.namespace_id,
+                                       name='resource_type_id')
+         migrate_engine.execute(DropConstraint(constraint))
++        fkc.create()
+ 
+         constraint = UniqueConstraint(metadef_namespaces.c.namespace,
+                                       name='namespace')
+@@ -251,7 +271,8 @@ def downgrade(migrate_engine):
+ 
+     if migrate_engine.name != 'sqlite':
+         fkc = migrate.ForeignKeyConstraint([metadef_tags.c.namespace_id],
+-                                           [metadef_namespaces.c.id])
++                                           [metadef_namespaces.c.id],
++                                           name='metadef_tags_ibfk_1')
+         fkc.drop()
+ 
+         if meta.bind.name != "ibm_db_sa":
+@@ -332,8 +353,8 @@ def downgrade(migrate_engine):
+     if migrate_engine.name == 'mysql':
+         fkc = migrate.ForeignKeyConstraint(
+             [metadef_ns_res_types.c.resource_type_id],
+-            [metadef_namespaces.c.id],
+-            name='metadef_namespace_resource_types_ibfk_2')
++            [metadef_resource_types.c.id],
++            name='metadef_namespace_resource_types_ibfk_1')
+         fkc.drop()
+ 
+         Index('ix_metadef_ns_res_types_namespace_id',
+--- glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/040_add_changes_to_satisfy_metadefs_tags.py.orig	2016-08-10 09:42:23.016042269 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/040_add_changes_to_satisfy_metadefs_tags.py	2016-08-10 09:41:29.896233507 -0700
+@@ -10,7 +10,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
+-
++import migrate
+ import sqlalchemy
+ from sqlalchemy import (Table, Index)
+ 
+@@ -20,5 +20,11 @@ def upgrade(migrate_engine):
+         meta = sqlalchemy.MetaData()
+         meta.bind = migrate_engine
+         metadef_tags = Table('metadef_tags', meta, autoload=True)
++        metadef_namespaces = Table('metadef_namespaces', meta, autoload=True)
++        fkc = migrate.ForeignKeyConstraint([metadef_tags.c.namespace_id],
++                                           [metadef_namespaces.c.id],
++                                           name='metadef_tags_ibfk_1')
++        fkc.drop()
+         Index('namespace_id', metadef_tags.c.namespace_id,
+               metadef_tags.c.name).drop()
++        fkc.create()
+--- glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/041_add_artifact_tables.py.orig	2016-08-10 09:36:22.752236945 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/migrate_repo/versions/041_add_artifact_tables.py	2016-08-10 09:34:27.477711872 -0700
+@@ -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,8 @@ 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 +46,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,
+                       mysql_charset='utf8',
+                       extend_existing=True)
+ 
+@@ -64,12 +67,14 @@ def define_artifact_tags_table(meta):
+                           Column('id', String(36), primary_key=True,
+                                  nullable=False),
+                           Column('artifact_id', String(36),
+-                                 ForeignKey('artifacts.id'), nullable=False),
++                                 ForeignKey('artifacts.id',
++                                 name='artifact_tags_ibfk_1'),
++                                 nullable=False),
+                           Column('value', String(255), nullable=False),
+                           Column('created_at', DateTime(), nullable=False),
+                           Column('updated_at', DateTime(),
+                                  nullable=False),
+-                          mysql_engine='InnoDB',
++                          mysql_engine=CONF.database.mysql_storage_engine,
+                           mysql_charset='utf8',
+                           extend_existing=True)
+ 
+@@ -86,13 +91,16 @@ def define_artifact_dependencies_table(m
+                                   Column('id', String(36), primary_key=True,
+                                          nullable=False),
+                                   Column('artifact_source', String(36),
+-                                         ForeignKey('artifacts.id'),
++                                         ForeignKey('artifacts.id',
++                                         name='artifact_dependencies_ibfk_1'),
+                                          nullable=False),
+                                   Column('artifact_dest', String(36),
+-                                         ForeignKey('artifacts.id'),
++                                         ForeignKey('artifacts.id',
++                                         name='artifact_dependencies_ibfk_2'),
+                                          nullable=False),
+                                   Column('artifact_origin', String(36),
+-                                         ForeignKey('artifacts.id'),
++                                         ForeignKey('artifacts.id',
++                                         name='artifact_dependencies_ibfk_3'),
+                                          nullable=False),
+                                   Column('is_direct', Boolean(),
+                                          nullable=False),
+@@ -102,7 +110,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,
+                                   mysql_charset='utf8',
+                                   extend_existing=True)
+ 
+@@ -124,7 +132,8 @@ def define_artifact_blobs_table(meta):
+                            Column('id', String(36), primary_key=True,
+                                   nullable=False),
+                            Column('artifact_id', String(36),
+-                                  ForeignKey('artifacts.id'),
++                                  ForeignKey('artifacts.id',
++                                  name='artifact_blobs_ibfk_1'),
+                                   nullable=False),
+                            Column('size', BigInteger(), nullable=False),
+                            Column('checksum', String(32)),
+@@ -134,7 +143,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,
+                            mysql_charset='utf8',
+                            extend_existing=True)
+     Index('ix_artifact_blobs_artifact_id',
+@@ -151,7 +160,8 @@ def define_artifact_properties_table(met
+                                        primary_key=True,
+                                        nullable=False),
+                                 Column('artifact_id', String(36),
+-                                       ForeignKey('artifacts.id'),
++                                       ForeignKey('artifacts.id',
++                                       name='artifact_properties_ibfk_1'),
+                                        nullable=False),
+                                 Column('name', String(255),
+                                        nullable=False),
+@@ -165,7 +175,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,
+                                 mysql_charset='utf8',
+                                 extend_existing=True)
+     Index('ix_artifact_properties_artifact_id',
+@@ -181,7 +191,8 @@ def define_artifact_blob_locations_table
+                                            primary_key=True,
+                                            nullable=False),
+                                     Column('blob_id', String(36),
+-                                           ForeignKey('artifact_blobs.id'),
++                                           ForeignKey('artifact_blobs.id',
++                                                      name='artifact_blob_locations_ibfk_1'),
+                                            nullable=False),
+                                     Column('value', Text(), nullable=False),
+                                     Column('created_at', DateTime(),
+@@ -191,7 +202,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,
+                                     mysql_charset='utf8',
+                                     extend_existing=True)
+     Index('ix_artifact_blob_locations_blob_id',
+--- glance-12.0.0/glance/db/sqlalchemy/models_glare.py.orig	2016-08-10 09:36:22.759461763 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/models_glare.py	2016-08-10 09:34:27.479493197 -0700
+@@ -14,6 +14,8 @@
+ 
+ import uuid
+ 
++from oslo_config import cfg
++from oslo_db import options
+ from oslo_db.sqlalchemy import models
+ from sqlalchemy import BigInteger
+ from sqlalchemy import Boolean
+@@ -35,12 +37,15 @@ from glance.common import timeutils
+ import glance.glare as ga
+ 
+ BASE = declarative.declarative_base()
++CONF = cfg.CONF
++options.set_defaults(cfg.CONF)
+ 
+ 
+ class ArtifactBase(models.ModelBase, models.TimestampMixin):
+     """Base class for Artifact Models."""
+ 
+-    __table_args__ = {'mysql_engine': 'InnoDB', 'mysql_charset': 'utf8'}
++    __table_args__ = {'mysql_engine': CONF.database.mysql_storage_engine,
++                      'mysql_charset': 'utf8'}
+     __table_initialized__ = False
+     __protected_attributes__ = set([
+         "created_at", "updated_at"])
+@@ -98,7 +103,8 @@ class Artifact(BASE, ArtifactBase):
+         Index('ix_artifact_state', 'state'),
+         Index('ix_artifact_owner', 'owner'),
+         Index('ix_artifact_visibility', 'visibility'),
+-        {'mysql_engine': 'InnoDB', 'mysql_charset': 'utf8'})
++        {'mysql_engine': CONF.database.mysql_storage_engine,
++         'mysql_charset': 'utf8'})
+ 
+     __protected_attributes__ = ArtifactBase.__protected_attributes__.union(
+         set(['published_at', 'deleted_at']))
+@@ -219,7 +225,8 @@ class ArtifactDependency(BASE, ArtifactB
+                             'artifact_dest'),
+                       Index('ix_artifact_dependencies_direct_dependencies',
+                             'artifact_source', 'is_direct'),
+-                      {'mysql_engine': 'InnoDB', 'mysql_charset': 'utf8'})
++                      {'mysql_engine': CONF.database.mysql_storage_engine,
++                       'mysql_charset': 'utf8'})
+ 
+     id = Column(String(36), primary_key=True, nullable=False,
+                 default=lambda: str(uuid.uuid4()))
+@@ -248,7 +255,8 @@ 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_charset': 'utf8'},)
++                      {'mysql_engine': CONF.database.mysql_storage_engine,
++                       'mysql_charset': 'utf8'},)
+ 
+     id = Column(String(36), primary_key=True, nullable=False,
+                 default=lambda: str(uuid.uuid4()))
+@@ -265,7 +273,8 @@ class ArtifactProperty(BASE, ArtifactBas
+     __table_args__ = (
+         Index('ix_artifact_properties_artifact_id', 'artifact_id'),
+         Index('ix_artifact_properties_name', 'name'),
+-        {'mysql_engine': 'InnoDB', 'mysql_charset': 'utf8'},)
++        {'mysql_engine': CONF.database.mysql_storage_engine,
++         'mysql_charset': 'utf8'},)
+     id = Column(String(36), primary_key=True, nullable=False,
+                 default=lambda: str(uuid.uuid4()))
+     artifact_id = Column(String(36), ForeignKey('artifacts.id'),
+@@ -287,7 +296,8 @@ class ArtifactBlob(BASE, ArtifactBase):
+     __table_args__ = (
+         Index('ix_artifact_blobs_artifact_id', 'artifact_id'),
+         Index('ix_artifact_blobs_name', 'name'),
+-        {'mysql_engine': 'InnoDB', 'mysql_charset': 'utf8'},)
++        {'mysql_engine': CONF.database.mysql_storage_engine,
++         'mysql_charset': 'utf8'},)
+     id = Column(String(36), primary_key=True, nullable=False,
+                 default=lambda: str(uuid.uuid4()))
+     artifact_id = Column(String(36), ForeignKey('artifacts.id'),
+@@ -307,7 +317,8 @@ class ArtifactBlobLocation(BASE, Artifac
+     __tablename__ = 'artifact_blob_locations'
+     __table_args__ = (Index('ix_artifact_blob_locations_blob_id',
+                             'blob_id'),
+-                      {'mysql_engine': 'InnoDB', 'mysql_charset': 'utf8'})
++                      {'mysql_engine': CONF.database.mysql_storage_engine,
++                       'mysql_charset': 'utf8'})
+ 
+     id = Column(String(36), primary_key=True, nullable=False,
+                 default=lambda: str(uuid.uuid4()))
+--- glance-12.0.0/glance/db/sqlalchemy/models_metadef.py.orig	2016-08-10 09:36:22.766310320 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/models_metadef.py	2016-08-10 09:34:27.480397292 -0700
+@@ -16,6 +16,7 @@
+ SQLAlchemy models for glance metadata schema
+ """
+ 
++from oslo_config import cfg
+ from oslo_db.sqlalchemy import models
+ from sqlalchemy import Boolean
+ from sqlalchemy import Column
+@@ -32,6 +33,8 @@ from sqlalchemy import UniqueConstraint
+ from glance.common import timeutils
+ from glance.db.sqlalchemy.models import JSONEncodedDict
+ 
++CONF = cfg.CONF
++
+ 
+ class DictionaryBase(models.ModelBase):
+     metadata = None
+@@ -49,7 +52,8 @@ BASE_DICT = declarative_base(cls=Diction
+ class GlanceMetadefBase(models.TimestampMixin):
+     """Base class for Glance Metadef Models."""
+ 
+-    __table_args__ = {'mysql_engine': 'InnoDB', 'mysql_charset': 'utf8'}
++    __table_args__ = {'mysql_engine': CONF.database.mysql_storage_engine,
++                      'mysql_charset': 'utf8'}
+     __table_initialized__ = False
+     __protected_attributes__ = set(["created_at", "updated_at"])
+ 
+--- glance-12.0.0/glance/db/sqlalchemy/models.py.orig	2016-08-10 09:36:22.773221505 -0700
++++ glance-12.0.0/glance/db/sqlalchemy/models.py	2016-08-10 09:34:27.481259927 -0700
+@@ -20,6 +20,7 @@ SQLAlchemy models for glance data
+ 
+ import uuid
+ 
++from oslo_config import cfg
+ from oslo_db.sqlalchemy import models
+ from oslo_serialization import jsonutils
+ from sqlalchemy import BigInteger
+@@ -41,6 +42,7 @@ from glance.common import timeutils
+ 
+ 
+ BASE = declarative_base()
++CONF = cfg.CONF
+ 
+ 
+ class JSONEncodedDict(TypeDecorator):
+@@ -62,7 +64,7 @@ class JSONEncodedDict(TypeDecorator):
+ class GlanceBase(models.ModelBase, models.TimestampMixin):
+     """Base class for Glance Models."""
+ 
+-    __table_args__ = {'mysql_engine': 'InnoDB', 'mysql_charset': 'utf8'}
++    __table_args__ = {'mysql_engine': CONF.database.mysql_storage_engine, 'mysql_charset': 'utf8'}
+     __table_initialized__ = False
+     __protected_attributes__ = set([
+         "created_at", "updated_at", "deleted_at", "deleted"])
+--- glance-12.0.0/glance/tests/unit/test_migrations.py.orig	2016-08-10 09:36:22.780385325 -0700
++++ glance-12.0.0/glance/tests/unit/test_migrations.py	2016-08-10 09:34:27.483366399 -0700
+@@ -122,7 +122,7 @@ class MigrationsMixin(test_migrations.Wa
+                                                         sqlalchemy.Boolean(),
+                                                         nullable=False,
+                                                         default=False),
+-                                      mysql_engine='InnoDB',
++                                      mysql_engine=CONF.database.mysql_storage_engine,
+                                       mysql_charset='utf8')
+         images_001.create()
+ 
+@@ -1846,10 +1846,11 @@ 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(0, count, "%d non InnoDB tables created" % count)
+ 
--- a/components/openstack/heat/files/heat.conf	Thu Sep 08 12:41:54 2016 -0700
+++ b/components/openstack/heat/files/heat.conf	Thu Sep 08 13:16:06 2016 -0600
@@ -900,6 +900,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	Thu Sep 08 13:16:06 2016 -0600
@@ -0,0 +1,304 @@
+This patchset is for bug:
+
+24394543 Mitaka Heat should 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-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/028_havana.py.orig	2016-08-08 13:53:36.196603218 -0700
++++ heat-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/028_havana.py	2016-08-08 13:53:14.078159110 -0700
+@@ -11,12 +11,15 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ import uuid
+ 
+ import sqlalchemy
+ 
+ from heat.db.sqlalchemy import types
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = sqlalchemy.MetaData()
+@@ -29,7 +32,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.Column('created_at', sqlalchemy.DateTime),
+         sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
+         sqlalchemy.Column('template', types.LongText),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -46,7 +49,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.Column('tenant_id', sqlalchemy.String(256)),
+         sqlalchemy.Column('trust_id', sqlalchemy.String(255)),
+         sqlalchemy.Column('trustor_user_id', sqlalchemy.String(64)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -75,7 +78,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'
+     )
+ 
+@@ -93,7 +96,7 @@ def upgrade(migrate_engine):
+         sqlalchemy.Column('stack_id', sqlalchemy.String(36),
+                           sqlalchemy.ForeignKey('stack.id'), nullable=False),
+         sqlalchemy.Column('rsrc_metadata', types.LongText),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -110,7 +113,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'
+     )
+ 
+@@ -129,7 +132,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'
+     )
+ 
+@@ -145,7 +148,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'
+     )
+ 
+@@ -159,7 +162,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-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/031_stack_lock.py.orig	2016-08-08 13:53:44.254365335 -0700
++++ heat-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/031_stack_lock.py	2016-08-08 13:53:14.078870800 -0700
+@@ -11,8 +11,11 @@
+ #    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 +30,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-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/033_software_config.py.orig	2016-08-08 13:53:52.462462615 -0700
++++ heat-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/033_software_config.py	2016-08-08 13:53:14.079526502 -0700
+@@ -11,10 +11,13 @@
+ #    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 +37,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 +66,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-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/044_snapshots.py.orig	2016-08-08 13:54:01.375663605 -0700
++++ heat-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/044_snapshots.py	2016-08-08 13:53:14.080116985 -0700
+@@ -11,10 +11,13 @@
+ #    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 +41,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-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/051_service.py.orig	2016-08-08 13:54:08.527359970 -0700
++++ heat-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/051_service.py	2016-08-08 13:53:14.080700065 -0700
+@@ -13,10 +13,13 @@
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ 
++from oslo_config import cfg
+ import uuid
+ 
+ import sqlalchemy
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = sqlalchemy.MetaData()
+@@ -36,7 +39,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-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/054_stack_tags_table.py.orig	2016-08-08 13:54:17.198831162 -0700
++++ heat-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/054_stack_tags_table.py	2016-08-08 13:53:14.081281862 -0700
+@@ -11,8 +11,11 @@
+ #    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(bind=migrate_engine)
+@@ -33,7 +36,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-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/057_resource_uuid_to_id.py.orig	2016-08-08 13:54:24.119188110 -0700
++++ heat-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/057_resource_uuid_to_id.py	2016-08-08 13:53:14.081963807 -0700
+@@ -189,10 +189,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-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/059_sync_point.py.orig	2016-08-08 13:54:31.078965167 -0700
++++ heat-6.0.0/heat/db/sqlalchemy/migrate_repo/versions/059_sync_point.py	2016-08-08 13:53:14.082544202 -0700
+@@ -11,10 +11,13 @@
+ #    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 +44,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-6.0.0/heat/db/sqlalchemy/models.py.orig	2016-08-08 13:54:38.888846543 -0700
++++ heat-6.0.0/heat/db/sqlalchemy/models.py	2016-08-08 13:55:40.851731167 -0700
+@@ -15,6 +15,7 @@
+ 
+ import uuid
+ 
++from oslo_config import cfg
+ from oslo_db.sqlalchemy import models
+ from oslo_utils import timeutils
+ import six
+@@ -27,6 +28,7 @@ from sqlalchemy.orm import session as or
+ from heat.db.sqlalchemy import types
+ 
+ BASE = declarative.declarative_base()
++CONF = cfg.CONF
+ 
+ 
+ def get_session():
+@@ -36,7 +38,7 @@ def get_session():
+ 
+ class HeatBase(models.ModelBase, models.TimestampMixin):
+     """Base class for Heat Models."""
+-    __table_args__ = {'mysql_engine': 'InnoDB'}
++    __table_args__ = {'mysql_engine': CONF.database.mysql_storage_engine}
+ 
+     def expire(self, session=None, attrs=None):
+         """Expire this object ()."""
--- a/components/openstack/ironic/files/ironic.conf	Thu Sep 08 12:41:54 2016 -0700
+++ b/components/openstack/ironic/files/ironic.conf	Thu Sep 08 13:16:06 2016 -0600
@@ -894,6 +894,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	Thu Sep 08 13:16:06 2016 -0600
@@ -0,0 +1,149 @@
+This patchset is for bug:
+
+24394552 Mitaka Ironic should 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 be quoted because "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-5.1.2/ironic/db/sqlalchemy/alembic/versions/2581ebaf0cb2_initial_migration.py.orig	2016-08-05 15:02:32.138604246 -0700
++++ ironic-5.1.2/ironic/db/sqlalchemy/alembic/versions/2581ebaf0cb2_initial_migration.py	2016-08-05 15:04:47.376598798 -0700
+@@ -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-5.1.2/ironic/db/sqlalchemy/alembic/versions/487deb87cc9d_add_conductor_affinity_and_online.py.orig	2016-08-05 15:01:05.339248664 -0700
++++ ironic-5.1.2/ironic/db/sqlalchemy/alembic/versions/487deb87cc9d_add_conductor_affinity_and_online.py	2016-08-05 15:01:53.896426955 -0700
+@@ -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(),
+--- ironic-5.1.2/ironic/db/sqlalchemy/alembic/versions/48d6c242bb9b_add_node_tags.py.orig	2016-08-05 15:01:12.489520146 -0700
++++ ironic-5.1.2/ironic/db/sqlalchemy/alembic/versions/48d6c242bb9b_add_node_tags.py	2016-08-05 15:01:53.897903465 -0700
+@@ -23,8 +23,10 @@ revision = '48d6c242bb9b'
+ down_revision = '516faf1bb9b1'
+ 
+ from alembic import op
++from oslo_config import cfg
+ import sqlalchemy as sa
+ 
++CONF = cfg.CONF
+ 
+ def upgrade():
+     op.create_table(
+@@ -36,7 +38,7 @@ def upgrade():
+         sa.Column('tag', sa.String(length=255), nullable=False),
+         sa.ForeignKeyConstraint(['node_id'], ['nodes.id'], ),
+         sa.PrimaryKeyConstraint('node_id', 'tag'),
+-        mysql_ENGINE='InnoDB',
++        mysql_ENGINE=CONF.database.mysql_storage_engine,
+         mysql_DEFAULT_CHARSET='UTF8'
+     )
+     op.create_index('node_tags_idx', 'node_tags', ['tag'], unique=False)
+--- ironic-5.1.2/ironic/db/sqlalchemy/alembic/versions/5ea1b0d310e_added_port_group_table_and_altered_ports.py.orig	2016-08-05 15:01:20.133426869 -0700
++++ ironic-5.1.2/ironic/db/sqlalchemy/alembic/versions/5ea1b0d310e_added_port_group_table_and_altered_ports.py	2016-08-05 15:01:53.898548390 -0700
+@@ -23,8 +23,10 @@ revision = '5ea1b0d310e'
+ down_revision = '48d6c242bb9b'
+ 
+ from alembic import op
++from oslo_config import cfg
+ import sqlalchemy as sa
+ 
++CONF = cfg.CONF
+ 
+ def upgrade():
+     op.create_table('portgroups',
+@@ -42,7 +44,7 @@ def upgrade():
+                     sa.UniqueConstraint('address',
+                                         name='uniq_portgroups0address'),
+                     sa.UniqueConstraint('name', name='uniq_portgroups0name'),
+-                    mysql_ENGINE='InnoDB',
++                    mysql_ENGINE=CONF.database.mysql_storage_engine,
+                     mysql_DEFAULT_CHARSET='UTF8')
+     op.add_column(u'ports', sa.Column('local_link_connection', sa.Text(),
+                                       nullable=True))
+--- ironic-5.1.2/ironic/db/sqlalchemy/models.py.orig	2016-08-05 15:01:28.309661466 -0700
++++ ironic-5.1.2/ironic/db/sqlalchemy/models.py	2016-08-05 15:01:53.899243145 -0700
+@@ -48,8 +48,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
+ 
+ 
+@@ -93,7 +97,7 @@ class Conductor(Base):
+     id = Column(Integer, primary_key=True)
+     hostname = Column(String(255), nullable=False)
+     drivers = Column(db_types.JsonEncodedList)
+-    online = Column(Boolean, default=True)
++    online = Column('online', Boolean, default=True, quote=True)
+ 
+ 
+ class Node(Base):
--- a/components/openstack/keystone/files/keystone.conf	Thu Sep 08 12:41:54 2016 -0700
+++ b/components/openstack/keystone/files/keystone.conf	Thu Sep 08 13:16:06 2016 -0600
@@ -558,6 +558,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	Thu Sep 08 13:16:06 2016 -0600
@@ -0,0 +1,337 @@
+This patchset is for bug:
+
+24394567 Mitaka Keystone should 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-9.1.0/keystone/common/sql/migrate_repo/versions/067_kilo.py.orig	2016-08-04 10:10:34.947867201 -0700
++++ keystone-9.1.0/keystone/common/sql/migrate_repo/versions/067_kilo.py	2016-08-04 10:16:37.481333376 -0700
+@@ -12,6 +12,7 @@
+ 
+ 
+ import migrate
++from oslo_config import cfg
+ from oslo_log import log
+ import sqlalchemy as sql
+ 
+@@ -21,6 +22,7 @@ from keystone.identity.mapping_backends
+ 
+ 
+ LOG = log.getLogger(__name__)
++CONF = cfg.CONF
+ 
+ 
+ def upgrade(migrate_engine):
+@@ -44,7 +46,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(
+@@ -53,7 +55,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(
+@@ -67,7 +69,7 @@ def upgrade(migrate_engine):
+         sql.Column('enabled', sql.Boolean, nullable=False, default=True,
+                    server_default='1'),
+         sql.Column('region_id', sql.String(length=255), nullable=True),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     group = sql.Table(
+@@ -77,7 +79,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(
+@@ -86,7 +88,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(
+@@ -98,7 +100,7 @@ def upgrade(migrate_engine):
+         sql.Column('enabled', sql.Boolean),
+         sql.Column('domain_id', sql.String(length=64), nullable=False),
+         sql.Column('parent_id', sql.String(64), nullable=True),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     role = sql.Table(
+@@ -106,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(
+@@ -116,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(
+@@ -127,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(
+@@ -141,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(
+@@ -150,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(
+@@ -162,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(
+@@ -179,7 +181,7 @@ def upgrade(migrate_engine):
+         sql.Column('description', sql.String(255), nullable=False),
+         sql.Column('parent_region_id', sql.String(255), nullable=True),
+         sql.Column('extra', sql.Text()),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     assignment = sql.Table(
+@@ -197,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')
+ 
+     mapping = sql.Table(
+@@ -211,7 +213,7 @@ def upgrade(migrate_engine):
+             mapping_backend.EntityType.GROUP,
+             name='entity_type'),
+             nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+ 
+     domain_config_whitelist = sql.Table(
+@@ -221,7 +223,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')
+ 
+     domain_config_sensitive = sql.Table(
+@@ -231,7 +233,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')
+ 
+     # create all tables
+--- keystone-9.1.0/keystone/common/sql/migrate_repo/versions/073_insert_assignment_inherited_pk.py.orig	2016-08-04 10:10:40.619013471 -0700
++++ keystone-9.1.0/keystone/common/sql/migrate_repo/versions/073_insert_assignment_inherited_pk.py	2016-08-04 10:18:06.349087340 -0700
+@@ -11,11 +11,13 @@
+ # under the License.
+ 
+ import migrate
++from oslo_config import cfg
+ import sqlalchemy as sql
+ from sqlalchemy.orm import sessionmaker
+ 
+ from keystone.assignment.backends import sql as assignment_sql
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     """Inserts inherited column to assignment table PK constraints.
+@@ -57,7 +59,7 @@ def upgrade(migrate_engine):
+                        nullable=False),
+             sql.PrimaryKeyConstraint('type', 'actor_id', 'target_id',
+                                      'role_id', 'inherited'),
+-            mysql_engine='InnoDB',
++            mysql_engine=CONF.database.mysql_storage_engine,
+             mysql_charset='utf8')
+ 
+         # Create the new assignment table
+--- keystone-9.1.0/keystone/common/sql/migrate_repo/versions/075_confirm_config_registration.py.orig	2016-08-04 10:10:47.746776861 -0700
++++ keystone-9.1.0/keystone/common/sql/migrate_repo/versions/075_confirm_config_registration.py	2016-08-04 10:19:03.802564813 -0700
+@@ -10,9 +10,11 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
++from oslo_config import cfg
+ import sqlalchemy as sql
+ 
+ REGISTRATION_TABLE = 'config_register'
++CONF = cfg.CONF
+ 
+ 
+ def upgrade(migrate_engine):
+@@ -24,6 +26,6 @@ def upgrade(migrate_engine):
+         meta,
+         sql.Column('type', sql.String(64), primary_key=True),
+         sql.Column('domain_id', sql.String(64), nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+     registration_table.create(migrate_engine, checkfirst=True)
+--- keystone-9.1.0/keystone/common/sql/migrate_repo/versions/081_add_endpoint_policy_table.py.orig	2016-08-04 10:10:53.258335033 -0700
++++ keystone-9.1.0/keystone/common/sql/migrate_repo/versions/081_add_endpoint_policy_table.py	2016-08-04 10:20:06.575865756 -0700
+@@ -12,10 +12,12 @@
+ # License for the specific language governing permissions and limitations
+ # under the License.
+ 
++from oslo_config import cfg
+ import sqlalchemy as sql
+ 
+ from keystone.common.sql import migration_helpers
+ 
++CONF = cfg.CONF
+ 
+ def upgrade(migrate_engine):
+     try:
+@@ -48,7 +50,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-9.1.0/keystone/common/sql/migrate_repo/versions/082_add_federation_tables.py.orig	2016-08-04 10:10:59.098720956 -0700
++++ keystone-9.1.0/keystone/common/sql/migrate_repo/versions/082_add_federation_tables.py	2016-08-04 10:22:41.994100588 -0700
+@@ -45,7 +45,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)
+ 
+@@ -57,7 +57,7 @@ def upgrade(migrate_engine):
+                    sql.ForeignKey('identity_provider.id', ondelete='CASCADE'),
+                    primary_key=True),
+         sql.Column('mapping_id', sql.String(64), nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+     federation_protocol_table.create(migrate_engine, checkfirst=True)
+ 
+@@ -66,7 +66,7 @@ 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)
+ 
+@@ -81,7 +81,7 @@ def upgrade(migrate_engine):
+         sql.Column('sp_url', sql.String(256), nullable=False),
+         sql.Column(_RELAY_STATE_PREFIX, sql.String(256), nullable=False,
+                    server_default=relay_state_prefix_default),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+     sp_table.create(migrate_engine, checkfirst=True)
+ 
+@@ -92,6 +92,6 @@ def upgrade(migrate_engine):
+         sql.Column('idp_id', sql.String(64),
+                    sql.ForeignKey('identity_provider.id', ondelete='CASCADE')),
+         sql.Column('remote_id', sql.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-9.1.0/keystone/common/sql/migrate_repo/versions/087_implied_roles.py.orig	2016-08-04 10:11:04.322293468 -0700
++++ keystone-9.1.0/keystone/common/sql/migrate_repo/versions/087_implied_roles.py	2016-08-04 10:23:34.919749416 -0700
+@@ -12,10 +12,12 @@
+ 
+ 
+ import migrate
++from oslo_config import cfg
+ import sqlalchemy as sql
+ 
+ 
+ ROLE_TABLE = 'role'
++CONF = cfg.CONF
+ 
+ 
+ def upgrade(migrate_engine):
+@@ -27,7 +29,7 @@ def upgrade(migrate_engine):
+         sql.Column('prior_role_id', sql.String(length=64), primary_key=True),
+         sql.Column(
+             'implied_role_id', sql.String(length=64), primary_key=True),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8')
+     implied_role.create()
+     role = sql.Table(ROLE_TABLE, meta, autoload=True)
--- a/components/openstack/neutron/files/neutron.conf	Thu Sep 08 12:41:54 2016 -0700
+++ b/components/openstack/neutron/files/neutron.conf	Thu Sep 08 13:16:06 2016 -0600
@@ -708,6 +708,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/neutron/patches/11-mysql_cluster_support.patch	Thu Sep 08 13:16:06 2016 -0600
@@ -0,0 +1,630 @@
+This patchset is for bug:
+
+24394574 Mitaka Neutron should 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 has not been committed upstream, but has been filed in launchpad:
+
+https://bugs.launchpad.net/neutron/+bug/1564110
+
+
+--- neutron-8.1.2/neutron/db/agents_db.py.orig	2016-08-25 14:48:36.647874143 -0700
++++ neutron-8.1.2/neutron/db/agents_db.py	2016-08-25 15:25:50.307210666 -0700
+@@ -73,6 +73,7 @@ AGENT_OPTS = [
+                        "agent until admin changes admin_state_up to True.")),
+ ]
+ cfg.CONF.register_opts(AGENT_OPTS)
++CONF = cfg.CONF
+ 
+ # this is the ratio from agent_down_time to the time we use to consider
+ # the agents down for considering their resource versions in the
+@@ -90,10 +91,17 @@ class Agent(model_base.BASEV2, model_bas
+     )
+ 
+     # L3 agent, DHCP agent, OVS agent, LinuxBridge
+-    agent_type = sa.Column(sa.String(255), nullable=False)
+-    binary = sa.Column(sa.String(255), nullable=False)
+-    # TOPIC is a fanout exchange topic
+-    topic = sa.Column(sa.String(255), nullable=False)
++    if CONF.database.mysql_storage_engine == 'NDBCLUSTER':
++        agent_type = sa.Column(sa.String(128), nullable=False)
++        binary = sa.Column(sa.String(128), nullable=False)
++        # TOPIC is a fanout exchange topic
++        topic = sa.Column(sa.String(128), nullable=False)
++    else:
++        agent_type = sa.Column(sa.String(255), nullable=False)
++        binary = sa.Column(sa.String(255), nullable=False)
++        # TOPIC is a fanout exchange topic
++        topic = sa.Column(sa.String(255), nullable=False)
++
+     # TOPIC.host is a target topic
+     host = sa.Column(sa.String(255), nullable=False)
+     availability_zone = sa.Column(sa.String(255))
+@@ -108,11 +116,17 @@ class Agent(model_base.BASEV2, model_bas
+     # description is note for admin user
+     description = sa.Column(sa.String(attributes.DESCRIPTION_MAX_LEN))
+     # configurations: a json dict string, I think 4095 is enough
+-    configurations = sa.Column(sa.String(4095), nullable=False)
++    if CONF.database.mysql_storage_engine == 'NDBCLUSTER':
++        configurations = sa.Column(sa.Text(), nullable=False)
++    else:
++        configurations = sa.Column(sa.String(4095), nullable=False)
+     # resource_versions: json dict, 8191 allows for ~256 resource versions
+     #                    assuming ~32byte length "'name': 'ver',"
+     #                    the whole row limit is 65535 bytes in mysql
+-    resource_versions = sa.Column(sa.String(8191))
++    if CONF.database.mysql_storage_engine == 'NDBCLUSTER':
++        resource_versions = sa.Column(sa.Text())
++    else:
++        resource_versions = sa.Column(sa.String(8191))
+     # load - number of resources hosted by the agent
+     load = sa.Column(sa.Integer, server_default='0', nullable=False)
+ 
+--- neutron-8.1.2/neutron/db/api.py.orig	2016-08-25 14:46:46.198992228 -0700
++++ neutron-8.1.2/neutron/db/api.py	2016-08-25 14:43:31.067614686 -0700
+@@ -37,6 +37,8 @@ retry_db_errors = oslo_db_api.wrap_db_re
+     exception_checker=is_deadlock
+ )
+ 
++CONF = cfg.CONF
++
+ 
+ @contextlib.contextmanager
+ def exc_to_retry(exceptions):
+@@ -81,12 +83,22 @@ def get_session(autocommit=True, expire_
+ @contextlib.contextmanager
+ def autonested_transaction(sess):
+     """This is a convenience method to not bother with 'nested' parameter."""
+-    if sess.is_active:
+-        session_context = sess.begin(nested=True)
++    # MySQL Cluster does not support nested operations.
++    if CONF.database.mysql_storage_engine == "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:
+-        session_context = sess.begin(subtransactions=True)
+-    with session_context as tx:
+-        yield tx
++        if sess.is_active:
++            session_context = sess.begin(nested=True)
++        else:
++            session_context = sess.begin(subtransactions=True)
++        with session_context as tx:
++            yield tx
+ 
+ 
+ # Common database operation implementations
+--- neutron-8.1.2/neutron/db/flavors_db.py.orig	2016-08-25 15:01:44.265969231 -0700
++++ neutron-8.1.2/neutron/db/flavors_db.py	2016-08-25 15:03:44.220882633 -0700
+@@ -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 oslo_utils import uuidutils
+ import sqlalchemy as sa
+@@ -26,6 +27,8 @@ from neutron.extensions import flavors a
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
++
+ 
+ class Flavor(model_base.BASEV2, model_base.HasId):
+     name = sa.Column(sa.String(attr.NAME_MAX_LEN))
+@@ -43,7 +46,10 @@ class ServiceProfile(model_base.BASEV2,
+     driver = sa.Column(sa.String(1024), nullable=False)
+     enabled = sa.Column(sa.Boolean, nullable=False, default=True,
+                         server_default=sa.sql.true())
+-    metainfo = sa.Column(sa.String(4096))
++    if CONF.database.mysql_storage_engine == 'NDBCLUSTER':
++        metainfo = sa.Column(sa.Text())
++    else:
++        metainfo = sa.Column(sa.String(4096))
+     flavors = orm.relationship("FlavorServiceProfileBinding")
+ 
+ 
+--- neutron-8.1.2/neutron/db/migration/alembic_migrations/agent_init_ops.py.orig	2016-08-25 14:46:52.869757151 -0700
++++ neutron-8.1.2/neutron/db/migration/alembic_migrations/agent_init_ops.py	2016-08-25 14:43:31.069947973 -0700
+@@ -18,26 +18,53 @@
+ # 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
++
+ 
+ def upgrade():
+-    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,
+-                  server_default=sa.sql.true()),
+-        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.Column('load', sa.Integer(), server_default='0', nullable=False),
+-        sa.PrimaryKeyConstraint('id'),
+-        sa.UniqueConstraint('agent_type', 'host',
+-                            name='uniq_agents0agent_type0host'))
++    # MySQL Cluster limits rows to 14,000 characters. This adjusts the
++    # columns to fit within that limit. Excessively large columns are
++    # converted to TEXT.
++    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=128), nullable=False),
++            sa.Column('binary', sa.String(length=128), nullable=False),
++            sa.Column('topic', sa.String(length=128), nullable=False),
++            sa.Column('host', sa.String(length=255), nullable=False),
++            sa.Column('admin_state_up', sa.Boolean(), nullable=False,
++                      server_default=sa.sql.true()),
++            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.Text(), nullable=False),
++            sa.Column('load', sa.Integer(), server_default='0', nullable=False),
++            sa.PrimaryKeyConstraint('id'),
++            sa.UniqueConstraint('agent_type', 'host',
++                                name='uniq_agents0agent_type0host'))
++    else:
++        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,
++                      server_default=sa.sql.true()),
++            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.Column('load', sa.Integer(), server_default='0', nullable=False),
++            sa.PrimaryKeyConstraint('id'),
++            sa.UniqueConstraint('agent_type', 'host',
++                                name='uniq_agents0agent_type0host'))
+--- neutron-8.1.2/neutron/db/migration/alembic_migrations/dvr_init_opts.py.orig	2016-08-25 14:46:59.635718601 -0700
++++ neutron-8.1.2/neutron/db/migration/alembic_migrations/dvr_init_opts.py	2016-08-25 14:43:31.071309141 -0700
+@@ -15,9 +15,13 @@
+ 
+ # Initial operations for dvr
+ 
++from alembic import context
+ from alembic import op
+ import sqlalchemy as sa
+ 
++config = context.config
++CONF = config.neutron_config
++
+ 
+ def upgrade():
+     op.create_table(
+@@ -27,23 +31,43 @@ def upgrade():
+                   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(u'status', sa.String(16), nullable=False),
+-        sa.ForeignKeyConstraint(['port_id'], ['ports.id'],
+-                                ondelete='CASCADE'),
+-        sa.PrimaryKeyConstraint('port_id', 'host')
+-    )
++    # MySQL Cluster limits rows to 14,000 characters. This adjusts the
++    # columns to fit within that limit. Excessively large columns are
++    # converted to TEXT.
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        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.Text(), nullable=False),
++            sa.Column('vnic_type', sa.String(length=64),
++                      nullable=False, server_default='normal'),
++            sa.Column('profile', sa.Text(), nullable=False),
++            sa.Column(u'status', sa.String(16), nullable=False),
++            sa.ForeignKeyConstraint(['port_id'], ['ports.id'],
++                                    ondelete='CASCADE'),
++            sa.PrimaryKeyConstraint('port_id', 'host')
++        )
++    else:
++        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(u'status', sa.String(16), nullable=False),
++            sa.ForeignKeyConstraint(['port_id'], ['ports.id'],
++                                    ondelete='CASCADE'),
++            sa.PrimaryKeyConstraint('port_id', 'host')
++        )
+     op.create_table(
+         'csnat_l3_agent_bindings',
+         sa.Column('router_id', sa.String(length=36), nullable=False),
+--- neutron-8.1.2/neutron/db/migration/alembic_migrations/env.py.orig	2016-08-25 14:47:07.700975613 -0700
++++ neutron-8.1.2/neutron/db/migration/alembic_migrations/env.py	2016-08-25 14:43:31.072607136 -0700
+@@ -34,6 +34,7 @@ except ImportError:
+ 
+ 
+ MYSQL_ENGINE = None
++MYSQL_STORAGE_ENGINE = None
+ 
+ # this is the Alembic Config object, which provides
+ # access to the values within the .ini file in use.
+@@ -59,6 +60,16 @@ def set_mysql_engine():
+                     model_base.BASEV2.__table_args__['mysql_engine'])
+ 
+ 
++def set_mysql_storage_engine():
++    try:
++        mysql_storage_engine = neutron_config.database.mysql_storage_engine
++    except cfg.NoSuchOptError:
++        mysql_storage_engine = InnoDB
++
++    global MYSQL_STORAGE_ENGINE
++    MYSQL_STORAGE_ENGINE = mysql_storage_engine
++
++
+ def include_object(object_, name, type_, reflected, compare_to):
+     if type_ == 'table' and name in external.TABLES:
+         return False
+@@ -81,6 +92,7 @@ def run_migrations_offline():
+ 
+     """
+     set_mysql_engine()
++    set_mysql_storage_engine()
+ 
+     kwargs = dict()
+     if neutron_config.database.connection:
+@@ -108,6 +120,7 @@ def run_migrations_online():
+ 
+     """
+     set_mysql_engine()
++    set_mysql_storage_engine()
+     connection = config.attributes.get('connection')
+     with DBConnection(neutron_config.database.connection, connection) as conn:
+         context.configure(
+--- neutron-8.1.2/neutron/db/migration/alembic_migrations/ml2_init_ops.py.orig	2016-08-25 14:47:14.579387371 -0700
++++ neutron-8.1.2/neutron/db/migration/alembic_migrations/ml2_init_ops.py	2016-08-25 14:43:31.074019618 -0700
+@@ -16,9 +16,13 @@
+ # Initial operations for ML2 plugin and drivers
+ 
+ 
++from alembic import context
+ from alembic import op
+ import sqlalchemy as sa
+ 
++config = context.config
++CONF = config.neutron_config
++
+ 
+ def upgrade():
+     op.create_table(
+@@ -83,21 +87,39 @@ def upgrade():
+                                 ondelete='CASCADE'),
+         sa.PrimaryKeyConstraint('id'))
+ 
+-    op.create_table(
+-        'ml2_port_bindings',
+-        sa.Column('port_id', sa.String(length=36), nullable=False),
+-        sa.Column('host', sa.String(length=255), nullable=False,
+-                  server_default=''),
+-        sa.Column('vif_type', sa.String(length=64), nullable=False),
+-        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('vif_details', sa.String(length=4095), nullable=False,
+-                  server_default=''),
+-        sa.ForeignKeyConstraint(['port_id'], ['ports.id'],
+-                                ondelete='CASCADE'),
+-        sa.PrimaryKeyConstraint('port_id'))
++    # MySQL Cluster limits rows to 14,000 characters. This adjusts the
++    # columns to fit within that limit. Excessively large columns are
++    # converted to TEXT.
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        op.create_table(
++            'ml2_port_bindings',
++            sa.Column('port_id', sa.String(length=36), nullable=False),
++            sa.Column('host', sa.String(length=255), nullable=False,
++                      server_default=''),
++            sa.Column('vif_type', sa.String(length=64), nullable=False),
++            sa.Column('vnic_type', sa.String(length=64), nullable=False,
++                      server_default='normal'),
++            sa.Column('profile', sa.Text(), nullable=False),
++            sa.Column('vif_details', sa.Text(), nullable=False),
++            sa.ForeignKeyConstraint(['port_id'], ['ports.id'],
++                                    ondelete='CASCADE'),
++            sa.PrimaryKeyConstraint('port_id'))
++    else:
++        op.create_table(
++            'ml2_port_bindings',
++            sa.Column('port_id', sa.String(length=36), nullable=False),
++            sa.Column('host', sa.String(length=255), nullable=False,
++                      server_default=''),
++            sa.Column('vif_type', sa.String(length=64), nullable=False),
++            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('vif_details', sa.String(length=4095), nullable=False,
++                      server_default=''),
++            sa.ForeignKeyConstraint(['port_id'], ['ports.id'],
++                                    ondelete='CASCADE'),
++            sa.PrimaryKeyConstraint('port_id'))
+ 
+     op.create_table(
+         'ml2_port_binding_levels',
+--- neutron-8.1.2/neutron/db/migration/alembic_migrations/versions/liberty/expand/31337ec0ffee_flavors.py.orig	2016-08-25 14:47:21.341890981 -0700
++++ neutron-8.1.2/neutron/db/migration/alembic_migrations/versions/liberty/expand/31337ec0ffee_flavors.py	2016-08-25 14:43:31.076633173 -0700
+@@ -24,9 +24,13 @@ Create Date: 2014-07-17 03:00:00.00
+ revision = '313373c0ffee'
+ down_revision = '52c5312f6baf'
+ 
++from alembic import context
+ from alembic import op
+ import sqlalchemy as sa
+ 
++config = context.config
++CONF = config.neutron_config
++
+ 
+ def upgrade():
+     op.create_table(
+@@ -40,16 +44,31 @@ def upgrade():
+         sa.PrimaryKeyConstraint('id')
+     )
+ 
+-    op.create_table(
+-        'serviceprofiles',
+-        sa.Column('id', sa.String(36)),
+-        sa.Column('description', sa.String(1024)),
+-        sa.Column('driver', sa.String(1024), nullable=False),
+-        sa.Column('enabled', sa.Boolean, nullable=False,
+-                  server_default=sa.sql.true()),
+-        sa.Column('metainfo', sa.String(4096)),
+-        sa.PrimaryKeyConstraint('id')
+-    )
++    # MySQL Cluster limits rows to 14,000 characters. This adjusts the
++    # columns to fit within that limit. Excessively large columns are
++    # converted to TEXT.
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        op.create_table(
++            'serviceprofiles',
++            sa.Column('id', sa.String(36)),
++            sa.Column('description', sa.String(1024)),
++            sa.Column('driver', sa.String(1024), nullable=False),
++            sa.Column('enabled', sa.Boolean, nullable=False,
++                      server_default=sa.sql.true()),
++            sa.Column('metainfo', sa.Text()),
++            sa.PrimaryKeyConstraint('id')
++        )
++    else:
++        op.create_table(
++            'serviceprofiles',
++            sa.Column('id', sa.String(36)),
++            sa.Column('description', sa.String(1024)),
++            sa.Column('driver', sa.String(1024), nullable=False),
++            sa.Column('enabled', sa.Boolean, nullable=False,
++                      server_default=sa.sql.true()),
++            sa.Column('metainfo', sa.String(4096)),
++            sa.PrimaryKeyConstraint('id')
++        )
+ 
+     op.create_table(
+         'flavorserviceprofilebindings',
+--- neutron-8.1.2/neutron/db/migration/alembic_migrations/versions/mitaka/expand/31ed664953e6_add_resource_versions_row_to_agent_table.py.orig	2016-08-25 14:47:28.407786618 -0700
++++ neutron-8.1.2/neutron/db/migration/alembic_migrations/versions/mitaka/expand/31ed664953e6_add_resource_versions_row_to_agent_table.py	2016-08-25 14:43:31.079354015 -0700
+@@ -25,10 +25,21 @@ Create Date: 2016-01-15 13:41:30.016915
+ revision = '31ed664953e6'
+ down_revision = '15e43b934f81'
+ 
++from alembic import context
+ from alembic import op
+ import sqlalchemy as sa
+ 
++config = context.config
++CONF = config.neutron_config
++
+ 
+ def upgrade():
+-    op.add_column('agents',
+-                  sa.Column('resource_versions', sa.String(length=8191)))
++    # MySQL Cluster limits rows to 14,000 characters. This adjusts the
++    # columns to fit within that limit. Excessively large columns are
++    # converted to TEXT.
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        op.add_column('agents',
++                      sa.Column('resource_versions', sa.Text()))
++    else:
++        op.add_column('agents',
++                      sa.Column('resource_versions', sa.String(length=8191)))
+--- neutron-8.1.2/neutron/db/migration/cli.py.orig	2016-08-25 14:47:38.390828076 -0700
++++ neutron-8.1.2/neutron/db/migration/cli.py	2016-08-25 14:43:31.081266845 -0700
+@@ -103,6 +103,9 @@ _db_opts = [
+                default='',
+                help=_('Database engine for which script will be generated '
+                       'when using offline migration.')),
++    cfg.StrOpt('mysql_storage_engine',
++               default='InnoDB',
++               help=_('MySQL Storage Engine')),
+ ]
+ 
+ CONF = cfg.ConfigOpts()
+--- neutron-8.1.2/neutron/db/model_base.py.orig	2016-08-25 14:47:46.388723853 -0700
++++ neutron-8.1.2/neutron/db/model_base.py	2016-08-25 14:43:31.082371798 -0700
+@@ -13,6 +13,8 @@
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ 
++from alembic import context
++from oslo_config import cfg
+ from oslo_db.sqlalchemy import models
+ from oslo_utils import uuidutils
+ import sqlalchemy as sa
+@@ -22,6 +24,15 @@ from sqlalchemy import orm
+ 
+ from neutron.api.v2 import attributes as attr
+ 
++# Attempt to determine the context that this module is being used.
++# If via neutron-db-manage and alembic, use alembic context. If not,
++# use oslo_config.
++try:
++    config = context.config
++    CONF = config.neutron_config
++except AttributeError:
++    CONF = cfg.CONF
++
+ 
+ class HasTenant(object):
+     """Tenant mixin, add to subclasses that have a tenant."""
+@@ -48,7 +59,7 @@ class HasStatusDescription(object):
+ class NeutronBase(models.ModelBase):
+     """Base class for Neutron Models."""
+ 
+-    __table_args__ = {'mysql_engine': 'InnoDB'}
++    __table_args__ = {'mysql_engine': CONF.database.mysql_storage_engine}
+ 
+     def __iter__(self):
+         self._i = iter(orm.object_mapper(self).columns)
+--- neutron-8.1.2/neutron/plugins/ml2/models.py.orig	2016-08-25 15:03:58.107501050 -0700
++++ neutron-8.1.2/neutron/plugins/ml2/models.py	2016-08-25 15:22:24.556984578 -0700
+@@ -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
+ 
+@@ -22,6 +23,8 @@ from neutron.extensions import portbindi
+ 
+ BINDING_PROFILE_LEN = 4095
+ 
++CONF = cfg.CONF
++
+ 
+ class NetworkSegment(model_base.BASEV2, model_base.HasId):
+     """Represent persistent state of a network segment.
+@@ -63,11 +66,22 @@ class PortBinding(model_base.BASEV2):
+     vnic_type = sa.Column(sa.String(64), nullable=False,
+                           default=portbindings.VNIC_NORMAL,
+                           server_default=portbindings.VNIC_NORMAL)
+-    profile = sa.Column(sa.String(BINDING_PROFILE_LEN), nullable=False,
+-                        default='', server_default='')
++
++    if CONF.database.mysql_storage_engine == 'NDBCLUSTER':
++        profile = sa.Column(sa.Text(), nullable=False,
++                            default='', server_default='')
++    else:
++        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='',
+-                            server_default='')
++
++    if CONF.database.mysql_storage_engine == 'NDBCLUSTER':
++        vif_details = sa.Column(sa.Text(), nullable=False, default='',
++                                server_default='')
++    else:
++        vif_details = sa.Column(sa.String(4095), nullable=False, default='',
++                                server_default='')
+ 
+     # Add a relationship to the Port model in order to instruct SQLAlchemy to
+     # eagerly load port bindings
+@@ -113,13 +127,25 @@ class DVRPortBinding(model_base.BASEV2):
+     host = sa.Column(sa.String(255), nullable=False, primary_key=True)
+     router_id = sa.Column(sa.String(36), nullable=True)
+     vif_type = sa.Column(sa.String(64), nullable=False)
+-    vif_details = sa.Column(sa.String(4095), nullable=False, default='',
+-                            server_default='')
++
++    if CONF.database.mysql_storage_engine == 'NDBCLUSTER':
++        vif_details = sa.Column(sa.Text(), nullable=False, default='',
++                                server_default='')
++    else:
++        vif_details = sa.Column(sa.String(4095), nullable=False, default='',
++                                server_default='')
++
+     vnic_type = sa.Column(sa.String(64), nullable=False,
+                           default=portbindings.VNIC_NORMAL,
+                           server_default=portbindings.VNIC_NORMAL)
+-    profile = sa.Column(sa.String(BINDING_PROFILE_LEN), nullable=False,
+-                        default='', server_default='')
++
++    if CONF.database.mysql_storage_engine == 'NDBCLUSTER':
++        profile = sa.Column(sa.Text(), nullable=False,
++                            default='', server_default='')
++    else:
++        profile = sa.Column(sa.String(BINDING_PROFILE_LEN), nullable=False,
++                            default='', server_default='')
++
+     status = sa.Column(sa.String(16), nullable=False)
+ 
+     # Add a relationship to the Port model in order to instruct SQLAlchemy to
+--- neutron-8.1.2/neutron/tests/functional/db/test_migrations.py.orig	2016-08-25 14:47:53.221640215 -0700
++++ neutron-8.1.2/neutron/tests/functional/db/test_migrations.py	2016-08-25 14:43:31.084056418 -0700
+@@ -30,6 +30,7 @@ from neutron.db.migration.models import
+ from neutron.tests.common import base
+ 
+ cfg.CONF.import_opt('core_plugin', 'neutron.common.config')
++CONF = cfg.CONF
+ 
+ CORE_PLUGIN = 'neutron.plugins.ml2.plugin.Ml2Plugin'
+ 
+@@ -273,7 +274,7 @@ class TestModelsMigrationsMysql(_TestMod
+             self.assertTrue(len(tables) > 0,
+                             "No tables found. Wrong schema?")
+             res = [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(res), "%s non InnoDB tables created" % res)
+ 
--- a/components/openstack/nova/files/nova.conf	Thu Sep 08 12:41:54 2016 -0700
+++ b/components/openstack/nova/files/nova.conf	Thu Sep 08 13:16:06 2016 -0600
@@ -2181,6 +2181,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)
 #idle_timeout = 3600
 
@@ -3159,6 +3165,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/nova/patches/13-mysql_cluster_support.patch	Thu Sep 08 13:16:06 2016 -0600
@@ -0,0 +1,1300 @@
+This patchset is for bug:
+
+24394587 Mitaka Nova should 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-13.1.0/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/001_cell_mapping.py.orig	2016-08-24 14:22:51.920016201 -0700
++++ nova-13.1.0/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/001_cell_mapping.py	2016-08-24 14:22:34.974838825 -0700
+@@ -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,8 @@ from sqlalchemy import String
+ from sqlalchemy import Table
+ from sqlalchemy import Text
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -34,7 +37,7 @@ def upgrade(migrate_engine):
+         Column('transport_url', Text()),
+         Column('database_connection', Text()),
+         UniqueConstraint('uuid', name='uniq_cell_mappings0uuid'),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+--- nova-13.1.0/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/002_instance_mapping.py.orig	2016-08-24 14:22:59.979100128 -0700
++++ nova-13.1.0/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/002_instance_mapping.py	2016-08-24 14:22:34.976482225 -0700
+@@ -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,8 @@ from sqlalchemy import MetaData
+ from sqlalchemy import String
+ from sqlalchemy import Table
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -38,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'
+     )
+ 
+--- nova-13.1.0/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/003_host_mapping.py.orig	2016-08-24 14:23:07.246721338 -0700
++++ nova-13.1.0/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/003_host_mapping.py	2016-08-24 14:22:34.977720063 -0700
+@@ -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,8 @@ from sqlalchemy import MetaData
+ from sqlalchemy import String
+ from sqlalchemy import Table
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -36,7 +39,7 @@ def upgrade(migrate_engine):
+             name='uniq_host_mappings0host'),
+         ForeignKeyConstraint(columns=['cell_id'],
+             refcolumns=[cell_mappings.c.id]),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+--- nova-13.1.0/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/004_add_request_spec.py.orig	2016-08-24 14:23:13.631755716 -0700
++++ nova-13.1.0/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/004_add_request_spec.py	2016-08-24 14:22:34.978932430 -0700
+@@ -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,8 @@ from sqlalchemy import String
+ from sqlalchemy import Table
+ from sqlalchemy import Text
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -33,7 +36,7 @@ def upgrade(migrate_engine):
+         Column('spec', Text, nullable=False),
+         UniqueConstraint('instance_uuid',
+             name='uniq_request_specs0instance_uuid'),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+--- nova-13.1.0/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/005_flavors.py.orig	2016-08-24 14:23:20.047706518 -0700
++++ nova-13.1.0/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/005_flavors.py	2016-08-24 14:22:34.980360970 -0700
+@@ -12,6 +12,7 @@
+ 
+ from migrate.changeset.constraint import ForeignKeyConstraint
+ from migrate import UniqueConstraint
++from oslo_config import cfg
+ from sqlalchemy import Boolean
+ from sqlalchemy import Column
+ from sqlalchemy import DateTime
+@@ -22,6 +23,8 @@ from sqlalchemy import MetaData
+ from sqlalchemy import String
+ from sqlalchemy import Table
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -44,7 +47,7 @@ def upgrade(migrate_engine):
+         Column('is_public', Boolean),
+         UniqueConstraint("flavorid", name="uniq_flavors0flavorid"),
+         UniqueConstraint("name", name="uniq_flavors0name"),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+     flavors.create(checkfirst=True)
+@@ -59,7 +62,7 @@ def upgrade(migrate_engine):
+         UniqueConstraint('flavor_id', 'key',
+             name='uniq_flavor_extra_specs0flavor_id0key'),
+         ForeignKeyConstraint(columns=['flavor_id'], refcolumns=[flavors.c.id]),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -82,7 +85,7 @@ def upgrade(migrate_engine):
+             name='uniq_flavor_projects0flavor_id0project_id'),
+         ForeignKeyConstraint(columns=['flavor_id'],
+             refcolumns=[flavors.c.id]),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+     flavor_projects.create(checkfirst=True)
+--- nova-13.1.0/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/006_build_request.py.orig	2016-08-24 14:23:28.058484501 -0700
++++ nova-13.1.0/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/006_build_request.py	2016-08-24 14:22:34.981684038 -0700
+@@ -12,6 +12,7 @@
+ 
+ from migrate.changeset.constraint import ForeignKeyConstraint
+ from migrate import UniqueConstraint
++from oslo_config import cfg
+ from sqlalchemy import Boolean
+ from sqlalchemy import Column
+ from sqlalchemy import DateTime
+@@ -24,6 +25,8 @@ from sqlalchemy import String
+ from sqlalchemy import Table
+ from sqlalchemy import Text
+ 
++CONF = cfg.CONF
++
+ 
+ def InetSmall():
+     return String(length=39).with_variant(dialects.postgresql.INET(),
+@@ -61,7 +64,7 @@ def upgrade(migrate_engine):
+         Index('build_requests_project_id_idx', 'project_id'),
+         ForeignKeyConstraint(columns=['request_spec_id'],
+             refcolumns=[request_specs.c.id]),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+--- nova-13.1.0/nova/db/sqlalchemy/migrate_repo/versions/216_havana.py.orig	2016-08-24 14:23:37.472011893 -0700
++++ nova-13.1.0/nova/db/sqlalchemy/migrate_repo/versions/216_havana.py	2016-08-24 14:22:34.987060556 -0700
+@@ -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,8 @@ from nova.i18n import _LE
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
++
+ 
+ # Note on the autoincrement flag: this is defaulted for primary key columns
+ # of integral type, so is no longer set explicitly in such cases.
+@@ -37,6 +40,10 @@ def MediumText():
+     return Text().with_variant(dialects.mysql.MEDIUMTEXT(), 'mysql')
+ 
+ 
++def TinyText():
++    return Text().with_variant(dialects.mysql.TINYTEXT(), 'mysql')
++
++
+ def Inet():
+     return String(length=43).with_variant(dialects.postgresql.INET(),
+                   'postgresql')
+@@ -76,7 +83,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 +174,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()
+ 
+ 
+@@ -187,7 +194,7 @@ def upgrade(migrate_engine):
+         Column('url', String(length=255)),
+         Column('md5hash', String(length=255)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -200,7 +207,7 @@ def upgrade(migrate_engine):
+         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'
+     )
+ 
+@@ -214,7 +221,7 @@ def upgrade(migrate_engine):
+         Column('key', String(length=255), nullable=False),
+         Column('value', String(length=255), nullable=False),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -225,7 +232,7 @@ def upgrade(migrate_engine):
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('name', String(length=255)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -250,7 +257,7 @@ def upgrade(migrate_engine):
+         Column('disk_bus', String(length=255), 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'
+     )
+ 
+@@ -268,7 +275,7 @@ def upgrade(migrate_engine):
+         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'
+     )
+ 
+@@ -284,7 +291,7 @@ def upgrade(migrate_engine):
+         Column('is_parent', Boolean),
+         Column('deleted', Integer),
+         Column('transport_url', String(length=255), nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -297,7 +304,7 @@ def upgrade(migrate_engine):
+         Column('project_id', String(length=255)),
+         Column('file_name', String(length=255)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -310,7 +317,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'
+     )
+ 
+@@ -339,7 +346,7 @@ def upgrade(migrate_engine):
+         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'
+     )
+ 
+@@ -356,7 +363,7 @@ def upgrade(migrate_engine):
+         Column('host', String(length=255)),
+         Column('compute_host', String(length=255)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -379,7 +386,7 @@ def upgrade(migrate_engine):
+         Column('pool_id', Integer, ForeignKey('console_pools.id')),
+         Column(*consoles_instance_uuid_column_args),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -392,7 +399,7 @@ def upgrade(migrate_engine):
+         Column('scope', String(length=255)),
+         Column('availability_zone', String(length=255)),
+         Column('project_id', String(length=255)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -410,7 +417,7 @@ def upgrade(migrate_engine):
+         Column('host', String(length=255)),
+         Column('instance_uuid', String(length=36)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -427,7 +434,7 @@ def upgrade(migrate_engine):
+         Column('pool', String(length=255)),
+         Column('interface', String(length=255)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -442,7 +449,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'
+     )
+ 
+@@ -453,7 +460,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'
+     )
+ 
+@@ -465,7 +472,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'
+     )
+ 
+@@ -481,7 +488,7 @@ def upgrade(migrate_engine):
+         Column('name', String(length=255)),
+         UniqueConstraint('uuid', 'deleted',
+                          name='uniq_instance_groups0uuid0deleted'),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8',
+     )
+ 
+@@ -495,7 +502,7 @@ def upgrade(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',
+     )
+ 
+@@ -508,7 +515,7 @@ def upgrade(migrate_engine):
+         Column('policy', 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',
+     )
+ 
+@@ -521,7 +528,7 @@ def upgrade(migrate_engine):
+         Column('instance_id', 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',
+     )
+ 
+@@ -534,7 +541,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'
+     )
+ 
+@@ -547,7 +554,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'
+     )
+ 
+@@ -561,7 +568,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'
+     )
+ 
+@@ -573,7 +580,7 @@ def upgrade(migrate_engine):
+         Column('instance_type_id', Integer, nullable=False),
+         Column('project_id', String(length=255)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -594,67 +601,131 @@ def upgrade(migrate_engine):
+         Column('disabled', Boolean),
+         Column('is_public', Boolean),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+-    inst_lock_enum = Enum('owner', 'admin', name='instances0locked_by')
+-    instances = Table('instances', meta,
+-        Column('created_at', DateTime),
+-        Column('updated_at', DateTime),
+-        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('launch_index', Integer),
+-        Column('key_name', String(length=255)),
+-        Column('key_data', MediumText()),
+-        Column('power_state', Integer),
+-        Column('vm_state', String(length=255)),
+-        Column('memory_mb', Integer),
+-        Column('vcpus', Integer),
+-        Column('hostname', String(length=255)),
+-        Column('host', String(length=255)),
+-        Column('user_data', MediumText()),
+-        Column('reservation_id', String(length=255)),
+-        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('locked', Boolean),
+-        Column('os_type', String(length=255)),
+-        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('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('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('deleted', Integer),
+-        Column('locked_by', inst_lock_enum),
+-        Column('cleaned', Integer, default=0),
+-        mysql_engine='InnoDB',
+-        mysql_charset='utf8'
+-    )
++    # MySQL Cluster limits row lengths to 14,000 characters. The logic
++    # below modifies the 'instances' table so that it can fit within these
++    # constraints if NDBCLUSTER is set as the mysql_storage_engine. Columns
++    # that can be shrunk are, while others are converted to TinyText blobs
++    # which can hold 256 characters.
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        inst_lock_enum = Enum('owner', 'admin', name='instances0locked_by')
++        instances = Table('instances', meta,
++            Column('created_at', DateTime),
++            Column('updated_at', DateTime),
++            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', TinyText()),
++            Column('ramdisk_id', TinyText()),
++            Column('launch_index', Integer),
++            Column('key_name', TinyText()),
++            Column('key_data', MediumText()),
++            Column('power_state', Integer),
++            Column('vm_state', String(length=64)),
++            Column('memory_mb', Integer),
++            Column('vcpus', Integer),
++            Column('hostname', String(length=255)),
++            Column('host', String(length=255)),
++            Column('user_data', MediumText()),
++            Column('reservation_id', String(length=255)),
++            Column('scheduled_at', DateTime),
++            Column('launched_at', DateTime),
++            Column('terminated_at', DateTime),
++            Column('display_name', String(length=255)),
++            Column('display_description', TinyText()),
++            Column('availability_zone', TinyText()),
++            Column('locked', Boolean),
++            Column('os_type', String(length=64)),
++            Column('launched_on', MediumText()),
++            Column('instance_type_id', Integer),
++            Column('vm_mode', String(length=64)),
++            Column('uuid', String(length=36)),
++            Column('architecture', String(length=64)),
++            Column('root_device_name', String(length=64)),
++            Column('access_ip_v4', InetSmall()),
++            Column('access_ip_v6', InetSmall()),
++            Column('config_drive', TinyText()),
++            Column('task_state', String(length=64)),
++            Column('default_ephemeral_device', TinyText()),
++            Column('default_swap_device', TinyText()),
++            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('deleted', Integer),
++            Column('locked_by', inst_lock_enum),
++            Column('cleaned', Integer, default=0),
++            mysql_engine=CONF.database.mysql_storage_engine,
++            mysql_charset='utf8'
++        )
++    else:
++        inst_lock_enum = Enum('owner', 'admin', name='instances0locked_by')
++        instances = Table('instances', meta,
++            Column('created_at', DateTime),
++            Column('updated_at', DateTime),
++            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('launch_index', Integer),
++            Column('key_name', String(length=255)),
++            Column('key_data', MediumText()),
++            Column('power_state', Integer),
++            Column('vm_state', String(length=255)),
++            Column('memory_mb', Integer),
++            Column('vcpus', Integer),
++            Column('hostname', String(length=255)),
++            Column('host', String(length=255)),
++            Column('user_data', MediumText()),
++            Column('reservation_id', String(length=255)),
++            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('locked', Boolean),
++            Column('os_type', String(length=255)),
++            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('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('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('deleted', Integer),
++            Column('locked_by', inst_lock_enum),
++            Column('cleaned', Integer, default=0),
++            mysql_engine=CONF.database.mysql_storage_engine,
++            mysql_charset='utf8'
++        )
+ 
+     instance_actions = Table('instance_actions', meta,
+         Column('created_at', DateTime),
+@@ -670,7 +741,7 @@ def upgrade(migrate_engine):
+         Column('finish_time', DateTime),
+         Column('message', String(length=255)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8',
+     )
+ 
+@@ -686,7 +757,7 @@ def upgrade(migrate_engine):
+         Column('result', String(length=255)),
+         Column('traceback', Text),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8',
+     )
+ 
+@@ -699,7 +770,7 @@ def upgrade(migrate_engine):
+         Column('host', String(length=255)),
+         Column('volume_id', String(length=36), nullable=True),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -713,7 +784,7 @@ def upgrade(migrate_engine):
+         Column('fingerprint', String(length=255)),
+         Column('public_key', MediumText()),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -732,7 +803,7 @@ def upgrade(migrate_engine):
+         Column('source_node', String(length=255)),
+         Column('dest_node', String(length=255)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -766,7 +837,7 @@ def upgrade(migrate_engine):
+         Column('priority', Integer),
+         Column('rxtx_base', Integer),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -794,7 +865,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,
+@@ -807,7 +878,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'
+     )
+ 
+@@ -820,7 +891,7 @@ def upgrade(migrate_engine):
+         Column('resource', String(length=255)),
+         Column('hard_limit', Integer),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -836,7 +907,7 @@ def upgrade(migrate_engine):
+         Column('until_refresh', Integer),
+         Column('deleted', Integer),
+         Column('user_id', String(length=255)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -849,7 +920,7 @@ def upgrade(migrate_engine):
+         Column('resource', String(length=255), nullable=False),
+         Column('hard_limit', Integer),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -873,7 +944,7 @@ def upgrade(migrate_engine):
+                         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',
+                         )
+ 
+@@ -890,7 +961,7 @@ def upgrade(migrate_engine):
+         Column('expire', DateTime),
+         Column('deleted', Integer),
+         Column('user_id', String(length=255)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -901,7 +972,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'
+     )
+ 
+@@ -914,7 +985,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'
+     )
+ 
+@@ -930,7 +1001,7 @@ def upgrade(migrate_engine):
+         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'
+     )
+ 
+@@ -944,7 +1015,7 @@ def upgrade(migrate_engine):
+         Column('user_id', String(length=255)),
+         Column('project_id', String(length=255)),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -958,7 +1029,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',
+     )
+ 
+@@ -974,7 +1045,7 @@ def upgrade(migrate_engine):
+         Column('disabled', Boolean),
+         Column('deleted', Integer),
+         Column('disabled_reason', String(length=255)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -985,7 +1056,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'
+     )
+ 
+@@ -1004,7 +1075,7 @@ def upgrade(migrate_engine):
+         Column('display_name', String(length=255)),
+         Column('display_description', String(length=255)),
+         Column('deleted', String(length=36)),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -1022,7 +1093,7 @@ def upgrade(migrate_engine):
+         Column('task_items', Integer),
+         Column('errors', Integer),
+         Column('deleted', Integer),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='utf8'
+     )
+ 
+@@ -1036,7 +1107,7 @@ def upgrade(migrate_engine):
+         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'
+     )
+ 
+@@ -1047,7 +1118,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'
+     )
+ 
+@@ -1077,7 +1148,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'
+     )
+ 
+@@ -1102,7 +1173,7 @@ def upgrade(migrate_engine):
+             Column("project_id", String(length=36)),
+             Column("user_id", String(length=36)),
+             Column("availability_zone", String(length=255)),
+-            mysql_engine='InnoDB',
++            mysql_engine=CONF.database.mysql_storage_engine,
+             mysql_charset='utf8'
+     )
+ 
+@@ -1475,10 +1546,12 @@ def upgrade(migrate_engine):
+ 
+         # mysql-specific index by leftmost 100 chars.  (mysql gets angry if the
+         # index key length is too long.)
+-        sql = ("create index migrations_by_host_nodes_and_status_idx ON "
+-               "migrations (deleted, source_compute(100), dest_compute(100), "
+-               "source_node(100), dest_node(100), status)")
+-        migrate_engine.execute(sql)
++        # MySQL Cluster does not support index prefixes.
++        if CONF.database.mysql_storage_engine != "NDBCLUSTER":
++            sql = ("create index migrations_by_host_nodes_and_status_idx ON "
++                   "migrations (deleted, source_compute(100), dest_compute(100), "
++                   "source_node(100), dest_node(100), status)")
++            migrate_engine.execute(sql)
+ 
+     # PostgreSQL specific indexes
+     if migrate_engine.name == 'postgresql':
+--- nova-13.1.0/nova/db/sqlalchemy/migrate_repo/versions/249_remove_duplicate_index.py.orig	2016-08-24 14:23:44.593220901 -0700
++++ nova-13.1.0/nova/db/sqlalchemy/migrate_repo/versions/249_remove_duplicate_index.py	2016-08-24 14:22:34.988854556 -0700
+@@ -13,7 +13,7 @@
+ #    License for the specific language governing permissions and limitations
+ #    under the License.
+ 
+-
++from migrate.changeset.constraint import ForeignKeyConstraint
+ from sqlalchemy import MetaData, Table
+ 
+ 
+@@ -25,7 +25,17 @@ 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()
+--- nova-13.1.0/nova/db/sqlalchemy/migrate_repo/versions/252_add_instance_extra_table.py.orig	2016-08-24 14:23:51.489446458 -0700
++++ nova-13.1.0/nova/db/sqlalchemy/migrate_repo/versions/252_add_instance_extra_table.py	2016-08-24 14:22:34.990323618 -0700
+@@ -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,8 @@ from sqlalchemy import String
+ from sqlalchemy import Table
+ from sqlalchemy import Text
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -42,7 +45,8 @@ 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-13.1.0/nova/db/sqlalchemy/migrate_repo/versions/266_add_instance_tags.py.orig	2016-08-24 14:23:58.465133071 -0700
++++ nova-13.1.0/nova/db/sqlalchemy/migrate_repo/versions/266_add_instance_tags.py	2016-08-24 14:22:34.991752728 -0700
+@@ -10,8 +10,11 @@
+ #    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,6 +25,6 @@ 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-13.1.0/nova/db/sqlalchemy/migrate_repo/versions/267_instance_uuid_non_nullable.py.orig	2016-08-24 14:24:04.907962418 -0700
++++ nova-13.1.0/nova/db/sqlalchemy/migrate_repo/versions/267_instance_uuid_non_nullable.py	2016-08-24 14:22:34.993331103 -0700
+@@ -13,6 +13,7 @@
+ #    under the License.
+ 
+ from migrate import UniqueConstraint
++from oslo_config import cfg
+ from oslo_log import log as logging
+ from sqlalchemy import MetaData
+ from sqlalchemy.sql import null
+@@ -24,6 +25,8 @@ LOG = logging.getLogger(__name__)
+ 
+ UC_NAME = 'uniq_instances0uuid'
+ 
++CONF = cfg.CONF
++
+ 
+ def scan_for_null_records(table, col_name, check_fkeys):
+     """Queries the table looking for NULL instances of the given column.
+@@ -96,10 +99,15 @@ def upgrade(migrate_engine):
+     # defined with cascading deletes.
+     meta = MetaData(migrate_engine)
+     meta.reflect(migrate_engine)
+-    # Scan the database first and fail if any NULL records found.
+-    process_null_records(meta, scan=True)
+-    # Now run the alter statements.
+-    process_null_records(meta, scan=False)
++
++    # MySQL Cluster creates non-NULL records by default. We can skip
++    # the checks and just configure the constraint.
++    if CONF.database.mysql_storage_engine != "NDBCLUSTER":
++        # Scan the database first and fail if any NULL records found.
++        process_null_records(meta, scan=True)
++        # Now run the alter statements.
++        process_null_records(meta, scan=False)
++
+     # Create a unique constraint on instances.uuid for foreign keys.
+     instances = meta.tables['instances']
+     UniqueConstraint('uuid', table=instances, name=UC_NAME).create()
+--- nova-13.1.0/nova/db/sqlalchemy/migrate_repo/versions/314_add_resource_provider_tables.py.orig	2016-08-24 14:24:12.780710808 -0700
++++ nova-13.1.0/nova/db/sqlalchemy/migrate_repo/versions/314_add_resource_provider_tables.py	2016-08-24 14:22:34.995184176 -0700
+@@ -12,6 +12,7 @@
+ """Database migrations for resource-providers."""
+ 
+ from migrate import UniqueConstraint
++from oslo_config import cfg
+ from sqlalchemy import Column
+ from sqlalchemy import Float
+ from sqlalchemy import Index
+@@ -20,6 +21,8 @@ from sqlalchemy import MetaData
+ from sqlalchemy import String
+ from sqlalchemy import Table
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData()
+@@ -30,7 +33,7 @@ def upgrade(migrate_engine):
+         Column('id', Integer, primary_key=True, nullable=False),
+         Column('uuid', String(36), nullable=False),
+         UniqueConstraint('uuid', name='uniq_resource_providers0uuid'),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='latin1'
+     )
+     # NOTE(mriedem): DB2 creates an index when a unique constraint is created
+@@ -50,7 +53,7 @@ def upgrade(migrate_engine):
+         Column('max_unit', Integer, nullable=False),
+         Column('step_size', Integer, nullable=False),
+         Column('allocation_ratio', Float, nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='latin1'
+     )
+     Index('inventories_resource_provider_id_idx',
+@@ -65,7 +68,7 @@ def upgrade(migrate_engine):
+         Column('consumer_id', String(36), nullable=False),
+         Column('resource_class_id', Integer, nullable=False),
+         Column('used', Integer, nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='latin1'
+     )
+     Index('allocations_resource_provider_class_id_idx',
+--- nova-13.1.0/nova/db/sqlalchemy/migrate_repo/versions/318_resource_provider_name_aggregates.py.orig	2016-08-24 14:24:19.484566325 -0700
++++ nova-13.1.0/nova/db/sqlalchemy/migrate_repo/versions/318_resource_provider_name_aggregates.py	2016-08-24 14:22:34.997184351 -0700
+@@ -11,6 +11,7 @@
+ #    under the License.
+ 
+ from migrate import UniqueConstraint
++from oslo_config import cfg
+ from oslo_db.sqlalchemy import utils
+ from sqlalchemy import Column
+ from sqlalchemy import DDL
+@@ -20,6 +21,8 @@ from sqlalchemy import MetaData
+ from sqlalchemy import Table
+ from sqlalchemy import Unicode
+ 
++CONF = cfg.CONF
++
+ 
+ def upgrade(migrate_engine):
+     meta = MetaData(bind=migrate_engine)
+@@ -66,7 +69,7 @@ def upgrade(migrate_engine):
+         Column('resource_provider_id', Integer, primary_key=True,
+                nullable=False),
+         Column('aggregate_id', Integer, primary_key=True, nullable=False),
+-        mysql_engine='InnoDB',
++        mysql_engine=CONF.database.mysql_storage_engine,
+         mysql_charset='latin1'
+     )
+     Index('resource_provider_aggregates_aggregate_id_idx',
+--- nova-13.1.0/nova/db/sqlalchemy/models.py.orig	2016-08-24 14:24:27.031251043 -0700
++++ nova-13.1.0/nova/db/sqlalchemy/models.py	2016-08-24 14:25:54.013809653 -0700
+@@ -20,6 +20,7 @@ SQLAlchemy models for nova data.
+ """
+ 
+ from oslo_config import cfg
++from oslo_db import options
+ from oslo_db.sqlalchemy import models
+ from oslo_utils import timeutils
+ from sqlalchemy import (Column, Index, Integer, BigInteger, Enum, String,
+@@ -33,12 +34,17 @@ from nova.db.sqlalchemy import types
+ 
+ CONF = cfg.CONF
+ BASE = declarative_base()
++options.set_defaults(cfg.CONF)
+ 
+ 
+ def MediumText():
+     return Text().with_variant(MEDIUMTEXT(), 'mysql')
+ 
+ 
++def TinyText():
++    return Text().with_variant(TINYTEXT(), 'mysql')
++
++
+ class NovaBase(models.TimestampMixin,
+                models.ModelBase):
+     metadata = None
+@@ -250,17 +256,32 @@ class Instance(BASE, NovaBase, models.So
+     project_id = Column(String(255))
+ 
+     image_ref = Column(String(255))
+-    kernel_id = Column(String(255))
+-    ramdisk_id = Column(String(255))
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        kernel_id = Column(TinyText())
++        ramdisk_id = Column(TinyText())
++    else:
++        kernel_id = Column(String(255))
++        ramdisk_id = Column(String(255))
++
+     hostname = Column(String(255))
+ 
+     launch_index = Column(Integer)
+-    key_name = Column(String(255))
++
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        key_name = Column(TinyText())
++    else:
++        key_name = Column(String(255))
++
+     key_data = Column(MediumText())
+ 
+     power_state = Column(Integer)
+-    vm_state = Column(String(255))
+-    task_state = Column(String(255))
++
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        vm_state = Column(String(64))
++        task_state = Column(String(64))
++    else:
++        vm_state = Column(String(255))
++        task_state = Column(String(255))
+ 
+     memory_mb = Column(Integer)
+     vcpus = Column(Integer)
+@@ -291,11 +312,17 @@ class Instance(BASE, NovaBase, models.So
+     # This always refers to the availability_zone kwarg passed in /servers and
+     # provided as an API option, not at all related to the host AZ the instance
+     # belongs to.
+-    availability_zone = Column(String(255))
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        availability_zone = Column(TinyText())
++    else:
++        availability_zone = Column(String(255))
+ 
+     # User editable field for display in user-facing UIs
+     display_name = Column(String(255))
+-    display_description = Column(String(255))
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        display_description = Column(TinyText())
++    else:
++        display_description = Column(String(255))
+ 
+     # To remember on which host an instance booted.
+     # An instance may have moved to another host by live migration.
+@@ -306,15 +333,27 @@ class Instance(BASE, NovaBase, models.So
+     locked = Column(Boolean)
+     locked_by = Column(Enum('owner', 'admin'))
+ 
+-    os_type = Column(String(255))
+-    architecture = Column(String(255))
+-    vm_mode = Column(String(255))
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        os_type = Column(String(64))
++        architecture = Column(String(64))
++        vm_mode = Column(String(64))
++    else:
++        os_type = Column(String(255))
++        architecture = Column(String(255))
++        vm_mode = Column(String(255))
++
+     uuid = Column(String(36), nullable=False)
+ 
+-    root_device_name = Column(String(255))
+-    default_ephemeral_device = Column(String(255))
+-    default_swap_device = Column(String(255))
+-    config_drive = Column(String(255))
++    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
++        root_device_name = Column(String(64))
++        default_ephemeral_device = Column(TinyText())
++        default_swap_device = Column(TinyText())
++        config_drive = Column(TinyText())
++    else:
++        root_device_name = Column(String(255))
++        default_ephemeral_device = Column(String(255))
++        default_swap_device = Column(String(255))
++        config_drive = Column(String(255))
+ 
+     # User editable field meant to represent what ip should be used
+     # to connect to the instance
+--- nova-13.1.0/nova/db/sqlalchemy/utils.py.orig	2016-08-24 14:24:33.499513020 -0700
++++ nova-13.1.0/nova/db/sqlalchemy/utils.py	2016-08-24 14:22:35.001433371 -0700
+@@ -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
+@@ -30,6 +31,8 @@ from nova.i18n import _, _LE
+ 
+ LOG = logging.getLogger(__name__)
+ 
++CONF = cfg.CONF
++
+ 
+ class DeleteFromSelect(UpdateBase):
+     def __init__(self, table, select, column):
+@@ -120,7 +123,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-13.1.0/nova/tests/unit/db/test_migrations.py.orig	2016-08-24 14:24:39.811171818 -0700
++++ nova-13.1.0/nova/tests/unit/db/test_migrations.py	2016-08-24 14:22:35.003780248 -0700
+@@ -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,8 @@ from nova import exception
+ from nova import test
+ from nova.tests import fixtures as nova_fixtures
+ 
++CONF = cfg.CONF
++
+ 
+ class NovaMigrationsCheckers(test_migrations.ModelsMigrationsSync,
+                              test_migrations.WalkVersionsMixin):
+@@ -911,9 +914,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)
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/python/oslo.db/patches/mysql_cluster_support.patch	Thu Sep 08 13:16:06 2016 -0600
@@ -0,0 +1,29 @@
+This patchset is for bug:
+
+24409419 Mitaka oslo.db should 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-4.7.0/oslo_db/options.py.orig	2016-08-04 14:14:42.609731178 -0700
++++ oslo.db-4.7.0/oslo_db/options.py	2016-08-04 14:42:24.071847993 -0700
+@@ -48,6 +48,13 @@ 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 '
++                    'engine such as InnoDB, NDB, etc. For MySQL Cluster, '
++                    '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',