From cdf8ba5acb7f65042af9c21fcbe1a126bd857ad0 Mon Sep 17 00:00:00 2001 From: Matt Riedemann Date: Tue, 31 Jul 2018 11:20:47 -0400 Subject: [PATCH] Handle binding_failed vif plug errors on compute restart Like change Ia584dba66affb86787e3069df19bd17b89cb5c49 which came before, is port binding fails and we have a "binding_failed" vif type in the info cache, we'll fail to plug vifs for an instance on compute restart which will prevent the service from restarting. Before the os-vif conversion code, this was handled with VirtualInterfacePlugException but the os-vif conversion code fails in a different way by raising a generic NovaException because the os-vif conversion utility doesn't handle a vif_type of "binding_failed". To resolve this and make the os-vif flow for binding_failed behave the same as the legacy path, we implement a translation function in os_vif_util for binding_failed which will make the plug_vifs code raise VirtualInterfacePlugException which is what the _init_instance code in ComputeManager is already handling. Admittedly this isn't the smartest thing and doesn't attempt to recover / fix the instance networking info, but it at least gives a more clear indication of what's wrong and lets the nova-compute service start up. A note is left in the _init_instance error handling that we could potentially try to heal binding_failed vifs in _heal_instance_info_cache, but that would need to be done in a separate change since it's more invasive. Change-Id: Ia963a093a1b26d90b4de2e8fc623031cf175aece Closes-Bug: #1784579 --- nova/compute/manager.py | 11 +++++++++-- nova/network/os_vif_util.py | 14 ++++++++++++++ nova/tests/unit/network/test_os_vif_util.py | 18 +++++++++++++++--- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 0e31263a67a..326b7f9dec1 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -959,8 +959,15 @@ def _init_instance(self, context, instance): except NotImplementedError as e: LOG.debug(e, instance=instance) except exception.VirtualInterfacePlugException: - # we don't want an exception to block the init_host - LOG.exception("Vifs plug failed", instance=instance) + # NOTE(mriedem): If we get here, it could be because the vif_type + # in the cache is "binding_failed". The only way to fix that is to + # try and bind the ports again, which would be expensive here on + # host startup. We could add a check to _heal_instance_info_cache + # to handle this, but probably only if the instance task_state is + # None. + LOG.exception('Virtual interface plugging failed for instance. ' + 'The port binding:host_id may need to be manually ' + 'updated.', instance=instance) self._set_instance_obj_error_state(context, instance) return diff --git a/nova/network/os_vif_util.py b/nova/network/os_vif_util.py index 1634fb36ff4..e00845737e1 100644 --- a/nova/network/os_vif_util.py +++ b/nova/network/os_vif_util.py @@ -481,6 +481,20 @@ def _nova_to_osvif_vif_hostdev_physical(vif): raise NotImplementedError() +# VIF_TYPE_BINDING_FAILED = 'binding_failed' +def _nova_to_osvif_vif_binding_failed(vif): + """Special handler for the "binding_failed" vif type. + + The "binding_failed" vif type indicates port binding to a host failed + and we are trying to plug the vifs again, which will fail because we + do not know the actual real vif type, like ovs, bridge, etc. We raise + NotImplementedError to indicate to the caller that we cannot handle + this type of vif rather than the generic "Unsupported VIF type" error + in nova_to_osvif_vif. + """ + raise NotImplementedError() + + def nova_to_osvif_vif(vif): """Convert a Nova VIF model to an os-vif object diff --git a/nova/tests/unit/network/test_os_vif_util.py b/nova/tests/unit/network/test_os_vif_util.py index 1864f99a48c..203cf83cf9a 100644 --- a/nova/tests/unit/network/test_os_vif_util.py +++ b/nova/tests/unit/network/test_os_vif_util.py @@ -14,6 +14,7 @@ from os_vif import objects as osv_objects from os_vif.objects import fields as os_vif_fields +import six from nova import exception from nova.network import model @@ -1013,9 +1014,20 @@ def test_nova_to_osvif_vif_unknown(self): subnets=[]), ) - self.assertRaises(exception.NovaException, - os_vif_util.nova_to_osvif_vif, - vif) + ex = self.assertRaises(exception.NovaException, + os_vif_util.nova_to_osvif_vif, vif) + self.assertIn('Unsupported VIF type wibble', six.text_type(ex)) + + def test_nova_to_osvif_vif_binding_failed(self): + vif = model.VIF( + id="dc065497-3c8d-4f44-8fb4-e1d33c16a536", + type="binding_failed", + address="22:52:25:62:e2:aa", + network=model.Network( + id="b82c1929-051e-481d-8110-4669916c7915", + label="Demo Net", + subnets=[]),) + self.assertIsNone(os_vif_util.nova_to_osvif_vif(vif)) def test_nova_to_osvif_vhostuser_vrouter(self): vif = model.VIF(