]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Fixes Hyper-V agent RPC calls for ML2 support
authorPetrut Lucian <lpetrut@cloudbasesolutions.com>
Tue, 17 Sep 2013 16:15:41 +0000 (19:15 +0300)
committerPetrut Lucian <lpetrut@cloudbasesolutions.com>
Wed, 25 Sep 2013 19:36:42 +0000 (22:36 +0300)
Adds support for the RPC report status in the Hyper-V
agent and plugin.

Fixes bug: #1226654

Change-Id: Ie5eee875afc062c536856589d6a3fd0414190f6d

neutron/plugins/hyperv/agent/hyperv_neutron_agent.py
neutron/plugins/hyperv/hyperv_neutron_plugin.py
neutron/plugins/hyperv/rpc_callbacks.py
neutron/plugins/ml2/drivers/mech_hyperv.py
neutron/tests/unit/hyperv/test_hyperv_neutron_agent.py

index 40c347a8ac8c6aba20bed003509bef51c8051fd4..c4421a3b3b7a222d7ab124c49e10623d30152ee9 100644 (file)
@@ -25,11 +25,14 @@ import time
 
 from oslo.config import cfg
 
+from neutron.agent.common import config
 from neutron.agent import rpc as agent_rpc
 from neutron.common import config as logging_config
+from neutron.common import constants as n_const
 from neutron.common import topics
 from neutron import context
 from neutron.openstack.common import log as logging
+from neutron.openstack.common import loopingcall
 from neutron.openstack.common.rpc import dispatcher
 from neutron.plugins.hyperv.agent import utils
 from neutron.plugins.hyperv.agent import utilsfactory
@@ -63,6 +66,7 @@ agent_opts = [
 
 CONF = cfg.CONF
 CONF.register_opts(agent_opts, "AGENT")
+config.register_agent_state_opts_helper(cfg.CONF)
 
 
 class HyperVNeutronAgent(object):
@@ -74,13 +78,34 @@ class HyperVNeutronAgent(object):
         self._polling_interval = CONF.AGENT.polling_interval
         self._load_physical_network_mappings()
         self._network_vswitch_map = {}
+        self._set_agent_state()
         self._setup_rpc()
 
+    def _set_agent_state(self):
+        self.agent_state = {
+            'binary': 'neutron-hyperv-agent',
+            'host': cfg.CONF.host,
+            'topic': n_const.L2_AGENT_TOPIC,
+            'configurations': {'vswitch_mappings':
+                               self._physical_network_mappings},
+            'agent_type': n_const.AGENT_TYPE_HYPERV,
+            'start_flag': True}
+
+    def _report_state(self):
+        try:
+            self.state_rpc.report_state(self.context,
+                                        self.agent_state)
+            self.agent_state.pop('start_flag', None)
+        except Exception as ex:
+            LOG.exception(_("Failed reporting state! %s"), ex)
+
     def _setup_rpc(self):
         self.agent_id = 'hyperv_%s' % platform.node()
         self.topic = topics.AGENT
         self.plugin_rpc = agent_rpc.PluginApi(topics.PLUGIN)
 
+        self.state_rpc = agent_rpc.PluginReportStateAPI(topics.PLUGIN)
+
         # RPC network init
         self.context = context.get_admin_context_without_session()
         # Handle updates from service
@@ -93,6 +118,10 @@ class HyperVNeutronAgent(object):
         self.connection = agent_rpc.create_consumers(self.dispatcher,
                                                      self.topic,
                                                      consumers)
+        report_interval = CONF.AGENT.report_interval
+        if report_interval:
+            heartbeat = loopingcall.LoopingCall(self._report_state)
+            heartbeat.start(interval=report_interval)
 
     def _load_physical_network_mappings(self):
         self._physical_network_mappings = {}
@@ -103,14 +132,14 @@ class HyperVNeutronAgent(object):
             else:
                 pattern = re.escape(parts[0].strip()).replace('\\*', '.*')
                 vswitch = parts[1].strip()
-                self._physical_network_mappings[re.compile(pattern)] = vswitch
+                self._physical_network_mappings[pattern] = vswitch
 
     def _get_vswitch_for_physical_network(self, phys_network_name):
-        for compre in self._physical_network_mappings:
+        for pattern in self._physical_network_mappings:
             if phys_network_name is None:
                 phys_network_name = ''
-            if compre.match(phys_network_name):
-                return self._physical_network_mappings[compre]
+            if re.match(pattern, phys_network_name):
+                return self._physical_network_mappings[pattern]
         # Not found in the mappings, the vswitch has the same name
         return phys_network_name
 
index 943d11204f2627598c16e8e6fcfd59f5fcb5e04d..07d6c9d3e49e47fafa6067758187a10381f550b8 100644 (file)
@@ -21,6 +21,7 @@ from oslo.config import cfg
 from neutron.api.v2 import attributes
 from neutron.common import exceptions as q_exc
 from neutron.common import topics
+from neutron.db import agents_db
 from neutron.db import db_base_plugin_v2
 from neutron.db import external_net_db
 from neutron.db import l3_gwmode_db
@@ -143,7 +144,8 @@ class VlanNetworkProvider(BaseNetworkProvider):
         network[provider.SEGMENTATION_ID] = binding.segmentation_id
 
 
-class HyperVNeutronPlugin(db_base_plugin_v2.NeutronDbPluginV2,
+class HyperVNeutronPlugin(agents_db.AgentDbMixin,
+                          db_base_plugin_v2.NeutronDbPluginV2,
                           external_net_db.External_net_db_mixin,
                           l3_gwmode_db.L3_NAT_db_mixin,
                           portbindings_base.PortBindingBaseMixin):
@@ -153,7 +155,7 @@ class HyperVNeutronPlugin(db_base_plugin_v2.NeutronDbPluginV2,
     # is qualified by class
     __native_bulk_support = True
     supported_extension_aliases = ["provider", "external-net", "router",
-                                   "ext-gw-mode", "binding", "quotas"]
+                                   "agent", "ext-gw-mode", "binding", "quotas"]
 
     def __init__(self, configfile=None):
         self._db = hyperv_db.HyperVPluginDB()
@@ -165,7 +167,6 @@ class HyperVNeutronPlugin(db_base_plugin_v2.NeutronDbPluginV2,
 
         self._parse_network_vlan_ranges()
         self._create_network_providers_map()
-
         self._db.sync_vlan_allocations(self._network_vlan_ranges)
 
         self._setup_rpc()
index 9f596b2aa910e29bcdd541abb30a7afc157e3bd1..aa8b7c0b98da0b16611c14b54fb9384a95f4c655 100644 (file)
@@ -18,6 +18,7 @@
 
 from neutron.common import constants as q_const
 from neutron.common import rpc as q_rpc
+from neutron.db import agents_db
 from neutron.db import dhcp_rpc_base
 from neutron.db import l3_rpc_base
 from neutron.openstack.common import log as logging
@@ -44,7 +45,8 @@ class HyperVRpcCallbacks(
         If a manager would like to set an rpc API version, or support more than
         one class as the target of rpc messages, override this method.
         '''
-        return q_rpc.PluginRpcDispatcher([self])
+        return q_rpc.PluginRpcDispatcher([self,
+                                         agents_db.AgentExtRpcCallback()])
 
     def get_device_details(self, rpc_context, **kwargs):
         """Agent requests device details."""
index a6c8d4225b3672916a4208c277759063a18b1c5c..87cf6c22c433865af572b01ee817de01575594f5 100644 (file)
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import re
+
 from neutron.common import constants
 from neutron.extensions import portbindings
 from neutron.openstack.common import log
@@ -46,6 +48,10 @@ class HypervMechanismDriver(mech_agent.AgentMechanismDriverBase):
         if network_type == 'local':
             return True
         elif network_type in ['flat', 'vlan']:
-            return segment[api.PHYSICAL_NETWORK] in mappings
+            for pattern in mappings:
+                if re.match(pattern, segment[api.PHYSICAL_NETWORK]):
+                    return True
+            else:
+                return False
         else:
             return False
index f9e17d41bb687b78f9c3da4d75469b6d07ebac8b..59cdcb896a43ed9664b3200f816cc671b68e5766 100644 (file)
@@ -39,11 +39,32 @@ class TestHyperVNeutronAgent(base.BaseTestCase):
 
         utilsfactory._get_windows_version = mock.MagicMock(
             return_value='6.2.0')
+
+        class MockFixedIntervalLoopingCall(object):
+            def __init__(self, f):
+                self.f = f
+
+            def start(self, interval=0):
+                self.f()
+
+        mock.patch('neutron.openstack.common.loopingcall.'
+                   'FixedIntervalLoopingCall',
+                   new=MockFixedIntervalLoopingCall)
+
         self.agent = hyperv_neutron_agent.HyperVNeutronAgent()
         self.agent.plugin_rpc = mock.Mock()
         self.agent.context = mock.Mock()
         self.agent.agent_id = mock.Mock()
 
+        fake_agent_state = {
+            'binary': 'neutron-hyperv-agent',
+            'host': 'fake_host_name',
+            'topic': 'N/A',
+            'configurations': {'vswitch_mappings': ['*:MyVirtualSwitch']},
+            'agent_type': 'HyperV agent',
+            'start_flag': True}
+        self.agent_state = fake_agent_state
+
     def test_port_bound(self):
         port = mock.Mock()
         net_uuid = 'my-net-uuid'
@@ -112,6 +133,14 @@ class TestHyperVNeutronAgent(base.BaseTestCase):
     def test_treat_devices_removed_ignores_missing_port(self):
         self.mock_treat_devices_removed(False)
 
+    def test_report_state(self):
+        with mock.patch.object(self.agent.state_rpc,
+                               "report_state") as report_st:
+            self.agent._report_state()
+            report_st.assert_called_with(self.agent.context,
+                                         self.agent.agent_state)
+            self.assertNotIn("start_flag", self.agent.agent_state)
+
     def test_main(self):
         with mock.patch.object(hyperv_neutron_agent,
                                'HyperVNeutronAgent') as plugin: