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:
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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"]]
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user