From 2781fce238e79690bf707a3df4823aec422687bd Mon Sep 17 00:00:00 2001 From: Akihiro Motoki Date: Sat, 23 Aug 2014 18:16:18 +0900 Subject: [PATCH] Make SecurityGroupsRpcCallback a separate callback class RPC has a version of itself. In Neutron a plugin implements several RPC interface, so a single RPC version doesn't work. In Mixin callback class approach, RPC versioning depends on each plugin implementation and it makes harder to maintain RPC version appropriately. This patch series replaces mixin RPC callback of server side with a separate class. This commit handles server-side callback of security group RPC interface. * The server-side callback of Security group RPC is moved to api/rpc/handler and db/securitygroups_rpc_base now only contains a mixin class to add agent-based security group implementation with db operations. * get_port_from_device method in server-side callback class is moved to a mixin class of plugin implementation (SecurityGroupServerRpcMixin) because it involves DB lookup and is tightly coupled with plugin implementation rather than RPC interface definition. Most unit tests for SGServerRpcCallBackTestCase were skipped in the base class before, but now they are no longer skipped. The following items will be planned in later patches to avoid drastic changes in a single patch. * Merge security group RPC API and agent callback classes in agent/securitygroups_rpc into api/rpc/handlers/securitygroup_rpc * Remove completely duplicated db access code in get_port_from_device and get_port_and_sgs Partial-Bug: #1359416 Change-Id: Ia6535217d2e3b849a95667c1b53dd09675002892 --- .../api/rpc/handlers/securitygroups_rpc.py | 59 +++++++++ neutron/db/securitygroups_rpc_base.py | 50 ++++---- neutron/plugins/bigswitch/plugin.py | 12 +- neutron/plugins/brocade/NeutronPlugin.py | 64 +++++----- .../plugins/linuxbridge/lb_neutron_plugin.py | 32 ++--- neutron/plugins/ml2/plugin.py | 28 ++++ neutron/plugins/ml2/rpc.py | 37 +----- neutron/plugins/mlnx/mlnx_plugin.py | 22 ++++ neutron/plugins/mlnx/rpc_callbacks.py | 24 +--- neutron/plugins/nec/nec_plugin.py | 35 +++-- neutron/plugins/oneconvergence/plugin.py | 10 +- .../plugins/openvswitch/ovs_neutron_plugin.py | 24 ++-- neutron/plugins/ryu/ryu_neutron_plugin.py | 24 ++-- .../unit/bigswitch/test_security_groups.py | 2 +- .../linuxbridge/test_linuxbridge_plugin.py | 29 ++--- neutron/tests/unit/ml2/test_rpcapi.py | 3 +- neutron/tests/unit/ml2/test_security_group.py | 9 +- neutron/tests/unit/nec/test_security_group.py | 6 +- .../oneconvergence/test_security_group.py | 11 +- .../openvswitch/test_ovs_security_group.py | 9 +- .../tests/unit/ryu/test_ryu_security_group.py | 4 +- .../tests/unit/test_security_groups_rpc.py | 120 ++++++++++-------- 22 files changed, 338 insertions(+), 276 deletions(-) create mode 100644 neutron/api/rpc/handlers/securitygroups_rpc.py diff --git a/neutron/api/rpc/handlers/securitygroups_rpc.py b/neutron/api/rpc/handlers/securitygroups_rpc.py new file mode 100644 index 0000000000..bbba92a16e --- /dev/null +++ b/neutron/api/rpc/handlers/securitygroups_rpc.py @@ -0,0 +1,59 @@ +# 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. + +from neutron.common import rpc as n_rpc +from neutron import manager + + +# TODO(amotoki): Move security group RPC API and agent callback +# from securitygroups_rpc.py. + + +class SecurityGroupServerRpcCallback(n_rpc.RpcCallback): + """Callback for SecurityGroup agent RPC in plugin implementations. + + Subclass which inherits this class must implement get_port_from_device(). + """ + + # API version history: + # 1.1 - Initial version + + # NOTE: RPC_API_VERSION must not be overridden in subclasses + # to keep RPC API version consistent across plugins. + RPC_API_VERSION = '1.1' + + @property + def plugin(self): + return manager.NeutronManager.get_plugin() + + def security_group_rules_for_devices(self, context, **kwargs): + """Callback method to return security group rules for each port. + + also convert remote_group_id rule + to source_ip_prefix and dest_ip_prefix rule + + :params devices: list of devices + :returns: port correspond to the devices with security group rules + """ + devices = kwargs.get('devices') + + ports = {} + for device in devices: + port = self.plugin.get_port_from_device(device) + if not port: + continue + if port['device_owner'].startswith('network:'): + continue + ports[port['id']] = port + return self.plugin.security_group_rules_for_ports(context, ports) diff --git a/neutron/db/securitygroups_rpc_base.py b/neutron/db/securitygroups_rpc_base.py index 4a659bd188..81d3457f67 100644 --- a/neutron/db/securitygroups_rpc_base.py +++ b/neutron/db/securitygroups_rpc_base.py @@ -36,6 +36,27 @@ DIRECTION_IP_PREFIX = {'ingress': 'source_ip_prefix', class SecurityGroupServerRpcMixin(sg_db.SecurityGroupDbMixin): + """Mixin class to add agent-based security group implementation.""" + + def get_port_from_device(self, device): + """Get port dict from device name on an agent. + + Subclass must provide this method. + + :param device: device name which identifies a port on the agent side. + What is specified in "device" depends on a plugin agent implementation. + For example, it is a port ID in OVS agent and netdev name in Linux + Bridge agent. + :return: port dict returned by DB plugin get_port(). In addition, + it must contain the following fields in the port dict returned. + - device + - security_groups + - security_group_rules, + - security_group_source_groups + - fixed_ips + """ + raise NotImplementedError(_("%s must implement get_port_from_device.") + % self.__class__.__name__) def create_security_group_rule(self, context, security_group_rule): bulk_rule = {'security_group_rules': [security_group_rule]} @@ -128,33 +149,6 @@ class SecurityGroupServerRpcMixin(sg_db.SecurityGroupDbMixin): self.notifier.security_groups_member_updated( context, port.get(ext_sg.SECURITYGROUPS)) - -class SecurityGroupServerRpcCallbackMixin(object): - """A mix-in that enable SecurityGroup agent support in plugin - implementations. - """ - - def security_group_rules_for_devices(self, context, **kwargs): - """Return security group rules for each port. - - also convert remote_group_id rule - to source_ip_prefix and dest_ip_prefix rule - - :params devices: list of devices - :returns: port correspond to the devices with security group rules - """ - devices = kwargs.get('devices') - - ports = {} - for device in devices: - port = self.get_port_from_device(device) - if not port: - continue - if port['device_owner'].startswith('network:'): - continue - ports[port['id']] = port - return self._security_group_rules_for_ports(context, ports) - def _select_rules_for_ports(self, context, ports): if not ports: return [] @@ -354,7 +348,7 @@ class SecurityGroupServerRpcCallbackMixin(object): self._add_ingress_ra_rule(port, ips_ra) self._add_ingress_dhcp_rule(port, ips_dhcp) - def _security_group_rules_for_ports(self, context, ports): + def security_group_rules_for_ports(self, context, ports): rules_in_db = self._select_rules_for_ports(context, ports) for (binding, rule_in_db) in rules_in_db: port_id = binding['port_id'] diff --git a/neutron/plugins/bigswitch/plugin.py b/neutron/plugins/bigswitch/plugin.py index 1ac8a78e31..78ed005c7b 100644 --- a/neutron/plugins/bigswitch/plugin.py +++ b/neutron/plugins/bigswitch/plugin.py @@ -56,6 +56,7 @@ from neutron.agent import securitygroups_rpc as sg_rpc from neutron.api import extensions as neutron_extensions from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api from neutron.api.rpc.handlers import dhcp_rpc +from neutron.api.rpc.handlers import securitygroups_rpc from neutron.common import constants as const from neutron.common import exceptions from neutron.common import rpc as n_rpc @@ -72,7 +73,7 @@ from neutron.db import extradhcpopt_db from neutron.db import l3_db from neutron.db import models_v2 from neutron.db import securitygroups_db as sg_db -from neutron.db import securitygroups_rpc_base as sg_rpc_base +from neutron.db import securitygroups_rpc_base as sg_db_rpc from neutron.extensions import allowedaddresspairs as addr_pair from neutron.extensions import external_net from neutron.extensions import extra_dhcp_opt as edo_ext @@ -113,10 +114,7 @@ class AgentNotifierApi(n_rpc.RpcProxy, topic=self.topic_port_update) -class RestProxyCallbacks(n_rpc.RpcCallback, - sg_rpc_base.SecurityGroupServerRpcCallbackMixin): - - RPC_API_VERSION = '1.1' +class SecurityGroupServerRpcMixin(sg_db_rpc.SecurityGroupServerRpcMixin): def get_port_from_device(self, device): port_id = re.sub(r"^tap", "", device) @@ -454,7 +452,7 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base, addr_pair_db.AllowedAddressPairsMixin, extradhcpopt_db.ExtraDhcpOptMixin, agentschedulers_db.DhcpAgentSchedulerDbMixin, - sg_rpc_base.SecurityGroupServerRpcMixin): + SecurityGroupServerRpcMixin): _supported_extension_aliases = ["external-net", "router", "binding", "router_rules", "extra_dhcp_opt", "quotas", @@ -509,7 +507,7 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base, self.agent_notifiers[const.AGENT_TYPE_DHCP] = ( self._dhcp_agent_notifier ) - self.endpoints = [RestProxyCallbacks(), + self.endpoints = [securitygroups_rpc.SecurityGroupServerRpcCallback(), dhcp_rpc.DhcpRpcCallback(), agents_db.AgentExtRpcCallback()] self.conn.create_consumer(self.topic, self.endpoints, diff --git a/neutron/plugins/brocade/NeutronPlugin.py b/neutron/plugins/brocade/NeutronPlugin.py index e1408c44db..7b46e04bce 100644 --- a/neutron/plugins/brocade/NeutronPlugin.py +++ b/neutron/plugins/brocade/NeutronPlugin.py @@ -30,6 +30,7 @@ from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api from neutron.api.rpc.handlers import dhcp_rpc from neutron.api.rpc.handlers import l3_rpc +from neutron.api.rpc.handlers import securitygroups_rpc from neutron.common import constants as q_const from neutron.common import rpc as n_rpc from neutron.common import topics @@ -57,6 +58,7 @@ LOG = logging.getLogger(__name__) PLUGIN_VERSION = 0.88 AGENT_OWNER_PREFIX = "network:" NOS_DRIVER = 'neutron.plugins.brocade.nos.nosdriver.NOSdriver' +TAP_PREFIX_LEN = 3 SWITCH_OPTS = [cfg.StrOpt('address', default='', help=_('The address of the host to SSH to')), @@ -77,8 +79,7 @@ cfg.CONF.register_opts(SWITCH_OPTS, "SWITCH") cfg.CONF.register_opts(PHYSICAL_INTERFACE_OPTS, "PHYSICAL_INTERFACE") -class BridgeRpcCallbacks(n_rpc.RpcCallback, - sg_db_rpc.SecurityGroupServerRpcCallbackMixin): +class BridgeRpcCallbacks(n_rpc.RpcCallback): """Agent callback.""" RPC_API_VERSION = '1.2' @@ -86,32 +87,6 @@ class BridgeRpcCallbacks(n_rpc.RpcCallback, # history # 1.1 Support Security Group RPC # 1.2 Support get_devices_details_list - TAP_PREFIX_LEN = 3 - - @classmethod - def get_port_from_device(cls, device): - """Get port from the brocade specific db.""" - - # TODO(shh) context is not being passed as - # an argument to this function; - # - # need to be fixed in: - # file: neutron/db/securtygroups_rpc_base.py - # function: securitygroup_rules_for_devices() - # which needs to pass context to us - - # Doing what other plugins are doing - session = db.get_session() - port = brocade_db.get_port_from_device( - session, device[cls.TAP_PREFIX_LEN:]) - - # TODO(shiv): need to extend the db model to include device owners - # make it appears that the device owner is of type network - if port: - port['device'] = device - port['device_owner'] = AGENT_OWNER_PREFIX - port['binding:vif_type'] = 'bridge' - return port def get_device_details(self, rpc_context, **kwargs): """Agent requests device details.""" @@ -120,7 +95,7 @@ class BridgeRpcCallbacks(n_rpc.RpcCallback, device = kwargs.get('device') LOG.debug(_("Device %(device)s details requested from %(agent_id)s"), {'device': device, 'agent_id': agent_id}) - port = brocade_db.get_port(rpc_context, device[self.TAP_PREFIX_LEN:]) + port = brocade_db.get_port(rpc_context, device[TAP_PREFIX_LEN:]) if port: entry = {'device': device, 'vlan_id': port.vlan_id, @@ -163,6 +138,34 @@ class BridgeRpcCallbacks(n_rpc.RpcCallback, return entry +class SecurityGroupServerRpcMixin(sg_db_rpc.SecurityGroupServerRpcMixin): + + @classmethod + def get_port_from_device(cls, device): + """Get port from the brocade specific db.""" + + # TODO(shh) context is not being passed as + # an argument to this function; + # + # need to be fixed in: + # file: neutron/db/securtygroups_rpc_base.py + # function: securitygroup_rules_for_devices() + # which needs to pass context to us + + # Doing what other plugins are doing + session = db.get_session() + port = brocade_db.get_port_from_device( + session, device[TAP_PREFIX_LEN:]) + + # TODO(shiv): need to extend the db model to include device owners + # make it appears that the device owner is of type network + if port: + port['device'] = device + port['device_owner'] = AGENT_OWNER_PREFIX + port['binding:vif_type'] = 'bridge' + return port + + class AgentNotifierApi(n_rpc.RpcProxy, sg_rpc.SecurityGroupAgentRpcApiMixin): """Agent side of the linux bridge rpc API. @@ -205,7 +208,7 @@ class AgentNotifierApi(n_rpc.RpcProxy, class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2, external_net_db.External_net_db_mixin, extraroute_db.ExtraRoute_db_mixin, - sg_db_rpc.SecurityGroupServerRpcMixin, + SecurityGroupServerRpcMixin, l3_agentschedulers_db.L3AgentSchedulerDbMixin, agentschedulers_db.DhcpAgentSchedulerDbMixin, portbindings_base.PortBindingBaseMixin): @@ -262,6 +265,7 @@ class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2, is_admin=False) self.conn = n_rpc.create_connection(new=True) self.endpoints = [BridgeRpcCallbacks(), + securitygroups_rpc.SecurityGroupServerRpcCallback(), dhcp_rpc.DhcpRpcCallback(), l3_rpc.L3RpcCallback(), agents_db.AgentExtRpcCallback()] diff --git a/neutron/plugins/linuxbridge/lb_neutron_plugin.py b/neutron/plugins/linuxbridge/lb_neutron_plugin.py index b8ff5710de..2319f8da96 100644 --- a/neutron/plugins/linuxbridge/lb_neutron_plugin.py +++ b/neutron/plugins/linuxbridge/lb_neutron_plugin.py @@ -22,6 +22,7 @@ from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api from neutron.api.rpc.handlers import dhcp_rpc from neutron.api.rpc.handlers import l3_rpc +from neutron.api.rpc.handlers import securitygroups_rpc from neutron.api.v2 import attributes from neutron.common import constants as q_const from neutron.common import exceptions as n_exc @@ -52,24 +53,16 @@ from neutron.plugins.linuxbridge.db import l2network_db_v2 as db LOG = logging.getLogger(__name__) +# Device names start with "tap" +TAP_PREFIX_LEN = 3 -class LinuxBridgeRpcCallbacks(n_rpc.RpcCallback, - sg_db_rpc.SecurityGroupServerRpcCallbackMixin - ): + +class LinuxBridgeRpcCallbacks(n_rpc.RpcCallback): # history # 1.1 Support Security Group RPC # 1.2 Support get_devices_details_list RPC_API_VERSION = '1.2' - # Device names start with "tap" - TAP_PREFIX_LEN = 3 - - @classmethod - def get_port_from_device(cls, device): - port = db.get_port_from_device(device[cls.TAP_PREFIX_LEN:]) - if port: - port['device'] = device - return port def get_device_details(self, rpc_context, **kwargs): """Agent requests device details.""" @@ -77,7 +70,8 @@ class LinuxBridgeRpcCallbacks(n_rpc.RpcCallback, device = kwargs.get('device') LOG.debug(_("Device %(device)s details requested from %(agent_id)s"), {'device': device, 'agent_id': agent_id}) - port = self.get_port_from_device(device) + plugin = manager.NeutronManager.get_plugin() + port = plugin.get_port_from_device(device) if port: binding = db.get_network_binding(db_api.get_session(), port['network_id']) @@ -117,10 +111,10 @@ class LinuxBridgeRpcCallbacks(n_rpc.RpcCallback, agent_id = kwargs.get('agent_id') device = kwargs.get('device') host = kwargs.get('host') - port = self.get_port_from_device(device) LOG.debug(_("Device %(device)s no longer exists on %(agent_id)s"), {'device': device, 'agent_id': agent_id}) plugin = manager.NeutronManager.get_plugin() + port = plugin.get_port_from_device(device) if port: entry = {'device': device, 'exists': True} @@ -143,10 +137,10 @@ class LinuxBridgeRpcCallbacks(n_rpc.RpcCallback, agent_id = kwargs.get('agent_id') device = kwargs.get('device') host = kwargs.get('host') - port = self.get_port_from_device(device) LOG.debug(_("Device %(device)s up on %(agent_id)s"), {'device': device, 'agent_id': agent_id}) plugin = manager.NeutronManager.get_plugin() + port = plugin.get_port_from_device(device) if port: if (host and not plugin.get_port_host(rpc_context, port['id']) == host): @@ -283,6 +277,7 @@ class LinuxBridgePluginV2(db_base_plugin_v2.NeutronDbPluginV2, svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN} self.conn = n_rpc.create_connection(new=True) self.endpoints = [LinuxBridgeRpcCallbacks(), + securitygroups_rpc.SecurityGroupServerRpcCallback(), dhcp_rpc.DhcpRpcCallback(), l3_rpc.L3RpcCallback(), agents_db.AgentExtRpcCallback()] @@ -542,3 +537,10 @@ class LinuxBridgePluginV2(db_base_plugin_v2.NeutronDbPluginV2, self.notifier.port_update(context, port, binding.physical_network, binding.vlan_id) + + @classmethod + def get_port_from_device(cls, device): + port = db.get_port_from_device(device[TAP_PREFIX_LEN:]) + if port: + port['device'] = device + return port diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index cb57323544..7f60ba5ce6 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -25,6 +25,7 @@ from neutron.agent import securitygroups_rpc as sg_rpc from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api from neutron.api.rpc.handlers import dhcp_rpc from neutron.api.rpc.handlers import dvr_rpc +from neutron.api.rpc.handlers import securitygroups_rpc from neutron.api.v2 import attributes from neutron.common import constants as const from neutron.common import exceptions as exc @@ -51,6 +52,7 @@ from neutron.openstack.common import importutils from neutron.openstack.common import jsonutils from neutron.openstack.common import lockutils from neutron.openstack.common import log +from neutron.openstack.common import uuidutils from neutron.plugins.common import constants as service_constants from neutron.plugins.ml2.common import exceptions as ml2_exc from neutron.plugins.ml2 import config # noqa @@ -69,6 +71,9 @@ MAX_BIND_TRIES = 10 # providernet.py? TYPE_MULTI_SEGMENT = 'multi-segment' +TAP_DEVICE_PREFIX = 'tap' +TAP_DEVICE_PREFIX_LENGTH = 3 + class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, dvr_mac_db.DVRDbMixin, @@ -136,6 +141,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, def start_rpc_listeners(self): self.endpoints = [rpc.RpcCallbacks(self.notifier, self.type_manager), + securitygroups_rpc.SecurityGroupServerRpcCallback(), dvr_rpc.DVRServerRpcCallback(), dhcp_rpc.DhcpRpcCallback(), agents_db.AgentExtRpcCallback()] @@ -1083,3 +1089,25 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, else: port_host = db.get_port_binding_host(port_id) return (port_host == host) + + def get_port_from_device(self, device): + port_id = self._device_to_port_id(device) + port = db.get_port_and_sgs(port_id) + if port: + port['device'] = device + return port + + def _device_to_port_id(self, device): + # REVISIT(rkukura): Consider calling into MechanismDrivers to + # process device names, or having MechanismDrivers supply list + # of device prefixes to strip. + if device.startswith(TAP_DEVICE_PREFIX): + return device[TAP_DEVICE_PREFIX_LENGTH:] + else: + # REVISIT(irenab): Consider calling into bound MD to + # handle the get_device_details RPC, then remove the 'else' clause + if not uuidutils.is_uuid_like(device): + port = db.get_port_from_device_mac(device) + if port: + return port.id + return device diff --git a/neutron/plugins/ml2/rpc.py b/neutron/plugins/ml2/rpc.py index 6a1c647cde..52d3980d92 100644 --- a/neutron/plugins/ml2/rpc.py +++ b/neutron/plugins/ml2/rpc.py @@ -20,13 +20,10 @@ from neutron.common import exceptions from neutron.common import rpc as n_rpc from neutron.common import topics from neutron.common import utils -from neutron.db import securitygroups_rpc_base as sg_db_rpc from neutron.extensions import portbindings from neutron import manager from neutron.openstack.common import log -from neutron.openstack.common import uuidutils from neutron.plugins.common import constants as service_constants -from neutron.plugins.ml2 import db from neutron.plugins.ml2 import driver_api as api from neutron.plugins.ml2.drivers import type_tunnel # REVISIT(kmestery): Allow the type and mechanism drivers to supply the @@ -34,12 +31,8 @@ from neutron.plugins.ml2.drivers import type_tunnel LOG = log.getLogger(__name__) -TAP_DEVICE_PREFIX = 'tap' -TAP_DEVICE_PREFIX_LENGTH = 3 - class RpcCallbacks(n_rpc.RpcCallback, - sg_db_rpc.SecurityGroupServerRpcCallbackMixin, type_tunnel.TunnelRpcCallbackMixin): RPC_API_VERSION = '1.3' @@ -53,30 +46,6 @@ class RpcCallbacks(n_rpc.RpcCallback, self.setup_tunnel_callback_mixin(notifier, type_manager) super(RpcCallbacks, self).__init__() - @classmethod - def _device_to_port_id(cls, device): - # REVISIT(rkukura): Consider calling into MechanismDrivers to - # process device names, or having MechanismDrivers supply list - # of device prefixes to strip. - if device.startswith(TAP_DEVICE_PREFIX): - return device[TAP_DEVICE_PREFIX_LENGTH:] - else: - # REVISIT(irenab): Consider calling into bound MD to - # handle the get_device_details RPC, then remove the 'else' clause - if not uuidutils.is_uuid_like(device): - port = db.get_port_from_device_mac(device) - if port: - return port.id - return device - - @classmethod - def get_port_from_device(cls, device): - port_id = cls._device_to_port_id(device) - port = db.get_port_and_sgs(port_id) - if port: - port['device'] = device - return port - def get_device_details(self, rpc_context, **kwargs): """Agent requests device details.""" agent_id = kwargs.get('agent_id') @@ -85,9 +54,9 @@ class RpcCallbacks(n_rpc.RpcCallback, LOG.debug("Device %(device)s details requested by agent " "%(agent_id)s with host %(host)s", {'device': device, 'agent_id': agent_id, 'host': host}) - port_id = self._device_to_port_id(device) plugin = manager.NeutronManager.get_plugin() + port_id = plugin._device_to_port_id(device) port_context = plugin.get_bound_port_context(rpc_context, port_id, host) @@ -152,7 +121,7 @@ class RpcCallbacks(n_rpc.RpcCallback, "%(agent_id)s"), {'device': device, 'agent_id': agent_id}) plugin = manager.NeutronManager.get_plugin() - port_id = self._device_to_port_id(device) + port_id = plugin._device_to_port_id(device) port_exists = True if (host and not plugin.port_bound_to_host(rpc_context, port_id, host)): @@ -177,7 +146,7 @@ class RpcCallbacks(n_rpc.RpcCallback, LOG.debug(_("Device %(device)s up at agent %(agent_id)s"), {'device': device, 'agent_id': agent_id}) plugin = manager.NeutronManager.get_plugin() - port_id = self._device_to_port_id(device) + port_id = plugin._device_to_port_id(device) if (host and not plugin.port_bound_to_host(rpc_context, port_id, host)): LOG.debug(_("Device %(device)s not bound to the" diff --git a/neutron/plugins/mlnx/mlnx_plugin.py b/neutron/plugins/mlnx/mlnx_plugin.py index ea5a4bc92f..0a8ed5b761 100644 --- a/neutron/plugins/mlnx/mlnx_plugin.py +++ b/neutron/plugins/mlnx/mlnx_plugin.py @@ -22,6 +22,7 @@ from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api from neutron.api.rpc.handlers import dhcp_rpc from neutron.api.rpc.handlers import l3_rpc +from neutron.api.rpc.handlers import securitygroups_rpc from neutron.api.v2 import attributes from neutron.common import constants as q_const from neutron.common import exceptions as n_exc @@ -51,6 +52,9 @@ from neutron.plugins.mlnx import rpc_callbacks LOG = logging.getLogger(__name__) +#to be compatible with Linux Bridge Agent on Network Node +TAP_PREFIX_LEN = 3 + class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2, external_net_db.External_net_db_mixin, @@ -122,6 +126,7 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2, svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN} self.conn = n_rpc.create_connection(new=True) self.endpoints = [rpc_callbacks.MlnxRpcCallbacks(), + securitygroups_rpc.SecurityGroupServerRpcCallback(), dhcp_rpc.DhcpRpcCallback(), l3_rpc.L3RpcCallback(), agents_db.AgentExtRpcCallback()] @@ -515,3 +520,20 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2, # now that we've left db transaction, we are safe to notify self.notify_routers_updated(context, router_ids) self.notify_security_groups_member_updated(context, port) + + @classmethod + def get_port_from_device(cls, device): + """Get port according to device. + + To maintain compatibility with Linux Bridge L2 Agent for DHCP/L3 + services get device either by linux bridge plugin + device name convention or by mac address + """ + port = db.get_port_from_device(device[TAP_PREFIX_LEN:]) + if port: + port['device'] = device + else: + port = db.get_port_from_device_mac(device) + if port: + port['device'] = device + return port diff --git a/neutron/plugins/mlnx/rpc_callbacks.py b/neutron/plugins/mlnx/rpc_callbacks.py index 9337290fa6..d2252d3505 100644 --- a/neutron/plugins/mlnx/rpc_callbacks.py +++ b/neutron/plugins/mlnx/rpc_callbacks.py @@ -17,40 +17,18 @@ from oslo.config import cfg from neutron.common import constants as q_const from neutron.common import rpc as n_rpc from neutron.db import api as db_api -from neutron.db import securitygroups_rpc_base as sg_db_rpc from neutron.openstack.common import log as logging from neutron.plugins.mlnx.db import mlnx_db_v2 as db LOG = logging.getLogger(__name__) -class MlnxRpcCallbacks(n_rpc.RpcCallback, - sg_db_rpc.SecurityGroupServerRpcCallbackMixin): +class MlnxRpcCallbacks(n_rpc.RpcCallback): # History # 1.1 Support Security Group RPC # 1.2 Support get_devices_details_list RPC_API_VERSION = '1.2' - #to be compatible with Linux Bridge Agent on Network Node - TAP_PREFIX_LEN = 3 - - @classmethod - def get_port_from_device(cls, device): - """Get port according to device. - - To maintain compatibility with Linux Bridge L2 Agent for DHCP/L3 - services get device either by linux bridge plugin - device name convention or by mac address - """ - port = db.get_port_from_device(device[cls.TAP_PREFIX_LEN:]) - if port: - port['device'] = device - else: - port = db.get_port_from_device_mac(device) - if port: - port['device'] = device - return port - def get_device_details(self, rpc_context, **kwargs): """Agent requests device details.""" agent_id = kwargs.get('agent_id') diff --git a/neutron/plugins/nec/nec_plugin.py b/neutron/plugins/nec/nec_plugin.py index 936057ba1b..f88ce8d3d3 100644 --- a/neutron/plugins/nec/nec_plugin.py +++ b/neutron/plugins/nec/nec_plugin.py @@ -19,6 +19,7 @@ from neutron.api import extensions as neutron_extensions from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api from neutron.api.rpc.handlers import dhcp_rpc from neutron.api.rpc.handlers import l3_rpc +from neutron.api.rpc.handlers import securitygroups_rpc from neutron.api.v2 import attributes as attrs from neutron.common import constants as const from neutron.common import exceptions as n_exc @@ -53,10 +54,23 @@ from neutron.plugins.nec import packet_filter LOG = logging.getLogger(__name__) +class SecurityGroupServerRpcMixin(sg_db_rpc.SecurityGroupServerRpcMixin): + + @staticmethod + def get_port_from_device(device): + port = ndb.get_port_from_device(device) + if port: + port['device'] = device + LOG.debug("NECPluginV2.get_port_from_device() called, " + "device=%(device)s => %(ret)s.", + {'device': device, 'ret': port}) + return port + + class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2, external_net_db.External_net_db_mixin, nec_router.RouterMixin, - sg_db_rpc.SecurityGroupServerRpcMixin, + SecurityGroupServerRpcMixin, agentschedulers_db.DhcpAgentSchedulerDbMixin, nec_router.L3AgentSchedulerDbMixin, packet_filter.PacketFilterMixin, @@ -143,7 +157,7 @@ class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2, ) # NOTE: callback_sg is referred to from the sg unit test. - self.callback_sg = SecurityGroupServerRpcCallback() + self.callback_sg = securitygroups_rpc.SecurityGroupServerRpcCallback() self.endpoints = [ NECPluginV2RPCCallbacks(self.safe_reference), dhcp_rpc.DhcpRpcCallback(), @@ -680,23 +694,6 @@ class NECPluginV2AgentNotifierApi(n_rpc.RpcProxy, topic=self.topic_port_update) -class SecurityGroupServerRpcCallback( - n_rpc.RpcCallback, - sg_db_rpc.SecurityGroupServerRpcCallbackMixin): - - RPC_API_VERSION = sg_rpc.SG_RPC_VERSION - - @staticmethod - def get_port_from_device(device): - port = ndb.get_port_from_device(device) - if port: - port['device'] = device - LOG.debug(_("NECPluginV2RPCCallbacks.get_port_from_device() called, " - "device=%(device)s => %(ret)s."), - {'device': device, 'ret': port}) - return port - - class NECPluginV2RPCCallbacks(n_rpc.RpcCallback): RPC_API_VERSION = '1.0' diff --git a/neutron/plugins/oneconvergence/plugin.py b/neutron/plugins/oneconvergence/plugin.py index b0c0f3e17f..580a66d3d8 100644 --- a/neutron/plugins/oneconvergence/plugin.py +++ b/neutron/plugins/oneconvergence/plugin.py @@ -23,6 +23,7 @@ from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api from neutron.api.rpc.handlers import dhcp_rpc from neutron.api.rpc.handlers import l3_rpc +from neutron.api.rpc.handlers import securitygroups_rpc from neutron.common import constants as q_const from neutron.common import exceptions as nexception from neutron.common import rpc as n_rpc @@ -51,10 +52,7 @@ LOG = logging.getLogger(__name__) IPv6 = 6 -class NVSDPluginRpcCallbacks(n_rpc.RpcCallback, - sg_db_rpc.SecurityGroupServerRpcCallbackMixin): - - RPC_API_VERSION = '1.1' +class SecurityGroupServerRpcMixin(sg_db_rpc.SecurityGroupServerRpcMixin): @staticmethod def get_port_from_device(device): @@ -88,7 +86,7 @@ class OneConvergencePluginV2(db_base_plugin_v2.NeutronDbPluginV2, external_net_db.External_net_db_mixin, l3_gwmode_db.L3_NAT_db_mixin, portbindings_base.PortBindingBaseMixin, - sg_db_rpc.SecurityGroupServerRpcMixin): + SecurityGroupServerRpcMixin): """L2 Virtual Network Plugin. @@ -159,7 +157,7 @@ class OneConvergencePluginV2(db_base_plugin_v2.NeutronDbPluginV2, self.agent_notifiers[q_const.AGENT_TYPE_L3] = ( l3_rpc_agent_api.L3AgentNotifyAPI() ) - self.endpoints = [NVSDPluginRpcCallbacks(), + self.endpoints = [securitygroups_rpc.SecurityGroupServerRpcCallback(), dhcp_rpc.DhcpRpcCallback(), l3_rpc.L3RpcCallback(), agents_db.AgentExtRpcCallback()] diff --git a/neutron/plugins/openvswitch/ovs_neutron_plugin.py b/neutron/plugins/openvswitch/ovs_neutron_plugin.py index f72a82e365..7dad9b66d9 100644 --- a/neutron/plugins/openvswitch/ovs_neutron_plugin.py +++ b/neutron/plugins/openvswitch/ovs_neutron_plugin.py @@ -22,6 +22,7 @@ from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api from neutron.api.rpc.handlers import dhcp_rpc from neutron.api.rpc.handlers import l3_rpc +from neutron.api.rpc.handlers import securitygroups_rpc from neutron.api.v2 import attributes from neutron.common import constants as q_const from neutron.common import exceptions as n_exc @@ -58,8 +59,7 @@ from neutron.plugins.openvswitch import ovs_db_v2 LOG = logging.getLogger(__name__) -class OVSRpcCallbacks(n_rpc.RpcCallback, - sg_db_rpc.SecurityGroupServerRpcCallbackMixin): +class OVSRpcCallbacks(n_rpc.RpcCallback): # history # 1.0 Initial version @@ -73,13 +73,6 @@ class OVSRpcCallbacks(n_rpc.RpcCallback, self.notifier = notifier self.tunnel_type = tunnel_type - @classmethod - def get_port_from_device(cls, device): - port = ovs_db_v2.get_port_from_device(device) - if port: - port['device'] = device - return port - def get_device_details(self, rpc_context, **kwargs): """Agent requests device details.""" agent_id = kwargs.get('agent_id') @@ -183,6 +176,16 @@ class OVSRpcCallbacks(n_rpc.RpcCallback, return entry +class SecurityGroupServerRpcMixin(sg_db_rpc.SecurityGroupServerRpcMixin): + + @classmethod + def get_port_from_device(cls, device): + port = ovs_db_v2.get_port_from_device(device) + if port: + port['device'] = device + return port + + class AgentNotifierApi(n_rpc.RpcProxy, sg_rpc.SecurityGroupAgentRpcApiMixin): '''Agent side of the openvswitch rpc API. @@ -236,7 +239,7 @@ class OVSNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, external_net_db.External_net_db_mixin, extraroute_db.ExtraRoute_db_mixin, l3_gwmode_db.L3_NAT_db_mixin, - sg_db_rpc.SecurityGroupServerRpcMixin, + SecurityGroupServerRpcMixin, l3_agentschedulers_db.L3AgentSchedulerDbMixin, agentschedulers_db.DhcpAgentSchedulerDbMixin, portbindings_db.PortBindingMixin, @@ -344,6 +347,7 @@ class OVSNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, l3_rpc_agent_api.L3AgentNotifyAPI() ) self.endpoints = [OVSRpcCallbacks(self.notifier, self.tunnel_type), + securitygroups_rpc.SecurityGroupServerRpcCallback(), dhcp_rpc.DhcpRpcCallback(), l3_rpc.L3RpcCallback(), agents_db.AgentExtRpcCallback()] diff --git a/neutron/plugins/ryu/ryu_neutron_plugin.py b/neutron/plugins/ryu/ryu_neutron_plugin.py index cb6ee87804..a6da5df3d5 100644 --- a/neutron/plugins/ryu/ryu_neutron_plugin.py +++ b/neutron/plugins/ryu/ryu_neutron_plugin.py @@ -22,6 +22,7 @@ from ryu.app import rest_nw_id from neutron.agent import securitygroups_rpc as sg_rpc from neutron.api.rpc.handlers import dhcp_rpc from neutron.api.rpc.handlers import l3_rpc +from neutron.api.rpc.handlers import securitygroups_rpc from neutron.common import constants as q_const from neutron.common import exceptions as n_exc from neutron.common import rpc as n_rpc @@ -45,8 +46,17 @@ from neutron.plugins.ryu.db import api_v2 as db_api_v2 LOG = logging.getLogger(__name__) -class RyuRpcCallbacks(n_rpc.RpcCallback, - sg_db_rpc.SecurityGroupServerRpcCallbackMixin): +class SecurityGroupServerRpcMixin(sg_db_rpc.SecurityGroupServerRpcMixin): + + @classmethod + def get_port_from_device(cls, device): + port = db_api_v2.get_port_from_device(device) + if port: + port['device'] = device + return port + + +class RyuRpcCallbacks(n_rpc.RpcCallback): RPC_API_VERSION = '1.1' @@ -58,13 +68,6 @@ class RyuRpcCallbacks(n_rpc.RpcCallback, LOG.debug(_("get_ofp_rest_api: %s"), self.ofp_rest_api_addr) return self.ofp_rest_api_addr - @classmethod - def get_port_from_device(cls, device): - port = db_api_v2.get_port_from_device(device) - if port: - port['device'] = device - return port - class AgentNotifierApi(n_rpc.RpcProxy, sg_rpc.SecurityGroupAgentRpcApiMixin): @@ -88,7 +91,7 @@ class RyuNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, external_net_db.External_net_db_mixin, extraroute_db.ExtraRoute_db_mixin, l3_gwmode_db.L3_NAT_db_mixin, - sg_db_rpc.SecurityGroupServerRpcMixin, + SecurityGroupServerRpcMixin, portbindings_base.PortBindingBaseMixin): _supported_extension_aliases = ["external-net", "router", "ext-gw-mode", @@ -138,6 +141,7 @@ class RyuNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, self.conn = n_rpc.create_connection(new=True) self.notifier = AgentNotifierApi(topics.AGENT) self.endpoints = [RyuRpcCallbacks(self.ofp_api_host), + securitygroups_rpc.SecurityGroupServerRpcCallback(), dhcp_rpc.DhcpRpcCallback(), l3_rpc.L3RpcCallback()] for svc_topic in self.service_topics.values(): diff --git a/neutron/tests/unit/bigswitch/test_security_groups.py b/neutron/tests/unit/bigswitch/test_security_groups.py index 1e3a7aa56f..409e9ce4f4 100644 --- a/neutron/tests/unit/bigswitch/test_security_groups.py +++ b/neutron/tests/unit/bigswitch/test_security_groups.py @@ -36,7 +36,7 @@ class RestProxySecurityGroupsTestCase(test_sg.SecurityGroupDBTestCase, self.startHttpPatch() -class TestSecServerRpcCallBack(test_sg_rpc.SGServerRpcCallBackMixinTestCase, +class TestSecServerRpcCallBack(test_sg_rpc.SGServerRpcCallBackTestCase, RestProxySecurityGroupsTestCase): pass diff --git a/neutron/tests/unit/linuxbridge/test_linuxbridge_plugin.py b/neutron/tests/unit/linuxbridge/test_linuxbridge_plugin.py index 3ff0f7592a..0572336af5 100644 --- a/neutron/tests/unit/linuxbridge/test_linuxbridge_plugin.py +++ b/neutron/tests/unit/linuxbridge/test_linuxbridge_plugin.py @@ -13,8 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import contextlib - import mock from oslo.config import cfg @@ -95,11 +93,9 @@ class TestLinuxBridgePluginRpcCallbacks(test_plugin.NeutronDbPluginV2TestCase): self.callbacks = lb_neutron_plugin.LinuxBridgeRpcCallbacks() def test_update_device_down(self): - with contextlib.nested( - mock.patch.object(self.callbacks, "get_port_from_device", - return_value=None), - mock.patch.object(manager.NeutronManager, "get_plugin") - ) as (gpfd, gp): + with mock.patch.object(manager.NeutronManager, "get_plugin") as gp: + plugin = gp.return_value + plugin.get_port_from_device.return_value = None self.assertEqual( self.callbacks.update_device_down("fake_context", agent_id="123", @@ -107,8 +103,9 @@ class TestLinuxBridgePluginRpcCallbacks(test_plugin.NeutronDbPluginV2TestCase): host="host"), {'device': 'device', 'exists': False} ) - gpfd.return_value = {'id': 'fakeid', - 'status': q_const.PORT_STATUS_ACTIVE} + plugin.get_port_from_device.return_value = { + 'id': 'fakeid', + 'status': q_const.PORT_STATUS_ACTIVE} self.assertEqual( self.callbacks.update_device_down("fake_context", agent_id="123", @@ -118,15 +115,13 @@ class TestLinuxBridgePluginRpcCallbacks(test_plugin.NeutronDbPluginV2TestCase): ) def test_update_device_up(self): - with contextlib.nested( - mock.patch.object(self.callbacks, "get_port_from_device", - return_value=None), - mock.patch.object(manager.NeutronManager, "get_plugin") - ) as (gpfd, gp): - gpfd.return_value = {'id': 'fakeid', - 'status': q_const.PORT_STATUS_ACTIVE} + with mock.patch.object(manager.NeutronManager, "get_plugin") as gp: + plugin = gp.return_value + plugin.get_port_from_device.return_value = { + 'id': 'fakeid', + 'status': q_const.PORT_STATUS_ACTIVE} self.callbacks.update_device_up("fake_context", agent_id="123", device="device", host="host") - gpfd.assert_called_once_with('device') + plugin.get_port_from_device.assert_called_once_with('device') diff --git a/neutron/tests/unit/ml2/test_rpcapi.py b/neutron/tests/unit/ml2/test_rpcapi.py index 71d80d040d..272dcb2f36 100644 --- a/neutron/tests/unit/ml2/test_rpcapi.py +++ b/neutron/tests/unit/ml2/test_rpcapi.py @@ -42,7 +42,8 @@ class RpcCallbacksTestCase(base.BaseTestCase): } def _test_update_device_up(self, extensions, kwargs): - with mock.patch.object(self.callbacks, '_device_to_port_id'): + with mock.patch('neutron.plugins.ml2.plugin.Ml2Plugin' + '._device_to_port_id'): type(self.l3plugin).supported_extension_aliases = ( mock.PropertyMock(return_value=extensions)) self.callbacks.update_device_up(mock.ANY, **kwargs) diff --git a/neutron/tests/unit/ml2/test_security_group.py b/neutron/tests/unit/ml2/test_security_group.py index 3e82c91e4f..39c3cc2bae 100644 --- a/neutron/tests/unit/ml2/test_security_group.py +++ b/neutron/tests/unit/ml2/test_security_group.py @@ -74,8 +74,7 @@ class TestMl2SecurityGroups(Ml2SecurityGroupsTestCase, req.get_response(self.api)) port_id = res['port']['id'] plugin = manager.NeutronManager.get_plugin() - callbacks = plugin.endpoints[0] - port_dict = callbacks.get_port_from_device(port_id) + port_dict = plugin.get_port_from_device(port_id) self.assertEqual(port_id, port_dict['id']) self.assertEqual([security_group_id], port_dict[ext_sg.SECURITYGROUPS]) @@ -86,7 +85,7 @@ class TestMl2SecurityGroups(Ml2SecurityGroupsTestCase, def test_security_group_get_port_from_device_with_no_port(self): plugin = manager.NeutronManager.get_plugin() - port_dict = plugin.endpoints[0].get_port_from_device('bad_device_id') + port_dict = plugin.get_port_from_device('bad_device_id') self.assertIsNone(port_dict) @@ -96,11 +95,11 @@ class TestMl2SecurityGroupsXML(TestMl2SecurityGroups): class TestMl2SGServerRpcCallBack( Ml2SecurityGroupsTestCase, - test_sg_rpc.SGServerRpcCallBackMixinTestCase): + test_sg_rpc.SGServerRpcCallBackTestCase): pass class TestMl2SGServerRpcCallBackXML( Ml2SecurityGroupsTestCase, - test_sg_rpc.SGServerRpcCallBackMixinTestCaseXML): + test_sg_rpc.SGServerRpcCallBackTestCaseXML): pass diff --git a/neutron/tests/unit/nec/test_security_group.py b/neutron/tests/unit/nec/test_security_group.py index fd442c3b24..1d961fa650 100644 --- a/neutron/tests/unit/nec/test_security_group.py +++ b/neutron/tests/unit/nec/test_security_group.py @@ -51,13 +51,13 @@ class NecSecurityGroupsTestCase(test_sg.SecurityGroupDBTestCase): class TestNecSGServerRpcCallBack( - test_sg_rpc.SGServerRpcCallBackMixinTestCase, + test_sg_rpc.SGServerRpcCallBackTestCase, NecSecurityGroupsTestCase): pass class TestNecSGServerRpcCallBackXML( - test_sg_rpc.SGServerRpcCallBackMixinTestCaseXML, + test_sg_rpc.SGServerRpcCallBackTestCaseXML, NecSecurityGroupsTestCase): pass @@ -84,7 +84,7 @@ class TestNecSecurityGroups(NecSecurityGroupsTestCase, req.get_response(self.api)) plugin = manager.NeutronManager.get_plugin() - port_dict = plugin.callback_sg.get_port_from_device(port_id) + port_dict = plugin.get_port_from_device(port_id) self.assertEqual(port_id, port_dict['id']) self.assertEqual([sg_id], port_dict[ext_sg.SECURITYGROUPS]) diff --git a/neutron/tests/unit/oneconvergence/test_security_group.py b/neutron/tests/unit/oneconvergence/test_security_group.py index 93dc0ab4dc..495a30b99d 100644 --- a/neutron/tests/unit/oneconvergence/test_security_group.py +++ b/neutron/tests/unit/oneconvergence/test_security_group.py @@ -68,15 +68,13 @@ class OneConvergenceSecurityGroupsTestCase(test_sg.SecurityGroupDBTestCase): class TestOneConvergenceSGServerRpcCallBack( OneConvergenceSecurityGroupsTestCase, - test_sg_rpc.SGServerRpcCallBackMixinTestCase): - + test_sg_rpc.SGServerRpcCallBackTestCase): pass class TestOneConvergenceSGServerRpcCallBackXML( OneConvergenceSecurityGroupsTestCase, - test_sg_rpc.SGServerRpcCallBackMixinTestCaseXML): - + test_sg_rpc.SGServerRpcCallBackTestCaseXML): pass @@ -103,8 +101,7 @@ class TestOneConvergenceSecurityGroups(OneConvergenceSecurityGroupsTestCase, req.get_response(self.api)) port_id = res['port']['id'] plugin = manager.NeutronManager.get_plugin() - callbacks = plugin.endpoints[0] - port_dict = callbacks.get_port_from_device(port_id) + port_dict = plugin.get_port_from_device(port_id) self.assertEqual(port_id, port_dict['id']) self.assertEqual([security_group_id], port_dict[ext_sg.SECURITYGROUPS]) @@ -116,7 +113,7 @@ class TestOneConvergenceSecurityGroups(OneConvergenceSecurityGroupsTestCase, def test_security_group_get_port_from_device_with_no_port(self): plugin = manager.NeutronManager.get_plugin() - port_dict = plugin.endpoints[0].get_port_from_device('bad_device_id') + port_dict = plugin.get_port_from_device('bad_device_id') self.assertIsNone(port_dict) diff --git a/neutron/tests/unit/openvswitch/test_ovs_security_group.py b/neutron/tests/unit/openvswitch/test_ovs_security_group.py index 05acdc5dec..83f91cb7b9 100644 --- a/neutron/tests/unit/openvswitch/test_ovs_security_group.py +++ b/neutron/tests/unit/openvswitch/test_ovs_security_group.py @@ -50,13 +50,13 @@ class OpenvswitchSecurityGroupsTestCase(test_sg.SecurityGroupDBTestCase): class TestOpenvswitchSGServerRpcCallBack( OpenvswitchSecurityGroupsTestCase, - test_sg_rpc.SGServerRpcCallBackMixinTestCase): + test_sg_rpc.SGServerRpcCallBackTestCase): pass class TestOpenvswitchSGServerRpcCallBackXML( OpenvswitchSecurityGroupsTestCase, - test_sg_rpc.SGServerRpcCallBackMixinTestCaseXML): + test_sg_rpc.SGServerRpcCallBackTestCaseXML): pass @@ -82,8 +82,7 @@ class TestOpenvswitchSecurityGroups(OpenvswitchSecurityGroupsTestCase, req.get_response(self.api)) port_id = res['port']['id'] plugin = manager.NeutronManager.get_plugin() - callbacks = plugin.endpoints[0] - port_dict = callbacks.get_port_from_device(port_id) + port_dict = plugin.get_port_from_device(port_id) self.assertEqual(port_id, port_dict['id']) self.assertEqual([security_group_id], port_dict[ext_sg.SECURITYGROUPS]) @@ -94,7 +93,7 @@ class TestOpenvswitchSecurityGroups(OpenvswitchSecurityGroupsTestCase, def test_security_group_get_port_from_device_with_no_port(self): plugin = manager.NeutronManager.get_plugin() - port_dict = plugin.endpoints[0].get_port_from_device('bad_device_id') + port_dict = plugin.get_port_from_device('bad_device_id') self.assertIsNone(port_dict) diff --git a/neutron/tests/unit/ryu/test_ryu_security_group.py b/neutron/tests/unit/ryu/test_ryu_security_group.py index 5e1c1ecd6c..8939c79b06 100644 --- a/neutron/tests/unit/ryu/test_ryu_security_group.py +++ b/neutron/tests/unit/ryu/test_ryu_security_group.py @@ -71,7 +71,7 @@ class TestRyuSecurityGroups(RyuSecurityGroupsTestCase, req.get_response(self.api)) port_id = res['port']['id'] plugin = manager.NeutronManager.get_plugin() - port_dict = plugin.endpoints[0].get_port_from_device(port_id) + port_dict = plugin.get_port_from_device(port_id) self.assertEqual(port_id, port_dict['id']) self.assertEqual([security_group_id], port_dict[ext_sg.SECURITYGROUPS]) @@ -82,7 +82,7 @@ class TestRyuSecurityGroups(RyuSecurityGroupsTestCase, def test_security_group_get_port_from_device_with_no_port(self): plugin = manager.NeutronManager.get_plugin() - port_dict = plugin.endpoints[0].get_port_from_device('bad_device_id') + port_dict = plugin.get_port_from_device('bad_device_id') self.assertIsNone(port_dict) diff --git a/neutron/tests/unit/test_security_groups_rpc.py b/neutron/tests/unit/test_security_groups_rpc.py index 81a43ea5bf..695a744871 100644 --- a/neutron/tests/unit/test_security_groups_rpc.py +++ b/neutron/tests/unit/test_security_groups_rpc.py @@ -25,6 +25,7 @@ from neutron.agent import firewall as firewall_base from neutron.agent.linux import iptables_manager from neutron.agent import rpc as agent_rpc from neutron.agent import securitygroups_rpc as sg_rpc +from neutron.api.rpc.handlers import securitygroups_rpc from neutron.common import constants as const from neutron.common import ipv6_utils as ipv6 from neutron.common import rpc as n_rpc @@ -45,7 +46,38 @@ FAKE_IP = {const.IPv4: '10.0.0.1', 'IPv6_LLA': 'fe80::123'} -class FakeSGCallback(sg_db_rpc.SecurityGroupServerRpcCallbackMixin): +TEST_PLUGIN_CLASS = ('neutron.tests.unit.test_security_groups_rpc.' + 'SecurityGroupRpcTestPlugin') + + +class SecurityGroupRpcTestPlugin(test_sg.SecurityGroupTestPlugin, + sg_db_rpc.SecurityGroupServerRpcMixin): + def __init__(self): + super(SecurityGroupRpcTestPlugin, self).__init__() + self.notifier = mock.Mock() + self.devices = {} + + def create_port(self, context, port): + result = super(SecurityGroupRpcTestPlugin, + self).create_port(context, port) + self.devices[result['id']] = result + self.notify_security_groups_member_updated(context, result) + return result + + def update_port(self, context, id, port): + original_port = self.get_port(context, id) + updated_port = super(SecurityGroupRpcTestPlugin, + self).update_port(context, id, port) + self.devices[id] = updated_port + self.update_security_group_on_port( + context, id, port, original_port, updated_port) + + def delete_port(self, context, id): + port = self.get_port(context, id) + super(SecurityGroupRpcTestPlugin, self).delete_port(context, id) + self.notify_security_groups_member_updated(context, port) + del self.devices[id] + def get_port_from_device(self, device): device = self.devices.get(device) if device: @@ -56,13 +88,15 @@ class FakeSGCallback(sg_db_rpc.SecurityGroupServerRpcCallbackMixin): return device -class SGServerRpcCallBackMixinTestCase(test_sg.SecurityGroupDBTestCase): +class SGServerRpcCallBackTestCase(test_sg.SecurityGroupDBTestCase): def setUp(self, plugin=None): + plugin = plugin or TEST_PLUGIN_CLASS cfg.CONF.set_default('firewall_driver', 'neutron.agent.firewall.NoopFirewallDriver', group='SECURITYGROUP') - super(SGServerRpcCallBackMixinTestCase, self).setUp(plugin) - self.rpc = FakeSGCallback() + super(SGServerRpcCallBackTestCase, self).setUp(plugin) + self.notifier = manager.NeutronManager.get_plugin().notifier + self.rpc = securitygroups_rpc.SecurityGroupServerRpcCallback() def _test_security_group_port(self, device_owner, gw_ip, cidr, ip_version, ip_address): @@ -71,93 +105,73 @@ class SGServerRpcCallBackMixinTestCase(test_sg.SecurityGroupDBTestCase): gateway_ip=gw_ip, cidr=cidr, ip_version=ip_version) as subnet: - with mock.patch.object( - self.notifier, - 'security_groups_provider_updated') as mock_notifier: - kwargs = { - 'fixed_ips': [{'subnet_id': subnet['subnet']['id'], - 'ip_address': ip_address}]} - if device_owner: - kwargs['device_owner'] = device_owner - res = self._create_port( - self.fmt, net['network']['id'], **kwargs) - res = self.deserialize(self.fmt, res) - port_id = res['port']['id'] - if device_owner == const.DEVICE_OWNER_ROUTER_INTF: - data = {'port': {'fixed_ips': []}} - req = self.new_update_request('ports', data, port_id) - res = self.deserialize(self.fmt, - req.get_response(self.api)) - self._delete('ports', port_id) - return mock_notifier + kwargs = { + 'fixed_ips': [{'subnet_id': subnet['subnet']['id'], + 'ip_address': ip_address}]} + if device_owner: + kwargs['device_owner'] = device_owner + res = self._create_port( + self.fmt, net['network']['id'], **kwargs) + res = self.deserialize(self.fmt, res) + port_id = res['port']['id'] + if device_owner == const.DEVICE_OWNER_ROUTER_INTF: + data = {'port': {'fixed_ips': []}} + req = self.new_update_request('ports', data, port_id) + res = self.deserialize(self.fmt, + req.get_response(self.api)) + self._delete('ports', port_id) def test_notify_security_group_ipv6_gateway_port_added(self): - if getattr(self, "notifier", None) is None: - self.skipTest("Notifier mock is not set so security group " - "RPC calls can't be tested") - - mock_notifier = self._test_security_group_port( + self._test_security_group_port( const.DEVICE_OWNER_ROUTER_INTF, '2001:0db8::1', '2001:0db8::/64', 6, '2001:0db8::1') - self.assertTrue(mock_notifier.called) + self.assertTrue(self.notifier.security_groups_provider_updated.called) def test_notify_security_group_ipv6_normal_port_added(self): - if getattr(self, "notifier", None) is None: - self.skipTest("Notifier mock is not set so security group " - "RPC calls can't be tested") - mock_notifier = self._test_security_group_port( + self._test_security_group_port( None, '2001:0db8::1', '2001:0db8::/64', 6, '2001:0db8::3') - self.assertFalse(mock_notifier.called) + self.assertFalse(self.notifier.security_groups_provider_updated.called) def test_notify_security_group_ipv4_dhcp_port_added(self): - if getattr(self, "notifier", None) is None: - self.skipTest("Notifier mock is not set so security group " - "RPC calls can't be tested") - mock_notifier = self._test_security_group_port( + self._test_security_group_port( const.DEVICE_OWNER_DHCP, '192.168.1.1', '192.168.1.0/24', 4, '192.168.1.2') - self.assertTrue(mock_notifier.called) + self.assertTrue(self.notifier.security_groups_provider_updated.called) def test_notify_security_group_ipv4_gateway_port_added(self): - if getattr(self, "notifier", None) is None: - self.skipTest("Notifier mock is not set so security group " - "RPC calls can't be tested") - mock_notifier = self._test_security_group_port( + self._test_security_group_port( const.DEVICE_OWNER_ROUTER_INTF, '192.168.1.1', '192.168.1.0/24', 4, '192.168.1.1') - self.assertFalse(mock_notifier.called) + self.assertFalse(self.notifier.security_groups_provider_updated.called) def test_notify_security_group_ipv4_normal_port_added(self): - if getattr(self, "notifier", None) is None: - self.skipTest("Notifier mock is not set so security group " - "RPC calls can't be tested") - mock_notifier = self._test_security_group_port( + self._test_security_group_port( None, '192.168.1.1', '192.168.1.0/24', 4, '192.168.1.3') - self.assertFalse(mock_notifier.called) + self.assertFalse(self.notifier.security_groups_provider_updated.called) def test_security_group_rules_for_devices_ipv4_ingress(self): fake_prefix = FAKE_PREFIX[const.IPv4] with self.network() as n: - with contextlib.nested(self.subnet(n), - self.security_group()) as (subnet_v4, - sg1): + with contextlib.nested( + self.subnet(n), + self.security_group()) as (subnet_v4, sg1): sg1_id = sg1['security_group']['id'] rule1 = self._build_security_group_rule( sg1_id, @@ -829,7 +843,7 @@ class SGServerRpcCallBackMixinTestCase(test_sg.SecurityGroupDBTestCase): self._delete('ports', port_id2) -class SGServerRpcCallBackMixinTestCaseXML(SGServerRpcCallBackMixinTestCase): +class SGServerRpcCallBackTestCaseXML(SGServerRpcCallBackTestCase): fmt = 'xml'