diff --git a/neutron_dynamic_routing/db/bgp_db.py b/neutron_dynamic_routing/db/bgp_db.py index 52ab5a6f..dc308cbc 100644 --- a/neutron_dynamic_routing/db/bgp_db.py +++ b/neutron_dynamic_routing/db/bgp_db.py @@ -19,6 +19,7 @@ from oslo_log import log as logging from oslo_utils import uuidutils import sqlalchemy as sa from sqlalchemy import and_ +from sqlalchemy.ext import declarative from sqlalchemy import orm from sqlalchemy.orm import aliased from sqlalchemy.orm import exc as sa_exc @@ -45,6 +46,29 @@ DEVICE_OWNER_ROUTER_GW = lib_consts.DEVICE_OWNER_ROUTER_GW DEVICE_OWNER_ROUTER_INTF = lib_consts.DEVICE_OWNER_ROUTER_INTF +class HasTenant(object): + # NOTE(HenryG): Temporary solution! + # Remove when I87a8ef342ccea004731ba0192b23a8e79bc382dc is merged. + + project_id = sa.Column(sa.String(attr.TENANT_ID_MAX_LEN), index=True) + + def __init__(self, *args, **kwargs): + # NOTE(HenryG): debtcollector requires init in class + super(HasTenant, 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 + def tenant_id(cls): + return orm.synonym( + 'project_id', + descriptor=property(cls.get_tenant_id, cls.set_tenant_id)) + + class BgpSpeakerPeerBinding(model_base.BASEV2): """Represents a mapping between BGP speaker and BGP peer""" @@ -85,7 +109,7 @@ class BgpSpeakerNetworkBinding(model_base.BASEV2): class BgpSpeaker(model_base.BASEV2, model_base.HasId, - model_base.HasTenant): + HasTenant): """Represents a BGP speaker""" @@ -108,7 +132,7 @@ class BgpSpeaker(model_base.BASEV2, class BgpPeer(model_base.BASEV2, model_base.HasId, - model_base.HasTenant): + HasTenant): """Represents a BGP routing peer.""" diff --git a/neutron_dynamic_routing/db/migration/alembic_migrations/versions/CONTRACT_HEAD b/neutron_dynamic_routing/db/migration/alembic_migrations/versions/CONTRACT_HEAD index 2d217581..2130dc38 100644 --- a/neutron_dynamic_routing/db/migration/alembic_migrations/versions/CONTRACT_HEAD +++ b/neutron_dynamic_routing/db/migration/alembic_migrations/versions/CONTRACT_HEAD @@ -1 +1 @@ -61cc795e43e8 +4cf8bc3edb66 diff --git a/neutron_dynamic_routing/db/migration/alembic_migrations/versions/newton/contract/4cf8bc3edb66_rename_tenant_to_project.py b/neutron_dynamic_routing/db/migration/alembic_migrations/versions/newton/contract/4cf8bc3edb66_rename_tenant_to_project.py new file mode 100644 index 00000000..dac79029 --- /dev/null +++ b/neutron_dynamic_routing/db/migration/alembic_migrations/versions/newton/contract/4cf8bc3edb66_rename_tenant_to_project.py @@ -0,0 +1,133 @@ +# 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: 4cf8bc3edb66 +Revises: 61cc795e43e8 +Create Date: 2016-07-14 17:32:00.852342 + +""" + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.engine import reflection + +# revision identifiers, used by Alembic. +revision = '4cf8bc3edb66' +down_revision = '61cc795e43e8' + + +_INSPECTOR = None + + +def get_inspector(): + """Reuse inspector""" + + global _INSPECTOR + + if _INSPECTOR: + return _INSPECTOR + + bind = op.get_bind() + _INSPECTOR = reflection.Inspector.from_engine(bind) + return _INSPECTOR + + +def get_tables(): + """ + Returns hardcoded list of tables which have ``tenant_id`` column. + + The list is hardcoded to match the state of the schema when this + upgrade script is run. + """ + + tables = [ + 'bgp_peers', + 'bgp_speakers', + ] + + 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)]. + + The list is built from tables with a tenant_id column. + """ + + 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(): + """Code reused from + + Change-Id: I87a8ef342ccea004731ba0192b23a8e79bc382dc + """ + + 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() + }