Fix volume retype with migration as non-admin

As a non-admin user, when retyping a volume from type
A -> B, where both types are in different backends,
Cinder will complete the operation but the volumes will
 not be migrated.

This happens because the retype operation relies in
getting the extra_specs information to the related type,
but extra_specs is only avaiable in admin context.

Closes-bug: #1657806
Change-Id: Id9f39ddab3a3648b8721b711ecf78c18c8293451
This commit is contained in:
Erlon R. Cruz 2017-01-19 13:50:45 -02:00
parent 183dca0f91
commit 7aecdf919c
3 changed files with 24 additions and 13 deletions

View File

@ -58,6 +58,9 @@ class BaseVolumeTestCase(test.TestCase):
# assertions with the notification code, it's part of an
# elastic-recheck query so don't remove it or change it.
self.project_id = '7f265bd4-3a85-465e-a899-5dc4854a86d3'
self.user_context = context.RequestContext(user_id=fake.USER_ID,
project_id=self.project_id,
is_admin=False)
self.context.project_id = self.project_id
self.volume_params = {
'status': 'creating',

View File

@ -53,8 +53,8 @@ def create_snapshot(volume_id, size=1, metadata=None, ctxt=None,
metadata = metadata or {}
snap = objects.Snapshot(ctxt or context.get_admin_context())
snap.volume_size = size
snap.user_id = fake.USER_ID
snap.project_id = fake.PROJECT_ID
snap.user_id = kwargs.get('user_id', fake.USER_ID)
snap.project_id = kwargs.get('project_id', fake.PROJECT_ID)
snap.volume_id = volume_id
snap.status = "creating"
if metadata is not None:
@ -710,7 +710,10 @@ class VolumeMigrationTestCase(base.BaseVolumeTestCase):
volume.previous_status = 'available'
volume.save()
if snap:
create_snapshot(volume.id, size=volume.size)
create_snapshot(volume.id, size=volume.size,
user_id=self.user_context.user_id,
project_id=self.user_context.project_id,
ctxt=self.user_context)
if driver or diff_equal:
host_obj = {'host': CONF.host, 'capabilities': {}}
else:
@ -746,9 +749,11 @@ class VolumeMigrationTestCase(base.BaseVolumeTestCase):
with mock.patch.object(self.volume.driver, 'retype') as _retype,\
mock.patch.object(volume_types, 'volume_types_diff') as _diff,\
mock.patch.object(self.volume, 'migrate_volume') as _mig,\
mock.patch.object(db.sqlalchemy.api, 'volume_get') as mock_get:
mock_get.return_value = volume
mock.patch.object(db.sqlalchemy.api, 'volume_get') as _vget,\
mock.patch.object(context.RequestContext, 'elevated') as _ctx:
_vget.return_value = volume
_retype.return_value = driver
_ctx.return_value = self.context
returned_diff = {
'encryption': {},
'qos_specs': {},

View File

@ -2305,10 +2305,11 @@ class VolumeManager(manager.CleanableManager,
# We already got the new reservations
new_reservations = reservations
# If volume types have the same contents, no need to do anything
# If volume types have the same contents, no need to do anything.
# Use the admin contex to be able to access volume extra_specs
retyped = False
diff, all_equal = volume_types.volume_types_diff(
context, volume.volume_type_id, new_type_id)
context.elevated(), volume.volume_type_id, new_type_id)
if all_equal:
retyped = True
@ -2328,12 +2329,14 @@ class VolumeManager(manager.CleanableManager,
not diff.get('encryption') and
self._is_our_backend(host['host'], host.get('cluster_name'))):
try:
new_type = volume_types.get_volume_type(context, new_type_id)
ret = self.driver.retype(context,
volume,
new_type,
diff,
host)
new_type = volume_types.get_volume_type(context.elevated(),
new_type_id)
with volume.obj_as_admin():
ret = self.driver.retype(context,
volume,
new_type,
diff,
host)
# Check if the driver retype provided a model update or
# just a retype indication
if type(ret) == tuple: