Merge "OVO for NetworkDhcpAgentBinding"
This commit is contained in:
commit
e03744c335
@ -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,
|
||||
|
@ -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'),
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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):
|
||||
|
@ -1716,7 +1716,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,
|
||||
|
@ -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
|
||||
|
@ -57,6 +57,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',
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user