Enable rpc notifications only when rpc_workers >= 1

rpc_workers can be set < 1 with 'ovn' backend when no
other agent is running apart from ovn agents to
consume these rpc notifications.

Add and apply disable_notifications decorator on
methods which do rpc cast calls to agents, the
decorator makes the caller method execute only
when rpc_workers >=1. This patch not changing
default behavior and utilizes the rpc_workers config option
to enable rpc notification on resources updates only when
rpc_workers >= 1.

Also set rpc_workers=0 in ovn jobs to cover this scenario.

Closes-Bug: #1889737
Closes-Bug: #1992352
Change-Id: I700fe2cd422bc1eb8b5144ec116e7f0a60238419
This commit is contained in:
yatinkarel 2022-01-06 04:49:03 +00:00
parent 1374b01cfb
commit 3e1e2d63b3
8 changed files with 65 additions and 3 deletions

View File

@ -28,6 +28,8 @@ from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
import oslo_messaging import oslo_messaging
from neutron.common import utils
# Priorities - lower value is higher priority # Priorities - lower value is higher priority
PRIORITY_NETWORK_CREATE = 0 PRIORITY_NETWORK_CREATE = 0
@ -87,6 +89,8 @@ class DhcpAgentNotifyAPI(object):
self._plugin = plugin self._plugin = plugin
target = oslo_messaging.Target(topic=topic, version='1.0') target = oslo_messaging.Target(topic=topic, version='1.0')
self.client = n_rpc.get_client(target) self.client = n_rpc.get_client(target)
if not cfg.CONF.dhcp_agent_notification:
return
# register callbacks for router interface changes # register callbacks for router interface changes
registry.subscribe(self._after_router_interface_created, registry.subscribe(self._after_router_interface_created,
resources.ROUTER_INTERFACE, events.AFTER_CREATE) resources.ROUTER_INTERFACE, events.AFTER_CREATE)
@ -101,8 +105,6 @@ class DhcpAgentNotifyAPI(object):
resources.SUBNET, resources.SUBNET,
resources.SUBNETS, resources.SUBNETS,
) )
if not cfg.CONF.dhcp_agent_notification:
return
for resource in callback_resources: for resource in callback_resources:
registry.subscribe(self._send_dhcp_notification, registry.subscribe(self._send_dhcp_notification,
resource, events.BEFORE_RESPONSE) resource, events.BEFORE_RESPONSE)
@ -182,6 +184,7 @@ class DhcpAgentNotifyAPI(object):
def _is_reserved_dhcp_port(self, port): def _is_reserved_dhcp_port(self, port):
return port.get('device_id') == constants.DEVICE_ID_RESERVED_DHCP_PORT return port.get('device_id') == constants.DEVICE_ID_RESERVED_DHCP_PORT
@utils.disable_notifications
def _notify_agents( def _notify_agents(
self, context, method, payload, network_id, network=None): self, context, method, payload, network_id, network=None):
"""Notify all the agents that are hosting the network.""" """Notify all the agents that are hosting the network."""
@ -242,12 +245,14 @@ class DhcpAgentNotifyAPI(object):
self._cast_message(context, "port_create_end", self._cast_message(context, "port_create_end",
payload, agent.host, agent.topic) payload, agent.host, agent.topic)
@utils.disable_notifications
def _cast_message(self, context, method, payload, host, def _cast_message(self, context, method, payload, host,
topic=topics.DHCP_AGENT): topic=topics.DHCP_AGENT):
"""Cast the payload to the dhcp agent running on the host.""" """Cast the payload to the dhcp agent running on the host."""
cctxt = self.client.prepare(topic=topic, server=host) cctxt = self.client.prepare(topic=topic, server=host)
cctxt.cast(context, method, payload=payload) cctxt.cast(context, method, payload=payload)
@utils.disable_notifications
def _fanout_message(self, context, method, payload): def _fanout_message(self, context, method, payload):
"""Fanout the payload to all dhcp agents.""" """Fanout the payload to all dhcp agents."""
cctxt = self.client.prepare(fanout=True) cctxt = self.client.prepare(fanout=True)

View File

@ -25,6 +25,7 @@ from oslo_log import log as logging
import oslo_messaging import oslo_messaging
from neutron.api.rpc.agentnotifiers import utils as ag_utils from neutron.api.rpc.agentnotifiers import utils as ag_utils
from neutron.common import utils
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -41,6 +42,7 @@ class L3AgentNotifyAPI(object):
target = oslo_messaging.Target(topic=topic, version='1.0') target = oslo_messaging.Target(topic=topic, version='1.0')
self.client = n_rpc.get_client(target) self.client = n_rpc.get_client(target)
@utils.disable_notifications
def _notification_host(self, context, method, host, use_call=False, def _notification_host(self, context, method, host, use_call=False,
**kwargs): **kwargs):
"""Notify the agent that is hosting the router.""" """Notify the agent that is hosting the router."""
@ -52,6 +54,7 @@ class L3AgentNotifyAPI(object):
if use_call else cctxt.cast) if use_call else cctxt.cast)
rpc_method(context, method, **kwargs) rpc_method(context, method, **kwargs)
@utils.disable_notifications
def _agent_notification(self, context, method, router_ids, operation, def _agent_notification(self, context, method, router_ids, operation,
shuffle_agents): shuffle_agents):
"""Notify changed routers to hosting l3 agents.""" """Notify changed routers to hosting l3 agents."""
@ -72,6 +75,7 @@ class L3AgentNotifyAPI(object):
version='1.1') version='1.1')
cctxt.cast(context, method, routers=[router_id]) cctxt.cast(context, method, routers=[router_id])
@utils.disable_notifications
def _agent_notification_arp(self, context, method, router_id, def _agent_notification_arp(self, context, method, router_id,
operation, data): operation, data):
"""Notify arp details to l3 agents hosting router.""" """Notify arp details to l3 agents hosting router."""
@ -82,6 +86,7 @@ class L3AgentNotifyAPI(object):
cctxt = self.client.prepare(fanout=True, version='1.2') cctxt = self.client.prepare(fanout=True, version='1.2')
cctxt.cast(context, method, payload=dvr_arptable) cctxt.cast(context, method, payload=dvr_arptable)
@utils.disable_notifications
def _notification(self, context, method, router_ids, operation, def _notification(self, context, method, router_ids, operation,
shuffle_agents, schedule_routers=True): shuffle_agents, schedule_routers=True):
"""Notify all the agents that are hosting the routers.""" """Notify all the agents that are hosting the routers."""
@ -102,6 +107,7 @@ class L3AgentNotifyAPI(object):
cctxt = self.client.prepare(fanout=True) cctxt = self.client.prepare(fanout=True)
cctxt.cast(context, method, routers=router_ids) cctxt.cast(context, method, routers=router_ids)
@utils.disable_notifications
def _notification_fanout(self, context, method, router_id=None, **kwargs): def _notification_fanout(self, context, method, router_id=None, **kwargs):
"""Fanout the information to all L3 agents. """Fanout the information to all L3 agents.

View File

@ -27,6 +27,7 @@ from oslo_utils import versionutils
from neutron.api.rpc.callbacks import resources from neutron.api.rpc.callbacks import resources
from neutron.api.rpc.handlers import resources_rpc from neutron.api.rpc.handlers import resources_rpc
from neutron.common import utils
from neutron.db import securitygroups_rpc_base as sg_rpc_base from neutron.db import securitygroups_rpc_base as sg_rpc_base
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -169,6 +170,7 @@ class SecurityGroupAgentRpcApiMixin(object):
topics.SECURITY_GROUP, topics.SECURITY_GROUP,
topics.UPDATE) topics.UPDATE)
@utils.disable_notifications
def security_groups_rule_updated(self, context, security_groups): def security_groups_rule_updated(self, context, security_groups):
"""Notify rule updated security groups.""" """Notify rule updated security groups."""
if not security_groups: if not security_groups:
@ -179,6 +181,7 @@ class SecurityGroupAgentRpcApiMixin(object):
cctxt.cast(context, 'security_groups_rule_updated', cctxt.cast(context, 'security_groups_rule_updated',
security_groups=security_groups) security_groups=security_groups)
@utils.disable_notifications
def security_groups_member_updated(self, context, security_groups): def security_groups_member_updated(self, context, security_groups):
"""Notify member updated security groups.""" """Notify member updated security groups."""
if not security_groups: if not security_groups:

View File

@ -1031,6 +1031,16 @@ def get_az_hints(resource):
cfg.CONF.default_availability_zones) cfg.CONF.default_availability_zones)
def disable_notifications(function):
"""Decorator to disable notifications"""
@functools.wraps(function)
def wrapper(*args, **kwargs):
if cfg.CONF.rpc_workers is None or cfg.CONF.rpc_workers >= 1:
return function(*args, **kwargs)
return wrapper
def skip_exceptions(exceptions): def skip_exceptions(exceptions):
"""Decorator to catch and hide any provided exception in the argument""" """Decorator to catch and hide any provided exception in the argument"""

View File

@ -400,7 +400,9 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
@log_helpers.log_method_call @log_helpers.log_method_call
def _start_rpc_notifiers(self): def _start_rpc_notifiers(self):
"""Initialize RPC notifiers for agents.""" """Initialize RPC notifiers for agents."""
self.ovo_notifier = ovo_rpc.OVOServerRpcInterface() self.ovo_notifier = None
if cfg.CONF.rpc_workers is None or cfg.CONF.rpc_workers >= 1:
self.ovo_notifier = ovo_rpc.OVOServerRpcInterface()
self.notifier = rpc.AgentNotifierApi(topics.AGENT) self.notifier = rpc.AgentNotifierApi(topics.AGENT)
if cfg.CONF.enable_traditional_dhcp: if cfg.CONF.enable_traditional_dhcp:
self.agent_notifiers[const.AGENT_TYPE_DHCP] = ( self.agent_notifiers[const.AGENT_TYPE_DHCP] = (

View File

@ -31,6 +31,7 @@ from sqlalchemy.orm import exc
from neutron.api.rpc.handlers import dvr_rpc from neutron.api.rpc.handlers import dvr_rpc
from neutron.api.rpc.handlers import securitygroups_rpc as sg_rpc from neutron.api.rpc.handlers import securitygroups_rpc as sg_rpc
from neutron.common import utils
from neutron.db import l3_hamode_db from neutron.db import l3_hamode_db
from neutron.db import provisioning_blocks from neutron.db import provisioning_blocks
from neutron.plugins.ml2 import db as ml2_db from neutron.plugins.ml2 import db as ml2_db
@ -475,11 +476,13 @@ class AgentNotifierApi(dvr_rpc.DVRAgentRpcApiMixin,
target = oslo_messaging.Target(topic=topic, version='1.0') target = oslo_messaging.Target(topic=topic, version='1.0')
self.client = n_rpc.get_client(target) self.client = n_rpc.get_client(target)
@utils.disable_notifications
def network_delete(self, context, network_id): def network_delete(self, context, network_id):
cctxt = self.client.prepare(topic=self.topic_network_delete, cctxt = self.client.prepare(topic=self.topic_network_delete,
fanout=True) fanout=True)
cctxt.cast(context, 'network_delete', network_id=network_id) cctxt.cast(context, 'network_delete', network_id=network_id)
@utils.disable_notifications
def port_update(self, context, port, network_type, segmentation_id, def port_update(self, context, port, network_type, segmentation_id,
physical_network): physical_network):
cctxt = self.client.prepare(topic=self.topic_port_update, cctxt = self.client.prepare(topic=self.topic_port_update,
@ -488,22 +491,26 @@ class AgentNotifierApi(dvr_rpc.DVRAgentRpcApiMixin,
network_type=network_type, segmentation_id=segmentation_id, network_type=network_type, segmentation_id=segmentation_id,
physical_network=physical_network) physical_network=physical_network)
@utils.disable_notifications
def port_delete(self, context, port_id): def port_delete(self, context, port_id):
cctxt = self.client.prepare(topic=self.topic_port_delete, cctxt = self.client.prepare(topic=self.topic_port_delete,
fanout=True) fanout=True)
cctxt.cast(context, 'port_delete', port_id=port_id) cctxt.cast(context, 'port_delete', port_id=port_id)
@utils.disable_notifications
def network_update(self, context, network): def network_update(self, context, network):
cctxt = self.client.prepare(topic=self.topic_network_update, cctxt = self.client.prepare(topic=self.topic_network_update,
fanout=True, version='1.4') fanout=True, version='1.4')
cctxt.cast(context, 'network_update', network=network) cctxt.cast(context, 'network_update', network=network)
@utils.disable_notifications
def binding_deactivate(self, context, port_id, host, network_id): def binding_deactivate(self, context, port_id, host, network_id):
cctxt = self.client.prepare(topic=self.topic_port_binding_deactivate, cctxt = self.client.prepare(topic=self.topic_port_binding_deactivate,
fanout=True, version='1.5') fanout=True, version='1.5')
cctxt.cast(context, 'binding_deactivate', port_id=port_id, host=host, cctxt.cast(context, 'binding_deactivate', port_id=port_id, host=host,
network_id=network_id) network_id=network_id)
@utils.disable_notifications
def binding_activate(self, context, port_id, host): def binding_activate(self, context, port_id, host):
cctxt = self.client.prepare(topic=self.topic_port_binding_activate, cctxt = self.client.prepare(topic=self.topic_port_binding_activate,
fanout=True, version='1.5') fanout=True, version='1.5')

View File

@ -23,6 +23,7 @@ import eventlet
from eventlet import queue from eventlet import queue
import netaddr import netaddr
from neutron_lib import constants from neutron_lib import constants
from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from osprofiler import profiler from osprofiler import profiler
import testscenarios import testscenarios
@ -627,6 +628,25 @@ class SkipDecoratorTestCase(base.BaseTestCase):
self.assertRaises(AttributeError, raise_attribute_error) self.assertRaises(AttributeError, raise_attribute_error)
class DisableNotificationTestCase(base.BaseTestCase):
@utils.disable_notifications
def sample_method(self):
raise AttributeError()
def test_notification_rpc_workers_lt_one(self):
cfg.CONF.set_override('rpc_workers', 0)
self.assertIsNone(self.sample_method())
def test_notification_rpc_workers_none(self):
cfg.CONF.set_override('rpc_workers', None)
self.assertRaises(AttributeError, self.sample_method)
def test_notification_rpc_workers_one(self):
cfg.CONF.set_override('rpc_workers', 1)
self.assertRaises(AttributeError, self.sample_method)
class SignatureTestCase(base.BaseTestCase): class SignatureTestCase(base.BaseTestCase):
def test_sign_instance_id(self): def test_sign_instance_id(self):

View File

@ -477,6 +477,10 @@
$TEMPEST_CONFIG: $TEMPEST_CONFIG:
neutron_plugin_options: neutron_plugin_options:
is_igmp_snooping_enabled: True is_igmp_snooping_enabled: True
post-config:
$NEUTRON_CONF:
DEFAULT:
rpc_workers: 0
devstack_localrc: devstack_localrc:
CIRROS_VERSION: 0.5.1 CIRROS_VERSION: 0.5.1
DEFAULT_IMAGE_NAME: cirros-0.5.1-x86_64-uec DEFAULT_IMAGE_NAME: cirros-0.5.1-x86_64-uec
@ -723,6 +727,11 @@
s-container: false s-container: false
s-object: false s-object: false
s-proxy: false s-proxy: false
devstack_local_conf:
post-config:
$NEUTRON_CONF:
DEFAULT:
rpc_workers: 0
zuul_copy_output: zuul_copy_output:
'/var/log/ovn': 'logs' '/var/log/ovn': 'logs'
'/var/log/openvswitch': 'logs' '/var/log/openvswitch': 'logs'