Rename DB columns: tenant -> project
All occurences of ``tenant_id`` across the database are renamed to ``project_id``. Both options are equally valid, but ``project_id`` is preferred. To inform external users about the change, HasTenant class was deprecated. UpgradeImpact Partially-Implements: blueprint keystone-v3 Change-Id: I87a8ef342ccea004731ba0192b23a8e79bc382dc
This commit is contained in:
parent
8ff526df04
commit
df9411dc11
@ -25,7 +25,7 @@ from neutron.extensions import address_scope as ext_address_scope
|
||||
from neutron.objects import subnetpool as subnetpool_obj
|
||||
|
||||
|
||||
class AddressScope(model_base.BASEV2, model_base.HasId, model_base.HasTenant):
|
||||
class AddressScope(model_base.BASEV2, model_base.HasId, model_base.HasProject):
|
||||
"""Represents a neutron address scope."""
|
||||
|
||||
__tablename__ = "address_scopes"
|
||||
|
@ -88,7 +88,7 @@ class RouterPort(model_base.BASEV2):
|
||||
|
||||
|
||||
class Router(model_base.HasStandardAttributes, model_base.BASEV2,
|
||||
model_base.HasId, model_base.HasTenant):
|
||||
model_base.HasId, model_base.HasProject):
|
||||
"""Represents a v2 neutron router."""
|
||||
|
||||
name = sa.Column(sa.String(attributes.NAME_MAX_LEN))
|
||||
@ -108,7 +108,7 @@ class Router(model_base.HasStandardAttributes, model_base.BASEV2,
|
||||
|
||||
|
||||
class FloatingIP(model_base.HasStandardAttributes, model_base.BASEV2,
|
||||
model_base.HasId, model_base.HasTenant):
|
||||
model_base.HasId, model_base.HasProject):
|
||||
"""Represents a floating IP address.
|
||||
|
||||
This IP address may or may not be allocated to a tenant, and may or
|
||||
|
@ -124,7 +124,7 @@ class L3HARouterAgentPortBinding(model_base.BASEV2):
|
||||
server_default=n_const.HA_ROUTER_STATE_STANDBY)
|
||||
|
||||
|
||||
class L3HARouterNetwork(model_base.BASEV2):
|
||||
class L3HARouterNetwork(model_base.BASEV2, model_base.HasProjectPrimaryKey):
|
||||
"""Host HA network for a tenant.
|
||||
|
||||
One HA Network is used per tenant, all HA router ports are created
|
||||
@ -133,8 +133,6 @@ class L3HARouterNetwork(model_base.BASEV2):
|
||||
|
||||
__tablename__ = 'ha_router_networks'
|
||||
|
||||
tenant_id = sa.Column(sa.String(attributes.TENANT_ID_MAX_LEN),
|
||||
primary_key=True, nullable=False)
|
||||
network_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('networks.id', ondelete="CASCADE"),
|
||||
nullable=False, primary_key=True)
|
||||
|
@ -38,7 +38,9 @@ class MeteringLabelRule(model_base.BASEV2, model_base.HasId):
|
||||
excluded = sa.Column(sa.Boolean, default=False, server_default=sql.false())
|
||||
|
||||
|
||||
class MeteringLabel(model_base.BASEV2, model_base.HasId, model_base.HasTenant):
|
||||
class MeteringLabel(model_base.BASEV2,
|
||||
model_base.HasId,
|
||||
model_base.HasProject):
|
||||
name = sa.Column(sa.String(attr.NAME_MAX_LEN))
|
||||
description = sa.Column(sa.String(attr.LONG_DESCRIPTION_MAX_LEN))
|
||||
rules = orm.relationship(MeteringLabelRule, backref="label",
|
||||
|
@ -1 +1 @@
|
||||
a84ccf28f06a
|
||||
7d9d8eeec6ad
|
||||
|
@ -0,0 +1,161 @@
|
||||
# Copyright 2016 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
"""rename tenant to project
|
||||
|
||||
Revision ID: 7d9d8eeec6ad
|
||||
Create Date: 2016-06-29 19:42:17.862721
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '7d9d8eeec6ad'
|
||||
down_revision = 'a84ccf28f06a'
|
||||
depends_on = ('5abc0278ca73',)
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
_INSPECTOR = None
|
||||
|
||||
|
||||
def get_inspector():
|
||||
"""Reuse inspector"""
|
||||
|
||||
global _INSPECTOR
|
||||
|
||||
if _INSPECTOR:
|
||||
return _INSPECTOR
|
||||
|
||||
else:
|
||||
bind = op.get_bind()
|
||||
_INSPECTOR = sa.engine.reflection.Inspector.from_engine(bind)
|
||||
|
||||
return _INSPECTOR
|
||||
|
||||
|
||||
def get_tables():
|
||||
"""
|
||||
Returns hardcoded list of tables which have ``tenant_id`` column.
|
||||
|
||||
DB head can be changed. To prevent possible problems, when models will be
|
||||
updated, return hardcoded list of tables, up-to-date for this day.
|
||||
|
||||
Output retrieved by using:
|
||||
|
||||
>>> metadata = head.get_metadata()
|
||||
>>> all_tables = metadata.sorted_tables
|
||||
>>> tenant_tables = []
|
||||
>>> for table in all_tables:
|
||||
... for column in table.columns:
|
||||
... if column.name == 'tenant_id':
|
||||
... tenant_tables.append((table, column))
|
||||
|
||||
"""
|
||||
|
||||
tables = [
|
||||
'address_scopes',
|
||||
'floatingips',
|
||||
'meteringlabels',
|
||||
'networkrbacs',
|
||||
'networks',
|
||||
'ports',
|
||||
'qos_policies',
|
||||
'qospolicyrbacs',
|
||||
'quotas',
|
||||
'reservations',
|
||||
'routers',
|
||||
'securitygrouprules',
|
||||
'securitygroups',
|
||||
'subnetpools',
|
||||
'subnets',
|
||||
'trunks',
|
||||
'auto_allocated_topologies',
|
||||
'default_security_group',
|
||||
'ha_router_networks',
|
||||
'quotausages',
|
||||
]
|
||||
|
||||
return tables
|
||||
|
||||
|
||||
def get_columns(table):
|
||||
"""Returns list of columns for given table."""
|
||||
inspector = get_inspector()
|
||||
return inspector.get_columns(table)
|
||||
|
||||
|
||||
def get_data():
|
||||
"""Returns combined list of tuples: [(table, column)].
|
||||
|
||||
List is built, based on retrieved tables, where column with name
|
||||
``tenant_id`` exists.
|
||||
"""
|
||||
|
||||
output = []
|
||||
tables = get_tables()
|
||||
for table in tables:
|
||||
columns = get_columns(table)
|
||||
|
||||
for column in columns:
|
||||
if column['name'] == 'tenant_id':
|
||||
output.append((table, column))
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def alter_column(table, column):
|
||||
old_name = 'tenant_id'
|
||||
new_name = 'project_id'
|
||||
|
||||
op.alter_column(
|
||||
table_name=table,
|
||||
column_name=old_name,
|
||||
new_column_name=new_name,
|
||||
existing_type=column['type'],
|
||||
existing_nullable=column['nullable']
|
||||
)
|
||||
|
||||
|
||||
def recreate_index(index, table_name):
|
||||
old_name = index['name']
|
||||
new_name = old_name.replace('tenant', 'project')
|
||||
|
||||
op.drop_index(op.f(old_name), table_name)
|
||||
op.create_index(new_name, table_name, ['project_id'])
|
||||
|
||||
|
||||
def upgrade():
|
||||
inspector = get_inspector()
|
||||
|
||||
data = get_data()
|
||||
for table, column in data:
|
||||
alter_column(table, column)
|
||||
|
||||
indexes = inspector.get_indexes(table)
|
||||
for index in indexes:
|
||||
if 'tenant_id' in index['name']:
|
||||
recreate_index(index, table)
|
||||
|
||||
|
||||
def contract_creation_exceptions():
|
||||
"""Special migration for the blueprint to support Keystone V3.
|
||||
We drop all tenant_id columns and create project_id columns instead.
|
||||
"""
|
||||
return {
|
||||
sa.Column: ['.'.join([table, 'project_id']) for table in get_tables()],
|
||||
sa.Index: get_tables()
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import debtcollector
|
||||
from oslo_db.sqlalchemy import models
|
||||
from oslo_utils import uuidutils
|
||||
import sqlalchemy as sa
|
||||
@ -23,16 +24,63 @@ from sqlalchemy import orm
|
||||
from neutron.api.v2 import attributes as attr
|
||||
|
||||
|
||||
class HasTenant(object):
|
||||
"""Tenant mixin, add to subclasses that have a tenant."""
|
||||
class HasProject(object):
|
||||
"""Project mixin, add to subclasses that have a user."""
|
||||
|
||||
# NOTE(jkoelker) tenant_id is just a free form string ;(
|
||||
tenant_id = sa.Column(sa.String(attr.TENANT_ID_MAX_LEN), index=True)
|
||||
# NOTE(jkoelker) project_id is just a free form string ;(
|
||||
project_id = sa.Column(sa.String(attr.TENANT_ID_MAX_LEN), index=True)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# NOTE(dasm): debtcollector requires init in class
|
||||
super(HasProject, self).__init__(*args, **kwargs)
|
||||
|
||||
def get_tenant_id(self):
|
||||
return self.project_id
|
||||
|
||||
def set_tenant_id(self, value):
|
||||
self.project_id = value
|
||||
|
||||
@declarative.declared_attr
|
||||
@debtcollector.moves.moved_property('project_id')
|
||||
def tenant_id(cls):
|
||||
return orm.synonym(
|
||||
'project_id',
|
||||
descriptor=property(cls.get_tenant_id, cls.set_tenant_id))
|
||||
|
||||
|
||||
HasTenant = debtcollector.moves.moved_class(HasProject, "HasTenant", __name__)
|
||||
|
||||
|
||||
class HasProjectNoIndex(HasProject):
|
||||
"""Project mixin, add to subclasses that have a user."""
|
||||
|
||||
# NOTE(jkoelker) project_id is just a free form string ;(
|
||||
project_id = sa.Column(sa.String(attr.TENANT_ID_MAX_LEN))
|
||||
|
||||
|
||||
class HasProjectPrimaryKeyIndex(HasProject):
|
||||
"""Project mixin, add to subclasses that have a user."""
|
||||
|
||||
# NOTE(jkoelker) project_id is just a free form string ;(
|
||||
project_id = sa.Column(sa.String(attr.TENANT_ID_MAX_LEN), nullable=False,
|
||||
primary_key=True, index=True)
|
||||
|
||||
|
||||
class HasProjectPrimaryKey(HasProject):
|
||||
"""Project mixin, add to subclasses that have a user."""
|
||||
|
||||
# NOTE(jkoelker) project_id is just a free form string ;(
|
||||
project_id = sa.Column(sa.String(attr.TENANT_ID_MAX_LEN), nullable=False,
|
||||
primary_key=True)
|
||||
|
||||
|
||||
class HasId(object):
|
||||
"""id mixin, add to subclasses that have an id."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# NOTE(dasm): debtcollector requires init in class
|
||||
super(HasId, self).__init__(*args, **kwargs)
|
||||
|
||||
id = sa.Column(sa.String(36),
|
||||
primary_key=True,
|
||||
default=uuidutils.generate_uuid)
|
||||
@ -41,6 +89,10 @@ class HasId(object):
|
||||
class HasStatusDescription(object):
|
||||
"""Status with description mixin."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# NOTE(dasm): debtcollector requires init in class
|
||||
super(HasStatusDescription, self).__init__(*args, **kwargs)
|
||||
|
||||
status = sa.Column(sa.String(16), nullable=False)
|
||||
status_description = sa.Column(sa.String(attr.DESCRIPTION_MAX_LEN))
|
||||
|
||||
|
@ -21,7 +21,7 @@ from neutron.db import models_v2
|
||||
from neutron.db import rbac_db_models
|
||||
|
||||
|
||||
class QosPolicy(model_base.BASEV2, model_base.HasId, model_base.HasTenant):
|
||||
class QosPolicy(model_base.BASEV2, model_base.HasId, model_base.HasProject):
|
||||
__tablename__ = 'qos_policies'
|
||||
name = sa.Column(sa.String(attrs.NAME_MAX_LEN))
|
||||
description = sa.Column(sa.String(attrs.DESCRIPTION_MAX_LEN))
|
||||
|
@ -16,7 +16,6 @@ import sqlalchemy as sa
|
||||
from sqlalchemy import orm
|
||||
from sqlalchemy import sql
|
||||
|
||||
from neutron.api.v2 import attributes as attr
|
||||
from neutron.db import model_base
|
||||
|
||||
|
||||
@ -31,8 +30,8 @@ class ResourceDelta(model_base.BASEV2):
|
||||
amount = sa.Column(sa.Integer)
|
||||
|
||||
|
||||
class Reservation(model_base.BASEV2, model_base.HasId):
|
||||
tenant_id = sa.Column(sa.String(attr.TENANT_ID_MAX_LEN))
|
||||
class Reservation(model_base.BASEV2, model_base.HasId,
|
||||
model_base.HasProjectNoIndex):
|
||||
expiration = sa.Column(sa.DateTime())
|
||||
resource_deltas = orm.relationship(ResourceDelta,
|
||||
backref='reservation',
|
||||
@ -40,7 +39,7 @@ class Reservation(model_base.BASEV2, model_base.HasId):
|
||||
cascade='all, delete-orphan')
|
||||
|
||||
|
||||
class Quota(model_base.BASEV2, model_base.HasId, model_base.HasTenant):
|
||||
class Quota(model_base.BASEV2, model_base.HasId, model_base.HasProject):
|
||||
"""Represent a single quota override for a tenant.
|
||||
|
||||
If there is no row for a given tenant id and resource, then the
|
||||
@ -50,13 +49,11 @@ class Quota(model_base.BASEV2, model_base.HasId, model_base.HasTenant):
|
||||
limit = sa.Column(sa.Integer)
|
||||
|
||||
|
||||
class QuotaUsage(model_base.BASEV2):
|
||||
class QuotaUsage(model_base.BASEV2, model_base.HasProjectPrimaryKeyIndex):
|
||||
"""Represents the current usage for a given resource."""
|
||||
|
||||
resource = sa.Column(sa.String(255), nullable=False,
|
||||
primary_key=True, index=True)
|
||||
tenant_id = sa.Column(sa.String(attr.TENANT_ID_MAX_LEN), nullable=False,
|
||||
primary_key=True, index=True)
|
||||
dirty = sa.Column(sa.Boolean, nullable=False, server_default=sql.false())
|
||||
|
||||
in_use = sa.Column(sa.Integer, nullable=False,
|
||||
|
@ -35,7 +35,7 @@ class InvalidActionForType(n_exc.InvalidInput):
|
||||
"'%(object_type)s'. Valid actions: %(valid_actions)s")
|
||||
|
||||
|
||||
class RBACColumns(model_base.HasId, model_base.HasTenant):
|
||||
class RBACColumns(model_base.HasId, model_base.HasProject):
|
||||
"""Mixin that object-specific RBAC tables should inherit.
|
||||
|
||||
All RBAC tables should inherit directly from this one because
|
||||
|
@ -41,17 +41,15 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SecurityGroup(model_base.HasStandardAttributes, model_base.BASEV2,
|
||||
model_base.HasId, model_base.HasTenant):
|
||||
model_base.HasId, model_base.HasProject):
|
||||
"""Represents a v2 neutron security group."""
|
||||
|
||||
name = sa.Column(sa.String(attributes.NAME_MAX_LEN))
|
||||
|
||||
|
||||
class DefaultSecurityGroup(model_base.BASEV2):
|
||||
class DefaultSecurityGroup(model_base.BASEV2, model_base.HasProjectPrimaryKey):
|
||||
__tablename__ = 'default_security_group'
|
||||
|
||||
tenant_id = sa.Column(sa.String(attributes.TENANT_ID_MAX_LEN),
|
||||
primary_key=True, nullable=False)
|
||||
security_group_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey("securitygroups.id",
|
||||
ondelete="CASCADE"),
|
||||
@ -83,7 +81,7 @@ class SecurityGroupPortBinding(model_base.BASEV2):
|
||||
|
||||
|
||||
class SecurityGroupRule(model_base.HasStandardAttributes, model_base.BASEV2,
|
||||
model_base.HasId, model_base.HasTenant):
|
||||
model_base.HasId, model_base.HasProject):
|
||||
"""Represents a v2 neutron security group rule."""
|
||||
|
||||
security_group_id = sa.Column(sa.String(36),
|
||||
|
@ -18,12 +18,11 @@ import sqlalchemy as sa
|
||||
from neutron.db import model_base
|
||||
|
||||
|
||||
class AutoAllocatedTopology(model_base.BASEV2):
|
||||
class AutoAllocatedTopology(model_base.BASEV2,
|
||||
model_base.HasProjectPrimaryKey):
|
||||
|
||||
__tablename__ = 'auto_allocated_topologies'
|
||||
|
||||
tenant_id = sa.Column(sa.String(255), primary_key=True)
|
||||
|
||||
network_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('networks.id',
|
||||
ondelete='CASCADE'),
|
||||
|
@ -23,7 +23,7 @@ from neutron.services.trunk import constants
|
||||
|
||||
|
||||
class Trunk(model_base.HasStandardAttributes, model_base.BASEV2,
|
||||
model_base.HasId, model_base.HasTenant):
|
||||
model_base.HasId, model_base.HasProject):
|
||||
|
||||
admin_state_up = sa.Column(
|
||||
sa.Boolean(), nullable=False, server_default=sql.true())
|
||||
|
@ -6007,7 +6007,7 @@ class TestSubnetPoolsV2(NeutronDbPluginV2TestCase):
|
||||
self.assertEqual(400, res.status_int)
|
||||
|
||||
|
||||
class DbModelTestCase(testlib_api.SqlTestCase):
|
||||
class DbModelMixin(object):
|
||||
"""DB model tests."""
|
||||
def test_repr(self):
|
||||
"""testing the string representation of 'model' classes."""
|
||||
@ -6016,7 +6016,7 @@ class DbModelTestCase(testlib_api.SqlTestCase):
|
||||
actual_repr_output = repr(network)
|
||||
exp_start_with = "<neutron.db.models_v2.Network"
|
||||
exp_middle = "[object at %x]" % id(network)
|
||||
exp_end_with = (" {tenant_id=None, id=None, "
|
||||
exp_end_with = (" {project_id=None, id=None, "
|
||||
"name='net_net', status='OK', "
|
||||
"admin_state_up=True, "
|
||||
"vlan_transparent=None, "
|
||||
@ -6025,43 +6025,6 @@ class DbModelTestCase(testlib_api.SqlTestCase):
|
||||
final_exp = exp_start_with + exp_middle + exp_end_with
|
||||
self.assertEqual(final_exp, actual_repr_output)
|
||||
|
||||
def _make_network(self, ctx):
|
||||
with ctx.session.begin():
|
||||
network = models_v2.Network(name="net_net", status="OK",
|
||||
tenant_id='dbcheck',
|
||||
admin_state_up=True)
|
||||
ctx.session.add(network)
|
||||
return network
|
||||
|
||||
def _make_subnet(self, ctx, network_id):
|
||||
with ctx.session.begin():
|
||||
subnet = models_v2.Subnet(name="subsub", ip_version=4,
|
||||
tenant_id='dbcheck',
|
||||
cidr='turn_down_for_what',
|
||||
network_id=network_id)
|
||||
ctx.session.add(subnet)
|
||||
return subnet
|
||||
|
||||
def _make_port(self, ctx, network_id):
|
||||
with ctx.session.begin():
|
||||
port = models_v2.Port(network_id=network_id, mac_address='1',
|
||||
tenant_id='dbcheck',
|
||||
admin_state_up=True, status="COOL",
|
||||
device_id="devid", device_owner="me")
|
||||
ctx.session.add(port)
|
||||
return port
|
||||
|
||||
def _make_subnetpool(self, ctx):
|
||||
with ctx.session.begin():
|
||||
subnetpool = models_v2.SubnetPool(
|
||||
ip_version=4, default_prefixlen=4, min_prefixlen=4,
|
||||
max_prefixlen=4, shared=False, default_quota=4,
|
||||
address_scope_id='f', tenant_id='dbcheck',
|
||||
is_default=False
|
||||
)
|
||||
ctx.session.add(subnetpool)
|
||||
return subnetpool
|
||||
|
||||
def _make_security_group_and_rule(self, ctx):
|
||||
with ctx.session.begin():
|
||||
sg = sgdb.SecurityGroup(name='sg', description='sg')
|
||||
@ -6251,6 +6214,84 @@ class DbModelTestCase(testlib_api.SqlTestCase):
|
||||
disc, obj.standard_attr.resource_type)
|
||||
|
||||
|
||||
class DbModelTenantTestCase(DbModelMixin, testlib_api.SqlTestCase):
|
||||
def _make_network(self, ctx):
|
||||
with ctx.session.begin():
|
||||
network = models_v2.Network(name="net_net", status="OK",
|
||||
tenant_id='dbcheck',
|
||||
admin_state_up=True)
|
||||
ctx.session.add(network)
|
||||
return network
|
||||
|
||||
def _make_subnet(self, ctx, network_id):
|
||||
with ctx.session.begin():
|
||||
subnet = models_v2.Subnet(name="subsub", ip_version=4,
|
||||
tenant_id='dbcheck',
|
||||
cidr='turn_down_for_what',
|
||||
network_id=network_id)
|
||||
ctx.session.add(subnet)
|
||||
return subnet
|
||||
|
||||
def _make_port(self, ctx, network_id):
|
||||
with ctx.session.begin():
|
||||
port = models_v2.Port(network_id=network_id, mac_address='1',
|
||||
tenant_id='dbcheck',
|
||||
admin_state_up=True, status="COOL",
|
||||
device_id="devid", device_owner="me")
|
||||
ctx.session.add(port)
|
||||
return port
|
||||
|
||||
def _make_subnetpool(self, ctx):
|
||||
with ctx.session.begin():
|
||||
subnetpool = models_v2.SubnetPool(
|
||||
ip_version=4, default_prefixlen=4, min_prefixlen=4,
|
||||
max_prefixlen=4, shared=False, default_quota=4,
|
||||
address_scope_id='f', tenant_id='dbcheck',
|
||||
is_default=False
|
||||
)
|
||||
ctx.session.add(subnetpool)
|
||||
return subnetpool
|
||||
|
||||
|
||||
class DbModelProjectTestCase(DbModelMixin, testlib_api.SqlTestCase):
|
||||
def _make_network(self, ctx):
|
||||
with ctx.session.begin():
|
||||
network = models_v2.Network(name="net_net", status="OK",
|
||||
project_id='dbcheck',
|
||||
admin_state_up=True)
|
||||
ctx.session.add(network)
|
||||
return network
|
||||
|
||||
def _make_subnet(self, ctx, network_id):
|
||||
with ctx.session.begin():
|
||||
subnet = models_v2.Subnet(name="subsub", ip_version=4,
|
||||
project_id='dbcheck',
|
||||
cidr='turn_down_for_what',
|
||||
network_id=network_id)
|
||||
ctx.session.add(subnet)
|
||||
return subnet
|
||||
|
||||
def _make_port(self, ctx, network_id):
|
||||
with ctx.session.begin():
|
||||
port = models_v2.Port(network_id=network_id, mac_address='1',
|
||||
project_id='dbcheck',
|
||||
admin_state_up=True, status="COOL",
|
||||
device_id="devid", device_owner="me")
|
||||
ctx.session.add(port)
|
||||
return port
|
||||
|
||||
def _make_subnetpool(self, ctx):
|
||||
with ctx.session.begin():
|
||||
subnetpool = models_v2.SubnetPool(
|
||||
ip_version=4, default_prefixlen=4, min_prefixlen=4,
|
||||
max_prefixlen=4, shared=False, default_quota=4,
|
||||
address_scope_id='f', project_id='dbcheck',
|
||||
is_default=False
|
||||
)
|
||||
ctx.session.add(subnetpool)
|
||||
return subnetpool
|
||||
|
||||
|
||||
class NeutronDbPluginV2AsMixinTestCase(NeutronDbPluginV2TestCase,
|
||||
testlib_api.SqlTestCase):
|
||||
"""Tests for NeutronDbPluginV2 as Mixin.
|
||||
|
@ -19,9 +19,9 @@ from neutron.db import model_base
|
||||
# Model classes for test resources
|
||||
|
||||
|
||||
class MehModel(model_base.BASEV2, model_base.HasTenant):
|
||||
class MehModel(model_base.BASEV2, model_base.HasProject):
|
||||
meh = sa.Column(sa.String(8), primary_key=True)
|
||||
|
||||
|
||||
class OtherMehModel(model_base.BASEV2, model_base.HasTenant):
|
||||
class OtherMehModel(model_base.BASEV2, model_base.HasProject):
|
||||
othermeh = sa.Column(sa.String(8), primary_key=True)
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
tenant_id column has been renamed to project_id.
|
||||
This database migration is required to be applied as offline migration.
|
Loading…
Reference in New Issue
Block a user