Merge "[apic-mapping] Segmentation Label extension for PT"
This commit is contained in:
commit
7cde0d37ea
|
@ -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