Merge "Schedule networks to new segments if needed" into stable/queens

This commit is contained in:
Zuul 2021-03-27 17:53:59 +00:00 committed by Gerrit Code Review
commit 8c6af33cde
2 changed files with 71 additions and 1 deletions

View File

@ -17,9 +17,13 @@ import datetime
import random import random
import time import time
from neutron_lib.callbacks import events
from neutron_lib.callbacks import registry
from neutron_lib.callbacks import resources
from neutron_lib import constants from neutron_lib import constants
from neutron_lib import context as ncontext from neutron_lib import context as ncontext
from neutron_lib.exceptions import agent as agent_exc from neutron_lib.exceptions import agent as agent_exc
from neutron_lib.plugins import directory
from oslo_config import cfg 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
@ -33,6 +37,7 @@ from neutron.db import agents_db
from neutron.db.availability_zone import network as network_az from neutron.db.availability_zone import network as network_az
from neutron.extensions import dhcpagentscheduler from neutron.extensions import dhcpagentscheduler
from neutron.objects import network from neutron.objects import network
from neutron.objects import subnet as subnet_obj
from neutron import worker as neutron_worker from neutron import worker as neutron_worker
@ -218,12 +223,15 @@ class DhcpAgentSchedulerDbMixin(dhcpagentscheduler
additional_time) additional_time)
return agent_expected_up > timeutils.utcnow() return agent_expected_up > timeutils.utcnow()
def _schedule_network(self, context, network_id, dhcp_notifier): def _schedule_network(self, context, network_id, dhcp_notifier,
candidate_hosts=None):
LOG.info("Scheduling unhosted network %s", network_id) LOG.info("Scheduling unhosted network %s", network_id)
try: try:
# TODO(enikanorov): have to issue redundant db query # TODO(enikanorov): have to issue redundant db query
# to satisfy scheduling interface # to satisfy scheduling interface
network = self.get_network(context, network_id) network = self.get_network(context, network_id)
if candidate_hosts:
network['candidate_hosts'] = candidate_hosts
agents = self.schedule_network(context, network) agents = self.schedule_network(context, network)
if not agents: if not agents:
LOG.info("Failed to schedule network %s, " LOG.info("Failed to schedule network %s, "
@ -470,6 +478,25 @@ class DhcpAgentSchedulerDbMixin(dhcpagentscheduler
if self.network_scheduler: if self.network_scheduler:
self.network_scheduler.auto_schedule_networks(self, context, host) self.network_scheduler.auto_schedule_networks(self, context, host)
@registry.receives(resources.SEGMENT_HOST_MAPPING, [events.AFTER_CREATE])
def auto_schedule_new_network_segments(self, resource, event, trigger,
payload=None):
if not cfg.CONF.network_auto_schedule:
return
segment_plugin = directory.get_plugin('segments')
dhcp_notifier = self.agent_notifiers.get(constants.AGENT_TYPE_DHCP)
segment_ids = payload.metadata.get('current_segment_ids')
segments = segment_plugin.get_segments(
payload.context, filters={'id': segment_ids})
subnets = subnet_obj.Subnet.get_objects(
payload.context, segment_id=segment_ids)
network_ids = {s.network_id for s in subnets}
for network_id in network_ids:
for segment in segments:
self._schedule_network(
payload.context, network_id, dhcp_notifier,
candidate_hosts=segment['hosts'])
class AZDhcpAgentSchedulerDbMixin(DhcpAgentSchedulerDbMixin, class AZDhcpAgentSchedulerDbMixin(DhcpAgentSchedulerDbMixin,
network_az.NetworkAvailabilityZoneMixin): network_az.NetworkAvailabilityZoneMixin):

View File

@ -17,6 +17,8 @@ import datetime
import mock import mock
from neutron_lib.api.definitions import portbindings from neutron_lib.api.definitions import portbindings
from neutron_lib.callbacks import events
from neutron_lib.callbacks import resources
from neutron_lib import constants from neutron_lib import constants
from neutron_lib import context from neutron_lib import context
from neutron_lib.plugins import constants as plugin_constants from neutron_lib.plugins import constants as plugin_constants
@ -1492,6 +1494,47 @@ class OvsDhcpAgentNotifierTestCase(test_agent.AgentDBTestMixIn,
for expected in low_expecteds: for expected in low_expecteds:
self.assertIn(expected, self.dhcp_notifier_cast.call_args_list) self.assertIn(expected, self.dhcp_notifier_cast.call_args_list)
def _test_auto_schedule_new_network_segments(self, subnet_on_segment):
ctx = mock.Mock()
payload = events.DBEventPayload(
ctx,
metadata={'host': 'HOST A',
'current_segment_ids': set(['segment-1'])})
segments_plugin = mock.Mock()
segments_plugin.get_segments.return_value = [
{'id': 'segment-1', 'hosts': ['HOST A']}]
dhcp_notifier = mock.Mock()
dhcp_mixin = agentschedulers_db.DhcpAgentSchedulerDbMixin()
with mock.patch(
'neutron_lib.plugins.directory.get_plugin',
return_value=segments_plugin), \
mock.patch(
'neutron.objects.subnet.Subnet.get_objects') as get_subnets, \
mock.patch.object(
dhcp_mixin, '_schedule_network') as schedule_network:
get_subnets.return_value = (
[subnet_on_segment] if subnet_on_segment else [])
dhcp_mixin.agent_notifiers[constants.AGENT_TYPE_DHCP] = (
dhcp_notifier)
dhcp_mixin.auto_schedule_new_network_segments(
resources.SEGMENT_HOST_MAPPING, events.AFTER_CREATE,
ctx, payload)
if subnet_on_segment:
schedule_network.assert_called_once_with(
ctx, subnet_on_segment.network_id,
dhcp_notifier, candidate_hosts=['HOST A'])
else:
schedule_network.assert_not_called()
def test_auto_schedule_new_network_segments(self):
self._test_auto_schedule_new_network_segments(
subnet_on_segment=mock.Mock(network_id='net-1'))
def test_auto_schedule_new_network_segments_no_networks_on_segment(self):
self._test_auto_schedule_new_network_segments(subnet_on_segment=None)
def _is_schedule_network_called(self, device_id): def _is_schedule_network_called(self, device_id):
dhcp_notifier_schedule = mock.patch( dhcp_notifier_schedule = mock.patch(
'neutron.api.rpc.agentnotifiers.dhcp_rpc_agent_api.' 'neutron.api.rpc.agentnotifiers.dhcp_rpc_agent_api.'