Convert network API to use InfoCache object

This converts the db.info_cache_update() call in network/api to use
objects.  The save() method has been extended to support what we need
for cells.

Converting to the object allows us to ditch the conductor_api kwarg on
some methods.

Related to blueprint unified-object-model

Change-Id: I1722c03d20511d67acc0a8947de1d4273dc78597
This commit is contained in:
Chris Behrens
2013-07-11 20:08:35 +00:00
committed by Dan Smith
parent 5701c4e5a8
commit d8eeea1bae
9 changed files with 102 additions and 51 deletions

View File

@@ -140,8 +140,8 @@ class InstanceMetadata():
# get network info, and the rendered network template
if network_info is None:
network_info = network.API().get_instance_nw_info(ctxt, instance,
conductor_api=capi)
network_info = network.API().get_instance_nw_info(ctxt,
instance)
self.network_config = None
cfg = netutils.get_injected_network_template(network_info)

View File

@@ -854,7 +854,7 @@ class ComputeManager(manager.SchedulerDependentManager):
instance = self.conductor_api.instance_get_by_uuid(
context, instance['uuid'])
network_info = self.network_api.get_instance_nw_info(context,
instance, conductor_api=self.conductor_api)
instance)
return network_info
def _legacy_nw_info(self, network_info):
@@ -3556,8 +3556,9 @@ class ComputeManager(manager.SchedulerDependentManager):
def detach_interface(self, context, instance, port_id):
"""Detach an network adapter from an instance."""
network_info = self.network_api.get_instance_nw_info(
context.elevated(), instance, conductor_api=self.conductor_api)
# FIXME(comstud): Why does this need elevated context?
network_info = self._get_instance_nw_info(context.elevated(),
instance)
legacy_nwinfo = self._legacy_nw_info(network_info)
condemned = None
for (network, mapping) in legacy_nwinfo:

View File

@@ -21,13 +21,13 @@
import functools
import inspect
from nova.cells import rpcapi as cells_rpcapi
from nova.compute import flavors
from nova.db import base
from nova import exception
from nova.network import floating_ips
from nova.network import model as network_model
from nova.network import rpcapi as network_rpcapi
from nova.objects import instance_info_cache as info_cache_obj
from nova.openstack.common import log as logging
from nova import policy
from nova import utils
@@ -57,38 +57,27 @@ def refresh_cache(f):
raise Exception(msg)
update_instance_cache_with_nw_info(self, context, instance,
nw_info=res, conductor_api=kwargs.get('conductor_api'))
nw_info=res)
# return the original function's return value
return res
return wrapper
def update_instance_cache_with_nw_info(api, context, instance,
nw_info=None, conductor_api=None,
def update_instance_cache_with_nw_info(api, context, instance, nw_info=None,
update_cells=True):
try:
if not isinstance(nw_info, network_model.NetworkInfo):
nw_info = None
if not nw_info:
nw_info = api._get_instance_nw_info(context, instance)
# update cache
cache = {'network_info': nw_info.json()}
if conductor_api:
rv = conductor_api.instance_info_cache_update(context,
instance,
cache)
else:
rv = api.db.instance_info_cache_update(context,
instance['uuid'],
cache)
if update_cells:
cells_api = cells_rpcapi.CellsAPI()
try:
cells_api.instance_info_cache_update_at_top(context, rv)
except Exception:
LOG.exception(_("Failed to notify cells of instance info "
"cache update"))
# NOTE(comstud): The save() method actually handles updating or
# creating the instance. We don't need to retrieve the object
# from the DB first.
ic = info_cache_obj.InstanceInfoCache.new(context,
instance['uuid'])
ic.network_info = nw_info
ic.save(update_cells=update_cells)
except Exception:
LOG.exception(_('Failed storing info cache'), instance=instance)
@@ -378,7 +367,7 @@ class API(base.Base):
self.db.network_associate(context, project, network_id, True)
@wrap_check_policy
def get_instance_nw_info(self, context, instance, conductor_api=None):
def get_instance_nw_info(self, context, instance):
"""Returns all network info related to an instance."""
result = self._get_instance_nw_info(context, instance)
# NOTE(comstud): Don't update API cell with new info_cache every
@@ -386,8 +375,7 @@ class API(base.Base):
# of info_cache causes too many cells messages. Healing the API
# will happen separately.
update_instance_cache_with_nw_info(self, context, instance,
result, conductor_api,
update_cells=False)
result, update_cells=False)
return result
def _get_instance_nw_info(self, context, instance):

View File

@@ -396,14 +396,13 @@ class API(base.Base):
"""Return the port for the client given the port id."""
return neutronv2.get_client(context).show_port(port_id)
def get_instance_nw_info(self, context, instance, conductor_api=None,
networks=None):
def get_instance_nw_info(self, context, instance, networks=None):
"""Return network information for specified instance
and update cache.
"""
result = self._get_instance_nw_info(context, instance, networks)
update_instance_info_cache(self, context, instance, result,
conductor_api)
update_cells=False)
return result
def _get_instance_nw_info(self, context, instance, networks=None):

View File

@@ -12,16 +12,22 @@
# License for the specific language governing permissions and limitations
# under the License.
from nova.cells import opts as cells_opts
from nova.cells import rpcapi as cells_rpcapi
from nova import db
from nova import exception
from nova.objects import base
from nova.objects import utils
from nova.openstack.common import log as logging
LOG = logging.getLogger(__name__)
class InstanceInfoCache(base.NovaObject):
VERSION = '1.1'
VERSION = '1.2'
# Version 1.0: Initial version
# Version 1.1: Converted network_info to store the model.
# Version 1.2: Added new() and update_cells kwarg to save().
fields = {
'instance_uuid': str,
@@ -41,6 +47,21 @@ class InstanceInfoCache(base.NovaObject):
info_cache._context = context
return info_cache
@classmethod
def new(cls, context, instance_uuid):
"""Create an InfoCache object that can be used to create the DB
entry for the first time.
When save()ing this object, the info_cache_update() DB call
will properly handle creating it if it doesn't exist already.
"""
info_cache = cls()
info_cache.instance_uuid = instance_uuid
info_cache.network_info = None
info_cache._context = context
# Leave the fields dirty
return info_cache
@base.remotable_classmethod
def get_by_instance_uuid(cls, context, instance_uuid):
db_obj = db.instance_info_cache_get(context, instance_uuid)
@@ -49,10 +70,24 @@ class InstanceInfoCache(base.NovaObject):
instance_uuid=instance_uuid)
return InstanceInfoCache._from_db_object(context, cls(), db_obj)
@staticmethod
def _info_cache_cells_update(ctxt, info_cache):
cell_type = cells_opts.get_cell_type()
if cell_type != 'compute':
return
cells_api = cells_rpcapi.CellsAPI()
try:
cells_api.instance_info_cache_update_at_top(ctxt, info_cache)
except Exception:
LOG.exception(_("Failed to notify cells of instance info "
"cache update"))
@base.remotable
def save(self, context):
def save(self, context, update_cells=True):
if 'network_info' in self.obj_what_changed():
nw_info_json = self._attr_network_info_to_primitive()
db.instance_info_cache_update(context, self.instance_uuid,
{'network_info': nw_info_json})
self.obj_reset_changes()
rv = db.instance_info_cache_update(context, self.instance_uuid,
{'network_info': nw_info_json})
if update_cells and rv:
self._info_cache_cells_update(context, rv)
self.obj_reset_changes()

View File

@@ -4415,8 +4415,7 @@ class ComputeTestCase(BaseTestCase):
self.compute.conductor_api.instance_get_by_uuid(
self.context, fake_instance['uuid']).AndReturn(fake_instance)
self.compute.network_api.get_instance_nw_info(self.context,
fake_instance, conductor_api=self.compute.conductor_api
).AndReturn(fake_nw_info)
fake_instance).AndReturn(fake_nw_info)
self.mox.ReplayAll()
@@ -7699,7 +7698,7 @@ class ComputeAPITestCase(BaseTestCase):
def test_detach_interface(self):
nwinfo, port_id = self.test_attach_interface()
self.stubs.Set(self.compute.network_api, 'get_instance_nw_info',
self.stubs.Set(self.compute, '_get_instance_nw_info',
lambda *a, **k: nwinfo)
self.stubs.Set(self.compute.network_api,
'deallocate_port_for_instance',

View File

@@ -12,6 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
from nova.cells import opts as cells_opts
from nova.cells import rpcapi as cells_rpcapi
from nova import context
from nova import db
from nova import exception
@@ -44,18 +46,49 @@ class _TestInstanceInfoCacheObject(object):
instance_info_cache.InstanceInfoCache.get_by_instance_uuid,
ctxt, 'fake-uuid')
def test_save(self):
def test_new(self):
ctxt = context.get_admin_context()
obj = instance_info_cache.InstanceInfoCache.new(ctxt,
'fake-uuid')
self.assertEqual(set(['instance_uuid', 'network_info']),
obj.obj_what_changed())
self.assertEqual('fake-uuid', obj.instance_uuid)
self.assertEqual(None, obj.network_info)
def _save_helper(self, cell_type, update_cells):
obj = instance_info_cache.InstanceInfoCache()
cells_api = cells_rpcapi.CellsAPI()
ctxt = context.get_admin_context()
self.mox.StubOutWithMock(db, 'instance_info_cache_update')
self.mox.StubOutWithMock(cells_opts, 'get_cell_type')
self.mox.StubOutWithMock(cells_rpcapi, 'CellsAPI',
use_mock_anything=True)
self.mox.StubOutWithMock(cells_api,
'instance_info_cache_update_at_top')
nwinfo = network_model.NetworkInfo.hydrate([{'address': 'foo'}])
db.instance_info_cache_update(ctxt, 'fake-uuid',
{'network_info': nwinfo.json()})
db.instance_info_cache_update(
ctxt, 'fake-uuid',
{'network_info': nwinfo.json()}).AndReturn('foo')
if update_cells:
cells_opts.get_cell_type().AndReturn(cell_type)
if cell_type == 'compute':
cells_rpcapi.CellsAPI().AndReturn(cells_api)
cells_api.instance_info_cache_update_at_top(ctxt, 'foo')
self.mox.ReplayAll()
obj = instance_info_cache.InstanceInfoCache()
obj._context = ctxt
obj.instance_uuid = 'fake-uuid'
obj.network_info = nwinfo
obj.save()
obj.save(update_cells=update_cells)
def test_save_with_update_cells_and_compute_cell(self):
self._save_helper('compute', True)
def test_save_with_update_cells_and_non_compute_cell(self):
self._save_helper(None, True)
def test_save_without_update_cells(self):
self._save_helper(None, False)
class TestInstanceInfoCacheObject(test_objects._LocalTest,

View File

@@ -290,8 +290,7 @@ class MetadataTestCase(test.TestCase):
network_api.API.get_instance_nw_info(
mox.IgnoreArg(),
mox.IgnoreArg(),
conductor_api=mox.IgnoreArg()).AndReturn(network_info_from_api)
mox.IgnoreArg()).AndReturn(network_info_from_api)
self.mox.StubOutWithMock(netutils, "get_injected_network_template")

View File

@@ -19,7 +19,6 @@
from oslo.config import cfg
from nova import conductor
from nova import context
from nova import network
from nova.network import linux_net
@@ -421,12 +420,10 @@ class IptablesFirewallDriver(FirewallDriver):
# and should be the only one making
# making rpc calls.
nw_api = network.API()
capi = conductor.API()
for instance in rule['grantee_group']['instances']:
nw_info = nw_api.get_instance_nw_info(
ctxt,
instance,
conductor_api=capi)
instance)
ips = [ip['address']
for ip in nw_info.fixed_ips()