Refactor GBP resource mapping with Neutron RESTful APIs
1. Decouple GBP resource mapping from neutron plugins and use Neutron RESTful APIs instead. 2. Move neutron_client related calls to neutron_api_mixin for easier removing in the future. 3. Add mock_neutronv2_api to provide methods to patch the Neutron RESTful API calls with WSGI calls. 4. Modify the existing 'UT' for the resource mapping driver, by patching the RESTful APIs with the WSGI calls, to ensure the test scenarios are still examined and passed. 5. Modify the existing 'UT' for the APIC mapping driver, by patching the RESTful APIs with the WSGI calls, to ensure the test scenarios are still examined and passed. Change-Id: I9ec6d159b87e77fcd034b2ff6d4e5c0969798b34 Author: Yi Yang <yyos1999@gmail.com> Co-Authored-By: Yapeng Wu <yapengwu@gmail.com> Co-Authored-By: Ivar Lazzaro <ivarlazzaro@gmail.com> Co-Authored-By: Robert Kukura <kukura@noironetworks.com>
This commit is contained in:
parent
c33954fb86
commit
84afe597d7
|
@ -0,0 +1,194 @@
|
|||
# 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.
|
||||
|
||||
import itertools
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from gbpservice.neutron.tests.unit import common as cm
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# While plugin APIs support ORing filters, they are not supported in REST APIs
|
||||
# or WSGI. A combination of these filters have to be generated to emulate the
|
||||
# ORing behavior.
|
||||
# For example, filters = {'foo': [a1, a2], 'bar': [b1, b2]} will be mapped to
|
||||
# a list of filters
|
||||
# [{'foo': a1, 'bar': b1},
|
||||
# {'foo': a1, 'bar': b2},
|
||||
# {'foo': a2, 'bar': b1},
|
||||
# {'foo': a2, 'bar': b2}]
|
||||
def get_filter_combinations(filters):
|
||||
formatted_filters = {}
|
||||
for key, value in filters.iteritems():
|
||||
formatted_filters[key] = value if isinstance(value, list) else [value]
|
||||
keys = sorted(formatted_filters)
|
||||
return [dict(zip(keys, prod)) for prod in
|
||||
itertools.product(*(formatted_filters[key] for key in keys))]
|
||||
|
||||
|
||||
class NeutronAPIMixin(object):
|
||||
"""A Wrapper class of Neutronv2 Client APIs.
|
||||
|
||||
Ideally, we want to call Neutronv2 Client APIs directly in resource mapping
|
||||
and other drivers. But there are some existing APIs as previously plugin
|
||||
APIs were used, and we need to keep these APIs so we don't need to touch
|
||||
too many codes. Later when we clean up the resource mappings, this Mixin
|
||||
wrapper should be removed as well.
|
||||
"""
|
||||
|
||||
def _create_port(self, plugin_context, attrs):
|
||||
return self._create_neutron_resource(plugin_context, 'port', attrs)
|
||||
|
||||
def _get_port(self, plugin_context, port_id):
|
||||
return self._get_neutron_resource(plugin_context, 'port', port_id)
|
||||
|
||||
def _update_port(self, plugin_context, port_id, attrs):
|
||||
return self._update_neutron_resource(
|
||||
plugin_context, 'port', port_id, attrs)
|
||||
|
||||
def _delete_port(self, plugin_context, port_id):
|
||||
self._delete_neutron_resource(plugin_context, 'port', port_id)
|
||||
|
||||
def _create_subnet(self, plugin_context, attrs):
|
||||
return self._create_neutron_resource(plugin_context, 'subnet', attrs)
|
||||
|
||||
def _get_subnet(self, plugin_context, subnet_id):
|
||||
return self._get_neutron_resource(plugin_context, 'subnet', subnet_id)
|
||||
|
||||
def _get_subnets(self, plugin_context, filters={}):
|
||||
return self._get_neutron_resources(plugin_context, 'subnet', filters)
|
||||
|
||||
def _update_subnet(self, plugin_context, subnet_id, attrs):
|
||||
return self._update_neutron_resource(
|
||||
plugin_context, 'subnet', subnet_id, attrs)
|
||||
|
||||
def _delete_subnet(self, plugin_context, subnet_id):
|
||||
self._delete_neutron_resource(plugin_context, 'subnet', subnet_id)
|
||||
|
||||
def _create_network(self, plugin_context, attrs):
|
||||
return self._create_neutron_resource(plugin_context, 'network', attrs)
|
||||
|
||||
def _get_network(self, plugin_context, network_id):
|
||||
return self._get_neutron_resource(
|
||||
plugin_context, 'network', network_id)
|
||||
|
||||
def _delete_network(self, plugin_context, network_id):
|
||||
self._delete_neutron_resource(plugin_context, 'network', network_id)
|
||||
|
||||
def _create_router(self, plugin_context, attrs):
|
||||
return self._create_neutron_resource(plugin_context, 'router', attrs)
|
||||
|
||||
def _get_router(self, plugin_context, router_id):
|
||||
return self._get_neutron_resource(plugin_context, 'router', router_id)
|
||||
|
||||
def _update_router(self, plugin_context, router_id, attrs):
|
||||
return self._update_neutron_resource(
|
||||
plugin_context, 'router', router_id, attrs)
|
||||
|
||||
def _delete_router(self, plugin_context, router_id):
|
||||
self._delete_neutron_resource(plugin_context, 'router', router_id)
|
||||
|
||||
def _add_router_interface(self, plugin_context, router_id, interface):
|
||||
self._neutron.add_router_interface(
|
||||
plugin_context, router_id, interface)
|
||||
|
||||
def _remove_router_interface(self, plugin_context, router_id, interface):
|
||||
self._neutron.remove_router_interface(
|
||||
plugin_context, router_id, interface)
|
||||
|
||||
def _add_router_gw_interface(self, plugin_context, router_id, gw_info):
|
||||
return self._update_router(
|
||||
plugin_context, router_id, {'external_gateway_info': gw_info})
|
||||
|
||||
def _remove_router_gw_interface(
|
||||
self, plugin_context, router_id, interface_info):
|
||||
self._update_router(
|
||||
plugin_context, router_id, {'external_gateway_info': None})
|
||||
|
||||
def _create_sg(self, plugin_context, attrs):
|
||||
return self._create_neutron_resource(
|
||||
plugin_context, 'security_group', attrs)
|
||||
|
||||
def _get_sg(self, plugin_context, sg_id):
|
||||
return self._get_neutron_resource(
|
||||
plugin_context, 'security_group', sg_id)
|
||||
|
||||
def _get_sgs(self, plugin_context, filters={}):
|
||||
return self._get_neutron_resources(
|
||||
plugin_context, 'security_group', filters)
|
||||
|
||||
def _update_sg(self, plugin_context, sg_id, attrs):
|
||||
return self._update_neutron_resource(
|
||||
plugin_context, 'security_group', sg_id, attrs)
|
||||
|
||||
def _delete_sg(self, plugin_context, sg_id):
|
||||
self._delete_neutron_resource(
|
||||
plugin_context, 'security_group', sg_id)
|
||||
|
||||
def _create_sg_rule(self, plugin_context, attrs):
|
||||
return self._create_neutron_resource(
|
||||
plugin_context, 'security_group_rule', attrs)
|
||||
|
||||
def _get_sg_rule(self, plugin_context, sg_rule_id):
|
||||
return self._get_neutron_resource(
|
||||
plugin_context, 'security_group_rule', sg_rule_id)
|
||||
|
||||
def _get_sg_rules(self, plugin_context, filters={}):
|
||||
return self._get_neutron_resources(
|
||||
plugin_context, 'security_group_rule', filters)
|
||||
|
||||
# REVISIT(yi): update_security_group_rule not supported in neutron yet
|
||||
# def _update_security_group_rule(self, plugin_context, sg_rule_id, attrs):
|
||||
# return self._update_neutron_resource(
|
||||
# plugin_context, 'security_group_rule', sg_rule_id, attrs)
|
||||
|
||||
def _delete_sg_rule(self, plugin_context, sg_rule_id):
|
||||
self._delete_neutron_resource(
|
||||
plugin_context, 'security_group_rule', sg_rule_id)
|
||||
|
||||
def _create_neutron_resource(self, context, resource, attrs):
|
||||
action = 'create_' + resource
|
||||
obj_creator = getattr(self._neutron, action)
|
||||
obj = obj_creator(context, {resource: attrs})
|
||||
return obj
|
||||
|
||||
def _get_neutron_resource(self, context, resource, resource_id):
|
||||
obj_getter = getattr(self._neutron, 'show_' + resource)
|
||||
obj = obj_getter(context, resource_id)
|
||||
return obj
|
||||
|
||||
def _get_neutron_resources(self, context, resource, filters={}):
|
||||
# REST APIs does not support ORing filtering
|
||||
# Has to handle the combination of filters instead
|
||||
filter_list = get_filter_combinations(filters)
|
||||
resources = cm.get_resource_plural(resource)
|
||||
obj_getter = getattr(self._neutron, 'list_' + resources)
|
||||
res = []
|
||||
for filter in filter_list:
|
||||
obj = obj_getter(context, filter)
|
||||
# merge the result and remove the duplicate
|
||||
res.extend(x for x in obj if x not in res)
|
||||
return res
|
||||
|
||||
def _update_neutron_resource(self, context, resource, resource_id, attrs):
|
||||
action = 'update_' + resource
|
||||
obj_updater = getattr(self._neutron, action)
|
||||
obj = obj_updater(context, resource_id, {resource: attrs})
|
||||
return obj
|
||||
|
||||
def _delete_neutron_resource(self, context, resource, resource_id):
|
||||
action = 'delete_' + resource
|
||||
obj_deleter = getattr(self._neutron, action)
|
||||
obj_deleter(context, resource_id)
|
|
@ -13,9 +13,7 @@
|
|||
import netaddr
|
||||
|
||||
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
|
||||
from neutron.api.v2 import attributes
|
||||
from neutron.common import constants as const
|
||||
from neutron.common import exceptions as n_exc
|
||||
from neutron.common import log
|
||||
from neutron import context as n_context
|
||||
from neutron.db import model_base
|
||||
|
@ -24,17 +22,20 @@ from neutron.extensions import securitygroup as ext_sg
|
|||
from neutron import manager
|
||||
from neutron.notifiers import nova
|
||||
from neutron.plugins.common import constants as pconst
|
||||
from neutronclient.common import exceptions as neutron_client_exc
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
import sqlalchemy as sa
|
||||
|
||||
from gbpservice.network.neutronv2 import api as neutron_api
|
||||
from gbpservice.neutron.db.grouppolicy import group_policy_db as gpdb
|
||||
from gbpservice.neutron.db import servicechain_db # noqa
|
||||
from gbpservice.neutron.services.grouppolicy import (
|
||||
group_policy_driver_api as api)
|
||||
from gbpservice.neutron.services.grouppolicy.common import constants as gconst
|
||||
from gbpservice.neutron.services.grouppolicy.common import exceptions as exc
|
||||
from gbpservice.neutron.services.grouppolicy.drivers import neutron_api_mixin
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -119,7 +120,8 @@ class ServicePolicyPTGIpAddressMapping(model_base.BASEV2):
|
|||
ipaddress = sa.Column(sa.String(36))
|
||||
|
||||
|
||||
class ResourceMappingDriver(api.PolicyDriver):
|
||||
class ResourceMappingDriver(api.PolicyDriver,
|
||||
neutron_api_mixin.NeutronAPIMixin):
|
||||
"""Resource Mapping driver for Group Policy plugin.
|
||||
|
||||
This driver implements group policy semantics by mapping group
|
||||
|
@ -130,6 +132,7 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
def initialize(self):
|
||||
self._cached_agent_notifier = None
|
||||
self._nova_notifier = nova.Notifier()
|
||||
self._neutron = neutron_api.API()
|
||||
|
||||
def _reject_shared(self, object, type):
|
||||
if object.get('shared'):
|
||||
|
@ -156,7 +159,7 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
|
||||
def _reject_non_shared_net_on_shared_l2p(self, context):
|
||||
if context.current.get('shared') and context.current['network_id']:
|
||||
net = self._core_plugin.get_network(
|
||||
net = self._get_network(
|
||||
context._plugin_context, context.current['network_id'])
|
||||
if not net.get('shared'):
|
||||
raise exc.NonSharedNetworkOnSharedL2PolicyNotSupported()
|
||||
|
@ -170,9 +173,8 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
plugin_context = context._plugin_context
|
||||
network = None
|
||||
try:
|
||||
network = self._core_plugin.get_network(plugin_context,
|
||||
network_id)
|
||||
except n_exc.NetworkNotFound:
|
||||
network = self._get_network(plugin_context, network_id)
|
||||
except neutron_client_exc.NotFound:
|
||||
raise exc.InvalidNetworkAccess(
|
||||
msg="Can't access other tenants networks",
|
||||
network_id=context.current['network_id'],
|
||||
|
@ -193,9 +195,8 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
for router_id in context.current['routers']:
|
||||
router = None
|
||||
try:
|
||||
router = self._l3_plugin.get_router(context._plugin_context,
|
||||
router_id)
|
||||
except n_exc.NotFound:
|
||||
router = self._get_router(context._plugin_context, router_id)
|
||||
except neutron_client_exc.NotFound:
|
||||
raise exc.InvalidRouterAccess(
|
||||
msg="Can't access other tenants router",
|
||||
router_id=router_id,
|
||||
|
@ -265,12 +266,13 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
|
||||
@log.log
|
||||
def delete_policy_target_postcommit(self, context):
|
||||
sg_list = self._generate_list_of_sg_from_ptg(
|
||||
context, context.current['policy_target_group_id'])
|
||||
self._disassoc_sgs_from_port(context._plugin_context,
|
||||
context.current['port_id'], sg_list)
|
||||
port_id = context.current['port_id']
|
||||
self._cleanup_port(context._plugin_context, port_id)
|
||||
if port_id:
|
||||
sg_list = self._generate_list_of_sg_from_ptg(
|
||||
context, context.current['policy_target_group_id'])
|
||||
self._disassoc_sgs_from_port(
|
||||
context._plugin_context, port_id, sg_list)
|
||||
self._cleanup_port(context._plugin_context, port_id)
|
||||
|
||||
@log.log
|
||||
def create_policy_target_group_precommit(self, context):
|
||||
|
@ -824,10 +826,10 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
|
||||
def create_external_segment_precommit(self, context):
|
||||
if context.current['subnet_id']:
|
||||
subnet = self._core_plugin.get_subnet(context._plugin_context,
|
||||
context.current['subnet_id'])
|
||||
network = self._core_plugin.get_network(context._plugin_context,
|
||||
subnet['network_id'])
|
||||
subnet = self._get_subnet(context._plugin_context,
|
||||
context.current['subnet_id'])
|
||||
network = self._get_network(context._plugin_context,
|
||||
subnet['network_id'])
|
||||
if not network['router:external']:
|
||||
raise exc.InvalidSubnetForES(sub_id=subnet['id'],
|
||||
net_id=network['id'])
|
||||
|
@ -1029,8 +1031,6 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
attrs = {'tenant_id': context.current['tenant_id'],
|
||||
'name': 'pt_' + context.current['name'],
|
||||
'network_id': l2p['network_id'],
|
||||
'mac_address': attributes.ATTR_NOT_SPECIFIED,
|
||||
'fixed_ips': attributes.ATTR_NOT_SPECIFIED,
|
||||
'device_id': '',
|
||||
'device_owner': '',
|
||||
'security_groups': [sg_id] if sg_id else None,
|
||||
|
@ -1044,7 +1044,7 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
if self._port_is_owned(plugin_context.session, port_id):
|
||||
try:
|
||||
self._delete_port(plugin_context, port_id)
|
||||
except n_exc.PortNotFound:
|
||||
except neutron_client_exc.NotFound:
|
||||
LOG.warn(_("Port %s is missing") % port_id)
|
||||
|
||||
def _plug_router_to_external_segment(self, context, es_dict):
|
||||
|
@ -1053,8 +1053,8 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
if context.current['routers']:
|
||||
router_id = context.current['routers'][0]
|
||||
for es in es_list:
|
||||
subnet = self._core_plugin.get_subnet(context._plugin_context,
|
||||
es['subnet_id'])
|
||||
subnet = self._get_subnet(context._plugin_context,
|
||||
es['subnet_id'])
|
||||
external_fixed_ips = [
|
||||
{'subnet_id': es['subnet_id'],
|
||||
'ip_address': x} for x in es_dict[es['id']]
|
||||
|
@ -1081,8 +1081,8 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
if context.current['routers']:
|
||||
router_id = context.current['routers'][0]
|
||||
for es in es_list:
|
||||
subnet = self._core_plugin.get_subnet(context._plugin_context,
|
||||
es['subnet_id'])
|
||||
subnet = self._get_subnet(context._plugin_context,
|
||||
es['subnet_id'])
|
||||
interface_info = {'network_id': subnet['network_id']}
|
||||
self._remove_router_gw_interface(context._plugin_context,
|
||||
router_id, interface_info)
|
||||
|
@ -1107,8 +1107,8 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
subnets = []
|
||||
for ptg in ptgs:
|
||||
subnets.extend(ptg['subnets'])
|
||||
subnets = self._core_plugin.get_subnets(context._plugin_context,
|
||||
filters={'id': subnets})
|
||||
subnets = self._get_subnets(context._plugin_context,
|
||||
filters={'id': subnets})
|
||||
for cidr in pool.subnet(l3p['subnet_prefix_length']):
|
||||
if not self._validate_subnet_overlap_for_l3p(subnets,
|
||||
cidr.__str__()):
|
||||
|
@ -1119,11 +1119,7 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
'network_id': l2p['network_id'],
|
||||
'ip_version': l3p['ip_version'],
|
||||
'cidr': cidr.__str__(),
|
||||
'enable_dhcp': True,
|
||||
'gateway_ip': attributes.ATTR_NOT_SPECIFIED,
|
||||
'allocation_pools': attributes.ATTR_NOT_SPECIFIED,
|
||||
'dns_nameservers': attributes.ATTR_NOT_SPECIFIED,
|
||||
'host_routes': attributes.ATTR_NOT_SPECIFIED}
|
||||
'enable_dhcp': True}
|
||||
subnet = self._create_subnet(context._plugin_context, attrs)
|
||||
subnet_id = subnet['id']
|
||||
try:
|
||||
|
@ -1136,18 +1132,19 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
context._plugin_context.session, subnet_id)
|
||||
context.add_subnet(subnet_id)
|
||||
return
|
||||
except n_exc.InvalidInput:
|
||||
except neutron_client_exc.BadRequest:
|
||||
# This exception is not expected. We catch this
|
||||
# here so that it isn't caught below and handled
|
||||
# as if the CIDR is already in use.
|
||||
LOG.exception(_("adding subnet to router failed"))
|
||||
self._delete_subnet(context._plugin_context, subnet['id'])
|
||||
raise exc.GroupPolicyInternalError()
|
||||
except n_exc.BadRequest:
|
||||
except neutron_client_exc.BadRequest:
|
||||
# This is expected (CIDR overlap) until we have a
|
||||
# proper subnet allocation algorithm. We ignore the
|
||||
# exception and repeat with the next CIDR.
|
||||
pass
|
||||
|
||||
raise exc.NoSubnetAvailable()
|
||||
|
||||
def _validate_subnet_overlap_for_l3p(self, subnets, subnet_cidr):
|
||||
|
@ -1208,14 +1205,13 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
# This method sets up the attributes of security group
|
||||
attrs = {'tenant_id': context.current['tenant_id'],
|
||||
'name': sg_name_prefix + '_' + context.current['name'],
|
||||
'description': '',
|
||||
'security_group_rules': ''}
|
||||
'description': ''}
|
||||
sg = self._create_sg(context._plugin_context, attrs)
|
||||
# Cleanup default rules
|
||||
for rule in self._core_plugin.get_security_group_rules(
|
||||
for rule in self._get_sg_rules(
|
||||
context._plugin_context,
|
||||
filters={'security_group_id': [sg['id']]}):
|
||||
self._core_plugin.delete_security_group_rule(
|
||||
self._delete_sg_rule(
|
||||
context._plugin_context, rule['id'])
|
||||
return sg
|
||||
|
||||
|
@ -1388,142 +1384,43 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
def _cleanup_redirect_action(self, context):
|
||||
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.
|
||||
#
|
||||
# REVISIT(rkukura): Can we just use the WSGI Controller? Using
|
||||
# neutronclient is also a possibility, but presents significant
|
||||
# issues to unit testing as well as overhead and failure modes.
|
||||
|
||||
def _create_port(self, plugin_context, attrs):
|
||||
return self._create_resource(self._core_plugin, plugin_context, 'port',
|
||||
attrs)
|
||||
|
||||
def _update_port(self, plugin_context, port_id, attrs):
|
||||
return self._update_resource(self._core_plugin, plugin_context, 'port',
|
||||
port_id, attrs)
|
||||
|
||||
def _delete_port(self, plugin_context, port_id):
|
||||
self._delete_resource(self._core_plugin,
|
||||
plugin_context, 'port', port_id)
|
||||
|
||||
def _create_subnet(self, plugin_context, attrs):
|
||||
return self._create_resource(self._core_plugin, plugin_context,
|
||||
'subnet', attrs)
|
||||
|
||||
def _update_subnet(self, plugin_context, subnet_id, attrs):
|
||||
return self._update_resource(self._core_plugin, plugin_context,
|
||||
'subnet', subnet_id, attrs)
|
||||
|
||||
def _delete_subnet(self, plugin_context, subnet_id):
|
||||
self._delete_resource(self._core_plugin, plugin_context, 'subnet',
|
||||
subnet_id)
|
||||
|
||||
def _create_network(self, plugin_context, attrs):
|
||||
return self._create_resource(self._core_plugin, plugin_context,
|
||||
'network', attrs)
|
||||
|
||||
def _delete_network(self, plugin_context, network_id):
|
||||
self._delete_resource(self._core_plugin, plugin_context,
|
||||
'network', network_id)
|
||||
|
||||
def _create_router(self, plugin_context, attrs):
|
||||
return self._create_resource(self._l3_plugin, plugin_context, 'router',
|
||||
attrs)
|
||||
|
||||
def _update_router(self, plugin_context, router_id, attrs):
|
||||
return self._update_resource(self._l3_plugin, plugin_context, 'router',
|
||||
router_id, attrs)
|
||||
|
||||
def _add_router_interface(self, plugin_context, router_id, interface_info):
|
||||
self._l3_plugin.add_router_interface(plugin_context,
|
||||
router_id, interface_info)
|
||||
|
||||
def _remove_router_interface(self, plugin_context, router_id,
|
||||
interface_info):
|
||||
self._l3_plugin.remove_router_interface(plugin_context, router_id,
|
||||
interface_info)
|
||||
|
||||
def _add_router_gw_interface(self, plugin_context, router_id, gw_info):
|
||||
return self._l3_plugin.update_router(
|
||||
plugin_context, router_id,
|
||||
{'router': {'external_gateway_info': gw_info}})
|
||||
|
||||
def _remove_router_gw_interface(self, plugin_context, router_id,
|
||||
interface_info):
|
||||
self._l3_plugin.update_router(
|
||||
plugin_context, router_id,
|
||||
{'router': {'external_gateway_info': None}})
|
||||
|
||||
def _delete_router(self, plugin_context, router_id):
|
||||
self._delete_resource(self._l3_plugin, plugin_context, 'router',
|
||||
router_id)
|
||||
|
||||
def _create_sg(self, plugin_context, attrs):
|
||||
return self._create_resource(self._core_plugin, plugin_context,
|
||||
'security_group', attrs)
|
||||
|
||||
def _update_sg(self, plugin_context, sg_id, attrs):
|
||||
return self._update_resouce(self._core_plugin, plugin_context,
|
||||
'security_group', sg_id, attrs)
|
||||
|
||||
def _delete_sg(self, plugin_context, sg_id):
|
||||
self._delete_resource(self._core_plugin, plugin_context,
|
||||
'security_group', sg_id)
|
||||
|
||||
def _create_sg_rule(self, plugin_context, attrs):
|
||||
try:
|
||||
return self._create_resource(self._core_plugin, plugin_context,
|
||||
'security_group_rule', attrs)
|
||||
except ext_sg.SecurityGroupRuleExists as ex:
|
||||
LOG.warn(_('Security Group already exists %s'), ex.message)
|
||||
return
|
||||
|
||||
def _update_sg_rule(self, plugin_context, sg_rule_id, attrs):
|
||||
return self._update_resource(self._core_plugin, plugin_context,
|
||||
'security_group_rule', sg_rule_id,
|
||||
attrs)
|
||||
|
||||
def _delete_sg_rule(self, plugin_context, sg_rule_id):
|
||||
self._delete_resource(self._core_plugin, plugin_context,
|
||||
'security_group_rule', sg_rule_id)
|
||||
context, ptg_chain.servicechain_instance_id)
|
||||
|
||||
def _restore_ip_to_allocation_pool(self, context, subnet_id, ip_address):
|
||||
# TODO(Magesh):Pass subnets and loop on subnets. Better to add logic
|
||||
# to Merge the pools together after Fragmentation
|
||||
subnet = self._core_plugin.get_subnet(context._plugin_context,
|
||||
subnet_id)
|
||||
subnet = self._get_subnet(context._plugin_context, subnet_id)
|
||||
allocation_pools = subnet['allocation_pools']
|
||||
for allocation_pool in allocation_pools:
|
||||
pool_end_ip = allocation_pool.get('end')
|
||||
if ip_address == str(netaddr.IPAddress(pool_end_ip) + 1):
|
||||
new_last_ip = ip_address
|
||||
allocation_pool['end'] = new_last_ip
|
||||
del subnet['gateway_ip']
|
||||
subnet = self._update_subnet(context._plugin_context,
|
||||
subnet['id'], subnet)
|
||||
subnet_update = {'gateway_ip': None}
|
||||
subnet_update['allocation_pools'] = allocation_pools
|
||||
self._update_subnet(context._plugin_context,
|
||||
subnet['id'], subnet_update)
|
||||
return
|
||||
# TODO(Magesh):Have to test this logic. Add proper unit tests
|
||||
subnet['allocation_pools'].append({"start": ip_address,
|
||||
"end": ip_address})
|
||||
del subnet['gateway_ip']
|
||||
subnet = self._update_subnet(context._plugin_context,
|
||||
subnet['id'], subnet)
|
||||
subnet_update = {'gateway_ip': None}
|
||||
subnet_update['allocation_pools'] = subnet['allocation_pools']
|
||||
self._update_subnet(context._plugin_context,
|
||||
subnet['id'], subnet_update)
|
||||
|
||||
def _remove_ip_from_allocation_pool(self, context, subnet_id, ip_address):
|
||||
# TODO(Magesh):Pass subnets and loop on subnets
|
||||
subnet = self._core_plugin.get_subnet(context._plugin_context,
|
||||
subnet_id)
|
||||
subnet = self._get_subnet(context._plugin_context, subnet_id)
|
||||
allocation_pools = subnet['allocation_pools']
|
||||
for allocation_pool in reversed(allocation_pools):
|
||||
if ip_address == allocation_pool.get('end'):
|
||||
new_last_ip = str(netaddr.IPAddress(ip_address) - 1)
|
||||
allocation_pool['end'] = new_last_ip
|
||||
del subnet['gateway_ip']
|
||||
subnet_update = {'gateway_ip': None}
|
||||
subnet_update['allocation_pools'] = allocation_pools
|
||||
self._update_subnet(context._plugin_context,
|
||||
subnet['id'], subnet)
|
||||
subnet['id'], subnet_update)
|
||||
break
|
||||
|
||||
def _get_last_free_ip(self, context, subnets):
|
||||
|
@ -1759,12 +1656,15 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
value = attrs[key]
|
||||
if value:
|
||||
filters[key] = [value]
|
||||
rule = self._core_plugin.get_security_group_rules(
|
||||
rule = self._get_sg_rules(
|
||||
plugin_context, filters)
|
||||
if rule:
|
||||
self._delete_sg_rule(plugin_context, rule[0]['id'])
|
||||
else:
|
||||
return self._create_sg_rule(plugin_context, attrs)
|
||||
try:
|
||||
return self._create_sg_rule(plugin_context, attrs)
|
||||
except neutron_client_exc.Conflict:
|
||||
LOG.warn(_('Security Group Rule already exists'))
|
||||
|
||||
def _sg_ingress_rule(self, context, sg_id, protocol, port_range, cidr,
|
||||
unset=False):
|
||||
|
@ -1781,11 +1681,11 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
def _assoc_sgs_to_pt(self, context, pt_id, sg_list):
|
||||
pt = context._plugin.get_policy_target(context._plugin_context, pt_id)
|
||||
port_id = pt['port_id']
|
||||
port = self._core_plugin.get_port(context._plugin_context, port_id)
|
||||
port = self._get_port(context._plugin_context, port_id)
|
||||
cur_sg_list = port[ext_sg.SECURITYGROUPS]
|
||||
new_sg_list = cur_sg_list + sg_list
|
||||
port[ext_sg.SECURITYGROUPS] = new_sg_list
|
||||
self._update_port(context._plugin_context, port_id, port)
|
||||
port_update = {ext_sg.SECURITYGROUPS: new_sg_list}
|
||||
self._update_port(context._plugin_context, port_id, port_update)
|
||||
|
||||
def _disassoc_sgs_from_pt(self, context, pt_id, sg_list):
|
||||
pt = context._plugin.get_policy_target(context._plugin_context, pt_id)
|
||||
|
@ -1794,12 +1694,12 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
|
||||
def _disassoc_sgs_from_port(self, plugin_context, port_id, sg_list):
|
||||
try:
|
||||
port = self._core_plugin.get_port(plugin_context, port_id)
|
||||
port = self._get_port(plugin_context, port_id)
|
||||
cur_sg_list = port[ext_sg.SECURITYGROUPS]
|
||||
new_sg_list = list(set(cur_sg_list) - set(sg_list))
|
||||
port[ext_sg.SECURITYGROUPS] = new_sg_list
|
||||
self._update_port(plugin_context, port_id, port)
|
||||
except n_exc.PortNotFound:
|
||||
port_update = {ext_sg.SECURITYGROUPS: new_sg_list}
|
||||
self._update_port(plugin_context, port_id, port_update)
|
||||
except neutron_client_exc.NotFound:
|
||||
LOG.warn(_("Port %s is missing") % port_id)
|
||||
|
||||
def _generate_list_of_sg_from_ptg(self, context, ptg_id):
|
||||
|
@ -1860,8 +1760,7 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
|
||||
cidr_list = []
|
||||
for subnet_id in subnets:
|
||||
subnet = self._core_plugin.get_subnet(context._plugin_context,
|
||||
subnet_id)
|
||||
subnet = self._get_subnet(context._plugin_context, subnet_id)
|
||||
cidr = subnet['cidr']
|
||||
cidr_list.append(cidr)
|
||||
self._set_or_unset_rules_for_cidrs(
|
||||
|
@ -2015,7 +1914,7 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
tenant_id):
|
||||
port_name = 'gbp_%s' % ptg_id
|
||||
filters = {'name': [port_name], 'tenant_id': [tenant_id]}
|
||||
default_group = self._core_plugin.get_security_groups(
|
||||
default_group = self._get_sgs(
|
||||
plugin_context, filters)
|
||||
return default_group[0]['id'] if default_group else None
|
||||
|
||||
|
@ -2031,7 +1930,7 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
'description': 'default'}
|
||||
sg_id = self._create_sg(plugin_context, attrs)['id']
|
||||
|
||||
for subnet in self._core_plugin.get_subnets(
|
||||
for subnet in self._get_subnets(
|
||||
plugin_context, filters={'id': subnets or []}):
|
||||
self._sg_rule(plugin_context, tenant_id, sg_id,
|
||||
'ingress', cidr=subnet['cidr'],
|
||||
|
@ -2058,7 +1957,7 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
ptgs = context._plugin.get_policy_target_groups(
|
||||
context._plugin_context, filters={'id': ptgs})
|
||||
for ptg in ptgs:
|
||||
cidrs.extend([self._core_plugin.get_subnet(
|
||||
cidrs.extend([self._get_subnet(
|
||||
context._plugin_context, x)['cidr'] for x in ptg['subnets']])
|
||||
return cidrs
|
||||
|
||||
|
@ -2145,7 +2044,7 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
l3ps = context._plugin.get_l3_policies(
|
||||
admin_context, filters={'id': context.current['l3_policies']})
|
||||
for l3p in l3ps:
|
||||
router = self._l3_plugin.get_routes(
|
||||
router = self._get_router(
|
||||
admin_context, l3p['router_id'])
|
||||
current_routes = set((x['destination'], x['nexthop']) for x in
|
||||
router['routes'])
|
||||
|
@ -2219,8 +2118,7 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
l2p_id)
|
||||
# Validate explicit subnet belongs to L2P's network
|
||||
network_id = l2p['network_id']
|
||||
network = self._core_plugin.get_network(context._plugin_context,
|
||||
network_id)
|
||||
network = self._get_network(context._plugin_context, network_id)
|
||||
for subnet_id in subnets or context.current['subnets']:
|
||||
if subnet_id not in network['subnets']:
|
||||
raise exc.InvalidSubnetForPTG(subnet_id=subnet_id,
|
||||
|
@ -2255,8 +2153,7 @@ class ResourceMappingDriver(api.PolicyDriver):
|
|||
# Validate if explicit port's subnet
|
||||
# is same as the subnet of PTG.
|
||||
port_id = context.current['port_id']
|
||||
core_plugin = self._core_plugin
|
||||
port = core_plugin.get_port(context._plugin_context, port_id)
|
||||
port = self._get_port(context._plugin_context, port_id)
|
||||
|
||||
port_subnet_id = None
|
||||
fixed_ips = port['fixed_ips']
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"regular_user": "",
|
||||
"default": "rule:admin_or_owner",
|
||||
"gbp_shared": "field:policy_target_groups:shared=True",
|
||||
"neutron_shared": "field:networks:shared=True",
|
||||
|
||||
"create_policy_target_group": "",
|
||||
"get_policy_target_group": "rule:admin_or_owner or rule:gbp_shared",
|
||||
|
@ -48,5 +49,11 @@
|
|||
|
||||
"gbp_nat_pool_shared": "field:nat_pools:shared=True",
|
||||
"create_nat_pool": "",
|
||||
"get_nat_pool": "rule:admin_or_owner or rule:gbp_nat_pool_shared"
|
||||
"get_nat_pool": "rule:admin_or_owner or rule:gbp_nat_pool_shared",
|
||||
|
||||
"create_network": "",
|
||||
"get_network": "rule:admin_or_owner or rule:neutron_shared",
|
||||
|
||||
"create_subnet": "",
|
||||
"get_subnet": "rule:admin_or_owner or rule:neutron_shared"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
# 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.
|
||||
|
||||
import mock
|
||||
|
||||
from neutronclient.common import exceptions as neutron_client_exc
|
||||
|
||||
from gbpservice.neutron.services.grouppolicy.drivers import (
|
||||
neutron_api_mixin as nm)
|
||||
from gbpservice.neutron.services.grouppolicy.drivers import resource_mapping
|
||||
from gbpservice.neutron.tests.unit import common as cm
|
||||
|
||||
|
||||
# Based on the resource types, Neutron REST API calls need to be patched to
|
||||
# different neutron-plugins.
|
||||
PLUGIN_MAP = {
|
||||
'network': '_core_plugin',
|
||||
'subnet': '_core_plugin',
|
||||
'port': '_core_plugin',
|
||||
'security_group': '_core_plugin',
|
||||
'security_group_rule': '_core_plugin',
|
||||
'router': '_l3_plugin',
|
||||
}
|
||||
|
||||
# Based on the resource types, WSGI calls need to be patched to
|
||||
# different APIs.
|
||||
API_MAP = {
|
||||
'network': 'api',
|
||||
'subnet': 'api',
|
||||
'port': 'api',
|
||||
'security_group': 'ext_api',
|
||||
'security_group_rule': 'ext_api',
|
||||
'router': 'ext_api',
|
||||
|
||||
}
|
||||
|
||||
|
||||
# security-groups and security-group-rules appear in WSGI resource,
|
||||
# but security_groups and security_group_rules appear in request body.
|
||||
def _replace_sg_underscore(resources):
|
||||
return resources.replace('_', '-') if (
|
||||
'security_group' in resources) else resources
|
||||
|
||||
|
||||
class Neutronv2MockMixin(object):
|
||||
""" A mixin class to mock Neutron REST APIs with WSGI calls.
|
||||
|
||||
The _*_resource APIs defined in neutron_api_mixin.NeutronAPIMixin are
|
||||
patched here.
|
||||
"""
|
||||
|
||||
def _setUp_mock(self):
|
||||
mock_create = mock.patch.object(resource_mapping.ResourceMappingDriver,
|
||||
'_create_neutron_resource',
|
||||
autospec=True).start()
|
||||
mock_create.side_effect = self._patched_create_resource
|
||||
mock_show = mock.patch.object(resource_mapping.ResourceMappingDriver,
|
||||
'_get_neutron_resource',
|
||||
autospec=True).start()
|
||||
mock_show.side_effect = self._patched_get_resource
|
||||
mock_list = mock.patch.object(resource_mapping.ResourceMappingDriver,
|
||||
'_get_neutron_resources',
|
||||
autospec=True).start()
|
||||
mock_list.side_effect = self._patched_get_resources
|
||||
mock_update = mock.patch.object(resource_mapping.ResourceMappingDriver,
|
||||
'_update_neutron_resource',
|
||||
autospec=True).start()
|
||||
mock_update.side_effect = self._patched_update_resource
|
||||
mock_delete = mock.patch.object(resource_mapping.ResourceMappingDriver,
|
||||
'_delete_neutron_resource',
|
||||
autospec=True).start()
|
||||
mock_delete.side_effect = self._patched_delete_resource
|
||||
mock_add = mock.patch.object(resource_mapping.ResourceMappingDriver,
|
||||
'_add_router_interface',
|
||||
autospec=True).start()
|
||||
mock_add.side_effect = self._patched_add_router_interface
|
||||
mock_remove = mock.patch.object(resource_mapping.ResourceMappingDriver,
|
||||
'_remove_router_interface',
|
||||
autospec=True).start()
|
||||
mock_remove.side_effect = self._patched_remove_router_interface
|
||||
|
||||
def _wsgi_req(self, req, api, context, return_flag=True):
|
||||
req.environ['neutron.context'] = context
|
||||
ret = req.get_response(api)
|
||||
if ret.status_int >= neutron_client_exc.BadRequest.status_code:
|
||||
raise neutron_client_exc.HTTP_EXCEPTION_MAP.get(ret.status_int)
|
||||
if return_flag:
|
||||
return self.deserialize(self.fmt, ret)
|
||||
|
||||
def _patched_create_resource(self, obj, context, resource, attrs):
|
||||
resources = _replace_sg_underscore(cm.get_resource_plural(resource))
|
||||
data = {resource: attrs}
|
||||
api = getattr(self, API_MAP[resource])
|
||||
req = self.new_create_request(resources, data, self.fmt)
|
||||
return self._wsgi_req(req, api, context)[resource]
|
||||
|
||||
def _patched_get_resource(self, obj, context, resource, resource_id):
|
||||
resources = _replace_sg_underscore(cm.get_resource_plural(resource))
|
||||
api = getattr(self, API_MAP[resource])
|
||||
req = self.new_show_request(resources, resource_id)
|
||||
return self._wsgi_req(req, api, context)[resource]
|
||||
|
||||
def _patched_get_resources(self, obj, context, resource, filters={}):
|
||||
resources = cm.get_resource_plural(resource)
|
||||
formatted_resources = _replace_sg_underscore(resources)
|
||||
api = getattr(self, API_MAP[resource])
|
||||
filter_list = nm.get_filter_combinations(filters)
|
||||
|
||||
res = []
|
||||
for filter in filter_list:
|
||||
params = None
|
||||
if filter:
|
||||
param_list = []
|
||||
for key, value in filter.iteritems():
|
||||
# REVISIT(yi): need to replace equal sign = with %3D if
|
||||
# present in value
|
||||
param_list.append("%s=%s" % (key, value))
|
||||
params = '&'.join(param_list)
|
||||
|
||||
req = self.new_list_request(formatted_resources, self.fmt, params)
|
||||
obj = self._wsgi_req(req, api, context)[resources]
|
||||
res.extend(x for x in obj if x not in res)
|
||||
return res
|
||||
|
||||
def _patched_update_resource(self, obj, context,
|
||||
resource, resource_id, attrs):
|
||||
resources = _replace_sg_underscore(cm.get_resource_plural(resource))
|
||||
data = {resource: attrs}
|
||||
api = getattr(self, API_MAP[resource])
|
||||
req = self.new_update_request(resources, data, resource_id, self.fmt)
|
||||
return self._wsgi_req(req, api, context)[resource]
|
||||
|
||||
def _patched_delete_resource(self, obj, context, resource, resource_id):
|
||||
resources = _replace_sg_underscore(cm.get_resource_plural(resource))
|
||||
api = getattr(self, API_MAP[resource])
|
||||
req = self.new_delete_request(resources, resource_id)
|
||||
self._wsgi_req(req, api, context, False)
|
||||
|
||||
def _patched_add_router_interface(
|
||||
self, obj, context, router_id, interface):
|
||||
req = self.new_action_request(
|
||||
'routers', interface, router_id, 'add_router_interface')
|
||||
return self._wsgi_req(req, self.ext_api, context)
|
||||
|
||||
def _patched_remove_router_interface(
|
||||
self, obj, context, router_id, interface):
|
||||
req = self.new_action_request(
|
||||
'routers', interface, router_id, 'remove_router_interface')
|
||||
return self._wsgi_req(req, self.ext_api, context)
|
|
@ -33,6 +33,8 @@ sys.modules["apicapi"] = mock.Mock()
|
|||
from gbpservice.neutron.services.grouppolicy import config
|
||||
from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import (
|
||||
apic_mapping as amap)
|
||||
from gbpservice.neutron.tests.unit.services.grouppolicy import (
|
||||
mock_neutronv2_api as mock_neutron)
|
||||
from gbpservice.neutron.tests.unit.services.grouppolicy import (
|
||||
test_grouppolicy_plugin as test_gp_plugin)
|
||||
|
||||
|
@ -70,7 +72,8 @@ class MockCallRecorder(mock.Mock):
|
|||
|
||||
class ApicMappingTestCase(
|
||||
test_gp_plugin.GroupPolicyPluginTestCase,
|
||||
mocked.ControllerMixin, mocked.ConfigMixin):
|
||||
mocked.ControllerMixin, mocked.ConfigMixin,
|
||||
mock_neutron.Neutronv2MockMixin):
|
||||
|
||||
def setUp(self):
|
||||
config.cfg.CONF.set_override('policy_drivers',
|
||||
|
@ -109,6 +112,7 @@ class ApicMappingTestCase(
|
|||
self.driver.apic_manager.apic.transaction = self.fake_transaction
|
||||
amap.apic_manager.TENANT_COMMON = 'common'
|
||||
self.common_tenant = amap.apic_manager.TENANT_COMMON
|
||||
self._setUp_mock()
|
||||
|
||||
def _get_object(self, type, id, api):
|
||||
req = self.new_show_request(type, id, self.fmt)
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
|
||||
import contextlib
|
||||
import itertools
|
||||
import mock
|
||||
import netaddr
|
||||
|
||||
import mock
|
||||
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
|
||||
from neutron.common import constants as cst
|
||||
from neutron import context as nctx
|
||||
|
@ -37,9 +37,14 @@ from gbpservice.neutron.services.grouppolicy.common import constants as gconst
|
|||
from gbpservice.neutron.services.grouppolicy import config
|
||||
from gbpservice.neutron.services.grouppolicy.drivers import resource_mapping
|
||||
from gbpservice.neutron.services.servicechain import config as sc_cfg
|
||||
from gbpservice.neutron.tests.unit.services.grouppolicy import (
|
||||
mock_neutronv2_api as mock_neutron)
|
||||
from gbpservice.neutron.tests.unit.services.grouppolicy import (
|
||||
test_grouppolicy_plugin as test_plugin)
|
||||
|
||||
|
||||
CORE_PLUGIN = ('gbpservice.neutron.tests.unit.services.grouppolicy.'
|
||||
'test_resource_mapping.NoL3NatSGTestPlugin')
|
||||
SERVICECHAIN_NODES = 'servicechain/servicechain_nodes'
|
||||
SERVICECHAIN_SPECS = 'servicechain/servicechain_specs'
|
||||
SERVICECHAIN_INSTANCES = 'servicechain/servicechain_instances'
|
||||
|
@ -52,11 +57,8 @@ class NoL3NatSGTestPlugin(
|
|||
supported_extension_aliases = ["external-net", "security-group"]
|
||||
|
||||
|
||||
CORE_PLUGIN = ('gbpservice.neutron.tests.unit.services.grouppolicy.'
|
||||
'test_resource_mapping.NoL3NatSGTestPlugin')
|
||||
|
||||
|
||||
class ResourceMappingTestCase(test_plugin.GroupPolicyPluginTestCase):
|
||||
class ResourceMappingTestCase(test_plugin.GroupPolicyPluginTestCase,
|
||||
mock_neutron.Neutronv2MockMixin):
|
||||
|
||||
def setUp(self, policy_drivers=None):
|
||||
policy_drivers = policy_drivers or ['implicit_policy',
|
||||
|
@ -78,6 +80,7 @@ class ResourceMappingTestCase(test_plugin.GroupPolicyPluginTestCase):
|
|||
self._context = nctx.get_admin_context()
|
||||
plugins = manager.NeutronManager.get_service_plugins()
|
||||
self._gbp_plugin = plugins.get(pconst.GROUP_POLICY)
|
||||
self._setUp_mock()
|
||||
|
||||
def get_plugin_context(self):
|
||||
return self._plugin, self._context
|
||||
|
@ -2731,4 +2734,4 @@ class TestNetworkServicePolicy(ResourceMappingTestCase):
|
|||
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)
|
||||
initial_allocation_pool, allocation_pool_after_nsp_cleanup)
|
||||
|
|
Loading…
Reference in New Issue