Remove network_api fallback for info_cache from APIs

Fixes bug 932395

OS API and EC2 would query the network API when instance['info_cache']
had no network info.. or network info was an empty list.  The ideal was
to fall back to querying the network IP in case the cache was busted.

However, reality says this case is extremely common as it is the case
when instances are freshly built and haven't had network info assigned
yet.  The calls to network API are expensive and goes against the whole
idea of this "cache".

So, this patch removes the fallback to querying the network API.  In its
place, it adds a periodic task to the compute manager to periodically
sync the cache entry.

Since I had to fix a number of tests, I consolidated some things there
as well with regards to instance stubbing.

Change-Id: I493f811bcba4e99ac6a5756bcab473557d5c0104
This commit is contained in:
Chris Behrens
2012-02-17 00:42:10 +00:00
parent 2191e1c69c
commit 1d0eef7f99

View File

@@ -19,7 +19,7 @@
"""
Tests For Compute
"""
from copy import copy
import copy
import datetime
import sys
import time
@@ -1604,6 +1604,81 @@ class ComputeTestCase(BaseTestCase):
val = self.compute._running_deleted_instances('context')
self.assertEqual(val, [instance1])
def test_heal_instance_info_cache(self):
# Update on every call for the test
self.flags(heal_instance_info_cache_interval=-1)
ctxt = context.get_admin_context()
instance_map = {}
instances = []
for x in xrange(5):
uuid = 'fake-uuid-%s' % x
instance_map[uuid] = {'uuid': uuid, 'host': FLAGS.host}
instances.append(instance_map[uuid])
call_info = {'get_all_by_host': 0, 'get_by_uuid': 0,
'get_nw_info': 0, 'expected_instance': None}
def fake_instance_get_all_by_host(context, host):
call_info['get_all_by_host'] += 1
return instances[:]
def fake_instance_get_by_uuid(context, instance_uuid):
if instance_uuid not in instance_map:
raise exception.InstanceNotFound
call_info['get_by_uuid'] += 1
return instance_map[instance_uuid]
def fake_get_instance_nw_info(context, instance):
# Note that this exception gets caught in compute/manager
# and is ignored. However, the below increment of
# 'get_nw_info' won't happen, and you'll get an assert
# failure checking it below.
self.assertEqual(instance, call_info['expected_instance'])
call_info['get_nw_info'] += 1
self.stubs.Set(db, 'instance_get_all_by_host',
fake_instance_get_all_by_host)
self.stubs.Set(db, 'instance_get_by_uuid',
fake_instance_get_by_uuid)
self.stubs.Set(self.compute.network_api, 'get_instance_nw_info',
fake_get_instance_nw_info)
call_info['expected_instance'] = instances[0]
self.compute._heal_instance_info_cache(ctxt)
self.assertEqual(call_info['get_all_by_host'], 1)
self.assertEqual(call_info['get_by_uuid'], 0)
self.assertEqual(call_info['get_nw_info'], 1)
call_info['expected_instance'] = instances[1]
self.compute._heal_instance_info_cache(ctxt)
self.assertEqual(call_info['get_all_by_host'], 1)
self.assertEqual(call_info['get_by_uuid'], 1)
self.assertEqual(call_info['get_nw_info'], 2)
# Make an instance switch hosts
instances[2]['host'] = 'not-me'
# Make an instance disappear
instance_map.pop(instances[3]['uuid'])
# '2' and '3' should be skipped..
call_info['expected_instance'] = instances[4]
self.compute._heal_instance_info_cache(ctxt)
self.assertEqual(call_info['get_all_by_host'], 1)
# Incremented for '2' and '4'.. '3' caused a raise above.
self.assertEqual(call_info['get_by_uuid'], 3)
self.assertEqual(call_info['get_nw_info'], 3)
# Should be no more left.
self.assertEqual(len(self.compute._instance_uuids_to_heal), 0)
# This should cause a DB query now so we get first instance
# back again
call_info['expected_instance'] = instances[0]
self.compute._heal_instance_info_cache(ctxt)
self.assertEqual(call_info['get_all_by_host'], 2)
# Stays the same, beacuse the instance came from the DB
self.assertEqual(call_info['get_by_uuid'], 3)
self.assertEqual(call_info['get_nw_info'], 4)
class ComputeAPITestCase(BaseTestCase):
@@ -1638,7 +1713,7 @@ class ComputeAPITestCase(BaseTestCase):
inst_type['memory_mb'] = 1
def fake_show(*args):
img = copy(self.fake_image)
img = copy.copy(self.fake_image)
img['min_ram'] = 2
return img
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
@@ -1659,7 +1734,7 @@ class ComputeAPITestCase(BaseTestCase):
inst_type['root_gb'] = 1
def fake_show(*args):
img = copy(self.fake_image)
img = copy.copy(self.fake_image)
img['min_disk'] = 2
return img
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
@@ -1681,7 +1756,7 @@ class ComputeAPITestCase(BaseTestCase):
inst_type['memory_mb'] = 2
def fake_show(*args):
img = copy(self.fake_image)
img = copy.copy(self.fake_image)
img['min_ram'] = 2
img['min_disk'] = 2
return img
@@ -1699,7 +1774,7 @@ class ComputeAPITestCase(BaseTestCase):
inst_type['memory_mb'] = 1
def fake_show(*args):
return copy(self.fake_image)
return copy.copy(self.fake_image)
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
(refs, resv_id) = self.compute_api.create(self.context,
@@ -2143,7 +2218,7 @@ class ComputeAPITestCase(BaseTestCase):
"""
def fake_show(*args):
img = copy(self.fake_image)
img = copy.copy(self.fake_image)
img['disk_format'] = 'vhd'
return img
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
@@ -2175,7 +2250,7 @@ class ComputeAPITestCase(BaseTestCase):
"""
def fake_show(*args):
img = copy(self.fake_image)
img = copy.copy(self.fake_image)
img['disk_format'] = 'raw'
img['min_ram'] = 512
img['min_disk'] = 1
@@ -2205,7 +2280,7 @@ class ComputeAPITestCase(BaseTestCase):
"""
def fake_show(*args):
img = copy(self.fake_image)
img = copy.copy(self.fake_image)
img['disk_format'] = 'raw'
img['min_disk'] = 1
return img