Scope common App Profile with the system ID
For compatibility on multi OS instances per APIC Change-Id: Iaf93f24466889a7f2a1e84605ca59b6e9ad5ec56
This commit is contained in:
parent
1bd73b1709
commit
3ad4abcea8
@ -1 +1 @@
|
||||
d978a7a73785
|
||||
facc1ababba1
|
@ -0,0 +1,46 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""change common ap name
|
||||
|
||||
Revision ID: facc1ababba1
|
||||
Revises: d978a7a73785
|
||||
Create Date: 2017-05-15 00:00:00.000000
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'facc1ababba1'
|
||||
down_revision = 'd978a7a73785'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
# See if AIM is being used, and if so, migrate data.
|
||||
bind = op.get_bind()
|
||||
insp = sa.engine.reflection.Inspector.from_engine(bind)
|
||||
if 'aim_tenants' in insp.get_table_names():
|
||||
# Note - this cannot be imported unless we know the
|
||||
# apic_aim mechanism driver is deployed, since the AIM
|
||||
# library may not be installed.
|
||||
from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import (
|
||||
data_migrations)
|
||||
|
||||
session = sa.orm.Session(bind=bind, autocommit=True)
|
||||
data_migrations.do_ap_name_change(session)
|
||||
|
||||
|
||||
def downgrade():
|
||||
pass
|
@ -13,6 +13,13 @@
|
||||
from neutron.db.migration.cli import * # noqa
|
||||
|
||||
|
||||
global_opts = [
|
||||
cfg.StrOpt('apic_system_id',
|
||||
help="Prefix for APIC domain/names/profiles created"),
|
||||
]
|
||||
CONF.register_cli_opts(global_opts)
|
||||
|
||||
|
||||
def main():
|
||||
config = alembic_config.Config(
|
||||
os.path.join(os.path.dirname(__file__), 'alembic.ini'))
|
||||
|
@ -19,10 +19,13 @@ from aim.api import resource as aim_resource
|
||||
from aim import context as aim_context
|
||||
from alembic import util as alembic_util
|
||||
from neutron.db.models import address_scope as as_db
|
||||
from neutron.db.migration.cli import * # noqa
|
||||
from neutron.db import models_v2
|
||||
from neutron.db import segments_db # noqa
|
||||
from neutron_lib.db import model_base
|
||||
import sqlalchemy as sa
|
||||
|
||||
from gbpservice.neutron.extensions import cisco_apic as ext
|
||||
from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import apic_mapper
|
||||
from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import db
|
||||
from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import extension_db
|
||||
@ -149,3 +152,81 @@ def do_apic_aim_persist_migration(session):
|
||||
|
||||
alembic_util.msg(
|
||||
"Finished data migration for apic_aim mechanism driver persistence.")
|
||||
|
||||
|
||||
def do_ap_name_change(session, conf=None):
|
||||
alembic_util.msg("Starting data migration for apic_aim ap name change.")
|
||||
cfg = conf or CONF
|
||||
aim = aim_manager.AimManager()
|
||||
aim_ctx = aim_context.AimContext(session)
|
||||
system_id = cfg.apic_system_id
|
||||
alembic_util.msg("APIC System ID: %s" % system_id)
|
||||
ext_mixin = extension_db.ExtensionDbMixin()
|
||||
db_mixin = db.DbMixin()
|
||||
with session.begin(subtransactions=True):
|
||||
net_dbs = session.query(models_v2.Network).all()
|
||||
for net_db in net_dbs:
|
||||
ext_db = ext_mixin.get_network_extn_db(session, net_db.id)
|
||||
if ext_db and ext_db[ext.EXTERNAL_NETWORK]:
|
||||
alembic_util.msg("Migrating external network: %s" % net_db)
|
||||
# Its a managed external network.
|
||||
ext_net = aim_resource.ExternalNetwork.from_dn(
|
||||
ext_db[ext.EXTERNAL_NETWORK])
|
||||
ext_net = aim.get(aim_ctx, ext_net)
|
||||
l3out = aim_resource.L3Outside(tenant_name=ext_net.tenant_name,
|
||||
name=ext_net.l3out_name)
|
||||
if ext_db[ext.NAT_TYPE] == '':
|
||||
ns_cls = nat_strategy.NoNatStrategy
|
||||
elif ext_db[ext.NAT_TYPE] == 'edge':
|
||||
ns_cls = nat_strategy.EdgeNatStrategy
|
||||
else:
|
||||
ns_cls = nat_strategy.DistributedNatStrategy
|
||||
clone_ext_nets = {}
|
||||
ns = ns_cls(aim)
|
||||
ns.app_profile_name = 'OpenStack'
|
||||
ns.common_scope = None
|
||||
# Start Cleanup
|
||||
if not isinstance(ns, nat_strategy.NoNatStrategy):
|
||||
l3out_clones = ns.db.get_clones(aim_ctx, l3out)
|
||||
# Retrieve External Networks
|
||||
for l3out_clone in l3out_clones:
|
||||
for extc in aim.find(
|
||||
aim_ctx, aim_resource.ExternalNetwork,
|
||||
tenant_name=l3out_clone[0],
|
||||
l3out_name=l3out_clone[1]):
|
||||
clone_ext_nets[(l3out.tenant_name,
|
||||
l3out.name,
|
||||
extc.name)] = extc
|
||||
vrfs = ns.read_vrfs(aim_ctx, ext_net)
|
||||
session.query(db.NetworkMapping).filter(
|
||||
db.NetworkMapping.network_id == net_db.id).delete()
|
||||
for vrf in vrfs:
|
||||
ns.disconnect_vrf(aim_ctx, ext_net, vrf)
|
||||
ns.delete_external_network(aim_ctx, ext_net)
|
||||
ns.delete_l3outside(aim_ctx, l3out)
|
||||
# Recreate
|
||||
ns.common_scope = system_id
|
||||
ns.create_l3outside(aim_ctx, l3out)
|
||||
ns.create_external_network(aim_ctx, ext_net)
|
||||
ns.update_external_cidrs(aim_ctx, ext_net,
|
||||
ext_db[ext.EXTERNAL_CIDRS])
|
||||
for subnet in net_db.subnets:
|
||||
aim_subnet = aim_resource.Subnet.to_gw_ip_mask(
|
||||
subnet.gateway_ip, int(subnet.cidr.split('/')[1]))
|
||||
ns.create_subnet(aim_ctx, l3out, aim_subnet)
|
||||
for resource in ns.get_l3outside_resources(aim_ctx, l3out):
|
||||
if isinstance(resource, aim_resource.BridgeDomain):
|
||||
bd = resource
|
||||
elif isinstance(resource, aim_resource.EndpointGroup):
|
||||
epg = resource
|
||||
elif isinstance(resource, aim_resource.VRF):
|
||||
vrf = resource
|
||||
db_mixin._add_network_mapping(session, net_db.id, bd, epg, vrf)
|
||||
eid = (ext_net.tenant_name, ext_net.l3out_name, ext_net.name)
|
||||
for vrf in vrfs:
|
||||
if eid in clone_ext_nets:
|
||||
ext_net.provided_contract_names = clone_ext_nets[
|
||||
eid].provided_contract_names
|
||||
ext_net.consumed_contract_names = clone_ext_nets[
|
||||
eid].consumed_contract_names
|
||||
ns.connect_vrf(aim_ctx, ext_net, vrf)
|
||||
|
@ -2254,16 +2254,6 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
|
||||
mapping = self._get_network_mapping(session, network['id'])
|
||||
return mapping and self._get_network_vrf(mapping)
|
||||
|
||||
# DB Configuration callbacks
|
||||
def _set_enable_metadata_opt(self, new_conf):
|
||||
self.enable_metadata_opt = new_conf['value']
|
||||
|
||||
def _set_enable_dhcp_opt(self, new_conf):
|
||||
self.enable_dhcp_opt = new_conf['value']
|
||||
|
||||
def _set_ap_name(self, new_conf):
|
||||
self.ap_name = new_conf['value']
|
||||
|
||||
def get_aim_domains(self, aim_ctx):
|
||||
vmms = [x.name for x in self.aim.find(aim_ctx, aim_resource.VMMDomain)
|
||||
if x.type == utils.OPENSTACK_VMM_TYPE]
|
||||
@ -2282,6 +2272,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
|
||||
ns_cls = nat_strategy.EdgeNatStrategy
|
||||
ns = ns_cls(self.aim)
|
||||
ns.app_profile_name = self.ap_name
|
||||
ns.common_scope = self.apic_system_id
|
||||
return ns
|
||||
|
||||
def _get_aim_nat_strategy(self, network):
|
||||
|
@ -2137,6 +2137,8 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
|
||||
ext_segment_name = dn.replace('/', ':')
|
||||
ipms.append({'external_segment_name': ext_segment_name,
|
||||
'nat_epg_name': ext_net_epg.name,
|
||||
'nat_epg_app_profile': (
|
||||
ext_net_epg.app_profile_name),
|
||||
'nat_epg_tenant': ext_net_epg.tenant_name})
|
||||
# TODO(amitbose) Set next_hop_ep_tenant for per-tenant NAT EPG
|
||||
if host:
|
||||
@ -2148,6 +2150,7 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
|
||||
else:
|
||||
for f in fips_in_ext_net:
|
||||
f['nat_epg_name'] = ext_net_epg.name
|
||||
f['nat_epg_app_profile'] = ext_net_epg.app_profile_name
|
||||
f['nat_epg_tenant'] = ext_net_epg.tenant_name
|
||||
return fips, ipms, host_snat_ips
|
||||
|
||||
|
@ -3275,6 +3275,102 @@ class TestMigrations(ApicAimTestCase, db.DbMixin):
|
||||
epg = self._find_by_dn(net1_epg, aim_resource.EndpointGroup)
|
||||
self.assertIsNone(epg)
|
||||
|
||||
def test_ap_name_change(self):
|
||||
self.tenant_1 = 't1'
|
||||
net = self._make_ext_network(
|
||||
'net2', dn='uni/tn-common/out-l1/instP-n1')
|
||||
self._make_subnet(self.fmt, {'network': net}, '10.0.1.1',
|
||||
'10.0.1.0/24')
|
||||
|
||||
addr_scope = self._make_address_scope(
|
||||
self.fmt, 4, name='as1', tenant_id=self.tenant_1)['address_scope']
|
||||
subnetpool = self._make_subnetpool(
|
||||
self.fmt, ['10.0.0.0/8'], name='spool1', tenant_id=self.tenant_1,
|
||||
address_scope_id=addr_scope['id'])['subnetpool']
|
||||
net_int = self._make_network(self.fmt, 'pvt-net', True,
|
||||
tenant_id=self.tenant_1)['network']
|
||||
sp_id = subnetpool['id']
|
||||
sub = self._make_subnet(
|
||||
self.fmt, {'network': net_int}, '10.10.1.1', '10.10.1.0/24',
|
||||
subnetpool_id=sp_id)['subnet']
|
||||
router = self._make_router(
|
||||
self.fmt, self.tenant_1, 'router',
|
||||
arg_list=self.extension_attributes,
|
||||
external_gateway_info={'network_id': net['id']})['router']
|
||||
self._router_interface_action('add', router['id'], sub['id'], None)
|
||||
|
||||
aim = self.aim_mgr
|
||||
aim_ctx = aim_context.AimContext(self.db_session)
|
||||
ns = self.driver._nat_type_to_strategy(None)
|
||||
ext_net = aim_resource.ExternalNetwork.from_dn(
|
||||
net[DN]['ExternalNetwork'])
|
||||
l3out = aim_resource.L3Outside(tenant_name=ext_net.tenant_name,
|
||||
name=ext_net.l3out_name)
|
||||
right_res = ns.get_l3outside_resources(aim_ctx, l3out)
|
||||
for res in copy.deepcopy(right_res):
|
||||
if isinstance(res, aim_resource.ApplicationProfile):
|
||||
aim.delete(aim_ctx, res)
|
||||
res.name = self.driver.ap_name
|
||||
wrong_ap = aim.create(aim_ctx, res)
|
||||
if isinstance(res, aim_resource.EndpointGroup):
|
||||
aim.delete(aim_ctx, res)
|
||||
res.app_profile_name = self.driver.ap_name
|
||||
res.bd_name = 'EXT-%s' % l3out.name
|
||||
wrong_epg = aim.create(aim_ctx, res)
|
||||
if isinstance(res, aim_resource.BridgeDomain):
|
||||
aim.delete(aim_ctx, res)
|
||||
res.name = 'EXT-%s' % l3out.name
|
||||
wrong_bd = aim.create(aim_ctx, res)
|
||||
if isinstance(res, aim_resource.Contract):
|
||||
aim.delete(aim_ctx, res)
|
||||
res.name = 'EXT-%s' % l3out.name
|
||||
wrong_ctr = aim.create(aim_ctx, res)
|
||||
if isinstance(res, aim_resource.Filter):
|
||||
aim.delete(aim_ctx, res)
|
||||
res.name = 'EXT-%s' % l3out.name
|
||||
wrong_flt = aim.create(aim_ctx, res)
|
||||
if isinstance(res, aim_resource.FilterEntry):
|
||||
aim.delete(aim_ctx, res)
|
||||
res.filter_name = 'EXT-%s' % l3out.name
|
||||
wrong_entry = aim.create(aim_ctx, res)
|
||||
if isinstance(res, aim_resource.ContractSubject):
|
||||
aim.delete(aim_ctx, res)
|
||||
res.contract_name = 'EXT-%s' % l3out.name
|
||||
wrong_sbj = aim.create(aim_ctx, res)
|
||||
|
||||
ns.common_scope = None
|
||||
wrong_res = ns.get_l3outside_resources(aim_ctx, l3out)
|
||||
self.assertEqual(len(right_res), len(wrong_res))
|
||||
self.assertNotEqual(sorted(right_res), sorted(wrong_res))
|
||||
|
||||
data_migrations.do_ap_name_change(self.db_session, cfg.CONF)
|
||||
# Verify new model
|
||||
ns = self.driver._nat_type_to_strategy(None)
|
||||
final_res = ns.get_l3outside_resources(aim_ctx, l3out)
|
||||
self.assertEqual(sorted(right_res), sorted(final_res))
|
||||
self.assertIsNone(aim.get(aim_ctx, wrong_ap))
|
||||
self.assertIsNone(aim.get(aim_ctx, wrong_epg))
|
||||
self.assertIsNone(aim.get(aim_ctx, wrong_bd))
|
||||
self.assertIsNone(aim.get(aim_ctx, wrong_ctr))
|
||||
self.assertIsNone(aim.get(aim_ctx, wrong_flt))
|
||||
self.assertIsNone(aim.get(aim_ctx, wrong_entry))
|
||||
self.assertIsNone(aim.get(aim_ctx, wrong_sbj))
|
||||
self.assertIsNotNone(ns.get_subnet(aim_ctx, l3out, '10.0.1.1/24'))
|
||||
# Top level objects are scoped
|
||||
for r in final_res:
|
||||
if any(isinstance(r, x) for x in [aim_resource.ApplicationProfile,
|
||||
aim_resource.BridgeDomain,
|
||||
aim_resource.Contract,
|
||||
aim_resource.Filter]):
|
||||
self.assertTrue(r.name.startswith(self.driver.apic_system_id),
|
||||
'%s name: %s' % (type(r), r.name))
|
||||
self._update('routers', router['id'],
|
||||
{'router': {'external_gateway_info': {}}})
|
||||
self._delete('networks', net['id'])
|
||||
for r in final_res:
|
||||
self.assertIsNone(aim.get(aim_ctx, r),
|
||||
'Resource: %s still in AIM' % r)
|
||||
|
||||
|
||||
class TestPortBinding(ApicAimTestCase):
|
||||
def test_bind_opflex_agent(self):
|
||||
|
@ -2888,17 +2888,20 @@ class TestPolicyTarget(AIMBaseTestCase):
|
||||
return ext_seg, subnet
|
||||
|
||||
def _verify_fip_details(self, mapping, fip, ext_epg_tenant,
|
||||
ext_epg_name):
|
||||
ext_epg_name, ext_epg_app_profile='OpenStack'):
|
||||
self.assertEqual(1, len(mapping['floating_ip']))
|
||||
fip = copy.deepcopy(fip)
|
||||
fip['nat_epg_name'] = ext_epg_name
|
||||
fip['nat_epg_tenant'] = ext_epg_tenant
|
||||
fip['nat_epg_app_profile'] = ext_epg_app_profile
|
||||
self.assertEqual(fip, mapping['floating_ip'][0])
|
||||
|
||||
def _verify_ip_mapping_details(self, mapping, ext_segment_name,
|
||||
ext_epg_tenant, ext_epg_name):
|
||||
ext_epg_tenant, ext_epg_name,
|
||||
ext_epg_app_profile='OpenStack'):
|
||||
self.assertTrue({'external_segment_name': ext_segment_name,
|
||||
'nat_epg_name': ext_epg_name,
|
||||
'nat_epg_app_profile': ext_epg_app_profile,
|
||||
'nat_epg_tenant': ext_epg_tenant}
|
||||
in mapping['ip_mapping'])
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user