OVO for NetworkDhcpAgentBinding

This patch introduces and implements Oslo-Versioned Objects for
NetworkDhcpAgentBinding

Partially-Implements: blueprint adopt-oslo-versioned-objects-for-db
Co-Authored-By: Manjeet Singh Bhatia <manjeet.s.bhatia@intel.com>

Change-Id: Ie6220f8a1455ea721f0d9c7a1b58240cc5fde05a
This commit is contained in:
Nakul Dahiwade 2016-11-10 11:35:04 +01:00 committed by Manjeet Singh Bhatia
parent 96f8fbc62d
commit 7c7b2d75aa
9 changed files with 227 additions and 133 deletions

View File

@ -23,7 +23,6 @@ from oslo_config import cfg
from oslo_log import log as logging
import oslo_messaging
from oslo_utils import timeutils
from sqlalchemy import orm
from sqlalchemy.orm import exc
from neutron._i18n import _
@ -32,10 +31,9 @@ from neutron.common import constants as n_const
from neutron.common import utils
from neutron.db import agents_db
from neutron.db.availability_zone import network as network_az
from neutron.db.models import agent as agent_model
from neutron.db.network_dhcp_agent_binding import models as ndab_model
from neutron.extensions import agent as ext_agent
from neutron.extensions import dhcpagentscheduler
from neutron.objects import network
from neutron import worker as neutron_worker
@ -234,9 +232,8 @@ class DhcpAgentSchedulerDbMixin(dhcpagentscheduler
"""
agent_dead_limit = datetime.timedelta(
seconds=self.agent_dead_limit_seconds())
network_count = (context.session.query(ndab_model.
NetworkDhcpAgentBinding).
filter_by(dhcp_agent_id=agent['id']).count())
network_count = network.NetworkDhcpAgentBinding.count(
context, dhcp_agent_id=agent['id'])
# amount of networks assigned to agent affect amount of time we give
# it so startup. Tests show that it's more or less sage to assume
# that DHCP agent processes each network in less than 2 seconds.
@ -285,9 +282,10 @@ class DhcpAgentSchedulerDbMixin(dhcpagentscheduler
checked_agents = {}
for binding in bindings:
try:
agent_id = binding.dhcp_agent['id']
agent_id = binding.db_obj.dhcp_agent['id']
if agent_id not in checked_agents:
if self.agent_starting_up(context, binding.dhcp_agent):
if self.agent_starting_up(context,
binding.db_obj.dhcp_agent):
# When agent starts and it has many networks to process
# it may fail to send state reports in defined interval
# The server will consider it dead and try to remove
@ -316,11 +314,8 @@ class DhcpAgentSchedulerDbMixin(dhcpagentscheduler
context = ncontext.get_admin_context()
try:
down_bindings = (
context.session.query(ndab_model.NetworkDhcpAgentBinding).
join(agent_model.Agent).
filter(agent_model.Agent.heartbeat_timestamp < cutoff,
agent_model.Agent.admin_state_up))
down_bindings = network.NetworkDhcpAgentBinding.get_down_bindings(
context, cutoff)
dhcp_notifier = self.agent_notifiers.get(constants.AGENT_TYPE_DHCP)
dead_bindings = [b for b in
self._filter_bindings(context, down_bindings)]
@ -381,23 +376,23 @@ class DhcpAgentSchedulerDbMixin(dhcpagentscheduler
hosts=None):
if not network_ids:
return []
query = context.session.query(ndab_model.NetworkDhcpAgentBinding)
query = query.options(orm.contains_eager(
ndab_model.NetworkDhcpAgentBinding.dhcp_agent))
query = query.join(ndab_model.NetworkDhcpAgentBinding.dhcp_agent)
if network_ids:
query = query.filter(
ndab_model.NetworkDhcpAgentBinding.network_id.in_(network_ids))
if hosts:
query = query.filter(agent_model.Agent.host.in_(hosts))
# get all the NDAB objects, which will also fetch (from DB)
# the related dhcp_agent objects because of the synthetic field
bindings = network.NetworkDhcpAgentBinding.get_objects(
context, network_id=network_ids)
# get the already fetched dhcp_agent objects
agent_objs = [binding.db_obj.dhcp_agent for binding in bindings]
# filter the dhcp_agent objects on admin_state_up
if admin_state_up is not None:
query = query.filter(agent_model.Agent.admin_state_up ==
admin_state_up)
return [binding.dhcp_agent
for binding in query
if self.is_eligible_agent(context, active,
binding.dhcp_agent)]
agent_objs = [agent for agent in agent_objs
if agent.admin_state_up == admin_state_up]
# filter the dhcp_agent objects on hosts
if hosts:
agent_objs = [agent for agent in agent_objs
if agent.host in hosts]
# finally filter if the agents are eligible
return [agent for agent in agent_objs
if self.is_eligible_agent(context, active, agent)]
def add_network_to_dhcp_agent(self, context, id, network_id):
self._get_network(context, network_id)
@ -412,10 +407,8 @@ class DhcpAgentSchedulerDbMixin(dhcpagentscheduler
if id == dhcp_agent.id:
raise dhcpagentscheduler.NetworkHostedByDHCPAgent(
network_id=network_id, agent_id=id)
binding = ndab_model.NetworkDhcpAgentBinding()
binding.dhcp_agent_id = id
binding.network_id = network_id
context.session.add(binding)
network.NetworkDhcpAgentBinding(context, dhcp_agent_id=id,
network_id=network_id).create()
dhcp_notifier = self.agent_notifiers.get(constants.AGENT_TYPE_DHCP)
if dhcp_notifier:
dhcp_notifier.network_added_to_agent(
@ -424,12 +417,9 @@ class DhcpAgentSchedulerDbMixin(dhcpagentscheduler
def remove_network_from_dhcp_agent(self, context, id, network_id,
notify=True):
agent = self._get_agent(context, id)
try:
query = context.session.query(ndab_model.NetworkDhcpAgentBinding)
binding = query.filter(
ndab_model.NetworkDhcpAgentBinding.network_id == network_id,
ndab_model.NetworkDhcpAgentBinding.dhcp_agent_id == id).one()
except exc.NoResultFound:
binding_obj = network.NetworkDhcpAgentBinding.get_object(
context, network_id=network_id, dhcp_agent_id=id)
if not binding_obj:
raise dhcpagentscheduler.NetworkNotHostedByDhcpAgent(
network_id=network_id, agent_id=id)
@ -444,8 +434,7 @@ class DhcpAgentSchedulerDbMixin(dhcpagentscheduler
for port in ports:
port['device_id'] = n_const.DEVICE_ID_RESERVED_DHCP_PORT
self.update_port(context, port['id'], dict(port=port))
with context.session.begin():
context.session.delete(binding)
binding_obj.delete()
if not notify:
return
@ -455,12 +444,9 @@ class DhcpAgentSchedulerDbMixin(dhcpagentscheduler
context, network_id, agent.host)
def list_networks_on_dhcp_agent(self, context, id):
query = context.session.query(
ndab_model.NetworkDhcpAgentBinding.network_id)
query = query.filter(
ndab_model.NetworkDhcpAgentBinding.dhcp_agent_id == id)
net_ids = [item[0] for item in query]
objs = network.NetworkDhcpAgentBinding.get_objects(context,
dhcp_agent_id=id)
net_ids = [item.network_id for item in objs]
if net_ids:
return {'networks':
self.get_networks(context, filters={'id': net_ids})}
@ -479,12 +465,11 @@ class DhcpAgentSchedulerDbMixin(dhcpagentscheduler
if not services_available(agent.admin_state_up):
return []
query = context.session.query(
ndab_model.NetworkDhcpAgentBinding.network_id)
query = query.filter(
ndab_model.NetworkDhcpAgentBinding.dhcp_agent_id == agent.id)
net_ids = [item[0] for item in query]
query = network.NetworkDhcpAgentBinding.get_objects(
context, dhcp_agent_id=agent.id)
net_ids = [item.network_id for item in query]
if net_ids:
return self.get_networks(
context,

View File

@ -23,7 +23,7 @@ class NetworkDhcpAgentBinding(model_base.BASEV2):
network_id = sa.Column(sa.String(36),
sa.ForeignKey("networks.id", ondelete='CASCADE'),
primary_key=True)
dhcp_agent = orm.relation(agent_model.Agent)
dhcp_agent = orm.relation(agent_model.Agent, lazy='subquery')
dhcp_agent_id = sa.Column(sa.String(36),
sa.ForeignKey("agents.id",
ondelete='CASCADE'),

View File

@ -20,9 +20,11 @@ from neutron.db.models import dns as dns_models
from neutron.db.models import external_net as ext_net_model
from neutron.db.models import segment as segment_model
from neutron.db import models_v2
from neutron.db.network_dhcp_agent_binding import models as ndab_models
from neutron.db.port_security import models as ps_models
from neutron.db import rbac_db_models
from neutron.extensions import availability_zone as az_ext
from neutron.objects import agent as agent_obj
from neutron.objects import base
from neutron.objects import common_types
from neutron.objects.extensions import port_security as base_ps
@ -30,6 +32,30 @@ from neutron.objects.qos import binding
from neutron.objects import rbac_db
@obj_base.VersionedObjectRegistry.register
class NetworkDhcpAgentBinding(base.NeutronDbObject):
# Version 1.0: Initial version
VERSION = '1.0'
db_model = ndab_models.NetworkDhcpAgentBinding
primary_keys = ['network_id', 'dhcp_agent_id']
fields = {
'network_id': common_types.UUIDField(),
'dhcp_agent_id': common_types.UUIDField(),
}
# NOTE(ndahiwade): The join was implemented this way as get_objects
# currently doesn't support operators like '<' or '>'
@classmethod
def get_down_bindings(cls, context, cutoff):
agent_objs = agent_obj.Agent.get_objects(context)
dhcp_agent_ids = [obj.id for obj in agent_objs
if obj.heartbeat_timestamp < cutoff]
return cls.get_objects(context, dhcp_agent_id=dhcp_agent_ids)
@obj_base.VersionedObjectRegistry.register
class NetworkSegment(base.NeutronDbObject):
# Version 1.0: Initial version

View File

@ -18,15 +18,13 @@ import collections
from operator import itemgetter
from neutron_lib import constants
from neutron_lib.objects import exceptions
from oslo_config import cfg
from oslo_db import exception as db_exc
from oslo_log import log as logging
from sqlalchemy import sql
from neutron.agent.common import utils as agent_utils
from neutron.db import api as db_api
from neutron.db.models import agent as agent_model
from neutron.db.network_dhcp_agent_binding import models as ndab_model
from neutron.extensions import availability_zone as az_ext
from neutron.objects import network
from neutron.scheduler import base_resource_filter
@ -181,15 +179,10 @@ class DhcpFilter(base_resource_filter.BaseResourceFilter):
# saving agent_id to use it after rollback to avoid
# DetachedInstanceError
agent_id = agent.id
binding = ndab_model.NetworkDhcpAgentBinding()
binding.dhcp_agent_id = agent_id
binding.network_id = network_id
try:
with db_api.autonested_transaction(context.session):
context.session.add(binding)
# try to actually write the changes and catch integrity
# DBDuplicateEntry
except db_exc.DBDuplicateEntry:
network.NetworkDhcpAgentBinding(context,
dhcp_agent_id=agent_id, network_id=network_id).create()
except exceptions.NeutronDbObjectDuplicateEntry:
# it's totally ok, someone just did our job!
bound_agents.remove(agent)
LOG.info('Agent %s already present', agent_id)
@ -273,15 +266,14 @@ class DhcpFilter(base_resource_filter.BaseResourceFilter):
az_hints = (network.get(az_ext.AZ_HINTS) or
cfg.CONF.default_availability_zones)
active_dhcp_agents = self._get_active_agents(plugin, context, az_hints)
hosted_agent_ids = [agent['id'] for agent in hosted_agents]
if not active_dhcp_agents:
return {'n_agents': 0, 'hostable_agents': [],
'hosted_agents': hosted_agents}
hostable_dhcp_agents = [
agent for agent in set(active_dhcp_agents)
if agent not in hosted_agents and plugin.is_eligible_agent(
context, True, agent)
]
agent for agent in active_dhcp_agents
if agent.id not in hosted_agent_ids and plugin.is_eligible_agent(
context, True, agent)]
hostable_dhcp_agents = self._filter_agents_with_network_access(
plugin, context, network, hostable_dhcp_agents)

View File

@ -19,12 +19,13 @@ from operator import attrgetter
from neutron_lib.api.definitions import provider_net as providernet
from neutron_lib import constants
from neutron_lib import context
from oslo_utils import uuidutils
import testscenarios
from neutron.db import agents_db
from neutron.db import agentschedulers_db
from neutron.db import common_db_mixin
from neutron.db.network_dhcp_agent_binding import models as ndab_model
from neutron.objects import network
from neutron.scheduler import dhcp_agent_scheduler
from neutron.tests.common import helpers
from neutron.tests.unit.plugins.ml2 import test_plugin
@ -359,10 +360,10 @@ class TestAutoSchedule(test_dhcp_sch.TestDhcpSchedulerBaseTestCase,
def get_subnets(self, context, fields=None):
subnets = []
for net_id in self._networks:
enable_dhcp = (not self._strip_host_index(net_id) in
for net in self._networks:
enable_dhcp = (self._strip_host_index(net['name']) not in
self.networks_with_dhcp_disabled)
subnets.append({'network_id': net_id,
subnets.append({'network_id': net.id,
'enable_dhcp': enable_dhcp,
'segment_id': None})
return subnets
@ -374,13 +375,9 @@ class TestAutoSchedule(test_dhcp_sch.TestDhcpSchedulerBaseTestCase,
return {'availability_zone_hints': az_hints}
def _get_hosted_networks_on_dhcp_agent(self, agent_id):
query = self.ctx.session.query(
ndab_model.NetworkDhcpAgentBinding.network_id)
query = query.filter(
ndab_model.NetworkDhcpAgentBinding.dhcp_agent_id ==
agent_id)
return [item[0] for item in query]
binding_objs = network.NetworkDhcpAgentBinding.get_objects(
self.ctx, dhcp_agent_id=agent_id)
return [item.network_id for item in binding_objs]
def _test_auto_schedule(self, host_index):
self.config(dhcp_agents_per_network=self.max_agents_per_network)
@ -394,9 +391,16 @@ class TestAutoSchedule(test_dhcp_sch.TestDhcpSchedulerBaseTestCase,
dhcp_agents = self._create_and_set_agents_down(hosts)
# create networks
self._networks = ['%s-network-%s' % (host_index, i)
for i in range(self.network_count)]
self._save_networks(self._networks)
self._networks = [
network.Network(
self.ctx,
id=uuidutils.generate_uuid(),
name='%s-network-%s' % (host_index, i))
for i in range(self.network_count)
]
for i in range(len(self._networks)):
self._networks[i].create()
network_ids = [net.id for net in self._networks]
# pre schedule the networks to the agents defined in
# self.hosted_networks before calling auto_schedule_network
@ -406,7 +410,7 @@ class TestAutoSchedule(test_dhcp_sch.TestDhcpSchedulerBaseTestCase,
net_index = self._extract_index(net)
scheduler.resource_filter.bind(self.ctx,
[dhcp_agents[agent_index]],
self._networks[net_index])
network_ids[net_index])
retval = scheduler.auto_schedule_networks(self, self.ctx,
hosts[host_index])
@ -415,11 +419,14 @@ class TestAutoSchedule(test_dhcp_sch.TestDhcpSchedulerBaseTestCase,
agent_id = dhcp_agents[host_index].id
hosted_networks = self._get_hosted_networks_on_dhcp_agent(agent_id)
hosted_net_ids = [self._strip_host_index(net)
for net in hosted_networks]
hosted_net_names = [
self._strip_host_index(net['name'])
for net in network.Network.get_objects(
self.ctx, id=hosted_networks)
]
expected_hosted_networks = self.expected_hosted_networks['agent-%s' %
host_index]
self.assertItemsEqual(hosted_net_ids, expected_hosted_networks, msg)
self.assertItemsEqual(hosted_net_names, expected_hosted_networks, msg)
def test_auto_schedule(self):
for i in range(self.agent_count):

View File

@ -1715,7 +1715,17 @@ class BaseDbObjectTestCase(_BaseObjectTestCase,
# check that the stored database model does not have non-empty
# relationships
dbattr = obj.fields_need_translation.get(field, field)
self.assertFalse(getattr(obj.db_obj, dbattr, None))
# Skipping empty relationships for the following reasons:
# 1) db_obj have the related object loaded - In this case we do not
# have to create the related objects and the loop can continue.
# 2) when the related objects are not loaded - In this
# case they need to be created because of the foreign key
# relationships. But we still need to check whether the
# relationships are loaded or not. That is achieved by the
# assertTrue statement after retrieving the dbattr in
# this method.
if getattr(obj.db_obj, dbattr, None):
continue
if isinstance(cls_.fields[field], obj_fields.ObjectField):
objclass_fields = self._get_non_synth_fields(objclass,

View File

@ -20,6 +20,26 @@ from neutron.tests.unit.objects import test_base as obj_test_base
from neutron.tests.unit import testlib_api
class NetworkDhcpAgentBindingObjectIfaceTestCase(
obj_test_base.BaseObjectIfaceTestCase):
_test_class = network.NetworkDhcpAgentBinding
class NetworkDhcpAgentBindingDbObjectTestCase(
obj_test_base.BaseDbObjectTestCase, testlib_api.SqlTestCase):
_test_class = network.NetworkDhcpAgentBinding
def setUp(self):
super(NetworkDhcpAgentBindingDbObjectTestCase, self).setUp()
self._network = self._create_test_network()
self.update_obj_fields(
{'network_id': self._network.id,
'dhcp_agent_id': lambda: self._create_test_agent_id()})
class NetworkPortSecurityIfaceObjTestCase(
obj_test_base.BaseObjectIfaceTestCase):
_test_class = network.NetworkPortSecurity

View File

@ -54,6 +54,7 @@ object_data = {
'MeteringLabelRule': '1.0-b5c5717e7bab8d1af1623156012a5842',
'Log': '1.0-6391351c0f34ed34375a19202f361d24',
'Network': '1.0-f2f6308f79731a767b92b26b0f4f3849',
'NetworkDhcpAgentBinding': '1.0-6eeceb5fb4335cd65a305016deb41c68',
'NetworkDNSDomain': '1.0-420db7910294608534c1e2e30d6d8319',
'NetworkPortSecurity': '1.0-b30802391a87945ee9c07582b4ff95e3',
'NetworkSegment': '1.0-57b7f2960971e3b95ded20cbc59244a8',

View File

@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import datetime
import random
import mock
@ -20,13 +21,15 @@ from neutron_lib import constants
from neutron_lib import context
from oslo_config import cfg
from oslo_utils import importutils
from oslo_utils import uuidutils
import testscenarios
from neutron.db import agentschedulers_db as sched_db
from neutron.db import common_db_mixin
from neutron.db import models_v2
from neutron.db.network_dhcp_agent_binding import models as ndab_model
from neutron.extensions import dhcpagentscheduler
from neutron.objects import agent
from neutron.objects import network as network_obj
from neutron.scheduler import dhcp_agent_scheduler
from neutron.services.segments import db as segments_service_db
from neutron.tests.common import helpers
@ -47,8 +50,8 @@ class TestDhcpSchedulerBaseTestCase(testlib_api.SqlTestCase):
super(TestDhcpSchedulerBaseTestCase, self).setUp()
self.setup_coreplugin(self.CORE_PLUGIN)
self.ctx = context.get_admin_context()
self.network = {'id': 'foo_network_id'}
self.network_id = 'foo_network_id'
self.network = {'id': uuidutils.generate_uuid()}
self.network_id = self.network['id']
self._save_networks([self.network_id])
def _create_and_set_agents_down(self, hosts, down_agent_count=0,
@ -72,11 +75,10 @@ class TestDhcpSchedulerBaseTestCase(testlib_api.SqlTestCase):
def _test_schedule_bind_network(self, agents, network_id):
scheduler = dhcp_agent_scheduler.ChanceScheduler()
scheduler.resource_filter.bind(self.ctx, agents, network_id)
results = self.ctx.session.query(
ndab_model.NetworkDhcpAgentBinding).filter_by(
network_id=network_id).all()
self.assertEqual(len(agents), len(results))
for result in results:
binding_objs = network_obj.NetworkDhcpAgentBinding.get_objects(
self.ctx, network_id=network_id)
self.assertEqual(len(agents), len(binding_objs))
for result in binding_objs:
self.assertEqual(network_id, result.network_id)
@ -135,9 +137,8 @@ class TestDhcpScheduler(TestDhcpSchedulerBaseTestCase):
self._test_reschedule_vs_network_on_dead_agent(False)
def _get_agent_binding_from_db(self, agent):
return self.ctx.session.query(
ndab_model.NetworkDhcpAgentBinding
).filter_by(dhcp_agent_id=agent[0].id).all()
return network_obj.NetworkDhcpAgentBinding.get_objects(
self.ctx, dhcp_agent_id=agent[0].id)
def _test_auto_reschedule_vs_network_on_dead_agent(self,
active_hosts_only):
@ -289,9 +290,9 @@ class TestAutoScheduleNetworks(TestDhcpSchedulerBaseTestCase):
observed_ret_value = scheduler.auto_schedule_networks(
plugin, self.ctx, host)
self.assertEqual(expected_result, observed_ret_value)
hosted_agents = self.ctx.session.query(
ndab_model.NetworkDhcpAgentBinding).all()
self.assertEqual(expected_hosted_agents, len(hosted_agents))
count_hosted_agents = network_obj.NetworkDhcpAgentBinding.count(
self.ctx)
self.assertEqual(expected_hosted_agents, count_hosted_agents)
class TestAutoScheduleSegments(test_plugin.Ml2PluginV2TestCase,
@ -409,10 +410,11 @@ class TestNetworksFailover(TestDhcpSchedulerBaseTestCase,
sched_db.DhcpAgentSchedulerDbMixin,
common_db_mixin.CommonDbMixin):
def test_reschedule_network_from_down_agent(self):
net_id = uuidutils.generate_uuid()
agents = self._create_and_set_agents_down(['host-a', 'host-b'], 1)
self._test_schedule_bind_network([agents[0]], self.network_id)
self._save_networks(["foo-network-2"])
self._test_schedule_bind_network([agents[1]], "foo-network-2")
self._save_networks([net_id])
self._test_schedule_bind_network([agents[1]], net_id)
with mock.patch.object(self, 'remove_network_from_dhcp_agent') as rn,\
mock.patch.object(self,
'schedule_network',
@ -459,24 +461,70 @@ class TestNetworksFailover(TestDhcpSchedulerBaseTestCase,
rn_side_effect=dhcpagentscheduler.NetworkNotHostedByDhcpAgent(
network_id='foo', agent_id='bar'))
def _create_test_networks(self, num_net=0):
networks = [network_obj.Network(
self.ctx,
id=uuidutils.generate_uuid(),
name='network-%s' % (i))
for i in range(num_net)]
for net in networks:
net.create()
return [net.id for net in networks]
def _create_dhcp_agents(self):
timestamp = datetime.datetime.now()
dhcp_agent_ids = [uuidutils.generate_uuid() for x in range(2)]
dhcp_agent_1 = agent.Agent(self.ctx, id=dhcp_agent_ids[0],
agent_type='DHCP Agent',
topic='fake_topic',
host='fake_host',
binary='fake_binary',
created_at=timestamp,
started_at=timestamp,
heartbeat_timestamp=timestamp,
configurations={},
load=0)
dhcp_agent_1.create()
dhcp_agent_2 = agent.Agent(self.ctx, id=dhcp_agent_ids[1],
agent_type='DHCP Agent',
topic='fake_topic',
host='fake_host_1',
binary='fake_binary',
created_at=timestamp,
started_at=timestamp,
heartbeat_timestamp=timestamp,
configurations={},
load=0)
dhcp_agent_2.create()
return [dhcp_agent_1.id, dhcp_agent_2.id]
def test_filter_bindings(self):
bindings = [
ndab_model.NetworkDhcpAgentBinding(network_id='foo1',
dhcp_agent={'id': 'id1'}),
ndab_model.NetworkDhcpAgentBinding(network_id='foo2',
dhcp_agent={'id': 'id1'}),
ndab_model.NetworkDhcpAgentBinding(network_id='foo3',
dhcp_agent={'id': 'id2'}),
ndab_model.NetworkDhcpAgentBinding(network_id='foo4',
dhcp_agent={'id': 'id2'})]
self.ctx = context.get_admin_context()
dhcp_agt_ids = self._create_dhcp_agents()
network_ids = self._create_test_networks(num_net=4)
ndab_obj1 = network_obj.NetworkDhcpAgentBinding(self.ctx,
network_id=network_ids[0], dhcp_agent_id=dhcp_agt_ids[0])
ndab_obj1.create()
ndab_obj2 = network_obj.NetworkDhcpAgentBinding(self.ctx,
network_id=network_ids[1], dhcp_agent_id=dhcp_agt_ids[0])
ndab_obj2.create()
ndab_obj3 = network_obj.NetworkDhcpAgentBinding(self.ctx,
network_id=network_ids[2], dhcp_agent_id=dhcp_agt_ids[1])
ndab_obj3.create()
ndab_obj4 = network_obj.NetworkDhcpAgentBinding(self.ctx,
network_id=network_ids[3], dhcp_agent_id=dhcp_agt_ids[1])
ndab_obj4.create()
bindings_objs = network_obj.NetworkDhcpAgentBinding.get_objects(
self.ctx)
with mock.patch.object(self, 'agent_starting_up',
side_effect=[True, False]):
res = [b for b in self._filter_bindings(None, bindings)]
res = [b for b in self._filter_bindings(None, bindings_objs)]
# once per each agent id1 and id2
self.assertEqual(2, len(res))
res_ids = [b.network_id for b in res]
self.assertIn('foo3', res_ids)
self.assertIn('foo4', res_ids)
self.assertIn(network_ids[2], res_ids)
self.assertIn(network_ids[3], res_ids)
def test_reschedule_network_from_down_agent_failed_on_unexpected(self):
agents = self._create_and_set_agents_down(['host-a'], 1)
@ -717,7 +765,7 @@ class TestDhcpSchedulerFilter(TestDhcpSchedulerBaseTestCase,
admin_state_up=False)
def test_get_dhcp_agents_hosting_many_networks(self):
net_id = 'another-net-id'
net_id = uuidutils.generate_uuid()
self._save_networks([net_id])
networks = [net_id, self.network_id]
self._test_get_dhcp_agents_hosting_networks({'host-a', 'host-b',
@ -745,35 +793,38 @@ class DHCPAgentAZAwareWeightSchedulerTestCase(TestDhcpSchedulerBaseTestCase):
cfg.CONF.set_override("dhcp_load_type", "networks")
def test_az_scheduler_one_az_hints(self):
self._save_networks(['1111'])
net_id = uuidutils.generate_uuid()
self._save_networks([net_id])
helpers.register_dhcp_agent('az1-host1', networks=1, az='az1')
helpers.register_dhcp_agent('az1-host2', networks=2, az='az1')
helpers.register_dhcp_agent('az2-host1', networks=3, az='az2')
helpers.register_dhcp_agent('az2-host2', networks=4, az='az2')
self.plugin.network_scheduler.schedule(self.plugin, self.ctx,
{'id': '1111', 'availability_zone_hints': ['az2']})
{'id': net_id, 'availability_zone_hints': ['az2']})
agents = self.plugin.get_dhcp_agents_hosting_networks(self.ctx,
['1111'])
[net_id])
self.assertEqual(1, len(agents))
self.assertEqual('az2-host1', agents[0]['host'])
def test_az_scheduler_default_az_hints(self):
net_id = uuidutils.generate_uuid()
cfg.CONF.set_override('default_availability_zones', ['az1'])
self._save_networks(['1111'])
self._save_networks([net_id])
helpers.register_dhcp_agent('az1-host1', networks=1, az='az1')
helpers.register_dhcp_agent('az1-host2', networks=2, az='az1')
helpers.register_dhcp_agent('az2-host1', networks=3, az='az2')
helpers.register_dhcp_agent('az2-host2', networks=4, az='az2')
self.plugin.network_scheduler.schedule(self.plugin, self.ctx,
{'id': '1111', 'availability_zone_hints': []})
{'id': net_id, 'availability_zone_hints': []})
agents = self.plugin.get_dhcp_agents_hosting_networks(self.ctx,
['1111'])
[net_id])
self.assertEqual(1, len(agents))
self.assertEqual('az1-host1', agents[0]['host'])
def test_az_scheduler_two_az_hints(self):
net_id = uuidutils.generate_uuid()
cfg.CONF.set_override('dhcp_agents_per_network', 2)
self._save_networks(['1111'])
self._save_networks([net_id])
helpers.register_dhcp_agent('az1-host1', networks=1, az='az1')
helpers.register_dhcp_agent('az1-host2', networks=2, az='az1')
helpers.register_dhcp_agent('az2-host1', networks=3, az='az2')
@ -781,17 +832,18 @@ class DHCPAgentAZAwareWeightSchedulerTestCase(TestDhcpSchedulerBaseTestCase):
helpers.register_dhcp_agent('az3-host1', networks=5, az='az3')
helpers.register_dhcp_agent('az3-host2', networks=6, az='az3')
self.plugin.network_scheduler.schedule(self.plugin, self.ctx,
{'id': '1111', 'availability_zone_hints': ['az1', 'az3']})
{'id': net_id, 'availability_zone_hints': ['az1', 'az3']})
agents = self.plugin.get_dhcp_agents_hosting_networks(self.ctx,
['1111'])
[net_id])
self.assertEqual(2, len(agents))
expected_hosts = set(['az1-host1', 'az3-host1'])
hosts = set([a['host'] for a in agents])
self.assertEqual(expected_hosts, hosts)
def test_az_scheduler_two_az_hints_one_available_az(self):
net_id = uuidutils.generate_uuid()
cfg.CONF.set_override('dhcp_agents_per_network', 2)
self._save_networks(['1111'])
self._save_networks([net_id])
helpers.register_dhcp_agent('az1-host1', networks=1, az='az1')
helpers.register_dhcp_agent('az1-host2', networks=2, az='az1')
helpers.register_dhcp_agent('az2-host1', networks=3, alive=False,
@ -799,26 +851,27 @@ class DHCPAgentAZAwareWeightSchedulerTestCase(TestDhcpSchedulerBaseTestCase):
helpers.register_dhcp_agent('az2-host2', networks=4,
admin_state_up=False, az='az2')
self.plugin.network_scheduler.schedule(self.plugin, self.ctx,
{'id': '1111', 'availability_zone_hints': ['az1', 'az2']})
{'id': net_id, 'availability_zone_hints': ['az1', 'az2']})
agents = self.plugin.get_dhcp_agents_hosting_networks(self.ctx,
['1111'])
[net_id])
self.assertEqual(2, len(agents))
expected_hosts = set(['az1-host1', 'az1-host2'])
hosts = set([a['host'] for a in agents])
self.assertEqual(expected_hosts, hosts)
def _test_az_scheduler_no_az_hints(self, multiple_agent=False):
net_id = uuidutils.generate_uuid()
num_agent = 2 if multiple_agent else 1
cfg.CONF.set_override('dhcp_agents_per_network', num_agent)
self._save_networks(['1111'])
self._save_networks([net_id])
helpers.register_dhcp_agent('az1-host1', networks=2, az='az1')
helpers.register_dhcp_agent('az1-host2', networks=3, az='az1')
helpers.register_dhcp_agent('az2-host1', networks=2, az='az2')
helpers.register_dhcp_agent('az2-host2', networks=1, az='az2')
self.plugin.network_scheduler.schedule(self.plugin, self.ctx,
{'id': '1111', 'availability_zone_hints': []})
{'id': net_id, 'availability_zone_hints': []})
agents = self.plugin.get_dhcp_agents_hosting_networks(self.ctx,
['1111'])
[net_id])
self.assertEqual(num_agent, len(agents))
if multiple_agent:
expected_hosts = set(['az1-host1', 'az2-host2'])
@ -834,7 +887,7 @@ class DHCPAgentAZAwareWeightSchedulerTestCase(TestDhcpSchedulerBaseTestCase):
self._test_az_scheduler_no_az_hints()
def test_az_scheduler_select_az_with_least_weight(self):
self._save_networks(['1111'])
self._save_networks([uuidutils.generate_uuid()])
dhcp_agents = []
# Register 6 dhcp agents in 3 AZs, every AZ will have 2 agents.
dhcp_agents.append(