[apic-mapping] Segmentation Label extension for PT
This patch defines a new extension: cisco_apic_gbp_segmentation_label, for the apic policy drivers. An extension attribute: segmentation_labels, that extends the Policy Target definition, is being introduced in this extension. A corresponding extension driver: apic_segmentation_label, that processes this extension, is also being added. This extension driver should be configured for this extension to be available. The driver name should be added to the existing list of extension drivers under: [group_policy] extension_drivers=<existing_ext_drivers>,apic_segmentation_label The segementation_labels attribute is a list of strings. Each string can be upto 255 characters long. These labels are not interpreted by GBP but are instead passed downstream by the apic policy driver. It is assumed that these are defined outside of OpenStack and the backend system can appropriately interpret them. The get_gbp_details() RPC call implemented by the apic policy driver will return the segmentation_labels in its body if the 'segmentation_labels' attribute is populated for the policy_target. A CLI option: --segmentation-labels will be provided for the policy_target create and update operations. This CLI option will accept a comma separated string as the option value. Change-Id: I360bf9f7f1d4bdca76d4f16b7535a6416f430830
This commit is contained in:
parent
8784548bce
commit
2cb02e2ea1
|
@ -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)
|
|
@ -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
|
|
@ -1 +1 @@
|
|||
d4bb487a81b8
|
||||
092e4b1aeb0a
|
||||
|
|
|
@ -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 {}
|
|
@ -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):
|
||||
|
|
|
@ -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
|
|
@ -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',
|
||||
|
|
|
@ -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
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue