components/openstack/neutron/patches/11-mysql_cluster_support.patch
changeset 6848 8e252a37ed0d
parent 6847 57069587975f
child 6849 f9a2279efa0d
equal deleted inserted replaced
6847:57069587975f 6848:8e252a37ed0d
     1 This patchset is for bug:
       
     2 
       
     3 22726251 - Neutron needs to support MySQL Cluster
       
     4 
       
     5 This fixes the following aspects of Neutron:
       
     6 1. Implementation of an oslo.db configuration parameter to specify the MySQL
       
     7    storage engine (mysql_storage_engine).
       
     8 2. Replacement of hardcoded SQL statements that set the engine to "InnoDB"
       
     9    to the above configuration value.
       
    10 3. Logic to handle SQL differences between MySQL InnoDB and MySQL Cluster (NDB).
       
    11    This includes column lengths, constraints, foreign keys, and indexes.
       
    12 
       
    13 This has not been committed upstream, but has been filed in launchpad:
       
    14 
       
    15 https://bugs.launchpad.net/neutron/+bug/1564110
       
    16 
       
    17 
       
    18 --- neutron-2015.1.2/neutron/db/model_base.py.orig	2016-07-29 13:15:07.909806102 -0600
       
    19 +++ neutron-2015.1.2/neutron/db/model_base.py	2016-07-29 13:27:41.817140969 -0600
       
    20 @@ -13,15 +13,24 @@
       
    21  # See the License for the specific language governing permissions and
       
    22  # limitations under the License.
       
    23  
       
    24 +from oslo_config import cfg
       
    25  from oslo_db.sqlalchemy import models
       
    26  from sqlalchemy.ext import declarative
       
    27  from sqlalchemy import orm
       
    28  
       
    29 +# Attempt to determine the context that this module is being used.
       
    30 +# If via neutron-db-manage and cli.py, import global variable. If not,
       
    31 +# use oslo_config.
       
    32 +try:
       
    33 +     from neutron.db.migration.cli import mysql_storage_eng_type
       
    34 +except ImportError:
       
    35 +     CONF = cfg.CONF
       
    36 +     mysql_storage_eng_type = CONF.database.mysql_storage_engine
       
    37  
       
    38  class NeutronBase(models.ModelBase):
       
    39      """Base class for Neutron Models."""
       
    40  
       
    41 -    __table_args__ = {'mysql_engine': 'InnoDB'}
       
    42 +    __table_args__ = {'mysql_engine': mysql_storage_eng_type}
       
    43  
       
    44      def __iter__(self):
       
    45          self._i = iter(orm.object_mapper(self).columns)
       
    46 --- neutron-2015.1.2/neutron/db/api.py.orig	2016-07-29 13:15:14.380329905 -0600
       
    47 +++ neutron-2015.1.2/neutron/db/api.py	2016-07-28 14:15:31.186601900 -0600
       
    48 @@ -19,7 +19,6 @@ from oslo_config import cfg
       
    49  from oslo_db.sqlalchemy import session
       
    50  from sqlalchemy import exc
       
    51  
       
    52 -
       
    53  _FACADE = None
       
    54  
       
    55  MAX_RETRIES = 10
       
    56 @@ -50,10 +49,30 @@ def get_session(autocommit=True, expire_
       
    57  @contextlib.contextmanager
       
    58  def autonested_transaction(sess):
       
    59      """This is a convenience method to not bother with 'nested' parameter."""
       
    60 +    # Attempt to determine the context that this module is being used.
       
    61 +    # If via neutron-db-manage and cli.py, import global variable. If not,
       
    62 +    # use oslo_config.
       
    63      try:
       
    64 -        session_context = sess.begin_nested()
       
    65 -    except exc.InvalidRequestError:
       
    66 -        session_context = sess.begin(subtransactions=True)
       
    67 -    finally:
       
    68 -        with session_context as tx:
       
    69 -            yield tx
       
    70 +        from neutron.db.migration.cli import mysql_storage_eng_type
       
    71 +    except ImportError:
       
    72 +        CONF = cfg.CONF
       
    73 +        mysql_storage_eng_type = CONF.database.mysql_storage_engine
       
    74 +
       
    75 +    # MySQL Cluster NDB does not support nested transactions
       
    76 +    # TODO (oorgeron) Look into making this workable.
       
    77 +    if mysql_storage_eng_type == "NDBCLUSTER":
       
    78 +        try:
       
    79 +            session_context = sess.begin(subtransactions=True, nested=False)
       
    80 +        except exc.InvalidRequestError:
       
    81 +            session_context = sess.begin(subtransactions=False, nested=False)
       
    82 +        finally:
       
    83 +            with session_context as tx:
       
    84 +                yield tx
       
    85 +    else:
       
    86 +        try:
       
    87 +            session_context = sess.begin_nested()
       
    88 +        except exc.InvalidRequestError:
       
    89 +            session_context = sess.begin(subtransactions=True)
       
    90 +        finally:
       
    91 +            with session_context as tx:
       
    92 +                yield tx
       
    93 --- neutron-2015.1.2/neutron/db/db_base_plugin_v2.py.orig	2016-07-29 13:15:20.388338380 -0600
       
    94 +++ neutron-2015.1.2/neutron/db/db_base_plugin_v2.py	2016-07-28 14:15:31.187095505 -0600
       
    95 @@ -46,6 +46,15 @@ from neutron.plugins.common import const
       
    96  
       
    97  LOG = logging.getLogger(__name__)
       
    98  
       
    99 +# Attempt to determine the context that this module is being used.
       
   100 +# If via neutron-db-manage and cli.py, import global variable. If not,
       
   101 +# use oslo_config.
       
   102 +try:
       
   103 +     from neutron.db.migration.cli import mysql_storage_eng_type
       
   104 +except ImportError:
       
   105 +     CONF = cfg.CONF
       
   106 +     mysql_storage_eng_type = CONF.database.mysql_storage_engine
       
   107 +
       
   108  # Ports with the following 'device_owner' values will not prevent
       
   109  # network deletion.  If delete_network() finds that all ports on a
       
   110  # network have these owners, it will explicitly delete each port
       
   111 @@ -1443,16 +1452,26 @@ class NeutronDbPluginV2(neutron_plugin_b
       
   112                                                     port_id=port['id'],
       
   113                                                     ip_address=ip_address,
       
   114                                                     subnet_id=subnet['id'])
       
   115 -                try:
       
   116 -                    # Do the insertion of each IP allocation entry within
       
   117 -                    # the context of a nested transaction, so that the entry
       
   118 -                    # is rolled back independently of other entries whenever
       
   119 -                    # the corresponding port has been deleted.
       
   120 -                    with context.session.begin_nested():
       
   121 -                        context.session.add(allocated)
       
   122 -                except db_exc.DBReferenceError:
       
   123 -                    LOG.debug("Port %s was deleted while updating it with an "
       
   124 -                              "IPv6 auto-address. Ignoring.", port['id'])
       
   125 +                # MySQL Cluster NDB does not support nested transactions
       
   126 +                # TODO (oorgeron) Look into making this workable.
       
   127 +                if mysql_storage_eng_type == "NDBCLUSTER":
       
   128 +                    try:
       
   129 +                        with context.session.begin(subtransactions=True):
       
   130 +                            context.session.add(allocated)
       
   131 +                    except db_exc.DBReferenceError:
       
   132 +                        LOG.debug("Port %s was deleted while updating it with an "
       
   133 +                                  "IPv6 auto-address. Ignoring.", port['id'])
       
   134 +                else:
       
   135 +                    try:
       
   136 +                        # Do the insertion of each IP allocation entry within
       
   137 +                        # the context of a nested transaction, so that the entry
       
   138 +                        # is rolled back independently of other entries whenever
       
   139 +                        # the corresponding port has been deleted.
       
   140 +                        with context.session.begin_nested():
       
   141 +                            context.session.add(allocated)
       
   142 +                    except db_exc.DBReferenceError:
       
   143 +                        LOG.debug("Port %s was deleted while updating it with an "
       
   144 +                                  "IPv6 auto-address. Ignoring.", port['id'])
       
   145  
       
   146      def _update_subnet_dns_nameservers(self, context, id, s):
       
   147          old_dns_list = self._get_dns_by_subnet(context, id)
       
   148 @@ -1797,8 +1816,16 @@ class NeutronDbPluginV2(neutron_plugin_b
       
   149                  # within a transaction, so that it can be rolled back to the
       
   150                  # point before its failure while maintaining the enclosing
       
   151                  # transaction
       
   152 -                return self._create_port_with_mac(
       
   153 -                    context, network_id, port_data, mac, nested=True)
       
   154 +
       
   155 +                # MySQL Cluster NDB does not support nested transactions
       
   156 +                # TODO (oorgeron) Look into making this workable.
       
   157 +                if mysql_storage_eng_type == "NDBCLUSTER":
       
   158 +                    return self._create_port_with_mac(
       
   159 +                        context, network_id, port_data, mac, nested=False)
       
   160 +                else:
       
   161 +                    return self._create_port_with_mac(
       
   162 +                        context, network_id, port_data, mac, nested=True)
       
   163 +
       
   164              except n_exc.MacAddressInUse:
       
   165                  LOG.debug('Generated mac %(mac_address)s exists on '
       
   166                            'network %(network_id)s',
       
   167 --- neutron-2015.1.2/neutron/db/migration/cli.py.orig	2016-07-29 13:15:27.041205822 -0600
       
   168 +++ neutron-2015.1.2/neutron/db/migration/cli.py	2016-07-28 14:15:31.187312338 -0600
       
   169 @@ -59,6 +59,9 @@ _db_opts = [
       
   170      cfg.StrOpt('engine',
       
   171                 default='',
       
   172                 help=_('Database engine')),
       
   173 +    cfg.StrOpt('mysql_storage_engine',
       
   174 +               default='',
       
   175 +               help=_('MySQL Storage Engine')),
       
   176  ]
       
   177  
       
   178  CONF = cfg.ConfigOpts()
       
   179 @@ -234,5 +237,11 @@ def main():
       
   180      config = get_alembic_config()
       
   181      config.neutron_config = CONF
       
   182  
       
   183 +    # Make global variable available for modules that will be called
       
   184 +    # by neutron-db-manage. This will prevent namespace collisions
       
   185 +    # between oslo_config and albemic_config
       
   186 +    global mysql_storage_eng_type
       
   187 +    mysql_storage_eng_type = CONF.database.mysql_storage_engine
       
   188 +
       
   189      #TODO(gongysh) enable logging
       
   190      CONF.command.func(config, CONF.command.name)
       
   191 --- neutron-2015.1.2/neutron/db/migration/models/frozen.py.orig	2016-07-29 13:15:33.940472370 -0600
       
   192 +++ neutron-2015.1.2/neutron/db/migration/models/frozen.py	2016-07-29 13:29:33.819709706 -0600
       
   193 @@ -22,7 +22,8 @@ Based on this comparison database can be
       
   194  Current HEAD commit is 59da928e945ec58836d34fd561d30a8a446e2728
       
   195  """
       
   196  
       
   197 -
       
   198 +from alembic import context
       
   199 +from oslo_config import cfg
       
   200  import sqlalchemy as sa
       
   201  from sqlalchemy.ext import declarative
       
   202  from sqlalchemy.ext.orderinglist import ordering_list
       
   203 @@ -32,6 +33,8 @@ from sqlalchemy import schema
       
   204  from neutron.db import model_base
       
   205  from neutron.openstack.common import uuidutils
       
   206  
       
   207 +config = context.config
       
   208 +CONF = config.neutron_config
       
   209  
       
   210  # Dictionary of all tables that was renamed:
       
   211  # {new_table_name: old_table_name}
       
   212 @@ -77,6 +80,10 @@ DHCPV6_STATELESS = 'dhcpv6-stateless'
       
   213  
       
   214  BASEV2 = declarative.declarative_base(cls=model_base.NeutronBaseV2)
       
   215  
       
   216 +if CONF.database.mysql_storage_engine == "NDBCLUSTER":
       
   217 +   db_string_length = 128
       
   218 +else:
       
   219 +   db_string_length = 255
       
   220  
       
   221  #neutron/db/models_v2.py
       
   222  class HasTenant(object):
       
   223 @@ -218,17 +225,30 @@ class Agent(BASEV2, HasId):
       
   224                              name='uniq_agents0agent_type0host'),
       
   225      )
       
   226  
       
   227 -    agent_type = sa.Column(sa.String(255), nullable=False)
       
   228 -    binary = sa.Column(sa.String(255), nullable=False)
       
   229 -    topic = sa.Column(sa.String(255), nullable=False)
       
   230 -    host = sa.Column(sa.String(255), nullable=False)
       
   231 -    admin_state_up = sa.Column(sa.Boolean, default=True,
       
   232 -                               server_default=sa.sql.true(), nullable=False)
       
   233 -    created_at = sa.Column(sa.DateTime, nullable=False)
       
   234 -    started_at = sa.Column(sa.DateTime, nullable=False)
       
   235 -    heartbeat_timestamp = sa.Column(sa.DateTime, nullable=False)
       
   236 -    description = sa.Column(sa.String(255))
       
   237 -    configurations = sa.Column(sa.String(4095), nullable=False)
       
   238 +    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
       
   239 +        agent_type = sa.Column(sa.String(db_string_length), nullable=False)
       
   240 +        binary = sa.Column(sa.String(db_string_length), nullable=False)
       
   241 +        topic = sa.Column(sa.String(db_string_length), nullable=False)
       
   242 +        host = sa.Column(sa.String(db_string_length), nullable=False)
       
   243 +        admin_state_up = sa.Column(sa.Boolean, default=True,
       
   244 +                                   server_default=sa.sql.true(), nullable=False)
       
   245 +        created_at = sa.Column(sa.DateTime, nullable=False)
       
   246 +        started_at = sa.Column(sa.DateTime, nullable=False)
       
   247 +        heartbeat_timestamp = sa.Column(sa.DateTime, nullable=False)
       
   248 +        description = sa.Column(sa.String(db_string_length))
       
   249 +        configurations = sa.Column(sa.Text(4095), nullable=False)
       
   250 +    else:
       
   251 +        agent_type = sa.Column(sa.String(db_string_length), nullable=False)
       
   252 +        binary = sa.Column(sa.String(db_string_length), nullable=False)
       
   253 +        topic = sa.Column(sa.String(db_string_length), nullable=False)
       
   254 +        host = sa.Column(sa.String(db_string_length), nullable=False)
       
   255 +        admin_state_up = sa.Column(sa.Boolean, default=True,
       
   256 +                                   server_default=sa.sql.true(), nullable=False)
       
   257 +        created_at = sa.Column(sa.DateTime, nullable=False)
       
   258 +        started_at = sa.Column(sa.DateTime, nullable=False)
       
   259 +        heartbeat_timestamp = sa.Column(sa.DateTime, nullable=False)
       
   260 +        description = sa.Column(sa.String(db_string_length))
       
   261 +        configurations = sa.Column(sa.String(4095), nullable=False)
       
   262  
       
   263  
       
   264  #neutron/db/agentschedulers_db.py
       
   265 @@ -431,10 +451,15 @@ class Vip(BASEV2, HasId, HasTenant, HasS
       
   266  
       
   267  #neutron/db/loadbalancer/loadbalancer_db.py
       
   268  class Member(BASEV2, HasId, HasTenant, HasStatusDescription):
       
   269 -    __table_args__ = (
       
   270 -        sa.schema.UniqueConstraint('pool_id', 'address', 'protocol_port',
       
   271 -                                   name='uniq_member0pool_id0address0port'),
       
   272 -    )
       
   273 +    
       
   274 +    # MySQL Cluster NDB does not support this constraint.
       
   275 +    # TODO (oorgeron) Look into making this workable.
       
   276 +    if CONF.database.mysql_storage_engine != "NDBCLUSTER":
       
   277 +        __table_args__ = (
       
   278 +            sa.schema.UniqueConstraint('pool_id', 'address', 'protocol_port',
       
   279 +                                       name='uniq_member0pool_id0address0port'),
       
   280 +        )
       
   281 +
       
   282      pool_id = sa.Column(sa.String(36), sa.ForeignKey("pools.id"),
       
   283                          nullable=False)
       
   284      address = sa.Column(sa.String(64), nullable=False)
       
   285 @@ -1229,8 +1254,15 @@ class PortBinding(BASEV2):
       
   286      profile = sa.Column(sa.String(BINDING_PROFILE_LEN), nullable=False,
       
   287                          default='', server_default='')
       
   288      vif_type = sa.Column(sa.String(64), nullable=False)
       
   289 -    vif_details = sa.Column(sa.String(4095), nullable=False, default='',
       
   290 +    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
       
   291 +        vif_details = sa.Column(sa.Text(4095), nullable=False)
       
   292 +        profile = sa.Column(sa.Text(length=4095),nullable=False)
       
   293 +    else:
       
   294 +        vif_details = sa.Column(sa.String(4095), nullable=False,
       
   295 +                                server_default='')
       
   296 +        profile = sa.Column(sa.String(length=4095),nullable=False,
       
   297                              server_default='')
       
   298 +
       
   299      driver = sa.Column(sa.String(64))
       
   300      segment = sa.Column(sa.String(36),
       
   301                          sa.ForeignKey('ml2_network_segments.id',
       
   302 @@ -1827,10 +1859,17 @@ class PoolPort(BASEV2):
       
   303  class IdentifierMap(BASEV2, HasTenant):
       
   304      __tablename__ = 'cisco_csr_identifier_map'
       
   305  
       
   306 -    ipsec_site_conn_id = sa.Column(sa.String(64),
       
   307 -                                   sa.ForeignKey('ipsec_site_connections.id',
       
   308 -                                                 ondelete="CASCADE"),
       
   309 -                                   primary_key=True)
       
   310 +    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
       
   311 +        ipsec_site_conn_id = sa.Column(sa.String(36),
       
   312 +                                       sa.ForeignKey('ipsec_site_connections.id',
       
   313 +                                                     ondelete="CASCADE"),
       
   314 +                                       primary_key=True)
       
   315 +    else:
       
   316 +        ipsec_site_conn_id = sa.Column(sa.String(64),
       
   317 +                                       sa.ForeignKey('ipsec_site_connections.id',
       
   318 +                                                     ondelete="CASCADE"),
       
   319 +                                       primary_key=True)
       
   320 +
       
   321      csr_tunnel_id = sa.Column(sa.Integer, nullable=False)
       
   322      csr_ike_policy_id = sa.Column(sa.Integer, nullable=False)
       
   323      csr_ipsec_policy_id = sa.Column(sa.Integer, nullable=False)
       
   324 --- neutron-2015.1.2/neutron/db/migration/alembic_migrations/agent_init_ops.py.orig	2016-07-29 13:15:57.799898995 -0600
       
   325 +++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/agent_init_ops.py	2016-07-29 13:30:30.011137004 -0600
       
   326 @@ -17,26 +17,49 @@
       
   327  # This module only manages the 'agents' table. Binding tables are created
       
   328  # in the modules for relevant resources
       
   329  
       
   330 -
       
   331 +from alembic import context
       
   332  from alembic import op
       
   333  import sqlalchemy as sa
       
   334  
       
   335 +config = context.config
       
   336 +CONF = config.neutron_config
       
   337 +
       
   338 +if CONF.database.mysql_storage_engine == "NDBCLUSTER":
       
   339 +   db_string_length = 128
       
   340 +else:
       
   341 +   db_string_length = 255
       
   342  
       
   343  def upgrade():
       
   344      bind = op.get_bind()
       
   345      insp = sa.engine.reflection.Inspector.from_engine(bind)
       
   346      if 'agents' not in insp.get_table_names():
       
   347 -        op.create_table(
       
   348 -        'agents',
       
   349 -        sa.Column('id', sa.String(length=36), nullable=False),
       
   350 -        sa.Column('agent_type', sa.String(length=255), nullable=False),
       
   351 -        sa.Column('binary', sa.String(length=255), nullable=False),
       
   352 -        sa.Column('topic', sa.String(length=255), nullable=False),
       
   353 -        sa.Column('host', sa.String(length=255), nullable=False),
       
   354 -        sa.Column('admin_state_up', sa.Boolean(), nullable=False),
       
   355 -        sa.Column('created_at', sa.DateTime(), nullable=False),
       
   356 -        sa.Column('started_at', sa.DateTime(), nullable=False),
       
   357 -        sa.Column('heartbeat_timestamp', sa.DateTime(), nullable=False),
       
   358 -        sa.Column('description', sa.String(length=255), nullable=True),
       
   359 -        sa.Column('configurations', sa.String(length=4095), nullable=False),
       
   360 -        sa.PrimaryKeyConstraint('id'))
       
   361 +        if CONF.database.mysql_storage_engine == "NDBCLUSTER":
       
   362 +            op.create_table(
       
   363 +                'agents',
       
   364 +                sa.Column('id', sa.String(length=36), nullable=False),
       
   365 +                sa.Column('agent_type', sa.String(length=db_string_length), nullable=False),
       
   366 +                sa.Column('binary', sa.String(length=db_string_length), nullable=False),
       
   367 +                sa.Column('topic', sa.String(length=db_string_length), nullable=False),
       
   368 +                sa.Column('host', sa.String(length=db_string_length), nullable=False),
       
   369 +                sa.Column('admin_state_up', sa.Boolean(), nullable=False),
       
   370 +                sa.Column('created_at', sa.DateTime(), nullable=False),
       
   371 +                sa.Column('started_at', sa.DateTime(), nullable=False),
       
   372 +                sa.Column('heartbeat_timestamp', sa.DateTime(), nullable=False),
       
   373 +                sa.Column('description', sa.String(length=db_string_length), nullable=True),
       
   374 +                sa.Column('configurations', sa.Text(length=4095), nullable=False),
       
   375 +                sa.PrimaryKeyConstraint('id'))
       
   376 +        else:
       
   377 +            op.create_table(
       
   378 +                'agents',
       
   379 +                sa.Column('id', sa.String(length=36), nullable=False),
       
   380 +                sa.Column('agent_type', sa.String(length=db_string_length), nullable=False),
       
   381 +                sa.Column('binary', sa.String(length=db_string_length), nullable=False),
       
   382 +                sa.Column('topic', sa.String(length=db_string_length), nullable=False),
       
   383 +                sa.Column('host', sa.String(length=db_string_length), nullable=False),
       
   384 +                sa.Column('admin_state_up', sa.Boolean(), nullable=False),
       
   385 +                sa.Column('created_at', sa.DateTime(), nullable=False),
       
   386 +                sa.Column('started_at', sa.DateTime(), nullable=False),
       
   387 +                sa.Column('heartbeat_timestamp', sa.DateTime(), nullable=False),
       
   388 +                sa.Column('description', sa.String(length=db_string_length), nullable=True),
       
   389 +                sa.Column('configurations', sa.String(length=4095), nullable=False),
       
   390 +                sa.PrimaryKeyConstraint('id'))
       
   391 --- neutron-2015.1.2/neutron/db/migration/alembic_migrations/heal_script.py.orig	2016-07-29 13:16:06.570595984 -0600
       
   392 +++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/heal_script.py	2016-07-29 13:31:36.373228770 -0600
       
   393 @@ -19,6 +19,7 @@ import alembic
       
   394  from alembic import autogenerate as autogen
       
   395  from alembic import context
       
   396  from alembic import op
       
   397 +from oslo_config import cfg
       
   398  
       
   399  import sqlalchemy
       
   400  from sqlalchemy import schema as sa_schema
       
   401 @@ -29,6 +30,9 @@ from sqlalchemy import types
       
   402  from neutron.db.migration.models import frozen as frozen_models
       
   403  from neutron.i18n import _LI, _LW
       
   404  
       
   405 +config = context.config
       
   406 +CONF = config.neutron_config
       
   407 +
       
   408  LOG = logging.getLogger(__name__)
       
   409  
       
   410  METHODS = {}
       
   411 @@ -70,7 +74,10 @@ def heal():
       
   412          'compare_server_default': _compare_server_default,
       
   413      }
       
   414      mc = alembic.migration.MigrationContext.configure(op.get_bind(), opts=opts)
       
   415 -    set_storage_engine(op.get_bind(), "InnoDB")
       
   416 +    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
       
   417 +        set_storage_engine(op.get_bind(), 'NDBCLUSTER')
       
   418 +    else:
       
   419 +        set_storage_engine(op.get_bind(), 'InnoDB')
       
   420      diff = autogen.compare_metadata(mc, models_metadata)
       
   421      for el in diff:
       
   422          execute_alembic_command(el)
       
   423 @@ -286,4 +293,6 @@ def set_storage_engine(bind, engine):
       
   424      if bind.dialect.name == 'mysql':
       
   425          for table in insp.get_table_names():
       
   426              if insp.get_table_options(table)['mysql_engine'] != engine:
       
   427 -                op.execute("ALTER TABLE %s ENGINE=%s" % (table, engine))
       
   428 +                op.execute("ALTER TABLE %(db_table)s Engine=%(mysql_storage_engine)s"
       
   429 +                           % dict(db_table=table,
       
   430 +                           mysql_storage_engine=CONF.database.mysql_storage_engine))
       
   431 --- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/157a5d299379_ml2_binding_profile.py.orig	2016-07-29 13:16:13.971296279 -0600
       
   432 +++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/157a5d299379_ml2_binding_profile.py	2016-07-29 13:32:20.859598698 -0600
       
   433 @@ -25,14 +25,24 @@ Create Date: 2014-02-13 23:48:25.147279
       
   434  revision = '157a5d299379'
       
   435  down_revision = '50d5ba354c23'
       
   436  
       
   437 +from alembic import context
       
   438  from alembic import op
       
   439  import sqlalchemy as sa
       
   440  
       
   441  from neutron.db import migration
       
   442  
       
   443 +config = context.config
       
   444 +CONF = config.neutron_config
       
   445  
       
   446  def upgrade():
       
   447      if migration.schema_has_table('ml2_port_bindings'):
       
   448 -        op.add_column('ml2_port_bindings',
       
   449 -                      sa.Column('profile', sa.String(length=4095),
       
   450 -                                nullable=False, server_default=''))
       
   451 +        # MySQL Cluster (NDB) does not support rows longer than 14000.
       
   452 +        # This configures the profile column as TEXT to keep the row size down.
       
   453 +        if CONF.database.mysql_storage_engine == "NDBCLUSTER":
       
   454 +            op.add_column('ml2_port_bindings',
       
   455 +                          sa.Column('profile', sa.Text(length=4095),
       
   456 +                                    nullable=False))
       
   457 +        else:
       
   458 +            op.add_column('ml2_port_bindings',
       
   459 +                          sa.Column('profile', sa.String(length=4095),
       
   460 +                                    nullable=False, server_default=''))
       
   461 --- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/50d5ba354c23_ml2_binding_vif_details.py.orig	2016-07-29 13:16:20.121107758 -0600
       
   462 +++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/50d5ba354c23_ml2_binding_vif_details.py	2016-07-29 13:32:42.870041087 -0600
       
   463 @@ -25,11 +25,14 @@ Create Date: 2014-02-11 23:21:59.577972
       
   464  revision = '50d5ba354c23'
       
   465  down_revision = '27cc183af192'
       
   466  
       
   467 +from alembic import context
       
   468  from alembic import op
       
   469  import sqlalchemy as sa
       
   470  
       
   471  from neutron.db import migration
       
   472  
       
   473 +config = context.config
       
   474 +CONF = config.neutron_config
       
   475  
       
   476  def upgrade():
       
   477  
       
   478 @@ -38,9 +41,17 @@ def upgrade():
       
   479          # did not create the ml2_port_bindings table.
       
   480          return
       
   481  
       
   482 -    op.add_column('ml2_port_bindings',
       
   483 -                  sa.Column('vif_details', sa.String(length=4095),
       
   484 -                            nullable=False, server_default=''))
       
   485 +    # MySQL Cluster (NDB) does not support rows longer than 14000.
       
   486 +    # This converts vif_details to TEXT to keep the row size down.
       
   487 +    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
       
   488 +        op.add_column('ml2_port_bindings',
       
   489 +                      sa.Column('vif_details', sa.Text(length=4095),
       
   490 +                                nullable=False))
       
   491 +    else:
       
   492 +        op.add_column('ml2_port_bindings',
       
   493 +                      sa.Column('vif_details', sa.String(length=4095),
       
   494 +                                nullable=False, server_default=''))
       
   495 +
       
   496      if op.get_bind().engine.name == 'ibm_db_sa':
       
   497          op.execute(
       
   498              "UPDATE ml2_port_bindings SET"
       
   499 --- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/e197124d4b9_add_unique_constrain.py.orig	2016-07-29 13:16:26.541620109 -0600
       
   500 +++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/e197124d4b9_add_unique_constrain.py	2016-07-29 13:33:26.620005420 -0600
       
   501 @@ -25,16 +25,27 @@ Create Date: 2013-11-17 10:09:37.728903
       
   502  revision = 'e197124d4b9'
       
   503  down_revision = 'havana'
       
   504  
       
   505 +from alembic import context
       
   506  from alembic import op
       
   507 +from oslo_config import cfg
       
   508  
       
   509  from neutron.db import migration
       
   510  
       
   511 +config = context.config
       
   512 +CONF = config.neutron_config
       
   513  
       
   514  CONSTRAINT_NAME = 'uniq_member0pool_id0address0port'
       
   515  TABLE_NAME = 'members'
       
   516  
       
   517  
       
   518  def upgrade():
       
   519 +
       
   520 +    # MySQL Cluster, a.k.a. NDB, does not support this migration step.
       
   521 +    # This test will skip this migration.
       
   522 +    # TODO (oorgeron) Look into making this workable.
       
   523 +    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
       
   524 +        return
       
   525 +
       
   526      if migration.schema_has_table(TABLE_NAME):
       
   527          op.create_unique_constraint(
       
   528              name=CONSTRAINT_NAME,
       
   529 --- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/86d6d9776e2b_cisco_apic_driver_update_l3.py.orig	2016-07-29 13:16:33.520954213 -0600
       
   530 +++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/86d6d9776e2b_cisco_apic_driver_update_l3.py	2016-07-29 13:34:14.398075900 -0600
       
   531 @@ -25,19 +25,31 @@ Create Date: 2014-04-23 09:27:08.177021
       
   532  revision = '86d6d9776e2b'
       
   533  down_revision = '236b90af57ab'
       
   534  
       
   535 -
       
   536 +from alembic import context
       
   537  from alembic import op
       
   538 +from oslo_config import cfg
       
   539  import sqlalchemy as sa
       
   540  
       
   541 +config = context.config
       
   542 +CONF = config.neutron_config
       
   543 +
       
   544  
       
   545  def upgrade():
       
   546  
       
   547      op.drop_table('cisco_ml2_apic_contracts')
       
   548      op.drop_table('cisco_ml2_apic_epgs')
       
   549  
       
   550 -    op.create_table(
       
   551 -        'cisco_ml2_apic_contracts',
       
   552 -        sa.Column('tenant_id', sa.String(length=255)),
       
   553 -        sa.Column('router_id', sa.String(length=64), nullable=False),
       
   554 -        sa.ForeignKeyConstraint(['router_id'], ['routers.id']),
       
   555 -        sa.PrimaryKeyConstraint('router_id'))
       
   556 +    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
       
   557 +        op.create_table(
       
   558 +            'cisco_ml2_apic_contracts',
       
   559 +            sa.Column('tenant_id', sa.String(length=255)),
       
   560 +            sa.Column('router_id', sa.String(length=36), nullable=False),
       
   561 +            sa.ForeignKeyConstraint(['router_id'], ['routers.id']),
       
   562 +            sa.PrimaryKeyConstraint('router_id'))
       
   563 +    else:
       
   564 +        op.create_table(
       
   565 +            'cisco_ml2_apic_contracts',
       
   566 +            sa.Column('tenant_id', sa.String(length=255)),
       
   567 +            sa.Column('router_id', sa.String(length=64), nullable=False),
       
   568 +            sa.ForeignKeyConstraint(['router_id'], ['routers.id']),
       
   569 +            sa.PrimaryKeyConstraint('router_id'))
       
   570 --- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/24c7ea5160d7_cisco_csr_vpnaas.py.orig	2016-07-29 13:16:40.087477384 -0600
       
   571 +++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/24c7ea5160d7_cisco_csr_vpnaas.py	2016-07-29 13:34:49.694936881 -0600
       
   572 @@ -23,25 +23,43 @@
       
   573  revision = '24c7ea5160d7'
       
   574  down_revision = '492a106273f8'
       
   575  
       
   576 +from alembic import context
       
   577  from alembic import op
       
   578 +from oslo_config import cfg
       
   579  import sqlalchemy as sa
       
   580  
       
   581  from neutron.db import migration
       
   582  
       
   583 +config = context.config
       
   584 +CONF = config.neutron_config
       
   585  
       
   586  def upgrade():
       
   587      if not migration.schema_has_table('ipsec_site_connections'):
       
   588          # The vpnaas service plugin was not configured.
       
   589          return
       
   590 -    op.create_table(
       
   591 -        'cisco_csr_identifier_map',
       
   592 -        sa.Column('tenant_id', sa.String(length=255), nullable=True),
       
   593 -        sa.Column('ipsec_site_conn_id', sa.String(length=64),
       
   594 -                  primary_key=True),
       
   595 -        sa.Column('csr_tunnel_id', sa.Integer(), nullable=False),
       
   596 -        sa.Column('csr_ike_policy_id', sa.Integer(), nullable=False),
       
   597 -        sa.Column('csr_ipsec_policy_id', sa.Integer(), nullable=False),
       
   598 -        sa.ForeignKeyConstraint(['ipsec_site_conn_id'],
       
   599 -                                ['ipsec_site_connections.id'],
       
   600 -                                ondelete='CASCADE')
       
   601 -    )
       
   602 +    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
       
   603 +        op.create_table(
       
   604 +            'cisco_csr_identifier_map',
       
   605 +            sa.Column('tenant_id', sa.String(length=255), nullable=True),
       
   606 +            sa.Column('ipsec_site_conn_id', sa.String(length=36),
       
   607 +                      primary_key=True),
       
   608 +            sa.Column('csr_tunnel_id', sa.Integer(), nullable=False),
       
   609 +            sa.Column('csr_ike_policy_id', sa.Integer(), nullable=False),
       
   610 +            sa.Column('csr_ipsec_policy_id', sa.Integer(), nullable=False),
       
   611 +            sa.ForeignKeyConstraint(['ipsec_site_conn_id'],
       
   612 +                                    ['ipsec_site_connections.id'],
       
   613 +                                    ondelete='CASCADE')
       
   614 +        )
       
   615 +    else:  
       
   616 +        op.create_table(
       
   617 +            'cisco_csr_identifier_map',
       
   618 +            sa.Column('tenant_id', sa.String(length=255), nullable=True),
       
   619 +            sa.Column('ipsec_site_conn_id', sa.String(length=64),
       
   620 +                      primary_key=True),
       
   621 +            sa.Column('csr_tunnel_id', sa.Integer(), nullable=False),
       
   622 +            sa.Column('csr_ike_policy_id', sa.Integer(), nullable=False),
       
   623 +            sa.Column('csr_ipsec_policy_id', sa.Integer(), nullable=False),
       
   624 +            sa.ForeignKeyConstraint(['ipsec_site_conn_id'],
       
   625 +                                    ['ipsec_site_connections.id'],
       
   626 +                                    ondelete='CASCADE')
       
   627 +        )
       
   628 --- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/16cdf118d31d_extra_dhcp_options_ipv6_support.py.orig	2016-07-29 13:16:46.865282929 -0600
       
   629 +++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/16cdf118d31d_extra_dhcp_options_ipv6_support.py	2016-07-29 13:35:19.078239546 -0600
       
   630 @@ -25,11 +25,16 @@ Create Date: 2014-10-23 17:04:19.796731
       
   631  revision = '16cdf118d31d'
       
   632  down_revision = '14be42f3d0a5'
       
   633  
       
   634 +from alembic import context
       
   635  from alembic import op
       
   636 +from oslo_config import cfg
       
   637  import sqlalchemy as sa
       
   638  
       
   639  from neutron.db import migration
       
   640  
       
   641 +config = context.config
       
   642 +CONF = config.neutron_config
       
   643 +
       
   644  CONSTRAINT_NAME_OLD = 'uidx_portid_optname'
       
   645  CONSTRAINT_NAME_NEW = 'uniq_extradhcpopts0portid0optname0ipversion'
       
   646  TABLE_NAME = 'extradhcpopts'
       
   647 @@ -47,8 +52,11 @@ def upgrade():
       
   648                    server_default='4', nullable=False))
       
   649          op.execute("UPDATE extradhcpopts SET ip_version = 4")
       
   650  
       
   651 -    op.create_unique_constraint(
       
   652 -        name=CONSTRAINT_NAME_NEW,
       
   653 -        source='extradhcpopts',
       
   654 -        local_cols=['port_id', 'opt_name', 'ip_version']
       
   655 -    )
       
   656 +    # MySQL Cluster NDB does not support this constraint.
       
   657 +    # TODO (oorgeron) Look into making this workable.
       
   658 +    if CONF.database.mysql_storage_engine != "NDBCLUSTER":
       
   659 +        op.create_unique_constraint(
       
   660 +            name=CONSTRAINT_NAME_NEW,
       
   661 +            source='extradhcpopts',
       
   662 +            local_cols=['port_id', 'opt_name', 'ip_version']
       
   663 +        )
       
   664 --- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/327ee5fde2c7_set_innodb_engine.py.orig	2016-07-29 13:16:54.825004264 -0600
       
   665 +++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/327ee5fde2c7_set_innodb_engine.py	2016-07-29 13:35:50.605636987 -0600
       
   666 @@ -26,7 +26,12 @@ revision = '327ee5fde2c7'
       
   667  down_revision = '4eba2f05c2f4'
       
   668  
       
   669  
       
   670 +from alembic import context
       
   671  from alembic import op
       
   672 +from oslo_config import cfg
       
   673 +
       
   674 +config = context.config
       
   675 +CONF = config.neutron_config
       
   676  
       
   677  # This list contain tables that could be deployed before change that converts
       
   678  # all tables to InnoDB appeared
       
   679 @@ -37,4 +42,6 @@ TABLES = ['router_extra_attributes', 'dv
       
   680  def upgrade():
       
   681      if op.get_bind().dialect.name == 'mysql':
       
   682          for table in TABLES:
       
   683 -            op.execute("ALTER TABLE %s ENGINE=InnoDB" % table)
       
   684 +            op.execute("ALTER TABLE %(db_table)s ENGINE=%(mysql_storage_engine)s"
       
   685 +                       % dict(db_table=table,
       
   686 +                       mysql_storage_engine=CONF.database.mysql_storage_engine))
       
   687 --- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/20c469a5f920_add_index_for_port.py.orig	2016-07-29 13:17:00.753891761 -0600
       
   688 +++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/20c469a5f920_add_index_for_port.py	2016-07-29 13:36:19.221516843 -0600
       
   689 @@ -25,11 +25,16 @@ Create Date: 2015-04-01 04:12:49.898443
       
   690  revision = '20c469a5f920'
       
   691  down_revision = '28a09af858a8'
       
   692  
       
   693 +from alembic import context
       
   694  from alembic import op
       
   695  
       
   696 +config = context.config
       
   697 +CONF = config.neutron_config
       
   698  
       
   699  def upgrade():
       
   700 -    op.create_index(op.f('ix_ports_network_id_device_owner'),
       
   701 -                    'ports', ['network_id', 'device_owner'], unique=False)
       
   702 -    op.create_index(op.f('ix_ports_network_id_mac_address'),
       
   703 -                    'ports', ['network_id', 'mac_address'], unique=False)
       
   704 +    # MySQL Cluster (NDB) does not support these indexes via alembic
       
   705 +    if CONF.database.mysql_storage_engine != "NDBCLUSTER":
       
   706 +        op.create_index(op.f('ix_ports_network_id_device_owner'),
       
   707 +                        'ports', ['network_id', 'device_owner'], unique=False)
       
   708 +        op.create_index(op.f('ix_ports_network_id_mac_address'),
       
   709 +                        'ports', ['network_id', 'mac_address'], unique=False)
       
   710 --- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/2a1ee2fb59e0_add_mac_address_unique_constraint.py.orig	2016-07-29 13:17:07.106004816 -0600
       
   711 +++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/2a1ee2fb59e0_add_mac_address_unique_constraint.py	2016-07-29 13:36:52.862356573 -0600
       
   712 @@ -25,15 +25,26 @@ Create Date: 2015-01-10 11:44:27.550349
       
   713  revision = '2a1ee2fb59e0'
       
   714  down_revision = '41662e32bce2'
       
   715  
       
   716 +from alembic import context
       
   717  from alembic import op
       
   718 +from oslo_config import cfg
       
   719 +
       
   720 +config = context.config
       
   721 +CONF = config.neutron_config
       
   722  
       
   723  TABLE_NAME = 'ports'
       
   724  CONSTRAINT_NAME = 'uniq_ports0network_id0mac_address'
       
   725  
       
   726  
       
   727  def upgrade():
       
   728 -    op.create_unique_constraint(
       
   729 -        name=CONSTRAINT_NAME,
       
   730 -        source=TABLE_NAME,
       
   731 -        local_cols=['network_id', 'mac_address']
       
   732 -    )
       
   733 +
       
   734 +    # MySQL Cluster NDB does not support this constraint.
       
   735 +    # TODO (oorgeron) Look into making this workable.
       
   736 +    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
       
   737 +        return
       
   738 +    else:
       
   739 +        op.create_unique_constraint(
       
   740 +            name=CONSTRAINT_NAME,
       
   741 +            source=TABLE_NAME,
       
   742 +            local_cols=['network_id', 'mac_address']
       
   743 +        )
       
   744 --- neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/2026156eab2f_l2_dvr_models.py.orig	2016-07-29 13:17:16.553516359 -0600
       
   745 +++ neutron-2015.1.2/neutron/db/migration/alembic_migrations/versions/2026156eab2f_l2_dvr_models.py	2016-07-29 13:37:31.406649583 -0600
       
   746 @@ -26,37 +26,73 @@ revision = '2026156eab2f'
       
   747  down_revision = '3927f7f7c456'
       
   748  
       
   749  
       
   750 +from alembic import context
       
   751  from alembic import op
       
   752  import sqlalchemy as sa
       
   753  
       
   754 +config = context.config
       
   755 +CONF = config.neutron_config
       
   756  
       
   757  def upgrade():
       
   758 -    op.create_table(
       
   759 -        'dvr_host_macs',
       
   760 -        sa.Column('host', sa.String(length=255), nullable=False),
       
   761 -        sa.Column('mac_address', sa.String(length=32),
       
   762 -                  nullable=False, unique=True),
       
   763 -        sa.PrimaryKeyConstraint('host')
       
   764 -    )
       
   765 -    op.create_table(
       
   766 -        'ml2_dvr_port_bindings',
       
   767 -        sa.Column('port_id', sa.String(length=36), nullable=False),
       
   768 -        sa.Column('host', sa.String(length=255), nullable=False),
       
   769 -        sa.Column('router_id', sa.String(length=36), nullable=True),
       
   770 -        sa.Column('vif_type', sa.String(length=64), nullable=False),
       
   771 -        sa.Column('vif_details', sa.String(length=4095),
       
   772 -                  nullable=False, server_default=''),
       
   773 -        sa.Column('vnic_type', sa.String(length=64),
       
   774 -                  nullable=False, server_default='normal'),
       
   775 -        sa.Column('profile', sa.String(length=4095),
       
   776 -                  nullable=False, server_default=''),
       
   777 -        sa.Column('cap_port_filter', sa.Boolean(), nullable=False),
       
   778 -        sa.Column('driver', sa.String(length=64), nullable=True),
       
   779 -        sa.Column('segment', sa.String(length=36), nullable=True),
       
   780 -        sa.Column(u'status', sa.String(16), nullable=False),
       
   781 -        sa.ForeignKeyConstraint(['port_id'], ['ports.id'],
       
   782 -                                ondelete='CASCADE'),
       
   783 -        sa.ForeignKeyConstraint(['segment'], ['ml2_network_segments.id'],
       
   784 -                                ondelete='SET NULL'),
       
   785 -        sa.PrimaryKeyConstraint('port_id', 'host')
       
   786 -    )
       
   787 +    # MySQL Cluster (NDB) does not support rows longer than 14000.
       
   788 +    # This reduces the size of columns or converts them to TEXT to keep the row size down.
       
   789 +    if CONF.database.mysql_storage_engine == "NDBCLUSTER":
       
   790 +        op.create_table(
       
   791 +            'dvr_host_macs',
       
   792 +            sa.Column('host', sa.String(length=128), nullable=False),
       
   793 +            sa.Column('mac_address', sa.String(length=32),
       
   794 +                      nullable=False, unique=True),
       
   795 +            sa.PrimaryKeyConstraint('host')
       
   796 +        )
       
   797 +        op.create_table(
       
   798 +            'ml2_dvr_port_bindings',
       
   799 +            sa.Column('port_id', sa.String(length=36), nullable=False),
       
   800 +            sa.Column('host', sa.String(length=128), nullable=False),
       
   801 +            sa.Column('router_id', sa.String(length=36), nullable=True),
       
   802 +            sa.Column('vif_type', sa.String(length=64), nullable=False),
       
   803 +            sa.Column('vif_details', sa.Text(length=4095),
       
   804 +                      nullable=False, server_default=''),
       
   805 +            sa.Column('vnic_type', sa.String(length=64),
       
   806 +                      nullable=False, server_default='normal'),
       
   807 +            sa.Column('profile', sa.Text(length=4095),
       
   808 +                      nullable=False, server_default=''),
       
   809 +            sa.Column('cap_port_filter', sa.Boolean(), nullable=False),
       
   810 +            sa.Column('driver', sa.String(length=64), nullable=True),
       
   811 +            sa.Column('segment', sa.String(length=36), nullable=True),
       
   812 +            sa.Column(u'status', sa.String(16), nullable=False),
       
   813 +            sa.ForeignKeyConstraint(['port_id'], ['ports.id'],
       
   814 +                                    ondelete='CASCADE'),
       
   815 +            sa.ForeignKeyConstraint(['segment'], ['ml2_network_segments.id'],
       
   816 +                                    ondelete='SET NULL'),
       
   817 +            sa.PrimaryKeyConstraint('port_id', 'host')
       
   818 +        )
       
   819 +    else:
       
   820 +        op.create_table(
       
   821 +            'dvr_host_macs',
       
   822 +            sa.Column('host', sa.String(length=255), nullable=False),
       
   823 +            sa.Column('mac_address', sa.String(length=32),
       
   824 +                      nullable=False, unique=True),
       
   825 +            sa.PrimaryKeyConstraint('host')
       
   826 +        )
       
   827 +        op.create_table(
       
   828 +            'ml2_dvr_port_bindings',
       
   829 +            sa.Column('port_id', sa.String(length=36), nullable=False),
       
   830 +            sa.Column('host', sa.String(length=255), nullable=False),
       
   831 +            sa.Column('router_id', sa.String(length=36), nullable=True),
       
   832 +            sa.Column('vif_type', sa.String(length=64), nullable=False),
       
   833 +            sa.Column('vif_details', sa.String(length=4095),
       
   834 +                      nullable=False, server_default=''),
       
   835 +            sa.Column('vnic_type', sa.String(length=64),
       
   836 +                      nullable=False, server_default='normal'),
       
   837 +            sa.Column('profile', sa.String(length=4095),
       
   838 +                      nullable=False, server_default=''),
       
   839 +            sa.Column('cap_port_filter', sa.Boolean(), nullable=False),
       
   840 +            sa.Column('driver', sa.String(length=64), nullable=True),
       
   841 +            sa.Column('segment', sa.String(length=36), nullable=True),
       
   842 +            sa.Column(u'status', sa.String(16), nullable=False),
       
   843 +            sa.ForeignKeyConstraint(['port_id'], ['ports.id'],
       
   844 +                                    ondelete='CASCADE'),
       
   845 +            sa.ForeignKeyConstraint(['segment'], ['ml2_network_segments.id'],
       
   846 +                                    ondelete='SET NULL'),
       
   847 +            sa.PrimaryKeyConstraint('port_id', 'host')
       
   848 +        )
       
   849 --- neutron-2015.1.2/neutron/db/extradhcpopt_db.py.orig	2016-07-29 13:17:23.118174498 -0600
       
   850 +++ neutron-2015.1.2/neutron/db/extradhcpopt_db.py	2016-07-29 13:38:57.088142872 -0600
       
   851 @@ -13,6 +13,7 @@
       
   852  #    License for the specific language governing permissions and limitations
       
   853  #    under the License.
       
   854  
       
   855 +from oslo_config import cfg
       
   856  from oslo_log import log as logging
       
   857  import sqlalchemy as sa
       
   858  from sqlalchemy import orm
       
   859 @@ -23,36 +24,67 @@ from neutron.db import model_base
       
   860  from neutron.db import models_v2
       
   861  from neutron.extensions import extra_dhcp_opt as edo_ext
       
   862  
       
   863 +# Attempt to determine the context that this module is being used.
       
   864 +# If via neutron-db-manage and cli.py, import global variable. If not,
       
   865 +# use oslo_config.
       
   866 +try:
       
   867 +     from neutron.db.migration.cli import mysql_storage_eng_type
       
   868 +except ImportError:
       
   869 +     CONF = cfg.CONF
       
   870 +     mysql_storage_eng_type = CONF.database.mysql_storage_engine
       
   871  
       
   872  LOG = logging.getLogger(__name__)
       
   873  
       
   874 -
       
   875 -class ExtraDhcpOpt(model_base.BASEV2, models_v2.HasId):
       
   876 -    """Represent a generic concept of extra options associated to a port.
       
   877 -
       
   878 -    Each port may have none to many dhcp opts associated to it that can
       
   879 -    define specifically different or extra options to DHCP clients.
       
   880 -    These will be written to the <network_id>/opts files, and each option's
       
   881 -    tag will be referenced in the <network_id>/host file.
       
   882 -    """
       
   883 -    port_id = sa.Column(sa.String(36),
       
   884 -                        sa.ForeignKey('ports.id', ondelete="CASCADE"),
       
   885 -                        nullable=False)
       
   886 -    opt_name = sa.Column(sa.String(64), nullable=False)
       
   887 -    opt_value = sa.Column(sa.String(255), nullable=False)
       
   888 -    ip_version = sa.Column(sa.Integer, server_default='4', nullable=False)
       
   889 -    __table_args__ = (sa.UniqueConstraint(
       
   890 -        'port_id',
       
   891 -        'opt_name',
       
   892 -        'ip_version',
       
   893 -        name='uniq_extradhcpopts0portid0optname0ipversion'),
       
   894 -                      model_base.BASEV2.__table_args__,)
       
   895 -
       
   896 -    # Add a relationship to the Port model in order to instruct SQLAlchemy to
       
   897 -    # eagerly load extra_dhcp_opts bindings
       
   898 -    ports = orm.relationship(
       
   899 -        models_v2.Port,
       
   900 -        backref=orm.backref("dhcp_opts", lazy='joined', cascade='delete'))
       
   901 +# MySQL Cluster NDB does not support this constraint.
       
   902 +# TODO (oorgeron) Look into making this workable.
       
   903 +if mysql_storage_eng_type == "NDBCLUSTER":
       
   904 +    class ExtraDhcpOpt(model_base.BASEV2, models_v2.HasId):
       
   905 +        """Represent a generic concept of extra options associated to a port.
       
   906 +
       
   907 +        Each port may have none to many dhcp opts associated to it that can
       
   908 +        define specifically different or extra options to DHCP clients.
       
   909 +        These will be written to the <network_id>/opts files, and each option's
       
   910 +        tag will be referenced in the <network_id>/host file.
       
   911 +        """
       
   912 +        port_id = sa.Column(sa.String(36),
       
   913 +                            sa.ForeignKey('ports.id', ondelete="CASCADE"),
       
   914 +                            nullable=False)
       
   915 +        opt_name = sa.Column(sa.String(64), nullable=False)
       
   916 +        opt_value = sa.Column(sa.String(255), nullable=False)
       
   917 +        ip_version = sa.Column(sa.Integer, server_default='4', nullable=False)
       
   918 +
       
   919 +        # Add a relationship to the Port model in order to instruct SQLAlchemy to
       
   920 +        # eagerly load extra_dhcp_opts bindings
       
   921 +        ports = orm.relationship(
       
   922 +            models_v2.Port,
       
   923 +            backref=orm.backref("dhcp_opts", lazy='joined', cascade='delete'))
       
   924 +else:
       
   925 +    class ExtraDhcpOpt(model_base.BASEV2, models_v2.HasId):
       
   926 +        """Represent a generic concept of extra options associated to a port.
       
   927 +
       
   928 +        Each port may have none to many dhcp opts associated to it that can
       
   929 +        define specifically different or extra options to DHCP clients.
       
   930 +        These will be written to the <network_id>/opts files, and each option's
       
   931 +        tag will be referenced in the <network_id>/host file.
       
   932 +        """
       
   933 +        port_id = sa.Column(sa.String(36),
       
   934 +                            sa.ForeignKey('ports.id', ondelete="CASCADE"),
       
   935 +                            nullable=False)
       
   936 +        opt_name = sa.Column(sa.String(64), nullable=False)
       
   937 +        opt_value = sa.Column(sa.String(255), nullable=False)
       
   938 +        ip_version = sa.Column(sa.Integer, server_default='4', nullable=False)
       
   939 +        __table_args__ = (sa.UniqueConstraint(
       
   940 +            'port_id',
       
   941 +            'opt_name',
       
   942 +            'ip_version',
       
   943 +            name='uniq_extradhcpopts0portid0optname0ipversion'),
       
   944 +                          model_base.BASEV2.__table_args__,)
       
   945 +
       
   946 +        # Add a relationship to the Port model in order to instruct SQLAlchemy to
       
   947 +        # eagerly load extra_dhcp_opts bindings
       
   948 +        ports = orm.relationship(
       
   949 +            models_v2.Port,
       
   950 +            backref=orm.backref("dhcp_opts", lazy='joined', cascade='delete'))
       
   951  
       
   952  
       
   953  class ExtraDhcpOptMixin(object):
       
   954 --- neutron-2015.1.2/neutron/db/models_v2.py.orig	2016-07-29 13:17:29.114096786 -0600
       
   955 +++ neutron-2015.1.2/neutron/db/models_v2.py	2016-07-29 13:40:10.416011760 -0600
       
   956 @@ -13,6 +13,7 @@
       
   957  #    License for the specific language governing permissions and limitations
       
   958  #    under the License.
       
   959  
       
   960 +from oslo_config import cfg
       
   961  import sqlalchemy as sa
       
   962  from sqlalchemy import orm
       
   963  
       
   964 @@ -21,6 +22,14 @@ from neutron.common import constants
       
   965  from neutron.db import model_base
       
   966  from neutron.openstack.common import uuidutils
       
   967  
       
   968 +# Attempt to determine the context that this module is being used.
       
   969 +# If via neutron-db-manage and cli.py, import global variable. If not,
       
   970 +# use oslo_config.
       
   971 +try:
       
   972 +     from neutron.db.migration.cli import mysql_storage_eng_type
       
   973 +except ImportError:
       
   974 +     CONF = cfg.CONF
       
   975 +     mysql_storage_eng_type = CONF.database.mysql_storage_engine
       
   976  
       
   977  class HasTenant(object):
       
   978      """Tenant mixin, add to subclasses that have a tenant."""
       
   979 @@ -126,47 +135,89 @@ class SubnetRoute(model_base.BASEV2, Rou
       
   980                            primary_key=True)
       
   981  
       
   982  
       
   983 -class Port(model_base.BASEV2, HasId, HasTenant):
       
   984 -    """Represents a port on a Neutron v2 network."""
       
   985 +# MySQL Cluster NDB does not support this constraint.
       
   986 +# TODO (oorgeron) Look into making this workable.
       
   987 +if mysql_storage_eng_type == "NDBCLUSTER":
       
   988 +    class Port(model_base.BASEV2, HasId, HasTenant):
       
   989 +        """Represents a port on a Neutron v2 network."""
       
   990 +
       
   991 +        name = sa.Column(sa.String(attr.NAME_MAX_LEN))
       
   992 +        network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id"),
       
   993 +                               nullable=False)
       
   994 +        fixed_ips = orm.relationship(IPAllocation, backref='ports', lazy='joined')
       
   995 +        mac_address = sa.Column(sa.String(32), nullable=False)
       
   996 +        admin_state_up = sa.Column(sa.Boolean(), nullable=False)
       
   997 +        status = sa.Column(sa.String(16), nullable=False)
       
   998 +        device_id = sa.Column(sa.String(attr.DEVICE_ID_MAX_LEN), nullable=False)
       
   999 +        device_owner = sa.Column(sa.String(attr.DEVICE_OWNER_MAX_LEN),
       
  1000 +                                 nullable=False)
       
  1001 +        __table_args__ = (
       
  1002 +            sa.Index(
       
  1003 +                'ix_ports_network_id_mac_address', 'network_id', 'mac_address'),
       
  1004 +            sa.Index(
       
  1005 +                'ix_ports_network_id_device_owner', 'network_id', 'device_owner'),
       
  1006 +            model_base.BASEV2.__table_args__
       
  1007 +        )
       
  1008 +
       
  1009 +        def __init__(self, id=None, tenant_id=None, name=None, network_id=None,
       
  1010 +                     mac_address=None, admin_state_up=None, status=None,
       
  1011 +                     device_id=None, device_owner=None, fixed_ips=None):
       
  1012 +            self.id = id
       
  1013 +            self.tenant_id = tenant_id
       
  1014 +            self.name = name
       
  1015 +            self.network_id = network_id
       
  1016 +            self.mac_address = mac_address
       
  1017 +            self.admin_state_up = admin_state_up
       
  1018 +            self.device_owner = device_owner
       
  1019 +            self.device_id = device_id
       
  1020 +            # Since this is a relationship only set it if one is passed in.
       
  1021 +            if fixed_ips:
       
  1022 +                self.fixed_ips = fixed_ips
       
  1023 +
       
  1024 +            # NOTE(arosen): status must be set last as an event is triggered on!
       
  1025 +            self.status = status            
       
  1026 +else:
       
  1027 +    class Port(model_base.BASEV2, HasId, HasTenant):
       
  1028 +        """Represents a port on a Neutron v2 network."""
       
  1029 +
       
  1030 +        name = sa.Column(sa.String(attr.NAME_MAX_LEN))
       
  1031 +        network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id"),
       
  1032 +                               nullable=False)
       
  1033 +        fixed_ips = orm.relationship(IPAllocation, backref='ports', lazy='joined')
       
  1034 +        mac_address = sa.Column(sa.String(32), nullable=False)
       
  1035 +        admin_state_up = sa.Column(sa.Boolean(), nullable=False)
       
  1036 +        status = sa.Column(sa.String(16), nullable=False)
       
  1037 +        device_id = sa.Column(sa.String(attr.DEVICE_ID_MAX_LEN), nullable=False)
       
  1038 +        device_owner = sa.Column(sa.String(attr.DEVICE_OWNER_MAX_LEN),
       
  1039 +                                 nullable=False)
       
  1040 +        __table_args__ = (
       
  1041 +            sa.Index(
       
  1042 +                'ix_ports_network_id_mac_address', 'network_id', 'mac_address'),
       
  1043 +            sa.Index(
       
  1044 +                'ix_ports_network_id_device_owner', 'network_id', 'device_owner'),
       
  1045 +            sa.UniqueConstraint(
       
  1046 +                network_id, mac_address,
       
  1047 +                name='uniq_ports0network_id0mac_address'),
       
  1048 +            model_base.BASEV2.__table_args__
       
  1049 +        )
       
  1050 +
       
  1051 +        def __init__(self, id=None, tenant_id=None, name=None, network_id=None,
       
  1052 +                     mac_address=None, admin_state_up=None, status=None,
       
  1053 +                     device_id=None, device_owner=None, fixed_ips=None):
       
  1054 +            self.id = id
       
  1055 +            self.tenant_id = tenant_id
       
  1056 +            self.name = name
       
  1057 +            self.network_id = network_id
       
  1058 +            self.mac_address = mac_address
       
  1059 +            self.admin_state_up = admin_state_up
       
  1060 +            self.device_owner = device_owner
       
  1061 +            self.device_id = device_id
       
  1062 +            # Since this is a relationship only set it if one is passed in.
       
  1063 +            if fixed_ips:
       
  1064 +                self.fixed_ips = fixed_ips
       
  1065  
       
  1066 -    name = sa.Column(sa.String(attr.NAME_MAX_LEN))
       
  1067 -    network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id"),
       
  1068 -                           nullable=False)
       
  1069 -    fixed_ips = orm.relationship(IPAllocation, backref='ports', lazy='joined')
       
  1070 -    mac_address = sa.Column(sa.String(32), nullable=False)
       
  1071 -    admin_state_up = sa.Column(sa.Boolean(), nullable=False)
       
  1072 -    status = sa.Column(sa.String(16), nullable=False)
       
  1073 -    device_id = sa.Column(sa.String(attr.DEVICE_ID_MAX_LEN), nullable=False)
       
  1074 -    device_owner = sa.Column(sa.String(attr.DEVICE_OWNER_MAX_LEN),
       
  1075 -                             nullable=False)
       
  1076 -    __table_args__ = (
       
  1077 -        sa.Index(
       
  1078 -            'ix_ports_network_id_mac_address', 'network_id', 'mac_address'),
       
  1079 -        sa.Index(
       
  1080 -            'ix_ports_network_id_device_owner', 'network_id', 'device_owner'),
       
  1081 -        sa.UniqueConstraint(
       
  1082 -            network_id, mac_address,
       
  1083 -            name='uniq_ports0network_id0mac_address'),
       
  1084 -        model_base.BASEV2.__table_args__
       
  1085 -    )
       
  1086 -
       
  1087 -    def __init__(self, id=None, tenant_id=None, name=None, network_id=None,
       
  1088 -                 mac_address=None, admin_state_up=None, status=None,
       
  1089 -                 device_id=None, device_owner=None, fixed_ips=None):
       
  1090 -        self.id = id
       
  1091 -        self.tenant_id = tenant_id
       
  1092 -        self.name = name
       
  1093 -        self.network_id = network_id
       
  1094 -        self.mac_address = mac_address
       
  1095 -        self.admin_state_up = admin_state_up
       
  1096 -        self.device_owner = device_owner
       
  1097 -        self.device_id = device_id
       
  1098 -        # Since this is a relationship only set it if one is passed in.
       
  1099 -        if fixed_ips:
       
  1100 -            self.fixed_ips = fixed_ips
       
  1101 -
       
  1102 -        # NOTE(arosen): status must be set last as an event is triggered on!
       
  1103 -        self.status = status
       
  1104 +            # NOTE(arosen): status must be set last as an event is triggered on!
       
  1105 +            self.status = status
       
  1106  
       
  1107  
       
  1108  class DNSNameServer(model_base.BASEV2):
       
  1109 --- neutron-2015.1.2/neutron/tests/functional/db/test_migrations.py.orig	2016-07-29 13:17:35.264552054 -0600
       
  1110 +++ neutron-2015.1.2/neutron/tests/functional/db/test_migrations.py	2016-07-29 13:41:12.657034516 -0600
       
  1111 @@ -19,6 +19,7 @@ import pprint
       
  1112  import alembic
       
  1113  import alembic.autogenerate
       
  1114  import alembic.migration
       
  1115 +from alembic import context
       
  1116  from alembic import script as alembic_script
       
  1117  import mock
       
  1118  from oslo_config import cfg
       
  1119 @@ -35,6 +36,9 @@ LOG = logging.getLogger(__name__)
       
  1120  
       
  1121  cfg.CONF.import_opt('core_plugin', 'neutron.common.config')
       
  1122  
       
  1123 +config = context.config
       
  1124 +CONF = config.neutron_config
       
  1125 +
       
  1126  CORE_PLUGIN = 'neutron.plugins.ml2.plugin.Ml2Plugin'
       
  1127  
       
  1128  # These tables are still in the neutron database, but their models have moved
       
  1129 @@ -195,7 +199,7 @@ class _TestModelsMigrations(test_migrati
       
  1130          self.assertTrue(len(tables) > 0,
       
  1131                          "No tables found. Wrong schema?")
       
  1132          noninnodb = [table for table in tables if
       
  1133 -                     insp.get_table_options(table)['mysql_engine'] != 'InnoDB'
       
  1134 +                     insp.get_table_options(table)['mysql_engine'] != CONF.database.mysql_storage_engine
       
  1135                       and table != 'alembic_version']
       
  1136          self.assertEqual(0, len(noninnodb), "%s non InnoDB tables created" %
       
  1137                                              noninnodb)
       
  1138 --- neutron-2015.1.2/neutron/plugins/ml2/drivers/cisco/apic/apic_model.py.orig	2016-07-29 13:17:41.409730731 -0600
       
  1139 +++ neutron-2015.1.2/neutron/plugins/ml2/drivers/cisco/apic/apic_model.py	2016-07-29 13:41:57.002278572 -0600
       
  1140 @@ -13,6 +13,7 @@
       
  1141  #    License for the specific language governing permissions and limitations
       
  1142  #    under the License.
       
  1143  
       
  1144 +from alembic import context
       
  1145  import sqlalchemy as sa
       
  1146  from sqlalchemy import orm
       
  1147  
       
  1148 @@ -22,6 +23,13 @@ from neutron.db import model_base
       
  1149  from neutron.db import models_v2
       
  1150  from neutron.plugins.ml2 import models as models_ml2
       
  1151  
       
  1152 +config = context.config
       
  1153 +CONF = config.neutron_config
       
  1154 +
       
  1155 +if CONF.database.mysql_storage_engine == "NDBCLUSTER":
       
  1156 +    router_string_length = 64
       
  1157 +else:
       
  1158 +    router_string_length = 36
       
  1159  
       
  1160  class RouterContract(model_base.BASEV2, models_v2.HasTenant):
       
  1161  
       
  1162 @@ -34,8 +42,8 @@ class RouterContract(model_base.BASEV2,
       
  1163  
       
  1164      __tablename__ = 'cisco_ml2_apic_contracts'
       
  1165  
       
  1166 -    router_id = sa.Column(sa.String(64), sa.ForeignKey('routers.id',
       
  1167 -                                                       ondelete='CASCADE'),
       
  1168 +    router_id = sa.Column(sa.String(router_string_length), 
       
  1169 +                          sa.ForeignKey('routers.id', ondelete='CASCADE'),
       
  1170                            primary_key=True)
       
  1171  
       
  1172