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
(cherry picked from commit cdf8ba5acb)
(cherry picked from commit a890e3d624)
This commit is contained in:
Matt Riedemann 2018-07-31 11:20:47 -04:00
parent 33dc9f7bbd
commit 4827cedbc5
3 changed files with 38 additions and 5 deletions

View File

@ -961,8 +961,15 @@ class ComputeManager(manager.Manager):
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

View File

@ -468,6 +468,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

View File

@ -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
@ -988,9 +989,20 @@ class OSVIFUtilTestCase(test.NoDBTestCase):
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(