API's and implementations to support L2 Gateways in Neutron.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
networking-l2gw/networking_l2gw/services/l2gateway/agent_scheduler.py

137 lines
5.3 KiB

# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
# 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.
import random
from neutron_lib.plugins import directory
from oslo_config import cfg
from oslo_log import log as logging
from oslo_service import loopingcall
from neutron.agent.common import utils
from neutron.db import agents_db
from neutron_lib import context as neutron_context
from networking_l2gw.services.l2gateway.common import config
from networking_l2gw.services.l2gateway.common import constants as srv_const
LOG = logging.getLogger(__name__)
class L2GatewayAgentScheduler(agents_db.AgentDbMixin):
"""L2gateway agent scheduler class.
This maintains active and inactive agents and
select monitor and transact agents.
"""
_plugin = None
_l2gwplugin = None
def __init__(self, agent_rpc, notifier=None):
super(L2GatewayAgentScheduler, self).__init__()
self.notifier = notifier
config.register_l2gw_opts_helper()
self.monitor_interval = cfg.CONF.periodic_monitoring_interval
self.agent_rpc = agent_rpc
@property
def l2gwplugin(self):
if self._l2gwplugin is None:
self._l2gwplugin = directory.get_plugin(srv_const.L2GW)
return self._l2gwplugin
@property
def plugin(self):
if self._plugin is None:
self._plugin = directory.get_plugin()
return self._plugin
def initialize_thread(self):
"""Initialization of L2gateway agent scheduler thread."""
try:
monitor_thread = loopingcall.FixedIntervalLoopingCall(
self.monitor_agent_state)
monitor_thread.start(
interval=self.monitor_interval,
initial_delay=random.randint(self.monitor_interval,
self.monitor_interval * 2))
LOG.debug("Successfully initialized L2gateway agent scheduler"
" thread with loop interval %s", self.monitor_interval)
except Exception:
LOG.error("Cannot initialize agent scheduler thread")
def _select_agent_type(self, context, agents_to_process):
"""Select the Monitor agent."""
# Various cases to be handled:
# 1. Check if there is a single active L2 gateway agent.
# If only one agent is active, then make it the Monitor agent.
# 2. Else, in the list of the active agents, if there does not
# exist Monitor agent, then make the agent that
# started first as the Monitor agent.
# 3. If multiple Monitor agents exist (case where the Monitor agent
# gets disconnected from the Neutron server and another agent
# becomes the Monitor agent and then the original Monitor agent
# connects back within the agent downtime value), then we need to
# send the fanout message so that only one becomes the Monitor
# agent.
# Check if there already exists Monitor agent and it's the only one.
monitor_agents = [
x for x in agents_to_process
if x['configurations'].get(srv_const.L2GW_AGENT_TYPE) ==
srv_const.MONITOR]
if len(monitor_agents) == 1:
return
# We either have more than one Monitor agent,
# or there does not exist Monitor agent.
# We will decide which agent should be the Monitor agent.
chosen_agent = None
if len(agents_to_process) == 1:
# Only one agent is configured.
# Make it the Monitor agent
chosen_agent = agents_to_process[0]
else:
# Select the agent with the oldest started_at
# timestamp as the Monitor agent.
sorted_active_agents = sorted(agents_to_process,
key=lambda k: k['started_at'])
chosen_agent = sorted_active_agents[0]
self.agent_rpc.set_monitor_agent(context, chosen_agent['host'])
def monitor_agent_state(self):
"""Represents L2gateway agent scheduler thread.
Maintains list of active and inactive agents based on
the heartbeat recorded.
"""
context = neutron_context.get_admin_context()
try:
all_agents = self.plugin.get_agents(
context,
filters={'agent_type': [srv_const.AGENT_TYPE_L2GATEWAY]})
except Exception:
LOG.exception("Unable to get the agent list. Continuing...")
return
# Reset the agents that will be processed for selecting the
# Monitor agent
agents_to_process = []
for agent in all_agents:
if not utils.is_agent_down(agent['heartbeat_timestamp']):
agents_to_process.append(agent)
if agents_to_process:
self._select_agent_type(context, agents_to_process)
return