summaryrefslogtreecommitdiffstats
path: root/nova/objects
diff options
context:
space:
mode:
authorDan Smith <danms@us.ibm.com>2013-06-04 16:49:40 -0700
committerDan Smith <danms@us.ibm.com>2013-06-07 11:43:37 -0700
commite95807e8cda4463d7c9a2aab918bd2bda3d3cf9e (patch)
tree83959867726d347e15774d7f5c5be8901c73ad2a /nova/objects
parent6fcf4133b49cfefa77151937dec4db097a85c349 (diff)
downloadnova-e95807e8cda4463d7c9a2aab918bd2bda3d3cf9e.tar.gz
nova-e95807e8cda4463d7c9a2aab918bd2bda3d3cf9e.tar.xz
nova-e95807e8cda4463d7c9a2aab918bd2bda3d3cf9e.zip
Add Instance.info_cache
This adds our first nested object: the InstanceInfoCache at Instance.info_cache. Related to blueprint unified-object-model Change-Id: I2dd8727bbe38eadd080e9ea1ef9feabc2fa50520
Diffstat (limited to 'nova/objects')
-rw-r--r--nova/objects/instance.py65
-rw-r--r--nova/objects/instance_info_cache.py42
-rw-r--r--nova/objects/utils.py17
3 files changed, 109 insertions, 15 deletions
diff --git a/nova/objects/instance.py b/nova/objects/instance.py
index 58c581542..18fdfb94d 100644
--- a/nova/objects/instance.py
+++ b/nova/objects/instance.py
@@ -15,6 +15,7 @@
from nova import db
from nova import notifications
from nova.objects import base
+from nova.objects import instance_info_cache
from nova.objects import utils as obj_utils
from nova import utils
@@ -24,7 +25,17 @@ from oslo.config import cfg
CONF = cfg.CONF
+# These are fields that can be specified as expected_attrs
+INSTANCE_OPTIONAL_FIELDS = ['metadata', 'system_metadata']
+# These are fields that are always joined by the db right now
+INSTANCE_IMPLIED_FIELDS = ['info_cache']
+
+
class Instance(base.NovaObject):
+ # Version 1.0: Initial version
+ # Version 1.1: Added info_cache
+ VERSION = '1.1'
+
fields = {
'id': int,
@@ -94,6 +105,9 @@ class Instance(base.NovaObject):
'metadata': dict,
'system_metadata': dict,
+ 'info_cache': obj_utils.nested_object_or_none(
+ instance_info_cache.InstanceInfoCache)
+
}
@property
@@ -132,11 +146,15 @@ class Instance(base.NovaObject):
_attr_scheduled_at_to_primitive = obj_utils.dt_serializer('scheduled_at')
_attr_launched_at_to_primitive = obj_utils.dt_serializer('launched_at')
_attr_terminated_at_to_primitive = obj_utils.dt_serializer('terminated_at')
+ _attr_info_cache_to_primitive = obj_utils.obj_serializer('info_cache')
_attr_scheduled_at_from_primitive = obj_utils.dt_deserializer
_attr_launched_at_from_primitive = obj_utils.dt_deserializer
_attr_terminated_at_from_primitive = obj_utils.dt_deserializer
+ def _attr_info_cache_from_primitive(self, val):
+ return base.NovaObject.obj_from_primitive(val)
+
@staticmethod
def _from_db_object(instance, db_inst, expected_attrs=None):
"""Method to help with migration to objects.
@@ -147,7 +165,7 @@ class Instance(base.NovaObject):
expected_attrs = []
# Most of the field names match right now, so be quick
for field in instance.fields:
- if field in ['metadata', 'system_metadata']:
+ if field in INSTANCE_OPTIONAL_FIELDS + INSTANCE_IMPLIED_FIELDS:
continue
elif field == 'deleted':
instance.deleted = db_inst['deleted'] == db_inst['id']
@@ -159,6 +177,13 @@ class Instance(base.NovaObject):
if 'system_metadata' in expected_attrs:
instance['system_metadata'] = utils.metadata_to_dict(
db_inst['system_metadata'])
+ # NOTE(danms): info_cache and security_groups are almost always joined
+ # in the DB layer right now, so check to see if they're filled instead
+ # of looking at expected_attrs
+ if db_inst['info_cache']:
+ instance['info_cache'] = instance_info_cache.InstanceInfoCache()
+ instance_info_cache.InstanceInfoCache._from_db_object(
+ instance['info_cache'], db_inst['info_cache'])
instance.obj_reset_changes()
return instance
@@ -174,6 +199,9 @@ class Instance(base.NovaObject):
columns_to_join.append('metadata')
if 'system_metadata' in expected_attrs:
columns_to_join.append('system_metadata')
+ # NOTE(danms): The DB API currently always joins info_cache and
+ # security_groups for get operations, so don't add them to the
+ # list of columns
db_inst = db.instance_get_by_uuid(context, uuid,
columns_to_join)
@@ -193,28 +221,33 @@ class Instance(base.NovaObject):
"""
updates = {}
changes = self.obj_what_changed()
- for field in changes:
- updates[field] = self[field]
+ for field in self.fields:
+ if (hasattr(self, base.get_attrname(field)) and
+ isinstance(self[field], base.NovaObject)):
+ self[field].save(context)
+ elif field in changes:
+ updates[field] = self[field]
if expected_task_state is not None:
updates['expected_task_state'] = expected_task_state
- old_ref, inst_ref = db.instance_update_and_get_original(context,
- self.uuid,
- updates)
-
- expected_attrs = []
- for attr in ('metadata', 'system_metadata'):
- if hasattr(self, base.get_attrname(attr)):
- expected_attrs.append(attr)
- Instance._from_db_object(self, inst_ref, expected_attrs)
- if 'vm_state' in changes or 'task_state' in changes:
- notifications.send_update(context, old_ref, inst_ref)
+
+ if updates:
+ old_ref, inst_ref = db.instance_update_and_get_original(context,
+ self.uuid,
+ updates)
+ expected_attrs = []
+ for attr in INSTANCE_OPTIONAL_FIELDS:
+ if hasattr(self, base.get_attrname(attr)):
+ expected_attrs.append(attr)
+ Instance._from_db_object(self, inst_ref, expected_attrs)
+ if 'vm_state' in changes or 'task_state' in changes:
+ notifications.send_update(context, old_ref, inst_ref)
self.obj_reset_changes()
@base.remotable
def refresh(self, context):
extra = []
- for field in ['system_metadata', 'metadata']:
+ for field in INSTANCE_OPTIONAL_FIELDS:
if hasattr(self, base.get_attrname(field)):
extra.append(field)
current = self.__class__.get_by_uuid(context, uuid=self.uuid,
@@ -230,6 +263,8 @@ class Instance(base.NovaObject):
extra.append('system_metadata')
elif attrname == 'metadata':
extra.append('metadata')
+ elif attrname == 'info_cache':
+ extra.append('info_cache')
if not extra:
raise Exception('Cannot load "%s" from instance' % attrname)
diff --git a/nova/objects/instance_info_cache.py b/nova/objects/instance_info_cache.py
new file mode 100644
index 000000000..6b46559ed
--- /dev/null
+++ b/nova/objects/instance_info_cache.py
@@ -0,0 +1,42 @@
+# Copyright 2013 IBM Corp.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from nova import db
+from nova.objects import base
+
+
+class InstanceInfoCache(base.NovaObject):
+ fields = {
+ 'instance_uuid': str,
+ 'network_info': str,
+ }
+
+ @staticmethod
+ def _from_db_object(info_cache, db_obj):
+ info_cache.instance_uuid = db_obj['instance_uuid']
+ info_cache.network_info = db_obj['network_info']
+ info_cache.obj_reset_changes()
+ 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)
+ return InstanceInfoCache._from_db_object(cls(), db_obj)
+
+ @base.remotable
+ def save(self, context):
+ if 'network_info' in self.obj_what_changed():
+ db.instance_info_cache_update(context, self.instance_uuid,
+ {'network_info': self.network_info})
+ self.obj_reset_changes()
diff --git a/nova/objects/utils.py b/nova/objects/utils.py
index 21ef6faeb..e79b36e7e 100644
--- a/nova/objects/utils.py
+++ b/nova/objects/utils.py
@@ -70,6 +70,14 @@ def ip_or_none(version):
return validator
+def nested_object_or_none(objclass):
+ def validator(val, objclass=objclass):
+ if val is None or isinstance(val, objclass):
+ return val
+ raise ValueError('An object of class %s is required here' % objclass)
+ return validator
+
+
def dt_serializer(name):
"""Return a datetime serializer for a named attribute."""
def serializer(self, name=name):
@@ -86,3 +94,12 @@ def dt_deserializer(instance, val):
return None
else:
return timeutils.parse_isotime(val)
+
+
+def obj_serializer(name):
+ def serializer(self, name=name):
+ if getattr(self, name) is not None:
+ return getattr(self, name).obj_to_primitive()
+ else:
+ return None
+ return serializer