Normalization of Remote IPs

Change-Id: Ib955b7f27fc4ac6b48c81ff29f1dd4ffbd2560f0
This commit is contained in:
sayalinaval 2023-10-15 12:23:52 -07:00 committed by Sayali Vidyadhar Naval
parent 1866d635d9
commit 89fd3400d0
9 changed files with 734 additions and 143 deletions

View File

@ -1 +1 @@
dc99863d1f2b
fd3e605a7232

View File

@ -0,0 +1,51 @@
# 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.
"""HPP Table
Revision ID: fd3e605a7232
Revises: dc99863d1f2b
Create Date: 2023-09-19 02:08:54.252877
"""
# revision identifiers, used by Alembic.
revision = 'fd3e605a7232'
down_revision = 'dc99863d1f2b'
from alembic import op
from alembic import util
import sqlalchemy as sa
def upgrade():
bind = op.get_bind()
op.create_table(
'apic_aim_hpp',
sa.Column('hpp_normalized', sa.Boolean, nullable=False),
sa.PrimaryKeyConstraint('hpp_normalized'))
try:
from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import (
data_migrations)
session = sa.orm.Session(bind=bind, autocommit=True)
with session.begin(subtransactions=True):
data_migrations.do_hpp_insertion(session)
except Exception as e:
util.warn("Caught exception while migrating data in %s: %s" %
('apic_aim_hpp', e))
def downgrade():
pass

View File

@ -69,6 +69,11 @@ AddressScopeMapping = sa.Table(
sa.Column('vrf_owned', sa.Boolean, nullable=False))
HPPDB = sa.Table(
'apic_aim_hpp', sa.MetaData(),
sa.Column('hpp_normalized', sa.Boolean, nullable=False))
# The following definition has been taken from commit:
# f8b41855acbbb7e59a0bab439445c198fc6aa146
# and is frozen for the data migration script that was included
@ -484,8 +489,6 @@ def do_ha_ip_network_id_insertion(session):
haip_port_id = HAIPAddressToPortAssociation.c.port_id
with session.begin(subtransactions=True):
haip_ip = HAIPAddressToPortAssociation.c.ha_ip_address
haip_port_id = HAIPAddressToPortAssociation.c.port_id
port_and_haip_dbs = (session.query(models_v2.Port,
HAIPAddressToPortAssociation).join(
HAIPAddressToPortAssociation,
@ -500,3 +503,93 @@ def do_ha_ip_network_id_insertion(session):
alembic_util.msg(
"Finished network id insertion for HA IP table.")
def do_hpp_insertion(session):
alembic_util.msg(
"Starting hpp normalized value insertion for HPP table.")
with session.begin(subtransactions=True):
session.execute(HPPDB.insert().values(hpp_normalized=False))
alembic_util.msg(
"Finished hpp normalized value insertion for HPP table.")
def normalize_hpp_ips(session):
aim = aim_manager.AimManager()
aim_ctx = aim_context.AimContext(session)
mapper = apic_mapper.APICNameMapper()
sg_dbs = (session.query(sg_models.SecurityGroup).
options(lazyload('*')).all())
for sg_db in sg_dbs:
tenant_aname = mapper.project(session,
sg_db['tenant_id'])
# Create remote group container for each security group
try:
sg_remote_group = aim_resource.SecurityGroupRemoteIpContainer(
tenant_name=tenant_aname,
security_group_name=sg_db['id'],
name=sg_db['id'])
aim.create(aim_ctx, sg_remote_group)
except Exception as e:
alembic_util.warning("%s" % e)
sg_ports = (session.query(models_v2.Port).
join(sg_models.SecurityGroupPortBinding,
sg_models.SecurityGroupPortBinding.port_id ==
models_v2.Port.id).
filter(sg_models.SecurityGroupPortBinding.
security_group_id ==
sg_db['id']).
options(lazyload('*')).all())
for sg_port in sg_ports:
for fixed_ip in sg_port['fixed_ips']:
# Create SG remote ip resource for each fixed ip
sg_remote_group_ip = aim_resource.SecurityGroupRemoteIp(
tenant_name=tenant_aname,
security_group_name=sg_db['id'],
addr=fixed_ip['ip_address'])
aim.create(aim_ctx, sg_remote_group_ip)
def normalize_hpps(session):
aim = aim_manager.AimManager()
aim_ctx = aim_context.AimContext(session)
mapper = apic_mapper.APICNameMapper()
sg_rule_dbs = (session.query(sg_models.SecurityGroupRule).
options(lazyload('*')).all())
for sg_rule_db in sg_rule_dbs:
sg = (session.query(sg_models.SecurityGroup).
filter(sg_models.SecurityGroup.id ==
sg_rule_db['security_group_id']).
options(lazyload('*')).first())
tenant_id = sg['tenant_id']
tenant_aname = mapper.project(session, tenant_id)
if sg_rule_db.get('remote_group_id'):
sg_rule_aim = aim_resource.SecurityGroupRule(
tenant_name=tenant_aname,
security_group_name=sg_rule_db['security_group_id'],
security_group_subject_name='default',
name=sg_rule_db['id'])
sg_rule_aim = aim.get(aim_ctx, sg_rule_aim)
if sg_rule_aim.remote_ips:
# Get the remote group container's dn
rg = (session.query(sg_models.SecurityGroup).
filter(sg_models.SecurityGroup.id ==
sg_rule_db['remote_group_id']).
options(lazyload('*')).first())
rg_tenant_id = rg['tenant_id']
rg_tenant_aname = mapper.project(session, rg_tenant_id)
rg_cont = aim_resource.SecurityGroupRemoteIpContainer(
tenant_name=rg_tenant_aname,
security_group_name=sg_rule_db['remote_group_id'],
name=sg_rule_db['remote_group_id'])
# Update SG rule tDn with remote group container dn
aim.update(aim_ctx, sg_rule_aim,
remote_ips=[], tDn=rg_cont.dn)

View File

@ -182,6 +182,13 @@ class RouterExtensionContractDb(model_base.BASEV2):
provides = sa.Column(sa.Boolean, primary_key=True)
class HPPDb(model_base.BASEV2):
__tablename__ = 'apic_aim_hpp'
hpp_normalized = sa.Column(sa.Boolean, default=False,
primary_key=True)
class ExtensionDbMixin(object):
def _set_if_not_none(self, res_dict, res_attr, db_attr):
@ -667,3 +674,16 @@ class ExtensionDbMixin(object):
'contract_name',
res_dict[cisco_apic_l3.EXTERNAL_CONSUMED_CONTRACTS],
router_id=router_id, provides=False)
def get_hpp_normalized(self, session):
with session.begin(subtransactions=True):
query = BAKERY(lambda s: s.query(HPPDb))
db_obj = query(session).first()
return db_obj['hpp_normalized']
def set_hpp_normalized(self, session, hpp_normalized):
with session.begin(subtransactions=True):
query = BAKERY(lambda s: s.query(HPPDb))
db_obj = query(session).first()
db_obj['hpp_normalized'] = hpp_normalized
session.add(db_obj)

View File

@ -87,6 +87,7 @@ from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import (
from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import apic_mapper
from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import cache
from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import config # noqa
from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import data_migrations
from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import db
from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import exceptions
from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import extension_db
@ -2809,18 +2810,77 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
# and try binding hierarchically if the network-type is OpFlex.
self._bind_physical_node(context)
def _update_sg_rule_with_remote_group_set(self, context, port):
security_groups = port['security_groups']
original_port = context.original
if original_port:
removed_sgs = (set(original_port['security_groups']) -
set(security_groups))
added_sgs = (set(security_groups) -
set(original_port['security_groups']))
self._really_update_sg_rule_with_remote_group_set(
context, port, removed_sgs, is_delete=True)
self._really_update_sg_rule_with_remote_group_set(
context, port, added_sgs, is_delete=False)
def _really_update_sg_remote_groups(
self, context, port, security_groups, is_delete):
if not security_groups:
return
session = context._plugin_context.session
aim_ctx = aim_context.AimContext(session)
fixed_ips = [x['ip_address'] for x in port['fixed_ips']]
for sg in security_groups:
tenant_id = self._get_sg_tenant_id(session, sg)
tenant_aname = self.name_mapper.project(session, tenant_id)
for fixed_ip in fixed_ips:
# Create or delete SG remote ip resource for fixed ip
sg_rg_ip_aim = aim_resource.SecurityGroupRemoteIp(
tenant_name=tenant_aname,
security_group_name=sg,
addr=fixed_ip)
if is_delete:
if self.aim.get(aim_ctx, sg_rg_ip_aim):
self.aim.delete(aim_ctx, sg_rg_ip_aim)
else:
if not self.aim.get(aim_ctx, sg_rg_ip_aim):
self.aim.create(aim_ctx, sg_rg_ip_aim)
query = BAKERY(lambda s: s.query(
models_v2.Port))
query += lambda q: q.join(
sg_models.SecurityGroupPortBinding,
sg_models.SecurityGroupPortBinding.port_id ==
models_v2.Port.id)
query += lambda q: q.filter(
sg_models.SecurityGroupPortBinding.security_group_id ==
sa.bindparam('sg_id'))
sg_ports = query(session).params(
sg_id=sg).all()
all_fixed_ips = []
for sg_port in sg_ports:
ip_addr = [x['ip_address'] for x in sg_port['fixed_ips']]
all_fixed_ips.extend(ip_addr)
old_fixed_ips = list(set(all_fixed_ips) - set(fixed_ips))
if (fixed_ips and not old_fixed_ips):
query = BAKERY(lambda s: s.query(
sg_models.SecurityGroupRule))
query += lambda q: q.filter(
sg_models.SecurityGroupRule.remote_group_id ==
sa.bindparam('security_group'))
sg_rules = query(session).params(
security_group=sg).all()
sg_rule_to_tenant = {}
for sg_rule in sg_rules:
sg_id = sg_rule['security_group_id']
sg_rule_tenant_id = sg_rule_to_tenant.setdefault(sg_id,
self._get_sg_rule_tenant_id(session, sg_rule))
sg_rule_tenant_aname = self.name_mapper.project(
session, sg_rule_tenant_id)
sg_rule_aim = aim_resource.SecurityGroupRule(
tenant_name=sg_rule_tenant_aname,
security_group_name=sg_id,
security_group_subject_name='default',
name=sg_rule['id'])
if is_delete:
self.aim.update(aim_ctx, sg_rule_aim, tDn='')
else:
rg_cont = aim_resource.SecurityGroupRemoteIpContainer(
tenant_name=tenant_aname,
security_group_name=sg_rule['remote_group_id'],
name=sg_rule['remote_group_id'])
self.aim.update(aim_ctx, sg_rule_aim, tDn=rg_cont.dn)
def _really_update_sg_rule_with_remote_group_set(
self, context, port, security_groups, is_delete):
@ -2839,11 +2899,8 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
sg_to_tenant = {}
for sg_rule in sg_rules:
sg_id = sg_rule['security_group_id']
if sg_id in sg_to_tenant:
tenant_id = sg_to_tenant[sg_id]
else:
tenant_id = self._get_sg_rule_tenant_id(session, sg_rule)
sg_to_tenant[sg_id] = tenant_id
tenant_id = sg_to_tenant.setdefault(sg_id,
self._get_sg_rule_tenant_id(session, sg_rule))
tenant_aname = self.name_mapper.project(session, tenant_id)
sg_rule_aim = aim_resource.SecurityGroupRule(
tenant_name=tenant_aname,
@ -3110,11 +3167,16 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
def create_port_precommit(self, context):
port = context.current
session = context._plugin_context.session
self._check_active_active_aap(context, port)
if port.get(cisco_apic.ERSPAN_CONFIG):
self._check_valid_erspan_config(port)
self._really_update_sg_rule_with_remote_group_set(
context, port, port['security_groups'], is_delete=False)
if self.get_hpp_normalized(session):
self._really_update_sg_remote_groups(
context, port, port['security_groups'], is_delete=False)
else:
self._really_update_sg_rule_with_remote_group_set(
context, port, port['security_groups'], is_delete=False)
self._insert_provisioning_block(context)
# Handle router gateway port creation.
@ -3330,7 +3392,41 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
erspan_deletions)
self._create_erspan_aim_config(context, cep_dn, port)
self._update_sg_rule_with_remote_group_set(context, port)
security_groups = port['security_groups']
# Check if any security groups are changed for the port
removed_sgs = (set(orig['security_groups']) -
set(security_groups))
added_sgs = (set(security_groups) -
set(orig['security_groups']))
# Check if any fixed ips are changed for the port
orig_ips = [x['ip_address'] for x in orig['fixed_ips']]
ips = [x['ip_address'] for x in port['fixed_ips']]
removed_ips = (set(orig_ips) - set(ips))
added_ips = (set(ips) - set(orig_ips))
if self.get_hpp_normalized(session):
self._really_update_sg_remote_groups(
context, port, removed_sgs, is_delete=True)
self._really_update_sg_remote_groups(
context, port, added_sgs, is_delete=False)
if removed_ips or added_ips:
self._really_update_sg_remote_groups(
context, orig, security_groups, is_delete=True)
self._really_update_sg_remote_groups(
context, port, security_groups, is_delete=False)
else:
self._really_update_sg_rule_with_remote_group_set(
context, port, removed_sgs, is_delete=True)
self._really_update_sg_rule_with_remote_group_set(
context, port, added_sgs, is_delete=False)
if removed_ips or added_ips:
self._really_update_sg_rule_with_remote_group_set(
context, orig, security_groups, is_delete=True)
self._really_update_sg_rule_with_remote_group_set(
context, port, security_groups, is_delete=False)
self._check_allowed_address_pairs(context, port)
self._insert_provisioning_block(context)
registry.notify(aim_cst.GBP_PORT, events.PRECOMMIT_UPDATE,
@ -3386,6 +3482,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
def delete_port_precommit(self, context):
port = context.current
session = context._plugin_context.session
if self._is_port_bound(port):
if self._use_static_path(context.bottom_bound_segment):
self._update_static_path(context, remove=True)
@ -3396,8 +3493,12 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
context.bottom_bound_segment[api.NETWORK_TYPE])):
self.disassociate_domain(context)
self._delete_erspan_aim_config(context, port)
self._really_update_sg_rule_with_remote_group_set(
context, port, port['security_groups'], is_delete=True)
if self.get_hpp_normalized(session):
self._really_update_sg_remote_groups(
context, port, port['security_groups'], is_delete=True)
else:
self._really_update_sg_rule_with_remote_group_set(
context, port, port['security_groups'], is_delete=True)
# Set status of floating ip DOWN.
self._update_floatingip_status(
@ -3508,6 +3609,14 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
security_group_name=sg['id'], name='default')
self.aim.create(aim_ctx, sg_subject)
if self.get_hpp_normalized(session):
# Create default remote group container
sg_remote_group = aim_resource.SecurityGroupRemoteIpContainer(
tenant_name=tenant_aname,
security_group_name=sg['id'],
remote_group_id=sg['id'])
self.aim.create(aim_ctx, sg_remote_group)
# Create those implicit rules
for sg_rule in sg.get('security_group_rules', []):
sg_rule_aim = aim_resource.SecurityGroupRule(
@ -3566,6 +3675,16 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
return tenant_id
def _get_sg_tenant_id(self, session, sg_id):
query = BAKERY(lambda s: s.query(
sg_models.SecurityGroup.tenant_id))
query += lambda q: q.filter(
sg_models.SecurityGroup.id == sa.bindparam('sg_id'))
tenant_id = query(session).params(
sg_id=sg_id).first()[0]
return tenant_id
def create_security_group_rule_precommit(self, context):
session = context._plugin_context.session
aim_ctx = aim_context.AimContext(session)
@ -3574,6 +3693,8 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
tenant_aname = self.name_mapper.project(session, tenant_id)
if sg_rule.get('remote_group_id'):
remote_ips = []
remote_group_id = sg_rule['remote_group_id']
dn = ''
query = BAKERY(lambda s: s.query(
models_v2.Port))
@ -3587,23 +3708,40 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
sg_ports = query(session).params(
sg_id=sg_rule['remote_group_id']).all()
ip_version = 0
if sg_rule['ethertype'] == 'IPv4':
ip_version = 4
elif sg_rule['ethertype'] == 'IPv6':
ip_version = 6
if self.get_hpp_normalized(session):
has_fixed_ips = False
for sg_port in sg_ports:
if sg_port['fixed_ips']:
has_fixed_ips = True
break
if has_fixed_ips:
# Get the remote group container's dn
rg_tenant_id = self._get_sg_tenant_id(session,
sg_rule['remote_group_id'])
rg_tenant_aname = self.name_mapper.project(session,
rg_tenant_id)
rg_cont = aim_resource.SecurityGroupRemoteIpContainer(
tenant_name=rg_tenant_aname,
security_group_name=sg_rule['remote_group_id'],
name=sg_rule['remote_group_id'])
dn = rg_cont.dn
else:
ip_version = 0
if sg_rule['ethertype'] == 'IPv4':
ip_version = 4
elif sg_rule['ethertype'] == 'IPv6':
ip_version = 6
for sg_port in sg_ports:
for fixed_ip in sg_port['fixed_ips']:
if ip_version == netaddr.IPAddress(
fixed_ip['ip_address']).version:
remote_ips.append(fixed_ip['ip_address'])
remote_group_id = sg_rule['remote_group_id']
for sg_port in sg_ports:
for fixed_ip in sg_port['fixed_ips']:
if ip_version == netaddr.IPAddress(
fixed_ip['ip_address']).version:
remote_ips.append(fixed_ip['ip_address'])
else:
remote_ips = ([sg_rule['remote_ip_prefix']]
if sg_rule['remote_ip_prefix'] else '')
remote_group_id = ''
dn = ''
sg_rule_aim = aim_resource.SecurityGroupRule(
tenant_name=tenant_aname,
@ -3628,6 +3766,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
if sg_rule['port_range_min'] else 'unspecified'),
to_port=(sg_rule['port_range_max']
if sg_rule['port_range_max'] else 'unspecified'),
tDn=dn,
remote_group_id=remote_group_id)
self.aim.create(aim_ctx, sg_rule_aim)
@ -6586,6 +6725,24 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
self, context=context,
network_id=mapping.network_id)
def normalize_hpp(self):
session = db_api.get_writer_session()
aim_ctx = aim_context.AimContext(db_session=session)
aim = aim_manager.AimManager()
remoteip_normalization = aim.get(aim_ctx,
aim_infra.ACISupportedMo(name="remoteipcont"))
if remoteip_normalization.supports:
if not self.get_hpp_normalized(session):
with session.begin(subtransactions=True):
aim_ctx = aim_context.AimContext(session)
data_migrations.normalize_hpp_ips(session)
data_migrations.normalize_hpps(session)
self.set_hpp_normalized(session, True)
return True
else:
return False
def validate_aim_mapping(self, mgr):
mgr.register_aim_resource_class(aim_infra.HostDomainMappingV2)
mgr.register_aim_resource_class(aim_resource.ApplicationProfile)
@ -6604,6 +6761,9 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
mgr.register_aim_resource_class(aim_resource.L3Outside)
mgr.register_aim_resource_class(aim_resource.PhysicalDomain)
mgr.register_aim_resource_class(aim_resource.SecurityGroup)
mgr.register_aim_resource_class(
aim_resource.SecurityGroupRemoteIpContainer)
mgr.register_aim_resource_class(aim_resource.SecurityGroupRemoteIp)
mgr.register_aim_resource_class(aim_resource.SecurityGroupRule)
mgr.register_aim_resource_class(aim_resource.SecurityGroupSubject)
mgr.register_aim_resource_class(aim_resource.Subnet)
@ -7362,6 +7522,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
def _validate_security_groups(self, mgr):
if not mgr._should_validate_neutron_resource("security_group"):
return
session = db_api.get_writer_session()
sg_ips = defaultdict(set)
query = BAKERY(lambda s: s.query(
@ -7403,17 +7564,45 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
tenant_name=tenant_name, security_group_name=sg_db.id,
name='default')
mgr.expect_aim_resource(sg_subject)
if self.get_hpp_normalized(mgr.actual_session):
sg_rg = aim_resource.SecurityGroupRemoteIpContainer(
tenant_name=tenant_name,
security_group_name=sg_db.id,
name=sg_db.id)
mgr.expect_aim_resource(sg_rg)
remote_ips = [
ip for ip in sg_ips[sg_db.id]]
for remote_ip in remote_ips:
sg_rg_ip = aim_resource.SecurityGroupRemoteIp(
tenant_name=tenant_name,
security_group_name=sg_db.id,
addr=remote_ip)
mgr.expect_aim_resource(sg_rg_ip)
for rule_db in sg_db.rules:
remote_ips = []
remote_group_id = ''
dn = ''
if rule_db.remote_group_id:
remote_group_id = rule_db.remote_group_id
ip_version = (4 if rule_db.ethertype == 'IPv4' else
6 if rule_db.ethertype == 'IPv6' else
0)
remote_ips = [
ip for ip in sg_ips[rule_db.remote_group_id]
if netaddr.IPAddress(ip).version == ip_version]
if self.get_hpp_normalized(mgr.actual_session):
rg_tenant_id = self._get_sg_tenant_id(
session, rule_db.remote_group_id)
rg_tenant_aname = self.name_mapper.project(
session, rg_tenant_id)
rg = aim_resource.SecurityGroupRemoteIpContainer(
tenant_name=rg_tenant_aname,
security_group_name=rule_db.remote_group_id,
name=rule_db.remote_group_id)
dn = rg.dn
else:
ip_version = (4 if rule_db.ethertype == 'IPv4' else
6 if rule_db.ethertype == 'IPv6' else
0)
remote_ips = [
ip for ip in sg_ips[rule_db.remote_group_id]
if netaddr.IPAddress(ip).version == ip_version]
elif rule_db.remote_ip_prefix:
remote_ips = [rule_db.remote_ip_prefix]
sg_rule = aim_resource.SecurityGroupRule(
@ -7431,6 +7620,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
to_port=(rule_db.port_range_max
if rule_db.port_range_max
else 'unspecified'),
tDn=dn,
remote_group_id=remote_group_id)
mgr.expect_aim_resource(sg_rule)

View File

@ -240,6 +240,7 @@ class ApicAimTestMixin(object):
self.aim_cfg_manager = aim_cfg.ConfigManager(
aim_context.AimContext(db_session=session), '')
self.aim_cfg_manager.replace_all(aim_cfg.CONF)
data_migrations.do_hpp_insertion(session)
def set_override(self, item, value, group=None, host=''):
# Override DB config as well
@ -528,6 +529,27 @@ class ApicAimTestCase(test_address_scope.AddressScopeTestCase,
self.assertIsNotNone(sg_rule)
return sg_rule
def _check_sg_remote_group_container(self, remote_group_name,
sg_name, tenant_name):
session = db_api.get_reader_session()
aim_ctx = aim_context.AimContext(session)
sg_remote_group = aim_resource.SecurityGroupRemoteIpContainer(
tenant_name=tenant_name, security_group_name=sg_name,
name=remote_group_name)
sg_remote_group = self.aim_mgr.get(aim_ctx, sg_remote_group)
self.assertIsNotNone(sg_remote_group)
return sg_remote_group
def _get_sg_remote_group_ip(self, remote_ip,
sg_name, tenant_name):
session = db_api.get_reader_session()
aim_ctx = aim_context.AimContext(session)
sg_remote_group_ip = aim_resource.SecurityGroupRemoteIp(
tenant_name=tenant_name, security_group_name=sg_name,
addr=remote_ip)
sg_remote_group_ip = self.aim_mgr.get(aim_ctx, sg_remote_group_ip)
return sg_remote_group_ip
def _get_contract(self, contract_name, tenant_name):
session = db_api.get_reader_session()
aim_ctx = aim_context.AimContext(session)
@ -11688,7 +11710,253 @@ class TestPortOnPhysicalNode(TestPortVlanNetwork):
set(self._doms(epg1.physical_domains,
with_type=False)))
def test_update_sg_rule_with_remote_group_set(self):
def _test_sg_update_remote_groups(self):
session = db_api.get_reader_session()
extn = extn_db.ExtensionDbMixin()
# Create network.
net_resp = self._make_network(self.fmt, 'net1', True)
net = net_resp['network']
# Create subnet
subnet = self._make_subnet(self.fmt, net_resp, '10.0.1.1',
'10.0.1.0/24')['subnet']
subnet_id = subnet['id']
# Create port on subnet
fixed_ips = [{'subnet_id': subnet_id, 'ip_address': '10.0.1.100'}]
port = self._make_port(self.fmt, net['id'],
fixed_ips=fixed_ips)['port']
default_sg_id = port['security_groups'][0]
default_sg = self._show('security-groups',
default_sg_id)['security_group']
tenant_aname = self.name_mapper.project(None, default_sg['tenant_id'])
for sg_rule in default_sg['security_group_rules']:
if sg_rule['remote_group_id'] and sg_rule['ethertype'] == 'IPv4':
break
aim_sg_rule = self._get_sg_rule(
sg_rule['id'], 'default', default_sg_id, tenant_aname)
self.assertEqual(
aim_sg_rule.remote_group_id, sg_rule['remote_group_id'])
if extn.get_hpp_normalized(session):
rg_cont = self._check_sg_remote_group_container(default_sg_id,
default_sg_id, tenant_aname)
remote_ips = ['10.0.1.100']
for remote_ip in remote_ips:
aim_sg_remote_group_ip = self._get_sg_remote_group_ip(
remote_ip, default_sg_id, tenant_aname)
self.assertEqual(aim_sg_remote_group_ip.addr, remote_ip)
self.assertEqual(aim_sg_rule.tDn, rg_cont.dn)
self.assertEqual(aim_sg_rule.remote_ips, [])
else:
self.assertEqual(aim_sg_rule.remote_ips, ['10.0.1.100'])
# add another rule with remote_group_id set
rule1 = self._build_security_group_rule(
default_sg_id, 'ingress', n_constants.PROTO_NAME_TCP, '22', '23',
remote_group_id=default_sg_id, ethertype=n_constants.IPv4)
rules = {'security_group_rules': [rule1['security_group_rule']]}
sg_rule1 = self._make_security_group_rule(
self.fmt, rules)['security_group_rules'][0]
aim_sg_rule = self._get_sg_rule(
sg_rule1['id'], 'default', default_sg_id, tenant_aname)
self.assertEqual(
aim_sg_rule.remote_group_id, sg_rule1['remote_group_id'])
if extn.get_hpp_normalized(session):
dn = 'uni/tn-' + tenant_aname + '/pol-' + sg_rule1[
'remote_group_id'] + '/remoteipcont'
self.assertEqual(aim_sg_rule.tDn, dn)
self.assertEqual(aim_sg_rule.remote_ips, [])
else:
self.assertEqual(aim_sg_rule.remote_ips, ['10.0.1.100'])
rule2 = self._build_security_group_rule(
default_sg_id, 'ingress', n_constants.PROTO_NAME_ICMP, '33', '2',
remote_group_id=default_sg_id, ethertype=n_constants.IPv4)
rules = {'security_group_rules': [rule2['security_group_rule']]}
sg_rule2 = self._make_security_group_rule(
self.fmt, rules)['security_group_rules'][0]
aim_sg_rule = self._get_sg_rule(
sg_rule2['id'], 'default', default_sg_id, tenant_aname)
self.assertEqual(
aim_sg_rule.remote_group_id, sg_rule2['remote_group_id'])
self.assertEqual(aim_sg_rule.icmp_code, '2')
self.assertEqual(aim_sg_rule.icmp_type, '33')
if extn.get_hpp_normalized(session):
dn = 'uni/tn-' + tenant_aname + '/pol-' + sg_rule2[
'remote_group_id'] + '/remoteipcont'
self.assertEqual(aim_sg_rule.tDn, dn)
self.assertEqual(aim_sg_rule.remote_ips, [])
else:
self.assertEqual(aim_sg_rule.remote_ips, ['10.0.1.100'])
rule3 = self._build_security_group_rule(
default_sg_id, 'ingress', n_constants.PROTO_NAME_ICMP, None, None,
remote_group_id=default_sg_id, ethertype=n_constants.IPv4)
rules = {'security_group_rules': [rule3['security_group_rule']]}
sg_rule3 = self._make_security_group_rule(
self.fmt, rules)['security_group_rules'][0]
aim_sg_rule = self._get_sg_rule(
sg_rule3['id'], 'default', default_sg_id, tenant_aname)
self.assertEqual(
aim_sg_rule.remote_group_id, sg_rule3['remote_group_id'])
self.assertEqual(aim_sg_rule.icmp_code, 'unspecified')
self.assertEqual(aim_sg_rule.icmp_type, 'unspecified')
if extn.get_hpp_normalized(session):
dn = 'uni/tn-' + tenant_aname + '/pol-' + sg_rule3[
'remote_group_id'] + '/remoteipcont'
self.assertEqual(aim_sg_rule.tDn, dn)
self.assertEqual(aim_sg_rule.remote_ips, [])
else:
self.assertEqual(aim_sg_rule.remote_ips, ['10.0.1.100'])
# delete SG from port
data = {'port': {'security_groups': []}}
port = self._update('ports', port['id'], data)['port']
aim_sg_rule = self._get_sg_rule(
sg_rule['id'], 'default', default_sg_id, tenant_aname)
aim_sg_rule1 = self._get_sg_rule(
sg_rule1['id'], 'default', default_sg_id, tenant_aname)
if extn.get_hpp_normalized(session):
self._check_sg_remote_group_container(
default_sg_id, default_sg_id, tenant_aname)
remote_ip = ''
aim_sg_remote_group_ip = self._get_sg_remote_group_ip(
sg_rule['id'], default_sg_id, tenant_aname)
self.assertIsNone(aim_sg_remote_group_ip)
self.assertEqual(aim_sg_rule.tDn, '')
self.assertEqual(aim_sg_rule1.tDn, '')
self.assertEqual(aim_sg_rule.remote_ips, [])
self.assertEqual(aim_sg_rule1.remote_ips, [])
# add SG to port
data = {'port': {'security_groups': [default_sg_id]}}
port = self._update('ports', port['id'], data)['port']
aim_sg_rule = self._get_sg_rule(
sg_rule['id'], 'default', default_sg_id, tenant_aname)
aim_sg_rule1 = self._get_sg_rule(
sg_rule1['id'], 'default', default_sg_id, tenant_aname)
if extn.get_hpp_normalized(session):
rg_cont = self._check_sg_remote_group_container(
default_sg_id, default_sg_id, tenant_aname)
remote_ips = ['10.0.1.100']
for remote_ip in remote_ips:
aim_sg_remote_group_ip = self._get_sg_remote_group_ip(
remote_ip, default_sg_id, tenant_aname)
self.assertEqual(aim_sg_remote_group_ip.addr, remote_ip)
self.assertEqual(aim_sg_rule.tDn, rg_cont.dn)
self.assertEqual(aim_sg_rule1.tDn, rg_cont.dn)
self.assertEqual(aim_sg_rule1.remote_ips, [])
else:
self.assertEqual(aim_sg_rule.remote_ips, ['10.0.1.100'])
self.assertEqual(aim_sg_rule1.remote_ips, ['10.0.1.100'])
def _test_create_sg_rule_with_remote_group_set_different_tenant(self):
session = db_api.get_reader_session()
extn = extn_db.ExtensionDbMixin()
# Create network.
net_resp = self._make_network(
self.fmt, 'net1', True, tenant_id='tenant_1')
net = net_resp['network']
# Create subnet
subnet = self._make_subnet(self.fmt, net_resp, '10.0.1.1',
'10.0.1.0/24', tenant_id='tenant_1')['subnet']
subnet_id = subnet['id']
# Create port on subnet
fixed_ips = [{'subnet_id': subnet_id, 'ip_address': '10.0.1.100'}]
port = self._make_port(self.fmt, net['id'], fixed_ips=fixed_ips,
tenant_id='tenant_1')['port']
default_sg_id = port['security_groups'][0]
default_sg = self._show('security-groups',
default_sg_id)['security_group']
for sg_rule in default_sg['security_group_rules']:
if sg_rule['remote_group_id'] and sg_rule['ethertype'] == 'IPv4':
break
tenant_aname = self.name_mapper.project(None, default_sg['tenant_id'])
aim_sg_rule = self._get_sg_rule(
sg_rule['id'], 'default', default_sg_id, tenant_aname)
if extn.get_hpp_normalized(session):
rg_cont = self._check_sg_remote_group_container(
sg_rule['remote_group_id'],
sg_rule['remote_group_id'], tenant_aname)
remote_ips = ['10.0.1.100']
for remote_ip in remote_ips:
aim_sg_remote_group_ip = self._get_sg_remote_group_ip(
remote_ip, sg_rule['remote_group_id'], tenant_aname)
self.assertEqual(aim_sg_remote_group_ip.addr, remote_ip)
self.assertEqual(aim_sg_rule.tDn, rg_cont.dn)
self.assertEqual(aim_sg_rule.remote_ips, [])
else:
self.assertEqual(aim_sg_rule.remote_ips, ['10.0.1.100'])
self.assertEqual(
aim_sg_rule.remote_group_id, sg_rule['remote_group_id'])
# add another rule with remote_group_id set
rule1 = self._build_security_group_rule(
default_sg_id, 'ingress', n_constants.PROTO_NAME_TCP, '22', '23',
remote_group_id=default_sg_id, ethertype=n_constants.IPv4)
rules = {'security_group_rules': [rule1['security_group_rule']]}
sg_rule1 = self._make_security_group_rule(
self.fmt, rules, tenant_id='tenant_2')['security_group_rules'][0]
aim_sg_rule1 = self._get_sg_rule(
sg_rule1['id'], 'default', default_sg_id, tenant_aname)
if extn.get_hpp_normalized(session):
rg_cont = self._check_sg_remote_group_container(
sg_rule1['remote_group_id'],
sg_rule1['remote_group_id'], tenant_aname)
remote_ips = ['10.0.1.100']
for remote_ip in remote_ips:
aim_sg_remote_group_ip = self._get_sg_remote_group_ip(
remote_ip, sg_rule1['remote_group_id'], tenant_aname)
self.assertEqual(aim_sg_remote_group_ip.addr, remote_ip)
self.assertEqual(aim_sg_rule1.tDn, rg_cont.dn)
self.assertEqual(aim_sg_rule1.remote_ips, [])
else:
self.assertEqual(aim_sg_rule1.remote_ips, ['10.0.1.100'])
self.assertEqual(
aim_sg_rule1.remote_group_id, sg_rule1['remote_group_id'])
# Add another port on subnet
fixed_ips = [{'subnet_id': subnet_id, 'ip_address': '10.0.1.200'}]
port = self._make_port(self.fmt, net['id'], fixed_ips=fixed_ips,
tenant_id='tenant_1')['port']
aim_sg_rule1 = self._get_sg_rule(
sg_rule1['id'], 'default', default_sg_id, tenant_aname)
if extn.get_hpp_normalized(session):
rg_cont = self._check_sg_remote_group_container(
sg_rule['remote_group_id'],
sg_rule['remote_group_id'], tenant_aname)
remote_ips = ['10.0.1.100', '10.0.1.200']
for remote_ip in remote_ips:
aim_sg_remote_group_ip = self._get_sg_remote_group_ip(
remote_ip, sg_rule['remote_group_id'], tenant_aname)
self.assertEqual(aim_sg_remote_group_ip.addr, remote_ip)
self.assertEqual(aim_sg_rule1.tDn, rg_cont.dn)
self.assertEqual(aim_sg_rule1.remote_ips, [])
else:
self.assertEqual(aim_sg_rule1.remote_ips,
['10.0.1.100', '10.0.1.200'])
self.assertEqual(
aim_sg_rule1.remote_group_id, sg_rule1['remote_group_id'])
def test_sg_update_remote_groups_normalized(self):
session = db_api.get_reader_session()
extn = extn_db.ExtensionDbMixin()
extn.set_hpp_normalized(session, True)
self._test_sg_update_remote_groups()
self._test_create_sg_rule_with_remote_group_set_different_tenant()
def test_sg_update_remote_groups_not_normalized(self):
self._test_sg_update_remote_groups()
self._test_create_sg_rule_with_remote_group_set_different_tenant()
def test_normalize_hpp(self):
session = db_api.get_reader_session()
extn = extn_db.ExtensionDbMixin()
aim_ctx = aim_context.AimContext(session)
# Create network.
net_resp = self._make_network(self.fmt, 'net1', True)
net = net_resp['network']
@ -11715,7 +11983,8 @@ class TestPortOnPhysicalNode(TestPortVlanNetwork):
self.assertEqual(
aim_sg_rule.remote_group_id, sg_rule['remote_group_id'])
# add another rule with remote_group_id set
# add rule with remote_group_id set
self.assertFalse(extn.get_hpp_normalized(session))
rule1 = self._build_security_group_rule(
default_sg_id, 'ingress', n_constants.PROTO_NAME_TCP, '22', '23',
remote_group_id=default_sg_id, ethertype=n_constants.IPv4)
@ -11728,108 +11997,30 @@ class TestPortOnPhysicalNode(TestPortVlanNetwork):
self.assertEqual(
aim_sg_rule.remote_group_id, sg_rule1['remote_group_id'])
rule2 = self._build_security_group_rule(
default_sg_id, 'ingress', n_constants.PROTO_NAME_ICMP, '33', '2',
remote_group_id=default_sg_id, ethertype=n_constants.IPv4)
rules = {'security_group_rules': [rule2['security_group_rule']]}
sg_rule2 = self._make_security_group_rule(
self.fmt, rules)['security_group_rules'][0]
aim_sg_rule = self._get_sg_rule(
sg_rule2['id'], 'default', default_sg_id, tenant_aname)
self.assertEqual(aim_sg_rule.remote_ips, ['10.0.1.100'])
self.assertEqual(aim_sg_rule.icmp_code, '2')
self.assertEqual(aim_sg_rule.icmp_type, '33')
# normalize the remote groups
self.remoteip_normalization = aim_infra.ACISupportedMo(
name="remoteipcont", supports=False)
self.aim_mgr.create(aim_ctx, self.remoteip_normalization)
self.mech = md.ApicMechanismDriver()
self.result = self.mech.normalize_hpp()
self.assertFalse(self.result)
rule3 = self._build_security_group_rule(
default_sg_id, 'ingress', n_constants.PROTO_NAME_ICMP, None, None,
remote_group_id=default_sg_id, ethertype=n_constants.IPv4)
rules = {'security_group_rules': [rule3['security_group_rule']]}
sg_rule3 = self._make_security_group_rule(
self.fmt, rules)['security_group_rules'][0]
aim_sg_rule = self._get_sg_rule(
sg_rule3['id'], 'default', default_sg_id, tenant_aname)
self.assertEqual(aim_sg_rule.remote_ips, ['10.0.1.100'])
self.assertEqual(aim_sg_rule.icmp_code, 'unspecified')
self.assertEqual(aim_sg_rule.icmp_type, 'unspecified')
# delete SG from port
data = {'port': {'security_groups': []}}
port = self._update('ports', port['id'], data)['port']
aim_sg_rule = self._get_sg_rule(
sg_rule['id'], 'default', default_sg_id, tenant_aname)
self.assertEqual(aim_sg_rule.remote_ips, [])
self.aim_mgr.update(aim_ctx, self.remoteip_normalization,
supports=True)
self.result = self.mech.normalize_hpp()
self.assertTrue(self.result)
self.assertTrue(extn.get_hpp_normalized(session))
rg_cont = self._check_sg_remote_group_container(
default_sg_id, default_sg_id, tenant_aname)
remote_ips = ['10.0.1.100']
for remote_ip in remote_ips:
aim_sg_remote_ip = self._get_sg_remote_group_ip(
remote_ip, default_sg_id, tenant_aname)
self.assertEqual(aim_sg_remote_ip.addr, remote_ip)
aim_sg_rule = self._get_sg_rule(
sg_rule1['id'], 'default', default_sg_id, tenant_aname)
self.assertEqual(aim_sg_rule.remote_ips, [])
# add SG to port
data = {'port': {'security_groups': [default_sg_id]}}
port = self._update('ports', port['id'], data)['port']
aim_sg_rule = self._get_sg_rule(
sg_rule['id'], 'default', default_sg_id, tenant_aname)
self.assertEqual(aim_sg_rule.remote_ips, ['10.0.1.100'])
aim_sg_rule = self._get_sg_rule(
sg_rule1['id'], 'default', default_sg_id, tenant_aname)
self.assertEqual(aim_sg_rule.remote_ips, ['10.0.1.100'])
self._delete('ports', port['id'])
aim_sg_rule = self._get_sg_rule(
sg_rule['id'], 'default', default_sg_id, tenant_aname)
self.assertEqual(aim_sg_rule.remote_ips, [])
aim_sg_rule = self._get_sg_rule(
sg_rule1['id'], 'default', default_sg_id, tenant_aname)
self.assertEqual(aim_sg_rule.remote_ips, [])
def test_create_sg_rule_with_remote_group_set_different_tenant(self):
# Create network.
net_resp = self._make_network(
self.fmt, 'net1', True, tenant_id='tenant_1')
net = net_resp['network']
# Create subnet
subnet = self._make_subnet(self.fmt, net_resp, '10.0.1.1',
'10.0.1.0/24', tenant_id='tenant_1')['subnet']
subnet_id = subnet['id']
# Create port on subnet
fixed_ips = [{'subnet_id': subnet_id, 'ip_address': '10.0.1.100'}]
port = self._make_port(self.fmt, net['id'], fixed_ips=fixed_ips,
tenant_id='tenant_1')['port']
default_sg_id = port['security_groups'][0]
default_sg = self._show('security-groups',
default_sg_id)['security_group']
for sg_rule in default_sg['security_group_rules']:
if sg_rule['remote_group_id'] and sg_rule['ethertype'] == 'IPv4':
break
tenant_aname = self.name_mapper.project(None, default_sg['tenant_id'])
aim_sg_rule = self._get_sg_rule(
sg_rule['id'], 'default', default_sg_id, tenant_aname)
self.assertEqual(aim_sg_rule.remote_ips, ['10.0.1.100'])
self.assertEqual(
aim_sg_rule.remote_group_id, sg_rule['remote_group_id'])
# add another rule with remote_group_id set
rule1 = self._build_security_group_rule(
default_sg_id, 'ingress', n_constants.PROTO_NAME_TCP, '22', '23',
remote_group_id=default_sg_id, ethertype=n_constants.IPv4)
rules = {'security_group_rules': [rule1['security_group_rule']]}
sg_rule1 = self._make_security_group_rule(
self.fmt, rules, tenant_id='tenant_2')['security_group_rules'][0]
aim_sg_rule1 = self._get_sg_rule(
sg_rule1['id'], 'default', default_sg_id, tenant_aname)
self.assertEqual(aim_sg_rule1.remote_ips, ['10.0.1.100'])
self.assertEqual(
aim_sg_rule1.remote_group_id, sg_rule1['remote_group_id'])
# Add another port on subnet
fixed_ips = [{'subnet_id': subnet_id, 'ip_address': '10.0.1.200'}]
port = self._make_port(self.fmt, net['id'], fixed_ips=fixed_ips,
tenant_id='tenant_1')['port']
aim_sg_rule1 = self._get_sg_rule(
sg_rule1['id'], 'default', default_sg_id, tenant_aname)
self.assertEqual(aim_sg_rule1.remote_ips, ['10.0.1.100', '10.0.1.200'])
self.assertEqual(
aim_sg_rule1.remote_group_id, sg_rule['remote_group_id'])
self.assertEqual(aim_sg_rule.tDn, rg_cont.dn)
def test_mixed_ports_on_network_with_specific_domains(self):
aim_ctx = aim_context.AimContext(self.db_session)

View File

@ -0,0 +1,45 @@
# Copyright (c) 2018 Cisco Systems Inc.
# All Rights Reserved.
#
# 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.
import sys
from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import (
mechanism_driver as md)
from oslo_config import cfg
from neutron.common import config
from neutron import manager
def main():
config.init(sys.argv[1:])
# Enable logging but prevent output to stderr.
cfg.CONF.use_stderr = False
config.setup_logging()
if not cfg.CONF.config_file:
sys.exit(_("ERROR: Unable to find configuration file via the default"
" search paths (~/.neutron/, ~/, /etc/neutron/, /etc/) and"
" the '--config-file' option!"))
manager.init()
mech = md.ApicMechanismDriver()
result = mech.normalize_hpp()
if not result:
sys.exit(_("ERROR: APIC version doesn't support"
" normalization of remote ips"))
return 0

View File

@ -41,6 +41,7 @@ scripts =
console_scripts=
gbp-db-manage = gbpservice.neutron.db.migration.cli:main
gbp-validate = gbpservice.tools.validate.cli:main
hpp-normalize = gbpservice.tools.hpp_normalize.cli:main
neutron.core_plugins =
ml2plus = gbpservice.neutron.plugins.ml2plus.plugin:Ml2PlusPlugin
neutron.service_plugins =