Merge "Schedule networks to new segments if needed"
This commit is contained in:
commit
e9a75a379e
@ -17,12 +17,16 @@ 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.db import api as db_api
|
from neutron_lib.db import api as db_api
|
||||||
from neutron_lib import exceptions as n_exc
|
from neutron_lib import exceptions as n_exc
|
||||||
from neutron_lib.exceptions import agent as agent_exc
|
from neutron_lib.exceptions import agent as agent_exc
|
||||||
from neutron_lib.exceptions import dhcpagentscheduler as das_exc
|
from neutron_lib.exceptions import dhcpagentscheduler as das_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
|
||||||
@ -36,6 +40,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
|
||||||
|
|
||||||
|
|
||||||
@ -226,12 +231,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, "
|
||||||
@ -481,6 +489,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):
|
||||||
|
@ -18,6 +18,8 @@ from unittest import mock
|
|||||||
|
|
||||||
from neutron_lib.api.definitions import dhcpagentscheduler as das_apidef
|
from neutron_lib.api.definitions import dhcpagentscheduler as das_apidef
|
||||||
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.db import api as db_api
|
from neutron_lib.db import api as db_api
|
||||||
@ -1588,6 +1590,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.'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user