Fix Network Service Policy Implementation

1) Adds validation for supported NSP parameters in RMD
2) Fixes issue with unset/cleanup of NSP from PTG
3) Prevent deletion of in use NSP

Change-Id: Ic67c705d239741f35792ed0e4b06f48663df63ff
Closes-Bug: 1423689
Closes-Bug: 1426902
Partial-Bug: 1421413
This commit is contained in:
magesh 2015-02-21 19:08:02 +05:30 committed by Magesh GV
parent 2cb2c9fc13
commit 74c1fecebd
6 changed files with 211 additions and 21 deletions

View File

@ -1316,6 +1316,9 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
with context.session.begin(subtransactions=True):
nsp_db = self._get_network_service_policy(
context, network_service_policy_id)
if nsp_db.policy_target_groups:
raise gpolicy.NetworkServicePolicyInUse(
network_service_policy_id=network_service_policy_id)
context.session.delete(nsp_db)
@log.log

View File

@ -74,6 +74,11 @@ class L3PolicyInUse(nexc.InUse):
"in use")
class NetworkServicePolicyInUse(nexc.InUse):
message = _("Unable to complete operation, NetworkServicePolicy "
"%(network_service_policy_id)s is in use")
class NetworkServicePolicyNotFound(nexc.NotFound):
message = _("NetworkServicePolicy %(network_service_policy_id)s "
"could not be found")

View File

@ -210,3 +210,8 @@ class MultipleRedirectActionsNotSupportedForRule(GroupPolicyBadRequest):
class MultipleRedirectActionsNotSupportedForPRS(GroupPolicyBadRequest):
message = _("Resource Mapping Driver does not support multiple redirect "
"actions in a Policy Rule Set.")
class InvalidNetworkServiceParameters(GroupPolicyBadRequest):
message = _("Resource Mapping Driver currently supports only one "
"parameter of type: ip_single and value: self_subnet")

View File

@ -310,15 +310,9 @@ class ResourceMappingDriver(api.PolicyDriver):
nsp = context._plugin.get_network_service_policy(
context._plugin_context, network_service_policy_id)
nsp_params = nsp.get("network_service_params")
if not nsp_params:
if not nsp.get("network_service_params"):
return
# RM Driver only supports one parameter of type ip_single and value
# self_subnet right now. Handle the other cases when we have usecase
if (len(nsp_params) > 1 or nsp_params[0].get("type") != "ip_single"
or nsp_params[0].get("value") != "self_subnet"):
return
# TODO(Magesh):Handle concurrency issues
free_ip = self._get_last_free_ip(context._plugin_context,
context.current['subnets'])
@ -340,11 +334,14 @@ class ResourceMappingDriver(api.PolicyDriver):
context._plugin_context.session, policy_target_group)
return ipaddress
def _cleanup_network_service_policy(self, context, subnet, ptg_id):
ipaddress = self._get_ptg_policy_ipaddress_mapping(
context._plugin_context.session, ptg_id)
def _cleanup_network_service_policy(self, context, subnet, ptg_id,
ipaddress=None):
if not ipaddress:
ipaddress = self._get_ptg_policy_ipaddress_mapping(
context._plugin_context.session, ptg_id)
if ipaddress:
self._restore_ip_to_allocation_pool(context, subnet, ipaddress)
self._restore_ip_to_allocation_pool(
context, subnet, ipaddress.ipaddress)
self._delete_policy_ipaddress_mapping(
context._plugin_context.session, ptg_id)
@ -486,6 +483,8 @@ class ResourceMappingDriver(api.PolicyDriver):
@log.log
def delete_policy_target_group_precommit(self, context):
context.nsp_cleanup_ipaddress = self._get_ptg_policy_ipaddress_mapping(
context._plugin_context.session, context.current['id'])
provider_ptg_chain_map = self._get_ptg_servicechain_mapping(
context._plugin_context.session,
context.current['id'],
@ -500,7 +499,8 @@ class ResourceMappingDriver(api.PolicyDriver):
def delete_policy_target_group_postcommit(self, context):
self._cleanup_network_service_policy(context,
context.current['subnets'][0],
context.current['id'])
context.current['id'],
context.nsp_cleanup_ipaddress)
self._cleanup_redirect_action(context)
# Cleanup SGs
self._unset_sg_rules_for_subnets(
@ -817,12 +817,8 @@ class ResourceMappingDriver(api.PolicyDriver):
context, context.current['child_policy_rule_sets'])
@log.log
def delete_network_service_policy_postcommit(self, context):
for ptg_id in context.current.get("policy_target_groups"):
ptg = context._plugin.get_policy_target_group(
context._plugin_context, ptg_id)
subnet = ptg.get('subnets')[0]
self._cleanup_network_service_policy(context, subnet, ptg_id)
def create_network_service_policy_precommit(self, context):
self._validate_nsp_parameters(context)
def create_external_segment_precommit(self, context):
if context.current['subnet_id']:
@ -974,6 +970,19 @@ class ResourceMappingDriver(api.PolicyDriver):
# REVISIT(ivar): ignore or reject?
pass
def _validate_nsp_parameters(self, context):
# RM Driver only supports one parameter of type ip_single and value
# self_subnet right now. Handle the other cases when we have usecase
nsp = context.current
nsp_params = nsp.get("network_service_params")
if nsp_params and (len(nsp_params) > 1 or
(nsp_params[0].get("type") != "ip_single" or
nsp_params[0].get("value") != "self_subnet")):
raise exc.InvalidNetworkServiceParameters()
def update_network_service_policy_precommit(self, context):
self._validate_nsp_parameters(context)
def _get_routerid_for_l2policy(self, context, l2p_id):
l2p = context._plugin.get_l2_policy(context._plugin_context, l2p_id)
l3p_id = l2p['l3_policy_id']
@ -1240,11 +1249,11 @@ class ResourceMappingDriver(api.PolicyDriver):
def _delete_policy_ipaddress_mapping(self, session, policy_target_group):
with session.begin(subtransactions=True):
mappings = session.query(
ip_mapping = session.query(
ServicePolicyPTGIpAddressMapping).filter_by(
policy_target_group=policy_target_group).first()
for ip_map in mappings:
session.delete(ip_map)
if ip_mapping:
session.delete(ip_mapping)
def _handle_redirect_spec_id_update(self, context):
if (context.current['action_type'] != gconst.GP_ACTION_REDIRECT

View File

@ -286,6 +286,62 @@ class TestGroupResources(GroupPolicyDbTestCase):
self._test_show_resource(
'policy_target_group', ptg['policy_target_group']['id'], attrs)
def test_create_associate_nsp_with_ptgs(self):
params = [{'type': 'ip_single', 'name': 'vip', 'value': 'self_subnet'}]
attrs = cm.get_create_network_service_policy_default_attrs(
network_service_params=params)
nsp = self.create_network_service_policy(network_service_params=params)
for k, v in attrs.iteritems():
self.assertEqual(nsp['network_service_policy'][k], v)
self._test_show_resource('network_service_policy',
nsp['network_service_policy']['id'], attrs)
# Create two PTGs that use this NSP
name1 = "ptg1"
provided_prs_id = (
self.create_policy_rule_set()['policy_rule_set']['id'])
consumed_prs_id = (
self.create_policy_rule_set()['policy_rule_set']['id'])
attrs = cm.get_create_policy_target_group_default_attrs(
name=name1,
network_service_policy_id=nsp['network_service_policy']['id'],
provided_policy_rule_sets=[provided_prs_id],
consumed_policy_rule_sets=[consumed_prs_id])
ptg1 = self.create_policy_target_group(
name=name1,
network_service_policy_id=nsp['network_service_policy']['id'],
provided_policy_rule_sets={provided_prs_id: None},
consumed_policy_rule_sets={consumed_prs_id: None})
for k, v in attrs.iteritems():
self.assertEqual(ptg1['policy_target_group'][k], v)
self._test_show_resource(
'policy_target_group', ptg1['policy_target_group']['id'], attrs)
name2 = "ptg2"
attrs.update(name=name2)
ptg2 = self.create_policy_target_group(
name=name2,
network_service_policy_id=nsp['network_service_policy']['id'],
provided_policy_rule_sets={provided_prs_id: None},
consumed_policy_rule_sets={consumed_prs_id: None})
for k, v in attrs.iteritems():
self.assertEqual(ptg2['policy_target_group'][k], v)
self._test_show_resource(
'policy_target_group', ptg2['policy_target_group']['id'], attrs)
# Update the PTG and unset the NSP used
data = {'policy_target_group': {
'name': name1, 'network_service_policy_id': None}}
req = self.new_update_request(
'policy_target_groups', data, ptg1['policy_target_group']['id'])
res = self.deserialize(self.fmt, req.get_response(self.ext_api))
self.assertEqual(
res['policy_target_group']['network_service_policy_id'], None)
def test_list_policy_target_groups(self):
ptgs = (
[self.create_policy_target_group(name='ptg1', description='ptg'),
@ -559,6 +615,29 @@ class TestGroupResources(GroupPolicyDbTestCase):
self.plugin.get_network_service_policy,
ctx, nsp_id)
def test_delete_network_service_policy_in_use(self):
ctx = context.get_admin_context()
nsp = self.create_network_service_policy()
nsp_id = nsp['network_service_policy']['id']
ptg = self.create_policy_target_group(network_service_policy_id=nsp_id)
ptg_id = ptg['policy_target_group']['id']
# Deleting the NSP used by the PTG should be rejected
self.assertRaises(gpolicy.NetworkServicePolicyInUse,
self.plugin.delete_network_service_policy,
ctx, nsp_id)
# After deleting the PTG, NSP delete should succeed
req = self.new_delete_request('policy_target_groups', ptg_id)
res = req.get_response(self.ext_api)
self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
req = self.new_delete_request('network_service_policies', nsp_id)
res = req.get_response(self.ext_api)
self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
self.assertRaises(gpolicy.NetworkServicePolicyNotFound,
self.plugin.get_network_service_policy,
ctx, nsp_id)
def test_delete_network_service_policy_with_params(self):
ctx = context.get_admin_context()
params = [{'type': 'ip_single', 'name': 'vip', 'value': 'self_subnet'}]

View File

@ -89,6 +89,10 @@ class ResourceMappingTestCase(test_plugin.GroupPolicyPluginTestCase):
return super(ResourceMappingTestCase, self)._create_network(
fmt, name, admin_state_up, arg_list=arg_list, **new_args)
def _show_subnet(self, id):
req = self.new_show_request('subnets', id, fmt=self.fmt)
return self.deserialize(self.fmt, req.get_response(self.api))
def _get_sg_rule(self, **filters):
plugin = manager.NeutronManager.get_plugin()
context = nctx.get_admin_context()
@ -2460,3 +2464,88 @@ class TestPolicyRule(ResourceMappingTestCase):
policy_actions=[action1['id'], action2['id']])
self.assertEqual('MultipleRedirectActionsNotSupportedForRule',
res['NeutronError']['type'])
class TestNetworkServicePolicy(ResourceMappingTestCase):
def test_create_nsp_multiple_ptgs(self):
nsp = self.create_network_service_policy(
network_service_params=[
{"type": "ip_single", "value": "self_subnet",
"name": "vip"}],
expected_res_status=webob.exc.HTTPCreated.code)[
'network_service_policy']
# Create two PTGs that use this NSP
ptg1 = self.create_policy_target_group(
network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
ptg2 = self.create_policy_target_group(
network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
# Update the PTGs and unset the NSP used
self.update_policy_target_group(
ptg1['id'],
network_service_policy_id=None,
expected_res_status=webob.exc.HTTPOk.code)
self.update_policy_target_group(
ptg2['id'],
network_service_policy_id=None,
expected_res_status=webob.exc.HTTPOk.code)
def test_unsupported_nsp_parameters_rejected(self):
self.create_network_service_policy(
network_service_params=[
{"type": "ip_pool", "value": "self_subnet", "name": "vip"}],
expected_res_status=webob.exc.HTTPBadRequest.code)
self.create_network_service_policy(
network_service_params=[
{"type": "ip_pool", "value": "external_subnet",
"name": "vip"}],
expected_res_status=webob.exc.HTTPBadRequest.code)
self.create_network_service_policy(
network_service_params=[
{"type": "ip_single", "value": "self_subnet", "name": "vip"},
{"type": "ip_single", "value": "self_subnet", "name": "vip"}],
expected_res_status=webob.exc.HTTPBadRequest.code)
def test_nsp_cleanup_on_unset(self):
ptg = self.create_policy_target_group(
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
ptg_subnet_id = ptg['subnets'][0]
subnet = self._show_subnet(ptg_subnet_id)['subnet']
initial_allocation_pool = subnet['allocation_pools']
nsp = self.create_network_service_policy(
network_service_params=[
{"type": "ip_single", "value": "self_subnet",
"name": "vip"}],
expected_res_status=webob.exc.HTTPCreated.code)[
'network_service_policy']
# Update PTG, associating a NSP with it and verify that an IP is
# reserved from the PTG subnet allocation pool
self.update_policy_target_group(
ptg['id'],
network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPOk.code)
subnet = self._show_subnet(ptg_subnet_id)['subnet']
allocation_pool_after_nsp = subnet['allocation_pools']
self.assertEqual(
netaddr.IPAddress(initial_allocation_pool[0].get('start')),
netaddr.IPAddress(allocation_pool_after_nsp[0].get('start')))
self.assertEqual(
netaddr.IPAddress(initial_allocation_pool[0].get('end')),
netaddr.IPAddress(allocation_pool_after_nsp[0].get('end')) + 1)
# Update the PTGs and unset the NSP used and verify that the IP is
# restored to the PTG subnet allocation pool
self.update_policy_target_group(
ptg['id'],
network_service_policy_id=None,
expected_res_status=webob.exc.HTTPOk.code)
subnet = self._show_subnet(ptg_subnet_id)['subnet']
allocation_pool_after_nsp_cleanup = subnet['allocation_pools']
self.assertEqual(
initial_allocation_pool, allocation_pool_after_nsp_cleanup)