Improve packet-filter test coverage in NEC Plugin

blueprint nec-plugin-test-coverage

This commit adds unit tests for packet-filter in NEC Plugin.

This commit refactors packet-filter in NEC Plugin.
- Put packet-filter classes and methods into nec/packet_filter.py (a) and
  nec/db/packetfilter.py (b), NEC Plugin specific codes are in (a)
- Change stateless methods to class methods in extenstions/packetfilter.py
- Add 'convert_to' option to the attribute map of packet-filter to convert
  some string parameter to int at the api layer

Also, this commit includes the following changes in packet-filter.
- Fix attribute map of packet-filter; set in_port to allow_put=False
- Add new methods to update attribute map properly
- Make packet-filters ignore status of associated resource (network)

Change-Id: I7c0b76afb603f1f078b28610181b16ce66225d37
This commit is contained in:
Ryota MIBU 2013-07-09 17:18:10 +09:00
parent 3ba25fa060
commit 0043044f2e
8 changed files with 754 additions and 352 deletions

View File

@ -33,7 +33,3 @@ class OFCConsistencyBroken(qexc.NeutronException):
class PortInfoNotFound(qexc.NotFound):
message = _("PortInfo %(id)s could not be found")
class PacketFilterNotFound(qexc.NotFound):
message = _("PacketFilter %(id)s could not be found")

View File

@ -80,26 +80,3 @@ class PortInfo(model_base.BASEV2, models_v2.HasId):
port_no = sa.Column(sa.Integer, nullable=False)
vlan_id = sa.Column(sa.Integer, nullable=False)
mac = sa.Column(sa.String(32), nullable=False)
class PacketFilter(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
"""Represents a packet filter."""
name = sa.Column(sa.String(255))
network_id = sa.Column(sa.String(36),
sa.ForeignKey('networks.id', ondelete="CASCADE"),
nullable=False)
priority = sa.Column(sa.Integer, nullable=False)
action = sa.Column(sa.String(16), nullable=False)
# condition
in_port = sa.Column(sa.String(36), nullable=False)
src_mac = sa.Column(sa.String(32), nullable=False)
dst_mac = sa.Column(sa.String(32), nullable=False)
eth_type = sa.Column(sa.Integer, nullable=False)
src_cidr = sa.Column(sa.String(64), nullable=False)
dst_cidr = sa.Column(sa.String(64), nullable=False)
protocol = sa.Column(sa.String(16), nullable=False)
src_port = sa.Column(sa.Integer, nullable=False)
dst_port = sa.Column(sa.Integer, nullable=False)
# status
admin_state_up = sa.Column(sa.Boolean(), nullable=False)
status = sa.Column(sa.String(16), nullable=False)

View File

@ -1,121 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 NEC Corporation. All rights reserved.
#
# 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.
# @author: Ryota MIBU
from sqlalchemy.orm import exc
from neutron.api.v2 import attributes
from neutron.db import db_base_plugin_v2
from neutron.openstack.common import log as logging
from neutron.openstack.common import uuidutils
from neutron.plugins.nec.common import exceptions as q_exc
from neutron.plugins.nec.db import models as nmodels
LOG = logging.getLogger(__name__)
class NECPluginV2Base(db_base_plugin_v2.NeutronDbPluginV2):
"""Base class of plugins that handle packet filters."""
def _make_packet_filter_dict(self, packet_filter, fields=None):
res = {'id': packet_filter['id'],
'name': packet_filter['name'],
'tenant_id': packet_filter['tenant_id'],
'network_id': packet_filter['network_id'],
'action': packet_filter['action'],
'priority': packet_filter['priority'],
'in_port': packet_filter['in_port'],
'src_mac': packet_filter['src_mac'],
'dst_mac': packet_filter['dst_mac'],
'eth_type': packet_filter['eth_type'],
'src_cidr': packet_filter['src_cidr'],
'dst_cidr': packet_filter['dst_cidr'],
'protocol': packet_filter['protocol'],
'src_port': packet_filter['src_port'],
'dst_port': packet_filter['dst_port'],
'admin_state_up': packet_filter['admin_state_up'],
'status': packet_filter['status']}
return self._fields(res, fields)
def _get_packet_filter(self, context, id):
try:
packet_filter = self._get_by_id(context, nmodels.PacketFilter, id)
except exc.NoResultFound:
raise q_exc.PacketFilterNotFound(id=id)
return packet_filter
def get_packet_filter(self, context, id, fields=None):
packet_filter = self._get_packet_filter(context, id)
return self._make_packet_filter_dict(packet_filter, fields)
def get_packet_filters(self, context, filters=None, fields=None):
return self._get_collection(context,
nmodels.PacketFilter,
self._make_packet_filter_dict,
filters=filters,
fields=fields)
def create_packet_filter(self, context, packet_filter):
pf = packet_filter['packet_filter']
tenant_id = self._get_tenant_id_for_create(context, pf)
# validate network ownership
super(NECPluginV2Base, self).get_network(context, pf['network_id'])
if pf.get('in_port') is not attributes.ATTR_NOT_SPECIFIED:
# validate port ownership
super(NECPluginV2Base, self).get_port(context, pf['in_port'])
params = {'tenant_id': tenant_id,
'id': pf.get('id') or uuidutils.generate_uuid(),
'name': pf['name'],
'network_id': pf['network_id'],
'priority': pf['priority'],
'action': pf['action'],
'admin_state_up': pf.get('admin_state_up', True),
'status': "ACTIVE"}
conditions = {'in_port': '',
'src_mac': '',
'dst_mac': '',
'eth_type': 0,
'src_cidr': '',
'dst_cidr': '',
'src_port': 0,
'dst_port': 0,
'protocol': ''}
for key, default in conditions.items():
if pf.get(key) is attributes.ATTR_NOT_SPECIFIED:
params.update({key: default})
else:
params.update({key: pf.get(key)})
with context.session.begin(subtransactions=True):
pf_entry = nmodels.PacketFilter(**params)
context.session.add(pf_entry)
return self._make_packet_filter_dict(pf_entry)
def update_packet_filter(self, context, id, packet_filter):
pf = packet_filter['packet_filter']
with context.session.begin(subtransactions=True):
pf_entry = self._get_packet_filter(context, id)
pf_entry.update(pf)
return self._make_packet_filter_dict(pf_entry)
def delete_packet_filter(self, context, id):
with context.session.begin(subtransactions=True):
packet_filter = self._get_packet_filter(context, id)
context.session.delete(packet_filter)

View File

@ -0,0 +1,148 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012-2013 NEC Corporation. All rights reserved.
#
# 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.
# @author: Ryota MIBU
import sqlalchemy as sa
from sqlalchemy.orm import exc as sa_exc
from neutron.api.v2 import attributes
from neutron.common import exceptions
from neutron.db import model_base
from neutron.db import models_v2
from neutron.openstack.common import uuidutils
PF_STATUS_ACTIVE = 'ACTIVE'
PF_STATUS_DOWN = 'DOWN'
PF_STATUS_ERROR = 'ERROR'
class PacketFilterNotFound(exceptions.NotFound):
message = _("PacketFilter %(id)s could not be found")
class PacketFilter(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
"""Represents a packet filter."""
name = sa.Column(sa.String(255))
network_id = sa.Column(sa.String(36),
sa.ForeignKey('networks.id', ondelete="CASCADE"),
nullable=False)
priority = sa.Column(sa.Integer, nullable=False)
action = sa.Column(sa.String(16), nullable=False)
# condition
in_port = sa.Column(sa.String(36), nullable=False)
src_mac = sa.Column(sa.String(32), nullable=False)
dst_mac = sa.Column(sa.String(32), nullable=False)
eth_type = sa.Column(sa.Integer, nullable=False)
src_cidr = sa.Column(sa.String(64), nullable=False)
dst_cidr = sa.Column(sa.String(64), nullable=False)
protocol = sa.Column(sa.String(16), nullable=False)
src_port = sa.Column(sa.Integer, nullable=False)
dst_port = sa.Column(sa.Integer, nullable=False)
# status
admin_state_up = sa.Column(sa.Boolean(), nullable=False)
status = sa.Column(sa.String(16), nullable=False)
class PacketFilterDbMixin(object):
def _make_packet_filter_dict(self, pf_entry, fields=None):
res = {'id': pf_entry['id'],
'name': pf_entry['name'],
'tenant_id': pf_entry['tenant_id'],
'network_id': pf_entry['network_id'],
'action': pf_entry['action'],
'priority': pf_entry['priority'],
'in_port': pf_entry['in_port'],
'src_mac': pf_entry['src_mac'],
'dst_mac': pf_entry['dst_mac'],
'eth_type': pf_entry['eth_type'],
'src_cidr': pf_entry['src_cidr'],
'dst_cidr': pf_entry['dst_cidr'],
'protocol': pf_entry['protocol'],
'src_port': pf_entry['src_port'],
'dst_port': pf_entry['dst_port'],
'admin_state_up': pf_entry['admin_state_up'],
'status': pf_entry['status']}
return self._fields(res, fields)
def _get_packet_filter(self, context, id):
try:
pf_entry = self._get_by_id(context, PacketFilter, id)
except sa_exc.NoResultFound:
raise PacketFilterNotFound(id=id)
return pf_entry
def get_packet_filter(self, context, id, fields=None):
pf_entry = self._get_packet_filter(context, id)
return self._make_packet_filter_dict(pf_entry, fields)
def get_packet_filters(self, context, filters=None, fields=None):
return self._get_collection(context,
PacketFilter,
self._make_packet_filter_dict,
filters=filters,
fields=fields)
def create_packet_filter(self, context, packet_filter):
pf_dict = packet_filter['packet_filter']
tenant_id = self._get_tenant_id_for_create(context, pf_dict)
if pf_dict['in_port'] == attributes.ATTR_NOT_SPECIFIED:
# validate network ownership
self.get_network(context, pf_dict['network_id'])
else:
# validate port ownership
self.get_port(context, pf_dict['in_port'])
params = {'tenant_id': tenant_id,
'id': pf_dict.get('id') or uuidutils.generate_uuid(),
'name': pf_dict['name'],
'network_id': pf_dict['network_id'],
'priority': pf_dict['priority'],
'action': pf_dict['action'],
'admin_state_up': pf_dict.get('admin_state_up', True),
'status': PF_STATUS_DOWN,
'in_port': pf_dict['in_port'],
'src_mac': pf_dict['src_mac'],
'dst_mac': pf_dict['dst_mac'],
'eth_type': pf_dict['eth_type'],
'src_cidr': pf_dict['src_cidr'],
'dst_cidr': pf_dict['dst_cidr'],
'src_port': pf_dict['src_port'],
'dst_port': pf_dict['dst_port'],
'protocol': pf_dict['protocol']}
for key, default in params.items():
if params[key] == attributes.ATTR_NOT_SPECIFIED:
params.update({key: ''})
with context.session.begin(subtransactions=True):
pf_entry = PacketFilter(**params)
context.session.add(pf_entry)
return self._make_packet_filter_dict(pf_entry)
def update_packet_filter(self, context, id, packet_filter):
pf = packet_filter['packet_filter']
with context.session.begin(subtransactions=True):
pf_entry = self._get_packet_filter(context, id)
pf_entry.update(pf)
return self._make_packet_filter_dict(pf_entry)
def delete_packet_filter(self, context, id):
with context.session.begin(subtransactions=True):
pf_entry = self._get_packet_filter(context, id)
context.session.delete(pf_entry)

View File

@ -1,6 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 NEC Corporation.
# Copyright 2012-2013 NEC Corporation.
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -23,6 +23,7 @@ from oslo.config import cfg
from neutron.api import extensions
from neutron.api.v2 import attributes
from neutron.api.v2 import base
from neutron.common import exceptions
from neutron.manager import NeutronManager
from neutron import quota
@ -33,20 +34,36 @@ quota_packet_filter_opts = [
help=_("Number of packet_filters allowed per tenant, "
"-1 for unlimited"))
]
# Register the configuration options
cfg.CONF.register_opts(quota_packet_filter_opts, 'QUOTAS')
PACKET_FILTER_ACTION_REGEX = "(?i)^(allow|accept|drop|deny)$"
PACKET_FILTER_NUMBER_REGEX = "(?i)^(0x[0-9a-fA-F]+|[0-9]+)$"
PACKET_FILTER_PROTOCOL_REGEX = "(?i)^(icmp|tcp|udp|arp|0x[0-9a-fA-F]+|[0-9]+)$"
PACKET_FILTER_ATTR_MAP = {
def convert_to_int(data):
try:
return int(data, 0)
except (ValueError, TypeError):
pass
try:
return int(data)
except (ValueError, TypeError):
msg = _("'%s' is not a integer") % data
raise exceptions.InvalidInput(error_message=msg)
ALIAS = 'packet-filter'
RESOURCE = 'packet_filter'
COLLECTION = 'packet_filters'
PACKET_FILTER_ACTION_REGEX = '(?i)^(allow|accept|drop|deny)$'
PACKET_FILTER_PROTOCOL_REGEX = (
'(?i)^(icmp|tcp|udp|arp|0x[0-9a-fA-F]+|[0-9]+|)$')
PACKET_FILTER_ATTR_PARAMS = {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True},
'name': {'allow_post': True, 'allow_put': True, 'default': '',
'validate': {'type:string': None},
'is_visible': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True},
'network_id': {'allow_post': True, 'allow_put': False,
@ -62,9 +79,9 @@ PACKET_FILTER_ATTR_MAP = {
'validate': {'type:regex': PACKET_FILTER_ACTION_REGEX},
'is_visible': True},
'priority': {'allow_post': True, 'allow_put': True,
'validate': {'type:regex': PACKET_FILTER_NUMBER_REGEX},
'convert_to': convert_to_int,
'is_visible': True},
'in_port': {'allow_post': True, 'allow_put': True,
'in_port': {'allow_post': True, 'allow_put': False,
'default': attributes.ATTR_NOT_SPECIFIED,
'validate': {'type:uuid': None},
'is_visible': True},
@ -78,7 +95,7 @@ PACKET_FILTER_ATTR_MAP = {
'is_visible': True},
'eth_type': {'allow_post': True, 'allow_put': True,
'default': attributes.ATTR_NOT_SPECIFIED,
'validate': {'type:regex': PACKET_FILTER_NUMBER_REGEX},
'convert_to': convert_to_int,
'is_visible': True},
'src_cidr': {'allow_post': True, 'allow_put': True,
'default': attributes.ATTR_NOT_SPECIFIED,
@ -94,40 +111,58 @@ PACKET_FILTER_ATTR_MAP = {
'is_visible': True},
'src_port': {'allow_post': True, 'allow_put': True,
'default': attributes.ATTR_NOT_SPECIFIED,
'validate': {'type:regex': PACKET_FILTER_NUMBER_REGEX},
'convert_to': convert_to_int,
'is_visible': True},
'dst_port': {'allow_post': True, 'allow_put': True,
'default': attributes.ATTR_NOT_SPECIFIED,
'validate': {'type:regex': PACKET_FILTER_NUMBER_REGEX},
'convert_to': convert_to_int,
'is_visible': True},
}
PACKET_FILTER_ATTR_MAP = {COLLECTION: PACKET_FILTER_ATTR_PARAMS}
class Packetfilter(extensions.ExtensionDescriptor):
def get_name(self):
return "PacketFilters"
@classmethod
def get_name(cls):
return ALIAS
def get_alias(self):
return "PacketFilters"
@classmethod
def get_alias(cls):
return ALIAS
def get_description(self):
return "PacketFilters"
@classmethod
def get_description(cls):
return "PacketFilters on OFC"
def get_namespace(self):
@classmethod
def get_namespace(cls):
return "http://www.nec.co.jp/api/ext/packet_filter/v2.0"
def get_updated(self):
return "2012-07-24T00:00:00+09:00"
@classmethod
def get_updated(cls):
return "2013-07-16T00:00:00+09:00"
def get_resources(self):
resource = base.create_resource('packet_filters', 'packet_filter',
NeutronManager.get_plugin(),
PACKET_FILTER_ATTR_MAP)
qresource = quota.CountableResource('packet_filter',
@classmethod
def get_resources(cls):
qresource = quota.CountableResource(RESOURCE,
quota._count_resource,
'quota_packet_filter')
'quota_%s' % RESOURCE)
quota.QUOTAS.register_resource(qresource)
return [extensions.ResourceExtension('packet_filters',
resource,
attr_map=PACKET_FILTER_ATTR_MAP)]
resource = base.create_resource(COLLECTION, RESOURCE,
NeutronManager.get_plugin(),
PACKET_FILTER_ATTR_PARAMS)
pf_ext = extensions.ResourceExtension(
COLLECTION, resource, attr_map=PACKET_FILTER_ATTR_PARAMS)
return [pf_ext]
def update_attributes_map(self, attributes):
super(Packetfilter, self).update_attributes_map(
attributes, extension_attrs_map=PACKET_FILTER_ATTR_MAP)
def get_extended_resources(self, version):
if version == "2.0":
return PACKET_FILTER_ATTR_MAP
else:
return {}

View File

@ -1,6 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2012 NEC Corporation. All rights reserved.
# Copyright 2012-2013 NEC Corporation. All rights reserved.
#
# 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
@ -39,8 +39,9 @@ from neutron.openstack.common.rpc import proxy
from neutron.plugins.nec.common import config
from neutron.plugins.nec.common import exceptions as nexc
from neutron.plugins.nec.db import api as ndb
from neutron.plugins.nec.db import nec_plugin_base
from neutron.plugins.nec.db import packetfilter as pf_db
from neutron.plugins.nec import ofc_manager
from neutron.plugins.nec import packet_filter
LOG = logging.getLogger(__name__)
@ -60,12 +61,13 @@ class OperationalStatus:
ERROR = "ERROR"
class NECPluginV2(nec_plugin_base.NECPluginV2Base,
class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
extraroute_db.ExtraRoute_db_mixin,
l3_gwmode_db.L3_NAT_db_mixin,
sg_db_rpc.SecurityGroupServerRpcMixin,
agentschedulers_db.L3AgentSchedulerDbMixin,
agentschedulers_db.DhcpAgentSchedulerDbMixin):
agentschedulers_db.DhcpAgentSchedulerDbMixin,
packet_filter.PacketFilterMixin):
"""NECPluginV2 controls an OpenFlow Controller.
The Neutron NECPluginV2 maps L2 logical networks to L2 virtualized networks
@ -82,13 +84,15 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
"binding", "security-group",
"extraroute", "agent",
"l3_agent_scheduler",
"dhcp_agent_scheduler"]
"dhcp_agent_scheduler",
"packet-filter"]
@property
def supported_extension_aliases(self):
if not hasattr(self, '_aliases'):
aliases = self._supported_extension_aliases[:]
sg_rpc.disable_security_group_extension_if_noop_driver(aliases)
self.remove_packet_filter_extension_if_disabled(aliases)
self._aliases = aliases
return self._aliases
@ -96,11 +100,6 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
ndb.initialize()
self.ofc = ofc_manager.OFCManager()
self.packet_filter_enabled = (config.OFC.enable_packet_filter and
self.ofc.driver.filter_supported())
if self.packet_filter_enabled:
self.supported_extension_aliases.append("PacketFilters")
# Set the plugin default extension path
# if no api_extensions_path is specified.
if not config.CONF.api_extensions_path:
@ -172,14 +171,11 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
if self.packet_filter_enabled:
if port_status is OperationalStatus.ACTIVE:
filters = dict(in_port=[port['id']],
status=[OperationalStatus.DOWN],
status=[pf_db.PF_STATUS_DOWN],
admin_state_up=[True])
pfs = (super(NECPluginV2, self).
get_packet_filters(context, filters=filters))
pfs = self.get_packet_filters(context, filters=filters)
for pf in pfs:
self._activate_packet_filter_if_ready(context, pf,
network=network,
in_port=port)
self.activate_packet_filter_if_ready(context, pf)
if port_status in [OperationalStatus.ACTIVE]:
if self.ofc.exists_ofc_port(context, port['id']):
@ -221,11 +217,10 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
# deactivate packet_filters after the port has deleted from OFC.
if self.packet_filter_enabled:
filters = dict(in_port=[port['id']],
status=[OperationalStatus.ACTIVE])
pfs = super(NECPluginV2, self).get_packet_filters(context,
filters=filters)
status=[pf_db.PF_STATUS_ACTIVE])
pfs = self.get_packet_filters(context, filters=filters)
for pf in pfs:
self._deactivate_packet_filter(context, pf)
self.deactivate_packet_filter(context, pf)
# Quantm Plugin Basic methods
@ -280,32 +275,22 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
if changed and not new_net['admin_state_up']:
self._update_resource_status(context, "network", id,
OperationalStatus.DOWN)
# disable all active ports and packet_filters of the network
# disable all active ports of the network
filters = dict(network_id=[id], status=[OperationalStatus.ACTIVE])
ports = super(NECPluginV2, self).get_ports(context,
filters=filters)
for port in ports:
self.deactivate_port(context, port)
if self.packet_filter_enabled:
pfs = (super(NECPluginV2, self).
get_packet_filters(context, filters=filters))
for pf in pfs:
self._deactivate_packet_filter(context, pf)
elif changed and new_net['admin_state_up']:
self._update_resource_status(context, "network", id,
OperationalStatus.ACTIVE)
# enable ports and packet_filters of the network
# enable ports of the network
filters = dict(network_id=[id], status=[OperationalStatus.DOWN],
admin_state_up=[True])
ports = super(NECPluginV2, self).get_ports(context,
filters=filters)
for port in ports:
self.activate_port_if_ready(context, port, new_net)
if self.packet_filter_enabled:
pfs = (super(NECPluginV2, self).
get_packet_filters(context, filters=filters))
for pf in pfs:
self._activate_packet_filter_if_ready(context, pf, new_net)
return new_net
@ -329,11 +314,12 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
' from OFC: %s'), port)
self.deactivate_port(context, port)
# get packet_filters associated with the network
# delete all packet_filters of the network
if self.packet_filter_enabled:
filters = dict(network_id=[id])
pfs = (super(NECPluginV2, self).
get_packet_filters(context, filters=filters))
pfs = self.get_packet_filters(context, filters=filters)
for pf in pfs:
self.delete_packet_filter(context, pf['id'])
super(NECPluginV2, self).delete_network(context, id)
try:
@ -346,11 +332,6 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
# resources, so this plugin just warns.
LOG.warn(reason)
# delete all packet_filters of the network
if self.packet_filter_enabled:
for pf in pfs:
self.delete_packet_filter(context, pf['id'])
# delete unnessary ofc_tenant
filters = dict(tenant_id=[tenant_id])
nets = super(NECPluginV2, self).get_networks(context, filters=filters)
@ -426,8 +407,7 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
# delete all packet_filters of the port
if self.packet_filter_enabled:
filters = dict(port_id=[id])
pfs = (super(NECPluginV2, self).
get_packet_filters(context, filters=filters))
pfs = self.get_packet_filters(context, filters=filters)
for packet_filter in pfs:
self.delete_packet_filter(context, packet_filter['id'])
@ -456,129 +436,6 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
self._extend_port_dict_binding(context, port)
return [self._fields(port, fields) for port in ports]
# For PacketFilter Extension
def _activate_packet_filter_if_ready(self, context, packet_filter,
network=None, in_port=None):
"""Activate packet_filter by creating filter on OFC if ready.
Conditions to create packet_filter on OFC are:
* packet_filter admin_state is UP
* network admin_state is UP
* (if 'in_port' is specified) portinfo is available
"""
net_id = packet_filter['network_id']
if not network:
network = super(NECPluginV2, self).get_network(context, net_id)
in_port_id = packet_filter.get("in_port")
if in_port_id and not in_port:
in_port = super(NECPluginV2, self).get_port(context, in_port_id)
pf_status = OperationalStatus.ACTIVE
if not packet_filter['admin_state_up']:
LOG.debug(_("_activate_packet_filter_if_ready(): skip, "
"packet_filter.admin_state_up is False."))
pf_status = OperationalStatus.DOWN
elif not network['admin_state_up']:
LOG.debug(_("_activate_packet_filter_if_ready(): skip, "
"network.admin_state_up is False."))
pf_status = OperationalStatus.DOWN
elif in_port_id and in_port_id is in_port.get('id'):
LOG.debug(_("_activate_packet_filter_if_ready(): skip, "
"invalid in_port_id."))
pf_status = OperationalStatus.DOWN
elif in_port_id and not ndb.get_portinfo(context.session, in_port_id):
LOG.debug(_("_activate_packet_filter_if_ready(): skip, "
"no portinfo for in_port."))
pf_status = OperationalStatus.DOWN
if pf_status in [OperationalStatus.ACTIVE]:
if self.ofc.exists_ofc_packet_filter(context, packet_filter['id']):
LOG.debug(_("_activate_packet_filter_if_ready(): skip, "
"ofc_packet_filter already exists."))
else:
try:
(self.ofc.
create_ofc_packet_filter(context,
packet_filter['id'],
packet_filter))
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
reason = _("create_ofc_packet_filter() failed due to "
"%s") % exc
LOG.error(reason)
pf_status = OperationalStatus.ERROR
if pf_status is not packet_filter['status']:
self._update_resource_status(context, "packet_filter",
packet_filter['id'], pf_status)
def _deactivate_packet_filter(self, context, packet_filter):
"""Deactivate packet_filter by deleting filter from OFC if exixts."""
pf_status = OperationalStatus.DOWN
if not self.ofc.exists_ofc_packet_filter(context, packet_filter['id']):
LOG.debug(_("_deactivate_packet_filter(): skip, "
"ofc_packet_filter does not exist."))
else:
try:
self.ofc.delete_ofc_packet_filter(context, packet_filter['id'])
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
reason = _("delete_ofc_packet_filter() failed due to "
"%s") % exc
LOG.error(reason)
pf_status = OperationalStatus.ERROR
if pf_status is not packet_filter['status']:
self._update_resource_status(context, "packet_filter",
packet_filter['id'], pf_status)
def create_packet_filter(self, context, packet_filter):
"""Create a new packet_filter entry on DB, then try to activate it."""
LOG.debug(_("NECPluginV2.create_packet_filter() called, "
"packet_filter=%s ."), packet_filter)
new_pf = super(NECPluginV2, self).create_packet_filter(context,
packet_filter)
self._update_resource_status(context, "packet_filter", new_pf['id'],
OperationalStatus.BUILD)
self._activate_packet_filter_if_ready(context, new_pf)
return new_pf
def update_packet_filter(self, context, id, packet_filter):
"""Update packet_filter entry on DB, and recreate it if changed.
If any rule of the packet_filter was changed, recreate it on OFC.
"""
LOG.debug(_("NECPluginV2.update_packet_filter() called, "
"id=%(id)s packet_filter=%(packet_filter)s ."),
{'id': id, 'packet_filter': packet_filter})
with context.session.begin(subtransactions=True):
old_pf = super(NECPluginV2, self).get_packet_filter(context, id)
new_pf = super(NECPluginV2, self).update_packet_filter(
context, id, packet_filter)
changed = False
exclude_items = ["id", "name", "tenant_id", "network_id", "status"]
for key in new_pf['packet_filter'].keys():
if key not in exclude_items:
if old_pf[key] is not new_pf[key]:
changed = True
break
if changed:
self._deactivate_packet_filter(context, old_pf)
self._activate_packet_filter_if_ready(context, new_pf)
return new_pf
def delete_packet_filter(self, context, id):
"""Deactivate and delete packet_filter."""
LOG.debug(_("NECPluginV2.delete_packet_filter() called, id=%s ."), id)
pf = super(NECPluginV2, self).get_packet_filter(context, id)
self._deactivate_packet_filter(context, pf)
super(NECPluginV2, self).delete_packet_filter(context, id)
class NECPluginV2AgentNotifierApi(proxy.RpcProxy,
sg_rpc.SecurityGroupAgentRpcApiMixin):

View File

@ -0,0 +1,170 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012-2013 NEC Corporation. All rights reserved.
#
# 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.
# @author: Ryota MIBU
from neutron.openstack.common import log as logging
from neutron.plugins.nec.common import config
from neutron.plugins.nec.common import exceptions as nexc
from neutron.plugins.nec.db import api as ndb
from neutron.plugins.nec.db import packetfilter as pf_db
LOG = logging.getLogger(__name__)
class PacketFilterMixin(pf_db.PacketFilterDbMixin):
"""Mixin class to add packet filter to NECPluginV2."""
@property
def packet_filter_enabled(self):
if not hasattr(self, '_packet_filter_enabled'):
self._packet_filter_enabled = (
config.OFC.enable_packet_filter and
self.ofc.driver.filter_supported())
return self._packet_filter_enabled
def remove_packet_filter_extension_if_disabled(self, aliases):
if not self.packet_filter_enabled:
LOG.debug(_('Disabled packet-filter extension.'))
aliases.remove('packet-filter')
def create_packet_filter(self, context, packet_filter):
"""Create a new packet_filter entry on DB, then try to activate it."""
LOG.debug(_("create_packet_filter() called, packet_filter=%s ."),
packet_filter)
pf = super(PacketFilterMixin, self).create_packet_filter(
context, packet_filter)
return self.activate_packet_filter_if_ready(context, pf)
def update_packet_filter(self, context, id, packet_filter):
"""Update packet_filter entry on DB, and recreate it if changed.
If any rule of the packet_filter was changed, recreate it on OFC.
"""
LOG.debug(_("update_packet_filter() called, "
"id=%(id)s packet_filter=%(packet_filter)s ."),
{'id': id, 'packet_filter': packet_filter})
# validate ownership
pf_old = self.get_packet_filter(context, id)
pf = super(PacketFilterMixin, self).update_packet_filter(
context, id, packet_filter)
def _packet_filter_changed(old_pf, new_pf):
for key in new_pf:
if key not in ('id', 'name', 'tenant_id', 'network_id',
'in_port', 'status'):
if old_pf[key] != new_pf[key]:
return True
return False
if _packet_filter_changed(pf_old, pf):
pf = self.deactivate_packet_filter(context, pf)
pf = self.activate_packet_filter_if_ready(context, pf)
return pf
def delete_packet_filter(self, context, id):
"""Deactivate and delete packet_filter."""
LOG.debug(_("delete_packet_filter() called, id=%s ."), id)
# validate ownership
pf = self.get_packet_filter(context, id)
pf = self.deactivate_packet_filter(context, pf)
if pf['status'] == pf_db.PF_STATUS_ERROR:
msg = _("failed to delete packet_filter id=%s which remains in "
"error status.") % id
LOG.error(msg)
raise nexc.OFCException(reason=msg)
super(PacketFilterMixin, self).delete_packet_filter(context, id)
def activate_packet_filter_if_ready(self, context, packet_filter):
"""Activate packet_filter by creating filter on OFC if ready.
Conditions to create packet_filter on OFC are:
* packet_filter admin_state is UP
* (if 'in_port' is specified) portinfo is available
"""
LOG.debug(_("activate_packet_filter_if_ready() called, "
"packet_filter=%s."), packet_filter)
pf_id = packet_filter['id']
in_port_id = packet_filter.get('in_port')
current = packet_filter['status']
pf_status = current
if not packet_filter['admin_state_up']:
LOG.debug(_("activate_packet_filter_if_ready(): skip pf_id=%s, "
"packet_filter.admin_state_up is False."), pf_id)
elif in_port_id and not ndb.get_portinfo(context.session, in_port_id):
LOG.debug(_("activate_packet_filter_if_ready(): skip "
"pf_id=%s, no portinfo for the in_port."), pf_id)
elif self.ofc.exists_ofc_packet_filter(context, packet_filter['id']):
LOG.debug(_("_activate_packet_filter_if_ready(): skip, "
"ofc_packet_filter already exists."))
else:
LOG.debug(_("activate_packet_filter_if_ready(): create "
"packet_filter id=%s on OFC."), pf_id)
try:
self.ofc.create_ofc_packet_filter(context, pf_id,
packet_filter)
pf_status = pf_db.PF_STATUS_ACTIVE
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
LOG.error(_("failed to create packet_filter id=%(id)s on "
"OFC: %(exc)s"), {'id': pf_id, 'exc': str(exc)})
pf_status = pf_db.PF_STATUS_ERROR
if pf_status != current:
self._update_resource_status(context, "packet_filter", pf_id,
pf_status)
packet_filter.update({'status': pf_status})
return packet_filter
def deactivate_packet_filter(self, context, packet_filter):
"""Deactivate packet_filter by deleting filter from OFC if exixts."""
LOG.debug(_("deactivate_packet_filter_if_ready() called, "
"packet_filter=%s."), packet_filter)
pf_id = packet_filter['id']
current = packet_filter['status']
pf_status = current
if self.ofc.exists_ofc_packet_filter(context, pf_id):
LOG.debug(_("deactivate_packet_filter(): "
"deleting packet_filter id=%s from OFC."), pf_id)
try:
self.ofc.delete_ofc_packet_filter(context, pf_id)
pf_status = pf_db.PF_STATUS_DOWN
except (nexc.OFCException, nexc.OFCConsistencyBroken) as exc:
LOG.error(_("failed to delete packet_filter id=%(id)s from "
"OFC: %(exc)s"), {'id': pf_id, 'exc': str(exc)})
pf_status = pf_db.PF_STATUS_ERROR
else:
LOG.debug(_("deactivate_packet_filter(): skip, "
"Not found OFC Mapping for packet_filter id=%s."),
pf_id)
if pf_status != current:
self._update_resource_status(context, "packet_filter", pf_id,
pf_status)
packet_filter.update({'status': pf_status})
return packet_filter

View File

@ -21,35 +21,41 @@ import webob.exc
from neutron.api.v2 import attributes
from neutron.common.test_lib import test_config
from neutron import context
from neutron.plugins.nec.common import exceptions as nexc
from neutron.plugins.nec.extensions import packetfilter
from neutron.tests.unit.nec import test_nec_plugin
from neutron.tests.unit import test_db_plugin as test_plugin
PLUGIN_NAME = 'neutron.plugins.nec.nec_plugin.NECPluginV2'
OFC_MANAGER = 'neutron.plugins.nec.nec_plugin.ofc_manager.OFCManager'
NEC_PLUGIN_PF_INI = """
[DEFAULT]
api_extensions_path = neutron/plugins/nec/extensions
[OFC]
driver = neutron.tests.unit.nec.stub_ofc_driver.StubOFCDriver
enable_packet_filter = True
"""
class PacketfilterExtensionManager(packetfilter.Packetfilter):
def get_resources(self):
@classmethod
def get_resources(cls):
# Add the resources to the global attribute map
# This is done here as the setup process won't
# initialize the main API router which extends
# the global attribute map
attributes.RESOURCE_ATTRIBUTE_MAP.update(
{'packet_filters': packetfilter.PACKET_FILTER_ATTR_MAP})
return super(PacketfilterExtensionManager, self).get_resources()
return super(PacketfilterExtensionManager, cls).get_resources()
class TestNecPluginPacketFilter(test_plugin.NeutronDbPluginV2TestCase):
class TestNecPluginPacketFilter(test_nec_plugin.NecPluginV2TestCase):
_nec_ini = NEC_PLUGIN_PF_INI
def setUp(self):
self.addCleanup(mock.patch.stopall)
ofc_manager_cls = mock.patch(OFC_MANAGER).start()
ofc_driver = ofc_manager_cls.return_value.driver
ofc_driver.filter_supported.return_value = True
test_config['extension_manager'] = PacketfilterExtensionManager()
super(TestNecPluginPacketFilter, self).setUp(PLUGIN_NAME)
super(TestNecPluginPacketFilter, self).setUp()
def _create_packet_filter(self, fmt, net_id, expected_res_status=None,
arg_list=None, **kwargs):
@ -98,6 +104,124 @@ class TestNecPluginPacketFilter(test_plugin.NeutronDbPluginV2TestCase):
if do_delete:
self._delete('packet_filters', pf['packet_filter']['id'])
@contextlib.contextmanager
def packet_filter_on_port(self, port=None, fmt=None, do_delete=True,
set_portinfo=True, **kwargs):
with test_plugin.optional_ctx(port, self.port) as port_to_use:
net_id = port_to_use['port']['network_id']
port_id = port_to_use['port']['id']
if set_portinfo:
portinfo = {'id': port_id,
'port_no': kwargs.get('port_no', 123)}
kw = {'added': [portinfo]}
if 'datapath_id' in kwargs:
kw['datapath_id'] = kwargs['datapath_id']
self.rpcapi_update_ports(**kw)
kwargs['in_port'] = port_id
pf = self._make_packet_filter(fmt or self.fmt, net_id, **kwargs)
self.assertEqual(port_id, pf['packet_filter']['in_port'])
try:
yield pf
finally:
if do_delete:
self._delete('packet_filters', pf['packet_filter']['id'])
def test_list_packet_filters(self):
self._list('packet_filters')
def test_create_pf_on_network_no_ofc_creation(self):
with self.packet_filter_on_network(admin_state_up=False) as pf:
self.assertEqual(pf['packet_filter']['status'], 'DOWN')
self.assertFalse(self.ofc.create_ofc_packet_filter.called)
self.assertFalse(self.ofc.delete_ofc_packet_filter.called)
def test_create_pf_on_port_no_ofc_creation(self):
with self.packet_filter_on_port(admin_state_up=False,
set_portinfo=False) as pf:
self.assertEqual(pf['packet_filter']['status'], 'DOWN')
self.assertFalse(self.ofc.create_ofc_packet_filter.called)
self.assertFalse(self.ofc.delete_ofc_packet_filter.called)
def test_create_pf_on_network_with_ofc_creation(self):
with self.packet_filter_on_network() as pf:
pf_id = pf['packet_filter']['id']
self.assertEqual(pf['packet_filter']['status'], 'ACTIVE')
ctx = mock.ANY
pf_dict = mock.ANY
expected = [
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.create_ofc_packet_filter(ctx, pf_id, pf_dict),
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.delete_ofc_packet_filter(ctx, pf_id),
]
self.ofc.assert_has_calls(expected)
self.assertEqual(self.ofc.create_ofc_packet_filter.call_count, 1)
self.assertEqual(self.ofc.delete_ofc_packet_filter.call_count, 1)
def test_create_pf_on_port_with_ofc_creation(self):
with self.packet_filter_on_port() as pf:
pf_id = pf['packet_filter']['id']
self.assertEqual(pf['packet_filter']['status'], 'ACTIVE')
ctx = mock.ANY
pf_dict = mock.ANY
expected = [
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.create_ofc_packet_filter(ctx, pf_id, pf_dict),
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.delete_ofc_packet_filter(ctx, pf_id),
]
self.ofc.assert_has_calls(expected)
self.assertEqual(self.ofc.create_ofc_packet_filter.call_count, 1)
self.assertEqual(self.ofc.delete_ofc_packet_filter.call_count, 1)
def test_create_pf_with_invalid_priority(self):
with self.network() as net:
net_id = net['network']['id']
kwargs = {'priority': 'high'}
self._create_packet_filter(self.fmt, net_id,
webob.exc.HTTPBadRequest.code,
**kwargs)
self.assertFalse(self.ofc.create_ofc_packet_filter.called)
def test_create_pf_with_ofc_creation_failure(self):
self.ofc.set_raise_exc('create_ofc_packet_filter',
nexc.OFCException(reason='hoge'))
with self.packet_filter_on_network() as pf:
pf_id = pf['packet_filter']['id']
pf_ref = self._show('packet_filters', pf_id)
self.assertEqual(pf_ref['packet_filter']['status'], 'ERROR')
self.ofc.set_raise_exc('create_ofc_packet_filter', None)
# Retry deactivate packet_filter.
data = {'packet_filter': {'priority': 1000}}
self._update('packet_filters', pf_id, data)
pf_ref = self._show('packet_filters', pf_id)
self.assertEqual(pf_ref['packet_filter']['status'], 'ACTIVE')
ctx = mock.ANY
pf_dict = mock.ANY
expected = [
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.create_ofc_packet_filter(ctx, pf_id, pf_dict),
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.create_ofc_packet_filter(ctx, pf_id, pf_dict),
]
self.ofc.assert_has_calls(expected)
self.assertEqual(self.ofc.create_ofc_packet_filter.call_count, 2)
def test_show_pf_on_network(self):
kwargs = {
'name': 'test-pf-net',
@ -125,3 +249,219 @@ class TestNecPluginPacketFilter(test_plugin.NeutronDbPluginV2TestCase):
self.assertEqual(pf_id, pf_ref['packet_filter']['id'])
for key in kwargs:
self.assertEqual(kwargs[key], pf_ref['packet_filter'][key])
def test_show_pf_on_port(self):
kwargs = {
'name': 'test-pf-port',
'admin_state_up': False,
'action': 'DENY',
'priority': '0o147',
'src_mac': '00:11:22:33:44:55',
'dst_mac': '66:77:88:99:aa:bb',
'eth_type': 2048,
'src_cidr': '192.168.1.0/24',
'dst_cidr': '192.168.2.0/24',
'protocol': 'TCP',
'dst_port': '0x50'
}
with self.packet_filter_on_port(**kwargs) as pf:
pf_id = pf['packet_filter']['id']
pf_ref = self._show('packet_filters', pf_id)
# convert string to int.
kwargs.update({'priority': 103, 'eth_type': 2048,
'src_port': u'', 'dst_port': 80})
self.assertEqual(pf_id, pf_ref['packet_filter']['id'])
for key in kwargs:
self.assertEqual(kwargs[key], pf_ref['packet_filter'][key])
def test_show_pf_not_found(self):
pf_id = '00000000-ffff-ffff-ffff-000000000000'
self._show('packet_filters', pf_id,
expected_code=webob.exc.HTTPNotFound.code)
def test_update_pf_on_network(self):
ctx = mock.ANY
pf_dict = mock.ANY
with self.packet_filter_on_network(admin_state_up=False) as pf:
pf_id = pf['packet_filter']['id']
self.assertFalse(self.ofc.create_ofc_packet_filter.called)
data = {'packet_filter': {'admin_state_up': True}}
self._update('packet_filters', pf_id, data)
self.ofc.create_ofc_packet_filter.assert_called_once_with(
ctx, pf_id, pf_dict)
self.assertFalse(self.ofc.delete_ofc_packet_filter.called)
data = {'packet_filter': {'admin_state_up': False}}
self._update('packet_filters', pf_id, data)
self.ofc.delete_ofc_packet_filter.assert_called_once_with(
ctx, pf_id)
def test_update_pf_on_port(self):
ctx = mock.ANY
pf_dict = mock.ANY
with self.packet_filter_on_port(admin_state_up=False) as pf:
pf_id = pf['packet_filter']['id']
self.assertFalse(self.ofc.create_ofc_packet_filter.called)
data = {'packet_filter': {'admin_state_up': True}}
self._update('packet_filters', pf_id, data)
self.ofc.create_ofc_packet_filter.assert_called_once_with(
ctx, pf_id, pf_dict)
self.assertFalse(self.ofc.delete_ofc_packet_filter.called)
data = {'packet_filter': {'admin_state_up': False}}
self._update('packet_filters', pf_id, data)
self.ofc.delete_ofc_packet_filter.assert_called_once_with(
ctx, pf_id)
def test_activate_pf_on_port_triggered_by_update_port(self):
ctx = mock.ANY
pf_dict = mock.ANY
with self.packet_filter_on_port(set_portinfo=False) as pf:
pf_id = pf['packet_filter']['id']
in_port_id = pf['packet_filter']['in_port']
self.assertFalse(self.ofc.create_ofc_packet_filter.called)
portinfo = {'id': in_port_id, 'port_no': 123}
kw = {'added': [portinfo]}
self.rpcapi_update_ports(**kw)
self.ofc.create_ofc_packet_filter.assert_called_once_with(
ctx, pf_id, pf_dict)
self.assertFalse(self.ofc.delete_ofc_packet_filter.called)
kw = {'removed': [in_port_id]}
self.rpcapi_update_ports(**kw)
self.ofc.delete_ofc_packet_filter.assert_called_once_with(
ctx, pf_id)
# Ensure pf was created before in_port has activated.
ctx = mock.ANY
pf_dict = mock.ANY
port_dict = mock.ANY
expected = [
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.create_ofc_packet_filter(ctx, pf_id, pf_dict),
mock.call.exists_ofc_port(ctx, in_port_id),
mock.call.create_ofc_port(ctx, in_port_id, port_dict),
mock.call.exists_ofc_port(ctx, in_port_id),
mock.call.delete_ofc_port(ctx, in_port_id, port_dict),
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.delete_ofc_packet_filter(ctx, pf_id),
]
self.ofc.assert_has_calls(expected)
self.assertEqual(self.ofc.create_ofc_packet_filter.call_count, 1)
self.assertEqual(self.ofc.delete_ofc_packet_filter.call_count, 1)
def test_activate_pf_while_exists_on_ofc(self):
ctx = mock.ANY
with self.packet_filter_on_network() as pf:
pf_id = pf['packet_filter']['id']
self.ofc.set_raise_exc('delete_ofc_packet_filter',
nexc.OFCException(reason='hoge'))
# This update request will make plugin reactivate pf.
data = {'packet_filter': {'priority': 1000}}
self._update('packet_filters', pf_id, data)
self.ofc.set_raise_exc('delete_ofc_packet_filter', None)
ctx = mock.ANY
pf_dict = mock.ANY
expected = [
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.create_ofc_packet_filter(ctx, pf_id, pf_dict),
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.delete_ofc_packet_filter(ctx, pf_id),
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.exists_ofc_packet_filter(ctx, pf_id),
]
self.ofc.assert_has_calls(expected)
self.assertEqual(self.ofc.delete_ofc_packet_filter.call_count, 2)
def test_deactivate_pf_with_ofc_deletion_failure(self):
ctx = mock.ANY
with self.packet_filter_on_network() as pf:
pf_id = pf['packet_filter']['id']
self.ofc.set_raise_exc('delete_ofc_packet_filter',
nexc.OFCException(reason='hoge'))
data = {'packet_filter': {'admin_state_up': False}}
self._update('packet_filters', pf_id, data)
pf_ref = self._show('packet_filters', pf_id)
self.assertEqual(pf_ref['packet_filter']['status'], 'ERROR')
self.ofc.set_raise_exc('delete_ofc_packet_filter', None)
data = {'packet_filter': {'priority': 1000}}
self._update('packet_filters', pf_id, data)
pf_ref = self._show('packet_filters', pf_id)
self.assertEqual(pf_ref['packet_filter']['status'], 'DOWN')
ctx = mock.ANY
pf_dict = mock.ANY
expected = [
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.create_ofc_packet_filter(ctx, pf_id, pf_dict),
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.delete_ofc_packet_filter(ctx, pf_id),
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.delete_ofc_packet_filter(ctx, pf_id),
mock.call.exists_ofc_packet_filter(ctx, pf_id),
]
self.ofc.assert_has_calls(expected)
self.assertEqual(self.ofc.delete_ofc_packet_filter.call_count, 2)
def test_delete_pf_with_ofc_deletion_failure(self):
self.ofc.set_raise_exc('delete_ofc_packet_filter',
nexc.OFCException(reason='hoge'))
with self.packet_filter_on_network() as pf:
pf_id = pf['packet_filter']['id']
self._delete('packet_filters', pf_id,
expected_code=webob.exc.HTTPInternalServerError.code)
pf_ref = self._show('packet_filters', pf_id)
self.assertEqual(pf_ref['packet_filter']['status'], 'ERROR')
self.ofc.set_raise_exc('delete_ofc_packet_filter', None)
# Then, self._delete('packet_filters', pf_id) will success.
ctx = mock.ANY
pf_dict = mock.ANY
expected = [
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.create_ofc_packet_filter(ctx, pf_id, pf_dict),
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.delete_ofc_packet_filter(ctx, pf_id),
mock.call.exists_ofc_packet_filter(ctx, pf_id),
mock.call.delete_ofc_packet_filter(ctx, pf_id),
]
self.ofc.assert_has_calls(expected)
self.assertEqual(self.ofc.delete_ofc_packet_filter.call_count, 2)
def test_auto_delete_pf_in_network_deletion(self):
with self.packet_filter_on_network(admin_state_up=False,
do_delete=False) as pf:
pf_id = pf['packet_filter']['id']
self._show('packet_filters', pf_id,
expected_code=webob.exc.HTTPNotFound.code)