From 028cca90c7c5e2b17205740d9198cbb443e6a2b2 Mon Sep 17 00:00:00 2001 From: Petrut Lucian Date: Tue, 17 Sep 2013 19:15:41 +0300 Subject: [PATCH] Fixes Hyper-V agent RPC calls for ML2 support Adds support for the RPC report status in the Hyper-V agent and plugin. Fixes bug: #1226654 Change-Id: Ie5eee875afc062c536856589d6a3fd0414190f6d --- .../hyperv/agent/hyperv_neutron_agent.py | 37 +++++++++++++++++-- .../plugins/hyperv/hyperv_neutron_plugin.py | 7 ++-- neutron/plugins/hyperv/rpc_callbacks.py | 4 +- neutron/plugins/ml2/drivers/mech_hyperv.py | 8 +++- .../unit/hyperv/test_hyperv_neutron_agent.py | 29 +++++++++++++++ 5 files changed, 76 insertions(+), 9 deletions(-) diff --git a/neutron/plugins/hyperv/agent/hyperv_neutron_agent.py b/neutron/plugins/hyperv/agent/hyperv_neutron_agent.py index 40c347a8a..c4421a3b3 100644 --- a/neutron/plugins/hyperv/agent/hyperv_neutron_agent.py +++ b/neutron/plugins/hyperv/agent/hyperv_neutron_agent.py @@ -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 diff --git a/neutron/plugins/hyperv/hyperv_neutron_plugin.py b/neutron/plugins/hyperv/hyperv_neutron_plugin.py index 943d11204..07d6c9d3e 100644 --- a/neutron/plugins/hyperv/hyperv_neutron_plugin.py +++ b/neutron/plugins/hyperv/hyperv_neutron_plugin.py @@ -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() diff --git a/neutron/plugins/hyperv/rpc_callbacks.py b/neutron/plugins/hyperv/rpc_callbacks.py index 9f596b2aa..aa8b7c0b9 100644 --- a/neutron/plugins/hyperv/rpc_callbacks.py +++ b/neutron/plugins/hyperv/rpc_callbacks.py @@ -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.""" diff --git a/neutron/plugins/ml2/drivers/mech_hyperv.py b/neutron/plugins/ml2/drivers/mech_hyperv.py index a6c8d4225..87cf6c22c 100644 --- a/neutron/plugins/ml2/drivers/mech_hyperv.py +++ b/neutron/plugins/ml2/drivers/mech_hyperv.py @@ -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 diff --git a/neutron/tests/unit/hyperv/test_hyperv_neutron_agent.py b/neutron/tests/unit/hyperv/test_hyperv_neutron_agent.py index f9e17d41b..59cdcb896 100644 --- a/neutron/tests/unit/hyperv/test_hyperv_neutron_agent.py +++ b/neutron/tests/unit/hyperv/test_hyperv_neutron_agent.py @@ -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: -- 2.45.2