diff options
| author | Dan Smith <danms@us.ibm.com> | 2013-06-04 16:49:40 -0700 |
|---|---|---|
| committer | Dan Smith <danms@us.ibm.com> | 2013-06-07 11:43:37 -0700 |
| commit | e95807e8cda4463d7c9a2aab918bd2bda3d3cf9e (patch) | |
| tree | 83959867726d347e15774d7f5c5be8901c73ad2a /nova/objects | |
| parent | 6fcf4133b49cfefa77151937dec4db097a85c349 (diff) | |
| download | nova-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.py | 65 | ||||
| -rw-r--r-- | nova/objects/instance_info_cache.py | 42 | ||||
| -rw-r--r-- | nova/objects/utils.py | 17 |
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 |
