]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Enable network to be scheduled to N DHCP agents
authorGary Kotton <gkotton@redhat.com>
Wed, 1 May 2013 12:54:11 +0000 (12:54 +0000)
committerGary Kotton <gkotton@redhat.com>
Tue, 21 May 2013 14:33:35 +0000 (14:33 +0000)
Fixes bug 1174132

Change-Id: Iabe96fd8a98f3539eb21268fb5ef58df8dbd8782

etc/quantum.conf
quantum/api/rpc/agentnotifiers/dhcp_rpc_agent_api.py
quantum/manager.py
quantum/scheduler/__init__.py
quantum/scheduler/dhcp_agent_scheduler.py
quantum/tests/unit/openvswitch/test_agent_scheduler.py
quantum/tests/unit/test_agent_ext_plugin.py
quantum/tests/unit/test_quantum_manager.py

index 9f2fccaaa3163d87b8ee30b8c310f37d5d59f713..206fa8583215b9fdaf4952489e87b1953dcffb2d 100644 (file)
@@ -229,6 +229,11 @@ notification_topics = notifications
 # Allow auto scheduling routers to L3 agent. It will schedule non-hosted
 # routers to first L3 agent which sends sync_routers message to quantum server
 # router_auto_schedule = True
+
+# Number of DHCP agents scheduled to host a network. This enables redundant
+# DHCP agents for configured networks.
+# dhcp_agents_per_network = 1
+
 # ===========  end of items for agent scheduler extension =====
 
 # =========== WSGI parameters related to the API server ==============
index fbb1bbb2f5e3140bf675b869c7777be3d0911b8a..959e2b1bfdeab4bb02589c2008927f33947f320e 100644 (file)
@@ -69,12 +69,13 @@ class DhcpAgentNotifyAPI(proxy.RpcProxy):
                 adminContext = (context if context.is_admin else
                                 context.elevated())
                 network = plugin.get_network(adminContext, network_id)
-                chosen_agent = plugin.schedule_network(adminContext, network)
-                if chosen_agent:
-                    self._notification_host(
-                        context, 'network_create_end',
-                        {'network': {'id': network_id}},
-                        chosen_agent['host'])
+                chosen_agents = plugin.schedule_network(adminContext, network)
+                if chosen_agents:
+                    for agent in chosen_agents:
+                        self._notification_host(
+                            context, 'network_create_end',
+                            {'network': {'id': network_id}},
+                            agent['host'])
             for (host, topic) in self._get_dhcp_agents(context, network_id):
                 self.cast(
                     context, self.make_msg(method,
index 5573ab19e887a88567636368f22a5bd5d48e1c2a..4c6a9f76c74be7a9fe30768f65761db67325f8d1 100644 (file)
@@ -59,6 +59,30 @@ class Manager(periodic_task.PeriodicTasks):
         pass
 
 
+def validate_post_plugin_load():
+    """Checks if the configuration variables are valid.
+
+    If the configuration is invalid then the method will return an error
+    message. If all is OK then it will return None.
+    """
+    if ('dhcp_agents_per_network' in cfg.CONF and
+        cfg.CONF.dhcp_agents_per_network <= 0):
+        msg = _("dhcp_agents_per_network must be >= 1. '%s' "
+                "is invalid.") % cfg.CONF.dhcp_agents_per_network
+        return msg
+
+
+def validate_pre_plugin_load():
+    """Checks if the configuration variables are valid.
+
+    If the configuration is invalid then the method will return an error
+    message. If all is OK then it will return None.
+    """
+    if cfg.CONF.core_plugin is None:
+        msg = _('Quantum core_plugin not configured!')
+        return msg
+
+
 class QuantumManager(object):
     """Quantum's Manager class.
 
@@ -74,8 +98,8 @@ class QuantumManager(object):
         if not options:
             options = {}
 
-        if cfg.CONF.core_plugin is None:
-            msg = _('Quantum core_plugin not configured!')
+        msg = validate_pre_plugin_load()
+        if msg:
             LOG.critical(msg)
             raise Exception(msg)
 
@@ -96,6 +120,11 @@ class QuantumManager(object):
                             "Example: pip install quantum-sample-plugin"))
         self.plugin = plugin_klass()
 
+        msg = validate_post_plugin_load()
+        if msg:
+            LOG.critical(msg)
+            raise Exception(msg)
+
         # core plugin as a part of plugin collection simplifies
         # checking extensions
         # TODO(enikanorov): make core plugin the same as
index 9dc2a46c3851a8e294114bef7b965abebb149685..7fc68d0669be7c44a076beef6ca89877c7c675a9 100644 (file)
@@ -31,4 +31,6 @@ AGENTS_SCHEDULER_OPTS = [
                 help=_('Allow auto scheduling networks to DHCP agent.')),
     cfg.BoolOpt('router_auto_schedule', default=True,
                 help=_('Allow auto scheduling routers to L3 agent.')),
+    cfg.IntOpt('dhcp_agents_per_network', default=1,
+               help=_('Number of DHCP agents scheduled to host a network.')),
 ]
index 3133eb23f6925f49b6106b5b886992f6bcee7762..9bcadd7edec24a0fa0a591381d81b69fad9d8a68 100644 (file)
 
 import random
 
-from sqlalchemy.orm import exc
-from sqlalchemy.sql import exists
+from oslo.config import cfg
 
 from quantum.common import constants
 from quantum.db import agents_db
 from quantum.db import agentschedulers_db
-from quantum.db import models_v2
 from quantum.openstack.common import log as logging
 
 
@@ -36,75 +34,87 @@ class ChanceScheduler(object):
     can be introduced later.
     """
 
+    def _schedule_bind_network(self, context, agent, network_id):
+        binding = agentschedulers_db.NetworkDhcpAgentBinding()
+        binding.dhcp_agent = agent
+        binding.network_id = network_id
+        context.session.add(binding)
+        LOG.debug(_('Network %(network_id)s is scheduled to be hosted by '
+                    'DHCP agent %(agent_id)s'),
+                  {'network_id': network_id,
+                   'agent_id': agent})
+
     def schedule(self, plugin, context, network):
-        """Schedule the network to an active DHCP agent if there
-        is no active DHCP agent hosting it.
+        """Schedule the network to active DHCP agent(s).
+
+        A list of scheduled agents is returned.
         """
+        agents_per_network = cfg.CONF.dhcp_agents_per_network
+
         #TODO(gongysh) don't schedule the networks with only
         # subnets whose enable_dhcp is false
         with context.session.begin(subtransactions=True):
             dhcp_agents = plugin.get_dhcp_agents_hosting_networks(
                 context, [network['id']], active=True)
-            if dhcp_agents:
+            if len(dhcp_agents) >= agents_per_network:
                 LOG.debug(_('Network %s is hosted already'),
                           network['id'])
                 return
+            n_agents = agents_per_network - len(dhcp_agents)
             enabled_dhcp_agents = plugin.get_agents_db(
                 context, filters={
                     'agent_type': [constants.AGENT_TYPE_DHCP],
                     'admin_state_up': [True]})
             if not enabled_dhcp_agents:
-                LOG.warn(_('No enabled DHCP agents'))
+                LOG.warn(_('No more DHCP agents'))
                 return
-            active_dhcp_agents = [enabled_dhcp_agent for enabled_dhcp_agent in
-                                  enabled_dhcp_agents if not
-                                  agents_db.AgentDbMixin.is_agent_down(
-                                  enabled_dhcp_agent['heartbeat_timestamp'])]
+            active_dhcp_agents = [
+                agent for agent in set(enabled_dhcp_agents)
+                if not agents_db.AgentDbMixin.is_agent_down(
+                    agent['heartbeat_timestamp'])
+                and agent not in dhcp_agents
+            ]
             if not active_dhcp_agents:
-                LOG.warn(_('No active DHCP agents'))
+                LOG.warn(_('No more DHCP agents'))
                 return
-            chosen_agent = random.choice(active_dhcp_agents)
-            binding = agentschedulers_db.NetworkDhcpAgentBinding()
-            binding.dhcp_agent = chosen_agent
-            binding.network_id = network['id']
-            context.session.add(binding)
-            LOG.debug(_('Network %(network_id)s is scheduled to be hosted by '
-                        'DHCP agent %(agent_id)s'),
-                      {'network_id': network['id'],
-                       'agent_id': chosen_agent['id']})
-        return chosen_agent
+            n_agents = min(len(active_dhcp_agents), n_agents)
+            chosen_agents = random.sample(active_dhcp_agents, n_agents)
+            for agent in chosen_agents:
+                self._schedule_bind_network(context, agent, network['id'])
+        return chosen_agents
 
     def auto_schedule_networks(self, plugin, context, host):
         """Schedule non-hosted networks to the DHCP agent on
         the specified host.
         """
+        agents_per_network = cfg.CONF.dhcp_agents_per_network
         with context.session.begin(subtransactions=True):
             query = context.session.query(agents_db.Agent)
             query = query.filter(agents_db.Agent.agent_type ==
                                  constants.AGENT_TYPE_DHCP,
                                  agents_db.Agent.host == host,
                                  agents_db.Agent.admin_state_up == True)
-            try:
-                dhcp_agent = query.one()
-            except (exc.MultipleResultsFound, exc.NoResultFound):
-                LOG.warn(_('No enabled DHCP agent on host %s'),
-                         host)
-                return False
-            if agents_db.AgentDbMixin.is_agent_down(
-                dhcp_agent.heartbeat_timestamp):
-                LOG.warn(_('DHCP agent %s is not active'), dhcp_agent.id)
-            #TODO(gongysh) consider the disabled agent's network
-            net_stmt = ~exists().where(
-                models_v2.Network.id ==
-                agentschedulers_db.NetworkDhcpAgentBinding.network_id)
-            net_ids = context.session.query(
-                models_v2.Network.id).filter(net_stmt).all()
-            if not net_ids:
-                LOG.debug(_('No non-hosted networks'))
-                return False
-            for net_id in net_ids:
-                binding = agentschedulers_db.NetworkDhcpAgentBinding()
-                binding.dhcp_agent = dhcp_agent
-                binding.network_id = net_id[0]
-                context.session.add(binding)
+            dhcp_agents = query.all()
+            for dhcp_agent in dhcp_agents:
+                if agents_db.AgentDbMixin.is_agent_down(
+                    dhcp_agent.heartbeat_timestamp):
+                    LOG.warn(_('DHCP agent %s is not active'), dhcp_agent.id)
+                    continue
+                #TODO(gongysh) consider the disabled agent's network
+                fields = ['network_id', 'enable_dhcp']
+                subnets = plugin.get_subnets(context, fields=fields)
+                net_ids = set(s['network_id'] for s in subnets
+                              if s['enable_dhcp'])
+                if not net_ids:
+                    LOG.debug(_('No non-hosted networks'))
+                    return False
+                for net_id in net_ids:
+                    agents = plugin.get_dhcp_agents_hosting_networks(
+                        context, [net_id], active=True)
+                    if len(agents) >= agents_per_network:
+                        continue
+                    binding = agentschedulers_db.NetworkDhcpAgentBinding()
+                    binding.dhcp_agent = dhcp_agent
+                    binding.network_id = net_id
+                    context.session.add(binding)
         return True
index 395ca77d1a496ab766c5e5cc9eed14bf3f8ef154..c28e09d7fc926bb5562855c196f77c39e41b3c12 100644 (file)
@@ -17,6 +17,7 @@ import contextlib
 import copy
 
 import mock
+from oslo.config import cfg
 from webob import exc
 
 from quantum.api import extensions
@@ -230,8 +231,9 @@ class OvsAgentSchedulerTestCase(test_l3_plugin.L3NatTestCaseMixin,
         self.assertEqual(0, len(dhcp_agents['agents']))
 
     def test_network_auto_schedule_with_disabled(self):
-        with contextlib.nested(self.network(),
-                               self.network()):
+        cfg.CONF.set_override('allow_overlapping_ips', True)
+        with contextlib.nested(self.subnet(),
+                               self.subnet()):
             dhcp_rpc = dhcp_rpc_base.DhcpRpcCallbackMixin()
             self._register_agent_states()
             hosta_id = self._get_agent_id(constants.AGENT_TYPE_DHCP,
@@ -249,17 +251,58 @@ class OvsAgentSchedulerTestCase(test_l3_plugin.L3NatTestCaseMixin,
         self.assertEqual(0, num_hosta_nets)
         self.assertEqual(2, num_hostc_nets)
 
+    def test_network_auto_schedule_with_no_dhcp(self):
+        cfg.CONF.set_override('allow_overlapping_ips', True)
+        with contextlib.nested(self.subnet(enable_dhcp=False),
+                               self.subnet(enable_dhcp=False)):
+            dhcp_rpc = dhcp_rpc_base.DhcpRpcCallbackMixin()
+            self._register_agent_states()
+            hosta_id = self._get_agent_id(constants.AGENT_TYPE_DHCP,
+                                          DHCP_HOSTA)
+            hostc_id = self._get_agent_id(constants.AGENT_TYPE_DHCP,
+                                          DHCP_HOSTC)
+            self._disable_agent(hosta_id)
+            dhcp_rpc.get_active_networks(self.adminContext, host=DHCP_HOSTA)
+            dhcp_rpc.get_active_networks(self.adminContext, host=DHCP_HOSTC)
+            networks = self._list_networks_hosted_by_dhcp_agent(hostc_id)
+            num_hostc_nets = len(networks['networks'])
+            networks = self._list_networks_hosted_by_dhcp_agent(hosta_id)
+            num_hosta_nets = len(networks['networks'])
+        self.assertEqual(0, num_hosta_nets)
+        self.assertEqual(0, num_hostc_nets)
+
+    def test_network_auto_schedule_with_multiple_agents(self):
+        cfg.CONF.set_override('dhcp_agents_per_network', 2)
+        cfg.CONF.set_override('allow_overlapping_ips', True)
+        with contextlib.nested(self.subnet(),
+                               self.subnet()):
+            dhcp_rpc = dhcp_rpc_base.DhcpRpcCallbackMixin()
+            self._register_agent_states()
+            hosta_id = self._get_agent_id(constants.AGENT_TYPE_DHCP,
+                                          DHCP_HOSTA)
+            hostc_id = self._get_agent_id(constants.AGENT_TYPE_DHCP,
+                                          DHCP_HOSTC)
+            dhcp_rpc.get_active_networks(self.adminContext, host=DHCP_HOSTA)
+            dhcp_rpc.get_active_networks(self.adminContext, host=DHCP_HOSTC)
+            networks = self._list_networks_hosted_by_dhcp_agent(hostc_id)
+            num_hostc_nets = len(networks['networks'])
+            networks = self._list_networks_hosted_by_dhcp_agent(hosta_id)
+            num_hosta_nets = len(networks['networks'])
+        self.assertEqual(2, num_hosta_nets)
+        self.assertEqual(2, num_hostc_nets)
+
     def test_network_auto_schedule_with_hosted(self):
         # one agent hosts all the networks, other hosts none
-        with contextlib.nested(self.network(),
-                               self.network()) as (net1, net2):
+        cfg.CONF.set_override('allow_overlapping_ips', True)
+        with contextlib.nested(self.subnet(),
+                               self.subnet()) as (sub1, sub2):
             dhcp_rpc = dhcp_rpc_base.DhcpRpcCallbackMixin()
             self._register_agent_states()
             dhcp_rpc.get_active_networks(self.adminContext, host=DHCP_HOSTA)
             # second agent will not host the network since first has got it.
             dhcp_rpc.get_active_networks(self.adminContext, host=DHCP_HOSTC)
             dhcp_agents = self._list_dhcp_agents_hosting_network(
-                net1['network']['id'])
+                sub1['subnet']['network_id'])
             hosta_id = self._get_agent_id(constants.AGENT_TYPE_DHCP,
                                           DHCP_HOSTA)
             hostc_id = self._get_agent_id(constants.AGENT_TYPE_DHCP,
@@ -287,20 +330,21 @@ class OvsAgentSchedulerTestCase(test_l3_plugin.L3NatTestCaseMixin,
             'agent_type': constants.AGENT_TYPE_DHCP}
         dhcp_hostc = copy.deepcopy(dhcp_hosta)
         dhcp_hostc['host'] = DHCP_HOSTC
-        with self.network() as net1:
+        cfg.CONF.set_override('allow_overlapping_ips', True)
+        with self.subnet() as sub1:
             self._register_one_agent_state(dhcp_hosta)
             dhcp_rpc.get_active_networks(self.adminContext, host=DHCP_HOSTA)
             hosta_id = self._get_agent_id(constants.AGENT_TYPE_DHCP,
                                           DHCP_HOSTA)
             self._disable_agent(hosta_id, admin_state_up=False)
-            with self.network() as net2:
+            with self.subnet() as sub2:
                 self._register_one_agent_state(dhcp_hostc)
                 dhcp_rpc.get_active_networks(self.adminContext,
                                              host=DHCP_HOSTC)
                 dhcp_agents_1 = self._list_dhcp_agents_hosting_network(
-                    net1['network']['id'])
+                    sub1['subnet']['network_id'])
                 dhcp_agents_2 = self._list_dhcp_agents_hosting_network(
-                    net2['network']['id'])
+                    sub2['subnet']['network_id'])
                 hosta_nets = self._list_networks_hosted_by_dhcp_agent(hosta_id)
                 num_hosta_nets = len(hosta_nets['networks'])
                 hostc_id = self._get_agent_id(
@@ -330,6 +374,43 @@ class OvsAgentSchedulerTestCase(test_l3_plugin.L3NatTestCaseMixin,
         self.assertEqual(0, result0)
         self.assertEqual(1, result1)
 
+    def test_network_ha_scheduling_on_port_creation(self):
+        cfg.CONF.set_override('dhcp_agents_per_network', 2)
+        with self.subnet() as subnet:
+            dhcp_agents = self._list_dhcp_agents_hosting_network(
+                subnet['subnet']['network_id'])
+            result0 = len(dhcp_agents['agents'])
+            self._register_agent_states()
+            with self.port(subnet=subnet,
+                           device_owner="compute:test:" + DHCP_HOSTA) as port:
+                dhcp_agents = self._list_dhcp_agents_hosting_network(
+                    port['port']['network_id'])
+                result1 = len(dhcp_agents['agents'])
+        self.assertEqual(0, result0)
+        self.assertEqual(2, result1)
+
+    def test_network_ha_scheduling_on_port_creation_with_new_agent(self):
+        cfg.CONF.set_override('dhcp_agents_per_network', 3)
+        with self.subnet() as subnet:
+            dhcp_agents = self._list_dhcp_agents_hosting_network(
+                subnet['subnet']['network_id'])
+            result0 = len(dhcp_agents['agents'])
+            self._register_agent_states()
+            with self.port(subnet=subnet,
+                           device_owner="compute:test:" + DHCP_HOSTA) as port:
+                dhcp_agents = self._list_dhcp_agents_hosting_network(
+                    port['port']['network_id'])
+                result1 = len(dhcp_agents['agents'])
+            self._register_one_dhcp_agent()
+            with self.port(subnet=subnet,
+                           device_owner="compute:test:" + DHCP_HOSTA) as port:
+                dhcp_agents = self._list_dhcp_agents_hosting_network(
+                    port['port']['network_id'])
+                result2 = len(dhcp_agents['agents'])
+        self.assertEqual(0, result0)
+        self.assertEqual(2, result1)
+        self.assertEqual(3, result2)
+
     def test_network_scheduler_with_disabled_agent(self):
         dhcp_hosta = {
             'binary': 'quantum-dhcp-agent',
@@ -873,6 +954,57 @@ class OvsDhcpAgentNotifierTestCase(test_l3_plugin.L3NatTestCaseMixin,
                     topic='dhcp_agent.' + DHCP_HOSTA)]
             self.assertEqual(mock_dhcp.call_args_list, expected_calls)
 
+    def test_network_ha_port_create_notification(self):
+        cfg.CONF.set_override('dhcp_agents_per_network', 2)
+        dhcp_hosta = {
+            'binary': 'quantum-dhcp-agent',
+            'host': DHCP_HOSTA,
+            'topic': 'dhcp_agent',
+            'configurations': {'dhcp_driver': 'dhcp_driver',
+                               'use_namespaces': True,
+                               },
+            'agent_type': constants.AGENT_TYPE_DHCP}
+        self._register_one_agent_state(dhcp_hosta)
+        dhcp_hostc = copy.deepcopy(dhcp_hosta)
+        dhcp_hostc['host'] = DHCP_HOSTC
+        self._register_one_agent_state(dhcp_hostc)
+        with mock.patch.object(self.dhcp_notifier, 'cast') as mock_dhcp:
+            with self.network(do_delete=False) as net1:
+                with self.subnet(network=net1,
+                                 do_delete=False) as subnet1:
+                    with self.port(subnet=subnet1, no_delete=True) as port:
+                        network_id = port['port']['network_id']
+            expected_calls_a = [
+                mock.call(
+                    mock.ANY,
+                    self.dhcp_notifier.make_msg(
+                        'network_create_end',
+                        payload={'network': {'id': network_id}}),
+                    topic='dhcp_agent.' + DHCP_HOSTA),
+                mock.call(
+                    mock.ANY,
+                    self.dhcp_notifier.make_msg(
+                        'port_create_end',
+                        payload={'port': port['port']}),
+                    topic='dhcp_agent.' + DHCP_HOSTA)]
+            expected_calls_c = [
+                mock.call(
+                    mock.ANY,
+                    self.dhcp_notifier.make_msg(
+                        'network_create_end',
+                        payload={'network': {'id': network_id}}),
+                    topic='dhcp_agent.' + DHCP_HOSTC),
+                mock.call(
+                    mock.ANY,
+                    self.dhcp_notifier.make_msg(
+                        'port_create_end',
+                        payload={'port': port['port']}),
+                    topic='dhcp_agent.' + DHCP_HOSTC)]
+            for expected in expected_calls_a:
+                self.assertIn(expected, mock_dhcp.call_args_list)
+            for expected in expected_calls_c:
+                self.assertIn(expected, mock_dhcp.call_args_list)
+
 
 class OvsL3AgentNotifierTestCase(test_l3_plugin.L3NatTestCaseMixin,
                                  test_agent_ext_plugin.AgentDBTestMixIn,
index ae11be5feb4a16497d8617905242878e11a163d8..f58d98ab59af08156884e0675a9dd047d7540bf9 100644 (file)
@@ -44,6 +44,7 @@ L3_HOSTA = 'hosta'
 DHCP_HOSTA = 'hosta'
 L3_HOSTB = 'hostb'
 DHCP_HOSTC = 'hostc'
+DHCP_HOST1 = 'host1'
 
 
 class AgentTestExtensionManager(object):
@@ -124,6 +125,22 @@ class AgentDBTestMixIn(object):
                               time=timeutils.strtime())
         return [l3_hosta, l3_hostb, dhcp_hosta, dhcp_hostc]
 
+    def _register_one_dhcp_agent(self):
+        """Register one DHCP agent."""
+        dhcp_host = {
+            'binary': 'quantum-dhcp-agent',
+            'host': DHCP_HOST1,
+            'topic': 'DHCP_AGENT',
+            'configurations': {'dhcp_driver': 'dhcp_driver',
+                               'use_namespaces': True,
+                               },
+            'agent_type': constants.AGENT_TYPE_DHCP}
+        callback = agents_db.AgentExtRpcCallback()
+        callback.report_state(self.adminContext,
+                              agent_state={'agent_state': dhcp_host},
+                              time=timeutils.strtime())
+        return [dhcp_host]
+
 
 class AgentDBTestCase(AgentDBTestMixIn,
                       test_db_plugin.QuantumDbPluginV2TestCase):
index 705f3a196751cae726b480dd71640b5140a25ea2..e5458a040f0ad0b46b60978e08d6404c78307aa7 100644 (file)
@@ -25,6 +25,8 @@ from oslo.config import cfg
 from quantum.common import config
 from quantum.common.test_lib import test_config
 from quantum.manager import QuantumManager
+from quantum.manager import validate_post_plugin_load
+from quantum.manager import validate_pre_plugin_load
 from quantum.openstack.common import log as logging
 from quantum.plugins.common import constants
 from quantum.tests import base
@@ -102,3 +104,17 @@ class QuantumManagerTestCase(base.BaseTestCase):
         self.assertIn(constants.CORE, svc_plugins.keys())
         self.assertIn(constants.LOADBALANCER, svc_plugins.keys())
         self.assertIn(constants.DUMMY, svc_plugins.keys())
+
+    def test_post_plugin_validation(self):
+        self.assertIsNone(validate_post_plugin_load())
+        cfg.CONF.set_override('dhcp_agents_per_network', 2)
+        self.assertIsNone(validate_post_plugin_load())
+        cfg.CONF.set_override('dhcp_agents_per_network', 0)
+        self.assertIsNotNone(validate_post_plugin_load())
+        cfg.CONF.set_override('dhcp_agents_per_network', -1)
+        self.assertIsNotNone(validate_post_plugin_load())
+
+    def test_pre_plugin_validation(self):
+        self.assertIsNotNone(validate_pre_plugin_load())
+        cfg.CONF.set_override('core_plugin', 'dummy.plugin')
+        self.assertIsNone(validate_pre_plugin_load())