class MyObj(base.CinderPersistentObject, base.CinderObject, base.CinderObjectDictCompat): VERSION = '1.6' fields = { 'foo': fields.Field(fields.Integer(), default=1), 'bar': fields.Field(fields.String()), 'missing': fields.Field(fields.String()), 'readonly': fields.Field(fields.Integer(), read_only=True), 'rel_object': fields.ObjectField('MyOwnedObject', nullable=True), 'rel_objects': fields.ListOfObjectsField('MyOwnedObject', nullable=True), } @staticmethod def _from_db_object(context, obj, db_obj): self = MyObj() self.foo = db_obj['foo'] self.bar = db_obj['bar'] self.missing = db_obj['missing'] self.readonly = 1 return self def obj_load_attr(self, attrname): setattr(self, attrname, 'loaded!') @base.remotable_classmethod def query(cls, context): obj = cls(context=context, foo=1, bar='bar') obj.obj_reset_changes() return obj @base.remotable def marco(self, context): return 'polo' @base.remotable def _update_test(self, context): if context.project_id == 'alternate': self.bar = 'alternate-context' else: self.bar = 'updated' @base.remotable def save(self, context): self.obj_reset_changes() @base.remotable def refresh(self, context): self.foo = 321 self.bar = 'refreshed' self.obj_reset_changes() @base.remotable def modify_save_modify(self, context): self.bar = 'meow' self.save() self.foo = 42 self.rel_object = MyOwnedObject(baz=42) def obj_make_compatible(self, primitive, target_version): super(MyObj, self).obj_make_compatible(primitive, target_version) # NOTE(danms): Simulate an older version that had a different # format for the 'bar' attribute if target_version == '1.1' and 'bar' in primitive: primitive['bar'] = 'old%s' % primitive['bar']
class ParentObject(base.CinderObject): fields = { 'foo': fields.IntegerField(), 'bar': fields.ObjectField('MyObj'), }
class Snapshot(base.CinderPersistentObject, base.CinderObject, base.CinderObjectDictCompat): # Version 1.0: Initial version VERSION = '1.0' fields = { 'id': fields.UUIDField(), 'user_id': fields.UUIDField(nullable=True), 'project_id': fields.UUIDField(nullable=True), 'volume_id': fields.UUIDField(), 'cgsnapshot_id': fields.UUIDField(nullable=True), 'status': fields.StringField(nullable=True), 'progress': fields.StringField(nullable=True), 'volume_size': fields.IntegerField(), 'display_name': fields.StringField(nullable=True), 'display_description': fields.StringField(nullable=True), 'encryption_key_id': fields.UUIDField(nullable=True), 'volume_type_id': fields.UUIDField(nullable=True), 'provider_location': fields.StringField(nullable=True), 'provider_id': fields.UUIDField(nullable=True), 'metadata': fields.DictOfStringsField(), 'volume': fields.ObjectField('Volume', nullable=True), } # NOTE(thangp): obj_extra_fields is used to hold properties that are not # usually part of the model obj_extra_fields = ['name', 'volume_name'] @property def name(self): return CONF.snapshot_name_template % self.id @property def volume_name(self): return self.volume.name def __init__(self, *args, **kwargs): super(Snapshot, self).__init__(*args, **kwargs) self._orig_metadata = {} self._reset_metadata_tracking() def obj_reset_changes(self, fields=None): super(Snapshot, self).obj_reset_changes(fields) self._reset_metadata_tracking(fields=fields) def _reset_metadata_tracking(self, fields=None): if fields is None or 'metadata' in fields: self._orig_metadata = (dict(self.metadata) if 'metadata' in self else {}) def obj_what_changed(self): changes = super(Snapshot, self).obj_what_changed() if 'metadata' in self and self.metadata != self._orig_metadata: changes.add('metadata') return changes def obj_make_compatible(self, primitive, target_version): """Make an object representation compatible with a target version.""" target_version = utils.convert_version_to_tuple(target_version) @staticmethod def _from_db_object(context, snapshot, db_snapshot, expected_attrs=None): if expected_attrs is None: expected_attrs = [] for name, field in snapshot.fields.items(): if name in OPTIONAL_FIELDS: continue value = db_snapshot.get(name) if isinstance(field, fields.IntegerField): value = value if value is not None else 0 snapshot[name] = value if 'volume' in expected_attrs: volume = objects.Volume(context) volume._from_db_object(context, volume, db_snapshot['volume']) snapshot.volume = volume if 'metadata' in expected_attrs: snapshot.metadata = db.snapshot_metadata_get( context, db_snapshot['id']) snapshot._context = context snapshot.obj_reset_changes() return snapshot @base.remotable_classmethod def get_by_id(cls, context, id): db_snapshot = db.snapshot_get(context, id) return cls._from_db_object(context, cls(context), db_snapshot, expected_attrs=['metadata']) @base.remotable def create(self, context): if self.obj_attr_is_set('id'): raise exception.ObjectActionError(action='create', reason=_('already created')) updates = self.obj_get_changes() if 'volume' in updates: raise exception.ObjectActionError(action='create', reason=_('volume assigned')) db_snapshot = db.snapshot_create(context, updates) self._from_db_object(context, self, db_snapshot) @base.remotable def save(self, context): updates = self.obj_get_changes() if updates: if 'volume' in updates: raise exception.ObjectActionError(action='save', reason=_('volume changed')) if 'metadata' in updates: # Metadata items that are not specified in the # self.metadata will be deleted metadata = updates.pop('metadata', None) self.metadata = db.snapshot_metadata_update( context, self.id, metadata, True) db.snapshot_update(context, self.id, updates) self.obj_reset_changes() @base.remotable def destroy(self, context): db.snapshot_destroy(context, self.id) def obj_load_attr(self, attrname): if attrname not in OPTIONAL_FIELDS: raise exception.ObjectActionError( action='obj_load_attr', reason=_('attribute %s not lazy-loadable') % attrname) if not self._context: raise exception.OrphanedObjectError(method='obj_load_attr', objtype=self.obj_name()) if attrname == 'volume': self.volume = objects.Volume.get_by_id(self._context, self.volume_id) self.obj_reset_changes(fields=[attrname]) def delete_metadata_key(self, context, key): db.snapshot_metadata_delete(context, self.id, key) md_was_changed = 'metadata' in self.obj_what_changed() del self.metadata[key] self._orig_metadata.pop(key, None) if not md_was_changed: self.obj_reset_changes(['metadata'])