From d4fa1d7da15a1c9c69a81365e34c8d94ebd070a2 Mon Sep 17 00:00:00 2001 From: Claudiu Belu Date: Tue, 30 Jan 2018 06:26:18 -0800 Subject: [PATCH] hyper-v: Logs tips on PortBindingFailed When spawning an Hyper-V instance with NICs having the vif_type "hyperv", neutron will fail to bind the port to the Hyper-V host if the neutron server doesn't have the "hyperv" mechanism driver installed and configured, resulting in a PortBindingFailed exception on the nova-compute side. When this exception is encountered, the logs will say to check the neutron-server logs, but the problem and its solution are not obvious or clear, resulting in plenty of questions / reports, all having the same solution: is there an L2 agent on the host alive and reporting to neutron, and if neutron Hyper-V agent is used, make sure to install networking-hyperv and configure neutron-server to use the "hyperv" mechanism_driver. Change-Id: I94ed8f15f3c6312a6f675b9255aff7e9d76f96fc Closes-Bug: #1744032 --- compute_hyperv/nova/vmops.py | 16 +++++++++++++++- compute_hyperv/tests/unit/test_vmops.py | 12 ++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/compute_hyperv/nova/vmops.py b/compute_hyperv/nova/vmops.py index 9b14f34c..c988a2bc 100644 --- a/compute_hyperv/nova/vmops.py +++ b/compute_hyperv/nova/vmops.py @@ -352,9 +352,11 @@ class VMOps(object): @contextlib.contextmanager def wait_vif_plug_events(self, instance, network_info): timeout = CONF.vif_plugging_timeout - events = self._get_neutron_events(network_info) try: + # NOTE(claudiub): async calls to bind the neutron ports will be + # done when network_info is being accessed. + events = self._get_neutron_events(network_info) with self._virtapi.wait_for_instance_event( instance, events, deadline=timeout, error_callback=self._neutron_failed_callback): @@ -365,6 +367,18 @@ class VMOps(object): 'instance.', instance=instance) if CONF.vif_plugging_is_fatal: raise exception.VirtualInterfaceCreateException() + except exception.PortBindingFailed: + LOG.warning( + "Neutron failed to bind a port to this host. Make sure that " + "an L2 agent is registered on this node and alive (Neutron " + "Open vSwitch agent or Hyper-V agent), or that Neutron is " + "configured with a mechanism driver that is able to bind " + "ports without requiring an L2 agent on this host (e.g. OVN " + "mechanism driver). If you're using Neutron Hyper-V agent, " + "make sure that networking-hyperv is installed on the " + "Neutron controller and that the neutron-server service was " + "configured to use the 'hyperv' mechanism_driver.") + raise def _neutron_failed_callback(self, event_name, instance): LOG.error('Neutron Reported failure on event %s', diff --git a/compute_hyperv/tests/unit/test_vmops.py b/compute_hyperv/tests/unit/test_vmops.py index 3ab978d9..ecaffe7a 100644 --- a/compute_hyperv/tests/unit/test_vmops.py +++ b/compute_hyperv/tests/unit/test_vmops.py @@ -616,6 +616,18 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase): deadline=CONF.vif_plugging_timeout, error_callback=self._vmops._neutron_failed_callback) + @mock.patch.object(vmops.VMOps, '_get_neutron_events') + def test_wait_vif_plug_events_port_binding_failed(self, mock_get_events): + mock_get_events.side_effect = exception.PortBindingFailed( + port_id='fake_id') + + def _context_user(): + with self._vmops.wait_vif_plug_events(mock.sentinel.instance, + mock.sentinel.network_info): + pass + + self.assertRaises(exception.PortBindingFailed, _context_user) + def test_neutron_failed_callback(self): self.flags(vif_plugging_is_fatal=True) self.assertRaises(exception.VirtualInterfaceCreateException,