Make InfoCache.network_info be the network model

Instead of storing the DB version of network_info (which is a JSON
version of network.model.NetworkInfo) on the object, go ahead and turn
it into its native object as well.  This means that all uses of the
object don't need to worry about hydrating network_info themselves.

This adjusts all uses in the code understand the old and new ways of
life.

There's also a small issue with the get_by_instance_uuid() method that
would cause a traceback when no entry was found.  This method is not
being used yet anywhere, but this is fixed to raise a NotFound.

Related to blueprint unified-object-model

Change-Id: I882311c8a9f9df927c5650946e6398eeb33e74d0
This commit is contained in:
Chris Behrens
2013-07-11 19:07:15 +00:00
committed by Dan Smith
parent 96a5baf673
commit 5701c4e5a8
8 changed files with 93 additions and 30 deletions

View File

@@ -24,6 +24,7 @@ from nova import context
from nova import db
from nova import exception
from nova.network import model as network_model
from nova.objects import instance as instance_obj
from nova.openstack.common import log as logging
from nova.openstack.common import memorycache
from nova.openstack.common import timeutils
@@ -154,12 +155,17 @@ def get_ip_info_for_instance_from_nw_info(nw_info):
def get_ip_info_for_instance(context, instance):
"""Return a dictionary of IP information for an instance."""
if isinstance(instance, instance_obj.Instance):
nw_info = instance.info_cache.network_info
else:
# FIXME(comstud): Temporary as we transition to objects.
info_cache = instance['info_cache'] or {}
cached_nwinfo = info_cache.get('network_info')
# Make sure empty response is turned into []
if not cached_nwinfo:
cached_nwinfo = []
nw_info = network_model.NetworkInfo.hydrate(cached_nwinfo)
nw_info = info_cache.get('network_info')
# Make sure empty response is turned into the model
if not nw_info:
nw_info = []
if not isinstance(nw_info, network_model.NetworkInfo):
nw_info = network_model.NetworkInfo.hydrate(nw_info)
return get_ip_info_for_instance_from_nw_info(nw_info)

View File

@@ -27,6 +27,7 @@ from nova.compute import flavors
from nova import exception
from nova.network import model as network_model
from nova import notifications
from nova.objects import instance as instance_obj
from nova.openstack.common import log
from nova.openstack.common.notifier import api as notifier_api
from nova.openstack.common import timeutils
@@ -276,9 +277,14 @@ def notify_about_aggregate_update(context, event_suffix, aggregate_payload):
def get_nw_info_for_instance(instance):
if isinstance(instance, instance_obj.Instance):
return instance.info_cache.network_info
# FIXME(comstud): Transitional while we convert to objects.
info_cache = instance['info_cache'] or {}
cached_nwinfo = info_cache.get('network_info') or []
return network_model.NetworkInfo.hydrate(cached_nwinfo)
nw_info = info_cache.get('network_info') or []
if not isinstance(nw_info, network_model.NetworkInfo):
nw_info = network_model.NetworkInfo.hydrate(nw_info)
return nw_info
def has_audit_been_run(context, conductor, host, timestamp=None):

View File

@@ -221,17 +221,18 @@ def bandwidth_usage(instance_ref, audit_start,
"""Get bandwidth usage information for the instance for the
specified audit period.
"""
admin_context = nova.context.get_admin_context(read_deleted='yes')
def _get_nwinfo_old_skool():
"""Support for getting network info without objects."""
if (instance_ref.get('info_cache') and
instance_ref['info_cache'].get('network_info') is not None):
cached_info = instance_ref['info_cache']['network_info']
nw_info = network_model.NetworkInfo.hydrate(cached_info)
else:
if isinstance(cached_info, network_model.NetworkInfo):
return cached_info
return network_model.NetworkInfo.hydrate(cached_info)
try:
nw_info = network.API().get_instance_nw_info(admin_context,
return network.API().get_instance_nw_info(admin_context,
instance_ref)
except Exception:
try:
@@ -243,6 +244,14 @@ def bandwidth_usage(instance_ref, audit_start,
return
raise
# FIXME(comstud): Temporary as we transition to objects. This import
# is here to avoid circular imports.
from nova.objects import instance as instance_obj
if isinstance(instance_ref, instance_obj.Instance):
nw_info = instance_ref.info_cache.network_info
else:
nw_info = _get_nwinfo_old_skool()
macs = [vif['address'] for vif in nw_info]
uuids = [instance_ref["uuid"]]

View File

@@ -13,16 +13,26 @@
# under the License.
from nova import db
from nova import exception
from nova.objects import base
from nova.objects import utils
class InstanceInfoCache(base.NovaObject):
VERSION = '1.1'
# Version 1.0: Initial version
# Version 1.1: Converted network_info to store the model.
fields = {
'instance_uuid': str,
'network_info': utils.str_or_none,
'network_info': utils.network_model_or_none,
}
def _attr_network_info_to_primitive(self):
if self.network_info is None:
return None
return self.network_info.json()
@staticmethod
def _from_db_object(context, info_cache, db_obj):
info_cache.instance_uuid = db_obj['instance_uuid']
@@ -34,11 +44,15 @@ class InstanceInfoCache(base.NovaObject):
@base.remotable_classmethod
def get_by_instance_uuid(cls, context, instance_uuid):
db_obj = db.instance_info_cache_get(context, instance_uuid)
if not db_obj:
raise exception.InstanceInfoCacheNotFound(
instance_uuid=instance_uuid)
return InstanceInfoCache._from_db_object(context, cls(), db_obj)
@base.remotable
def save(self, context):
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': self.network_info})
{'network_info': nw_info_json})
self.obj_reset_changes()

View File

@@ -18,6 +18,7 @@ import datetime
import iso8601
import netaddr
from nova.network import model as network_model
from nova.openstack.common import timeutils
@@ -78,6 +79,15 @@ def nested_object_or_none(objclass):
return validator
def network_model_or_none(val):
"""Validate/Convert to a network_model.NetworkInfo, or None."""
if val is None:
return val
if isinstance(val, network_model.NetworkInfo):
return val
return network_model.NetworkInfo.hydrate(val)
def dt_serializer(name):
"""Return a datetime serializer for a named attribute."""
def serializer(self, name=name):

View File

@@ -29,7 +29,7 @@ def fake_instance_get(context, instance_id, columns_to_join=None):
result['deleted_at'] = None
result['updated_at'] = None
result['deleted'] = 0
result['info_cache'] = {'network_info': 'foo',
result['info_cache'] = {'network_info': '[]',
'instance_uuid': result['uuid']}
return result

View File

@@ -21,6 +21,7 @@ import netaddr
from nova.cells import rpcapi as cells_rpcapi
from nova import context
from nova import db
from nova.network import model as network_model
from nova.objects import base
from nova.objects import instance
from nova.objects import security_group
@@ -292,7 +293,11 @@ class _TestInstanceObject(object):
ctxt = context.get_admin_context()
fake_inst = dict(self.fake_instance)
fake_uuid = fake_inst['uuid']
fake_inst['info_cache'] = {'network_info': 'foo',
nwinfo1 = network_model.NetworkInfo.hydrate([{'address': 'foo'}])
nwinfo2 = network_model.NetworkInfo.hydrate([{'address': 'bar'}])
nwinfo1_json = nwinfo1.json()
nwinfo2_json = nwinfo2.json()
fake_inst['info_cache'] = {'network_info': nwinfo1_json,
'instance_uuid': fake_uuid}
self.mox.StubOutWithMock(db, 'instance_get_by_uuid')
self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
@@ -300,13 +305,12 @@ class _TestInstanceObject(object):
db.instance_get_by_uuid(ctxt, fake_uuid, columns_to_join=[]
).AndReturn(fake_inst)
db.instance_info_cache_update(ctxt, fake_uuid,
{'network_info': 'bar'})
{'network_info': nwinfo2_json})
self.mox.ReplayAll()
inst = instance.Instance.get_by_uuid(ctxt, fake_uuid)
self.assertEqual(inst.info_cache.network_info,
fake_inst['info_cache']['network_info'])
self.assertEqual(inst.info_cache.network_info, nwinfo1)
self.assertEqual(inst.info_cache.instance_uuid, fake_uuid)
inst.info_cache.network_info = 'bar'
inst.info_cache.network_info = nwinfo2
inst.save()
def test_with_security_groups(self):
@@ -411,7 +415,7 @@ class _TestInstanceListObject(object):
fake_instance['launched_at'] = (
fake_instance['launched_at'].replace(
tzinfo=iso8601.iso8601.Utc(), microsecond=0))
fake_instance['info_cache'] = {'network_info': 'foo',
fake_instance['info_cache'] = {'network_info': '[]',
'instance_uuid': fake_instance['uuid']}
fake_instance['security_groups'] = []
fake_instance['deleted'] = 0

View File

@@ -14,6 +14,8 @@
from nova import context
from nova import db
from nova import exception
from nova.network import model as network_model
from nova.objects import instance_info_cache
from nova.tests.objects import test_objects
@@ -21,26 +23,38 @@ from nova.tests.objects import test_objects
class _TestInstanceInfoCacheObject(object):
def test_get_by_instance_uuid(self):
ctxt = context.get_admin_context()
nwinfo = network_model.NetworkInfo.hydrate([{'address': 'foo'}])
self.mox.StubOutWithMock(db, 'instance_info_cache_get')
db.instance_info_cache_get(ctxt, 'fake-uuid').AndReturn(
{'instance_uuid': 'fake-uuid', 'network_info': 'foo'})
{'instance_uuid': 'fake-uuid', 'network_info': nwinfo.json()})
self.mox.ReplayAll()
obj = instance_info_cache.InstanceInfoCache.get_by_instance_uuid(
ctxt, 'fake-uuid')
self.assertEqual(obj.instance_uuid, 'fake-uuid')
self.assertEqual(obj.network_info, 'foo')
self.assertEqual(obj.network_info, nwinfo)
self.assertRemotes()
def test_get_by_instance_uuid_no_entries(self):
ctxt = context.get_admin_context()
self.mox.StubOutWithMock(db, 'instance_info_cache_get')
db.instance_info_cache_get(ctxt, 'fake-uuid').AndReturn(None)
self.mox.ReplayAll()
self.assertRaises(
exception.InstanceInfoCacheNotFound,
instance_info_cache.InstanceInfoCache.get_by_instance_uuid,
ctxt, 'fake-uuid')
def test_save(self):
ctxt = context.get_admin_context()
self.mox.StubOutWithMock(db, 'instance_info_cache_update')
nwinfo = network_model.NetworkInfo.hydrate([{'address': 'foo'}])
db.instance_info_cache_update(ctxt, 'fake-uuid',
{'network_info': 'foo'})
{'network_info': nwinfo.json()})
self.mox.ReplayAll()
obj = instance_info_cache.InstanceInfoCache()
obj._context = ctxt
obj.instance_uuid = 'fake-uuid'
obj.network_info = 'foo'
obj.network_info = nwinfo
obj.save()