Merge "[apic-mapping] Segmentation Label extension for PT"

This commit is contained in:
Jenkins 2016-09-24 01:40:09 +00:00 committed by Gerrit Code Review
commit 7cde0d37ea
10 changed files with 343 additions and 3 deletions

View File

@ -0,0 +1,49 @@
# 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 ApicSegmentationLabelDB(model_base.BASEV2):
__tablename__ = 'gp_apic_mapping_segmentation_lablels'
policy_target_id = sa.Column(
sa.String(36), sa.ForeignKey('gp_policy_targets.id',
ondelete="CASCADE"), primary_key=True)
segmentation_label = sa.Column(sa.String(255), primary_key=True)
class ApicSegmentationLabelDBMixin(object):
def get_policy_target_segmentation_labels(self, session, policy_target_id):
rows = (session.query(ApicSegmentationLabelDB).filter_by(
policy_target_id=policy_target_id).all())
return rows
def get_policy_target_segmentation_label(self, session, policy_target_id,
segmentation_label):
row = (session.query(ApicSegmentationLabelDB).filter_by(
policy_target_id=policy_target_id,
segmentation_label=segmentation_label).one())
return row
def add_policy_target_segmentation_label(self, session, policy_target_id,
segmentation_label):
row = ApicSegmentationLabelDB(policy_target_id=policy_target_id,
segmentation_label=segmentation_label)
session.add(row)
def delete_policy_target_segmentation_label(
self, session, policy_target_id, segmentation_label):
row = self.get_policy_target_segmentation_label(
session, policy_target_id, segmentation_label)
session.delete(row)

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.
"""segmentation labels for PT (apic)
Revision ID: 092e4b1aeb0a
Revises: d4bb487a81b8
Create Date: 2016-09-18 18:58:26.810742
"""
# revision identifiers, used by Alembic.
revision = '092e4b1aeb0a'
down_revision = 'd4bb487a81b8'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.create_table(
'gp_apic_mapping_segmentation_labels',
sa.Column('policy_target_id', sa.String(length=36), nullable=False),
sa.Column('segmentation_label', sa.String(length=255),
nullable=False),
sa.ForeignKeyConstraint(
['policy_target_id'], ['gp_policy_targets.id'],
name='gp_apic_mapping_segmentation_lablel_fk_ptid',
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('policy_target_id', 'segmentation_label')
)
def downgrade():
pass

View File

@ -1 +1 @@
d4bb487a81b8
092e4b1aeb0a

View File

@ -0,0 +1,55 @@
# 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.api import extensions
from neutron.api.v2 import attributes as attr
from gbpservice.neutron.extensions import group_policy as gp
CISCO_APIC_GBP_SEGMENTATION_LABEL_EXT = 'cisco_apic_gbp_label_segmentation'
EXTENDED_ATTRIBUTES_2_0 = {
gp.POLICY_TARGETS: {
'segmentation_labels': {
'allow_post': True, 'allow_put': True, 'default': None,
'validate': {'type:list_of_unique_strings': None},
'convert_to': attr.convert_none_to_empty_list,
'is_visible': True},
},
}
class Apic_segmentation_label(extensions.ExtensionDescriptor):
@classmethod
def get_name(cls):
return "APIC GBP Segmentation Extension"
@classmethod
def get_alias(cls):
return CISCO_APIC_GBP_SEGMENTATION_LABEL_EXT
@classmethod
def get_description(cls):
return _("This extension supports a list of (micro)segmentation "
"labels that can be applied to the Policy Target resource.")
@classmethod
def get_updated(cls):
return "2016-08-03T10:00:00-00:00"
def get_extended_resources(self, version):
if version == "2.0":
return EXTENDED_ATTRIBUTES_2_0
else:
return {}

View File

@ -303,6 +303,7 @@ class ApicMappingDriver(api.ResourceMappingDriver,
self.nat_enabled = self.apic_manager.use_vmm
self.per_tenant_nat_epg = self.apic_manager.per_tenant_nat_epg
self._gbp_plugin = None
self._apic_segmentation_label_driver = None
self.l3out_vlan_alloc = l3out_vlan_alloc.L3outVlanAlloc()
self.l3out_vlan_alloc.sync_vlan_allocations(
self.apic_manager.ext_net_dict)
@ -330,6 +331,17 @@ class ApicMappingDriver(api.ResourceMappingDriver,
.get("GROUP_POLICY"))
return self._gbp_plugin
@property
def apic_segmentation_label_driver(self):
if not self._apic_segmentation_label_driver:
ext_drivers = self.gbp_plugin.extension_manager.ordered_ext_drivers
for driver in ext_drivers:
if 'apic_segmentation_label' == driver.name:
self._apic_segmentation_label_driver = (
driver.obj)
break
return self._apic_segmentation_label_driver
# HA RPC call
def update_ip_owner(self, ip_owner_info):
# Needs to handle proxy ports
@ -506,6 +518,9 @@ class ApicMappingDriver(api.ResourceMappingDriver,
# Active chain head must have changed in a concurrent
# operation, get out of here
pass
if self.apic_segmentation_label_driver and pt and (
'segmentation_labels' in pt):
details['segmentation_labels'] = pt['segmentation_labels']
return details
def get_snat_ip_for_vrf(self, context, vrf_id, network, es_name=None):

View File

@ -0,0 +1,70 @@
# 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 oslo_log import log as logging
from gbpservice.neutron.db.grouppolicy.extensions import (
apic_segmentation_label_db as db)
from gbpservice.neutron.extensions import apic_segmentation_label as aslext
from gbpservice.neutron.services.grouppolicy import (
group_policy_driver_api as api)
LOG = logging.getLogger(__name__)
class ApicSegmentationLabelExtensionDriver(api.ExtensionDriver,
db.ApicSegmentationLabelDBMixin):
_supported_extension_alias = aslext.CISCO_APIC_GBP_SEGMENTATION_LABEL_EXT
_extension_dict = aslext.EXTENDED_ATTRIBUTES_2_0
def __init__(self):
LOG.debug("APIC Segmentation Label Extension Driver __init__")
self._policy_driver = None
def initialize(self):
pass
@property
def extension_alias(self):
return self._supported_extension_alias
def process_create_policy_target(self, session, data, result):
pt = data['policy_target']
if 'segmentation_labels' in pt:
for label in pt['segmentation_labels']:
self.add_policy_target_segmentation_label(
session, policy_target_id=result['id'],
segmentation_label=label)
def process_update_policy_target(self, session, data, result):
pt = data['policy_target']
if not 'segmentation_labels' in pt:
return
rows = self.get_policy_target_segmentation_labels(
session, policy_target_id=result['id'])
old_labels = [r.segmentation_label for r in rows]
add_labels = list(set(pt['segmentation_labels']) - set(old_labels))
for label in add_labels:
self.add_policy_target_segmentation_label(
session, policy_target_id=result['id'],
segmentation_label=label)
delete_labels = list(set(old_labels) - set(pt['segmentation_labels']))
for label in delete_labels:
self.delete_policy_target_segmentation_label(
session, policy_target_id=result['id'],
segmentation_label=label)
def extend_policy_target_dict(self, session, result):
rows = self.get_policy_target_segmentation_labels(
session, policy_target_id=result['id'])
labels = [r.segmentation_label for r in rows]
result['segmentation_labels'] = labels

View File

@ -94,6 +94,8 @@ class MockCallRecorder(mock.Mock):
class ApicMappingTestCase(
test_rmd.ResourceMappingTestCase,
mocked.ControllerMixin, mocked.ConfigMixin):
_extension_drivers = ['apic_segmentation_label']
_extension_path = None
def setUp(self, sc_plugin=None, nat_enabled=True,
pre_existing_l3out=False, default_agent_conf=True,
@ -105,6 +107,13 @@ class ApicMappingTestCase(
cfg.CONF.register_opts(sg_cfg.security_group_opts, 'SECURITYGROUP')
config.cfg.CONF.set_override('enable_security_group', False,
group='SECURITYGROUP')
if not cfg.CONF.group_policy.extension_drivers:
config.cfg.CONF.set_override('extension_drivers',
self._extension_drivers,
group='group_policy')
if self._extension_path:
config.cfg.CONF.set_override(
'api_extensions_path', self._extension_path)
n_rpc.create_connection = mock.Mock()
amap.ApicMappingDriver.get_apic_manager = mock.Mock(
return_value=mock.MagicMock(
@ -425,12 +434,17 @@ class TestPolicyTarget(ApicMappingTestCase):
ptg = self.create_policy_target_group(
name="ptg1", l2_policy_id=l2p['id'],
network_service_policy_id=nsp['id'])['policy_target_group']
segmentation_labels = ['label1', 'label2']
pt1 = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
policy_target_group_id=ptg['id'],
segmentation_labels=segmentation_labels)['policy_target']
self._bind_port_to_host(pt1['port_id'], 'h1')
mapping = self.driver.get_gbp_details(context.get_admin_context(),
device='tap%s' % pt1['port_id'], host='h1')
if 'apic_segmentation_label' in self._extension_drivers:
self.assertItemsEqual(segmentation_labels,
mapping['segmentation_labels'])
req_mapping = self.driver.request_endpoint_details(
context.get_admin_context(),
request={'device': 'tap%s' % pt1['port_id'], 'host': 'h1',

View File

@ -0,0 +1,90 @@
# 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 api as db_api
from gbpservice.neutron.db.grouppolicy.extensions import (
apic_segmentation_label_db as db)
from gbpservice.neutron.tests.unit.services.grouppolicy import (
test_extension_driver_api as test_ext_base)
class ExtensionDriverTestCaseMixin(object):
def test_pt_lifecycle(self):
ptg = self.create_policy_target_group()['policy_target_group']
pt = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
self.assertEqual([], pt['segmentation_labels'])
pt = self.show_policy_target(
pt['id'], expected_res_status=200)['policy_target']
self.assertEqual([], pt['segmentation_labels'])
self.delete_policy_target(pt['id'], expected_res_status=204)
labels = []
pt = self.create_policy_target(
policy_target_group_id=ptg['id'],
segmentation_labels=labels)['policy_target']
self.assertItemsEqual(labels, pt['segmentation_labels'])
pt = self.show_policy_target(
pt['id'], expected_res_status=200)['policy_target']
self.assertItemsEqual([], pt['segmentation_labels'])
self.delete_policy_target(pt['id'], expected_res_status=204)
labels = ['red', 'blue']
pt = self.create_policy_target(
policy_target_group_id=ptg['id'],
segmentation_labels=labels)['policy_target']
self.assertItemsEqual(labels, pt['segmentation_labels'])
pt = self.show_policy_target(
pt['id'], expected_res_status=200)['policy_target']
self.assertItemsEqual(labels, pt['segmentation_labels'])
labels = ['green', 'black', 'red']
pt = self.update_policy_target(
pt['id'], segmentation_labels=labels,
expected_res_status=200)['policy_target']
self.assertItemsEqual(labels, pt['segmentation_labels'])
pt = self.show_policy_target(
pt['id'], expected_res_status=200)['policy_target']
self.assertItemsEqual(labels, pt['segmentation_labels'])
labels = []
pt = self.update_policy_target(
pt['id'], segmentation_labels=labels,
expected_res_status=200)['policy_target']
self.assertItemsEqual(labels, pt['segmentation_labels'])
pt = self.show_policy_target(
pt['id'], expected_res_status=200)['policy_target']
self.assertItemsEqual(labels, pt['segmentation_labels'])
labels = ['black']
pt = self.update_policy_target(
pt['id'], segmentation_labels=labels,
expected_res_status=200)['policy_target']
self.assertItemsEqual(labels, pt['segmentation_labels'])
pt = self.show_policy_target(
pt['id'], expected_res_status=200)['policy_target']
self.assertItemsEqual(labels, pt['segmentation_labels'])
self.delete_policy_target(pt['id'], expected_res_status=204)
session = db_api.get_session()
rows = (session.query(db.ApicSegmentationLabelDB).filter_by(
policy_target_id=pt['id']).all())
self.assertEqual([], rows)
class ExtensionDriverTestCase(test_ext_base.ExtensionDriverTestBase,
ExtensionDriverTestCaseMixin):
_extension_drivers = ['apic_segmentation_label']
_extension_path = None

View File

@ -36,7 +36,8 @@ class ApicMappingStitchingPlumberGBPTestCase(
def setUp(self, plumber='stitching_plumber'):
cfg.CONF.set_override(
'extension_drivers', ['proxy_group'], group='group_policy')
'extension_drivers', ['apic_segmentation_label',
'proxy_group'], group='group_policy')
cfg.CONF.set_override('node_plumber', plumber,
group='node_composition_plugin')
super(ApicMappingStitchingPlumberGBPTestCase, self).setUp(

View File

@ -59,6 +59,7 @@ gbpservice.neutron.group_policy.extension_drivers =
test = gbpservice.neutron.tests.unit.services.grouppolicy.test_extension_driver_api:TestExtensionDriver
proxy_group = gbpservice.neutron.services.grouppolicy.drivers.extensions.proxy_group_driver:ProxyGroupDriver
aim_extension = gbpservice.neutron.services.grouppolicy.drivers.extensions.aim_mapping_extension_driver:AIMExtensionDriver
apic_segmentation_label = gbpservice.neutron.services.grouppolicy.drivers.extensions.apic_segmentation_label_driver:ApicSegmentationLabelExtensionDriver
gbpservice.neutron.group_policy.policy_drivers =
dummy = gbpservice.neutron.services.grouppolicy.drivers.dummy_driver:NoopDriver
implicit_policy = gbpservice.neutron.services.grouppolicy.drivers.implicit_policy:ImplicitPolicyDriver