
To make objects that have other objects as fields compatible to an earlier version, oslo versioned objects uses either a manifest passed to obj_to_primitive or the object's obj_relationships mapping. Which means that if we don't have any of those mechanisms in place our rolling upgrades mechanism will fail whenever we try to backport a Versioned Object that has set an ObjectField field because Oslo Versioned Object will not know how to backport that related object. This patch introduces the usage of manifests on backports when we are doing rolling upgrades. For the manifest, we use the data in our Objects History. Which means that as long as we keep history in OBJ_VERSIONS right we will not have to create and worry about keeping lists' child_versions field or our versioned object's obj_relationships for fields with types ListOfObjectsField and ObjectField. We also don't have to worry about cascade version bumping, as in changing the List OVO version whenever the OVO it contains gets bumped, or bumping our OVO whenever one of the related OVO fields is bumped. Closes-Bug: #1571566 Change-Id: Ibc1a1257830c925c10696c0b5aedd5f471c538d0
175 lines
7.1 KiB
Python
175 lines
7.1 KiB
Python
# Copyright 2015 Yahoo Inc.
|
|
#
|
|
# 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 cinder import db
|
|
from cinder import exception
|
|
from cinder.i18n import _
|
|
from cinder import objects
|
|
from cinder.objects import base
|
|
from cinder.objects import fields as c_fields
|
|
from oslo_versionedobjects import fields
|
|
|
|
OPTIONAL_FIELDS = ['cgsnapshots', 'volumes']
|
|
|
|
|
|
@base.CinderObjectRegistry.register
|
|
class ConsistencyGroup(base.CinderPersistentObject, base.CinderObject,
|
|
base.CinderObjectDictCompat):
|
|
# Version 1.0: Initial version
|
|
# Version 1.1: Added cgsnapshots and volumes relationships
|
|
# Version 1.2: Changed 'status' field to use ConsistencyGroupStatusField
|
|
VERSION = '1.2'
|
|
|
|
fields = {
|
|
'id': fields.UUIDField(),
|
|
'user_id': fields.StringField(),
|
|
'project_id': fields.StringField(),
|
|
'host': fields.StringField(nullable=True),
|
|
'availability_zone': fields.StringField(nullable=True),
|
|
'name': fields.StringField(nullable=True),
|
|
'description': fields.StringField(nullable=True),
|
|
'volume_type_id': fields.StringField(nullable=True),
|
|
'status': c_fields.ConsistencyGroupStatusField(nullable=True),
|
|
'cgsnapshot_id': fields.UUIDField(nullable=True),
|
|
'source_cgid': fields.UUIDField(nullable=True),
|
|
'cgsnapshots': fields.ObjectField('CGSnapshotList', nullable=True),
|
|
'volumes': fields.ObjectField('VolumeList', nullable=True),
|
|
}
|
|
|
|
@staticmethod
|
|
def _from_db_object(context, consistencygroup, db_consistencygroup,
|
|
expected_attrs=None):
|
|
if expected_attrs is None:
|
|
expected_attrs = []
|
|
for name, field in consistencygroup.fields.items():
|
|
if name in OPTIONAL_FIELDS:
|
|
continue
|
|
value = db_consistencygroup.get(name)
|
|
setattr(consistencygroup, name, value)
|
|
|
|
if 'cgsnapshots' in expected_attrs:
|
|
cgsnapshots = base.obj_make_list(
|
|
context, objects.CGSnapshotList(context),
|
|
objects.CGSnapshot,
|
|
db_consistencygroup['cgsnapshots'])
|
|
consistencygroup.cgsnapshots = cgsnapshots
|
|
|
|
if 'volumes' in expected_attrs:
|
|
volumes = base.obj_make_list(
|
|
context, objects.VolumeList(context),
|
|
objects.Volume,
|
|
db_consistencygroup['volumes'])
|
|
consistencygroup.volumes = volumes
|
|
|
|
consistencygroup._context = context
|
|
consistencygroup.obj_reset_changes()
|
|
return consistencygroup
|
|
|
|
@base.remotable
|
|
def create(self, cg_snap_id=None, cg_id=None):
|
|
"""Create a consistency group.
|
|
|
|
If cg_snap_id or cg_id are specified then volume_type_id,
|
|
availability_zone, and host will be taken from the source Consistency
|
|
Group.
|
|
"""
|
|
if self.obj_attr_is_set('id'):
|
|
raise exception.ObjectActionError(action='create',
|
|
reason=_('already_created'))
|
|
updates = self.cinder_obj_get_changes()
|
|
|
|
if 'cgsnapshots' in updates:
|
|
raise exception.ObjectActionError(action='create',
|
|
reason=_('cgsnapshots assigned'))
|
|
|
|
if 'volumes' in updates:
|
|
raise exception.ObjectActionError(action='create',
|
|
reason=_('volumes assigned'))
|
|
|
|
db_consistencygroups = db.consistencygroup_create(self._context,
|
|
updates,
|
|
cg_snap_id,
|
|
cg_id)
|
|
self._from_db_object(self._context, self, db_consistencygroups)
|
|
|
|
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 == 'cgsnapshots':
|
|
self.cgsnapshots = objects.CGSnapshotList.get_all_by_group(
|
|
self._context, self.id)
|
|
|
|
if attrname == 'volumes':
|
|
self.volumes = objects.VolumeList.get_all_by_group(self._context,
|
|
self.id)
|
|
|
|
self.obj_reset_changes(fields=[attrname])
|
|
|
|
@base.remotable
|
|
def save(self):
|
|
updates = self.cinder_obj_get_changes()
|
|
if updates:
|
|
if 'cgsnapshots' in updates:
|
|
raise exception.ObjectActionError(
|
|
action='save', reason=_('cgsnapshots changed'))
|
|
if 'volumes' in updates:
|
|
raise exception.ObjectActionError(
|
|
action='save', reason=_('volumes changed'))
|
|
|
|
db.consistencygroup_update(self._context, self.id, updates)
|
|
self.obj_reset_changes()
|
|
|
|
@base.remotable
|
|
def destroy(self):
|
|
with self.obj_as_admin():
|
|
db.consistencygroup_destroy(self._context, self.id)
|
|
|
|
|
|
@base.CinderObjectRegistry.register
|
|
class ConsistencyGroupList(base.ObjectListBase, base.CinderObject):
|
|
# Version 1.0: Initial version
|
|
# Version 1.1: Add pagination support to consistency group
|
|
VERSION = '1.1'
|
|
|
|
fields = {
|
|
'objects': fields.ListOfObjectsField('ConsistencyGroup')
|
|
}
|
|
|
|
@base.remotable_classmethod
|
|
def get_all(cls, context, filters=None, marker=None, limit=None,
|
|
offset=None, sort_keys=None, sort_dirs=None):
|
|
consistencygroups = db.consistencygroup_get_all(
|
|
context, filters=filters, marker=marker, limit=limit,
|
|
offset=offset, sort_keys=sort_keys, sort_dirs=sort_dirs)
|
|
return base.obj_make_list(context, cls(context),
|
|
objects.ConsistencyGroup,
|
|
consistencygroups)
|
|
|
|
@base.remotable_classmethod
|
|
def get_all_by_project(cls, context, project_id, filters=None, marker=None,
|
|
limit=None, offset=None, sort_keys=None,
|
|
sort_dirs=None):
|
|
consistencygroups = db.consistencygroup_get_all_by_project(
|
|
context, project_id, filters=filters, marker=marker, limit=limit,
|
|
offset=offset, sort_keys=sort_keys, sort_dirs=sort_dirs)
|
|
return base.obj_make_list(context, cls(context),
|
|
objects.ConsistencyGroup,
|
|
consistencygroups)
|