[aim-mapping] intra-ptg-allow ext attr for PTG

This attribute maps to the policy_enforcement_pref attribute
of the AIM EPG, and is used to turn ON or OFF the intra-PTG
traffic. It's True by default, implying all PTs in a PTG are
allowed to communicate with each other. When set to False,
there is no direct connectivity between the PTs of that PTG.

Change-Id: I82094cbc1faaed879bfb75518df0f558f0bdad1c
Closes-bug: #1648019
This commit is contained in:
Sumit Naiksatam 2016-12-07 01:52:46 -08:00
parent 259053e740
commit 1f17e4f65a
7 changed files with 186 additions and 5 deletions

View File

@ -0,0 +1,43 @@
# 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.
from neutron.db import model_base
import sqlalchemy as sa
class ApicIntraPtgDB(model_base.BASEV2):
__tablename__ = 'gp_apic_intra_ptg'
policy_target_group_id = sa.Column(
sa.String(36), sa.ForeignKey('gp_policy_target_groups.id',
ondelete='CASCADE'), primary_key=True)
intra_ptg_allow = sa.Column(sa.Boolean, default=True, nullable=False)
class ApicIntraPtgDBMixin(object):
def get_intra_ptg_allow(self, session, policy_target_group_id):
row = (session.query(ApicIntraPtgDB).filter_by(
policy_target_group_id=policy_target_group_id).one())
return row['intra_ptg_allow']
def set_intra_ptg_allow(self, session, policy_target_group_id,
intra_ptg_allow=True):
with session.begin(subtransactions=True):
row = (session.query(ApicIntraPtgDB).filter_by(
policy_target_group_id=policy_target_group_id).first())
if not row:
row = ApicIntraPtgDB(
policy_target_group_id=policy_target_group_id,
intra_ptg_allow=intra_ptg_allow)
session.add(row)
else:
row.update({'intra_ptg_allow': intra_ptg_allow})

View File

@ -1 +1 @@
4af01d620224
fce38a8588a2

View File

@ -0,0 +1,45 @@
# 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.
"""intra_ptg_allow
Revision ID: fce38a8588a2
Revises: 4af01d620224
Create Date: 2016-12-06 17:01:30.735865
"""
# revision identifiers, used by Alembic.
revision = 'fce38a8588a2'
down_revision = '4af01d620224'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.create_table(
'gp_apic_intra_ptg',
sa.Column('policy_target_group_id', sa.String(length=36),
nullable=False),
sa.Column('intra_ptg_allow', sa.Boolean,
server_default=sa.sql.true(), nullable=False),
sa.ForeignKeyConstraint(
['policy_target_group_id'], ['gp_policy_target_groups.id'],
name='gp_apic_intra_ptg_fk_ptgid', ondelete='CASCADE'),
sa.PrimaryKeyConstraint('policy_target_group_id')
)
def downgrade():
pass

View File

@ -11,6 +11,7 @@
# under the License.
from neutron.api import extensions
from neutron.api.v2 import attributes as attr
from gbpservice.neutron.extensions import cisco_apic
from gbpservice.neutron.extensions import group_policy as gp
@ -26,6 +27,9 @@ EXTENDED_ATTRIBUTES_2_0 = {
gp.POLICY_TARGET_GROUPS: {
cisco_apic.DIST_NAMES: {
'allow_post': False, 'allow_put': False, 'is_visible': True},
'intra_ptg_allow': {
'allow_post': True, 'allow_put': True, 'default': True,
'convert_to': attr.convert_to_boolean, 'is_visible': True},
},
gp.POLICY_RULES: {
cisco_apic.DIST_NAMES: {

View File

@ -72,6 +72,8 @@ CONTRACTS = 'contracts'
CONTRACT_SUBJECTS = 'contract_subjects'
FILTERS = 'filters'
FILTER_ENTRIES = 'filter_entries'
ENFORCED = aim_resource.EndpointGroup.POLICY_ENFORCED
UNENFORCED = aim_resource.EndpointGroup.POLICY_UNENFORCED
# REVISIT: Auto-PTG is currently config driven to align with the
# config driven behavior of the older driver but is slated for
@ -405,6 +407,7 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
self._configure_contracts_for_default_epg(
context, l2p, default_epg_dn)
if self.create_auto_ptg:
default_epg = self._get_epg_by_dn(context, default_epg_dn)
desc = "System created auto PTG for L2P: %s" % l2p['id']
data = {
"id": self._get_auto_ptg_id(l2p['id']),
@ -417,6 +420,8 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
"network_service_policy_id": None,
"service_management": False,
"shared": l2p['shared'],
"intra_ptg_allow":
self._map_policy_enforcement_pref(default_epg),
}
self._create_policy_target_group(
context._plugin_context, data, clean_session=False)
@ -523,10 +528,14 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
session, context.current['provided_policy_rule_sets'])
consumed_contracts = self._get_aim_contract_names(
session, context.current['consumed_policy_rule_sets'])
aim_epg = self._aim_endpoint_group(
session, context.current, bd_name, bd_tenant_name,
provided_contracts=provided_contracts,
consumed_contracts=consumed_contracts)
consumed_contracts=consumed_contracts,
policy_enforcement_pref=
self._get_policy_enforcement_pref(context.current))
session = context._plugin_context.session
aim_ctx = aim_context.AimContext(session)
vmms, phys = self.aim_mech_driver.get_aim_domains(aim_ctx)
@ -553,6 +562,8 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
if not self._is_auto_ptg(context.current):
aim_epg.display_name = (
self.aim_display_name(context.current['name']))
aim_epg.policy_enforcement_pref = (
self._get_policy_enforcement_pref(context.current))
aim_epg.provided_contract_names = (
list((set(aim_epg.provided_contract_names) -
set(old_provided_contracts)) |
@ -861,7 +872,8 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
def _aim_endpoint_group(self, session, ptg, bd_name=None,
bd_tenant_name=None,
provided_contracts=None,
consumed_contracts=None):
consumed_contracts=None,
policy_enforcement_pref=UNENFORCED):
# This returns a new AIM EPG resource
# TODO(Sumit): Use _aim_resource_by_name
tenant_id = ptg['tenant_id']
@ -876,7 +888,8 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
kwargs = {'tenant_name': str(tenant_name),
'name': str(epg_name),
'display_name': display_name,
'app_profile_name': self.aim_mech_driver.ap_name}
'app_profile_name': self.aim_mech_driver.ap_name,
'policy_enforcement_pref': policy_enforcement_pref}
if bd_name:
kwargs['bd_name'] = bd_name
if bd_tenant_name:
@ -1922,6 +1935,25 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
def _is_auto_ptg(self, ptg):
return ptg['id'].startswith(AUTO_PTG_PREFIX)
def _get_policy_enforcement_pref(self, ptg):
if ptg.get('intra_ptg_allow'):
policy_enforcement_pref = UNENFORCED
else:
policy_enforcement_pref = ENFORCED
return policy_enforcement_pref
def _map_policy_enforcement_pref(self, epg):
if epg.policy_enforcement_pref == UNENFORCED:
return True
else:
return False
def _get_epg_by_dn(self, context, epg_dn):
aim_context = self._get_aim_context(context)
epg = self.aim.get(
aim_context, aim_resource.EndpointGroup.from_dn(epg_dn))
return epg
def _get_epg_name_from_dn(self, context, epg_dn):
aim_context = self._get_aim_context(context)
default_epg_name = self.aim.get(

View File

@ -14,14 +14,19 @@ from neutron._i18n import _LI
from neutron import manager as n_manager
from oslo_log import log as logging
from gbpservice.neutron.db.grouppolicy.extensions import (
apic_intra_ptg_db as db)
from gbpservice.neutron.db.grouppolicy import group_policy_db as gp_db
from gbpservice.neutron.extensions import cisco_apic_gbp
from gbpservice.neutron.extensions import group_policy as gpolicy
from gbpservice.neutron.services.grouppolicy import (
group_policy_driver_api as api)
LOG = logging.getLogger(__name__)
class AIMExtensionDriver(api.ExtensionDriver):
class AIMExtensionDriver(api.ExtensionDriver,
db.ApicIntraPtgDBMixin):
_supported_extension_alias = cisco_apic_gbp.ALIAS
_extension_dict = cisco_apic_gbp.EXTENDED_ATTRIBUTES_2_0
@ -45,7 +50,25 @@ class AIMExtensionDriver(api.ExtensionDriver):
def extension_alias(self):
return self._supported_extension_alias
def process_create_policy_target_group(self, session, data, result):
ptg = data['policy_target_group']
if 'intra_ptg_allow' in ptg:
ptg_db = (session.query(gp_db.PolicyTargetGroup)
.filter_by(id=result['id']).one())
if not ptg_db:
raise gpolicy.PolicyTargetGroupNotFound(
policy_target_group_id=result['id'])
self.set_intra_ptg_allow(
session, policy_target_group_id=result['id'],
intra_ptg_allow=ptg['intra_ptg_allow'])
result['intra_ptg_allow'] = ptg['intra_ptg_allow']
def process_update_policy_target_group(self, session, data, result):
self.process_create_policy_target_group(session, data, result)
def extend_policy_target_group_dict(self, session, result):
result['intra_ptg_allow'] = self.get_intra_ptg_allow(
session, policy_target_group_id=result['id'])
self._pd.extend_policy_target_group_dict(session, result)
def extend_policy_rule_dict(self, session, result):

View File

@ -1220,6 +1220,21 @@ class TestL2PolicyWithAutoPTG(TestL2PolicyBase):
self.assertEqual(l3p['subnetpools_v4'][0],
subnet['subnetpool_id'])
auto_ptg_id = self.driver._get_auto_ptg_id(ptg['l2_policy_id'])
aim_epg_name = self.driver.apic_epg_name_for_policy_target_group(
self._neutron_context.session, auto_ptg_id)
aim_epg = self.aim_mgr.find(
self._aim_context, aim_resource.EndpointGroup,
name=aim_epg_name)[0]
auto_ptg = self.show_policy_target_group(
auto_ptg_id, expected_res_status=200)['policy_target_group']
if aim_epg.policy_enforcement_pref == (
aim_resource.EndpointGroup.POLICY_UNENFORCED):
self.assertTrue(auto_ptg['intra_ptg_allow'])
elif aim_epg.policy_enforcement_pref == (
aim_resource.EndpointGroup.POLICY_ENFORCED):
self.assertFalse(ptg['intra_ptg_allow'])
self.delete_policy_target_group(ptg_id, expected_res_status=204)
self.show_policy_target_group(ptg_id, expected_res_status=404)
self.show_l2_policy(ptg['l2_policy_id'], expected_res_status=404)
@ -1559,6 +1574,25 @@ class TestPolicyTargetGroup(AIMBaseTestCase):
self.assertIn(subnet_id, info['subnet_ids'])
self.delete_policy_target_group(ptg_id, expected_res_status=204)
def test_policy_target_group_intra_ptg_allow(self):
ptg = self.create_policy_target_group(
intra_ptg_allow=False)['policy_target_group']
self.assertFalse(ptg['intra_ptg_allow'])
aim_epg_name = self.driver.apic_epg_name_for_policy_target_group(
self._neutron_context.session, ptg['id'])
aim_epgs = self.aim_mgr.find(
self._aim_context, aim_resource.EndpointGroup, name=aim_epg_name)
self.assertEqual(1, len(aim_epgs))
self.assertEqual(aim_resource.EndpointGroup.POLICY_ENFORCED,
aim_epgs[0].policy_enforcement_pref)
ptg = self.update_policy_target_group(
ptg['id'], intra_ptg_allow=True)['policy_target_group']
self.assertTrue(ptg['intra_ptg_allow'])
aim_epgs = self.aim_mgr.find(
self._aim_context, aim_resource.EndpointGroup, name=aim_epg_name)
self.assertEqual(aim_resource.EndpointGroup.POLICY_UNENFORCED,
aim_epgs[0].policy_enforcement_pref)
# TODO(Sumit): Add tests here which tests different scenarios for subnet
# allocation for PTGs