GBP servicechain instance should be maintained between a pair of PTGs
Change-Id: If30cbd09b1bd9ac2db5df47ac50e395274146dee Closes-bug: #1387508
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
# under the License.
|
||||
#
|
||||
|
||||
"""gbp_rule_servicechain_mapping
|
||||
"""gbp_ptgs_servicechain_mapping
|
||||
|
||||
Revision ID: 6d76bcf836a7
|
||||
Revises: 43443f15fa3f
|
||||
@@ -31,16 +31,22 @@ import sqlalchemy as sa
|
||||
|
||||
def upgrade(active_plugins=None, options=None):
|
||||
op.create_table(
|
||||
'gpm_rule_servicechain_mapping',
|
||||
sa.Column('rule_id', sa.String(length=36), nullable=False),
|
||||
'gpm_ptgs_servicechain_mapping',
|
||||
sa.Column('provider_ptg_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('consumer_ptg_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('servicechain_instance_id', sa.String(length=36)),
|
||||
sa.ForeignKeyConstraint(['rule_id'], ['gp_policy_rules.id']),
|
||||
sa.ForeignKeyConstraint(['provider_ptg_id'],
|
||||
['gp_policy_target_groups.id'],
|
||||
ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['consumer_ptg_id'],
|
||||
['gp_policy_target_groups.id'],
|
||||
ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['servicechain_instance_id'],
|
||||
['sc_instances.id'],
|
||||
ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('rule_id')
|
||||
sa.PrimaryKeyConstraint('servicechain_instance_id')
|
||||
)
|
||||
|
||||
|
||||
def downgrade(active_plugins=None, options=None):
|
||||
op.drop_table('gpm_rule_servicechain_mapping')
|
||||
op.drop_table('gpm_ptgs_servicechain_mapping')
|
||||
@@ -89,16 +89,22 @@ class PolicyRuleSetSGsMapping(model_base.BASEV2):
|
||||
sa.ForeignKey('securitygroups.id'))
|
||||
|
||||
|
||||
class RuleServiceChainInstanceMapping(model_base.BASEV2):
|
||||
"""Policy Rule to ServiceChainInstance mapping DB."""
|
||||
class PtgServiceChainInstanceMapping(model_base.BASEV2):
|
||||
"""Policy Target Group to ServiceChainInstance mapping DB."""
|
||||
|
||||
__tablename__ = 'gpm_rule_servicechain_mapping'
|
||||
rule_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('gp_policy_rules.id'),
|
||||
nullable=False, primary_key=True)
|
||||
__tablename__ = 'gpm_ptgs_servicechain_mapping'
|
||||
provider_ptg_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('gp_policy_target_groups.id',
|
||||
ondelete='CASCADE'),
|
||||
nullable=False)
|
||||
consumer_ptg_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('gp_policy_target_groups.id',
|
||||
ondelete='CASCADE'),
|
||||
nullable=False)
|
||||
servicechain_instance_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('sc_instances.id',
|
||||
ondelete='CASCADE'))
|
||||
ondelete='CASCADE'),
|
||||
primary_key=True)
|
||||
|
||||
|
||||
class ServicePolicyPTGIpAddressMapping(model_base.BASEV2):
|
||||
@@ -362,7 +368,15 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
|
||||
@log.log
|
||||
def delete_policy_target_group_precommit(self, context):
|
||||
pass
|
||||
provider_ptg_chain_map = self._get_ptg_servicechain_mapping(
|
||||
context._plugin_context.session,
|
||||
context.current['id'],
|
||||
None)
|
||||
consumer_ptg_chain_map = self._get_ptg_servicechain_mapping(
|
||||
context._plugin_context.session,
|
||||
None,
|
||||
context.current['id'],)
|
||||
context.ptg_chain_map = provider_ptg_chain_map + consumer_ptg_chain_map
|
||||
|
||||
@log.log
|
||||
def delete_policy_target_group_postcommit(self, context):
|
||||
@@ -883,10 +897,6 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
policy_rule_set = context._plugin.get_policy_rule_set(
|
||||
context._plugin_context, policy_rule_set_id)
|
||||
for rule_id in policy_rule_set.get('policy_rules'):
|
||||
rule_chain_map = self._get_rule_servicechain_mapping(
|
||||
context._plugin_context.session, rule_id)
|
||||
if rule_chain_map:
|
||||
break # Only one redirect action per rule
|
||||
policy_rule = context._plugin.get_policy_rule(
|
||||
context._plugin_context, rule_id)
|
||||
classifier_id = policy_rule.get("policy_classifier_id")
|
||||
@@ -896,46 +906,29 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
if policy_action['action_type'].upper() == "REDIRECT":
|
||||
for ptg_consuming_prs in (
|
||||
ptgs_consuming_policy_rule_set):
|
||||
ptg_chain_map = self._get_ptg_servicechain_mapping(
|
||||
context._plugin_context.session,
|
||||
ptg_providing_prs.policy_target_group_id,
|
||||
ptg_consuming_prs.policy_target_group_id)
|
||||
if ptg_chain_map:
|
||||
break # one chain between a pair of PTGs
|
||||
sc_instance = self._create_servicechain_instance(
|
||||
context, policy_action.get("action_value"),
|
||||
ptg_providing_prs.policy_target_group_id,
|
||||
ptg_consuming_prs.policy_target_group_id,
|
||||
classifier_id)
|
||||
chain_instance_id = sc_instance['id']
|
||||
self._set_rule_servicechain_instance_mapping(
|
||||
self._set_ptg_servicechain_instance_mapping(
|
||||
context._plugin_context.session,
|
||||
rule_id, chain_instance_id)
|
||||
ptg_providing_prs.policy_target_group_id,
|
||||
ptg_consuming_prs.policy_target_group_id,
|
||||
chain_instance_id)
|
||||
break
|
||||
|
||||
def _cleanup_redirect_action(self, context):
|
||||
consumed_policy_rule_sets = context.current[
|
||||
'consumed_policy_rule_sets']
|
||||
provided_policy_rule_sets = context.current[
|
||||
'provided_policy_rule_sets']
|
||||
if not provided_policy_rule_sets and not consumed_policy_rule_sets:
|
||||
return
|
||||
policy_rule_sets = provided_policy_rule_sets + (
|
||||
consumed_policy_rule_sets)
|
||||
for policy_rule_set_id in policy_rule_sets:
|
||||
ptgs_consuming_policy_rule_set = (
|
||||
self._get_ptgs_consuming_policy_rule_set(
|
||||
context._plugin_context._session, policy_rule_set_id))
|
||||
ptg_providing_policy_rule_set = (
|
||||
self._get_ptgs_providing_policy_rule_set(
|
||||
context._plugin_context._session, policy_rule_set_id))
|
||||
# Delete the ServiceChain Instance when we do not have either
|
||||
# the Provider or the consumer PTGs
|
||||
if not ptgs_consuming_policy_rule_set or (
|
||||
not ptg_providing_policy_rule_set):
|
||||
policy_rule_set = context._plugin.get_policy_rule_set(
|
||||
context._plugin_context, policy_rule_set_id)
|
||||
for rule_id in policy_rule_set.get('policy_rules'):
|
||||
chain_id_map = self._get_rule_servicechain_mapping(
|
||||
context._plugin_context.session, rule_id)
|
||||
if chain_id_map:
|
||||
self._delete_servicechain_instance(
|
||||
context, chain_id_map.servicechain_instance_id)
|
||||
break # Only one redirect action per rule
|
||||
for ptg_chain in context.ptg_chain_map:
|
||||
self._delete_servicechain_instance(
|
||||
context, ptg_chain.servicechain_instance_id)
|
||||
|
||||
# The following methods perform the necessary subset of
|
||||
# functionality from neutron.api.v2.base.Controller.
|
||||
@@ -1541,15 +1534,22 @@ class ResourceMappingDriver(api.PolicyDriver):
|
||||
'consuming_cidrs': self._get_ptg_cidrs(
|
||||
context, policy_rule_set['consuming_policy_target_groups'])}
|
||||
|
||||
def _set_rule_servicechain_instance_mapping(self, session, rule_id,
|
||||
servicechain_instance_id):
|
||||
def _set_ptg_servicechain_instance_mapping(self, session, provider_ptg_id,
|
||||
consumer_ptg_id,
|
||||
servicechain_instance_id):
|
||||
with session.begin(subtransactions=True):
|
||||
mapping = RuleServiceChainInstanceMapping(
|
||||
rule_id=rule_id,
|
||||
mapping = PtgServiceChainInstanceMapping(
|
||||
provider_ptg_id=provider_ptg_id,
|
||||
consumer_ptg_id=consumer_ptg_id,
|
||||
servicechain_instance_id=servicechain_instance_id)
|
||||
session.add(mapping)
|
||||
|
||||
def _get_rule_servicechain_mapping(self, session, rule_id):
|
||||
def _get_ptg_servicechain_mapping(self, session, provider_ptg_id,
|
||||
consumer_ptg_id):
|
||||
with session.begin(subtransactions=True):
|
||||
return (session.query(RuleServiceChainInstanceMapping).
|
||||
filter_by(rule_id=rule_id).first())
|
||||
query = session.query(PtgServiceChainInstanceMapping)
|
||||
if provider_ptg_id:
|
||||
query = query.filter_by(provider_ptg_id=provider_ptg_id)
|
||||
if consumer_ptg_id:
|
||||
query = query.filter_by(consumer_ptg_id=consumer_ptg_id)
|
||||
return query.all()
|
||||
|
||||
@@ -27,10 +27,12 @@ import webob.exc
|
||||
from gbp.neutron.db import servicechain_db
|
||||
from gbp.neutron.services.grouppolicy.common import constants as gconst
|
||||
from gbp.neutron.services.grouppolicy import config
|
||||
from gbp.neutron.services.grouppolicy.drivers import resource_mapping
|
||||
from gbp.neutron.services.servicechain import servicechain_plugin
|
||||
from gbp.neutron.tests.unit.services.grouppolicy import test_grouppolicy_plugin
|
||||
|
||||
SERVICECHAIN_NODES = 'servicechain/servicechain_nodes'
|
||||
SERVICECHAIN_SPECS = 'servicechain/servicechain_specs'
|
||||
SERVICECHAIN_INSTANCES = 'servicechain/servicechain_instances'
|
||||
|
||||
|
||||
class NoL3NatSGTestPlugin(
|
||||
test_l3_plugin.TestNoL3NatPlugin,
|
||||
@@ -858,12 +860,23 @@ class TestPolicyRuleSet(ResourceMappingTestCase):
|
||||
self.assertEqual(udp_rule['port_range_max'], 150)
|
||||
|
||||
def test_redirect_to_chain(self):
|
||||
data = {'servicechain_node': {'service_type': "LOADBALANCER",
|
||||
'tenant_id': self._tenant_id,
|
||||
'config': "{}"}}
|
||||
scn_req = self.new_create_request(SERVICECHAIN_NODES, data, self.fmt)
|
||||
node = self.deserialize(self.fmt, scn_req.get_response(self.ext_api))
|
||||
scn_id = node['servicechain_node']['id']
|
||||
data = {'servicechain_spec': {'tenant_id': self._tenant_id,
|
||||
'nodes': [scn_id]}}
|
||||
scs_req = self.new_create_request(SERVICECHAIN_SPECS, data, self.fmt)
|
||||
spec = self.deserialize(self.fmt, scs_req.get_response(self.ext_api))
|
||||
scs_id = spec['servicechain_spec']['id']
|
||||
classifier = self.create_policy_classifier(
|
||||
name="class1", protocol="tcp", direction="in", port_range="20:90")
|
||||
classifier_id = classifier['policy_classifier']['id']
|
||||
action = self.create_policy_action(
|
||||
name="action1", action_type=gconst.GP_ACTION_REDIRECT,
|
||||
action_value=uuidutils.generate_uuid())
|
||||
action_value=scs_id)
|
||||
action_id = action['policy_action']['id']
|
||||
action_id_list = [action_id]
|
||||
policy_rule = self.create_policy_rule(
|
||||
@@ -874,47 +887,29 @@ class TestPolicyRuleSet(ResourceMappingTestCase):
|
||||
policy_rule_set = self.create_policy_rule_set(
|
||||
name="c1", policy_rules=policy_rule_list)
|
||||
policy_rule_set_id = policy_rule_set['policy_rule_set']['id']
|
||||
self.create_policy_target_group(
|
||||
provider_ptg = self.create_policy_target_group(
|
||||
name="ptg1", provided_policy_rule_sets={policy_rule_set_id: None})
|
||||
create_chain_instance = mock.patch.object(
|
||||
servicechain_plugin.ServiceChainPlugin,
|
||||
'create_servicechain_instance')
|
||||
create_chain_instance = create_chain_instance.start()
|
||||
chain_instance_id = uuidutils.generate_uuid()
|
||||
create_chain_instance.return_value = {'id': chain_instance_id}
|
||||
# TODO(Magesh):Add tests which verifies that provide/consumer PTGs
|
||||
# are set correctly for the SCI
|
||||
with mock.patch.object(
|
||||
resource_mapping.ResourceMappingDriver,
|
||||
'_set_rule_servicechain_instance_mapping') as set_rule:
|
||||
with mock.patch.object(servicechain_db.ServiceChainDbPlugin,
|
||||
'get_servicechain_spec') as sc_spec_get:
|
||||
sc_spec_get.return_value = {'servicechain_spec': {}}
|
||||
consumer_ptg = self.create_policy_target_group(
|
||||
name="ptg2",
|
||||
consumed_policy_rule_sets={policy_rule_set_id: None})
|
||||
consumer_ptg_id = consumer_ptg['policy_target_group']['id']
|
||||
set_rule.assert_called_once_with(mock.ANY, policy_rule_id,
|
||||
chain_instance_id)
|
||||
with mock.patch.object(servicechain_plugin.ServiceChainPlugin,
|
||||
'delete_servicechain_instance'):
|
||||
with mock.patch.object(
|
||||
resource_mapping.ResourceMappingDriver,
|
||||
'_get_rule_servicechain_mapping') as get_rule:
|
||||
r_sc_map = resource_mapping.RuleServiceChainInstanceMapping()
|
||||
r_sc_map.rule_id = policy_rule_id
|
||||
r_sc_map.servicechain_instance_id = chain_instance_id
|
||||
get_rule.return_value = r_sc_map
|
||||
get_chain_inst = mock.patch.object(
|
||||
servicechain_db.ServiceChainDbPlugin,
|
||||
'get_servicechain_instance')
|
||||
get_chain_inst.start()
|
||||
get_chain_inst.return_value = {
|
||||
"servicechain_instance": {'id': chain_instance_id}}
|
||||
req = self.new_delete_request(
|
||||
'policy_target_groups', consumer_ptg_id)
|
||||
res = req.get_response(self.ext_api)
|
||||
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
|
||||
provider_ptg_id = provider_ptg['policy_target_group']['id']
|
||||
consumer_ptg = self.create_policy_target_group(
|
||||
name="ptg2",
|
||||
consumed_policy_rule_sets={policy_rule_set_id: None})
|
||||
consumer_ptg_id = consumer_ptg['policy_target_group']['id']
|
||||
sc_node_list_req = self.new_list_request(SERVICECHAIN_INSTANCES)
|
||||
res = sc_node_list_req.get_response(self.ext_api)
|
||||
sc_instances = self.deserialize(self.fmt, res)
|
||||
# We should have one service chain instance created now
|
||||
self.assertEqual(len(sc_instances['servicechain_instances']), 1)
|
||||
sc_instance = sc_instances['servicechain_instances'][0]
|
||||
self.assertEqual(sc_instance['provider_ptg_id'], provider_ptg_id)
|
||||
self.assertEqual(sc_instance['consumer_ptg_id'], consumer_ptg_id)
|
||||
req = self.new_delete_request(
|
||||
'policy_target_groups', consumer_ptg_id)
|
||||
res = req.get_response(self.ext_api)
|
||||
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
|
||||
sc_node_list_req = self.new_list_request(SERVICECHAIN_INSTANCES)
|
||||
res = sc_node_list_req.get_response(self.ext_api)
|
||||
sc_instances = self.deserialize(self.fmt, res)
|
||||
self.assertEqual(len(sc_instances['servicechain_instances']), 0)
|
||||
|
||||
def test_shared_policy_rule_set_create_negative(self):
|
||||
self.create_policy_rule_set(shared=True, expected_res_status=400)
|
||||
@@ -931,4 +926,4 @@ class TestPolicyAction(ResourceMappingTestCase):
|
||||
shared=True,
|
||||
action_value=uuid)
|
||||
self.assertEqual('InvalidSharedResource',
|
||||
res['NeutronError']['type'])
|
||||
res['NeutronError']['type'])
|
||||
|
||||
Reference in New Issue
Block a user