]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Move network schedule to first port creation.
authorgongysh <gongysh@linux.vnet.ibm.com>
Fri, 1 Mar 2013 08:23:32 +0000 (16:23 +0800)
committergongysh <gongysh@linux.vnet.ibm.com>
Sat, 2 Mar 2013 03:12:46 +0000 (11:12 +0800)
blueprint quantum-scheduler

we remove scheduling network
to dhcp agent when creating network so that we can give admin
the chance to allocate the given network to a given dhcp agent after
network creation.

Change-Id: I228870669825405277de0505a3f2ece074918524

quantum/api/rpc/agentnotifiers/dhcp_rpc_agent_api.py
quantum/db/agentschedulers_db.py
quantum/plugins/nicira/nicira_nvp_plugin/QuantumPlugin.py
quantum/plugins/openvswitch/ovs_quantum_plugin.py
quantum/scheduler/dhcp_agent_scheduler.py
quantum/scheduler/l3_agent_scheduler.py
quantum/tests/unit/openvswitch/test_agent_scheduler.py

index 2a01ad18e8a0a51e55e37937bcde09d7d604d88c..c89e6199a4d1426d352f9c7a4ee9be94171c63d0 100644 (file)
@@ -62,6 +62,19 @@ class DhcpAgentNotifyAPI(proxy.RpcProxy):
         plugin = manager.QuantumManager.get_plugin()
         if (method != 'network_delete_end' and utils.is_extension_supported(
                 plugin, constants.AGENT_SCHEDULER_EXT_ALIAS)):
+            if method == 'port_create_end':
+                # we don't schedule when we create network
+                # because we want to give admin a chance to
+                # schedule network manually by API
+                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'])
             for (host, topic) in self._get_dhcp_agents(context, network_id):
                 self.cast(
                     context, self.make_msg(method,
index 5137820f85439fec38c53dcfcbca05e0c8b8e2cb..bf04be20e288be6ca23faba612ddba2c54d69c1b 100644 (file)
@@ -292,12 +292,13 @@ class AgentSchedulerDbMixin(agentscheduler.AgentSchedulerPluginBase):
             else:
                 return {'agents': []}
 
-    def schedule_network(self, context, request_network, created_network):
+    def schedule_network(self, context, created_network):
         if self.network_scheduler:
-            result = self.network_scheduler.schedule(
-                self, context, request_network, created_network)
-            if not result:
+            chosen_agent = self.network_scheduler.schedule(
+                self, context, created_network)
+            if not chosen_agent:
                 LOG.warn(_('Fail scheduling network %s'), created_network)
+            return chosen_agent
 
     def auto_schedule_networks(self, context, host):
         if self.network_scheduler:
index 8fb8aee1938ac4ceaea8b0c6f53f0eef31a741b3..9ca9d4b72cb02fd1e08809fd7e70e6aa483684fb 100644 (file)
@@ -956,7 +956,7 @@ class NvpPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
                                                    net_binding)
             self._extend_network_port_security_dict(context, new_net)
             self._extend_network_dict_l3(context, new_net)
-        self.schedule_network(context, network['network'], new_net)
+        self.schedule_network(context, new_net)
         return new_net
 
     def delete_network(self, context, id):
@@ -1351,7 +1351,7 @@ class NvpPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
             self._extend_port_dict_security_group(context, port_data)
             self._extend_port_qos_queue(context, port_data)
         net = self.get_network(context, port_data['network_id'])
-        self.schedule_network(context, None, net)
+        self.schedule_network(context, net)
         return port_data
 
     def update_port(self, context, id, port):
index 9c2b72cda207943ba4ef384c20f3064980f950eb..54acdb8ca39e2906f145600c52e93c55b6abcc2a 100644 (file)
@@ -497,7 +497,6 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
             self._extend_network_dict_l3(context, net)
             # note - exception will rollback entire transaction
         LOG.debug(_("Created network: %s"), net['id'])
-        self.schedule_network(context, network['network'], net)
         return net
 
     def update_network(self, context, id, network):
@@ -578,8 +577,6 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
         else:
             self.notifier.security_groups_member_updated(
                 context, port.get(ext_sg.SECURITYGROUPS))
-        net = self.get_network(context, port['network_id'])
-        self.schedule_network(context, None, net)
         return self._extend_port_dict_binding(context, port)
 
     def get_port(self, context, id, fields=None):
index 62929889cbd4bff17a6b70dae16a182fe8895695..e8ae31950d56fd1b990e4485501f7de85ff3399f 100644 (file)
@@ -35,7 +35,7 @@ class ChanceScheduler(object):
     More sophisticated scheduler (similar to filter scheduler in nova?)
     can be introduced later."""
 
-    def schedule(self, plugin, context, request_network, network):
+    def schedule(self, plugin, context, network):
         """Schedule the network to an active DHCP agent if there
         is no active DHCP agent hosting it.
         """
@@ -47,21 +47,21 @@ class ChanceScheduler(object):
             if dhcp_agents:
                 LOG.debug(_('Network %s is hosted already'),
                           network['id'])
-                return False
+                return
             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'))
-                return False
+                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'])]
             if not active_dhcp_agents:
                 LOG.warn(_('No active DHCP agents'))
-                return False
+                return
             chosen_agent = random.choice(active_dhcp_agents)
             binding = agentschedulers_db.NetworkDhcpAgentBinding()
             binding.dhcp_agent = chosen_agent
@@ -71,7 +71,7 @@ class ChanceScheduler(object):
                         'DHCP agent %(agent_id)s'),
                       {'network_id': network['id'],
                        'agent_id': chosen_agent['id']})
-        return True
+        return chosen_agent
 
     def auto_schedule_networks(self, plugin, context, host):
         """Schedule non-hosted networks to the DHCP agent on
index 0d3b1efbb5a41121f37f8028c0b4fc3569ccec70..fda363f325ffbaaf08b73b2322300ae268b78967 100644 (file)
@@ -124,18 +124,18 @@ class ChanceScheduler(object):
                             ' by L3 agent %(agent_id)s'),
                           {'router_id': sync_router['id'],
                            'agent_id': l3_agents[0]['id']})
-                return False
+                return
 
             active_l3_agents = plugin.get_l3_agents(context, active=True)
             if not active_l3_agents:
                 LOG.warn(_('No active L3 agents'))
-                return False
+                return
             candidates = plugin.get_l3_agent_candidates(sync_router,
                                                         active_l3_agents)
             if not candidates:
                 LOG.warn(_('No L3 agents can host the router %s'),
                          sync_router['id'])
-                return False
+                return
 
             chosen_agent = random.choice(candidates)
             binding = agentschedulers_db.RouterL3AgentBinding()
@@ -146,4 +146,4 @@ class ChanceScheduler(object):
                         'L3 agent %(agent_id)s'),
                       {'router_id': sync_router['id'],
                        'agent_id': chosen_agent['id']})
-            return True
+            return chosen_agent
index 38c74ca9bdc0696ac2201277516d9b2e459b846a..4c80ca15b4895d46d6e6960854075ff2fdf5afed 100644 (file)
@@ -20,6 +20,7 @@ import mock
 from webob import exc
 
 from quantum.api import extensions
+from quantum.api.rpc.agentnotifiers import dhcp_rpc_agent_api
 from quantum.common import constants
 from quantum import context
 from quantum.db import agents_db
@@ -28,7 +29,6 @@ from quantum.db import l3_rpc_base
 from quantum.extensions import agentscheduler
 from quantum import manager
 from quantum.openstack.common import uuidutils
-from quantum.plugins.openvswitch.ovs_quantum_plugin import OVSQuantumPluginV2
 from quantum.tests.unit import test_agent_ext_plugin
 from quantum.tests.unit.testlib_api import create_request
 from quantum.tests.unit import test_db_plugin as test_plugin
@@ -183,27 +183,20 @@ class AgentSchedulerTestMixIn(object):
                 return agent['id']
 
 
-class AgentSchedulerTestCase(test_l3_plugin.L3NatTestCaseMixin,
-                             test_agent_ext_plugin.AgentDBTestMixIn,
-                             AgentSchedulerTestMixIn,
-                             test_plugin.QuantumDbPluginV2TestCase):
+class OvsAgentSchedulerTestCase(test_l3_plugin.L3NatTestCaseMixin,
+                                test_agent_ext_plugin.AgentDBTestMixIn,
+                                AgentSchedulerTestMixIn,
+                                test_plugin.QuantumDbPluginV2TestCase):
     fmt = 'json'
+    plugin_str = ('quantum.plugins.openvswitch.'
+                  'ovs_quantum_plugin.OVSQuantumPluginV2')
 
     def setUp(self):
-        plugin = ('quantum.plugins.openvswitch.'
-                  'ovs_quantum_plugin.OVSQuantumPluginV2')
-        self.dhcp_notifier_cls_p = mock.patch(
-            'quantum.api.rpc.agentnotifiers.dhcp_rpc_agent_api.'
-            'DhcpAgentNotifyAPI')
-        self.dhcp_notifier = mock.Mock(name='dhcp_notifier')
-        self.dhcp_notifier_cls = self.dhcp_notifier_cls_p.start()
-        self.dhcp_notifier_cls.return_value = self.dhcp_notifier
-        super(AgentSchedulerTestCase, self).setUp(plugin)
+        super(OvsAgentSchedulerTestCase, self).setUp(self.plugin_str)
         ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
         self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
         self.adminContext = context.get_admin_context()
         self.agentscheduler_dbMinxin = manager.QuantumManager.get_plugin()
-        self.addCleanup(self.dhcp_notifier_cls_p.stop)
 
     def test_report_states(self):
         self._register_agent_states()
@@ -215,7 +208,7 @@ class AgentSchedulerTestCase(test_l3_plugin.L3NatTestCaseMixin,
         with self.network() as net:
             dhcp_agents = self._list_dhcp_agents_hosting_network(
                 net['network']['id'])
-        self.assertEqual(1, len(dhcp_agents['agents']))
+        self.assertEqual(0, len(dhcp_agents['agents']))
 
     def test_network_auto_schedule_with_disabled(self):
         with contextlib.nested(self.network(),
@@ -328,15 +321,15 @@ class AgentSchedulerTestCase(test_l3_plugin.L3NatTestCaseMixin,
                                },
             'agent_type': constants.AGENT_TYPE_DHCP}
         self._register_one_agent_state(dhcp_hosta)
-        with self.network() as net1:
+        with self.port() as port1:
             dhcp_agents = self._list_dhcp_agents_hosting_network(
-                net1['network']['id'])
+                port1['port']['network_id'])
         self.assertEqual(1, len(dhcp_agents['agents']))
         agents = self._list_agents()
         self._disable_agent(agents['agents'][0]['id'])
-        with self.network() as net2:
+        with self.port() as port2:
             dhcp_agents = self._list_dhcp_agents_hosting_network(
-                net2['network']['id'])
+                port2['port']['network_id'])
         self.assertEqual(0, len(dhcp_agents['agents']))
 
     def test_network_scheduler_with_down_agent(self):
@@ -352,18 +345,19 @@ class AgentSchedulerTestCase(test_l3_plugin.L3NatTestCaseMixin,
         is_agent_down_str = 'quantum.db.agents_db.AgentDbMixin.is_agent_down'
         with mock.patch(is_agent_down_str) as mock_is_agent_down:
             mock_is_agent_down.return_value = False
-            with self.network() as net:
+            with self.port() as port:
                 dhcp_agents = self._list_dhcp_agents_hosting_network(
-                    net['network']['id'])
+                    port['port']['network_id'])
             self.assertEqual(1, len(dhcp_agents['agents']))
         with mock.patch(is_agent_down_str) as mock_is_agent_down:
             mock_is_agent_down.return_value = True
-            with self.network() as net:
+            with self.port() as port:
                 dhcp_agents = self._list_dhcp_agents_hosting_network(
-                    net['network']['id'])
+                    port['port']['network_id'])
             self.assertEqual(0, len(dhcp_agents['agents']))
 
     def test_network_scheduler_with_hosted_network(self):
+        plugin = manager.QuantumManager.get_plugin()
         dhcp_hosta = {
             'binary': 'quantum-dhcp-agent',
             'host': DHCP_HOSTA,
@@ -373,20 +367,26 @@ class AgentSchedulerTestCase(test_l3_plugin.L3NatTestCaseMixin,
                                },
             'agent_type': constants.AGENT_TYPE_DHCP}
         self._register_one_agent_state(dhcp_hosta)
-        agents = self._list_agents()
-        with self.network() as net1:
+        with self.port() as port1:
             dhcp_agents = self._list_dhcp_agents_hosting_network(
-                net1['network']['id'])
+                port1['port']['network_id'])
             self.assertEqual(1, len(dhcp_agents['agents']))
-        with mock.patch.object(OVSQuantumPluginV2,
+        with mock.patch.object(plugin,
                                'get_dhcp_agents_hosting_networks',
                                autospec=True) as mock_hosting_agents:
 
-            mock_hosting_agents.return_value = agents['agents']
-            with self.network(do_delete=False) as net2:
+            mock_hosting_agents.return_value = plugin.get_agents_db(
+                self.adminContext)
+            with self.network('test', do_delete=False) as net1:
+                pass
+            with self.subnet(network=net1,
+                             cidr='10.0.1.0/24',
+                             do_delete=False) as subnet1:
+                pass
+            with self.port(subnet=subnet1, no_delete=True) as port2:
                 pass
         dhcp_agents = self._list_dhcp_agents_hosting_network(
-            net2['network']['id'])
+            port2['port']['network_id'])
         self.assertEqual(0, len(dhcp_agents['agents']))
 
     def test_network_policy(self):
@@ -440,12 +440,12 @@ class AgentSchedulerTestCase(test_l3_plugin.L3NatTestCaseMixin,
         self._register_one_agent_state(dhcp_hosta)
         hosta_id = self._get_agent_id(constants.AGENT_TYPE_DHCP,
                                       DHCP_HOSTA)
-        with self.network() as net1:
+        with self.port() as port1:
             num_before_remove = len(
                 self._list_networks_hosted_by_dhcp_agent(
                     hosta_id)['networks'])
             self._remove_network_from_dhcp_agent(hosta_id,
-                                                 net1['network']['id'])
+                                                 port1['port']['network_id'])
             num_after_remove = len(
                 self._list_networks_hosted_by_dhcp_agent(
                     hosta_id)['networks'])
@@ -731,20 +731,119 @@ class AgentSchedulerTestCase(test_l3_plugin.L3NatTestCaseMixin,
                 admin_context=False)
 
 
-class L3AgentNotifierTestCase(test_l3_plugin.L3NatTestCaseMixin,
-                              test_agent_ext_plugin.AgentDBTestMixIn,
-                              AgentSchedulerTestMixIn,
-                              test_plugin.QuantumDbPluginV2TestCase):
+class OvsDhcpAgentNotifierTestCase(test_l3_plugin.L3NatTestCaseMixin,
+                                   test_agent_ext_plugin.AgentDBTestMixIn,
+                                   AgentSchedulerTestMixIn,
+                                   test_plugin.QuantumDbPluginV2TestCase):
+    plugin_str = ('quantum.plugins.openvswitch.'
+                  'ovs_quantum_plugin.OVSQuantumPluginV2')
+
     def setUp(self):
-        plugin = ('quantum.plugins.openvswitch.'
+        self.dhcp_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
+        self.dhcp_notifier_cls_p = mock.patch(
+            'quantum.api.rpc.agentnotifiers.dhcp_rpc_agent_api.'
+            'DhcpAgentNotifyAPI')
+        self.dhcp_notifier_cls = self.dhcp_notifier_cls_p.start()
+        self.dhcp_notifier_cls.return_value = self.dhcp_notifier
+        super(OvsDhcpAgentNotifierTestCase, self).setUp(self.plugin_str)
+        ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
+        self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
+        self.adminContext = context.get_admin_context()
+        self.addCleanup(self.dhcp_notifier_cls_p.stop)
+
+    def test_network_add_to_dhcp_agent_notification(self):
+        with mock.patch.object(self.dhcp_notifier, 'cast') as mock_dhcp:
+            with self.network() as net1:
+                network_id = net1['network']['id']
+                self._register_agent_states()
+                hosta_id = self._get_agent_id(constants.AGENT_TYPE_DHCP,
+                                              DHCP_HOSTA)
+                self._add_network_to_dhcp_agent(hosta_id,
+                                                network_id)
+            mock_dhcp.assert_called_with(
+                mock.ANY,
+                self.dhcp_notifier.make_msg(
+                    'network_create_end',
+                    payload={'network': {'id': network_id}}),
+                topic='dhcp_agent.' + DHCP_HOSTA)
+
+    def test_network_remove_from_dhcp_agent_notification(self):
+        with self.network(do_delete=False) as net1:
+            network_id = net1['network']['id']
+            self._register_agent_states()
+            hosta_id = self._get_agent_id(constants.AGENT_TYPE_DHCP,
+                                          DHCP_HOSTA)
+            self._add_network_to_dhcp_agent(hosta_id,
+                                            network_id)
+        with mock.patch.object(self.dhcp_notifier, 'cast') as mock_dhcp:
+            self._remove_network_from_dhcp_agent(hosta_id,
+                                                 network_id)
+            mock_dhcp.assert_called_with(
+                mock.ANY,
+                self.dhcp_notifier.make_msg(
+                    'network_delete_end',
+                    payload={'network_id': network_id}),
+                topic='dhcp_agent.' + DHCP_HOSTA)
+
+    def test_agent_updated_dhcp_agent_notification(self):
+        with mock.patch.object(self.dhcp_notifier, 'cast') as mock_dhcp:
+            self._register_agent_states()
+            hosta_id = self._get_agent_id(constants.AGENT_TYPE_DHCP,
+                                          DHCP_HOSTA)
+            self._disable_agent(hosta_id, admin_state_up=False)
+            mock_dhcp.assert_called_with(
+                mock.ANY, self.dhcp_notifier.make_msg(
+                    'agent_updated',
+                    payload={'admin_state_up': False}),
+                topic='dhcp_agent.' + DHCP_HOSTA)
+
+    def test_network_port_create_notification(self):
+        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)
+        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 = [
+                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)]
+            self.assertEqual(mock_dhcp.call_args_list, expected_calls)
+
+
+class OvsL3AgentNotifierTestCase(test_l3_plugin.L3NatTestCaseMixin,
+                                 test_agent_ext_plugin.AgentDBTestMixIn,
+                                 AgentSchedulerTestMixIn,
+                                 test_plugin.QuantumDbPluginV2TestCase):
+    plugin_str = ('quantum.plugins.openvswitch.'
                   'ovs_quantum_plugin.OVSQuantumPluginV2')
+
+    def setUp(self):
         self.dhcp_notifier_cls_p = mock.patch(
             'quantum.api.rpc.agentnotifiers.dhcp_rpc_agent_api.'
             'DhcpAgentNotifyAPI')
         self.dhcp_notifier = mock.Mock(name='dhcp_notifier')
         self.dhcp_notifier_cls = self.dhcp_notifier_cls_p.start()
         self.dhcp_notifier_cls.return_value = self.dhcp_notifier
-        super(L3AgentNotifierTestCase, self).setUp(plugin)
+        super(OvsL3AgentNotifierTestCase, self).setUp(self.plugin_str)
         ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
         self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
         self.adminContext = context.get_admin_context()
@@ -799,5 +898,5 @@ class L3AgentNotifierTestCase(test_l3_plugin.L3NatTestCaseMixin,
                 topic='l3_agent.hosta')
 
 
-class AgentSchedulerTestCaseXML(AgentSchedulerTestCase):
+class OvsAgentSchedulerTestCaseXML(OvsAgentSchedulerTestCase):
     fmt = 'xml'