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:
parent
44f4a9810f
commit
8996c75481
@ -33,7 +33,3 @@ class OFCConsistencyBroken(qexc.NeutronException):
|
|||||||
|
|
||||||
class PortInfoNotFound(qexc.NotFound):
|
class PortInfoNotFound(qexc.NotFound):
|
||||||
message = _("PortInfo %(id)s could not be found")
|
message = _("PortInfo %(id)s could not be found")
|
||||||
|
|
||||||
|
|
||||||
class PacketFilterNotFound(qexc.NotFound):
|
|
||||||
message = _("PacketFilter %(id)s could not be found")
|
|
||||||
|
@ -80,26 +80,3 @@ class PortInfo(model_base.BASEV2, models_v2.HasId):
|
|||||||
port_no = sa.Column(sa.Integer, nullable=False)
|
port_no = sa.Column(sa.Integer, nullable=False)
|
||||||
vlan_id = sa.Column(sa.Integer, nullable=False)
|
vlan_id = sa.Column(sa.Integer, nullable=False)
|
||||||
mac = sa.Column(sa.String(32), 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)
|
|
||||||
|
@ -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)
|
|
148
neutron/plugins/nec/db/packetfilter.py
Normal file
148
neutron/plugins/nec/db/packetfilter.py
Normal 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)
|
@ -1,6 +1,6 @@
|
|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
# Copyright 2012 NEC Corporation.
|
# Copyright 2012-2013 NEC Corporation.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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 import extensions
|
||||||
from neutron.api.v2 import attributes
|
from neutron.api.v2 import attributes
|
||||||
from neutron.api.v2 import base
|
from neutron.api.v2 import base
|
||||||
|
from neutron.common import exceptions
|
||||||
from neutron.manager import NeutronManager
|
from neutron.manager import NeutronManager
|
||||||
from neutron import quota
|
from neutron import quota
|
||||||
|
|
||||||
@ -33,20 +34,36 @@ quota_packet_filter_opts = [
|
|||||||
help=_("Number of packet_filters allowed per tenant, "
|
help=_("Number of packet_filters allowed per tenant, "
|
||||||
"-1 for unlimited"))
|
"-1 for unlimited"))
|
||||||
]
|
]
|
||||||
# Register the configuration options
|
|
||||||
cfg.CONF.register_opts(quota_packet_filter_opts, 'QUOTAS')
|
cfg.CONF.register_opts(quota_packet_filter_opts, 'QUOTAS')
|
||||||
|
|
||||||
|
|
||||||
PACKET_FILTER_ACTION_REGEX = "(?i)^(allow|accept|drop|deny)$"
|
def convert_to_int(data):
|
||||||
PACKET_FILTER_NUMBER_REGEX = "(?i)^(0x[0-9a-fA-F]+|[0-9]+)$"
|
try:
|
||||||
PACKET_FILTER_PROTOCOL_REGEX = "(?i)^(icmp|tcp|udp|arp|0x[0-9a-fA-F]+|[0-9]+)$"
|
return int(data, 0)
|
||||||
PACKET_FILTER_ATTR_MAP = {
|
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,
|
'id': {'allow_post': False, 'allow_put': False,
|
||||||
'validate': {'type:uuid': None},
|
'validate': {'type:uuid': None},
|
||||||
'is_visible': True},
|
'is_visible': True},
|
||||||
'name': {'allow_post': True, 'allow_put': True, 'default': '',
|
'name': {'allow_post': True, 'allow_put': True, 'default': '',
|
||||||
|
'validate': {'type:string': None},
|
||||||
'is_visible': True},
|
'is_visible': True},
|
||||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||||
|
'validate': {'type:string': None},
|
||||||
'required_by_policy': True,
|
'required_by_policy': True,
|
||||||
'is_visible': True},
|
'is_visible': True},
|
||||||
'network_id': {'allow_post': True, 'allow_put': False,
|
'network_id': {'allow_post': True, 'allow_put': False,
|
||||||
@ -62,9 +79,9 @@ PACKET_FILTER_ATTR_MAP = {
|
|||||||
'validate': {'type:regex': PACKET_FILTER_ACTION_REGEX},
|
'validate': {'type:regex': PACKET_FILTER_ACTION_REGEX},
|
||||||
'is_visible': True},
|
'is_visible': True},
|
||||||
'priority': {'allow_post': True, 'allow_put': True,
|
'priority': {'allow_post': True, 'allow_put': True,
|
||||||
'validate': {'type:regex': PACKET_FILTER_NUMBER_REGEX},
|
'convert_to': convert_to_int,
|
||||||
'is_visible': True},
|
'is_visible': True},
|
||||||
'in_port': {'allow_post': True, 'allow_put': True,
|
'in_port': {'allow_post': True, 'allow_put': False,
|
||||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
'default': attributes.ATTR_NOT_SPECIFIED,
|
||||||
'validate': {'type:uuid': None},
|
'validate': {'type:uuid': None},
|
||||||
'is_visible': True},
|
'is_visible': True},
|
||||||
@ -78,7 +95,7 @@ PACKET_FILTER_ATTR_MAP = {
|
|||||||
'is_visible': True},
|
'is_visible': True},
|
||||||
'eth_type': {'allow_post': True, 'allow_put': True,
|
'eth_type': {'allow_post': True, 'allow_put': True,
|
||||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
'default': attributes.ATTR_NOT_SPECIFIED,
|
||||||
'validate': {'type:regex': PACKET_FILTER_NUMBER_REGEX},
|
'convert_to': convert_to_int,
|
||||||
'is_visible': True},
|
'is_visible': True},
|
||||||
'src_cidr': {'allow_post': True, 'allow_put': True,
|
'src_cidr': {'allow_post': True, 'allow_put': True,
|
||||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
'default': attributes.ATTR_NOT_SPECIFIED,
|
||||||
@ -94,40 +111,58 @@ PACKET_FILTER_ATTR_MAP = {
|
|||||||
'is_visible': True},
|
'is_visible': True},
|
||||||
'src_port': {'allow_post': True, 'allow_put': True,
|
'src_port': {'allow_post': True, 'allow_put': True,
|
||||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
'default': attributes.ATTR_NOT_SPECIFIED,
|
||||||
'validate': {'type:regex': PACKET_FILTER_NUMBER_REGEX},
|
'convert_to': convert_to_int,
|
||||||
'is_visible': True},
|
'is_visible': True},
|
||||||
'dst_port': {'allow_post': True, 'allow_put': True,
|
'dst_port': {'allow_post': True, 'allow_put': True,
|
||||||
'default': attributes.ATTR_NOT_SPECIFIED,
|
'default': attributes.ATTR_NOT_SPECIFIED,
|
||||||
'validate': {'type:regex': PACKET_FILTER_NUMBER_REGEX},
|
'convert_to': convert_to_int,
|
||||||
'is_visible': True},
|
'is_visible': True},
|
||||||
}
|
}
|
||||||
|
PACKET_FILTER_ATTR_MAP = {COLLECTION: PACKET_FILTER_ATTR_PARAMS}
|
||||||
|
|
||||||
|
|
||||||
class Packetfilter(extensions.ExtensionDescriptor):
|
class Packetfilter(extensions.ExtensionDescriptor):
|
||||||
|
|
||||||
def get_name(self):
|
@classmethod
|
||||||
return "PacketFilters"
|
def get_name(cls):
|
||||||
|
return ALIAS
|
||||||
|
|
||||||
def get_alias(self):
|
@classmethod
|
||||||
return "PacketFilters"
|
def get_alias(cls):
|
||||||
|
return ALIAS
|
||||||
|
|
||||||
def get_description(self):
|
@classmethod
|
||||||
return "PacketFilters"
|
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"
|
return "http://www.nec.co.jp/api/ext/packet_filter/v2.0"
|
||||||
|
|
||||||
def get_updated(self):
|
@classmethod
|
||||||
return "2012-07-24T00:00:00+09:00"
|
def get_updated(cls):
|
||||||
|
return "2013-07-16T00:00:00+09:00"
|
||||||
|
|
||||||
def get_resources(self):
|
@classmethod
|
||||||
resource = base.create_resource('packet_filters', 'packet_filter',
|
def get_resources(cls):
|
||||||
NeutronManager.get_plugin(),
|
qresource = quota.CountableResource(RESOURCE,
|
||||||
PACKET_FILTER_ATTR_MAP)
|
|
||||||
qresource = quota.CountableResource('packet_filter',
|
|
||||||
quota._count_resource,
|
quota._count_resource,
|
||||||
'quota_packet_filter')
|
'quota_%s' % RESOURCE)
|
||||||
quota.QUOTAS.register_resource(qresource)
|
quota.QUOTAS.register_resource(qresource)
|
||||||
return [extensions.ResourceExtension('packet_filters',
|
|
||||||
resource,
|
resource = base.create_resource(COLLECTION, RESOURCE,
|
||||||
attr_map=PACKET_FILTER_ATTR_MAP)]
|
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 {}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
# 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
|
# 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
|
# 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 config
|
||||||
from neutron.plugins.nec.common import exceptions as nexc
|
from neutron.plugins.nec.common import exceptions as nexc
|
||||||
from neutron.plugins.nec.db import api as ndb
|
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 ofc_manager
|
||||||
|
from neutron.plugins.nec import packet_filter
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -60,12 +61,13 @@ class OperationalStatus:
|
|||||||
ERROR = "ERROR"
|
ERROR = "ERROR"
|
||||||
|
|
||||||
|
|
||||||
class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
extraroute_db.ExtraRoute_db_mixin,
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
l3_gwmode_db.L3_NAT_db_mixin,
|
l3_gwmode_db.L3_NAT_db_mixin,
|
||||||
sg_db_rpc.SecurityGroupServerRpcMixin,
|
sg_db_rpc.SecurityGroupServerRpcMixin,
|
||||||
agentschedulers_db.L3AgentSchedulerDbMixin,
|
agentschedulers_db.L3AgentSchedulerDbMixin,
|
||||||
agentschedulers_db.DhcpAgentSchedulerDbMixin):
|
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||||
|
packet_filter.PacketFilterMixin):
|
||||||
"""NECPluginV2 controls an OpenFlow Controller.
|
"""NECPluginV2 controls an OpenFlow Controller.
|
||||||
|
|
||||||
The Neutron NECPluginV2 maps L2 logical networks to L2 virtualized networks
|
The Neutron NECPluginV2 maps L2 logical networks to L2 virtualized networks
|
||||||
@ -82,13 +84,15 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
"binding", "security-group",
|
"binding", "security-group",
|
||||||
"extraroute", "agent",
|
"extraroute", "agent",
|
||||||
"l3_agent_scheduler",
|
"l3_agent_scheduler",
|
||||||
"dhcp_agent_scheduler"]
|
"dhcp_agent_scheduler",
|
||||||
|
"packet-filter"]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_extension_aliases(self):
|
def supported_extension_aliases(self):
|
||||||
if not hasattr(self, '_aliases'):
|
if not hasattr(self, '_aliases'):
|
||||||
aliases = self._supported_extension_aliases[:]
|
aliases = self._supported_extension_aliases[:]
|
||||||
sg_rpc.disable_security_group_extension_if_noop_driver(aliases)
|
sg_rpc.disable_security_group_extension_if_noop_driver(aliases)
|
||||||
|
self.remove_packet_filter_extension_if_disabled(aliases)
|
||||||
self._aliases = aliases
|
self._aliases = aliases
|
||||||
return self._aliases
|
return self._aliases
|
||||||
|
|
||||||
@ -96,11 +100,6 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
ndb.initialize()
|
ndb.initialize()
|
||||||
self.ofc = ofc_manager.OFCManager()
|
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
|
# Set the plugin default extension path
|
||||||
# if no api_extensions_path is specified.
|
# if no api_extensions_path is specified.
|
||||||
if not config.CONF.api_extensions_path:
|
if not config.CONF.api_extensions_path:
|
||||||
@ -172,14 +171,11 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
if self.packet_filter_enabled:
|
if self.packet_filter_enabled:
|
||||||
if port_status is OperationalStatus.ACTIVE:
|
if port_status is OperationalStatus.ACTIVE:
|
||||||
filters = dict(in_port=[port['id']],
|
filters = dict(in_port=[port['id']],
|
||||||
status=[OperationalStatus.DOWN],
|
status=[pf_db.PF_STATUS_DOWN],
|
||||||
admin_state_up=[True])
|
admin_state_up=[True])
|
||||||
pfs = (super(NECPluginV2, self).
|
pfs = self.get_packet_filters(context, filters=filters)
|
||||||
get_packet_filters(context, filters=filters))
|
|
||||||
for pf in pfs:
|
for pf in pfs:
|
||||||
self._activate_packet_filter_if_ready(context, pf,
|
self.activate_packet_filter_if_ready(context, pf)
|
||||||
network=network,
|
|
||||||
in_port=port)
|
|
||||||
|
|
||||||
if port_status in [OperationalStatus.ACTIVE]:
|
if port_status in [OperationalStatus.ACTIVE]:
|
||||||
if self.ofc.exists_ofc_port(context, port['id']):
|
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.
|
# deactivate packet_filters after the port has deleted from OFC.
|
||||||
if self.packet_filter_enabled:
|
if self.packet_filter_enabled:
|
||||||
filters = dict(in_port=[port['id']],
|
filters = dict(in_port=[port['id']],
|
||||||
status=[OperationalStatus.ACTIVE])
|
status=[pf_db.PF_STATUS_ACTIVE])
|
||||||
pfs = super(NECPluginV2, self).get_packet_filters(context,
|
pfs = self.get_packet_filters(context, filters=filters)
|
||||||
filters=filters)
|
|
||||||
for pf in pfs:
|
for pf in pfs:
|
||||||
self._deactivate_packet_filter(context, pf)
|
self.deactivate_packet_filter(context, pf)
|
||||||
|
|
||||||
# Quantm Plugin Basic methods
|
# Quantm Plugin Basic methods
|
||||||
|
|
||||||
@ -280,32 +275,22 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
if changed and not new_net['admin_state_up']:
|
if changed and not new_net['admin_state_up']:
|
||||||
self._update_resource_status(context, "network", id,
|
self._update_resource_status(context, "network", id,
|
||||||
OperationalStatus.DOWN)
|
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])
|
filters = dict(network_id=[id], status=[OperationalStatus.ACTIVE])
|
||||||
ports = super(NECPluginV2, self).get_ports(context,
|
ports = super(NECPluginV2, self).get_ports(context,
|
||||||
filters=filters)
|
filters=filters)
|
||||||
for port in ports:
|
for port in ports:
|
||||||
self.deactivate_port(context, port)
|
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']:
|
elif changed and new_net['admin_state_up']:
|
||||||
self._update_resource_status(context, "network", id,
|
self._update_resource_status(context, "network", id,
|
||||||
OperationalStatus.ACTIVE)
|
OperationalStatus.ACTIVE)
|
||||||
# enable ports and packet_filters of the network
|
# enable ports of the network
|
||||||
filters = dict(network_id=[id], status=[OperationalStatus.DOWN],
|
filters = dict(network_id=[id], status=[OperationalStatus.DOWN],
|
||||||
admin_state_up=[True])
|
admin_state_up=[True])
|
||||||
ports = super(NECPluginV2, self).get_ports(context,
|
ports = super(NECPluginV2, self).get_ports(context,
|
||||||
filters=filters)
|
filters=filters)
|
||||||
for port in ports:
|
for port in ports:
|
||||||
self.activate_port_if_ready(context, port, new_net)
|
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
|
return new_net
|
||||||
|
|
||||||
@ -329,11 +314,12 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
' from OFC: %s'), port)
|
' from OFC: %s'), port)
|
||||||
self.deactivate_port(context, 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:
|
if self.packet_filter_enabled:
|
||||||
filters = dict(network_id=[id])
|
filters = dict(network_id=[id])
|
||||||
pfs = (super(NECPluginV2, self).
|
pfs = self.get_packet_filters(context, filters=filters)
|
||||||
get_packet_filters(context, filters=filters))
|
for pf in pfs:
|
||||||
|
self.delete_packet_filter(context, pf['id'])
|
||||||
|
|
||||||
super(NECPluginV2, self).delete_network(context, id)
|
super(NECPluginV2, self).delete_network(context, id)
|
||||||
try:
|
try:
|
||||||
@ -346,11 +332,6 @@ class NECPluginV2(nec_plugin_base.NECPluginV2Base,
|
|||||||
# resources, so this plugin just warns.
|
# resources, so this plugin just warns.
|
||||||
LOG.warn(reason)
|
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
|
# delete unnessary ofc_tenant
|
||||||
filters = dict(tenant_id=[tenant_id])
|
filters = dict(tenant_id=[tenant_id])
|
||||||
nets = super(NECPluginV2, self).get_networks(context, filters=filters)
|
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
|
# delete all packet_filters of the port
|
||||||
if self.packet_filter_enabled:
|
if self.packet_filter_enabled:
|
||||||
filters = dict(port_id=[id])
|
filters = dict(port_id=[id])
|
||||||
pfs = (super(NECPluginV2, self).
|
pfs = self.get_packet_filters(context, filters=filters)
|
||||||
get_packet_filters(context, filters=filters))
|
|
||||||
for packet_filter in pfs:
|
for packet_filter in pfs:
|
||||||
self.delete_packet_filter(context, packet_filter['id'])
|
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)
|
self._extend_port_dict_binding(context, port)
|
||||||
return [self._fields(port, fields) for port in ports]
|
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,
|
class NECPluginV2AgentNotifierApi(proxy.RpcProxy,
|
||||||
sg_rpc.SecurityGroupAgentRpcApiMixin):
|
sg_rpc.SecurityGroupAgentRpcApiMixin):
|
||||||
|
170
neutron/plugins/nec/packet_filter.py
Normal file
170
neutron/plugins/nec/packet_filter.py
Normal 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
|
@ -21,35 +21,41 @@ import webob.exc
|
|||||||
from neutron.api.v2 import attributes
|
from neutron.api.v2 import attributes
|
||||||
from neutron.common.test_lib import test_config
|
from neutron.common.test_lib import test_config
|
||||||
from neutron import context
|
from neutron import context
|
||||||
|
from neutron.plugins.nec.common import exceptions as nexc
|
||||||
from neutron.plugins.nec.extensions import packetfilter
|
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
|
from neutron.tests.unit import test_db_plugin as test_plugin
|
||||||
|
|
||||||
|
|
||||||
PLUGIN_NAME = 'neutron.plugins.nec.nec_plugin.NECPluginV2'
|
NEC_PLUGIN_PF_INI = """
|
||||||
OFC_MANAGER = 'neutron.plugins.nec.nec_plugin.ofc_manager.OFCManager'
|
[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):
|
class PacketfilterExtensionManager(packetfilter.Packetfilter):
|
||||||
|
|
||||||
def get_resources(self):
|
@classmethod
|
||||||
|
def get_resources(cls):
|
||||||
# Add the resources to the global attribute map
|
# Add the resources to the global attribute map
|
||||||
# This is done here as the setup process won't
|
# This is done here as the setup process won't
|
||||||
# initialize the main API router which extends
|
# initialize the main API router which extends
|
||||||
# the global attribute map
|
# the global attribute map
|
||||||
attributes.RESOURCE_ATTRIBUTE_MAP.update(
|
attributes.RESOURCE_ATTRIBUTE_MAP.update(
|
||||||
{'packet_filters': packetfilter.PACKET_FILTER_ATTR_MAP})
|
{'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):
|
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()
|
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,
|
def _create_packet_filter(self, fmt, net_id, expected_res_status=None,
|
||||||
arg_list=None, **kwargs):
|
arg_list=None, **kwargs):
|
||||||
@ -98,6 +104,124 @@ class TestNecPluginPacketFilter(test_plugin.NeutronDbPluginV2TestCase):
|
|||||||
if do_delete:
|
if do_delete:
|
||||||
self._delete('packet_filters', pf['packet_filter']['id'])
|
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):
|
def test_show_pf_on_network(self):
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'name': 'test-pf-net',
|
'name': 'test-pf-net',
|
||||||
@ -125,3 +249,219 @@ class TestNecPluginPacketFilter(test_plugin.NeutronDbPluginV2TestCase):
|
|||||||
self.assertEqual(pf_id, pf_ref['packet_filter']['id'])
|
self.assertEqual(pf_id, pf_ref['packet_filter']['id'])
|
||||||
for key in kwargs:
|
for key in kwargs:
|
||||||
self.assertEqual(kwargs[key], pf_ref['packet_filter'][key])
|
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)
|
||||||
|
Loading…
Reference in New Issue
Block a user