From b78997c2bb8416a43fe0f03bac7853503bfa5422 Mon Sep 17 00:00:00 2001 From: Gorka Eguileor Date: Thu, 8 Apr 2021 19:16:15 +0200 Subject: [PATCH] Clear OVO history and compatibility The Oslo Versioned Objects history is used to generate the manifests required to do compatibility changes to OVOs on data serialization between services running with different OVO history versions. We haven't updated our OVO history since Train so all the history and compatibility code (obj_make_compatible method) is no longer necessary. This patch consolidates the OVO history into a single version reflecting the current status of the OVO versions and removes the compatibility code from the OVO classes. Since we tend to forget to update the obj_make_compatible when we add a field (like it happened with Volume in version 1.8 when we added shared_targets) this patch also adds a note next to the "fields" attribute (except for the list OVOs which are never updated). Change-Id: Ibfacccfb7c7dc70bc8f8e5ab98cc9c8feae694fb --- cinder/objects/backup.py | 13 +- cinder/objects/base.py | 122 ++++++++---------- cinder/objects/cgsnapshot.py | 1 + cinder/objects/cleanup_request.py | 1 + cinder/objects/cluster.py | 19 +-- cinder/objects/consistencygroup.py | 13 -- cinder/objects/dynamic_log.py | 1 + cinder/objects/group.py | 13 +- cinder/objects/group_snapshot.py | 1 + cinder/objects/group_type.py | 1 + cinder/objects/manageableresources.py | 2 + cinder/objects/qos_specs.py | 1 + cinder/objects/request_spec.py | 16 +-- cinder/objects/service.py | 14 +- cinder/objects/snapshot.py | 21 +-- cinder/objects/volume.py | 17 +-- cinder/objects/volume_attachment.py | 12 +- cinder/objects/volume_type.py | 17 +-- cinder/tests/unit/backup/test_backup.py | 15 ++- cinder/tests/unit/objects/test_base.py | 5 +- cinder/tests/unit/objects/test_cleanable.py | 31 +++-- cinder/tests/unit/objects/test_cluster.py | 13 -- cinder/tests/unit/objects/test_group.py | 17 --- cinder/tests/unit/objects/test_objects.py | 4 + cinder/tests/unit/objects/test_snapshot.py | 24 ---- cinder/tests/unit/objects/test_volume.py | 31 ----- .../unit/objects/test_volume_attachment.py | 20 --- cinder/tests/unit/objects/test_volume_type.py | 12 -- cinder/tests/unit/scheduler/test_scheduler.py | 15 ++- cinder/tests/unit/test.py | 12 ++ cinder/tests/unit/test_rpc.py | 17 +-- cinder/tests/unit/test_service.py | 12 +- cinder/tests/unit/volume/test_volume.py | 11 +- 33 files changed, 147 insertions(+), 377 deletions(-) diff --git a/cinder/objects/backup.py b/cinder/objects/backup.py index cd7196a1fbf..a056713f865 100644 --- a/cinder/objects/backup.py +++ b/cinder/objects/backup.py @@ -15,7 +15,6 @@ from oslo_config import cfg from oslo_serialization import base64 from oslo_serialization import jsonutils -from oslo_utils import versionutils from oslo_versionedobjects import fields from cinder import db @@ -45,6 +44,7 @@ class Backup(base.CinderPersistentObject, base.CinderObject, OPTIONAL_FIELDS = ('metadata', 'parent') + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'id': fields.UUIDField(), @@ -110,17 +110,6 @@ class Backup(base.CinderPersistentObject, base.CinderObject, def has_dependent_backups(self): return bool(self.num_dependent_backups) - def obj_make_compatible(self, primitive, target_version): - """Make an object representation compatible with a target version.""" - added_fields = (((1, 7), ('parent',)),) - - super(Backup, self).obj_make_compatible(primitive, target_version) - target_version = versionutils.convert_version_to_tuple(target_version) - for version, remove_fields in added_fields: - if target_version < version: - for obj_field in remove_fields: - primitive.pop(obj_field, None) - @classmethod def _from_db_object(cls, context, backup, db_backup, expected_attrs=None): if expected_attrs is None: diff --git a/cinder/objects/base.py b/cinder/objects/base.py index 1b04fe2683a..5ca7f8fb848 100644 --- a/cinder/objects/base.py +++ b/cinder/objects/base.py @@ -54,23 +54,45 @@ class CinderObjectVersionsHistory(dict): # # Please note that we do not need to add similar entires for each # release. Liberty is here just for historical reasons. - self.versions = ['liberty'] - self['liberty'] = { - 'Backup': '1.1', - 'BackupImport': '1.1', + self.versions = ['1.38'] + self['1.38'] = { + 'Backup': '1.7', + 'BackupDeviceInfo': '1.0', + 'BackupImport': '1.7', 'BackupList': '1.0', - 'ConsistencyGroup': '1.1', - 'ConsistencyGroupList': '1.0', - 'Service': '1.0', - 'ServiceList': '1.0', - 'Snapshot': '1.0', + 'CleanupRequest': '1.0', + 'CGSnapshot': '1.1', + 'CGSnapshotList': '1.0', + 'Cluster': '1.1', + 'ClusterList': '1.0', + 'ConsistencyGroup': '1.4', + 'ConsistencyGroupList': '1.1', + 'Group': '1.2', + 'GroupList': '1.0', + 'GroupSnapshot': '1.0', + 'GroupSnapshotList': '1.0', + 'GroupType': '1.0', + 'GroupTypeList': '1.0', + 'LogLevel': '1.0', + 'LogLevelList': '1.0', + 'ManageableSnapshot': '1.0', + 'ManageableSnapshotList': '1.0', + 'ManageableVolume': '1.0', + 'ManageableVolumeList': '1.0', + 'QualityOfServiceSpecs': '1.0', + 'QualityOfServiceSpecsList': '1.0', + 'RequestSpec': '1.5', + 'Service': '1.6', + 'ServiceList': '1.1', + 'Snapshot': '1.5', 'SnapshotList': '1.0', - 'Volume': '1.1', - 'VolumeAttachment': '1.0', - 'VolumeAttachmentList': '1.0', + 'Volume': '1.8', + 'VolumeAttachment': '1.3', + 'VolumeAttachmentList': '1.1', 'VolumeList': '1.1', - 'VolumeType': '1.0', - 'VolumeTypeList': '1.0', + 'VolumeProperties': '1.1', + 'VolumeType': '1.3', + 'VolumeTypeList': '1.1', } def get_current(self): @@ -92,61 +114,25 @@ class CinderObjectVersionsHistory(dict): OBJ_VERSIONS = CinderObjectVersionsHistory() # NOTE(dulek): You should add a new version here each time you bump a version # of any object. As a second parameter you need to specify only what changed. + +# On each release we should drop backward compatibility with -2 release, since +# rolling upgrades only needs to support compatibility with previous release. +# So if we are in N release we can remove history from L and earlier. +# Example of how to keep track of this: +# # TODO: (T release) remove up to next TODO (was added in R release) and +# # update CinderObjectVersionsHistory +# OBJ_VERSIONS.add('1.34', {'VolumeAttachment': '1.3'}) +# OBJ_VERSIONS.add('1.35', {'Backup': '1.6', 'BackupImport': '1.6'}) # -# When dropping backward compatibility with an OpenStack release we can rework -# this and remove some history while keeping the versions order. -OBJ_VERSIONS.add('1.0', {'Backup': '1.3', 'BackupImport': '1.3', - 'CGSnapshot': '1.0', 'CGSnapshotList': '1.0', - 'ConsistencyGroup': '1.2', - 'ConsistencyGroupList': '1.1', 'Service': '1.1', - 'Volume': '1.3', 'VolumeTypeList': '1.1'}) -OBJ_VERSIONS.add('1.1', {'Service': '1.2', 'ServiceList': '1.1'}) -OBJ_VERSIONS.add('1.2', {'Backup': '1.4', 'BackupImport': '1.4'}) -OBJ_VERSIONS.add('1.3', {'Service': '1.3'}) -OBJ_VERSIONS.add('1.4', {'Snapshot': '1.1'}) -OBJ_VERSIONS.add('1.5', {'VolumeType': '1.1'}) -OBJ_VERSIONS.add('1.6', {'QualityOfServiceSpecs': '1.0', - 'QualityOfServiceSpecsList': '1.0', - 'VolumeType': '1.2'}) -OBJ_VERSIONS.add('1.7', {'Cluster': '1.0', 'ClusterList': '1.0', - 'Service': '1.4', 'Volume': '1.4', - 'ConsistencyGroup': '1.3'}) -OBJ_VERSIONS.add('1.8', {'RequestSpec': '1.0', 'VolumeProperties': '1.0'}) -OBJ_VERSIONS.add('1.9', {'GroupType': '1.0', 'GroupTypeList': '1.0'}) -OBJ_VERSIONS.add('1.10', {'Group': '1.0', 'GroupList': '1.0', 'Volume': '1.5', - 'RequestSpec': '1.1', 'VolumeProperties': '1.1'}) -OBJ_VERSIONS.add('1.11', {'GroupSnapshot': '1.0', 'GroupSnapshotList': '1.0', - 'Group': '1.1'}) -OBJ_VERSIONS.add('1.12', {'VolumeType': '1.3'}) -OBJ_VERSIONS.add('1.13', {'CleanupRequest': '1.0'}) -OBJ_VERSIONS.add('1.14', {'VolumeAttachmentList': '1.1'}) -OBJ_VERSIONS.add('1.15', {'Volume': '1.6', 'Snapshot': '1.2'}) -OBJ_VERSIONS.add('1.16', {'BackupDeviceInfo': '1.0'}) -OBJ_VERSIONS.add('1.17', {'VolumeAttachment': '1.1'}) -OBJ_VERSIONS.add('1.18', {'Snapshot': '1.3'}) -OBJ_VERSIONS.add('1.19', {'ConsistencyGroup': '1.4', 'CGSnapshot': '1.1'}) -OBJ_VERSIONS.add('1.20', {'Cluster': '1.1'}) -OBJ_VERSIONS.add('1.21', {'ManageableSnapshot': '1.0', - 'ManageableVolume': '1.0', - 'ManageableVolumeList': '1.0', - 'ManageableSnapshotList': '1.0'}) -OBJ_VERSIONS.add('1.22', {'Snapshot': '1.4'}) -OBJ_VERSIONS.add('1.23', {'VolumeAttachment': '1.2'}) -OBJ_VERSIONS.add('1.24', {'LogLevel': '1.0', 'LogLevelList': '1.0'}) -OBJ_VERSIONS.add('1.25', {'Group': '1.2'}) -OBJ_VERSIONS.add('1.26', {'Snapshot': '1.5'}) -OBJ_VERSIONS.add('1.27', {'Backup': '1.5', 'BackupImport': '1.5'}) -OBJ_VERSIONS.add('1.28', {'Service': '1.5'}) -OBJ_VERSIONS.add('1.29', {'Service': '1.6'}) -OBJ_VERSIONS.add('1.30', {'RequestSpec': '1.2'}) -OBJ_VERSIONS.add('1.31', {'Volume': '1.7'}) -OBJ_VERSIONS.add('1.32', {'RequestSpec': '1.3'}) -OBJ_VERSIONS.add('1.33', {'Volume': '1.8'}) -OBJ_VERSIONS.add('1.34', {'VolumeAttachment': '1.3'}) -OBJ_VERSIONS.add('1.35', {'Backup': '1.6', 'BackupImport': '1.6'}) -OBJ_VERSIONS.add('1.36', {'RequestSpec': '1.4'}) -OBJ_VERSIONS.add('1.37', {'RequestSpec': '1.5'}) -OBJ_VERSIONS.add('1.38', {'Backup': '1.7', 'BackupImport': '1.7'}) +# # TODO: (U release) remove up to next TODO (was added in S release) and +# # update CinderObjectVersionsHistory +# OBJ_VERSIONS.add('1.36', {'RequestSpec': '1.4'}) +# OBJ_VERSIONS.add('1.37', {'RequestSpec': '1.5'}) +# OBJ_VERSIONS.add('1.38', {'Backup': '1.7', 'BackupImport': '1.7'}) +# When we reach T release we remove versions 1.34 and 1.35 and update __init__ +# method in CinderObjectVerseionsHistory to bump VolumeAttachment to 1.3, +# Backup to 1.6 and BackupImport to 1.6, and changing the versions list to +# '1.35' and the self[''] = { to self['1.35'] = { class CinderObjectRegistry(base.VersionedObjectRegistry): diff --git a/cinder/objects/cgsnapshot.py b/cinder/objects/cgsnapshot.py index 99b83996e61..50dc667d3f1 100644 --- a/cinder/objects/cgsnapshot.py +++ b/cinder/objects/cgsnapshot.py @@ -30,6 +30,7 @@ class CGSnapshot(base.CinderPersistentObject, base.CinderObject, OPTIONAL_FIELDS = ['consistencygroup', 'snapshots'] + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'id': fields.UUIDField(), 'consistencygroup_id': fields.UUIDField(nullable=True), diff --git a/cinder/objects/cleanup_request.py b/cinder/objects/cleanup_request.py index 30c1ee7a08e..03c5ad53b2d 100644 --- a/cinder/objects/cleanup_request.py +++ b/cinder/objects/cleanup_request.py @@ -24,6 +24,7 @@ class CleanupRequest(base.CinderObject, base.ClusteredObject): # Version 1.0: Initial version VERSION = '1.0' + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'service_id': fields.IntegerField(nullable=True), 'cluster_name': fields.StringField(nullable=True), diff --git a/cinder/objects/cluster.py b/cinder/objects/cluster.py index 09771b3f126..cb99926658c 100644 --- a/cinder/objects/cluster.py +++ b/cinder/objects/cluster.py @@ -42,9 +42,7 @@ class Cluster(base.CinderPersistentObject, base.CinderObject, VERSION = '1.1' OPTIONAL_FIELDS = ('num_hosts', 'num_down_hosts', 'services') - # NOTE(geguileo): We don't want to expose race_preventer field at the OVO - # layer since it is only meant for the DB layer internal mechanism to - # prevent races. + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'id': fields.IntegerField(), 'name': fields.StringField(nullable=False), @@ -60,20 +58,11 @@ class Cluster(base.CinderPersistentObject, base.CinderObject, 'replication_status': c_fields.ReplicationStatusField(nullable=True), 'frozen': fields.BooleanField(default=False), 'active_backend_id': fields.StringField(nullable=True), + + # Don't add race_preventer field, as it's a DB layer internal mechanism + # piece to prevent races and should not be touched by other layers. } - def obj_make_compatible(self, primitive, target_version): - """Make a cluster representation compatible with a target version.""" - # Convert all related objects - super(Cluster, self).obj_make_compatible(primitive, target_version) - - # Before v1.1 we didn't have relication fields so we have to remove - # them. - if target_version == '1.0': - for obj_field in ('replication_status', 'frozen', - 'active_backend_id'): - primitive.pop(obj_field, None) - @classmethod def _get_expected_attrs(cls, context, *args, **kwargs): """Return expected attributes when getting a cluster. diff --git a/cinder/objects/consistencygroup.py b/cinder/objects/consistencygroup.py index e216d4233fc..547bb7290c0 100644 --- a/cinder/objects/consistencygroup.py +++ b/cinder/objects/consistencygroup.py @@ -12,7 +12,6 @@ # License for the specific language governing permissions and limitations # under the License. -from oslo_utils import versionutils from oslo_versionedobjects import fields from cinder import db @@ -54,18 +53,6 @@ class ConsistencyGroup(base.CinderPersistentObject, base.CinderObject, 'volumes': fields.ObjectField('VolumeList', nullable=True), } - def obj_make_compatible(self, primitive, target_version): - """Make a CG representation compatible with a target version.""" - # Convert all related objects - super(ConsistencyGroup, self).obj_make_compatible(primitive, - target_version) - - target_version = versionutils.convert_version_to_tuple(target_version) - # Before v1.3 we didn't have cluster fields so we have to remove them. - if target_version < (1, 3): - for obj_field in ('cluster', 'cluster_name'): - primitive.pop(obj_field, None) - @classmethod def _from_db_object(cls, context, consistencygroup, db_consistencygroup, expected_attrs=None): diff --git a/cinder/objects/dynamic_log.py b/cinder/objects/dynamic_log.py index b72e82789de..adfa353e39c 100644 --- a/cinder/objects/dynamic_log.py +++ b/cinder/objects/dynamic_log.py @@ -24,6 +24,7 @@ class LogLevel(base.CinderObject): # Version 1.0: Initial version VERSION = '1.0' + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'prefix': fields.StringField(nullable=True), 'level': fields.StringField(nullable=True), diff --git a/cinder/objects/group.py b/cinder/objects/group.py index c159c14f41e..dd9fb1136b7 100644 --- a/cinder/objects/group.py +++ b/cinder/objects/group.py @@ -12,7 +12,6 @@ # License for the specific language governing permissions and limitations # under the License. -from oslo_utils import versionutils from oslo_versionedobjects import fields from cinder import db @@ -35,6 +34,7 @@ class Group(base.CinderPersistentObject, base.CinderObject, OPTIONAL_FIELDS = ['volumes', 'volume_types', 'group_snapshots'] + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'id': fields.UUIDField(), 'user_id': fields.StringField(), @@ -57,17 +57,6 @@ class Group(base.CinderPersistentObject, base.CinderObject, nullable=True), } - def obj_make_compatible(self, primitive, target_version): - """Make an object representation compatible with target version.""" - super(Group, self).obj_make_compatible(primitive, target_version) - target_version = versionutils.convert_version_to_tuple(target_version) - if target_version < (1, 1): - for key in ('group_snapshot_id', 'source_group_id', - 'group_snapshots'): - primitive.pop(key, None) - if target_version < (1, 2): - primitive.pop('replication_status', None) - @staticmethod def _from_db_object(context, group, db_group, expected_attrs=None): diff --git a/cinder/objects/group_snapshot.py b/cinder/objects/group_snapshot.py index 5021fd5e87d..083c1be1c03 100644 --- a/cinder/objects/group_snapshot.py +++ b/cinder/objects/group_snapshot.py @@ -28,6 +28,7 @@ class GroupSnapshot(base.CinderPersistentObject, base.CinderObject, OPTIONAL_FIELDS = ['group', 'snapshots'] + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'id': fields.UUIDField(), 'group_id': fields.UUIDField(nullable=False), diff --git a/cinder/objects/group_type.py b/cinder/objects/group_type.py index be66ee02790..a5fe61a8831 100644 --- a/cinder/objects/group_type.py +++ b/cinder/objects/group_type.py @@ -29,6 +29,7 @@ class GroupType(base.CinderPersistentObject, base.CinderObject, OPTIONAL_FIELDS = ['group_specs', 'projects'] + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'id': fields.UUIDField(), 'name': fields.StringField(nullable=True), diff --git a/cinder/objects/manageableresources.py b/cinder/objects/manageableresources.py index 3ccb38f9734..d7d510b85ed 100644 --- a/cinder/objects/manageableresources.py +++ b/cinder/objects/manageableresources.py @@ -19,6 +19,7 @@ from cinder.objects import base class ManageableObject(object): + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'reference': fields.DictOfNullableStringsField(nullable=False), 'size': fields.IntegerField(nullable=True), @@ -58,6 +59,7 @@ class ManageableSnapshot(base.CinderObject, base.CinderObjectDictCompat, # Version 1.0: Initial version VERSION = '1.0' + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'source_reference': fields.DictOfNullableStringsField(), } diff --git a/cinder/objects/qos_specs.py b/cinder/objects/qos_specs.py index 6fdfe1a4bde..9824983d087 100644 --- a/cinder/objects/qos_specs.py +++ b/cinder/objects/qos_specs.py @@ -35,6 +35,7 @@ class QualityOfServiceSpecs(base.CinderPersistentObject, OPTIONAL_FIELDS = ['volume_types'] + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'id': fields.UUIDField(), 'name': fields.StringField(), diff --git a/cinder/objects/request_spec.py b/cinder/objects/request_spec.py index 98249ee48fd..665e9750e31 100644 --- a/cinder/objects/request_spec.py +++ b/cinder/objects/request_spec.py @@ -12,7 +12,6 @@ # License for the specific language governing permissions and limitations # under the License. -from oslo_utils import versionutils from oslo_versionedobjects import fields from cinder import objects @@ -30,6 +29,7 @@ class RequestSpec(base.CinderObject, base.CinderObjectDictCompat, # Version 1.5: Added 'availability_zones' VERSION = '1.5' + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'consistencygroup_id': fields.UUIDField(nullable=True), 'group_id': fields.UUIDField(nullable=True), @@ -95,20 +95,6 @@ class RequestSpec(base.CinderObject, base.CinderObjectDictCompat, return spec_obj - def obj_make_compatible(self, primitive, target_version): - """Make an object representation compatible with target version.""" - super(RequestSpec, self).obj_make_compatible(primitive, target_version) - target_version = versionutils.convert_version_to_tuple(target_version) - added_fields = (((1, 1), ('group_id', 'group_backend')), - ((1, 2), ('resource_backend')), - ((1, 3), ('backup_id')), - ((1, 4), ('operation')), - ((1, 5), ('availability_zones'))) - for version, remove_fields in added_fields: - if target_version < version: - for obj_field in remove_fields: - primitive.pop(obj_field, None) - @base.CinderObjectRegistry.register class VolumeProperties(base.CinderObject, base.CinderObjectDictCompat): diff --git a/cinder/objects/service.py b/cinder/objects/service.py index 1686f210b95..347fcebd75f 100644 --- a/cinder/objects/service.py +++ b/cinder/objects/service.py @@ -44,6 +44,7 @@ class Service(base.CinderPersistentObject, base.CinderObject, OPTIONAL_FIELDS = ('cluster',) + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'id': fields.IntegerField(), 'host': fields.StringField(nullable=True), @@ -70,19 +71,6 @@ class Service(base.CinderPersistentObject, base.CinderObject, 'uuid': fields.StringField(), } - def obj_make_compatible(self, primitive, target_version): - """Make a service representation compatible with a target version.""" - # Convert all related objects - super(Service, self).obj_make_compatible(primitive, target_version) - - target_version = versionutils.convert_version_to_tuple(target_version) - # Before v1.4 we didn't have cluster fields so we have to remove them. - if target_version < (1, 4): - for obj_field in ('cluster', 'cluster_name'): - primitive.pop(obj_field, None) - if target_version < (1, 5) and 'uuid' in primitive: - del primitive['uuid'] - @staticmethod def _from_db_object(context, service, db_service, expected_attrs=None): expected_attrs = expected_attrs or [] diff --git a/cinder/objects/snapshot.py b/cinder/objects/snapshot.py index 844c51ca5ca..edb99ff211f 100644 --- a/cinder/objects/snapshot.py +++ b/cinder/objects/snapshot.py @@ -13,7 +13,6 @@ # under the License. from oslo_config import cfg -from oslo_utils import versionutils from oslo_versionedobjects import fields from cinder import db @@ -45,6 +44,7 @@ class Snapshot(cleanable.CinderCleanableObject, base.CinderObject, # are typically the relationship in the sqlalchemy object. OPTIONAL_FIELDS = ('volume', 'metadata', 'cgsnapshot', 'group_snapshot') + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'id': fields.UUIDField(), @@ -116,25 +116,6 @@ class Snapshot(cleanable.CinderCleanableObject, base.CinderObject, return changes - def obj_make_compatible(self, primitive, target_version): - """Make an object representation compatible with a target version.""" - super(Snapshot, self).obj_make_compatible(primitive, target_version) - target_version = versionutils.convert_version_to_tuple(target_version) - - backport_statuses = (((1, 3), - (c_fields.SnapshotStatus.UNMANAGING, - c_fields.SnapshotStatus.DELETING)), - ((1, 4), - (c_fields.SnapshotStatus.BACKING_UP, - c_fields.SnapshotStatus.AVAILABLE)), - ((1, 5), - (c_fields.SnapshotStatus.RESTORING, - c_fields.SnapshotStatus.AVAILABLE))) - for version, status in backport_statuses: - if target_version < version: - if primitive.get('status') == status[0]: - primitive['status'] = status[1] - @classmethod def _from_db_object(cls, context, snapshot, db_snapshot, expected_attrs=None): diff --git a/cinder/objects/volume.py b/cinder/objects/volume.py index 282fcfe62d8..a24f8504379 100644 --- a/cinder/objects/volume.py +++ b/cinder/objects/volume.py @@ -13,7 +13,6 @@ # under the License. from oslo_config import cfg -from oslo_utils import versionutils from oslo_versionedobjects import fields from cinder import db @@ -69,6 +68,7 @@ class Volume(cleanable.CinderCleanableObject, base.CinderObject, 'volume_type', 'volume_attachment', 'consistencygroup', 'snapshots', 'cluster', 'group') + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'id': fields.UUIDField(), '_name_id': fields.UUIDField(nullable=True), @@ -239,21 +239,6 @@ class Volume(cleanable.CinderCleanableObject, base.CinderObject, return changes - def obj_make_compatible(self, primitive, target_version): - """Make a Volume representation compatible with a target version.""" - added_fields = (((1, 4), ('cluster', 'cluster_name')), - ((1, 5), ('group', 'group_id')), - ((1, 7), ('service_uuid'))) - - # Convert all related objects - super(Volume, self).obj_make_compatible(primitive, target_version) - - target_version = versionutils.convert_version_to_tuple(target_version) - for version, remove_fields in added_fields: - if target_version < version: - for obj_field in remove_fields: - primitive.pop(obj_field, None) - @classmethod def _from_db_object(cls, context, volume, db_volume, expected_attrs=None): if expected_attrs is None: diff --git a/cinder/objects/volume_attachment.py b/cinder/objects/volume_attachment.py index d4462e9dc68..52c6a4f67b7 100644 --- a/cinder/objects/volume_attachment.py +++ b/cinder/objects/volume_attachment.py @@ -13,7 +13,6 @@ # under the License. from oslo_serialization import jsonutils -from oslo_utils import versionutils from oslo_versionedobjects import fields from cinder import db @@ -37,6 +36,7 @@ class VolumeAttachment(base.CinderPersistentObject, base.CinderObject, OPTIONAL_FIELDS = ['volume'] obj_extra_fields = ['project_id', 'volume_host'] + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'id': fields.UUIDField(), 'volume_id': fields.UUIDField(), @@ -67,16 +67,6 @@ class VolumeAttachment(base.CinderPersistentObject, base.CinderObject, def _get_expected_attrs(cls, context, *args, **kwargs): return ['volume'] - def obj_make_compatible(self, primitive, target_version): - """Make an object representation compatible with target version.""" - super(VolumeAttachment, self).obj_make_compatible(primitive, - target_version) - target_version = versionutils.convert_version_to_tuple(target_version) - if target_version < (1, 3): - primitive.pop('connector', None) - if target_version < (1, 2): - primitive.pop('connection_info', None) - @classmethod def _from_db_object(cls, context, attachment, db_attachment, expected_attrs=None): diff --git a/cinder/objects/volume_type.py b/cinder/objects/volume_type.py index 4fdf9fcc923..ff7a127d5e8 100644 --- a/cinder/objects/volume_type.py +++ b/cinder/objects/volume_type.py @@ -12,7 +12,6 @@ # License for the specific language governing permissions and limitations # under the License. -from oslo_utils import versionutils from oslo_versionedobjects import fields from cinder import db @@ -35,6 +34,7 @@ class VolumeType(base.CinderPersistentObject, base.CinderObject, OPTIONAL_FIELDS = ('extra_specs', 'projects', 'qos_specs') + # NOTE: When adding a field obj_make_compatible needs to be updated fields = { 'id': fields.UUIDField(), 'name': fields.StringField(nullable=True), @@ -47,21 +47,6 @@ class VolumeType(base.CinderPersistentObject, base.CinderObject, nullable=True), } - def obj_make_compatible(self, primitive, target_version): - super(VolumeType, self).obj_make_compatible(primitive, target_version) - - target_version = versionutils.convert_version_to_tuple(target_version) - if target_version < (1, 1): - if primitive.get('extra_specs'): - # Before 1.1 extra_specs field didn't allowed None values. To - # make sure we won't explode on receiver side - change Nones to - # empty string. - for k, v in primitive['extra_specs'].items(): - if v is None: - primitive['extra_specs'][k] = '' - if target_version < (1, 3): - primitive.pop('qos_specs_id', None) - @classmethod def _get_expected_attrs(cls, context, *args, **kwargs): return 'extra_specs', 'projects' diff --git a/cinder/tests/unit/backup/test_backup.py b/cinder/tests/unit/backup/test_backup.py index abd1afcaa26..22fed48b3f5 100644 --- a/cinder/tests/unit/backup/test_backup.py +++ b/cinder/tests/unit/backup/test_backup.py @@ -356,19 +356,22 @@ class BackupTestCase(BaseBackupTest): @mock.patch('cinder.objects.service.Service.get_minimum_obj_version') @mock.patch('cinder.rpc.LAST_RPC_VERSIONS', {'cinder-backup': '1.3', 'cinder-volume': '1.7'}) - @mock.patch('cinder.rpc.LAST_OBJ_VERSIONS', {'cinder-backup': '1.2', - 'cinder-volume': '1.4'}) def test_reset(self, get_min_obj, get_min_rpc): - get_min_obj.return_value = 'liberty' - backup_mgr = manager.BackupManager() + old_version = objects.base.OBJ_VERSIONS.versions[-2] + + with mock.patch('cinder.rpc.LAST_OBJ_VERSIONS', + {'cinder-volume': old_version, + 'cinder-scheduler': old_version, + 'cinder-backup': old_version}): + backup_mgr = manager.BackupManager() backup_rpcapi = backup_mgr.backup_rpcapi volume_rpcapi = backup_mgr.volume_rpcapi self.assertEqual('1.3', backup_rpcapi.client.version_cap) - self.assertEqual('1.2', + self.assertEqual(old_version, backup_rpcapi.client.serializer._base.version_cap) self.assertEqual('1.7', volume_rpcapi.client.version_cap) - self.assertEqual('1.4', + self.assertEqual(old_version, volume_rpcapi.client.serializer._base.version_cap) get_min_obj.return_value = objects.base.OBJ_VERSIONS.get_current() backup_mgr.reset() diff --git a/cinder/tests/unit/objects/test_base.py b/cinder/tests/unit/objects/test_base.py index 2db115cbe79..5f0619add2c 100644 --- a/cinder/tests/unit/objects/test_base.py +++ b/cinder/tests/unit/objects/test_base.py @@ -36,6 +36,7 @@ from cinder.tests.unit import test class TestCinderObjectVersionHistory(test_objects.BaseObjectsTestCase): def test_add(self): history = test_objects.obj_base.CinderObjectVersionsHistory() + first_version = history.versions[0] v10 = {'Backup': '2.0'} v11 = {'Backup': '2.1'} history.add('1.0', v10) @@ -43,9 +44,9 @@ class TestCinderObjectVersionHistory(test_objects.BaseObjectsTestCase): # We have 3 elements because we have the liberty version by default self.assertEqual(2 + 1, len(history)) - expected_v10 = history['liberty'].copy() + expected_v10 = history[first_version].copy() expected_v10.update(v10) - expected_v11 = history['liberty'].copy() + expected_v11 = history[first_version].copy() expected_v11.update(v11) self.assertEqual('1.1', history.get_current()) diff --git a/cinder/tests/unit/objects/test_cleanable.py b/cinder/tests/unit/objects/test_cleanable.py index 26202b33024..5d85f896eeb 100644 --- a/cinder/tests/unit/objects/test_cleanable.py +++ b/cinder/tests/unit/objects/test_cleanable.py @@ -19,7 +19,6 @@ from unittest import mock from cinder import context from cinder import exception from cinder.objects import cleanable -from cinder import rpc from cinder import service from cinder.tests.unit import objects as test_objects from cinder.volume import rpcapi @@ -35,7 +34,7 @@ class Backup(cleanable.CinderCleanableObject): @staticmethod def _is_cleanable(status, obj_version): - if obj_version and obj_version <= 1003: + if obj_version and obj_version < 1003: return False return status == 'cleanable' @@ -53,46 +52,52 @@ class TestCleanable(test_objects.BaseObjectsTestCase): vol_rpcapi = cleanable.CinderCleanableObject.get_rpc_api() self.assertEqual(rpcapi.VolumeAPI, vol_rpcapi) + def set_version(self, version): + self.patch('cinder.volume.rpcapi.VolumeAPI.determine_obj_version_cap', + mock.Mock(return_value='1.0')) + self.patch('cinder.objects.base.OBJ_VERSIONS', + {'1.0': {'Backup': version}}) + def test_get_pinned_version(self): """Test that we get the pinned version for this specific object.""" - rpc.LAST_OBJ_VERSIONS[Backup.get_rpc_api().BINARY] = '1.0' + self.set_version('1.3') version = Backup.get_pinned_version() self.assertEqual(1003, version) def test_is_cleanable_pinned_pinned_too_old(self): """Test is_cleanable with pinned version with uncleanable version.""" - rpc.LAST_OBJ_VERSIONS[Backup.get_rpc_api().BINARY] = '1.0' + self.set_version('1.0') backup = Backup(status='cleanable') self.assertFalse(backup.is_cleanable(pinned=True)) def test_is_cleanable_pinned_result_true(self): """Test with pinned version with cleanable version and status.""" - rpc.LAST_OBJ_VERSIONS[Backup.get_rpc_api().BINARY] = '1.3' + self.set_version('1.3') backup = Backup(status='cleanable') self.assertTrue(backup.is_cleanable(pinned=True)) def test_is_cleanable_pinned_result_false(self): """Test with pinned version with cleanable version but not status.""" - rpc.LAST_OBJ_VERSIONS[Backup.get_rpc_api().BINARY] = '1.3' + self.set_version('1.0') backup = Backup(status='not_cleanable') self.assertFalse(backup.is_cleanable(pinned=True)) def test_is_cleanable_unpinned_result_false(self): """Test unpinned version with old version and non cleanable status.""" - rpc.LAST_OBJ_VERSIONS[Backup.get_rpc_api().BINARY] = '1.0' + self.set_version('1.0') backup = Backup(status='not_cleanable') self.assertFalse(backup.is_cleanable(pinned=False)) def test_is_cleanable_unpinned_result_true(self): """Test unpinned version with old version and cleanable status.""" - rpc.LAST_OBJ_VERSIONS[Backup.get_rpc_api().BINARY] = '1.0' + self.set_version('1.0') backup = Backup(status='cleanable') self.assertTrue(backup.is_cleanable(pinned=False)) @mock.patch('cinder.db.worker_create', autospec=True) def test_create_worker(self, mock_create): """Test worker creation as if it were from an rpc call.""" - rpc.LAST_OBJ_VERSIONS[Backup.get_rpc_api().BINARY] = '1.3' + self.set_version('1.3') mock_create.return_value = mock.sentinel.worker backup = Backup(_context=self.context, status='cleanable', id=mock.sentinel.id) @@ -106,7 +111,7 @@ class TestCleanable(test_objects.BaseObjectsTestCase): @mock.patch('cinder.db.worker_create', autospec=True) def test_create_worker_pinned_too_old(self, mock_create): """Test worker creation when we are pinnned with an old version.""" - rpc.LAST_OBJ_VERSIONS[Backup.get_rpc_api().BINARY] = '1.0' + self.set_version('1.0') mock_create.return_value = mock.sentinel.worker backup = Backup(_context=self.context, status='cleanable', id=mock.sentinel.id) @@ -117,7 +122,7 @@ class TestCleanable(test_objects.BaseObjectsTestCase): @mock.patch('cinder.db.worker_create', autospec=True) def test_create_worker_non_cleanable(self, mock_create): """Test worker creation when status is non cleanable.""" - rpc.LAST_OBJ_VERSIONS[Backup.get_rpc_api().BINARY] = '1.3' + self.set_version('1.3') mock_create.return_value = mock.sentinel.worker backup = Backup(_context=self.context, status='non_cleanable', id=mock.sentinel.id) @@ -129,7 +134,7 @@ class TestCleanable(test_objects.BaseObjectsTestCase): @mock.patch('cinder.db.worker_create', autospec=True) def test_create_worker_already_exists(self, mock_create, mock_update): """Test worker creation when a worker for the resource exists.""" - rpc.LAST_OBJ_VERSIONS[Backup.get_rpc_api().BINARY] = '1.3' + self.set_version('1.3') mock_create.side_effect = exception.WorkerExists(type='type', id='id') backup = Backup(_context=self.context, status='cleanable', @@ -152,7 +157,7 @@ class TestCleanable(test_objects.BaseObjectsTestCase): that the entry gets removed from the DB between our failure to create it and our try to update the entry. """ - rpc.LAST_OBJ_VERSIONS[Backup.get_rpc_api().BINARY] = '1.3' + self.set_version('1.3') mock_create.side_effect = [ exception.WorkerExists(type='type', id='id'), mock.sentinel.worker] mock_update.side_effect = exception.WorkerNotFound diff --git a/cinder/tests/unit/objects/test_cluster.py b/cinder/tests/unit/objects/test_cluster.py index 6f56bfa5929..0feaa6423eb 100644 --- a/cinder/tests/unit/objects/test_cluster.py +++ b/cinder/tests/unit/objects/test_cluster.py @@ -124,19 +124,6 @@ class TestCluster(test_objects.BaseObjectsTestCase): 'active_backend_id': None}, {'cluster_name': cluster.name}) - @ddt.data('1.0', '1.1') - def tests_obj_make_compatible(self, version): - new_fields = {'replication_status': 'error', 'frozen': True, - 'active_backend_id': 'replication'} - cluster = objects.Cluster(self.context, **new_fields) - primitive = cluster.obj_to_primitive(version) - converted_cluster = objects.Cluster.obj_from_primitive(primitive) - for key, value in new_fields.items(): - if version == '1.0': - self.assertFalse(converted_cluster.obj_attr_is_set(key)) - else: - self.assertEqual(value, getattr(converted_cluster, key)) - class TestClusterList(test_objects.BaseObjectsTestCase): """Test ClusterList Versioned Object methods.""" diff --git a/cinder/tests/unit/objects/test_group.py b/cinder/tests/unit/objects/test_group.py index 22475589efb..74dcaddd0eb 100644 --- a/cinder/tests/unit/objects/test_group.py +++ b/cinder/tests/unit/objects/test_group.py @@ -18,7 +18,6 @@ import ddt from cinder import exception from cinder import objects -from cinder.objects import base as ovo_base from cinder.objects import fields from cinder.tests.unit import fake_constants as fake from cinder.tests.unit import fake_volume @@ -159,22 +158,6 @@ class TestGroup(test_objects.BaseObjectsTestCase): self.assertEqual(len(db_volumes), len(group.volumes)) self._compare(self, db_volumes[0], group.volumes[0]) - @ddt.data('1.10', '1.11') - def test_obj_make_compatible(self, version): - extra_data = {'group_snapshot_id': fake.GROUP_SNAPSHOT_ID, - 'source_group_id': fake.GROUP_ID, - 'group_snapshots': objects.GroupSnapshotList()} - group = objects.Group(self.context, name='name', **extra_data) - - serializer = ovo_base.CinderObjectSerializer(version) - primitive = serializer.serialize_entity(self.context, group) - - converted_group = objects.Group.obj_from_primitive(primitive) - is_set = version == '1.11' - for key in extra_data: - self.assertEqual(is_set, converted_group.obj_attr_is_set(key)) - self.assertEqual('name', converted_group.name) - @mock.patch('cinder.volume.group_types.get_group_type_specs') def test_is_replicated_true(self, mock_get_specs): mock_get_specs.return_value = ' True' diff --git a/cinder/tests/unit/objects/test_objects.py b/cinder/tests/unit/objects/test_objects.py index be608ec4622..49a4beef066 100644 --- a/cinder/tests/unit/objects/test_objects.py +++ b/cinder/tests/unit/objects/test_objects.py @@ -80,6 +80,10 @@ class TestObjectVersions(test.TestCase): "and we just have to change the hash in this module.") def test_versions_history(self): + # If we inserted a fake element in history, remove it so we don't fail + if base.OBJ_VERSIONS.get_current() == self.FAKE_OVO_HISTORY_VERSION: + fake_version = base.OBJ_VERSIONS.versions.pop(-1) + del base.OBJ_VERSIONS[fake_version] classes = base.CinderObjectRegistry.obj_classes() versions = base.OBJ_VERSIONS.get_current_versions() expected = {} diff --git a/cinder/tests/unit/objects/test_snapshot.py b/cinder/tests/unit/objects/test_snapshot.py index 11c740577a1..032786d1e74 100644 --- a/cinder/tests/unit/objects/test_snapshot.py +++ b/cinder/tests/unit/objects/test_snapshot.py @@ -229,30 +229,6 @@ class TestSnapshot(test_objects.BaseObjectsTestCase): mock.call(self.context, fake.SNAPSHOT_ID)]) - @ddt.data('1.1', '1.3') - def test_obj_make_compatible_1_3(self, version): - snapshot = objects.Snapshot(context=self.context) - snapshot.status = fields.SnapshotStatus.UNMANAGING - primitive = snapshot.obj_to_primitive(version) - snapshot = objects.Snapshot.obj_from_primitive(primitive) - if version == '1.3': - status = fields.SnapshotStatus.UNMANAGING - else: - status = fields.SnapshotStatus.DELETING - self.assertEqual(status, snapshot.status) - - @ddt.data('1.3', '1.4') - def test_obj_make_compatible_1_4(self, version): - snapshot = objects.Snapshot(context=self.context) - snapshot.status = fields.SnapshotStatus.BACKING_UP - primitive = snapshot.obj_to_primitive(version) - snapshot = objects.Snapshot.obj_from_primitive(primitive) - if version == '1.4': - status = fields.SnapshotStatus.BACKING_UP - else: - status = fields.SnapshotStatus.AVAILABLE - self.assertEqual(status, snapshot.status) - class TestSnapshotList(test_objects.BaseObjectsTestCase): @mock.patch('cinder.objects.volume.Volume.get_by_id') diff --git a/cinder/tests/unit/objects/test_volume.py b/cinder/tests/unit/objects/test_volume.py index f2093627de1..d874f8a90d2 100644 --- a/cinder/tests/unit/objects/test_volume.py +++ b/cinder/tests/unit/objects/test_volume.py @@ -21,7 +21,6 @@ import pytz from cinder import context from cinder import exception from cinder import objects -from cinder.objects import base as ovo_base from cinder.objects import fields from cinder.tests.unit.consistencygroup import fake_consistencygroup from cinder.tests.unit import fake_constants as fake @@ -532,36 +531,6 @@ class TestVolume(test_objects.BaseObjectsTestCase): self.assertEqual({}, volume.cinder_obj_get_changes()) self.assertFalse(volume_attachment_get.called) - @ddt.data('1.6', '1.7') - def test_obj_make_compatible_cluster_added(self, version): - extra_data = {'cluster_name': 'cluster_name', - 'cluster': objects.Cluster()} - volume = objects.Volume(self.context, host='host', **extra_data) - - serializer = ovo_base.CinderObjectSerializer(version) - primitive = serializer.serialize_entity(self.context, volume) - - converted_volume = objects.Volume.obj_from_primitive(primitive) - is_set = version == '1.7' - for key in extra_data: - self.assertEqual(is_set, converted_volume.obj_attr_is_set(key)) - self.assertEqual('host', converted_volume.host) - - @ddt.data('1.9', '1.10') - def test_obj_make_compatible_groups_added(self, version): - extra_data = {'group_id': fake.GROUP_ID, - 'group': objects.Group()} - volume = objects.Volume(self.context, host='host', **extra_data) - - serializer = ovo_base.CinderObjectSerializer(version) - primitive = serializer.serialize_entity(self.context, volume) - - converted_volume = objects.Volume.obj_from_primitive(primitive) - is_set = version == '1.10' - for key in extra_data: - self.assertEqual(is_set, converted_volume.obj_attr_is_set(key)) - self.assertEqual('host', converted_volume.host) - @ddt.data(True, False) def test_is_replicated(self, result): volume_type = fake_volume.fake_volume_type_obj(self.context) diff --git a/cinder/tests/unit/objects/test_volume_attachment.py b/cinder/tests/unit/objects/test_volume_attachment.py index 5e9556ffad8..41aed7eb186 100644 --- a/cinder/tests/unit/objects/test_volume_attachment.py +++ b/cinder/tests/unit/objects/test_volume_attachment.py @@ -123,26 +123,6 @@ class TestVolumeAttachment(test_objects.BaseObjectsTestCase): self.assertEqual(fields.VolumeAttachStatus.ATTACHED, attachment.attach_status) - @ddt.data('1.0', '1.1', '1.2', '1.3') - def test_obj_make_compatible(self, version): - connection_info = {'field': 'value'} - connector = {'host': '127.0.0.1'} - vol_attach = objects.VolumeAttachment(self.context, - connection_info=connection_info, - connector=connector) - primitive = vol_attach.obj_to_primitive(version) - converted_vol_attach = objects.VolumeAttachment.obj_from_primitive( - primitive) - if version == '1.3': - self.assertEqual(connector, converted_vol_attach.connector) - elif version == '1.2': - self.assertEqual(connection_info, - converted_vol_attach.connection_info) - else: - self.assertNotIn('connector', converted_vol_attach) - self.assertFalse(converted_vol_attach.obj_attr_is_set( - 'connection_info')) - def test_migrate_attachment_specs(self): # Create an attachment. attachment = objects.VolumeAttachment( diff --git a/cinder/tests/unit/objects/test_volume_type.py b/cinder/tests/unit/objects/test_volume_type.py index 53bdeedf2f6..042859436a6 100644 --- a/cinder/tests/unit/objects/test_volume_type.py +++ b/cinder/tests/unit/objects/test_volume_type.py @@ -75,18 +75,6 @@ class TestVolumeType(test_objects.BaseObjectsTestCase): self.context, fake.VOLUME_TYPE_ID) self._compare(self, db_volume_type, volume_type) - @ddt.data('1.0', '1.1') - def test_obj_make_compatible(self, version): - volume_type = objects.VolumeType(context=self.context) - volume_type.extra_specs = {'foo': None, 'bar': 'baz'} - volume_type.qos_specs_id = fake.QOS_SPEC_ID - primitive = volume_type.obj_to_primitive(version) - volume_type = objects.VolumeType.obj_from_primitive(primitive) - foo = '' if version == '1.0' else None - self.assertEqual(foo, volume_type.extra_specs['foo']) - self.assertEqual('baz', volume_type.extra_specs['bar']) - self.assertFalse(volume_type.obj_attr_is_set('qos_specs_id')) - @mock.patch('cinder.volume.volume_types.create') def test_create(self, volume_type_create): db_volume_type = fake_volume.fake_db_volume_type() diff --git a/cinder/tests/unit/scheduler/test_scheduler.py b/cinder/tests/unit/scheduler/test_scheduler.py index 4036e7d59ab..1ab60ce23e8 100644 --- a/cinder/tests/unit/scheduler/test_scheduler.py +++ b/cinder/tests/unit/scheduler/test_scheduler.py @@ -120,17 +120,20 @@ class SchedulerManagerTestCase(test.TestCase): @mock.patch('cinder.objects.service.Service.get_minimum_rpc_version') @mock.patch('cinder.objects.service.Service.get_minimum_obj_version') @mock.patch('cinder.rpc.LAST_RPC_VERSIONS', {'cinder-volume': '1.3'}) - @mock.patch('cinder.rpc.LAST_OBJ_VERSIONS', {'cinder-volume': '1.4', - 'cinder-scheduler': '1.4', - 'cinder-backup': '1.5'}) def test_reset(self, get_min_obj, get_min_rpc): - mgr = self.manager_cls() + old_version = objects.base.OBJ_VERSIONS.versions[-2] + + with mock.patch('cinder.rpc.LAST_OBJ_VERSIONS', + {'cinder-volume': old_version, + 'cinder-scheduler': old_version, + 'cinder-backup': old_version}): + mgr = self.manager_cls() volume_rpcapi = mgr.driver.volume_rpcapi self.assertEqual('1.3', volume_rpcapi.client.version_cap) - self.assertEqual('1.4', + self.assertEqual(old_version, volume_rpcapi.client.serializer._base.version_cap) - get_min_obj.return_value = objects.base.OBJ_VERSIONS.get_current() + get_min_obj.return_value = self.latest_ovo_version mgr.reset() volume_rpcapi = mgr.driver.volume_rpcapi diff --git a/cinder/tests/unit/test.py b/cinder/tests/unit/test.py index b687030ede7..4827ca12f64 100644 --- a/cinder/tests/unit/test.py +++ b/cinder/tests/unit/test.py @@ -112,8 +112,10 @@ class TestCase(testtools.TestCase): RESOURCE_FILTER_FILENAME) MOCK_WORKER = True MOCK_TOOZ = True + FAKE_OVO_HISTORY_VERSION = '9999.999' def __init__(self, *args, **kwargs): + super(TestCase, self).__init__(*args, **kwargs) # Suppress some log messages during test runs @@ -301,6 +303,16 @@ class TestCase(testtools.TestCase): self.vt = volume_types.get_default_volume_type() + # Create fake RPC history if we don't have enough to do tests + obj_versions = objects_base.OBJ_VERSIONS + if len(obj_versions) == 1: + vol_vers = obj_versions.get_current_versions()['Volume'].split('.') + new_volume_version = '%s.%s' % (vol_vers[0], int(vol_vers[1]) + 1) + obj_versions.add(self.FAKE_OVO_HISTORY_VERSION, + {'Volume': new_volume_version}) + + self.latest_ovo_version = obj_versions.get_current() + def _restore_obj_registry(self): objects_base.CinderObjectRegistry._registry._obj_classes = \ self._base_test_obj_backup diff --git a/cinder/tests/unit/test_rpc.py b/cinder/tests/unit/test_rpc.py index 923693b2473..39e1fdb487a 100644 --- a/cinder/tests/unit/test_rpc.py +++ b/cinder/tests/unit/test_rpc.py @@ -39,16 +39,16 @@ class RPCAPITestCase(test.TestCase): @mock.patch('cinder.objects.Service.get_minimum_rpc_version', return_value='1.2') - @mock.patch('cinder.objects.Service.get_minimum_obj_version', - return_value='1.4') + @mock.patch('cinder.objects.Service.get_minimum_obj_version') @mock.patch('cinder.rpc.get_client') def test_init(self, get_client, get_min_obj, get_min_rpc): def fake_get_client(target, version_cap, serializer): self.assertEqual(FakeAPI.TOPIC, target.topic) self.assertEqual(FakeAPI.RPC_API_VERSION, target.version) self.assertEqual('1.2', version_cap) - self.assertEqual('1.4', serializer.version_cap) + self.assertEqual(self.latest_ovo_version, serializer.version_cap) + get_min_obj.return_value = self.latest_ovo_version get_client.side_effect = fake_get_client FakeAPI() @@ -73,19 +73,20 @@ class RPCAPITestCase(test.TestCase): @mock.patch('cinder.objects.Service.get_minimum_obj_version') @mock.patch('cinder.rpc.get_client') @mock.patch('cinder.rpc.LAST_RPC_VERSIONS', {'cinder-scheduler': '1.4'}) - @mock.patch('cinder.rpc.LAST_OBJ_VERSIONS', {'cinder-scheduler': '1.3'}) def test_init_cached_caps(self, get_client, get_min_obj, get_min_rpc): def fake_get_client(target, version_cap, serializer): self.assertEqual(FakeAPI.TOPIC, target.topic) self.assertEqual(FakeAPI.RPC_API_VERSION, target.version) self.assertEqual('1.4', version_cap) - self.assertEqual('1.3', serializer.version_cap) + self.assertEqual(self.latest_ovo_version, serializer.version_cap) get_client.side_effect = fake_get_client - FakeAPI() + with mock.patch('cinder.rpc.LAST_OBJ_VERSIONS', + {'cinder-scheduler': self.latest_ovo_version}): + FakeAPI() - self.assertFalse(get_min_obj.called) - self.assertFalse(get_min_rpc.called) + get_min_obj.assert_not_called() + get_min_rpc.assert_not_called() @ddt.data([], ['noop'], ['noop', 'noop']) @mock.patch('oslo_messaging.JsonPayloadSerializer', wraps=True) diff --git a/cinder/tests/unit/test_service.py b/cinder/tests/unit/test_service.py index 7ad476dfe0f..fb131d1522c 100644 --- a/cinder/tests/unit/test_service.py +++ b/cinder/tests/unit/test_service.py @@ -380,19 +380,11 @@ class ServiceTestCase(test.TestCase): app.stop() - @mock.patch('cinder.objects.Service.get_minimum_obj_version', - return_value='1.6') - def test_start_rpc_and_init_host_no_cluster(self, is_upgrading_mock): - """Test that without cluster we don't create rpc service.""" - app = service.Service.create(host=self.host, - binary=constants.VOLUME_BINARY, - cluster=None, topic=self.topic) - self._check_rpc_servers_and_init_host(app, False, None) - @mock.patch('cinder.objects.Service.get_minimum_obj_version') def test_start_rpc_and_init_host_cluster(self, get_min_obj_mock): """Test that with cluster we create the rpc service.""" - get_min_obj_mock.return_value = '1.7' + # cluster was introduced in 1.7, so latest will be enough to test this + get_min_obj_mock.return_value = self.latest_ovo_version cluster = 'cluster@backend#pool' self.host = 'host@backend#pool' app = service.Service.create(host=self.host, diff --git a/cinder/tests/unit/volume/test_volume.py b/cinder/tests/unit/volume/test_volume.py index 7632706bd70..a498bc45fa5 100644 --- a/cinder/tests/unit/volume/test_volume.py +++ b/cinder/tests/unit/volume/test_volume.py @@ -125,15 +125,18 @@ class VolumeTestCase(base.BaseVolumeTestCase): @mock.patch('cinder.objects.service.Service.get_minimum_rpc_version') @mock.patch('cinder.objects.service.Service.get_minimum_obj_version') @mock.patch('cinder.rpc.LAST_RPC_VERSIONS', {'cinder-scheduler': '1.3'}) - @mock.patch('cinder.rpc.LAST_OBJ_VERSIONS', {'cinder-scheduler': '1.4'}) def test_reset(self, get_min_obj, get_min_rpc): - vol_mgr = vol_manager.VolumeManager() + old_version = objects.base.OBJ_VERSIONS.versions[-2] + + with mock.patch('cinder.rpc.LAST_OBJ_VERSIONS', + {'cinder-scheduler': old_version}): + vol_mgr = vol_manager.VolumeManager() scheduler_rpcapi = vol_mgr.scheduler_rpcapi self.assertEqual('1.3', scheduler_rpcapi.client.version_cap) - self.assertEqual('1.4', + self.assertEqual(old_version, scheduler_rpcapi.client.serializer._base.version_cap) - get_min_obj.return_value = objects.base.OBJ_VERSIONS.get_current() + get_min_obj.return_value = self.latest_ovo_version vol_mgr.reset() scheduler_rpcapi = vol_mgr.scheduler_rpcapi