Browse Source

Schedule networks to new segments if needed

In case when subnet in segment X was created before hosts from
that segment was mapped in the Neutron DB, network wasn't scheduled
to the DHCP agents in that new segment.
Now DHCP scheduler is triggered in such case.

Closes-bug: #1917811
Change-Id: Ic9e64aa4ecdc3d56f00c26204ad931b810db7599
(cherry picked from commit 5c931f2913)
changes/35/780835/1
Slawek Kaplonski 5 months ago
parent
commit
2fe402f483
  1. 29
      neutron/db/agentschedulers_db.py
  2. 43
      neutron/tests/unit/db/test_agentschedulers_db.py

29
neutron/db/agentschedulers_db.py

@ -17,12 +17,16 @@ import datetime
import random
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 context as ncontext
from neutron_lib.db import api as db_api
from neutron_lib import exceptions as n_exc
from neutron_lib.exceptions import agent as agent_exc
from neutron_lib.exceptions import dhcpagentscheduler as das_exc
from neutron_lib.plugins import directory
from oslo_config import cfg
from oslo_log import log as logging
import oslo_messaging
@ -36,6 +40,7 @@ from neutron.db import agents_db
from neutron.db.availability_zone import network as network_az
from neutron.extensions import dhcpagentscheduler
from neutron.objects import network
from neutron.objects import subnet as subnet_obj
from neutron import worker as neutron_worker
@ -227,12 +232,15 @@ class DhcpAgentSchedulerDbMixin(dhcpagentscheduler
additional_time)
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)
try:
# TODO(enikanorov): have to issue redundant db query
# to satisfy scheduling interface
network = self.get_network(context, network_id)
if candidate_hosts:
network['candidate_hosts'] = candidate_hosts
agents = self.schedule_network(context, network)
if not agents:
LOG.info("Failed to schedule network %s, "
@ -483,6 +491,25 @@ class DhcpAgentSchedulerDbMixin(dhcpagentscheduler
if self.network_scheduler:
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,
network_az.NetworkAvailabilityZoneMixin):

43
neutron/tests/unit/db/test_agentschedulers_db.py

@ -18,6 +18,8 @@ import datetime
import mock
from neutron_lib.api.definitions import dhcpagentscheduler as das_apidef
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 context
from neutron_lib.db import api as db_api
@ -1559,6 +1561,47 @@ class OvsDhcpAgentNotifierTestCase(test_agent.AgentDBTestMixIn,
for expected in low_expecteds:
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):
dhcp_notifier_schedule = mock.patch(
'neutron.api.rpc.agentnotifiers.dhcp_rpc_agent_api.'

Loading…
Cancel
Save