Address infinite loop in nova compute when getting network info

Move the refresh_cache decorator to get_instance_nw_info.
In fact, _get_instance_nw_info is called by the decorator
itself, potentially causing an infinite loop in case nw_info
is not of the expected value. This is also inline with
the method's purpose, as stated by the docstring. At the
same time, ensure that delete_port_for_instance and
allocate_for_instance continue to refresh the cache by
using the decorated version.

Also, add a couple of debug traces that are friendly to
the developer.

Partial-bug: 1235435
Related-bug: 1251792

Change-Id: I06f8634ea241d05ac8fbcc290adf0cb23829f3e4
(cherry picked from commit 2e520496c3)
This commit is contained in:
armando-migliaccio 2013-11-18 16:10:48 -08:00 committed by Yaguang Tang
parent f7cfc1cc6b
commit ef9aec1cb6
4 changed files with 15 additions and 13 deletions

View File

@ -4297,7 +4297,7 @@ class ComputeManager(manager.SchedulerDependentManager):
This is implemented by keeping a cache of uuids of instances
that live on this host. On each call, we pop one off of a
list, pull the DB record, and try the call to the network API.
If anything errors, we don't care. It's possible the instance
If anything errors don't fail, as it's possible the instance
has been deleted, etc.
"""
heal_interval = CONF.heal_instance_info_cache_interval
@ -4338,9 +4338,8 @@ class ComputeManager(manager.SchedulerDependentManager):
self._get_instance_nw_info(context, instance)
LOG.debug(_('Updated the info_cache for instance'),
instance=instance)
except Exception:
# We don't care about any failures
pass
except Exception as e:
LOG.debug(_("An error occurred: %s"), e)
@periodic_task.periodic_task
def _poll_rebooting_instances(self, context):

View File

@ -68,6 +68,7 @@ def refresh_cache(f):
def update_instance_cache_with_nw_info(api, context, instance, nw_info=None,
update_cells=True):
try:
LOG.debug(_('Updating cache with info: %s'), nw_info)
if not isinstance(nw_info, network_model.NetworkInfo):
nw_info = None
if not nw_info:

View File

@ -357,7 +357,7 @@ class API(base.Base):
msg = _("Failed to delete port %s")
LOG.exception(msg, port_id)
nw_info = self._get_instance_nw_info(context, instance, networks=nets)
nw_info = self.get_instance_nw_info(context, instance, networks=nets)
# NOTE(danms): Only return info about ports we created in this run.
# In the initial allocation case, this will be everything we created,
# and in later runs will only be what was created that time. Thus,
@ -438,7 +438,7 @@ class API(base.Base):
LOG.exception(_("Failed to delete neutron port %s") %
port_id)
return self._get_instance_nw_info(context, instance)
return self.get_instance_nw_info(context, instance)
def list_ports(self, context, **search_opts):
"""List ports for the client based on search options."""
@ -448,6 +448,7 @@ class API(base.Base):
"""Return the port for the client given the port id."""
return neutronv2.get_client(context).show_port(port_id)
@refresh_cache
def get_instance_nw_info(self, context, instance, networks=None):
"""Return network information for specified instance
and update cache.
@ -458,8 +459,9 @@ class API(base.Base):
return result
def _get_instance_nw_info(self, context, instance, networks=None):
LOG.debug(_('get_instance_nw_info() for %s'),
instance['display_name'])
# keep this caching-free version of the get_instance_nw_info method
# because it is used by the caching logic itself.
LOG.debug(_('get_instance_nw_info() for %s'), instance['display_name'])
nw_info = self._build_network_info_model(context, instance, networks)
return network_model.NetworkInfo.hydrate(nw_info)

View File

@ -257,7 +257,7 @@ class TestNeutronv2Base(test.TestCase):
def _stub_allocate_for_instance(self, net_idx=1, **kwargs):
api = neutronapi.API()
self.mox.StubOutWithMock(api, '_get_instance_nw_info')
self.mox.StubOutWithMock(api, 'get_instance_nw_info')
has_portbinding = False
has_extra_dhcp_opts = False
# Note: (dkehn) this option check should be removed as soon as support
@ -372,10 +372,10 @@ class TestNeutronv2Base(test.TestCase):
self.moxed_client.create_port(
MyComparator(port_req_body)).AndReturn(res_port)
api._get_instance_nw_info(mox.IgnoreArg(),
self.instance,
networks=nets).AndReturn(
self._returned_nw_info)
api.get_instance_nw_info(mox.IgnoreArg(),
self.instance,
networks=nets).AndReturn(
self._returned_nw_info)
self.mox.ReplayAll()
return api