Use versionedobjects in remotefs.py

Use versioned objects in remotefs.py, which is base classes
for all drivers with an interface of remote filesystem.

Update glusterfs, nfs, smbfs, quobyte, scality, vzstorage volume
drivers to use versionedobjects instead of dicts.

Please note that netapp_nfs driver wasn't fixed, just unit
tests were adapted to pass.

Change-Id: Iebd20544102672d7b7ca820c9e9005833ec2580e
Depends-On: I661ef85755e9c75aaedb4f157165d2514de3e9ec
This commit is contained in:
Dmitry Guryanov 2016-01-21 19:39:42 +03:00 committed by Evgeny Antyshev
parent ec51a682db
commit 369572f5b2
16 changed files with 872 additions and 844 deletions

View File

@ -34,8 +34,9 @@ from cinder import db
from cinder import exception from cinder import exception
from cinder.i18n import _ from cinder.i18n import _
from cinder.image import image_utils from cinder.image import image_utils
from cinder.objects import fields
from cinder import test from cinder import test
from cinder.tests.unit import fake_snapshot
from cinder.tests.unit import fake_volume
from cinder import utils from cinder import utils
from cinder.volume import driver as base_driver from cinder.volume import driver as base_driver
from cinder.volume.drivers import glusterfs from cinder.volume.drivers import glusterfs
@ -45,16 +46,6 @@ from cinder.volume.drivers import remotefs as remotefs_drv
CONF = cfg.CONF CONF = cfg.CONF
class DumbVolume(object):
fields = {}
def __setitem__(self, key, value):
self.fields[key] = value
def __getitem__(self, item):
return self.fields[item]
class FakeDb(object): class FakeDb(object):
msg = "Tests are broken: mock this out." msg = "Tests are broken: mock this out."
@ -66,6 +57,17 @@ class FakeDb(object):
return [] return []
class SideEffectList(object):
def __init__(self, obj, **kwargs):
self.obj = obj
self.attrs = kwargs
def __call__(self, *args, **kw):
for attr in self.attrs.keys():
setattr(self.obj, attr, self.attrs[attr].pop(0))
return self.obj
class GlusterFsDriverTestCase(test.TestCase): class GlusterFsDriverTestCase(test.TestCase):
"""Test case for GlusterFS driver.""" """Test case for GlusterFS driver."""
@ -75,12 +77,10 @@ class GlusterFsDriverTestCase(test.TestCase):
TEST_SIZE_IN_GB = 1 TEST_SIZE_IN_GB = 1
TEST_MNT_POINT = '/mnt/glusterfs' TEST_MNT_POINT = '/mnt/glusterfs'
TEST_MNT_POINT_BASE = '/mnt/test' TEST_MNT_POINT_BASE = '/mnt/test'
TEST_LOCAL_PATH = '/mnt/glusterfs/volume-123'
TEST_FILE_NAME = 'test.txt' TEST_FILE_NAME = 'test.txt'
TEST_SHARES_CONFIG_FILE = '/etc/cinder/test-shares.conf' TEST_SHARES_CONFIG_FILE = '/etc/cinder/test-shares.conf'
TEST_TMP_FILE = '/tmp/tempfile' TEST_TMP_FILE = '/tmp/tempfile'
VOLUME_UUID = 'abcdefab-cdef-abcd-efab-cdefabcdefab' VOLUME_UUID = 'abcdefab-cdef-abcd-efab-cdefabcdefab'
VOLUME_NAME = 'volume-%s' % VOLUME_UUID
SNAP_UUID = 'bacadaca-baca-daca-baca-dacadacadaca' SNAP_UUID = 'bacadaca-baca-daca-baca-dacadacadaca'
SNAP_UUID_2 = 'bebedede-bebe-dede-bebe-dedebebedede' SNAP_UUID_2 = 'bebedede-bebe-dede-bebe-dedebebedede'
@ -102,6 +102,7 @@ class GlusterFsDriverTestCase(test.TestCase):
db=FakeDb()) db=FakeDb())
self._driver.shares = {} self._driver.shares = {}
compute.API = mock.MagicMock() compute.API = mock.MagicMock()
self.context = context.get_admin_context()
def assertRaisesAndMessageMatches( def assertRaisesAndMessageMatches(
self, excClass, msg, callableObj, *args, **kwargs): self, excClass, msg, callableObj, *args, **kwargs):
@ -126,13 +127,12 @@ class GlusterFsDriverTestCase(test.TestCase):
self.TEST_MNT_POINT_BASE) self.TEST_MNT_POINT_BASE)
drv = self._driver drv = self._driver
volume = DumbVolume() volume = fake_volume.fake_volume_obj(
volume['id'] = self.VOLUME_UUID self.context,
volume['provider_location'] = self.TEST_EXPORT1 provider_location=self.TEST_EXPORT1)
volume['name'] = 'volume-123'
self.assertEqual( self.assertEqual(
'/mnt/test/ab03ab34eaca46a5fb81878f7e9b91fc/volume-123', '/mnt/test/ab03ab34eaca46a5fb81878f7e9b91fc/%s' % volume.name,
drv.local_path(volume)) drv.local_path(volume))
def test_mount_glusterfs(self): def test_mount_glusterfs(self):
@ -470,17 +470,20 @@ class GlusterFsDriverTestCase(test.TestCase):
drv._find_share, drv._find_share,
self.TEST_SIZE_IN_GB) self.TEST_SIZE_IN_GB)
def _simple_volume(self, id=None): def _simple_volume(self, id=None, **updates):
volume = DumbVolume()
volume['provider_location'] = self.TEST_EXPORT1
if id is None: if id is None:
volume['id'] = self.VOLUME_UUID id = self.VOLUME_UUID
else: if 'id' not in updates:
volume['id'] = id updates['id'] = self.VOLUME_UUID
# volume['name'] mirrors format from db/sqlalchemy/models.py if 'name' not in updates:
volume['name'] = 'volume-%s' % volume['id'] updates['name'] = 'volume-%s' % id
volume['size'] = 10 if 'status' not in updates:
volume['status'] = 'available' updates['status'] = 'available'
if 'provider_location' not in updates:
updates['provider_location'] = self.TEST_EXPORT1
if 'size' not in updates:
updates['size'] = 10
volume = fake_volume.fake_volume_obj(self.context, **updates)
return volume return volume
@ -497,7 +500,7 @@ class GlusterFsDriverTestCase(test.TestCase):
drv._do_create_volume(volume) drv._do_create_volume(volume)
volume_path = drv.local_path(volume) volume_path = drv.local_path(volume)
volume_size = volume['size'] volume_size = volume.size
mock_create_qcow2_file.assert_called_once_with(volume_path, mock_create_qcow2_file.assert_called_once_with(volume_path,
volume_size) volume_size)
mock_set_rw_permissions_for_all.\ mock_set_rw_permissions_for_all.\
@ -516,7 +519,7 @@ class GlusterFsDriverTestCase(test.TestCase):
drv._do_create_volume(volume) drv._do_create_volume(volume)
volume_path = drv.local_path(volume) volume_path = drv.local_path(volume)
volume_size = volume['size'] volume_size = volume.size
mock_fallocate.assert_called_once_with(volume_path, mock_fallocate.assert_called_once_with(volume_path,
volume_size) volume_size)
mock_set_rw_permissions_for_all.\ mock_set_rw_permissions_for_all.\
@ -539,7 +542,7 @@ class GlusterFsDriverTestCase(test.TestCase):
drv._do_create_volume(volume) drv._do_create_volume(volume)
volume_path = drv.local_path(volume) volume_path = drv.local_path(volume)
volume_size = volume['size'] volume_size = volume.size
mock_fallocate.assert_called_once_with(volume_path, mock_fallocate.assert_called_once_with(volume_path,
volume_size) volume_size)
mock_create_regular_file.assert_called_once_with(volume_path, mock_create_regular_file.assert_called_once_with(volume_path,
@ -556,9 +559,10 @@ class GlusterFsDriverTestCase(test.TestCase):
mock_do_create_volume,\ mock_do_create_volume,\
mock.patch.object(drv, '_ensure_shares_mounted') as \ mock.patch.object(drv, '_ensure_shares_mounted') as \
mock_ensure_shares_mounted: mock_ensure_shares_mounted:
volume = DumbVolume() volume = fake_volume.fake_volume_obj(self.context,
volume['size'] = self.TEST_SIZE_IN_GB size=self.TEST_SIZE_IN_GB,
volume['id'] = self.VOLUME_UUID id=self.VOLUME_UUID)
mock_find_share.return_value = self.TEST_EXPORT2
drv.create_volume(volume) drv.create_volume(volume)
self.assertTrue(mock_ensure_shares_mounted.called) self.assertTrue(mock_ensure_shares_mounted.called)
self.assertTrue(mock_do_create_volume.called) self.assertTrue(mock_do_create_volume.called)
@ -575,9 +579,9 @@ class GlusterFsDriverTestCase(test.TestCase):
mock_ensure_shares_mounted: mock_ensure_shares_mounted:
mock_find_share.return_value = self.TEST_EXPORT1 mock_find_share.return_value = self.TEST_EXPORT1
volume = DumbVolume() volume = fake_volume.fake_volume_obj(self.context,
volume['size'] = self.TEST_SIZE_IN_GB size=self.TEST_SIZE_IN_GB,
volume['id'] = self.VOLUME_UUID id=self.VOLUME_UUID)
result = drv.create_volume(volume) result = drv.create_volume(volume)
self.assertEqual(self.TEST_EXPORT1, result['provider_location']) self.assertEqual(self.TEST_EXPORT1, result['provider_location'])
self.assertTrue(mock_ensure_shares_mounted.called) self.assertTrue(mock_ensure_shares_mounted.called)
@ -610,7 +614,7 @@ class GlusterFsDriverTestCase(test.TestCase):
self._driver.delete_volume(volume) self._driver.delete_volume(volume)
mock_ensure_share_mounted.assert_called_once_with( mock_ensure_share_mounted.assert_called_once_with(
volume['provider_location']) volume.provider_location)
mock_local_volume_dir.assert_called_once_with(volume) mock_local_volume_dir.assert_called_once_with(volume)
mock_active_image_from_info.assert_called_once_with(volume) mock_active_image_from_info.assert_called_once_with(volume)
mock_execute.assert_called_once_with('rm', '-f', volume_path, mock_execute.assert_called_once_with('rm', '-f', volume_path,
@ -827,10 +831,12 @@ class GlusterFsDriverTestCase(test.TestCase):
with mock.patch.object(drv, '_execute') as mock_execute,\ with mock.patch.object(drv, '_execute') as mock_execute,\
mock.patch.object(drv, '_ensure_share_mounted') as \ mock.patch.object(drv, '_ensure_share_mounted') as \
mock_ensure_share_mounted: mock_ensure_share_mounted:
volume = DumbVolume()
volume['id'] = self.VOLUME_UUID volume = fake_volume.fake_volume_obj(
volume['name'] = 'volume-123' self.context,
volume['provider_location'] = self.TEST_EXPORT1 id=self.VOLUME_UUID,
display_name='volume-123',
provider_location=self.TEST_EXPORT1)
drv.delete_volume(volume) drv.delete_volume(volume)
@ -845,10 +851,10 @@ class GlusterFsDriverTestCase(test.TestCase):
with mock.patch.object(drv, '_execute') as mock_execute,\ with mock.patch.object(drv, '_execute') as mock_execute,\
mock.patch.object(drv, '_ensure_share_mounted') as \ mock.patch.object(drv, '_ensure_share_mounted') as \
mock_ensure_share_mounted: mock_ensure_share_mounted:
volume = DumbVolume() volume = fake_volume.fake_volume_obj(self.context,
volume['id'] = self.VOLUME_UUID id=self.VOLUME_UUID,
volume['name'] = 'volume-123' name='volume-123',
volume['provider_location'] = None provider_location=None)
drv.delete_volume(volume) drv.delete_volume(volume)
@ -868,10 +874,6 @@ class GlusterFsDriverTestCase(test.TestCase):
mock_read_file.return_value = '{"%(id)s": "volume-%(id)s"}' %\ mock_read_file.return_value = '{"%(id)s": "volume-%(id)s"}' %\
{'id': self.VOLUME_UUID} {'id': self.VOLUME_UUID}
volume = DumbVolume()
volume['id'] = self.VOLUME_UUID
volume['name'] = 'volume-%s' % self.VOLUME_UUID
info = drv._read_info_file(info_path) info = drv._read_info_file(info_path)
self.assertEqual('volume-%s' % self.VOLUME_UUID, self.assertEqual('volume-%s' % self.VOLUME_UUID,
@ -897,7 +899,7 @@ class GlusterFsDriverTestCase(test.TestCase):
mock_qemu_img_info,\ mock_qemu_img_info,\
mock.patch.object(image_utils, 'resize_image') as \ mock.patch.object(image_utils, 'resize_image') as \
mock_resize_image: mock_resize_image:
mock_get_active_image_from_info.return_value = volume['name'] mock_get_active_image_from_info.return_value = volume.name
mock_local_volume_dir.return_value = self.TEST_MNT_POINT mock_local_volume_dir.return_value = self.TEST_MNT_POINT
mock_qemu_img_info.return_value = img_info mock_qemu_img_info.return_value = img_info
@ -940,9 +942,6 @@ class GlusterFsDriverTestCase(test.TestCase):
def test_create_snapshot_online(self): def test_create_snapshot_online(self):
drv = self._driver drv = self._driver
volume = self._simple_volume()
volume['status'] = 'in-use'
hashed = drv._get_hash_str(self.TEST_EXPORT1) hashed = drv._get_hash_str(self.TEST_EXPORT1)
volume_file = 'volume-%s' % self.VOLUME_UUID volume_file = 'volume-%s' % self.VOLUME_UUID
volume_path = '%s/%s/%s' % (self.TEST_MNT_POINT_BASE, volume_path = '%s/%s/%s' % (self.TEST_MNT_POINT_BASE,
@ -951,13 +950,14 @@ class GlusterFsDriverTestCase(test.TestCase):
ctxt = context.RequestContext('fake_user', 'fake_project') ctxt = context.RequestContext('fake_user', 'fake_project')
snap_ref = {'name': 'test snap (online)', snap_ref = fake_snapshot.fake_snapshot_obj(
'volume_id': self.VOLUME_UUID, ctxt,
'volume': volume, display_name='test snap (online)',
'id': self.SNAP_UUID, volume_id=self.VOLUME_UUID,
'context': ctxt, id=self.SNAP_UUID,
'status': fields.SnapshotStatus.CREATING, status='creating',
'progress': 'asdf'} progress='asdf')
snap_ref.context = ctxt
snap_path = '%s.%s' % (volume_path, self.SNAP_UUID) snap_path = '%s.%s' % (volume_path, self.SNAP_UUID)
snap_file = '%s.%s' % (volume_file, self.SNAP_UUID) snap_file = '%s.%s' % (volume_file, self.SNAP_UUID)
@ -967,26 +967,13 @@ class GlusterFsDriverTestCase(test.TestCase):
mock.patch.object(db, 'snapshot_get') as mock_snapshot_get,\ mock.patch.object(db, 'snapshot_get') as mock_snapshot_get,\
mock.patch.object(drv, '_nova') as mock_nova,\ mock.patch.object(drv, '_nova') as mock_nova,\
mock.patch.object(time, 'sleep') as mock_sleep: mock.patch.object(time, 'sleep') as mock_sleep:
create_info = {'snapshot_id': snap_ref['id'], create_info = {'snapshot_id': snap_ref.id,
'type': 'qcow2', 'type': 'qcow2',
'new_file': snap_file} 'new_file': snap_file}
snap_ref_progress = snap_ref.copy() mock_snapshot_get.side_effect = SideEffectList(
snap_ref_progress['status'] = fields.SnapshotStatus.CREATING snap_ref,
progress = ['0%', '50%', '90%'])
snap_ref_progress_0p = snap_ref_progress.copy()
snap_ref_progress_0p['progress'] = '0%'
snap_ref_progress_50p = snap_ref_progress.copy()
snap_ref_progress_50p['progress'] = '50%'
snap_ref_progress_90p = snap_ref_progress.copy()
snap_ref_progress_90p['progress'] = '90%'
mock_snapshot_get.side_effect = [
snap_ref_progress_0p, snap_ref_progress_50p,
snap_ref_progress_90p
]
drv._create_snapshot_online(snap_ref, snap_file, snap_path) drv._create_snapshot_online(snap_ref, snap_file, snap_path)
mock_do_create_snapshot.\ mock_do_create_snapshot.\
@ -999,7 +986,7 @@ class GlusterFsDriverTestCase(test.TestCase):
drv = self._driver drv = self._driver
volume = self._simple_volume() volume = self._simple_volume()
volume['status'] = 'in-use' volume.status = 'in-use'
hashed = drv._get_hash_str(self.TEST_EXPORT1) hashed = drv._get_hash_str(self.TEST_EXPORT1)
volume_file = 'volume-%s' % self.VOLUME_UUID volume_file = 'volume-%s' % self.VOLUME_UUID
@ -1009,11 +996,12 @@ class GlusterFsDriverTestCase(test.TestCase):
ctxt = context.RequestContext('fake_user', 'fake_project') ctxt = context.RequestContext('fake_user', 'fake_project')
snap_ref = {'name': 'test snap (online)', snap_ref = fake_snapshot.fake_snapshot_obj(
'volume_id': self.VOLUME_UUID, ctxt,
'volume': volume, display_name='test snap (online)',
'id': self.SNAP_UUID, volume_id=self.VOLUME_UUID,
'context': ctxt} id=self.SNAP_UUID)
snap_ref.context = ctxt
snap_path = '%s.%s' % (volume_path, self.SNAP_UUID) snap_path = '%s.%s' % (volume_path, self.SNAP_UUID)
snap_file = '%s.%s' % (volume_file, self.SNAP_UUID) snap_file = '%s.%s' % (volume_file, self.SNAP_UUID)
@ -1022,23 +1010,11 @@ class GlusterFsDriverTestCase(test.TestCase):
mock.patch.object(db, 'snapshot_get') as mock_snapshot_get,\ mock.patch.object(db, 'snapshot_get') as mock_snapshot_get,\
mock.patch.object(drv, '_nova') as mock_nova,\ mock.patch.object(drv, '_nova') as mock_nova,\
mock.patch.object(time, 'sleep') as mock_sleep: mock.patch.object(time, 'sleep') as mock_sleep:
snap_ref_progress = snap_ref.copy()
snap_ref_progress['status'] = fields.SnapshotStatus.CREATING
snap_ref_progress_0p = snap_ref_progress.copy() mock_snapshot_get.side_effect = SideEffectList(
snap_ref_progress_0p['progress'] = '0%' snap_ref,
progress = ['0%', '50%', '99%'],
snap_ref_progress_50p = snap_ref_progress.copy() status = ["creating", "creating", "error"])
snap_ref_progress_50p['progress'] = '50%'
snap_ref_progress_99p = snap_ref_progress.copy()
snap_ref_progress_99p['progress'] = '99%'
snap_ref_progress_99p['status'] = fields.SnapshotStatus.ERROR
mock_snapshot_get.side_effect = [
snap_ref_progress_0p, snap_ref_progress_50p,
snap_ref_progress_99p
]
self.assertRaisesAndMessageMatches( self.assertRaisesAndMessageMatches(
exception.RemoteFSException, exception.RemoteFSException,
@ -1054,15 +1030,19 @@ class GlusterFsDriverTestCase(test.TestCase):
drv = self._driver drv = self._driver
volume = self._simple_volume() volume = self._simple_volume()
volume['status'] = 'in-use' volume.status = 'in-use'
ctxt = context.RequestContext('fake_user', 'fake_project') ctxt = context.RequestContext('fake_user', 'fake_project')
snap_ref = {'name': 'test snap to delete (online)', snap_ref = fake_snapshot.fake_snapshot_obj(
'volume_id': self.VOLUME_UUID, ctxt,
'volume': volume, display_name='test snap to delete (online)',
'id': self.SNAP_UUID, volume_id=self.VOLUME_UUID,
'context': ctxt} status="deleting",
id=self.SNAP_UUID)
snap_ref.context = ctxt
snap_ref.volume = volume
hashed = drv._get_hash_str(self.TEST_EXPORT1) hashed = drv._get_hash_str(self.TEST_EXPORT1)
volume_file = 'volume-%s' % self.VOLUME_UUID volume_file = 'volume-%s' % self.VOLUME_UUID
@ -1120,22 +1100,8 @@ class GlusterFsDriverTestCase(test.TestCase):
'volume_id': self.VOLUME_UUID 'volume_id': self.VOLUME_UUID
} }
snap_ref_progress = snap_ref.copy() mock_snapshot_get.side_effect = SideEffectList(
snap_ref_progress['status'] = 'deleting' snap_ref, progress = ['0%', '50%', '90%'])
snap_ref_progress_0p = snap_ref_progress.copy()
snap_ref_progress_0p['progress'] = '0%'
snap_ref_progress_50p = snap_ref_progress.copy()
snap_ref_progress_50p['progress'] = '50%'
snap_ref_progress_90p = snap_ref_progress.copy()
snap_ref_progress_90p['progress'] = '90%'
mock_snapshot_get.side_effect = [
snap_ref_progress_0p, snap_ref_progress_50p,
snap_ref_progress_90p
]
drv.delete_snapshot(snap_ref) drv.delete_snapshot(snap_ref)
@ -1156,15 +1122,18 @@ class GlusterFsDriverTestCase(test.TestCase):
drv = self._driver drv = self._driver
volume = self._simple_volume() volume = self._simple_volume()
volume['status'] = 'in-use' volume.status = 'in-use'
ctxt = context.RequestContext('fake_user', 'fake_project') ctxt = context.RequestContext('fake_user', 'fake_project')
snap_ref = {'name': 'test snap to delete (online)', snap_ref = fake_snapshot.fake_snapshot_obj(
'volume_id': self.VOLUME_UUID, ctxt,
'volume': volume, display_name='test snap to delete (online)',
'id': self.SNAP_UUID, volume_id=self.VOLUME_UUID,
'context': ctxt} status='deleting',
id=self.SNAP_UUID)
snap_ref.volume = volume
snap_ref.context = ctxt
hashed = drv._get_hash_str(self.TEST_EXPORT1) hashed = drv._get_hash_str(self.TEST_EXPORT1)
volume_file = 'volume-%s' % self.VOLUME_UUID volume_file = 'volume-%s' % self.VOLUME_UUID
@ -1225,21 +1194,8 @@ class GlusterFsDriverTestCase(test.TestCase):
'file_to_merge': snap_file, 'file_to_merge': snap_file,
'volume_id': self.VOLUME_UUID} 'volume_id': self.VOLUME_UUID}
snap_ref_progress = snap_ref.copy() mock_snapshot_get.side_effect = SideEffectList(
snap_ref_progress['status'] = 'deleting' snap_ref, progress = ['0%', '50%', '90%'])
snap_ref_progress_0p = snap_ref_progress.copy()
snap_ref_progress_0p['progress'] = '0%'
snap_ref_progress_50p = snap_ref_progress.copy()
snap_ref_progress_50p['progress'] = '50%'
snap_ref_progress_90p = snap_ref_progress.copy()
snap_ref_progress_90p['progress'] = '90%'
mock_snapshot_get.side_effect = [
snap_ref_progress_0p, snap_ref_progress_50p,
snap_ref_progress_90p]
drv.delete_snapshot(snap_ref) drv.delete_snapshot(snap_ref)
@ -1260,15 +1216,17 @@ class GlusterFsDriverTestCase(test.TestCase):
drv = self._driver drv = self._driver
volume = self._simple_volume() volume = self._simple_volume()
volume['status'] = 'in-use' volume.status = 'in-use'
ctxt = context.RequestContext('fake_user', 'fake_project') ctxt = context.RequestContext('fake_user', 'fake_project')
snap_ref = {'name': 'test snap to delete (online)', snap_ref = fake_snapshot.fake_snapshot_obj(
'volume_id': self.VOLUME_UUID, ctxt,
'volume': volume, display_name='test snap to delete (online)',
'id': self.SNAP_UUID, volume_id=self.VOLUME_UUID,
'context': ctxt} id=self.SNAP_UUID)
snap_ref.volume = volume
snap_ref.context = ctxt
hashed = drv._get_hash_str(self.TEST_EXPORT1) hashed = drv._get_hash_str(self.TEST_EXPORT1)
volume_file = 'volume-%s' % self.VOLUME_UUID volume_file = 'volume-%s' % self.VOLUME_UUID
@ -1320,23 +1278,10 @@ class GlusterFsDriverTestCase(test.TestCase):
return paths[args[0]] return paths[args[0]]
mock_qemu_img_info.side_effect = img_info_side_effect mock_qemu_img_info.side_effect = img_info_side_effect
mock_snapshot_get.side_effect = SideEffectList(
snap_ref_progress = snap_ref.copy() snap_ref,
snap_ref_progress['status'] = 'deleting' progress = ['0%', '50%', '99%'],
status = ['deleting', 'deleting', 'error'])
snap_ref_progress_0p = snap_ref_progress.copy()
snap_ref_progress_0p['progress'] = '0%'
snap_ref_progress_50p = snap_ref_progress.copy()
snap_ref_progress_50p['progress'] = '50%'
snap_ref_progress_90p = snap_ref_progress.copy()
snap_ref_progress_90p['status'] = 'error_deleting'
snap_ref_progress_90p['progress'] = '90%'
mock_snapshot_get.side_effect = [
snap_ref_progress_0p, snap_ref_progress_50p,
snap_ref_progress_90p]
self.assertRaisesAndMessageMatches(exception.RemoteFSException, self.assertRaisesAndMessageMatches(exception.RemoteFSException,
'Unable to delete snapshot', 'Unable to delete snapshot',
drv.delete_snapshot, drv.delete_snapshot,
@ -1355,9 +1300,9 @@ class GlusterFsDriverTestCase(test.TestCase):
self.TEST_MNT_POINT_BASE) self.TEST_MNT_POINT_BASE)
volume = self._simple_volume() volume = self._simple_volume()
vol_filename = volume['name'] vol_filename = volume.name
vol_filename_2 = volume['name'] + '.abcd' vol_filename_2 = volume.name + '.abcd'
vol_filename_3 = volume['name'] + '.efef' vol_filename_3 = volume.name + '.efef'
hashed = drv._get_hash_str(self.TEST_EXPORT1) hashed = drv._get_hash_str(self.TEST_EXPORT1)
vol_dir = '%s/%s' % (self.TEST_MNT_POINT_BASE, hashed) vol_dir = '%s/%s' % (self.TEST_MNT_POINT_BASE, hashed)
vol_path = '%s/%s' % (vol_dir, vol_filename) vol_path = '%s/%s' % (vol_dir, vol_filename)
@ -1432,25 +1377,29 @@ class GlusterFsDriverTestCase(test.TestCase):
vol_dir = os.path.join(self.TEST_MNT_POINT_BASE, vol_dir = os.path.join(self.TEST_MNT_POINT_BASE,
drv._get_hash_str(self.TEST_EXPORT1)) drv._get_hash_str(self.TEST_EXPORT1))
src_vol_path = os.path.join(vol_dir, src_volume['name']) src_vol_path = os.path.join(vol_dir, src_volume.name)
dest_vol_path = os.path.join(vol_dir, dest_volume['name']) dest_vol_path = os.path.join(vol_dir, dest_volume.name)
snapshot = {'volume_name': src_volume['name'],
'name': 'clone-snap-%s' % src_volume['id'], snapshot = fake_snapshot.fake_snapshot_obj(
'size': src_volume['size'], self.context,
'volume_size': src_volume['size'], volume_name=src_volume.name,
'volume_id': src_volume['id'], display_name='clone-snap-%s' % src_volume.id,
'id': 'tmp-snap-%s' % src_volume['id'], size=src_volume.size,
'volume': src_volume} volume_size=src_volume.size,
snap_file = dest_volume['name'] + '.' + snapshot['id'] volume_id=src_volume.id,
size = dest_volume['size'] id=self.SNAP_UUID)
snapshot.volume = src_volume
snap_file = dest_volume.name + '.' + snapshot.id
size = dest_volume.size
mock_read_info_file.return_value = {'active': snap_file, mock_read_info_file.return_value = {'active': snap_file,
snapshot['id']: snap_file} snapshot.id: snap_file}
qemu_img_output = """image: %s qemu_img_output = """image: %s
file format: raw file format: raw
virtual size: 1.0G (1073741824 bytes) virtual size: 1.0G (1073741824 bytes)
disk size: 173K disk size: 173K
backing file: %s backing file: %s
""" % (snap_file, src_volume['name']) """ % (snap_file, src_volume.name)
img_info = imageutils.QemuImgInfo(qemu_img_output) img_info = imageutils.QemuImgInfo(qemu_img_output)
mock_qemu_img_info.return_value = img_info mock_qemu_img_info.return_value = img_info
@ -1464,18 +1413,20 @@ class GlusterFsDriverTestCase(test.TestCase):
drv = self._driver drv = self._driver
src_volume = self._simple_volume() src_volume = self._simple_volume()
snap_ref = {'volume_name': src_volume['name'], snap_ref = fake_snapshot.fake_snapshot_obj(
'name': 'clone-snap-%s' % src_volume['id'], self.context,
'size': src_volume['size'], volume_name=src_volume.name,
'volume_size': src_volume['size'], display_name='clone-snap-%s' % src_volume.id,
'volume_id': src_volume['id'], size=src_volume.size,
'id': 'tmp-snap-%s' % src_volume['id'], volume_size=src_volume.size,
'volume': src_volume, volume_id=src_volume.id,
'status': 'available'} id=self.SNAP_UUID,
status='available')
snap_ref.volume = src_volume
new_volume = DumbVolume() new_volume = fake_volume.fake_volume_obj(self.context,
new_volume['id'] = self.VOLUME_UUID id=self.VOLUME_UUID,
new_volume['size'] = snap_ref['size'] size=snap_ref.volume.size)
with mock.patch.object(drv, '_ensure_shares_mounted') as \ with mock.patch.object(drv, '_ensure_shares_mounted') as \
mock_ensure_shares_mounted,\ mock_ensure_shares_mounted,\
@ -1492,7 +1443,7 @@ class GlusterFsDriverTestCase(test.TestCase):
mock_do_create_volume.assert_called_once_with(new_volume) mock_do_create_volume.assert_called_once_with(new_volume)
mock_copy_volume.assert_called_once_with(snap_ref, mock_copy_volume.assert_called_once_with(snap_ref,
new_volume, new_volume,
new_volume['size']) new_volume.size)
def test_initialize_connection(self): def test_initialize_connection(self):
drv = self._driver drv = self._driver
@ -1502,14 +1453,14 @@ class GlusterFsDriverTestCase(test.TestCase):
file format: raw file format: raw
virtual size: 1.0G (1073741824 bytes) virtual size: 1.0G (1073741824 bytes)
disk size: 173K disk size: 173K
""" % volume['name'] """ % volume.name
img_info = imageutils.QemuImgInfo(qemu_img_output) img_info = imageutils.QemuImgInfo(qemu_img_output)
with mock.patch.object(drv, 'get_active_image_from_info') as \ with mock.patch.object(drv, 'get_active_image_from_info') as \
mock_get_active_image_from_info,\ mock_get_active_image_from_info,\
mock.patch.object(image_utils, 'qemu_img_info') as \ mock.patch.object(image_utils, 'qemu_img_info') as \
mock_qemu_img_info: mock_qemu_img_info:
mock_get_active_image_from_info.return_value = volume['name'] mock_get_active_image_from_info.return_value = volume.name
mock_qemu_img_info.return_value = img_info mock_qemu_img_info.return_value = img_info
conn_info = drv.initialize_connection(volume, None) conn_info = drv.initialize_connection(volume, None)
@ -1539,7 +1490,7 @@ class GlusterFsDriverTestCase(test.TestCase):
mock_backup_volume: mock_backup_volume:
ctxt = context.RequestContext('fake_user', 'fake_project') ctxt = context.RequestContext('fake_user', 'fake_project')
volume = self._simple_volume() volume = self._simple_volume()
backup = {'volume_id': volume['id']} backup = {'volume_id': volume.id}
mock_volume_get.return_value = volume mock_volume_get.return_value = volume
mock_get_active_image_from_info.return_value = '/some/path' mock_get_active_image_from_info.return_value = '/some/path'
@ -1566,7 +1517,7 @@ class GlusterFsDriverTestCase(test.TestCase):
mock_backup_volume: mock_backup_volume:
ctxt = context.RequestContext('fake_user', 'fake_project') ctxt = context.RequestContext('fake_user', 'fake_project')
volume = self._simple_volume() volume = self._simple_volume()
backup = {'volume_id': volume['id']} backup = {'volume_id': volume.id}
mock_volume_get.return_value = volume mock_volume_get.return_value = volume
mock_get_active_image_from_info.return_value = '/some/file2' mock_get_active_image_from_info.return_value = '/some/file2'
@ -1586,7 +1537,7 @@ class GlusterFsDriverTestCase(test.TestCase):
mock_snapshot_get_all_for_volume: mock_snapshot_get_all_for_volume:
ctxt = context.RequestContext('fake_user', 'fake_project') ctxt = context.RequestContext('fake_user', 'fake_project')
volume = self._simple_volume() volume = self._simple_volume()
backup = {'volume_id': volume['id']} backup = {'volume_id': volume.id}
mock_snapshot_get_all_for_volume.return_value = [ mock_snapshot_get_all_for_volume.return_value = [
{'snap1': 'a'}, {'snap1': 'a'},
{'snap2': 'b'} {'snap2': 'b'}
@ -1606,7 +1557,7 @@ class GlusterFsDriverTestCase(test.TestCase):
mock_qemu_img_info: mock_qemu_img_info:
ctxt = context.RequestContext('fake_user', 'fake_project') ctxt = context.RequestContext('fake_user', 'fake_project')
volume = self._simple_volume() volume = self._simple_volume()
backup = {'volume_id': volume['id']} backup = {'volume_id': volume.id}
mock_volume_get.return_value = volume mock_volume_get.return_value = volume
mock_get_active_image_from_info.return_value = '/some/path/file2' mock_get_active_image_from_info.return_value = '/some/path/file2'
@ -1629,7 +1580,7 @@ class GlusterFsDriverTestCase(test.TestCase):
mock.patch.object(drv, '_qemu_img_info') as mock_qemu_img_info: mock.patch.object(drv, '_qemu_img_info') as mock_qemu_img_info:
ctxt = context.RequestContext('fake_user', 'fake_project') ctxt = context.RequestContext('fake_user', 'fake_project')
volume = self._simple_volume() volume = self._simple_volume()
backup = {'volume_id': volume['id']} backup = {'volume_id': volume.id}
mock_volume_get.return_value = volume mock_volume_get.return_value = volume
mock_get_active_image_from_info.return_value = '/some/path' mock_get_active_image_from_info.return_value = '/some/path'
@ -1651,7 +1602,7 @@ class GlusterFsDriverTestCase(test.TestCase):
drv = self._driver drv = self._driver
volume = self._simple_volume() volume = self._simple_volume()
volume_path = '%s/%s' % (self.TEST_MNT_POINT, volume['name']) volume_path = '%s/%s' % (self.TEST_MNT_POINT, volume.name)
image_meta = {'id': '10958016-e196-42e3-9e7f-5d8927ae3099'} image_meta = {'id': '10958016-e196-42e3-9e7f-5d8927ae3099'}
with mock.patch.object(drv, 'get_active_image_from_info') as \ with mock.patch.object(drv, 'get_active_image_from_info') as \
@ -1664,7 +1615,7 @@ class GlusterFsDriverTestCase(test.TestCase):
mock_upload_volume, \ mock_upload_volume, \
mock.patch.object(image_utils, 'create_temporary_file') as \ mock.patch.object(image_utils, 'create_temporary_file') as \
mock_create_temporary_file: mock_create_temporary_file:
mock_get_active_image_from_info.return_value = volume['name'] mock_get_active_image_from_info.return_value = volume.name
mock_local_volume_dir.return_value = self.TEST_MNT_POINT mock_local_volume_dir.return_value = self.TEST_MNT_POINT
@ -1674,7 +1625,7 @@ class GlusterFsDriverTestCase(test.TestCase):
file format: raw file format: raw
virtual size: 1.0G (1073741824 bytes) virtual size: 1.0G (1073741824 bytes)
disk size: 173K disk size: 173K
""" % volume['name'] """ % volume.name
img_info = imageutils.QemuImgInfo(qemu_img_output) img_info = imageutils.QemuImgInfo(qemu_img_output)
mock_qemu_img_info.return_value = img_info mock_qemu_img_info.return_value = img_info
@ -1694,7 +1645,7 @@ class GlusterFsDriverTestCase(test.TestCase):
drv = self._driver drv = self._driver
volume = self._simple_volume() volume = self._simple_volume()
volume_path = '%s/%s' % (self.TEST_MNT_POINT, volume['name']) volume_path = '%s/%s' % (self.TEST_MNT_POINT, volume.name)
image_meta = {'id': '10958016-e196-42e3-9e7f-5d8927ae3099'} image_meta = {'id': '10958016-e196-42e3-9e7f-5d8927ae3099'}
with mock.patch.object(drv, 'get_active_image_from_info') as \ with mock.patch.object(drv, 'get_active_image_from_info') as \
@ -1709,7 +1660,7 @@ class GlusterFsDriverTestCase(test.TestCase):
mock_upload_volume, \ mock_upload_volume, \
mock.patch.object(image_utils, 'create_temporary_file') as \ mock.patch.object(image_utils, 'create_temporary_file') as \
mock_create_temporary_file: mock_create_temporary_file:
mock_get_active_image_from_info.return_value = volume['name'] mock_get_active_image_from_info.return_value = volume.name
mock_local_volume_dir.return_value = self.TEST_MNT_POINT mock_local_volume_dir.return_value = self.TEST_MNT_POINT
@ -1719,7 +1670,7 @@ class GlusterFsDriverTestCase(test.TestCase):
file format: qcow2 file format: qcow2
virtual size: 1.0G (1073741824 bytes) virtual size: 1.0G (1073741824 bytes)
disk size: 173K disk size: 173K
""" % volume['name'] """ % volume.name
img_info = imageutils.QemuImgInfo(qemu_img_output) img_info = imageutils.QemuImgInfo(qemu_img_output)
mock_qemu_img_info.return_value = img_info mock_qemu_img_info.return_value = img_info
@ -1757,7 +1708,7 @@ class GlusterFsDriverTestCase(test.TestCase):
mock_upload_volume, \ mock_upload_volume, \
mock.patch.object(image_utils, 'create_temporary_file') as \ mock.patch.object(image_utils, 'create_temporary_file') as \
mock_create_temporary_file: mock_create_temporary_file:
mock_get_active_image_from_info.return_value = volume['name'] mock_get_active_image_from_info.return_value = volume.name
mock_local_volume_dir.return_value = self.TEST_MNT_POINT mock_local_volume_dir.return_value = self.TEST_MNT_POINT

View File

@ -23,9 +23,11 @@ import mock
from mox3 import mox as mox_lib from mox3 import mox as mox_lib
import six import six
from cinder import context
from cinder import exception from cinder import exception
from cinder.image import image_utils from cinder.image import image_utils
from cinder import test from cinder import test
from cinder.tests.unit import fake_volume
from cinder import utils as cinder_utils from cinder import utils as cinder_utils
from cinder.volume import configuration as conf from cinder.volume import configuration as conf
from cinder.volume.drivers.netapp import common from cinder.volume.drivers.netapp import common
@ -158,6 +160,7 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
self._driver.ssc_library = mock.Mock() self._driver.ssc_library = mock.Mock()
config = self._driver.configuration config = self._driver.configuration
config.netapp_vserver = FAKE_VSERVER config.netapp_vserver = FAKE_VSERVER
self.context = context.get_admin_context()
def test_create_snapshot(self): def test_create_snapshot(self):
"""Test snapshot can be created and deleted.""" """Test snapshot can be created and deleted."""
@ -519,7 +522,8 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
def test_clone_image_cloneableshare_raw(self): def test_clone_image_cloneableshare_raw(self):
drv = self._driver drv = self._driver
mox = self.mox mox = self.mox
volume = {'name': 'vol', 'size': '20'} volume = fake_volume.fake_volume_obj(self.context, size=20)
volume_name = 'volume-%s' % volume.id
mox.StubOutWithMock(utils, 'get_volume_extra_specs') mox.StubOutWithMock(utils, 'get_volume_extra_specs')
mox.StubOutWithMock(drv, '_find_image_in_cache') mox.StubOutWithMock(drv, '_find_image_in_cache')
mox.StubOutWithMock(drv, '_is_cloneable_share') mox.StubOutWithMock(drv, '_is_cloneable_share')
@ -541,11 +545,11 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
image_utils.qemu_img_info('/mnt/img-id', run_as_root=True).\ image_utils.qemu_img_info('/mnt/img-id', run_as_root=True).\
AndReturn(self.get_img_info('raw')) AndReturn(self.get_img_info('raw'))
drv._clone_backing_file_for_volume( drv._clone_backing_file_for_volume(
'img-id', 'vol', share='127.0.0.1:/share', volume_id=None) 'img-id', volume_name, share='127.0.0.1:/share', volume_id=None)
drv._get_mount_point_for_share(mox_lib.IgnoreArg()).AndReturn('/mnt') drv._get_mount_point_for_share(mox_lib.IgnoreArg()).AndReturn('/mnt')
drv._discover_file_till_timeout(mox_lib.IgnoreArg()).AndReturn(True) drv._discover_file_till_timeout(mox_lib.IgnoreArg()).AndReturn(True)
drv._set_rw_permissions('/mnt/vol') drv._set_rw_permissions('/mnt/%s' % volume_name)
drv._resize_image_file({'name': 'vol'}, mox_lib.IgnoreArg()) drv._resize_image_file({'name': volume_name}, mox_lib.IgnoreArg())
mox.ReplayAll() mox.ReplayAll()
drv.clone_image( drv.clone_image(
@ -559,7 +563,8 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
def test_clone_image_cloneableshare_notraw(self): def test_clone_image_cloneableshare_notraw(self):
drv = self._driver drv = self._driver
mox = self.mox mox = self.mox
volume = {'name': 'vol', 'size': '20'} volume = fake_volume.fake_volume_obj(self.context, size=20)
volume_name = 'volume-%s' % volume.id
mox.StubOutWithMock(utils, 'get_volume_extra_specs') mox.StubOutWithMock(utils, 'get_volume_extra_specs')
mox.StubOutWithMock(drv, '_find_image_in_cache') mox.StubOutWithMock(drv, '_find_image_in_cache')
mox.StubOutWithMock(drv, '_is_cloneable_share') mox.StubOutWithMock(drv, '_is_cloneable_share')
@ -572,6 +577,7 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
mox.StubOutWithMock(image_utils, 'convert_image') mox.StubOutWithMock(image_utils, 'convert_image')
mox.StubOutWithMock(drv, '_register_image_in_cache') mox.StubOutWithMock(drv, '_register_image_in_cache')
mox.StubOutWithMock(drv, '_is_share_clone_compatible') mox.StubOutWithMock(drv, '_is_share_clone_compatible')
mox.StubOutWithMock(drv, '_do_qos_for_volume')
utils.get_volume_extra_specs(mox_lib.IgnoreArg()) utils.get_volume_extra_specs(mox_lib.IgnoreArg())
drv._find_image_in_cache(mox_lib.IgnoreArg()).AndReturn([]) drv._find_image_in_cache(mox_lib.IgnoreArg()).AndReturn([])
@ -585,13 +591,15 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
image_utils.convert_image(mox_lib.IgnoreArg(), image_utils.convert_image(mox_lib.IgnoreArg(),
mox_lib.IgnoreArg(), mox_lib.IgnoreArg(),
'raw', run_as_root=True) 'raw', run_as_root=True)
image_utils.qemu_img_info('/mnt/vol', run_as_root=True).\ image_utils.qemu_img_info('/mnt/%s' % volume_name, run_as_root=True).\
AndReturn(self.get_img_info('raw')) AndReturn(self.get_img_info('raw'))
drv._register_image_in_cache(mox_lib.IgnoreArg(), mox_lib.IgnoreArg()) drv._register_image_in_cache(mox_lib.IgnoreArg(), mox_lib.IgnoreArg())
drv._do_qos_for_volume(mox_lib.IgnoreArg(), mox_lib.IgnoreArg())
drv._get_mount_point_for_share('127.0.0.1:/share').AndReturn('/mnt') drv._get_mount_point_for_share('127.0.0.1:/share').AndReturn('/mnt')
drv._discover_file_till_timeout(mox_lib.IgnoreArg()).AndReturn(True) drv._discover_file_till_timeout(mox_lib.IgnoreArg()).AndReturn(True)
drv._set_rw_permissions('/mnt/vol') drv._set_rw_permissions('/mnt/%s' % volume_name)
drv._resize_image_file({'name': 'vol'}, mox_lib.IgnoreArg()) drv._resize_image_file({'name': volume_name}, mox_lib.IgnoreArg())
mox.ReplayAll() mox.ReplayAll()
drv.clone_image( drv.clone_image(
@ -605,7 +613,8 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
def test_clone_image_file_not_discovered(self): def test_clone_image_file_not_discovered(self):
drv = self._driver drv = self._driver
mox = self.mox mox = self.mox
volume = {'name': 'vol', 'size': '20'} volume = fake_volume.fake_volume_obj(self.context, size=20)
volume_name = 'volume-%s' % volume.id
mox.StubOutWithMock(utils, 'get_volume_extra_specs') mox.StubOutWithMock(utils, 'get_volume_extra_specs')
mox.StubOutWithMock(drv, '_find_image_in_cache') mox.StubOutWithMock(drv, '_find_image_in_cache')
mox.StubOutWithMock(drv, '_is_cloneable_share') mox.StubOutWithMock(drv, '_is_cloneable_share')
@ -631,12 +640,12 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
image_utils.convert_image(mox_lib.IgnoreArg(), image_utils.convert_image(mox_lib.IgnoreArg(),
mox_lib.IgnoreArg(), mox_lib.IgnoreArg(),
'raw', run_as_root=True) 'raw', run_as_root=True)
image_utils.qemu_img_info('/mnt/vol', run_as_root=True).\ image_utils.qemu_img_info('/mnt/%s' % volume_name, run_as_root=True).\
AndReturn(self.get_img_info('raw')) AndReturn(self.get_img_info('raw'))
drv._register_image_in_cache(mox_lib.IgnoreArg(), drv._register_image_in_cache(mox_lib.IgnoreArg(),
mox_lib.IgnoreArg()) mox_lib.IgnoreArg())
drv._do_qos_for_volume(mox_lib.IgnoreArg(), mox_lib.IgnoreArg()) drv._do_qos_for_volume(mox_lib.IgnoreArg(), mox_lib.IgnoreArg())
drv.local_path(mox_lib.IgnoreArg()).AndReturn('/mnt/vol') drv.local_path(mox_lib.IgnoreArg()).AndReturn('/mnt/%s' % volume_name)
drv._discover_file_till_timeout(mox_lib.IgnoreArg()).AndReturn(False) drv._discover_file_till_timeout(mox_lib.IgnoreArg()).AndReturn(False)
mox.ReplayAll() mox.ReplayAll()
@ -1180,6 +1189,8 @@ class NetAppCmodeNfsDriverOnlyTestCase(test.TestCase):
'spec': None, 'spec': None,
} }
self.context = context.get_admin_context()
@mock.patch.object(utils, 'LOG', mock.Mock()) @mock.patch.object(utils, 'LOG', mock.Mock())
def test_create_volume(self): def test_create_volume(self):
drv = self._driver drv = self._driver
@ -1234,47 +1245,48 @@ class NetAppCmodeNfsDriverOnlyTestCase(test.TestCase):
def test_copy_img_to_vol_copyoffload_success(self): def test_copy_img_to_vol_copyoffload_success(self):
drv = self._driver drv = self._driver
context = object() volume = fake_volume.fake_volume_obj(self.context)
volume = {'id': 'vol_id', 'name': 'name'}
image_service = object() image_service = object()
image_id = 'image_id' image_id = 'image_id'
drv.zapi_client.get_ontapi_version = mock.Mock(return_value=(1, 20)) drv.zapi_client.get_ontapi_version = mock.Mock(return_value=(1, 20))
drv._copy_from_img_service = mock.Mock() drv._copy_from_img_service = mock.Mock()
drv._get_provider_location = mock.Mock(return_value='share') drv._get_provider_location = mock.Mock(return_value='share')
drv._get_vol_for_share = mock.Mock(return_value='vol') drv._get_vol_for_share = mock.Mock(return_value=volume.id)
drv._update_stale_vols = mock.Mock() drv._update_stale_vols = mock.Mock()
drv.copy_image_to_volume(context, volume, image_service, image_id) drv.copy_image_to_volume(self.context, volume, image_service, image_id)
drv._copy_from_img_service.assert_called_once_with(context, volume, drv._copy_from_img_service.assert_called_once_with(self.context,
volume,
image_service, image_service,
image_id) image_id)
drv._update_stale_vols.assert_called_once_with('vol') drv._update_stale_vols.assert_called_once_with(volume.id)
def test_copy_img_to_vol_copyoffload_failure(self): def test_copy_img_to_vol_copyoffload_failure(self):
drv = self._driver drv = self._driver
context = object() volume = fake_volume.fake_volume_obj(self.context)
volume = {'id': 'vol_id', 'name': 'name'}
image_service = object() image_service = object()
image_id = 'image_id' image_id = 'image_id'
drv.zapi_client.get_ontapi_version = mock.Mock(return_value=(1, 20)) drv.zapi_client.get_ontapi_version = mock.Mock(return_value=(1, 20))
drv._copy_from_img_service = mock.Mock(side_effect=Exception()) drv._copy_from_img_service = mock.Mock(side_effect=Exception())
nfs_base.NetAppNfsDriver.copy_image_to_volume = mock.Mock() nfs_base.NetAppNfsDriver.copy_image_to_volume = mock.Mock()
drv._get_provider_location = mock.Mock(return_value='share') drv._get_provider_location = mock.Mock(return_value='share')
drv._get_vol_for_share = mock.Mock(return_value='vol') drv._get_vol_for_share = mock.Mock(return_value=volume.id)
drv._update_stale_vols = mock.Mock() drv._update_stale_vols = mock.Mock()
drv.copy_image_to_volume(context, volume, image_service, image_id) drv.copy_image_to_volume(self.context, volume, image_service, image_id)
drv._copy_from_img_service.assert_called_once_with(context, volume, drv._copy_from_img_service.assert_called_once_with(self.context,
volume,
image_service, image_service,
image_id) image_id)
nfs_base.NetAppNfsDriver.copy_image_to_volume. \ nfs_base.NetAppNfsDriver.copy_image_to_volume. \
assert_called_once_with(context, volume, image_service, image_id) assert_called_once_with(self.context, volume,
drv._update_stale_vols.assert_called_once_with('vol') image_service, image_id)
drv._update_stale_vols.assert_called_once_with(volume.id)
def test_copy_img_to_vol_copyoffload_nonexistent_binary_path(self): def test_copy_img_to_vol_copyoffload_nonexistent_binary_path(self):
drv = self._driver drv = self._driver
context = object() volume = fake_volume.fake_volume_obj(self.context)
volume = {'id': 'vol_id', 'name': 'name'}
image_service = mock.Mock() image_service = mock.Mock()
image_service.get_location.return_value = (mock.Mock(), mock.Mock()) image_service.get_location.return_value = (mock.Mock(), mock.Mock())
image_service.show.return_value = {'size': 0} image_service.show.return_value = {'size': 0}
@ -1296,15 +1308,14 @@ class NetAppCmodeNfsDriverOnlyTestCase(test.TestCase):
# Verify the original error is propagated # Verify the original error is propagated
self.assertRaises(OSError, drv._copy_from_img_service, self.assertRaises(OSError, drv._copy_from_img_service,
context, volume, image_service, image_id) self.context, volume, image_service, image_id)
@mock.patch.object(image_utils, 'qemu_img_info') @mock.patch.object(image_utils, 'qemu_img_info')
def test_img_service_raw_copyoffload_workflow_success(self, def test_img_service_raw_copyoffload_workflow_success(self,
mock_qemu_img_info): mock_qemu_img_info):
drv = self._driver drv = self._driver
volume = {'id': 'vol_id', 'name': 'name', 'size': 1} volume = fake_volume.fake_volume_obj(self.context, size=1)
image_id = 'image_id' image_id = 'image_id'
context = object()
image_service = mock.Mock() image_service = mock.Mock()
image_service.get_location.return_value = ('nfs://ip1/openstack/img', image_service.get_location.return_value = ('nfs://ip1/openstack/img',
None) None)
@ -1329,9 +1340,10 @@ class NetAppCmodeNfsDriverOnlyTestCase(test.TestCase):
drv._clone_file_dst_exists = mock.Mock() drv._clone_file_dst_exists = mock.Mock()
drv._post_clone_image = mock.Mock() drv._post_clone_image = mock.Mock()
drv._copy_from_img_service(context, volume, image_service, image_id) drv._copy_from_img_service(self.context, volume,
image_service, image_id)
drv._get_ip_verify_on_cluster.assert_any_call('ip1') drv._get_ip_verify_on_cluster.assert_any_call('ip1')
drv._get_export_path.assert_called_with('vol_id') drv._get_export_path.assert_called_with(volume.id)
drv._check_share_can_hold_size.assert_called_with('share', 1) drv._check_share_can_hold_size.assert_called_with('share', 1)
assert drv._execute.call_count == 1 assert drv._execute.call_count == 1
@ -1344,9 +1356,8 @@ class NetAppCmodeNfsDriverOnlyTestCase(test.TestCase):
mock_qemu_img_info, mock_qemu_img_info,
mock_cvrt_image): mock_cvrt_image):
drv = self._driver drv = self._driver
volume = {'id': 'vol_id', 'name': 'name', 'size': 1} volume = fake_volume.fake_volume_obj(self.context, size=1)
image_id = 'image_id' image_id = 'image_id'
context = object()
image_service = mock.Mock() image_service = mock.Mock()
image_service.get_location.return_value = ('nfs://ip1/openstack/img', image_service.get_location.return_value = ('nfs://ip1/openstack/img',
None) None)
@ -1371,9 +1382,10 @@ class NetAppCmodeNfsDriverOnlyTestCase(test.TestCase):
drv._clone_file_dst_exists = mock.Mock() drv._clone_file_dst_exists = mock.Mock()
drv._post_clone_image = mock.Mock() drv._post_clone_image = mock.Mock()
drv._copy_from_img_service(context, volume, image_service, image_id) drv._copy_from_img_service(self.context, volume,
image_service, image_id)
drv._get_ip_verify_on_cluster.assert_any_call('ip1') drv._get_ip_verify_on_cluster.assert_any_call('ip1')
drv._get_export_path.assert_called_with('vol_id') drv._get_export_path.assert_called_with(volume.id)
drv._check_share_can_hold_size.assert_called_with('share', 1) drv._check_share_can_hold_size.assert_called_with('share', 1)
assert mock_cvrt_image.call_count == 1 assert mock_cvrt_image.call_count == 1
assert drv._execute.call_count == 1 assert drv._execute.call_count == 1
@ -1393,6 +1405,7 @@ class NetApp7modeNfsDriverTestCase(NetAppCmodeNfsDriverTestCase):
self._driver = netapp_nfs_7mode.NetApp7modeNfsDriver( self._driver = netapp_nfs_7mode.NetApp7modeNfsDriver(
configuration=create_configuration()) configuration=create_configuration())
self._driver.zapi_client = mock.Mock() self._driver.zapi_client = mock.Mock()
self.context = context.get_admin_context()
def _prepare_delete_snapshot_mock(self, snapshot_exists): def _prepare_delete_snapshot_mock(self, snapshot_exists):
drv = self._driver drv = self._driver

View File

@ -21,25 +21,16 @@ import os
import mock import mock
from oslo_utils import units from oslo_utils import units
from cinder import context
from cinder import exception from cinder import exception
from cinder.image import image_utils from cinder.image import image_utils
from cinder import test from cinder import test
from cinder.tests.unit import fake_volume
from cinder.volume import configuration as conf from cinder.volume import configuration as conf
from cinder.volume.drivers import nfs from cinder.volume.drivers import nfs
from cinder.volume.drivers import remotefs from cinder.volume.drivers import remotefs
class DumbVolume(object):
# TODO(eharney): replace this with an autospecced mock class
fields = {}
def __setitem__(self, key, value):
self.fields[key] = value
def __getitem__(self, item):
return self.fields[item]
class RemoteFsDriverTestCase(test.TestCase): class RemoteFsDriverTestCase(test.TestCase):
TEST_FILE_NAME = 'test.txt' TEST_FILE_NAME = 'test.txt'
TEST_EXPORT = 'nas-host1:/export' TEST_EXPORT = 'nas-host1:/export'
@ -346,18 +337,19 @@ class NfsDriverTestCase(test.TestCase):
mock_exc = mock.patch.object(self._driver, '_execute') mock_exc = mock.patch.object(self._driver, '_execute')
self._execute = mock_exc.start() self._execute = mock_exc.start()
self.addCleanup(mock_exc.stop) self.addCleanup(mock_exc.stop)
self.context = context.get_admin_context()
def test_local_path(self): def test_local_path(self):
"""local_path common use case.""" """local_path common use case."""
self.configuration.nfs_mount_point_base = self.TEST_MNT_POINT_BASE self.configuration.nfs_mount_point_base = self.TEST_MNT_POINT_BASE
drv = self._driver drv = self._driver
volume = DumbVolume() volume = fake_volume.fake_volume_obj(
volume['provider_location'] = self.TEST_NFS_EXPORT1 self.context,
volume['name'] = 'volume-123' provider_location=self.TEST_NFS_EXPORT1)
self.assertEqual( self.assertEqual(
'/mnt/test/2f4f60214cf43c595666dd815f0360a4/volume-123', '/mnt/test/2f4f60214cf43c595666dd815f0360a4/%s' % volume.name,
drv.local_path(volume)) drv.local_path(volume))
@mock.patch.object(image_utils, 'qemu_img_info') @mock.patch.object(image_utils, 'qemu_img_info')
@ -366,8 +358,9 @@ class NfsDriverTestCase(test.TestCase):
def test_copy_image_to_volume(self, mock_fetch, mock_resize, mock_qemu): def test_copy_image_to_volume(self, mock_fetch, mock_resize, mock_qemu):
"""resize_image common case usage.""" """resize_image common case usage."""
drv = self._driver drv = self._driver
TEST_IMG_SOURCE = 'foo.img' volume = fake_volume.fake_volume_obj(self.context,
volume = {'size': self.TEST_SIZE_IN_GB, 'name': TEST_IMG_SOURCE} size=self.TEST_SIZE_IN_GB)
TEST_IMG_SOURCE = 'volume-%s' % volume.id
with mock.patch.object(drv, 'local_path', with mock.patch.object(drv, 'local_path',
return_value=TEST_IMG_SOURCE): return_value=TEST_IMG_SOURCE):
@ -581,12 +574,10 @@ class NfsDriverTestCase(test.TestCase):
self.assertEqual(2, mock_get_capacity_info.call_count) self.assertEqual(2, mock_get_capacity_info.call_count)
def _simple_volume(self): def _simple_volume(self):
volume = DumbVolume() return fake_volume.fake_volume_obj(self.context,
volume['provider_location'] = '127.0.0.1:/mnt' display_name='volume_name',
volume['name'] = 'volume_name' provider_location='127.0.0.1:/mnt',
volume['size'] = 10 size=10)
return volume
def test_create_sparsed_volume(self): def test_create_sparsed_volume(self):
drv = self._driver drv = self._driver
@ -626,13 +617,14 @@ class NfsDriverTestCase(test.TestCase):
"""create_volume ensures shares provided in config are mounted.""" """create_volume ensures shares provided in config are mounted."""
drv = self._driver drv = self._driver
drv._find_share = mock.Mock() drv._find_share = mock.Mock()
drv._find_share.return_value = self.TEST_NFS_EXPORT1
drv._do_create_volume = mock.Mock() drv._do_create_volume = mock.Mock()
with mock.patch.object( with mock.patch.object(
drv, '_ensure_share_mounted') as mock_ensure_share: drv, '_ensure_share_mounted') as mock_ensure_share:
drv._ensure_share_mounted() drv._ensure_share_mounted()
volume = DumbVolume() volume = fake_volume.fake_volume_obj(self.context,
volume['size'] = self.TEST_SIZE_IN_GB size=self.TEST_SIZE_IN_GB)
drv.create_volume(volume) drv.create_volume(volume)
mock_ensure_share.assert_called_once_with() mock_ensure_share.assert_called_once_with()
@ -646,8 +638,8 @@ class NfsDriverTestCase(test.TestCase):
with mock.patch.object(drv, '_find_share') as mock_find_share: with mock.patch.object(drv, '_find_share') as mock_find_share:
mock_find_share.return_value = self.TEST_NFS_EXPORT1 mock_find_share.return_value = self.TEST_NFS_EXPORT1
volume = DumbVolume() volume = fake_volume.fake_volume_obj(self.context,
volume['size'] = self.TEST_SIZE_IN_GB size=self.TEST_SIZE_IN_GB)
result = drv.create_volume(volume) result = drv.create_volume(volume)
self.assertEqual(self.TEST_NFS_EXPORT1, self.assertEqual(self.TEST_NFS_EXPORT1,
result['provider_location']) result['provider_location'])
@ -658,9 +650,10 @@ class NfsDriverTestCase(test.TestCase):
drv = self._driver drv = self._driver
drv._ensure_share_mounted = mock.Mock() drv._ensure_share_mounted = mock.Mock()
volume = DumbVolume() volume = fake_volume.fake_volume_obj(
volume['name'] = 'volume-123' self.context,
volume['provider_location'] = self.TEST_NFS_EXPORT1 display_name='volume-123',
provider_location=self.TEST_NFS_EXPORT1)
with mock.patch.object(drv, 'local_path') as mock_local_path: with mock.patch.object(drv, 'local_path') as mock_local_path:
mock_local_path.return_value = self.TEST_LOCAL_PATH mock_local_path.return_value = self.TEST_LOCAL_PATH
@ -673,9 +666,10 @@ class NfsDriverTestCase(test.TestCase):
def test_delete_should_ensure_share_mounted(self): def test_delete_should_ensure_share_mounted(self):
"""delete_volume should ensure that corresponding share is mounted.""" """delete_volume should ensure that corresponding share is mounted."""
drv = self._driver drv = self._driver
volume = DumbVolume() volume = fake_volume.fake_volume_obj(
volume['name'] = 'volume-123' self.context,
volume['provider_location'] = self.TEST_NFS_EXPORT1 display_name='volume-123',
provider_location=self.TEST_NFS_EXPORT1)
with mock.patch.object( with mock.patch.object(
drv, '_ensure_share_mounted') as mock_ensure_share: drv, '_ensure_share_mounted') as mock_ensure_share:
@ -685,9 +679,9 @@ class NfsDriverTestCase(test.TestCase):
def test_delete_should_not_delete_if_provider_location_not_provided(self): def test_delete_should_not_delete_if_provider_location_not_provided(self):
"""delete_volume shouldn't delete if provider_location missed.""" """delete_volume shouldn't delete if provider_location missed."""
drv = self._driver drv = self._driver
volume = DumbVolume() volume = fake_volume.fake_volume_obj(self.context,
volume['name'] = 'volume-123' name='volume-123',
volume['provider_location'] = None provider_location=None)
with mock.patch.object(drv, '_ensure_share_mounted'): with mock.patch.object(drv, '_ensure_share_mounted'):
drv.delete_volume(volume) drv.delete_volume(volume)
@ -846,8 +840,11 @@ class NfsDriverTestCase(test.TestCase):
def test_extend_volume(self): def test_extend_volume(self):
"""Extend a volume by 1.""" """Extend a volume by 1."""
drv = self._driver drv = self._driver
volume = {'id': '80ee16b6-75d2-4d54-9539-ffc1b4b0fb10', 'size': 1, volume = fake_volume.fake_volume_obj(
'provider_location': 'nfs_share'} self.context,
id='80ee16b6-75d2-4d54-9539-ffc1b4b0fb10',
size=1,
provider_location='nfs_share')
path = 'path' path = 'path'
newSize = volume['size'] + 1 newSize = volume['size'] + 1
@ -865,8 +862,11 @@ class NfsDriverTestCase(test.TestCase):
def test_extend_volume_failure(self): def test_extend_volume_failure(self):
"""Error during extend operation.""" """Error during extend operation."""
drv = self._driver drv = self._driver
volume = {'id': '80ee16b6-75d2-4d54-9539-ffc1b4b0fb10', 'size': 1, volume = fake_volume.fake_volume_obj(
'provider_location': 'nfs_share'} self.context,
id='80ee16b6-75d2-4d54-9539-ffc1b4b0fb10',
size=1,
provider_location='nfs_share')
with mock.patch.object(image_utils, 'resize_image'): with mock.patch.object(image_utils, 'resize_image'):
with mock.patch.object(drv, 'local_path', return_value='path'): with mock.patch.object(drv, 'local_path', return_value='path'):
@ -880,8 +880,11 @@ class NfsDriverTestCase(test.TestCase):
def test_extend_volume_insufficient_space(self): def test_extend_volume_insufficient_space(self):
"""Insufficient space on nfs_share during extend operation.""" """Insufficient space on nfs_share during extend operation."""
drv = self._driver drv = self._driver
volume = {'id': '80ee16b6-75d2-4d54-9539-ffc1b4b0fb10', 'size': 1, volume = fake_volume.fake_volume_obj(
'provider_location': 'nfs_share'} self.context,
id='80ee16b6-75d2-4d54-9539-ffc1b4b0fb10',
size=1,
provider_location='nfs_share')
with mock.patch.object(image_utils, 'resize_image'): with mock.patch.object(image_utils, 'resize_image'):
with mock.patch.object(drv, 'local_path', return_value='path'): with mock.patch.object(drv, 'local_path', return_value='path'):
@ -1125,8 +1128,8 @@ class NfsDriverDoSetupTestCase(test.TestCase):
def _test_update_migrated_volume(self, volume_status, rename_volume, def _test_update_migrated_volume(self, volume_status, rename_volume,
rename_exception=False): rename_exception=False):
drv = nfs.NfsDriver(configuration=self.configuration) drv = nfs.NfsDriver(configuration=self.configuration)
fake_volume_id = 'vol1' fake_volume_id = 'f51b5730-13b7-11e6-a238-fa163e67a298'
fake_new_volume_id = 'vol2' fake_new_volume_id = '12341234-13b7-11e6-a238-fa163e67a298'
fake_provider_source = 'fake_provider_source' fake_provider_source = 'fake_provider_source'
fake_provider = 'fake_provider' fake_provider = 'fake_provider'
base_dir = '/dir_base/' base_dir = '/dir_base/'
@ -1135,27 +1138,34 @@ class NfsDriverDoSetupTestCase(test.TestCase):
current_name = volume_name_template % fake_new_volume_id current_name = volume_name_template % fake_new_volume_id
original_volume_path = base_dir + original_volume_name original_volume_path = base_dir + original_volume_name
current_path = base_dir + current_name current_path = base_dir + current_name
fake_volume = {'size': 1, 'id': fake_volume_id, volume = fake_volume.fake_volume_obj(
'provider_location': fake_provider_source, self.context,
'_name_id': None} id=fake_volume_id,
fake_new_volume = {'size': 1, 'id': fake_new_volume_id, size=1,
'provider_location': fake_provider, provider_location=fake_provider_source,
'_name_id': None} _name_id=None)
new_volume = fake_volume.fake_volume_obj(
self.context,
id=fake_new_volume_id,
size=1,
provider_location=fake_provider,
_name_id=None)
with mock.patch.object(drv, 'local_path') as local_path: with mock.patch.object(drv, 'local_path') as local_path:
local_path.return_value = base_dir + current_name local_path.return_value = base_dir + current_name
if volume_status == 'in-use': if volume_status == 'in-use':
update = drv.update_migrated_volume(self.context, update = drv.update_migrated_volume(self.context,
fake_volume, volume,
fake_new_volume, new_volume,
volume_status) volume_status)
self.assertEqual({'_name_id': fake_new_volume_id, self.assertEqual({'_name_id': fake_new_volume_id,
'provider_location': fake_provider}, update) 'provider_location': fake_provider}, update)
elif rename_exception: elif rename_exception:
rename_volume.side_effect = OSError rename_volume.side_effect = OSError
update = drv.update_migrated_volume(self.context, update = drv.update_migrated_volume(self.context,
fake_volume, volume,
fake_new_volume, new_volume,
volume_status) volume_status)
rename_volume.assert_called_once_with(current_path, rename_volume.assert_called_once_with(current_path,
original_volume_path) original_volume_path)
@ -1163,8 +1173,8 @@ class NfsDriverDoSetupTestCase(test.TestCase):
'provider_location': fake_provider}, update) 'provider_location': fake_provider}, update)
else: else:
update = drv.update_migrated_volume(self.context, update = drv.update_migrated_volume(self.context,
fake_volume, volume,
fake_new_volume, new_volume,
volume_status) volume_status)
rename_volume.assert_called_once_with(current_path, rename_volume.assert_called_once_with(current_path,
original_volume_path) original_volume_path)
@ -1175,7 +1185,7 @@ class NfsDriverDoSetupTestCase(test.TestCase):
"Ensure that driver.retype() is there.""" "Ensure that driver.retype() is there."""
drv = nfs.NfsDriver(configuration=self.configuration) drv = nfs.NfsDriver(configuration=self.configuration)
v1 = DumbVolume() v1 = fake_volume.fake_volume_obj(self.context)
ret = drv.retype(self.context, ret = drv.retype(self.context,
v1, v1,

View File

@ -30,6 +30,8 @@ from cinder import context
from cinder import exception from cinder import exception
from cinder.image import image_utils from cinder.image import image_utils
from cinder import test from cinder import test
from cinder.tests.unit import fake_snapshot
from cinder.tests.unit import fake_volume
from cinder.volume import configuration as conf from cinder.volume import configuration as conf
from cinder.volume.drivers import quobyte from cinder.volume.drivers import quobyte
@ -37,16 +39,6 @@ from cinder.volume.drivers import quobyte
CONF = cfg.CONF CONF = cfg.CONF
class DumbVolume(object):
fields = {}
def __setitem__(self, key, value):
self.fields[key] = value
def __getitem__(self, item):
return self.fields[item]
class FakeDb(object): class FakeDb(object):
msg = "Tests are broken: mock this out." msg = "Tests are broken: mock this out."
@ -66,7 +58,6 @@ class QuobyteDriverTestCase(test.TestCase):
TEST_SIZE_IN_GB = 1 TEST_SIZE_IN_GB = 1
TEST_MNT_POINT = '/mnt/quobyte' TEST_MNT_POINT = '/mnt/quobyte'
TEST_MNT_POINT_BASE = '/mnt' TEST_MNT_POINT_BASE = '/mnt'
TEST_LOCAL_PATH = '/mnt/quobyte/volume-123'
TEST_FILE_NAME = 'test.txt' TEST_FILE_NAME = 'test.txt'
TEST_SHARES_CONFIG_FILE = '/etc/cinder/test-shares.conf' TEST_SHARES_CONFIG_FILE = '/etc/cinder/test-shares.conf'
TEST_TMP_FILE = '/tmp/tempfile' TEST_TMP_FILE = '/tmp/tempfile'
@ -94,6 +85,7 @@ class QuobyteDriverTestCase(test.TestCase):
db=FakeDb()) db=FakeDb())
self._driver.shares = {} self._driver.shares = {}
self._driver.set_nas_security_options(is_new_cinder_install=False) self._driver.set_nas_security_options(is_new_cinder_install=False)
self.context = context.get_admin_context()
def assertRaisesAndMessageMatches( def assertRaisesAndMessageMatches(
self, excClass, msg, callableObj, *args, **kwargs): self, excClass, msg, callableObj, *args, **kwargs):
@ -115,13 +107,11 @@ class QuobyteDriverTestCase(test.TestCase):
def test_local_path(self): def test_local_path(self):
"""local_path common use case.""" """local_path common use case."""
drv = self._driver drv = self._driver
vol_id = self.VOLUME_UUID
volume = DumbVolume() volume = self._simple_volume(_name_id=vol_id)
volume['provider_location'] = self.TEST_QUOBYTE_VOLUME
volume['name'] = 'volume-123'
self.assertEqual( self.assertEqual(
'/mnt/1331538734b757ed52d0e18c0a7210cd/volume-123', '/mnt/1331538734b757ed52d0e18c0a7210cd/volume-%s' % vol_id,
drv.local_path(volume)) drv.local_path(volume))
def test_mount_quobyte_should_mount_correctly(self): def test_mount_quobyte_should_mount_correctly(self):
@ -428,19 +418,18 @@ class QuobyteDriverTestCase(test.TestCase):
# Future ones might do and therefore we mocked it. # Future ones might do and therefore we mocked it.
self.assertGreaterEqual(mock_get_available_capacity.call_count, 0) self.assertGreaterEqual(mock_get_available_capacity.call_count, 0)
def _simple_volume(self, uuid=None): def _simple_volume(self, **kwargs):
volume = DumbVolume() updates = {'id': self.VOLUME_UUID,
volume['provider_location'] = self.TEST_QUOBYTE_VOLUME 'provider_location': self.TEST_QUOBYTE_VOLUME,
if uuid is None: 'display_name': 'volume-%s' % self.VOLUME_UUID,
volume['id'] = self.VOLUME_UUID 'size': 10,
else: 'status': 'available'}
volume['id'] = uuid
# volume['name'] mirrors format from db/sqlalchemy/models.py
volume['name'] = 'volume-%s' % volume['id']
volume['size'] = 10
volume['status'] = 'available'
return volume updates.update(kwargs)
if 'display_name' not in updates:
updates['display_name'] = 'volume-%s' % updates['id']
return fake_volume.fake_volume_obj(self.context, **updates)
def test_create_sparsed_volume(self): def test_create_sparsed_volume(self):
drv = self._driver drv = self._driver
@ -501,11 +490,11 @@ class QuobyteDriverTestCase(test.TestCase):
drv.LOG = mock.Mock() drv.LOG = mock.Mock()
drv._find_share = mock.Mock() drv._find_share = mock.Mock()
drv._find_share.return_value = self.TEST_QUOBYTE_VOLUME
drv._do_create_volume = mock.Mock() drv._do_create_volume = mock.Mock()
drv._ensure_shares_mounted = mock.Mock() drv._ensure_shares_mounted = mock.Mock()
volume = DumbVolume() volume = self._simple_volume(size=self.TEST_SIZE_IN_GB)
volume['size'] = self.TEST_SIZE_IN_GB
drv.create_volume(volume) drv.create_volume(volume)
drv._find_share.assert_called_once_with(mock.ANY) drv._find_share.assert_called_once_with(mock.ANY)
@ -521,8 +510,7 @@ class QuobyteDriverTestCase(test.TestCase):
drv._do_create_volume = mock.Mock() drv._do_create_volume = mock.Mock()
drv._find_share = mock.Mock(return_value=self.TEST_QUOBYTE_VOLUME) drv._find_share = mock.Mock(return_value=self.TEST_QUOBYTE_VOLUME)
volume = DumbVolume() volume = self._simple_volume(size=self.TEST_SIZE_IN_GB)
volume['size'] = self.TEST_SIZE_IN_GB
result = drv.create_volume(volume) result = drv.create_volume(volume)
self.assertEqual(self.TEST_QUOBYTE_VOLUME, result['provider_location']) self.assertEqual(self.TEST_QUOBYTE_VOLUME, result['provider_location'])
@ -575,9 +563,7 @@ class QuobyteDriverTestCase(test.TestCase):
drv._execute = mock.Mock() drv._execute = mock.Mock()
volume = DumbVolume() volume = self._simple_volume(display_name='volume-123')
volume['name'] = 'volume-123'
volume['provider_location'] = self.TEST_QUOBYTE_VOLUME
drv._ensure_share_mounted = mock.Mock() drv._ensure_share_mounted = mock.Mock()
@ -596,9 +582,8 @@ class QuobyteDriverTestCase(test.TestCase):
drv._ensure_share_mounted = mock.Mock() drv._ensure_share_mounted = mock.Mock()
drv._execute = mock.Mock() drv._execute = mock.Mock()
volume = DumbVolume() volume = self._simple_volume(display_name='volume-123',
volume['name'] = 'volume-123' provider_location=None)
volume['provider_location'] = None
drv.delete_volume(volume) drv.delete_volume(volume)
@ -638,7 +623,7 @@ class QuobyteDriverTestCase(test.TestCase):
# lots of test vars to be prepared at first # lots of test vars to be prepared at first
dest_volume = self._simple_volume( dest_volume = self._simple_volume(
'c1073000-0000-0000-0000-0000000c1073') id='c1073000-0000-0000-0000-0000000c1073')
src_volume = self._simple_volume() src_volume = self._simple_volume()
vol_dir = os.path.join(self.TEST_MNT_POINT_BASE, vol_dir = os.path.join(self.TEST_MNT_POINT_BASE,
@ -647,13 +632,15 @@ class QuobyteDriverTestCase(test.TestCase):
dest_vol_path = os.path.join(vol_dir, dest_volume['name']) dest_vol_path = os.path.join(vol_dir, dest_volume['name'])
info_path = os.path.join(vol_dir, src_volume['name']) + '.info' info_path = os.path.join(vol_dir, src_volume['name']) + '.info'
snapshot = {'volume_name': src_volume['name'], snapshot = fake_snapshot.fake_snapshot_obj(
'name': 'clone-snap-%s' % src_volume['id'], self.context,
'size': src_volume['size'], volume_name=src_volume.name,
'volume_size': src_volume['size'], display_name='clone-snap-%s' % src_volume.id,
'volume_id': src_volume['id'], size=src_volume.size,
'id': 'tmp-snap-%s' % src_volume['id'], volume_size=src_volume.size,
'volume': src_volume} volume_id=src_volume.id,
id=self.SNAP_UUID)
snapshot.volume = src_volume
snap_file = dest_volume['name'] + '.' + snapshot['id'] snap_file = dest_volume['name'] + '.' + snapshot['id']
snap_path = os.path.join(vol_dir, snap_file) snap_path = os.path.join(vol_dir, snap_file)
@ -692,17 +679,18 @@ class QuobyteDriverTestCase(test.TestCase):
drv = self._driver drv = self._driver
src_volume = self._simple_volume() src_volume = self._simple_volume()
snap_ref = {'volume_name': src_volume['name'],
'name': 'clone-snap-%s' % src_volume['id'],
'size': src_volume['size'],
'volume_size': src_volume['size'],
'volume_id': src_volume['id'],
'id': 'tmp-snap-%s' % src_volume['id'],
'volume': src_volume,
'status': 'error'}
new_volume = DumbVolume() snap_ref = fake_snapshot.fake_snapshot_obj(
new_volume['size'] = snap_ref['size'] self.context,
volume_name=src_volume.name,
display_name='clone-snap-%s' % src_volume.id,
volume_size=src_volume.size,
volume_id=src_volume.id,
id=self.SNAP_UUID,
status='error')
snap_ref.volume = src_volume
new_volume = self._simple_volume(size=snap_ref.volume_size)
self.assertRaises(exception.InvalidSnapshot, self.assertRaises(exception.InvalidSnapshot,
drv.create_volume_from_snapshot, drv.create_volume_from_snapshot,
@ -713,17 +701,18 @@ class QuobyteDriverTestCase(test.TestCase):
drv = self._driver drv = self._driver
src_volume = self._simple_volume() src_volume = self._simple_volume()
snap_ref = {'volume_name': src_volume['name'],
'name': 'clone-snap-%s' % src_volume['id'],
'size': src_volume['size'],
'volume_size': src_volume['size'],
'volume_id': src_volume['id'],
'id': 'tmp-snap-%s' % src_volume['id'],
'volume': src_volume,
'status': 'available'}
new_volume = DumbVolume() snap_ref = fake_snapshot.fake_snapshot_obj(
new_volume['size'] = snap_ref['size'] self.context,
volume_name=src_volume.name,
display_name='clone-snap-%s' % src_volume.id,
volume_size=src_volume.size,
volume_id=src_volume.id,
id=self.SNAP_UUID,
status='available')
snap_ref.volume = src_volume
new_volume = self._simple_volume(size=snap_ref.volume_size)
drv._ensure_shares_mounted = mock.Mock() drv._ensure_shares_mounted = mock.Mock()
drv._find_share = mock.Mock(return_value=self.TEST_QUOBYTE_VOLUME) drv._find_share = mock.Mock(return_value=self.TEST_QUOBYTE_VOLUME)

View File

@ -12,15 +12,19 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import collections
import copy import copy
import os import os
import ddt import ddt
import mock import mock
from cinder import context
from cinder import exception from cinder import exception
from cinder.image import image_utils from cinder.image import image_utils
from cinder import test from cinder import test
from cinder.tests.unit import fake_snapshot
from cinder.tests.unit import fake_volume
from cinder import utils from cinder import utils
from cinder.volume.drivers import remotefs from cinder.volume.drivers import remotefs
@ -28,25 +32,7 @@ from cinder.volume.drivers import remotefs
@ddt.ddt @ddt.ddt
class RemoteFsSnapDriverTestCase(test.TestCase): class RemoteFsSnapDriverTestCase(test.TestCase):
_FAKE_CONTEXT = 'fake_context'
_FAKE_VOLUME_ID = '4f711859-4928-4cb7-801a-a50c37ceaccc'
_FAKE_VOLUME_NAME = 'volume-%s' % _FAKE_VOLUME_ID
_FAKE_VOLUME = {'id': _FAKE_VOLUME_ID,
'size': 1,
'provider_location': 'fake_share',
'name': _FAKE_VOLUME_NAME,
'status': 'available'}
_FAKE_MNT_POINT = '/mnt/fake_hash' _FAKE_MNT_POINT = '/mnt/fake_hash'
_FAKE_VOLUME_PATH = os.path.join(_FAKE_MNT_POINT,
_FAKE_VOLUME_NAME)
_FAKE_SNAPSHOT_ID = '5g811859-4928-4cb7-801a-a50c37ceacba'
_FAKE_SNAPSHOT = {'context': _FAKE_CONTEXT,
'id': _FAKE_SNAPSHOT_ID,
'volume': _FAKE_VOLUME,
'volume_id': _FAKE_VOLUME_ID,
'status': 'available',
'volume_size': 1}
_FAKE_SNAPSHOT_PATH = (_FAKE_VOLUME_PATH + '.' + _FAKE_SNAPSHOT_ID)
def setUp(self): def setUp(self):
super(RemoteFsSnapDriverTestCase, self).setUp() super(RemoteFsSnapDriverTestCase, self).setUp()
@ -55,21 +41,32 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
self._driver._execute = mock.Mock() self._driver._execute = mock.Mock()
self._driver._delete = mock.Mock() self._driver._delete = mock.Mock()
self.context = context.get_admin_context()
self._fake_volume = fake_volume.fake_volume_obj(
self.context, provider_location='fake_share')
self._fake_volume_path = os.path.join(self._FAKE_MNT_POINT,
self._fake_volume.name)
self._fake_snapshot = fake_snapshot.fake_snapshot_obj(self.context)
self._fake_snapshot_path = (self._fake_volume_path + '.' +
self._fake_snapshot.id)
self._fake_snapshot.volume = self._fake_volume
def _test_delete_snapshot(self, volume_in_use=False, def _test_delete_snapshot(self, volume_in_use=False,
stale_snapshot=False, stale_snapshot=False,
is_active_image=True): is_active_image=True):
# If the snapshot is not the active image, it is guaranteed that # If the snapshot is not the active image, it is guaranteed that
# another snapshot exists having it as backing file. # another snapshot exists having it as backing file.
fake_snapshot_name = os.path.basename(self._FAKE_SNAPSHOT_PATH) fake_snapshot_name = os.path.basename(self._fake_snapshot_path)
fake_info = {'active': fake_snapshot_name, fake_info = {'active': fake_snapshot_name,
self._FAKE_SNAPSHOT['id']: fake_snapshot_name} self._fake_snapshot.id: fake_snapshot_name}
fake_snap_img_info = mock.Mock() fake_snap_img_info = mock.Mock()
fake_base_img_info = mock.Mock() fake_base_img_info = mock.Mock()
if stale_snapshot: if stale_snapshot:
fake_snap_img_info.backing_file = None fake_snap_img_info.backing_file = None
else: else:
fake_snap_img_info.backing_file = self._FAKE_VOLUME_NAME fake_snap_img_info.backing_file = self._fake_volume.name
fake_snap_img_info.file_format = 'qcow2' fake_snap_img_info.file_format = 'qcow2'
fake_base_img_info.backing_file = None fake_base_img_info.backing_file = None
fake_base_img_info.file_format = 'raw' fake_base_img_info.file_format = 'raw'
@ -91,72 +88,71 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
expected_info = { expected_info = {
'active': fake_snapshot_name, 'active': fake_snapshot_name,
self._FAKE_SNAPSHOT_ID: fake_snapshot_name self._fake_snapshot.id: fake_snapshot_name
} }
if volume_in_use: if volume_in_use:
fake_snapshot = copy.deepcopy(self._FAKE_SNAPSHOT) self._fake_snapshot.volume.status = 'in-use'
fake_snapshot['volume']['status'] = 'in-use'
self._driver._read_info_file.return_value = fake_info self._driver._read_info_file.return_value = fake_info
self._driver._delete_snapshot(fake_snapshot) self._driver._delete_snapshot(self._fake_snapshot)
if stale_snapshot: if stale_snapshot:
self._driver._delete_stale_snapshot.assert_called_once_with( self._driver._delete_stale_snapshot.assert_called_once_with(
fake_snapshot) self._fake_snapshot)
else: else:
expected_online_delete_info = { expected_online_delete_info = {
'active_file': fake_snapshot_name, 'active_file': fake_snapshot_name,
'snapshot_file': fake_snapshot_name, 'snapshot_file': fake_snapshot_name,
'base_file': self._FAKE_VOLUME_NAME, 'base_file': self._fake_volume.name,
'base_id': None, 'base_id': None,
'new_base_file': None 'new_base_file': None
} }
self._driver._delete_snapshot_online.assert_called_once_with( self._driver._delete_snapshot_online.assert_called_once_with(
self._FAKE_CONTEXT, fake_snapshot, self.context, self._fake_snapshot,
expected_online_delete_info) expected_online_delete_info)
elif is_active_image: elif is_active_image:
self._driver._read_info_file.return_value = fake_info self._driver._read_info_file.return_value = fake_info
self._driver._delete_snapshot(self._FAKE_SNAPSHOT) self._driver._delete_snapshot(self._fake_snapshot)
self._driver._img_commit.assert_called_once_with( self._driver._img_commit.assert_called_once_with(
self._FAKE_SNAPSHOT_PATH) self._fake_snapshot_path)
self.assertNotIn(self._FAKE_SNAPSHOT_ID, fake_info) self.assertNotIn(self._fake_snapshot.id, fake_info)
self._driver._write_info_file.assert_called_once_with( self._driver._write_info_file.assert_called_once_with(
mock.sentinel.fake_info_path, fake_info) mock.sentinel.fake_info_path, fake_info)
else: else:
fake_upper_snap_id = 'fake_upper_snap_id' fake_upper_snap_id = 'fake_upper_snap_id'
fake_upper_snap_path = ( fake_upper_snap_path = (
self._FAKE_VOLUME_PATH + '-snapshot' + fake_upper_snap_id) self._fake_volume_path + '-snapshot' + fake_upper_snap_id)
fake_upper_snap_name = os.path.basename(fake_upper_snap_path) fake_upper_snap_name = os.path.basename(fake_upper_snap_path)
fake_backing_chain = [ fake_backing_chain = [
{'filename': fake_upper_snap_name, {'filename': fake_upper_snap_name,
'backing-filename': fake_snapshot_name}, 'backing-filename': fake_snapshot_name},
{'filename': fake_snapshot_name, {'filename': fake_snapshot_name,
'backing-filename': self._FAKE_VOLUME_NAME}, 'backing-filename': self._fake_volume.name},
{'filename': self._FAKE_VOLUME_NAME, {'filename': self._fake_volume.name,
'backing-filename': None}] 'backing-filename': None}]
fake_info[fake_upper_snap_id] = fake_upper_snap_name fake_info[fake_upper_snap_id] = fake_upper_snap_name
fake_info[self._FAKE_SNAPSHOT_ID] = fake_snapshot_name fake_info[self._fake_snapshot.id] = fake_snapshot_name
fake_info['active'] = fake_upper_snap_name fake_info['active'] = fake_upper_snap_name
expected_info = copy.deepcopy(fake_info) expected_info = copy.deepcopy(fake_info)
del expected_info[self._FAKE_SNAPSHOT_ID] del expected_info[self._fake_snapshot.id]
self._driver._read_info_file.return_value = fake_info self._driver._read_info_file.return_value = fake_info
self._driver._get_backing_chain_for_path = mock.Mock( self._driver._get_backing_chain_for_path = mock.Mock(
return_value=fake_backing_chain) return_value=fake_backing_chain)
self._driver._delete_snapshot(self._FAKE_SNAPSHOT) self._driver._delete_snapshot(self._fake_snapshot)
self._driver._img_commit.assert_called_once_with( self._driver._img_commit.assert_called_once_with(
self._FAKE_SNAPSHOT_PATH) self._fake_snapshot_path)
self._driver._rebase_img.assert_called_once_with( self._driver._rebase_img.assert_called_once_with(
fake_upper_snap_path, self._FAKE_VOLUME_NAME, fake_upper_snap_path, self._fake_volume.name,
fake_base_img_info.file_format) fake_base_img_info.file_format)
self._driver._write_info_file.assert_called_once_with( self._driver._write_info_file.assert_called_once_with(
mock.sentinel.fake_info_path, expected_info) mock.sentinel.fake_info_path, expected_info)
@ -175,12 +171,12 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
self._test_delete_snapshot(is_active_image=False) self._test_delete_snapshot(is_active_image=False)
def test_delete_stale_snapshot(self): def test_delete_stale_snapshot(self):
fake_snapshot_name = os.path.basename(self._FAKE_SNAPSHOT_PATH) fake_snapshot_name = os.path.basename(self._fake_snapshot_path)
fake_snap_info = { fake_snap_info = {
'active': self._FAKE_VOLUME_NAME, 'active': self._fake_volume.name,
self._FAKE_SNAPSHOT_ID: fake_snapshot_name self._fake_snapshot.id: fake_snapshot_name
} }
expected_info = {'active': self._FAKE_VOLUME_NAME} expected_info = {'active': self._fake_volume.name}
self._driver._local_path_volume_info = mock.Mock( self._driver._local_path_volume_info = mock.Mock(
return_value=mock.sentinel.fake_info_path) return_value=mock.sentinel.fake_info_path)
@ -190,42 +186,41 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
return_value=self._FAKE_MNT_POINT) return_value=self._FAKE_MNT_POINT)
self._driver._write_info_file = mock.Mock() self._driver._write_info_file = mock.Mock()
self._driver._delete_stale_snapshot(self._FAKE_SNAPSHOT) self._driver._delete_stale_snapshot(self._fake_snapshot)
self._driver._delete.assert_called_once_with(self._FAKE_SNAPSHOT_PATH) self._driver._delete.assert_called_once_with(self._fake_snapshot_path)
self._driver._write_info_file.assert_called_once_with( self._driver._write_info_file.assert_called_once_with(
mock.sentinel.fake_info_path, expected_info) mock.sentinel.fake_info_path, expected_info)
def test_do_create_snapshot(self): def test_do_create_snapshot(self):
self._driver._local_volume_dir = mock.Mock( self._driver._local_volume_dir = mock.Mock(
return_value=self._FAKE_VOLUME_PATH) return_value=self._fake_volume_path)
fake_backing_path = os.path.join( fake_backing_path = os.path.join(
self._driver._local_volume_dir(), self._driver._local_volume_dir(),
self._FAKE_VOLUME_NAME) self._fake_volume.name)
self._driver._execute = mock.Mock() self._driver._execute = mock.Mock()
self._driver._set_rw_permissions = mock.Mock() self._driver._set_rw_permissions = mock.Mock()
self._driver._qemu_img_info = mock.Mock( self._driver._qemu_img_info = mock.Mock(
return_value=mock.Mock(file_format=mock.sentinel.backing_fmt)) return_value=mock.Mock(file_format=mock.sentinel.backing_fmt))
self._driver._do_create_snapshot(self._FAKE_SNAPSHOT, self._driver._do_create_snapshot(self._fake_snapshot,
self._FAKE_VOLUME_NAME, self._fake_volume.name,
self._FAKE_SNAPSHOT_PATH) self._fake_snapshot_path)
command1 = ['qemu-img', 'create', '-f', 'qcow2', '-o', command1 = ['qemu-img', 'create', '-f', 'qcow2', '-o',
'backing_file=%s' % fake_backing_path, 'backing_file=%s' % fake_backing_path,
self._FAKE_SNAPSHOT_PATH] self._fake_snapshot_path]
command2 = ['qemu-img', 'rebase', '-u', command2 = ['qemu-img', 'rebase', '-u',
'-b', self._FAKE_VOLUME_NAME, '-b', self._fake_volume.name,
'-F', mock.sentinel.backing_fmt, '-F', mock.sentinel.backing_fmt,
self._FAKE_SNAPSHOT_PATH] self._fake_snapshot_path]
self._driver._execute.assert_any_call(*command1, run_as_root=True) self._driver._execute.assert_any_call(*command1, run_as_root=True)
self._driver._execute.assert_any_call(*command2, run_as_root=True) self._driver._execute.assert_any_call(*command2, run_as_root=True)
def _test_create_snapshot(self, volume_in_use=False): def _test_create_snapshot(self, volume_in_use=False):
fake_snapshot = copy.deepcopy(self._FAKE_SNAPSHOT)
fake_snapshot_info = {} fake_snapshot_info = {}
fake_snapshot_file_name = os.path.basename(self._FAKE_SNAPSHOT_PATH) fake_snapshot_file_name = os.path.basename(self._fake_snapshot_path)
self._driver._local_path_volume_info = mock.Mock( self._driver._local_path_volume_info = mock.Mock(
return_value=mock.sentinel.fake_info_path) return_value=mock.sentinel.fake_info_path)
@ -235,28 +230,28 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
self._driver._create_snapshot_online = mock.Mock() self._driver._create_snapshot_online = mock.Mock()
self._driver._write_info_file = mock.Mock() self._driver._write_info_file = mock.Mock()
self._driver.get_active_image_from_info = mock.Mock( self._driver.get_active_image_from_info = mock.Mock(
return_value=self._FAKE_VOLUME_NAME) return_value=self._fake_volume.name)
self._driver._get_new_snap_path = mock.Mock( self._driver._get_new_snap_path = mock.Mock(
return_value=self._FAKE_SNAPSHOT_PATH) return_value=self._fake_snapshot_path)
expected_snapshot_info = { expected_snapshot_info = {
'active': fake_snapshot_file_name, 'active': fake_snapshot_file_name,
self._FAKE_SNAPSHOT_ID: fake_snapshot_file_name self._fake_snapshot.id: fake_snapshot_file_name
} }
if volume_in_use: if volume_in_use:
fake_snapshot['volume']['status'] = 'in-use' self._fake_snapshot.volume.status = 'in-use'
expected_method_called = '_create_snapshot_online' expected_method_called = '_create_snapshot_online'
else: else:
fake_snapshot['volume']['status'] = 'available' self._fake_snapshot.volume.status = 'available'
expected_method_called = '_do_create_snapshot' expected_method_called = '_do_create_snapshot'
self._driver._create_snapshot(fake_snapshot) self._driver._create_snapshot(self._fake_snapshot)
fake_method = getattr(self._driver, expected_method_called) fake_method = getattr(self._driver, expected_method_called)
fake_method.assert_called_with( fake_method.assert_called_with(
fake_snapshot, self._FAKE_VOLUME_NAME, self._fake_snapshot, self._fake_volume.name,
self._FAKE_SNAPSHOT_PATH) self._fake_snapshot_path)
self._driver._write_info_file.assert_called_with( self._driver._write_info_file.assert_called_with(
mock.sentinel.fake_info_path, mock.sentinel.fake_info_path,
expected_snapshot_info) expected_snapshot_info)
@ -268,12 +263,10 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
self._test_create_snapshot(volume_in_use=True) self._test_create_snapshot(volume_in_use=True)
def test_create_snapshot_invalid_volume(self): def test_create_snapshot_invalid_volume(self):
fake_snapshot = copy.deepcopy(self._FAKE_SNAPSHOT) self._fake_snapshot.volume.status = 'error'
fake_snapshot['volume']['status'] = 'error'
self.assertRaises(exception.InvalidVolume, self.assertRaises(exception.InvalidVolume,
self._driver._create_snapshot, self._driver._create_snapshot,
fake_snapshot) self._fake_snapshot)
@mock.patch('cinder.db.snapshot_get') @mock.patch('cinder.db.snapshot_get')
@mock.patch('time.sleep') @mock.patch('time.sleep')
@ -294,18 +287,18 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
mock_do_create_snapshot: mock_do_create_snapshot:
self.assertRaises(exception.RemoteFSConcurrentRequest, self.assertRaises(exception.RemoteFSConcurrentRequest,
self._driver._create_snapshot_online, self._driver._create_snapshot_online,
self._FAKE_SNAPSHOT, self._fake_snapshot,
self._FAKE_VOLUME_NAME, self._fake_volume.name,
self._FAKE_SNAPSHOT_PATH) self._fake_snapshot_path)
mock_do_create_snapshot.assert_called_once_with( mock_do_create_snapshot.assert_called_once_with(
self._FAKE_SNAPSHOT, self._FAKE_VOLUME_NAME, self._fake_snapshot, self._fake_volume.name,
self._FAKE_SNAPSHOT_PATH) self._fake_snapshot_path)
self.assertEqual([mock.call(1), mock.call(1)], self.assertEqual([mock.call(1), mock.call(1)],
mock_sleep.call_args_list) mock_sleep.call_args_list)
self.assertEqual(3, mock_snapshot_get.call_count) self.assertEqual(3, mock_snapshot_get.call_count)
mock_snapshot_get.assert_called_with(self._FAKE_SNAPSHOT['context'], mock_snapshot_get.assert_called_with(self._fake_snapshot._context,
self._FAKE_SNAPSHOT['id']) self._fake_snapshot.id)
@mock.patch.object(utils, 'synchronized') @mock.patch.object(utils, 'synchronized')
def _locked_volume_operation_test_helper(self, mock_synchronized, func, def _locked_volume_operation_test_helper(self, mock_synchronized, func,
@ -318,7 +311,7 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
mock_synchronized.side_effect = mock_decorator mock_synchronized.side_effect = mock_decorator
expected_lock = '%s-%s' % (self._driver.driver_prefix, expected_lock = '%s-%s' % (self._driver.driver_prefix,
self._FAKE_VOLUME_ID) self._fake_volume.id)
if expected_exception: if expected_exception:
self.assertRaises(expected_exception, func, self.assertRaises(expected_exception, func,
@ -332,7 +325,8 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
self.assertEqual(mock.sentinel.ret_val, ret_val) self.assertEqual(mock.sentinel.ret_val, ret_val)
def test_locked_volume_id_operation(self): def test_locked_volume_id_operation(self):
mock_volume = {'id': self._FAKE_VOLUME_ID} mock_volume = mock.Mock()
mock_volume.id = self._fake_volume.id
@remotefs.locked_volume_id_operation @remotefs.locked_volume_id_operation
def synchronized_func(inst, volume): def synchronized_func(inst, volume):
@ -342,7 +336,8 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
volume=mock_volume) volume=mock_volume)
def test_locked_volume_id_snapshot_operation(self): def test_locked_volume_id_snapshot_operation(self):
mock_snapshot = {'volume': {'id': self._FAKE_VOLUME_ID}} mock_snapshot = mock.Mock()
mock_snapshot.volume.id = self._fake_volume.id
@remotefs.locked_volume_id_operation @remotefs.locked_volume_id_operation
def synchronized_func(inst, snapshot): def synchronized_func(inst, snapshot):
@ -432,22 +427,36 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
mock.patch.object(drv, '_copy_volume_from_snapshot') as \ mock.patch.object(drv, '_copy_volume_from_snapshot') as \
mock_copy_volume_from_snapshot: mock_copy_volume_from_snapshot:
volume = self._FAKE_VOLUME.copy() volume = fake_volume.fake_volume_obj(self.context)
src_vref = self._FAKE_VOLUME.copy() src_vref_id = '375e32b2-804a-49f2-b282-85d1d5a5b9e1'
src_vref['id'] = '375e32b2-804a-49f2-b282-85d1d5a5b9e1' src_vref = fake_volume.fake_volume_obj(
src_vref['name'] = 'volume-%s' % src_vref['id'] self.context,
volume_ref = {'id': volume['id'], id=src_vref_id,
'name': volume['name'], name='volume-%s' % src_vref_id)
'status': volume['status'],
'provider_location': volume['provider_location'], vol_attrs = ['provider_location', 'size', 'id', 'name', 'status',
'size': volume['size']} 'volume_type', 'metadata']
snap_ref = {'volume_name': volume['name'], Volume = collections.namedtuple('Volume', vol_attrs)
'name': 'clone-snap-%s' % src_vref['id'],
'size': src_vref['size'], snap_attrs = ['volume_name', 'volume_size', 'name',
'volume_size': src_vref['size'], 'volume_id', 'id', 'volume']
'volume_id': src_vref['id'], Snapshot = collections.namedtuple('Snapshot', snap_attrs)
'id': 'tmp-snap-%s' % src_vref['id'],
'volume': src_vref} volume_ref = Volume(id=volume.id,
name=volume.name,
status=volume.status,
provider_location=volume.provider_location,
size=volume.size,
volume_type=volume.volume_type,
metadata=volume.metadata)
snap_ref = Snapshot(volume_name=volume.name,
name='clone-snap-%s' % src_vref.id,
volume_size=src_vref.size,
volume_id=src_vref.id,
id='tmp-snap-%s' % src_vref.id,
volume=src_vref)
drv.create_cloned_volume(volume, src_vref) drv.create_cloned_volume(volume, src_vref)
mock_create_snapshot.assert_called_once_with(snap_ref) mock_create_snapshot.assert_called_once_with(snap_ref)

View File

@ -26,27 +26,26 @@ from six.moves import urllib
from cinder import context from cinder import context
from cinder import exception from cinder import exception
from cinder import test from cinder import test
from cinder.tests.unit import fake_snapshot
from cinder.tests.unit import fake_volume
from cinder.volume import configuration as conf from cinder.volume import configuration as conf
import cinder.volume.drivers.scality as driver import cinder.volume.drivers.scality as driver
_FAKE_VOLUME = {'name': 'volume-a79d463e-1fd5-11e5-a6ff-5b81bfee8544', _FAKE_VOLUME_ID = 'a79d463e-1fd5-11e5-a6ff-5b81bfee8544'
'id': 'a79d463e-1fd5-11e5-a6ff-5b81bfee8544', _FAKE_VOLUME_NAME = 'volume-a79d463e-1fd5-11e5-a6ff-5b81bfee8544'
'provider_location': 'fake_share'}
_FAKE_SNAPSHOT = {'id': 'ae3d6da2-1fd5-11e5-967f-1b8cf3b401ab', _FAKE_SNAPSHOT_ID = 'ae3d6da2-1fd5-11e5-967f-1b8cf3b401ab'
'volume': _FAKE_VOLUME, _FAKE_SNAPSHOT_NAME = 'snapshot-ae3d6da2-1fd5-11e5-967f-1b8cf3b401ab'
'status': 'available',
'provider_location': None,
'volume_size': 1,
'name': 'snapshot-ae3d6da2-1fd5-11e5-967f-1b8cf3b401ab'}
_FAKE_BACKUP = {'id': '914849d2-2585-11e5-be54-d70ca0c343d6', _FAKE_BACKUP = {'id': '914849d2-2585-11e5-be54-d70ca0c343d6',
'volume_id': _FAKE_VOLUME['id']} 'volume_id': _FAKE_VOLUME_ID}
_FAKE_MNT_POINT = '/tmp' _FAKE_MNT_POINT = '/tmp'
_FAKE_SOFS_CONFIG = '/etc/sfused.conf' _FAKE_SOFS_CONFIG = '/etc/sfused.conf'
_FAKE_VOLUME_DIR = 'cinder/volumes' _FAKE_VOLUME_DIR = 'cinder/volumes'
_FAKE_VOL_BASEDIR = os.path.join(_FAKE_MNT_POINT, _FAKE_VOLUME_DIR, '00') _FAKE_VOL_BASEDIR = os.path.join(_FAKE_MNT_POINT, _FAKE_VOLUME_DIR, '00')
_FAKE_VOL_PATH = os.path.join(_FAKE_VOL_BASEDIR, _FAKE_VOLUME['name']) _FAKE_VOL_PATH = os.path.join(_FAKE_VOL_BASEDIR, _FAKE_VOLUME_NAME)
_FAKE_SNAP_PATH = os.path.join(_FAKE_VOL_BASEDIR, _FAKE_SNAPSHOT['name']) _FAKE_SNAP_PATH = os.path.join(_FAKE_VOL_BASEDIR, _FAKE_SNAPSHOT_NAME)
_FAKE_MOUNTS_TABLE = [['tmpfs /dev/shm\n'], _FAKE_MOUNTS_TABLE = [['tmpfs /dev/shm\n'],
['fuse ' + _FAKE_MNT_POINT + '\n']] ['fuse ' + _FAKE_MNT_POINT + '\n']]
@ -66,6 +65,30 @@ class ScalityDriverTestCase(test.TestCase):
self.drv = driver.ScalityDriver(configuration=self.cfg) self.drv = driver.ScalityDriver(configuration=self.cfg)
self.drv.db = mock.Mock() self.drv.db = mock.Mock()
self.context = context.get_admin_context()
def _simple_volume(self, **kwargs):
updates = {'display_name': _FAKE_VOLUME_NAME,
'id': _FAKE_VOLUME_ID,
'provider_location': 'fake_share'}
updates.update(kwargs)
return fake_volume.fake_volume_obj(self.context, **updates)
def _simple_snapshot(self, **kwargs):
updates = {'id': _FAKE_SNAPSHOT_ID,
'display_name': _FAKE_SNAPSHOT_NAME,
'status': 'available',
'provider_location': None,
'volume_size': 1}
updates.update(kwargs)
snapshot = fake_snapshot.fake_snapshot_obj(self.context, **updates)
volume = self._simple_volume()
snapshot.volume = volume
return snapshot
@mock.patch.object(driver.urllib.request, 'urlopen') @mock.patch.object(driver.urllib.request, 'urlopen')
@mock.patch('os.access') @mock.patch('os.access')
def test_check_for_setup_error(self, mock_os_access, mock_urlopen): def test_check_for_setup_error(self, mock_os_access, mock_urlopen):
@ -206,27 +229,28 @@ class ScalityDriverTestCase(test.TestCase):
def test_initialize_connection(self, mock_qemu_img_info): def test_initialize_connection(self, mock_qemu_img_info):
info = imageutils.QemuImgInfo() info = imageutils.QemuImgInfo()
info.file_format = 'raw' info.file_format = 'raw'
info.image = _FAKE_VOLUME['name'] info.image = _FAKE_VOLUME_NAME
mock_qemu_img_info.return_value = info mock_qemu_img_info.return_value = info
volume = self._simple_volume()
with mock.patch.object(self.drv, 'get_active_image_from_info') as \ with mock.patch.object(self.drv, 'get_active_image_from_info') as \
mock_get_active_image_from_info: mock_get_active_image_from_info:
mock_get_active_image_from_info.return_value = _FAKE_VOLUME['name'] mock_get_active_image_from_info.return_value = _FAKE_VOLUME_NAME
conn_info = self.drv.initialize_connection(_FAKE_VOLUME, None) conn_info = self.drv.initialize_connection(volume, None)
expected_conn_info = { expected_conn_info = {
'driver_volume_type': driver.ScalityDriver.driver_volume_type, 'driver_volume_type': driver.ScalityDriver.driver_volume_type,
'mount_point_base': _FAKE_MNT_POINT, 'mount_point_base': _FAKE_MNT_POINT,
'data': { 'data': {
'export': _FAKE_VOLUME['provider_location'], 'export': volume.provider_location,
'name': _FAKE_VOLUME['name'], 'name': volume.name,
'sofs_path': 'cinder/volumes/00/' + _FAKE_VOLUME['name'], 'sofs_path': 'cinder/volumes/00/' + volume.name,
'format': 'raw' 'format': 'raw'
} }
} }
self.assertEqual(expected_conn_info, conn_info) self.assertEqual(expected_conn_info, conn_info)
mock_get_active_image_from_info.assert_called_once_with(_FAKE_VOLUME) mock_get_active_image_from_info.assert_called_once_with(volume)
mock_qemu_img_info.assert_called_once_with(_FAKE_VOL_PATH) mock_qemu_img_info.assert_called_once_with(_FAKE_VOL_PATH)
@mock.patch("cinder.image.image_utils.resize_image") @mock.patch("cinder.image.image_utils.resize_image")
@ -236,7 +260,7 @@ class ScalityDriverTestCase(test.TestCase):
info.file_format = 'raw' info.file_format = 'raw'
mock_qemu_img_info.return_value = info mock_qemu_img_info.return_value = info
self.drv.extend_volume(_FAKE_VOLUME, 2) self.drv.extend_volume(self._simple_volume(), 2)
mock_qemu_img_info.assert_called_once_with(_FAKE_VOL_PATH) mock_qemu_img_info.assert_called_once_with(_FAKE_VOL_PATH)
@ -249,7 +273,7 @@ class ScalityDriverTestCase(test.TestCase):
mock_qemu_img_info.return_value = info mock_qemu_img_info.return_value = info
self.assertRaises(exception.InvalidVolume, self.assertRaises(exception.InvalidVolume,
self.drv.extend_volume, _FAKE_VOLUME, 2) self.drv.extend_volume, self._simple_volume(), 2)
@mock.patch("cinder.image.image_utils.resize_image") @mock.patch("cinder.image.image_utils.resize_image")
@mock.patch("cinder.image.image_utils.convert_image") @mock.patch("cinder.image.image_utils.convert_image")
@ -260,8 +284,8 @@ class ScalityDriverTestCase(test.TestCase):
mock.patch.object(self.drv, '_set_rw_permissions_for_all') as \ mock.patch.object(self.drv, '_set_rw_permissions_for_all') as \
mock_set_rw_permissions: mock_set_rw_permissions:
mock_read_info_file.side_effect = IOError(errno.ENOENT, '') mock_read_info_file.side_effect = IOError(errno.ENOENT, '')
self.drv._copy_volume_from_snapshot(_FAKE_SNAPSHOT, self.drv._copy_volume_from_snapshot(self._simple_snapshot(),
_FAKE_VOLUME, 1) self._simple_volume(), 1)
mock_read_info_file.assert_called_once_with("%s.info" % _FAKE_VOL_PATH) mock_read_info_file.assert_called_once_with("%s.info" % _FAKE_VOL_PATH)
mock_convert_image.assert_called_once_with(_FAKE_SNAP_PATH, mock_convert_image.assert_called_once_with(_FAKE_SNAP_PATH,
@ -276,10 +300,11 @@ class ScalityDriverTestCase(test.TestCase):
def test_copy_volume_from_snapshot(self, mock_qemu_img_info, def test_copy_volume_from_snapshot(self, mock_qemu_img_info,
mock_convert_image, mock_resize_image): mock_convert_image, mock_resize_image):
new_volume = {'name': 'volume-3fa63b02-1fe5-11e5-b492-abf97a8fb23b', new_volume = self._simple_volume(
'id': '3fa63b02-1fe5-11e5-b492-abf97a8fb23b', display_name='volume-3fa63b02-1fe5-11e5-b492-abf97a8fb23b',
'provider_location': 'fake_share'} id='3fa63b02-1fe5-11e5-b492-abf97a8fb23b',
new_vol_path = os.path.join(_FAKE_VOL_BASEDIR, new_volume['name']) provider_location='fake_share')
new_vol_path = os.path.join(_FAKE_VOL_BASEDIR, new_volume.name)
info = imageutils.QemuImgInfo() info = imageutils.QemuImgInfo()
info.file_format = 'raw' info.file_format = 'raw'
@ -290,7 +315,7 @@ class ScalityDriverTestCase(test.TestCase):
mock_read_info_file, \ mock_read_info_file, \
mock.patch.object(self.drv, '_set_rw_permissions_for_all') as \ mock.patch.object(self.drv, '_set_rw_permissions_for_all') as \
mock_set_rw_permissions: mock_set_rw_permissions:
self.drv._copy_volume_from_snapshot(_FAKE_SNAPSHOT, self.drv._copy_volume_from_snapshot(self._simple_snapshot(),
new_volume, 1) new_volume, 1)
mock_read_info_file.assert_called_once_with("%s.info" % _FAKE_VOL_PATH) mock_read_info_file.assert_called_once_with("%s.info" % _FAKE_VOL_PATH)
@ -311,9 +336,9 @@ class ScalityDriverTestCase(test.TestCase):
info.file_format = 'raw' info.file_format = 'raw'
mock_qemu_img_info.return_value = info mock_qemu_img_info.return_value = info
backup = {'volume_id': _FAKE_VOLUME['id']} backup = {'volume_id': _FAKE_VOLUME_ID}
mock_backup_service = mock.MagicMock() mock_backup_service = mock.MagicMock()
self.drv.db.volume_get.return_value = _FAKE_VOLUME self.drv.db.volume_get.return_value = self._simple_volume()
self.drv.backup_volume(context, backup, mock_backup_service) self.drv.backup_volume(context, backup, mock_backup_service)
@ -330,7 +355,7 @@ class ScalityDriverTestCase(test.TestCase):
info.file_format = 'qcow2' info.file_format = 'qcow2'
mock_qemu_img_info.return_value = info mock_qemu_img_info.return_value = info
self.drv.db.volume_get.return_value = _FAKE_VOLUME self.drv.db.volume_get.return_value = self._simple_volume()
self.assertRaises(exception.InvalidVolume, self.drv.backup_volume, self.assertRaises(exception.InvalidVolume, self.drv.backup_volume,
context, _FAKE_BACKUP, mock.MagicMock()) context, _FAKE_BACKUP, mock.MagicMock())
@ -345,8 +370,8 @@ class ScalityDriverTestCase(test.TestCase):
info.backing_file = 'fake.img' info.backing_file = 'fake.img'
mock_qemu_img_info.return_value = info mock_qemu_img_info.return_value = info
backup = {'volume_id': _FAKE_VOLUME['id']} backup = {'volume_id': _FAKE_VOLUME_ID}
self.drv.db.volume_get.return_value = _FAKE_VOLUME self.drv.db.volume_get.return_value = self._simple_volume()
self.assertRaises(exception.InvalidVolume, self.drv.backup_volume, self.assertRaises(exception.InvalidVolume, self.drv.backup_volume,
context, backup, mock.MagicMock()) context, backup, mock.MagicMock())
@ -358,10 +383,10 @@ class ScalityDriverTestCase(test.TestCase):
def test_restore_bakup(self, mock_open, mock_temporary_chown): def test_restore_bakup(self, mock_open, mock_temporary_chown):
mock_backup_service = mock.MagicMock() mock_backup_service = mock.MagicMock()
self.drv.restore_backup(context, _FAKE_BACKUP, _FAKE_VOLUME, self.drv.restore_backup(context, _FAKE_BACKUP, self._simple_volume(),
mock_backup_service) mock_backup_service)
mock_temporary_chown.assert_called_once_with(_FAKE_VOL_PATH) mock_temporary_chown.assert_called_once_with(_FAKE_VOL_PATH)
mock_open.assert_called_once_with(_FAKE_VOL_PATH, 'wb') mock_open.assert_called_once_with(_FAKE_VOL_PATH, 'wb')
mock_backup_service.restore.assert_called_once_with( mock_backup_service.restore.assert_called_once_with(
_FAKE_BACKUP, _FAKE_VOLUME['id'], mock_open().__enter__()) _FAKE_BACKUP, _FAKE_VOLUME_ID, mock_open().__enter__())

View File

@ -21,11 +21,10 @@ import mock
from oslo_utils import fileutils from oslo_utils import fileutils
from cinder import context from cinder import context
from cinder import db
from cinder import exception from cinder import exception
from cinder.image import image_utils from cinder.image import image_utils
from cinder import objects
from cinder import test from cinder import test
from cinder.tests.unit import fake_snapshot
from cinder.tests.unit import fake_volume from cinder.tests.unit import fake_volume
from cinder.volume.drivers import remotefs from cinder.volume.drivers import remotefs
from cinder.volume.drivers import smbfs from cinder.volume.drivers import smbfs
@ -39,7 +38,7 @@ def requires_allocation_data_update(expected_size):
inst._smbfs_driver, inst._smbfs_driver,
'update_disk_allocation_data') as fake_update: 'update_disk_allocation_data') as fake_update:
func(inst, *args, **kwargs) func(inst, *args, **kwargs)
fake_update.assert_called_once_with(inst._FAKE_VOLUME, fake_update.assert_called_once_with(inst.volume,
expected_size) expected_size)
return inner return inner
return wrapper return wrapper
@ -55,18 +54,10 @@ class SmbFsTestCase(test.TestCase):
_FAKE_TOTAL_SIZE = '2048' _FAKE_TOTAL_SIZE = '2048'
_FAKE_TOTAL_AVAILABLE = '1024' _FAKE_TOTAL_AVAILABLE = '1024'
_FAKE_TOTAL_ALLOCATED = 1024 _FAKE_TOTAL_ALLOCATED = 1024
_FAKE_VOLUME = {'id': '4f711859-4928-4cb7-801a-a50c37ceaccc',
'size': 1,
'provider_location': _FAKE_SHARE,
'name': _FAKE_VOLUME_NAME,
'status': 'available'}
_FAKE_MNT_POINT = os.path.join(_FAKE_MNT_BASE, _FAKE_SHARE_HASH) _FAKE_MNT_POINT = os.path.join(_FAKE_MNT_BASE, _FAKE_SHARE_HASH)
_FAKE_VOLUME_PATH = os.path.join(_FAKE_MNT_POINT, _FAKE_VOLUME_NAME) _FAKE_VOLUME_PATH = os.path.join(_FAKE_MNT_POINT, _FAKE_VOLUME_NAME)
_FAKE_SNAPSHOT_ID = '5g811859-4928-4cb7-801a-a50c37ceacba' _FAKE_VOLUME_SIZE = 1
_FAKE_SNAPSHOT = {'id': _FAKE_SNAPSHOT_ID, _FAKE_SNAPSHOT_ID = '50811859-4928-4cb7-801a-a50c37ceacba'
'volume': _FAKE_VOLUME,
'status': 'available',
'volume_size': 1}
_FAKE_SNAPSHOT_PATH = ( _FAKE_SNAPSHOT_PATH = (
_FAKE_VOLUME_PATH + '-snapshot' + _FAKE_SNAPSHOT_ID) _FAKE_VOLUME_PATH + '-snapshot' + _FAKE_SNAPSHOT_ID)
_FAKE_SHARE_OPTS = '-o username=Administrator,password=12345' _FAKE_SHARE_OPTS = '-o username=Administrator,password=12345'
@ -93,6 +84,22 @@ class SmbFsTestCase(test.TestCase):
self._smbfs_driver.base = self._FAKE_MNT_BASE self._smbfs_driver.base = self._FAKE_MNT_BASE
self._smbfs_driver._alloc_info_file_path = ( self._smbfs_driver._alloc_info_file_path = (
self._FAKE_ALLOCATION_DATA_PATH) self._FAKE_ALLOCATION_DATA_PATH)
self.context = context.get_admin_context()
self.volume = fake_volume.fake_volume_obj(
self.context,
id='4f711859-4928-4cb7-801a-a50c37ceaccc',
size=self._FAKE_VOLUME_SIZE,
provider_location=self._FAKE_SHARE,
display_name=self._FAKE_VOLUME_NAME,
status='available')
self.snapshot = fake_snapshot.fake_snapshot_obj(
self.context,
id=self._FAKE_SNAPSHOT_ID,
status='available',
volume_size=1)
self.snapshot.volume = self.volume
self.addCleanup(mock.patch.stopall) self.addCleanup(mock.patch.stopall)
@ -137,24 +144,24 @@ class SmbFsTestCase(test.TestCase):
fake_alloc_data = self._get_fake_allocation_data() fake_alloc_data = self._get_fake_allocation_data()
if volume_exists: if volume_exists:
fake_alloc_data[self._FAKE_SHARE_HASH][ fake_alloc_data[self._FAKE_SHARE_HASH][
self._FAKE_VOLUME_NAME] = self._FAKE_VOLUME['size'] self._FAKE_VOLUME_NAME] = self.volume.size
self._smbfs_driver._allocation_data = fake_alloc_data self._smbfs_driver._allocation_data = fake_alloc_data
self._smbfs_driver.update_disk_allocation_data(self._FAKE_VOLUME, self._smbfs_driver.update_disk_allocation_data(self.volume,
virtual_size_gb) virtual_size_gb)
vol_allocated_size = fake_alloc_data[self._FAKE_SHARE_HASH].get( vol_allocated_size = fake_alloc_data[self._FAKE_SHARE_HASH].get(
self._FAKE_VOLUME_NAME, None) self._FAKE_VOLUME_NAME, None)
if not virtual_size_gb: if not virtual_size_gb:
expected_total_allocated = (self._FAKE_TOTAL_ALLOCATED - expected_total_allocated = (self._FAKE_TOTAL_ALLOCATED -
self._FAKE_VOLUME['size']) self.volume.size)
self.assertIsNone(vol_allocated_size) self.assertIsNone(vol_allocated_size)
else: else:
expected_total_allocated = (self._FAKE_TOTAL_ALLOCATED + expected_total_allocated = (self._FAKE_TOTAL_ALLOCATED +
virtual_size_gb - virtual_size_gb -
self._FAKE_VOLUME['size']) self.volume.size)
self.assertEqual(virtual_size_gb, vol_allocated_size) self.assertEqual(virtual_size_gb, vol_allocated_size)
update_func.assert_called_once_with() update_func.assert_called_once_with()
@ -168,11 +175,11 @@ class SmbFsTestCase(test.TestCase):
def test_update_allocation_data_volume_extended(self): def test_update_allocation_data_volume_extended(self):
self._test_update_allocation_data( self._test_update_allocation_data(
virtual_size_gb=self._FAKE_VOLUME['size'] + 1) virtual_size_gb=self.volume.size + 1)
def test_update_allocation_data_volume_created(self): def test_update_allocation_data_volume_created(self):
self._test_update_allocation_data( self._test_update_allocation_data(
virtual_size_gb=self._FAKE_VOLUME['size']) virtual_size_gb=self.volume.size)
@requires_allocation_data_update(expected_size=None) @requires_allocation_data_update(expected_size=None)
def test_delete_volume(self): def test_delete_volume(self):
@ -191,7 +198,7 @@ class SmbFsTestCase(test.TestCase):
return_value=fake_vol_info) return_value=fake_vol_info)
with mock.patch('os.path.exists', lambda x: True): with mock.patch('os.path.exists', lambda x: True):
drv.delete_volume(self._FAKE_VOLUME) drv.delete_volume(self.volume)
fake_ensure_mounted.assert_called_once_with(self._FAKE_SHARE) fake_ensure_mounted.assert_called_once_with(self._FAKE_SHARE)
drv._delete.assert_any_call( drv._delete.assert_any_call(
@ -266,12 +273,12 @@ class SmbFsTestCase(test.TestCase):
if volume_exists: if volume_exists:
self.assertRaises(exception.InvalidVolume, self.assertRaises(exception.InvalidVolume,
self._smbfs_driver._do_create_volume, self._smbfs_driver._do_create_volume,
self._FAKE_VOLUME) self.volume)
return return
self._smbfs_driver._do_create_volume(self._FAKE_VOLUME) self._smbfs_driver._do_create_volume(self.volume)
expected_create_args = [mock.sentinel.vol_path, expected_create_args = [mock.sentinel.vol_path,
self._FAKE_VOLUME['size']] self.volume.size]
if volume_format in [self._smbfs_driver._DISK_FORMAT_VHDX, if volume_format in [self._smbfs_driver._DISK_FORMAT_VHDX,
self._smbfs_driver._DISK_FORMAT_VHD]: self._smbfs_driver._DISK_FORMAT_VHD]:
expected_create_args.append(volume_format) expected_create_args.append(volume_format)
@ -320,14 +327,14 @@ class SmbFsTestCase(test.TestCase):
if not mounted_shares: if not mounted_shares:
self.assertRaises(exception.SmbfsNoSharesMounted, self.assertRaises(exception.SmbfsNoSharesMounted,
self._smbfs_driver._find_share, self._smbfs_driver._find_share,
self._FAKE_VOLUME['size']) self.volume.size)
elif not eligible_shares: elif not eligible_shares:
self.assertRaises(exception.SmbfsNoSuitableShareFound, self.assertRaises(exception.SmbfsNoSuitableShareFound,
self._smbfs_driver._find_share, self._smbfs_driver._find_share,
self._FAKE_VOLUME['size']) self.volume.size)
else: else:
ret_value = self._smbfs_driver._find_share( ret_value = self._smbfs_driver._find_share(
self._FAKE_VOLUME['size']) self.volume.size)
# The eligible share with the minimum allocated space # The eligible share with the minimum allocated space
# will be selected # will be selected
self.assertEqual('fake_share3', ret_value) self.assertEqual('fake_share3', ret_value)
@ -404,12 +411,12 @@ class SmbFsTestCase(test.TestCase):
expected_vol_path if volume_exists else None) expected_vol_path if volume_exists else None)
mock_get_volume_format.return_value = volume_format mock_get_volume_format.return_value = volume_format
ret_val = drv.local_path(self._FAKE_VOLUME) ret_val = drv.local_path(self.volume)
if volume_exists: if volume_exists:
self.assertFalse(mock_get_volume_format.called) self.assertFalse(mock_get_volume_format.called)
else: else:
mock_get_volume_format.assert_called_once_with(self._FAKE_VOLUME) mock_get_volume_format.assert_called_once_with(self.volume)
self.assertEqual(expected_vol_path, ret_val) self.assertEqual(expected_vol_path, ret_val)
def test_get_existing_volume_path(self): def test_get_existing_volume_path(self):
@ -422,7 +429,7 @@ class SmbFsTestCase(test.TestCase):
def test_get_local_volume_path_template(self, mock_get_local_dir): def test_get_local_volume_path_template(self, mock_get_local_dir):
mock_get_local_dir.return_value = self._FAKE_MNT_POINT mock_get_local_dir.return_value = self._FAKE_MNT_POINT
ret_val = self._smbfs_driver._get_local_volume_path_template( ret_val = self._smbfs_driver._get_local_volume_path_template(
self._FAKE_VOLUME) self.volume)
self.assertEqual(self._FAKE_VOLUME_PATH, ret_val) self.assertEqual(self._FAKE_VOLUME_PATH, ret_val)
@mock.patch('os.path.exists') @mock.patch('os.path.exists')
@ -457,7 +464,7 @@ class SmbFsTestCase(test.TestCase):
mock_qemu_img_info.return_value.file_format = volume_format mock_qemu_img_info.return_value.file_format = volume_format
mock_get_format_spec.return_value = volume_format mock_get_format_spec.return_value = volume_format
ret_val = self._smbfs_driver.get_volume_format(self._FAKE_VOLUME, ret_val = self._smbfs_driver.get_volume_format(self.volume,
qemu_format) qemu_format)
if volume_exists: if volume_exists:
@ -465,7 +472,7 @@ class SmbFsTestCase(test.TestCase):
self._FAKE_VOLUME_NAME) self._FAKE_VOLUME_NAME)
self.assertFalse(mock_get_format_spec.called) self.assertFalse(mock_get_format_spec.called)
else: else:
mock_get_format_spec.assert_called_once_with(self._FAKE_VOLUME) mock_get_format_spec.assert_called_once_with(self.volume)
self.assertFalse(mock_qemu_img_info.called) self.assertFalse(mock_qemu_img_info.called)
return ret_val return ret_val
@ -506,7 +513,7 @@ class SmbFsTestCase(test.TestCase):
'data': fake_data, 'data': fake_data,
'mount_point_base': self._FAKE_MNT_BASE} 'mount_point_base': self._FAKE_MNT_BASE}
ret_val = self._smbfs_driver.initialize_connection( ret_val = self._smbfs_driver.initialize_connection(
self._FAKE_VOLUME, None) self.volume, None)
self.assertEqual(expected, ret_val) self.assertEqual(expected, ret_val)
@ -529,9 +536,9 @@ class SmbFsTestCase(test.TestCase):
if extend_failed: if extend_failed:
self.assertRaises(exception.ExtendVolumeError, self.assertRaises(exception.ExtendVolumeError,
drv.extend_volume, drv.extend_volume,
self._FAKE_VOLUME, mock.sentinel.new_size) self.volume, mock.sentinel.new_size)
else: else:
drv.extend_volume(self._FAKE_VOLUME, mock.sentinel.new_size) drv.extend_volume(self.volume, mock.sentinel.new_size)
if image_format in (drv._DISK_FORMAT_VHDX, if image_format in (drv._DISK_FORMAT_VHDX,
drv._DISK_FORMAT_VHD_LEGACY): drv._DISK_FORMAT_VHD_LEGACY):
@ -576,14 +583,14 @@ class SmbFsTestCase(test.TestCase):
if has_snapshots: if has_snapshots:
self.assertRaises(exception.InvalidVolume, self.assertRaises(exception.InvalidVolume,
self._smbfs_driver._check_extend_volume_support, self._smbfs_driver._check_extend_volume_support,
self._FAKE_VOLUME, 2) self.volume, 2)
elif not is_eligible: elif not is_eligible:
self.assertRaises(exception.ExtendVolumeError, self.assertRaises(exception.ExtendVolumeError,
self._smbfs_driver._check_extend_volume_support, self._smbfs_driver._check_extend_volume_support,
self._FAKE_VOLUME, 2) self.volume, 2)
else: else:
self._smbfs_driver._check_extend_volume_support( self._smbfs_driver._check_extend_volume_support(
self._FAKE_VOLUME, 2) self.volume, 2)
self._smbfs_driver._is_share_eligible.assert_called_once_with( self._smbfs_driver._is_share_eligible.assert_called_once_with(
self._FAKE_SHARE, 1) self._FAKE_SHARE, 1)
@ -596,35 +603,35 @@ class SmbFsTestCase(test.TestCase):
def test_check_extend_volume_uneligible_share(self): def test_check_extend_volume_uneligible_share(self):
self._test_check_extend_support(is_eligible=False) self._test_check_extend_support(is_eligible=False)
@requires_allocation_data_update(expected_size=_FAKE_VOLUME['size']) @requires_allocation_data_update(expected_size=_FAKE_VOLUME_SIZE)
@mock.patch.object(remotefs.RemoteFSSnapDriver, 'create_volume') @mock.patch.object(remotefs.RemoteFSSnapDriver, 'create_volume')
def test_create_volume_base(self, mock_create_volume): def test_create_volume_base(self, mock_create_volume):
self._smbfs_driver.create_volume(self._FAKE_VOLUME) self._smbfs_driver.create_volume(self.volume)
mock_create_volume.assert_called_once_with(self._FAKE_VOLUME) mock_create_volume.assert_called_once_with(self.volume)
@requires_allocation_data_update(expected_size=_FAKE_VOLUME['size']) @requires_allocation_data_update(expected_size=_FAKE_VOLUME_SIZE)
@mock.patch.object(smbfs.SmbfsDriver, @mock.patch.object(smbfs.SmbfsDriver,
'_create_volume_from_snapshot') '_create_volume_from_snapshot')
def test_create_volume_from_snapshot(self, mock_create_volume): def test_create_volume_from_snapshot(self, mock_create_volume):
self._smbfs_driver.create_volume_from_snapshot(self._FAKE_VOLUME, self._smbfs_driver.create_volume_from_snapshot(self.volume,
self._FAKE_SNAPSHOT) self.snapshot)
mock_create_volume.assert_called_once_with(self._FAKE_VOLUME, mock_create_volume.assert_called_once_with(self.volume,
self._FAKE_SNAPSHOT) self.snapshot)
@requires_allocation_data_update(expected_size=_FAKE_VOLUME['size']) @requires_allocation_data_update(expected_size=_FAKE_VOLUME_SIZE)
@mock.patch.object(smbfs.SmbfsDriver, '_create_cloned_volume') @mock.patch.object(smbfs.SmbfsDriver, '_create_cloned_volume')
def test_create_cloned_volume(self, mock_create_volume): def test_create_cloned_volume(self, mock_create_volume):
self._smbfs_driver.create_cloned_volume(self._FAKE_VOLUME, self._smbfs_driver.create_cloned_volume(self.volume,
mock.sentinel.src_vol) mock.sentinel.src_vol)
mock_create_volume.assert_called_once_with(self._FAKE_VOLUME, mock_create_volume.assert_called_once_with(self.volume,
mock.sentinel.src_vol) mock.sentinel.src_vol)
def test_create_volume_from_in_use_snapshot(self): def test_create_volume_from_unavailable_snapshot(self):
fake_snapshot = {'status': 'in-use'} self.snapshot.status = 'error'
self.assertRaises( self.assertRaises(
exception.InvalidSnapshot, exception.InvalidSnapshot,
self._smbfs_driver.create_volume_from_snapshot, self._smbfs_driver.create_volume_from_snapshot,
self._FAKE_VOLUME, fake_snapshot) self.volume, self.snapshot)
def test_copy_volume_from_snapshot(self): def test_copy_volume_from_snapshot(self):
drv = self._smbfs_driver drv = self._smbfs_driver
@ -651,10 +658,10 @@ class SmbFsTestCase(test.TestCase):
with mock.patch.object(image_utils, 'convert_image') as ( with mock.patch.object(image_utils, 'convert_image') as (
fake_convert_image): fake_convert_image):
drv._copy_volume_from_snapshot( drv._copy_volume_from_snapshot(
self._FAKE_SNAPSHOT, self._FAKE_VOLUME, self.snapshot, self.volume,
self._FAKE_VOLUME['size']) self.volume.size)
drv._extend_volume.assert_called_once_with( drv._extend_volume.assert_called_once_with(
self._FAKE_VOLUME, self._FAKE_VOLUME['size']) self.volume, self.volume.size)
fake_convert_image.assert_called_once_with( fake_convert_image.assert_called_once_with(
self._FAKE_VOLUME_PATH, self._FAKE_VOLUME_PATH[:-1], 'raw') self._FAKE_VOLUME_PATH, self._FAKE_VOLUME_PATH[:-1], 'raw')
@ -668,7 +675,7 @@ class SmbFsTestCase(test.TestCase):
def _test_copy_image_to_volume(self, wrong_size_after_fetch=False): def _test_copy_image_to_volume(self, wrong_size_after_fetch=False):
drv = self._smbfs_driver drv = self._smbfs_driver
vol_size_bytes = self._FAKE_VOLUME['size'] << 30 vol_size_bytes = self.volume.size << 30
fake_img_info = mock.MagicMock() fake_img_info = mock.MagicMock()
@ -696,12 +703,12 @@ class SmbFsTestCase(test.TestCase):
self.assertRaises( self.assertRaises(
exception.ImageUnacceptable, exception.ImageUnacceptable,
drv.copy_image_to_volume, drv.copy_image_to_volume,
mock.sentinel.context, self._FAKE_VOLUME, mock.sentinel.context, self.volume,
mock.sentinel.image_service, mock.sentinel.image_service,
mock.sentinel.image_id) mock.sentinel.image_id)
else: else:
drv.copy_image_to_volume( drv.copy_image_to_volume(
mock.sentinel.context, self._FAKE_VOLUME, mock.sentinel.context, self.volume,
mock.sentinel.image_service, mock.sentinel.image_service,
mock.sentinel.image_id) mock.sentinel.image_id)
fake_fetch.assert_called_once_with( fake_fetch.assert_called_once_with(
@ -711,8 +718,8 @@ class SmbFsTestCase(test.TestCase):
mock.sentinel.block_size) mock.sentinel.block_size)
drv._do_extend_volume.assert_called_once_with( drv._do_extend_volume.assert_called_once_with(
self._FAKE_VOLUME_PATH, self._FAKE_VOLUME_PATH,
self._FAKE_VOLUME['size'], self.volume.size,
self._FAKE_VOLUME['name']) self.volume.name)
def test_copy_image_to_volume(self): def test_copy_image_to_volume(self):
self._test_copy_image_to_volume() self._test_copy_image_to_volume()
@ -740,43 +747,34 @@ class SmbFsTestCase(test.TestCase):
self._FAKE_TOTAL_ALLOCATED) self._FAKE_TOTAL_ALLOCATED)
self.assertEqual(expected, ret_val) self.assertEqual(expected, ret_val)
@ddt.data([True, False, False], @ddt.data([False, False],
[False, False, False], [True, True],
[True, True, True], [False, True])
[False, True, True],
[False, False, True],
[True, False, True])
@ddt.unpack @ddt.unpack
def test_get_volume_format_spec(self, volume_versioned_object, def test_get_volume_format_spec(self,
volume_meta_contains_fmt, volume_meta_contains_fmt,
volume_type_contains_fmt): volume_type_contains_fmt):
self._smbfs_driver.configuration = copy.copy(self._FAKE_SMBFS_CONFIG)
fake_vol_meta_fmt = 'vhd' fake_vol_meta_fmt = 'vhd'
fake_vol_type_fmt = 'vhdx' fake_vol_type_fmt = 'vhdx'
volume_metadata = {} volume_metadata = {}
volume_type_extra_specs = {} volume_type_extra_specs = {}
fake_vol_dict = fake_volume.fake_db_volume()
del fake_vol_dict['name']
if volume_meta_contains_fmt: if volume_meta_contains_fmt:
volume_metadata['volume_format'] = fake_vol_meta_fmt volume_metadata['volume_format'] = fake_vol_meta_fmt
elif volume_type_contains_fmt: elif volume_type_contains_fmt:
volume_type_extra_specs['smbfs:volume_format'] = fake_vol_type_fmt volume_type_extra_specs['volume_format'] = fake_vol_type_fmt
ctxt = context.get_admin_context() volume_type = fake_volume.fake_volume_type_obj(self.context)
volume_type = db.volume_type_create( volume = fake_volume.fake_volume_obj(self.context)
ctxt, {'extra_specs': volume_type_extra_specs, # Optional arguments are not set in _from_db_object,
'name': 'fake_vol_type'}) # so have to set explicitly here
fake_vol_dict.update(metadata=volume_metadata, volume.volume_type = volume_type
volume_type_id=volume_type.id) volume.metadata = volume_metadata
# We want to get a 'real' SqlA model object, not just a dict. # Same for extra_specs and VolumeType
volume = db.volume_create(ctxt, fake_vol_dict) volume_type.extra_specs = volume_type_extra_specs
volume = db.volume_get(ctxt, volume.id)
if volume_versioned_object:
volume = objects.Volume._from_db_object(ctxt, objects.Volume(),
volume)
resulted_fmt = self._smbfs_driver._get_volume_format_spec(volume) resulted_fmt = self._smbfs_driver._get_volume_format_spec(volume)
@ -785,6 +783,6 @@ class SmbFsTestCase(test.TestCase):
elif volume_type_contains_fmt: elif volume_type_contains_fmt:
expected_fmt = fake_vol_type_fmt expected_fmt = fake_vol_type_fmt
else: else:
expected_fmt = None expected_fmt = self._FAKE_SMBFS_CONFIG.smbfs_default_volume_format
self.assertEqual(expected_fmt, resulted_fmt) self.assertEqual(expected_fmt, resulted_fmt)

View File

@ -21,9 +21,12 @@ import mock
from os_brick.remotefs import remotefs from os_brick.remotefs import remotefs
from oslo_utils import units from oslo_utils import units
from cinder import context
from cinder import exception from cinder import exception
from cinder.image import image_utils from cinder.image import image_utils
from cinder import test from cinder import test
from cinder.tests.unit import fake_snapshot
from cinder.tests.unit import fake_volume
from cinder.volume.drivers import vzstorage from cinder.volume.drivers import vzstorage
@ -37,24 +40,16 @@ class VZStorageTestCase(test.TestCase):
_FAKE_MNT_POINT = os.path.join(_FAKE_MNT_BASE, 'fake_hash') _FAKE_MNT_POINT = os.path.join(_FAKE_MNT_BASE, 'fake_hash')
_FAKE_VOLUME_NAME = 'volume-4f711859-4928-4cb7-801a-a50c37ceaccc' _FAKE_VOLUME_NAME = 'volume-4f711859-4928-4cb7-801a-a50c37ceaccc'
_FAKE_VOLUME_PATH = os.path.join(_FAKE_MNT_POINT, _FAKE_VOLUME_NAME) _FAKE_VOLUME_PATH = os.path.join(_FAKE_MNT_POINT, _FAKE_VOLUME_NAME)
_FAKE_VOLUME = {'id': '4f711859-4928-4cb7-801a-a50c37ceaccc', _FAKE_SNAPSHOT_ID = '50811859-4928-4cb7-801a-a50c37ceacba'
'size': 1,
'provider_location': _FAKE_SHARE,
'name': _FAKE_VOLUME_NAME,
'status': 'available'}
_FAKE_SNAPSHOT_ID = '5g811859-4928-4cb7-801a-a50c37ceacba'
_FAKE_SNAPSHOT_PATH = ( _FAKE_SNAPSHOT_PATH = (
_FAKE_VOLUME_PATH + '-snapshot' + _FAKE_SNAPSHOT_ID) _FAKE_VOLUME_PATH + '-snapshot' + _FAKE_SNAPSHOT_ID)
_FAKE_SNAPSHOT = {'id': _FAKE_SNAPSHOT_ID,
'volume': _FAKE_VOLUME,
'status': 'available',
'volume_size': 1}
_FAKE_VZ_CONFIG = mock.MagicMock() _FAKE_VZ_CONFIG = mock.MagicMock()
_FAKE_VZ_CONFIG.vzstorage_shares_config = '/fake/config/path' _FAKE_VZ_CONFIG.vzstorage_shares_config = '/fake/config/path'
_FAKE_VZ_CONFIG.vzstorage_sparsed_volumes = False _FAKE_VZ_CONFIG.vzstorage_sparsed_volumes = False
_FAKE_VZ_CONFIG.vzstorage_used_ratio = 0.7 _FAKE_VZ_CONFIG.vzstorage_used_ratio = 0.7
_FAKE_VZ_CONFIG.vzstorage_mount_point_base = _FAKE_MNT_BASE _FAKE_VZ_CONFIG.vzstorage_mount_point_base = _FAKE_MNT_BASE
_FAKE_VZ_CONFIG.vzstorage_default_volume_format = 'raw'
_FAKE_VZ_CONFIG.nas_secure_file_operations = 'auto' _FAKE_VZ_CONFIG.nas_secure_file_operations = 'auto'
_FAKE_VZ_CONFIG.nas_secure_file_permissions = 'auto' _FAKE_VZ_CONFIG.nas_secure_file_permissions = 'auto'
@ -72,6 +67,26 @@ class VZStorageTestCase(test.TestCase):
self._vz_driver._execute = mock.Mock() self._vz_driver._execute = mock.Mock()
self._vz_driver.base = self._FAKE_MNT_BASE self._vz_driver.base = self._FAKE_MNT_BASE
self.context = context.get_admin_context()
vol_type = fake_volume.fake_volume_type_obj(self.context)
vol_type.extra_specs = {}
_FAKE_VOLUME = {'id': '4f711859-4928-4cb7-801a-a50c37ceaccc',
'size': 1,
'provider_location': self._FAKE_SHARE,
'name': self._FAKE_VOLUME_NAME,
'status': 'available'}
self.vol = fake_volume.fake_volume_obj(self.context,
volume_type_id=vol_type.id,
**_FAKE_VOLUME)
self.vol.volume_type = vol_type
_FAKE_SNAPSHOT = {'id': self._FAKE_SNAPSHOT_ID,
'status': 'available',
'volume_size': 1}
self.snap = fake_snapshot.fake_snapshot_obj(self.context,
**_FAKE_SNAPSHOT)
self.snap.volume = self.vol
def _path_exists(self, path): def _path_exists(self, path):
if path.startswith(self._FAKE_VZ_CONFIG.vzstorage_shares_config): if path.startswith(self._FAKE_VZ_CONFIG.vzstorage_shares_config):
return True return True
@ -135,9 +150,13 @@ class VZStorageTestCase(test.TestCase):
file_format = 'raw' file_format = 'raw'
info = mock.Mock() info = mock.Mock()
info.file_format = file_format info.file_format = file_format
snap_info = """{"volume_format": "raw",
"active": "%s"}""" % self.vol.id
with mock.patch.object(drv, '_qemu_img_info', return_value=info): with mock.patch.object(drv, '_qemu_img_info', return_value=info):
ret = drv.initialize_connection(self._FAKE_VOLUME, None) with mock.patch.object(drv, '_read_file',
name = drv.get_active_image_from_info(self._FAKE_VOLUME) return_value=snap_info):
ret = drv.initialize_connection(self.vol, None)
name = drv.get_active_image_from_info(self.vol)
expected = {'driver_volume_type': 'vzstorage', expected = {'driver_volume_type': 'vzstorage',
'data': {'export': self._FAKE_SHARE, 'data': {'export': self._FAKE_SHARE,
'format': file_format, 'format': file_format,
@ -197,9 +216,13 @@ class VZStorageTestCase(test.TestCase):
drv._check_extend_volume_support = mock.Mock(return_value=True) drv._check_extend_volume_support = mock.Mock(return_value=True)
drv._is_file_size_equal = mock.Mock(return_value=True) drv._is_file_size_equal = mock.Mock(return_value=True)
snap_info = """{"volume_format": "raw",
"active": "%s"}""" % self.vol.id
with mock.patch.object(drv, 'local_path', with mock.patch.object(drv, 'local_path',
return_value=self._FAKE_VOLUME_PATH): return_value=self._FAKE_VOLUME_PATH):
drv.extend_volume(self._FAKE_VOLUME, 10) with mock.patch.object(drv, '_read_file',
return_value=snap_info):
drv.extend_volume(self.vol, 10)
mock_resize_image.assert_called_once_with(self._FAKE_VOLUME_PATH, 10) mock_resize_image.assert_called_once_with(self._FAKE_VOLUME_PATH, 10)
@ -218,13 +241,13 @@ class VZStorageTestCase(test.TestCase):
if has_snapshots: if has_snapshots:
self.assertRaises(exception.InvalidVolume, self.assertRaises(exception.InvalidVolume,
drv._check_extend_volume_support, drv._check_extend_volume_support,
self._FAKE_VOLUME, 2) self.vol, 2)
elif not is_eligible: elif not is_eligible:
self.assertRaises(exception.ExtendVolumeError, self.assertRaises(exception.ExtendVolumeError,
drv._check_extend_volume_support, drv._check_extend_volume_support,
self._FAKE_VOLUME, 2) self.vol, 2)
else: else:
drv._check_extend_volume_support(self._FAKE_VOLUME, 2) drv._check_extend_volume_support(self.vol, 2)
drv._is_share_eligible.assert_called_once_with(self._FAKE_SHARE, 1) drv._is_share_eligible.assert_called_once_with(self._FAKE_SHARE, 1)
def test_check_extend_support(self): def test_check_extend_support(self):
@ -258,10 +281,10 @@ class VZStorageTestCase(test.TestCase):
drv._extend_volume = mock.Mock() drv._extend_volume = mock.Mock()
drv._copy_volume_from_snapshot( drv._copy_volume_from_snapshot(
self._FAKE_SNAPSHOT, self._FAKE_VOLUME, self.snap, self.vol,
self._FAKE_VOLUME['size']) self.vol['size'])
drv._extend_volume.assert_called_once_with( drv._extend_volume.assert_called_once_with(
self._FAKE_VOLUME, self._FAKE_VOLUME['size']) self.vol, self.vol['size'])
mock_convert_image.assert_called_once_with( mock_convert_image.assert_called_once_with(
self._FAKE_VOLUME_PATH, self._FAKE_VOLUME_PATH[:-1], 'raw') self._FAKE_VOLUME_PATH, self._FAKE_VOLUME_PATH[:-1], 'raw')
@ -281,7 +304,7 @@ class VZStorageTestCase(test.TestCase):
return_value=fake_vol_info) return_value=fake_vol_info)
with mock.patch('os.path.exists', lambda x: True): with mock.patch('os.path.exists', lambda x: True):
drv.delete_volume(self._FAKE_VOLUME) drv.delete_volume(self.vol)
fake_ensure_mounted.assert_called_once_with(self._FAKE_SHARE) fake_ensure_mounted.assert_called_once_with(self._FAKE_SHARE)
drv._delete.assert_any_call( drv._delete.assert_any_call(

View File

@ -17,9 +17,12 @@ import os
import mock import mock
from oslo_utils import units from oslo_utils import units
from cinder import context
from cinder import exception from cinder import exception
from cinder.image import image_utils from cinder.image import image_utils
from cinder import test from cinder import test
from cinder.tests.unit import fake_snapshot
from cinder.tests.unit import fake_volume
from cinder.volume.drivers.windows import smbfs from cinder.volume.drivers.windows import smbfs
@ -35,12 +38,6 @@ class WindowsSmbFsTestCase(test.TestCase):
_FAKE_TOTAL_SIZE = '2048' _FAKE_TOTAL_SIZE = '2048'
_FAKE_TOTAL_AVAILABLE = '1024' _FAKE_TOTAL_AVAILABLE = '1024'
_FAKE_TOTAL_ALLOCATED = 1024 _FAKE_TOTAL_ALLOCATED = 1024
_FAKE_VOLUME = {'id': 'e8d76af4-cbb9-4b70-8e9e-5a133f1a1a66',
'size': 1,
'provider_location': _FAKE_SHARE}
_FAKE_SNAPSHOT = {'id': '35a23942-7625-4683-ad84-144b76e87a80',
'volume': _FAKE_VOLUME,
'volume_size': _FAKE_VOLUME['size']}
_FAKE_SHARE_OPTS = '-o username=Administrator,password=12345' _FAKE_SHARE_OPTS = '-o username=Administrator,password=12345'
_FAKE_VOLUME_PATH = os.path.join(_FAKE_MNT_POINT, _FAKE_VOLUME_PATH = os.path.join(_FAKE_MNT_POINT,
_FAKE_VOLUME_NAME + '.vhdx') _FAKE_VOLUME_NAME + '.vhdx')
@ -56,6 +53,25 @@ class WindowsSmbFsTestCase(test.TestCase):
self._smbfs_driver.local_path = mock.Mock( self._smbfs_driver.local_path = mock.Mock(
return_value=self._FAKE_VOLUME_PATH) return_value=self._FAKE_VOLUME_PATH)
def _simple_volume(self, **kwargs):
updates = {'id': 'e8d76af4-cbb9-4b70-8e9e-5a133f1a1a66',
'size': 1,
'provider_location': self._FAKE_SHARE}
updates.update(kwargs)
ctxt = context.get_admin_context()
return fake_volume.fake_volume_obj(ctxt, **updates)
def _simple_snapshot(self, **kwargs):
volume = self._simple_volume()
ctxt = context.get_admin_context()
updates = {'id': '35a23942-7625-4683-ad84-144b76e87a80',
'volume_size': volume.size,
'volume_id': volume.id}
updates.update(kwargs)
snapshot = fake_snapshot.fake_snapshot_obj(ctxt, **updates)
snapshot.volume = volume
return snapshot
def _test_create_volume(self, volume_exists=False, volume_format='vhdx'): def _test_create_volume(self, volume_exists=False, volume_format='vhdx'):
self._smbfs_driver.create_dynamic_vhd = mock.MagicMock() self._smbfs_driver.create_dynamic_vhd = mock.MagicMock()
fake_create = self._smbfs_driver._vhdutils.create_dynamic_vhd fake_create = self._smbfs_driver._vhdutils.create_dynamic_vhd
@ -63,15 +79,16 @@ class WindowsSmbFsTestCase(test.TestCase):
return_value=volume_format) return_value=volume_format)
with mock.patch('os.path.exists', new=lambda x: volume_exists): with mock.patch('os.path.exists', new=lambda x: volume_exists):
volume = self._simple_volume()
if volume_exists or volume_format not in ('vhd', 'vhdx'): if volume_exists or volume_format not in ('vhd', 'vhdx'):
self.assertRaises(exception.InvalidVolume, self.assertRaises(exception.InvalidVolume,
self._smbfs_driver._do_create_volume, self._smbfs_driver._do_create_volume,
self._FAKE_VOLUME) volume)
else: else:
fake_vol_path = self._FAKE_VOLUME_PATH fake_vol_path = self._FAKE_VOLUME_PATH
self._smbfs_driver._do_create_volume(self._FAKE_VOLUME) self._smbfs_driver._do_create_volume(volume)
fake_create.assert_called_once_with( fake_create.assert_called_once_with(
fake_vol_path, self._FAKE_VOLUME['size'] << 30) fake_vol_path, volume.size << 30)
def test_create_volume(self): def test_create_volume(self):
self._test_create_volume() self._test_create_volume()
@ -120,7 +137,7 @@ class WindowsSmbFsTestCase(test.TestCase):
self._smbfs_driver._vhdutils.create_differencing_vhd) self._smbfs_driver._vhdutils.create_differencing_vhd)
self._smbfs_driver._do_create_snapshot( self._smbfs_driver._do_create_snapshot(
self._FAKE_SNAPSHOT, self._simple_snapshot(),
os.path.basename(self._FAKE_VOLUME_PATH), os.path.basename(self._FAKE_VOLUME_PATH),
self._FAKE_SNAPSHOT_PATH) self._FAKE_SNAPSHOT_PATH)
@ -156,8 +173,9 @@ class WindowsSmbFsTestCase(test.TestCase):
with mock.patch.object(image_utils, 'upload_volume') as ( with mock.patch.object(image_utils, 'upload_volume') as (
fake_upload_volume): fake_upload_volume):
volume = self._simple_volume()
drv.copy_volume_to_image( drv.copy_volume_to_image(
mock.sentinel.context, self._FAKE_VOLUME, mock.sentinel.context, volume,
mock.sentinel.image_service, fake_image_meta) mock.sentinel.image_service, fake_image_meta)
expected_conversion = ( expected_conversion = (
@ -165,7 +183,7 @@ class WindowsSmbFsTestCase(test.TestCase):
if expected_conversion: if expected_conversion:
fake_temp_image_name = '%s.temp_image.%s.%s' % ( fake_temp_image_name = '%s.temp_image.%s.%s' % (
self._FAKE_VOLUME['id'], volume.id,
fake_image_meta['id'], fake_image_meta['id'],
drv._DISK_FORMAT_VHD) drv._DISK_FORMAT_VHD)
fake_temp_image_path = os.path.join( fake_temp_image_path = os.path.join(
@ -209,8 +227,9 @@ class WindowsSmbFsTestCase(test.TestCase):
with mock.patch.object(image_utils, with mock.patch.object(image_utils,
'fetch_to_volume_format') as fake_fetch: 'fetch_to_volume_format') as fake_fetch:
volume = self._simple_volume()
drv.copy_image_to_volume( drv.copy_image_to_volume(
mock.sentinel.context, self._FAKE_VOLUME, mock.sentinel.context, volume,
mock.sentinel.image_service, mock.sentinel.image_service,
mock.sentinel.image_id) mock.sentinel.image_id)
fake_fetch.assert_called_once_with( fake_fetch.assert_called_once_with(
@ -221,13 +240,14 @@ class WindowsSmbFsTestCase(test.TestCase):
mock.sentinel.block_size) mock.sentinel.block_size)
drv._vhdutils.resize_vhd.assert_called_once_with( drv._vhdutils.resize_vhd.assert_called_once_with(
self._FAKE_VOLUME_PATH, self._FAKE_VOLUME_PATH,
self._FAKE_VOLUME['size'] * units.Gi, volume.size * units.Gi,
is_file_max_size=False) is_file_max_size=False)
def test_copy_volume_from_snapshot(self): def test_copy_volume_from_snapshot(self):
drv = self._smbfs_driver drv = self._smbfs_driver
snapshot = self._simple_snapshot()
fake_volume_info = { fake_volume_info = {
self._FAKE_SNAPSHOT['id']: 'fake_snapshot_file_name'} snapshot.id: 'fake_snapshot_file_name'}
fake_img_info = mock.MagicMock() fake_img_info = mock.MagicMock()
fake_img_info.backing_file = self._FAKE_VOLUME_NAME + '.vhdx' fake_img_info.backing_file = self._FAKE_VOLUME_NAME + '.vhdx'
@ -242,9 +262,9 @@ class WindowsSmbFsTestCase(test.TestCase):
drv.local_path = mock.Mock( drv.local_path = mock.Mock(
return_value=mock.sentinel.new_volume_path) return_value=mock.sentinel.new_volume_path)
drv._copy_volume_from_snapshot( volume = self._simple_volume()
self._FAKE_SNAPSHOT, self._FAKE_VOLUME, drv._copy_volume_from_snapshot(snapshot,
self._FAKE_VOLUME['size']) volume, volume.size)
drv._delete.assert_called_once_with(mock.sentinel.new_volume_path) drv._delete.assert_called_once_with(mock.sentinel.new_volume_path)
drv._vhdutils.convert_vhd.assert_called_once_with( drv._vhdutils.convert_vhd.assert_called_once_with(
@ -252,7 +272,7 @@ class WindowsSmbFsTestCase(test.TestCase):
mock.sentinel.new_volume_path) mock.sentinel.new_volume_path)
drv._vhdutils.resize_vhd.assert_called_once_with( drv._vhdutils.resize_vhd.assert_called_once_with(
mock.sentinel.new_volume_path, mock.sentinel.new_volume_path,
self._FAKE_VOLUME['size'] * units.Gi, volume.size * units.Gi,
is_file_max_size=False) is_file_max_size=False)
def test_rebase_img(self): def test_rebase_img(self):

View File

@ -146,7 +146,7 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
pass pass
def _local_volume_dir(self, volume): def _local_volume_dir(self, volume):
hashed = self._get_hash_str(volume['provider_location']) hashed = self._get_hash_str(volume.provider_location)
path = '%s/%s' % (self.configuration.glusterfs_mount_point_base, path = '%s/%s' % (self.configuration.glusterfs_mount_point_base,
hashed) hashed)
return path return path
@ -185,13 +185,13 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
self._ensure_shares_mounted() self._ensure_shares_mounted()
volume['provider_location'] = self._find_share(volume['size']) volume.provider_location = self._find_share(volume.size)
LOG.info(_LI('casted to %s'), volume['provider_location']) LOG.info(_LI('casted to %s'), volume.provider_location)
self._do_create_volume(volume) self._do_create_volume(volume)
return {'provider_location': volume['provider_location']} return {'provider_location': volume.provider_location}
def _copy_volume_from_snapshot(self, snapshot, volume, volume_size): def _copy_volume_from_snapshot(self, snapshot, volume, volume_size):
"""Copy data from snapshot to destination volume. """Copy data from snapshot to destination volume.
@ -202,20 +202,20 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
LOG.debug("snapshot: %(snap)s, volume: %(vol)s, " LOG.debug("snapshot: %(snap)s, volume: %(vol)s, "
"volume_size: %(size)s", "volume_size: %(size)s",
{'snap': snapshot['id'], {'snap': snapshot.id,
'vol': volume['id'], 'vol': volume.id,
'size': volume_size}) 'size': volume_size})
info_path = self._local_path_volume_info(snapshot['volume']) info_path = self._local_path_volume_info(snapshot.volume)
snap_info = self._read_info_file(info_path) snap_info = self._read_info_file(info_path)
vol_path = self._local_volume_dir(snapshot['volume']) vol_path = self._local_volume_dir(snapshot.volume)
forward_file = snap_info[snapshot['id']] forward_file = snap_info[snapshot.id]
forward_path = os.path.join(vol_path, forward_file) forward_path = os.path.join(vol_path, forward_file)
# Find the file which backs this file, which represents the point # Find the file which backs this file, which represents the point
# when this snapshot was created. # when this snapshot was created.
img_info = self._qemu_img_info(forward_path, img_info = self._qemu_img_info(forward_path,
snapshot['volume']['name']) snapshot.volume.name)
path_to_snap_img = os.path.join(vol_path, img_info.backing_file) path_to_snap_img = os.path.join(vol_path, img_info.backing_file)
path_to_new_vol = self._local_path_volume(volume) path_to_new_vol = self._local_path_volume(volume)
@ -237,13 +237,13 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
def delete_volume(self, volume): def delete_volume(self, volume):
"""Deletes a logical volume.""" """Deletes a logical volume."""
if not volume['provider_location']: if not volume.provider_location:
LOG.warning(_LW('Volume %s does not have ' LOG.warning(_LW('Volume %s does not have '
'provider_location specified, ' 'provider_location specified, '
'skipping'), volume['name']) 'skipping'), volume.name)
return return
self._ensure_share_mounted(volume['provider_location']) self._ensure_share_mounted(volume.provider_location)
mounted_path = self._active_volume_path(volume) mounted_path = self._active_volume_path(volume)
@ -264,7 +264,7 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
def ensure_export(self, ctx, volume): def ensure_export(self, ctx, volume):
"""Synchronously recreates an export for a logical volume.""" """Synchronously recreates an export for a logical volume."""
self._ensure_share_mounted(volume['provider_location']) self._ensure_share_mounted(volume.provider_location)
def create_export(self, ctx, volume, connector): def create_export(self, ctx, volume, connector):
"""Exports the volume.""" """Exports the volume."""
@ -285,16 +285,16 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
# Find active qcow2 file # Find active qcow2 file
active_file = self.get_active_image_from_info(volume) active_file = self.get_active_image_from_info(volume)
path = '%s/%s/%s' % (self.configuration.glusterfs_mount_point_base, path = '%s/%s/%s' % (self.configuration.glusterfs_mount_point_base,
self._get_hash_str(volume['provider_location']), self._get_hash_str(volume.provider_location),
active_file) active_file)
data = {'export': volume['provider_location'], data = {'export': volume.provider_location,
'name': active_file} 'name': active_file}
if volume['provider_location'] in self.shares: if volume.provider_location in self.shares:
data['options'] = self.shares[volume['provider_location']] data['options'] = self.shares[volume.provider_location]
# Test file for raw vs. qcow2 format # Test file for raw vs. qcow2 format
info = self._qemu_img_info(path, volume['name']) info = self._qemu_img_info(path, volume.name)
data['format'] = info.file_format data['format'] = info.file_format
if data['format'] not in ['raw', 'qcow2']: if data['format'] not in ['raw', 'qcow2']:
msg = _('%s must be a valid raw or qcow2 image.') % path msg = _('%s must be a valid raw or qcow2 image.') % path
@ -314,7 +314,7 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
def extend_volume(self, volume, size_gb): def extend_volume(self, volume, size_gb):
volume_path = self._active_volume_path(volume) volume_path = self._active_volume_path(volume)
info = self._qemu_img_info(volume_path, volume['name']) info = self._qemu_img_info(volume_path, volume.name)
backing_fmt = info.file_format backing_fmt = info.file_format
if backing_fmt not in ['raw', 'qcow2']: if backing_fmt not in ['raw', 'qcow2']:
@ -331,7 +331,7 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
""" """
volume_path = self.local_path(volume) volume_path = self.local_path(volume)
volume_size = volume['size'] volume_size = volume.size
LOG.debug("creating new volume at %s", volume_path) LOG.debug("creating new volume at %s", volume_path)
@ -452,7 +452,7 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
active_file_path = self._active_volume_path(volume) active_file_path = self._active_volume_path(volume)
info = self._qemu_img_info(active_file_path, volume['name']) info = self._qemu_img_info(active_file_path, volume.name)
if info.backing_file is not None: if info.backing_file is not None:
LOG.error(_LE('No snapshots found in database, but %(path)s has ' LOG.error(_LE('No snapshots found in database, but %(path)s has '

View File

@ -300,13 +300,13 @@ class NfsDriver(driver.ExtendVD, remotefs.RemoteFSDriver):
def extend_volume(self, volume, new_size): def extend_volume(self, volume, new_size):
"""Extend an existing volume to the new size.""" """Extend an existing volume to the new size."""
LOG.info(_LI('Extending volume %s.'), volume['id']) LOG.info(_LI('Extending volume %s.'), volume.id)
extend_by = int(new_size) - volume['size'] extend_by = int(new_size) - volume.size
if not self._is_share_eligible(volume['provider_location'], if not self._is_share_eligible(volume.provider_location,
extend_by): extend_by):
raise exception.ExtendVolumeError(reason='Insufficient space to' raise exception.ExtendVolumeError(reason='Insufficient space to'
' extend volume %s to %sG' ' extend volume %s to %sG'
% (volume['id'], new_size)) % (volume.id, new_size))
path = self.local_path(volume) path = self.local_path(volume)
LOG.info(_LI('Resizing file to %sG...'), new_size) LOG.info(_LI('Resizing file to %sG...'), new_size)
image_utils.resize_image(path, new_size, image_utils.resize_image(path, new_size,
@ -396,8 +396,8 @@ class NfsDriver(driver.ExtendVD, remotefs.RemoteFSDriver):
# NFS snapshots are introduced. # NFS snapshots are introduced.
name_id = None name_id = None
if original_volume_status == 'available': if original_volume_status == 'available':
current_name = CONF.volume_name_template % new_volume['id'] current_name = CONF.volume_name_template % new_volume.id
original_volume_name = CONF.volume_name_template % volume['id'] original_volume_name = CONF.volume_name_template % volume.id
current_path = self.local_path(new_volume) current_path = self.local_path(new_volume)
# Replace the volume name with the original volume name # Replace the volume name with the original volume name
original_path = current_path.replace(current_name, original_path = current_path.replace(current_name,
@ -406,16 +406,16 @@ class NfsDriver(driver.ExtendVD, remotefs.RemoteFSDriver):
os.rename(current_path, original_path) os.rename(current_path, original_path)
except OSError: except OSError:
LOG.error(_LE('Unable to rename the logical volume ' LOG.error(_LE('Unable to rename the logical volume '
'for volume: %s'), volume['id']) 'for volume: %s'), volume.id)
# If the rename fails, _name_id should be set to the new # If the rename fails, _name_id should be set to the new
# volume id and provider_location should be set to the # volume id and provider_location should be set to the
# one from the new volume as well. # one from the new volume as well.
name_id = new_volume['_name_id'] or new_volume['id'] name_id = new_volume._name_id or new_volume.id
else: else:
# The back-end will not be renamed. # The back-end will not be renamed.
name_id = new_volume['_name_id'] or new_volume['id'] name_id = new_volume._name_id or new_volume.id
return {'_name_id': name_id, return {'_name_id': name_id,
'provider_location': new_volume['provider_location']} 'provider_location': new_volume.provider_location}
def _update_volume_stats(self): def _update_volume_stats(self):
"""Retrieve stats info from volume group.""" """Retrieve stats info from volume group."""

View File

@ -185,20 +185,20 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriver):
""" """
LOG.debug("snapshot: %(snap)s, volume: %(vol)s, ", LOG.debug("snapshot: %(snap)s, volume: %(vol)s, ",
{'snap': snapshot['id'], {'snap': snapshot.id,
'vol': volume['id'], 'vol': volume.id,
'size': volume_size}) 'size': volume_size})
info_path = self._local_path_volume_info(snapshot['volume']) info_path = self._local_path_volume_info(snapshot.volume)
snap_info = self._read_info_file(info_path) snap_info = self._read_info_file(info_path)
vol_path = self._local_volume_dir(snapshot['volume']) vol_path = self._local_volume_dir(snapshot.volume)
forward_file = snap_info[snapshot['id']] forward_file = snap_info[snapshot.id]
forward_path = os.path.join(vol_path, forward_file) forward_path = os.path.join(vol_path, forward_file)
# Find the file which backs this file, which represents the point # Find the file which backs this file, which represents the point
# when this snapshot was created. # when this snapshot was created.
img_info = self._qemu_img_info(forward_path, img_info = self._qemu_img_info(forward_path,
snapshot['volume']['name']) snapshot.volume.name)
path_to_snap_img = os.path.join(vol_path, img_info.backing_file) path_to_snap_img = os.path.join(vol_path, img_info.backing_file)
path_to_new_vol = self._local_path_volume(volume) path_to_new_vol = self._local_path_volume(volume)
@ -221,12 +221,12 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriver):
def delete_volume(self, volume): def delete_volume(self, volume):
"""Deletes a logical volume.""" """Deletes a logical volume."""
if not volume['provider_location']: if not volume.provider_location:
LOG.warning(_LW('Volume %s does not have provider_location ' LOG.warning(_LW('Volume %s does not have provider_location '
'specified, skipping'), volume['name']) 'specified, skipping'), volume.name)
return return
self._ensure_share_mounted(volume['provider_location']) self._ensure_share_mounted(volume.provider_location)
volume_dir = self._local_volume_dir(volume) volume_dir = self._local_volume_dir(volume)
mounted_path = os.path.join(volume_dir, mounted_path = os.path.join(volume_dir,
@ -261,16 +261,16 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriver):
# Find active qcow2 file # Find active qcow2 file
active_file = self.get_active_image_from_info(volume) active_file = self.get_active_image_from_info(volume)
path = '%s/%s/%s' % (self.configuration.quobyte_mount_point_base, path = '%s/%s/%s' % (self.configuration.quobyte_mount_point_base,
self._get_hash_str(volume['provider_location']), self._get_hash_str(volume.provider_location),
active_file) active_file)
data = {'export': volume['provider_location'], data = {'export': volume.provider_location,
'name': active_file} 'name': active_file}
if volume['provider_location'] in self.shares: if volume.provider_location in self.shares:
data['options'] = self.shares[volume['provider_location']] data['options'] = self.shares[volume.provider_location]
# Test file for raw vs. qcow2 format # Test file for raw vs. qcow2 format
info = self._qemu_img_info(path, volume['name']) info = self._qemu_img_info(path, volume.name)
data['format'] = info.file_format data['format'] = info.file_format
if data['format'] not in ['raw', 'qcow2']: if data['format'] not in ['raw', 'qcow2']:
msg = _('%s must be a valid raw or qcow2 image.') % path msg = _('%s must be a valid raw or qcow2 image.') % path
@ -299,7 +299,7 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriver):
' driver when no snapshots exist.') ' driver when no snapshots exist.')
raise exception.InvalidVolume(msg) raise exception.InvalidVolume(msg)
info = self._qemu_img_info(volume_path, volume['name']) info = self._qemu_img_info(volume_path, volume.name)
backing_fmt = info.file_format backing_fmt = info.file_format
if backing_fmt not in ['raw', 'qcow2']: if backing_fmt not in ['raw', 'qcow2']:
@ -315,7 +315,7 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriver):
:param volume: volume reference :param volume: volume reference
""" """
volume_path = self.local_path(volume) volume_path = self.local_path(volume)
volume_size = volume['size'] volume_size = volume.size
if self.configuration.quobyte_qcow2_volumes: if self.configuration.quobyte_qcow2_volumes:
self._create_qcow2_file(volume_path, volume_size) self._create_qcow2_file(volume_path, volume_size)

View File

@ -14,6 +14,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import collections
import hashlib import hashlib
import inspect import inspect
import json import json
@ -118,9 +119,9 @@ def locked_volume_id_operation(f, external=False):
call_args = inspect.getcallargs(f, inst, *args, **kwargs) call_args = inspect.getcallargs(f, inst, *args, **kwargs)
if call_args.get('volume'): if call_args.get('volume'):
volume_id = call_args['volume']['id'] volume_id = call_args['volume'].id
elif call_args.get('snapshot'): elif call_args.get('snapshot'):
volume_id = call_args['snapshot']['volume']['id'] volume_id = call_args['snapshot'].volume.id
else: else:
err_msg = _('The decorated method must accept either a volume or ' err_msg = _('The decorated method must accept either a volume or '
'a snapshot object') 'a snapshot object')
@ -163,10 +164,10 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
:param volume: volume reference :param volume: volume reference
:param connector: connector reference :param connector: connector reference
""" """
data = {'export': volume['provider_location'], data = {'export': volume.provider_location,
'name': volume['name']} 'name': volume.name}
if volume['provider_location'] in self.shares: if volume.provider_location in self.shares:
data['options'] = self.shares[volume['provider_location']] data['options'] = self.shares[volume.provider_location]
return { return {
'driver_volume_type': self.driver_volume_type, 'driver_volume_type': self.driver_volume_type,
'data': data, 'data': data,
@ -232,13 +233,13 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
""" """
self._ensure_shares_mounted() self._ensure_shares_mounted()
volume['provider_location'] = self._find_share(volume['size']) volume.provider_location = self._find_share(volume.size)
LOG.info(_LI('casted to %s'), volume['provider_location']) LOG.info(_LI('casted to %s'), volume.provider_location)
self._do_create_volume(volume) self._do_create_volume(volume)
return {'provider_location': volume['provider_location']} return {'provider_location': volume.provider_location}
def _do_create_volume(self, volume): def _do_create_volume(self, volume):
"""Create a volume on given remote share. """Create a volume on given remote share.
@ -246,7 +247,7 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
:param volume: volume reference :param volume: volume reference
""" """
volume_path = self.local_path(volume) volume_path = self.local_path(volume)
volume_size = volume['size'] volume_size = volume.size
if getattr(self.configuration, if getattr(self.configuration,
self.driver_prefix + '_sparsed_volumes'): self.driver_prefix + '_sparsed_volumes'):
@ -280,13 +281,13 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
:param volume: volume reference :param volume: volume reference
""" """
if not volume['provider_location']: if not volume.provider_location:
LOG.warning(_LW('Volume %s does not have ' LOG.warning(_LW('Volume %s does not have '
'provider_location specified, ' 'provider_location specified, '
'skipping'), volume['name']) 'skipping'), volume.name)
return return
self._ensure_share_mounted(volume['provider_location']) self._ensure_share_mounted(volume.provider_location)
mounted_path = self.local_path(volume) mounted_path = self.local_path(volume)
@ -294,7 +295,7 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
def ensure_export(self, ctx, volume): def ensure_export(self, ctx, volume):
"""Synchronously recreates an export for a logical volume.""" """Synchronously recreates an export for a logical volume."""
self._ensure_share_mounted(volume['provider_location']) self._ensure_share_mounted(volume.provider_location)
def create_export(self, ctx, volume, connector): def create_export(self, ctx, volume, connector):
"""Exports the volume. """Exports the volume.
@ -387,9 +388,9 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
:param volume: volume reference :param volume: volume reference
""" """
remotefs_share = volume['provider_location'] remotefs_share = volume.provider_location
return os.path.join(self._get_mount_point_for_share(remotefs_share), return os.path.join(self._get_mount_point_for_share(remotefs_share),
volume['name']) volume.name)
def copy_image_to_volume(self, context, volume, image_service, image_id): def copy_image_to_volume(self, context, volume, image_service, image_id):
"""Fetch the image from image_service and write it to the volume.""" """Fetch the image from image_service and write it to the volume."""
@ -400,7 +401,7 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
image_id, image_id,
self.local_path(volume), self.local_path(volume),
self.configuration.volume_dd_blocksize, self.configuration.volume_dd_blocksize,
size=volume['size'], size=volume.size,
run_as_root=run_as_root) run_as_root=run_as_root)
# NOTE (leseb): Set the virtual size of the image # NOTE (leseb): Set the virtual size of the image
@ -410,16 +411,16 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
# thus the initial 'size' parameter is not honored # thus the initial 'size' parameter is not honored
# this sets the size to the one asked in the first place by the user # this sets the size to the one asked in the first place by the user
# and then verify the final virtual size # and then verify the final virtual size
image_utils.resize_image(self.local_path(volume), volume['size'], image_utils.resize_image(self.local_path(volume), volume.size,
run_as_root=run_as_root) run_as_root=run_as_root)
data = image_utils.qemu_img_info(self.local_path(volume), data = image_utils.qemu_img_info(self.local_path(volume),
run_as_root=run_as_root) run_as_root=run_as_root)
virt_size = data.virtual_size / units.Gi virt_size = data.virtual_size / units.Gi
if virt_size != volume['size']: if virt_size != volume.size:
raise exception.ImageUnacceptable( raise exception.ImageUnacceptable(
image_id=image_id, image_id=image_id,
reason=(_("Expected volume size was %d") % volume['size']) reason=(_("Expected volume size was %d") % volume.size)
+ (_(" but size is now %d") % virt_size)) + (_(" but size is now %d") % virt_size))
def copy_volume_to_image(self, context, volume, image_service, image_meta): def copy_volume_to_image(self, context, volume, image_service, image_meta):
@ -647,20 +648,20 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
self._nova = compute.API() self._nova = compute.API()
def _local_volume_dir(self, volume): def _local_volume_dir(self, volume):
share = volume['provider_location'] share = volume.provider_location
local_dir = self._get_mount_point_for_share(share) local_dir = self._get_mount_point_for_share(share)
return local_dir return local_dir
def _local_path_volume(self, volume): def _local_path_volume(self, volume):
path_to_disk = os.path.join( path_to_disk = os.path.join(
self._local_volume_dir(volume), self._local_volume_dir(volume),
volume['name']) volume.name)
return path_to_disk return path_to_disk
def _get_new_snap_path(self, snapshot): def _get_new_snap_path(self, snapshot):
vol_path = self.local_path(snapshot['volume']) vol_path = self.local_path(snapshot.volume)
snap_path = '%s.%s' % (vol_path, snapshot['id']) snap_path = '%s.%s' % (vol_path, snapshot.id)
return snap_path return snap_path
def _local_path_volume_info(self, volume): def _local_path_volume_info(self, volume):
@ -757,7 +758,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
output = [] output = []
info = self._qemu_img_info(path, volume['name']) info = self._qemu_img_info(path, volume.name)
new_info = {} new_info = {}
new_info['filename'] = os.path.basename(path) new_info['filename'] = os.path.basename(path)
new_info['backing-filename'] = info.backing_file new_info['backing-filename'] = info.backing_file
@ -767,7 +768,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
while new_info['backing-filename']: while new_info['backing-filename']:
filename = new_info['backing-filename'] filename = new_info['backing-filename']
path = os.path.join(self._local_volume_dir(volume), filename) path = os.path.join(self._local_volume_dir(volume), filename)
info = self._qemu_img_info(path, volume['name']) info = self._qemu_img_info(path, volume.name)
backing_filename = info.backing_file backing_filename = info.backing_file
new_info = {} new_info = {}
new_info['filename'] = filename new_info['filename'] = filename
@ -846,13 +847,13 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
active_file = self.get_active_image_from_info(volume) active_file = self.get_active_image_from_info(volume)
active_file_path = os.path.join(self._local_volume_dir(volume), active_file_path = os.path.join(self._local_volume_dir(volume),
active_file) active_file)
info = self._qemu_img_info(active_file_path, volume['name']) info = self._qemu_img_info(active_file_path, volume.name)
backing_file = info.backing_file backing_file = info.backing_file
root_file_fmt = info.file_format root_file_fmt = info.file_format
tmp_params = { tmp_params = {
'prefix': '%s.temp_image.%s' % (volume['id'], image_meta['id']), 'prefix': '%s.temp_image.%s' % (volume.id, image_meta['id']),
'suffix': '.img' 'suffix': '.img'
} }
with image_utils.temporary_file(**tmp_params) as temp_path: with image_utils.temporary_file(**tmp_params) as temp_path:
@ -886,52 +887,64 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
def _create_cloned_volume(self, volume, src_vref): def _create_cloned_volume(self, volume, src_vref):
LOG.info(_LI('Cloning volume %(src)s to volume %(dst)s'), LOG.info(_LI('Cloning volume %(src)s to volume %(dst)s'),
{'src': src_vref['id'], {'src': src_vref.id,
'dst': volume['id']}) 'dst': volume.id})
if src_vref['status'] != 'available': if src_vref.status != 'available':
msg = _("Volume status must be 'available'.") msg = _("Volume status must be 'available'.")
raise exception.InvalidVolume(msg) raise exception.InvalidVolume(msg)
volume_name = CONF.volume_name_template % volume['id'] volume_name = CONF.volume_name_template % volume.id
# Create fake volume and snapshot objects
vol_attrs = ['provider_location', 'size', 'id', 'name', 'status',
'volume_type', 'metadata']
Volume = collections.namedtuple('Volume', vol_attrs)
snap_attrs = ['volume_name', 'volume_size', 'name',
'volume_id', 'id', 'volume']
Snapshot = collections.namedtuple('Snapshot', snap_attrs)
volume_info = Volume(provider_location=src_vref.provider_location,
size=src_vref.size,
id=volume.id,
name=volume_name,
status=src_vref.status,
volume_type=src_vref.volume_type,
metadata=src_vref.metadata)
temp_snapshot = Snapshot(volume_name=volume_name,
volume_size=src_vref.size,
name='clone-snap-%s' % src_vref.id,
volume_id=src_vref.id,
id='tmp-snap-%s' % src_vref.id,
volume=src_vref)
volume_info = {'provider_location': src_vref['provider_location'],
'size': src_vref['size'],
'id': volume['id'],
'name': volume_name,
'status': src_vref['status']}
temp_snapshot = {'volume_name': volume_name,
'size': src_vref['size'],
'volume_size': src_vref['size'],
'name': 'clone-snap-%s' % src_vref['id'],
'volume_id': src_vref['id'],
'id': 'tmp-snap-%s' % src_vref['id'],
'volume': src_vref}
self._create_snapshot(temp_snapshot) self._create_snapshot(temp_snapshot)
try: try:
self._copy_volume_from_snapshot(temp_snapshot, self._copy_volume_from_snapshot(temp_snapshot,
volume_info, volume_info,
volume['size']) volume.size)
finally: finally:
self._delete_snapshot(temp_snapshot) self._delete_snapshot(temp_snapshot)
return {'provider_location': src_vref['provider_location']} return {'provider_location': src_vref.provider_location}
def _delete_stale_snapshot(self, snapshot): def _delete_stale_snapshot(self, snapshot):
info_path = self._local_path_volume_info(snapshot['volume']) info_path = self._local_path_volume_info(snapshot.volume)
snap_info = self._read_info_file(info_path) snap_info = self._read_info_file(info_path)
snapshot_file = snap_info[snapshot['id']] snapshot_file = snap_info[snapshot.id]
active_file = self.get_active_image_from_info(snapshot['volume']) active_file = self.get_active_image_from_info(snapshot.volume)
snapshot_path = os.path.join( snapshot_path = os.path.join(
self._local_volume_dir(snapshot['volume']), snapshot_file) self._local_volume_dir(snapshot.volume), snapshot_file)
if (snapshot_file == active_file): if (snapshot_file == active_file):
return return
LOG.info(_LI('Deleting stale snapshot: %s'), snapshot['id']) LOG.info(_LI('Deleting stale snapshot: %s'), snapshot.id)
self._delete(snapshot_path) self._delete(snapshot_path)
del(snap_info[snapshot['id']]) del(snap_info[snapshot.id])
self._write_info_file(info_path, snap_info) self._write_info_file(info_path, snap_info)
def _delete_snapshot(self, snapshot): def _delete_snapshot(self, snapshot):
@ -949,39 +962,39 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
""" """
LOG.debug('Deleting snapshot %s:', snapshot['id']) LOG.debug('Deleting snapshot %s:', snapshot.id)
volume_status = snapshot['volume']['status'] volume_status = snapshot.volume.status
if volume_status not in ['available', 'in-use']: if volume_status not in ['available', 'in-use']:
msg = _('Volume status must be "available" or "in-use".') msg = _('Volume status must be "available" or "in-use".')
raise exception.InvalidVolume(msg) raise exception.InvalidVolume(msg)
vol_path = self._local_volume_dir(snapshot['volume']) vol_path = self._local_volume_dir(snapshot.volume)
self._ensure_share_writable(vol_path) self._ensure_share_writable(vol_path)
# Determine the true snapshot file for this snapshot # Determine the true snapshot file for this snapshot
# based on the .info file # based on the .info file
info_path = self._local_path_volume_info(snapshot['volume']) info_path = self._local_path_volume_info(snapshot.volume)
snap_info = self._read_info_file(info_path, empty_if_missing=True) snap_info = self._read_info_file(info_path, empty_if_missing=True)
if snapshot['id'] not in snap_info: if snapshot.id not in snap_info:
# If snapshot info file is present, but snapshot record does not # If snapshot info file is present, but snapshot record does not
# exist, do not attempt to delete. # exist, do not attempt to delete.
# (This happens, for example, if snapshot_create failed due to lack # (This happens, for example, if snapshot_create failed due to lack
# of permission to write to the share.) # of permission to write to the share.)
LOG.info(_LI('Snapshot record for %s is not present, allowing ' LOG.info(_LI('Snapshot record for %s is not present, allowing '
'snapshot_delete to proceed.'), snapshot['id']) 'snapshot_delete to proceed.'), snapshot.id)
return return
snapshot_file = snap_info[snapshot['id']] snapshot_file = snap_info[snapshot.id]
LOG.debug('snapshot_file for this snap is: %s', snapshot_file) LOG.debug('snapshot_file for this snap is: %s', snapshot_file)
snapshot_path = os.path.join( snapshot_path = os.path.join(
self._local_volume_dir(snapshot['volume']), self._local_volume_dir(snapshot.volume),
snapshot_file) snapshot_file)
snapshot_path_img_info = self._qemu_img_info( snapshot_path_img_info = self._qemu_img_info(
snapshot_path, snapshot_path,
snapshot['volume']['name']) snapshot.volume.name)
base_file = snapshot_path_img_info.backing_file base_file = snapshot_path_img_info.backing_file
if base_file is None: if base_file is None:
@ -996,15 +1009,15 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
base_path = os.path.join(vol_path, base_file) base_path = os.path.join(vol_path, base_file)
base_file_img_info = self._qemu_img_info(base_path, base_file_img_info = self._qemu_img_info(base_path,
snapshot['volume']['name']) snapshot.volume.name)
# Find what file has this as its backing file # Find what file has this as its backing file
active_file = self.get_active_image_from_info(snapshot['volume']) active_file = self.get_active_image_from_info(snapshot.volume)
active_file_path = os.path.join(vol_path, active_file) active_file_path = os.path.join(vol_path, active_file)
if volume_status == 'in-use': if volume_status == 'in-use':
# Online delete # Online delete
context = snapshot['context'] context = snapshot._context
new_base_file = base_file_img_info.backing_file new_base_file = base_file_img_info.backing_file
@ -1048,7 +1061,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
# used here) | | ptr update) | # used here) | | ptr update) |
backing_chain = self._get_backing_chain_for_path( backing_chain = self._get_backing_chain_for_path(
snapshot['volume'], active_file_path) snapshot.volume, active_file_path)
# This file is guaranteed to exist since we aren't operating on # This file is guaranteed to exist since we aren't operating on
# the active file. # the active file.
higher_file = next((os.path.basename(f['filename']) higher_file = next((os.path.basename(f['filename'])
@ -1077,7 +1090,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
self._rebase_img(higher_file_path, base_file, base_file_fmt) self._rebase_img(higher_file_path, base_file, base_file_fmt)
# Remove snapshot_file from info # Remove snapshot_file from info
del(snap_info[snapshot['id']]) del(snap_info[snapshot.id])
self._write_info_file(info_path, snap_info) self._write_info_file(info_path, snap_info)
def _create_volume_from_snapshot(self, volume, snapshot): def _create_volume_from_snapshot(self, volume, snapshot):
@ -1086,21 +1099,21 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
Snapshot must not be the active snapshot. (offline) Snapshot must not be the active snapshot. (offline)
""" """
if snapshot['status'] != 'available': if snapshot.status != 'available':
msg = _('Snapshot status must be "available" to clone.') msg = _('Snapshot status must be "available" to clone.')
raise exception.InvalidSnapshot(msg) raise exception.InvalidSnapshot(msg)
self._ensure_shares_mounted() self._ensure_shares_mounted()
volume['provider_location'] = self._find_share(volume['size']) volume.provider_location = self._find_share(volume.size)
self._do_create_volume(volume) self._do_create_volume(volume)
self._copy_volume_from_snapshot(snapshot, self._copy_volume_from_snapshot(snapshot,
volume, volume,
volume['size']) volume.size)
return {'provider_location': volume['provider_location']} return {'provider_location': volume.provider_location}
def _copy_volume_from_snapshot(self, snapshot, volume, volume_size): def _copy_volume_from_snapshot(self, snapshot, volume, volume_size):
raise NotImplementedError() raise NotImplementedError()
@ -1116,7 +1129,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
""" """
backing_path_full_path = os.path.join( backing_path_full_path = os.path.join(
self._local_volume_dir(snapshot['volume']), self._local_volume_dir(snapshot.volume),
backing_filename) backing_filename)
command = ['qemu-img', 'create', '-f', 'qcow2', '-o', command = ['qemu-img', 'create', '-f', 'qcow2', '-o',
@ -1124,7 +1137,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
self._execute(*command, run_as_root=self._execute_as_root) self._execute(*command, run_as_root=self._execute_as_root)
info = self._qemu_img_info(backing_path_full_path, info = self._qemu_img_info(backing_path_full_path,
snapshot['volume']['name']) snapshot.volume.name)
backing_fmt = info.file_format backing_fmt = info.file_format
command = ['qemu-img', 'rebase', '-u', command = ['qemu-img', 'rebase', '-u',
@ -1239,16 +1252,16 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
info file: { 'active': 'volume-1234' } (* changed!) info file: { 'active': 'volume-1234' } (* changed!)
""" """
status = snapshot['volume']['status'] status = snapshot.volume.status
if status not in ['available', 'in-use']: if status not in ['available', 'in-use']:
msg = _('Volume status must be "available" or "in-use"' msg = _('Volume status must be "available" or "in-use"'
' for snapshot. (is %s)') % status ' for snapshot. (is %s)') % status
raise exception.InvalidVolume(msg) raise exception.InvalidVolume(msg)
info_path = self._local_path_volume_info(snapshot['volume']) info_path = self._local_path_volume_info(snapshot.volume)
snap_info = self._read_info_file(info_path, empty_if_missing=True) snap_info = self._read_info_file(info_path, empty_if_missing=True)
backing_filename = self.get_active_image_from_info( backing_filename = self.get_active_image_from_info(
snapshot['volume']) snapshot.volume)
new_snap_path = self._get_new_snap_path(snapshot) new_snap_path = self._get_new_snap_path(snapshot)
if status == 'in-use': if status == 'in-use':
@ -1261,13 +1274,13 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
new_snap_path) new_snap_path)
snap_info['active'] = os.path.basename(new_snap_path) snap_info['active'] = os.path.basename(new_snap_path)
snap_info[snapshot['id']] = os.path.basename(new_snap_path) snap_info[snapshot.id] = os.path.basename(new_snap_path)
self._write_info_file(info_path, snap_info) self._write_info_file(info_path, snap_info)
def _create_snapshot_online(self, snapshot, backing_filename, def _create_snapshot_online(self, snapshot, backing_filename,
new_snap_path): new_snap_path):
# Perform online snapshot via Nova # Perform online snapshot via Nova
context = snapshot['context'] context = snapshot._context
self._do_create_snapshot(snapshot, self._do_create_snapshot(snapshot,
backing_filename, backing_filename,
@ -1276,13 +1289,13 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
connection_info = { connection_info = {
'type': 'qcow2', 'type': 'qcow2',
'new_file': os.path.basename(new_snap_path), 'new_file': os.path.basename(new_snap_path),
'snapshot_id': snapshot['id'] 'snapshot_id': snapshot.id
} }
try: try:
result = self._nova.create_volume_snapshot( result = self._nova.create_volume_snapshot(
context, context,
snapshot['volume_id'], snapshot.volume_id,
connection_info) connection_info)
LOG.debug('nova call result: %s', result) LOG.debug('nova call result: %s', result)
except Exception: except Exception:
@ -1296,7 +1309,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
increment = 1 increment = 1
timeout = 600 timeout = 600
while True: while True:
s = db.snapshot_get(context, snapshot['id']) s = db.snapshot_get(context, snapshot.id)
LOG.debug('Status of snapshot %(id)s is now %(status)s', LOG.debug('Status of snapshot %(id)s is now %(status)s',
{'id': snapshot['id'], {'id': snapshot['id'],
@ -1320,7 +1333,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
msg = _('Snapshot %(id)s has been asked to be deleted while ' msg = _('Snapshot %(id)s has been asked to be deleted while '
'waiting for it to become available. Perhaps a ' 'waiting for it to become available. Perhaps a '
'concurrent request was made.') % {'id': 'concurrent request was made.') % {'id':
snapshot['id']} snapshot.id}
raise exception.RemoteFSConcurrentRequest(msg) raise exception.RemoteFSConcurrentRequest(msg)
if 10 < seconds_elapsed <= 20: if 10 < seconds_elapsed <= 20:
@ -1332,13 +1345,13 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
if seconds_elapsed > timeout: if seconds_elapsed > timeout:
msg = _('Timed out while waiting for Nova update ' msg = _('Timed out while waiting for Nova update '
'for creation of snapshot %s.') % snapshot['id'] 'for creation of snapshot %s.') % snapshot.id
raise exception.RemoteFSException(msg) raise exception.RemoteFSException(msg)
def _delete_snapshot_online(self, context, snapshot, info): def _delete_snapshot_online(self, context, snapshot, info):
# Update info over the course of this method # Update info over the course of this method
# active file never changes # active file never changes
info_path = self._local_path_volume_info(snapshot['volume']) info_path = self._local_path_volume_info(snapshot.volume)
snap_info = self._read_info_file(info_path) snap_info = self._read_info_file(info_path)
if info['active_file'] == info['snapshot_file']: if info['active_file'] == info['snapshot_file']:
@ -1357,9 +1370,9 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
delete_info = {'file_to_merge': new_base, delete_info = {'file_to_merge': new_base,
'merge_target_file': None, # current 'merge_target_file': None, # current
'type': 'qcow2', 'type': 'qcow2',
'volume_id': snapshot['volume']['id']} 'volume_id': snapshot.volume.id}
del(snap_info[snapshot['id']]) del(snap_info[snapshot.id])
else: else:
# blockCommit snapshot into base # blockCommit snapshot into base
# info['base'] <= snapshot_file # info['base'] <= snapshot_file
@ -1369,14 +1382,14 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
delete_info = {'file_to_merge': info['snapshot_file'], delete_info = {'file_to_merge': info['snapshot_file'],
'merge_target_file': info['base_file'], 'merge_target_file': info['base_file'],
'type': 'qcow2', 'type': 'qcow2',
'volume_id': snapshot['volume']['id']} 'volume_id': snapshot.volume.id}
del(snap_info[snapshot['id']]) del(snap_info[snapshot.id])
try: try:
self._nova.delete_volume_snapshot( self._nova.delete_volume_snapshot(
context, context,
snapshot['id'], snapshot.id,
delete_info) delete_info)
except Exception: except Exception:
LOG.exception(_LE('Call to Nova delete snapshot failed')) LOG.exception(_LE('Call to Nova delete snapshot failed'))
@ -1389,7 +1402,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
increment = 1 increment = 1
timeout = 7200 timeout = 7200
while True: while True:
s = db.snapshot_get(context, snapshot['id']) s = db.snapshot_get(context, snapshot.id)
if s['status'] == fields.SnapshotStatus.DELETING: if s['status'] == fields.SnapshotStatus.DELETING:
if s['progress'] == '90%': if s['progress'] == '90%':
@ -1397,12 +1410,12 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
break break
else: else:
LOG.debug('status of snapshot %s is still "deleting"... ' LOG.debug('status of snapshot %s is still "deleting"... '
'waiting', snapshot['id']) 'waiting', snapshot.id)
time.sleep(increment) time.sleep(increment)
seconds_elapsed += increment seconds_elapsed += increment
else: else:
msg = _('Unable to delete snapshot %(id)s, ' msg = _('Unable to delete snapshot %(id)s, '
'status: %(status)s.') % {'id': snapshot['id'], 'status: %(status)s.') % {'id': snapshot.id,
'status': s['status']} 'status': s['status']}
raise exception.RemoteFSException(msg) raise exception.RemoteFSException(msg)
@ -1416,7 +1429,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
if seconds_elapsed > timeout: if seconds_elapsed > timeout:
msg = _('Timed out while waiting for Nova update ' msg = _('Timed out while waiting for Nova update '
'for deletion of snapshot %(id)s.') %\ 'for deletion of snapshot %(id)s.') %\
{'id': snapshot['id']} {'id': snapshot.id}
raise exception.RemoteFSException(msg) raise exception.RemoteFSException(msg)
# Write info file updated above # Write info file updated above
@ -1424,7 +1437,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
# Delete stale file # Delete stale file
path_to_delete = os.path.join( path_to_delete = os.path.join(
self._local_volume_dir(snapshot['volume']), file_to_delete) self._local_volume_dir(snapshot.volume), file_to_delete)
self._execute('rm', '-f', path_to_delete, run_as_root=True) self._execute('rm', '-f', path_to_delete, run_as_root=True)
@locked_volume_id_operation @locked_volume_id_operation

View File

@ -186,14 +186,14 @@ class ScalityDriver(remotefs_drv.RemoteFSSnapDriver):
active_file = self.get_active_image_from_info(volume) active_file = self.get_active_image_from_info(volume)
path = '%s/%s' % (self._get_mount_point_for_share(), active_file) path = '%s/%s' % (self._get_mount_point_for_share(), active_file)
sofs_rel_path = os.path.join(self.sofs_rel_volume_dir, "00", sofs_rel_path = os.path.join(self.sofs_rel_volume_dir, "00",
volume['name']) volume.name)
data = {'export': volume['provider_location'], data = {'export': volume.provider_location,
'name': active_file, 'name': active_file,
'sofs_path': sofs_rel_path} 'sofs_path': sofs_rel_path}
# Test file for raw vs. qcow2 format # Test file for raw vs. qcow2 format
info = self._qemu_img_info(path, volume['name']) info = self._qemu_img_info(path, volume.name)
data['format'] = info.file_format data['format'] = info.file_format
if data['format'] not in ['raw', 'qcow2']: if data['format'] not in ['raw', 'qcow2']:
msg = _('%s must be a valid raw or qcow2 image.') % path msg = _('%s must be a valid raw or qcow2 image.') % path
@ -213,7 +213,7 @@ class ScalityDriver(remotefs_drv.RemoteFSSnapDriver):
def extend_volume(self, volume, size_gb): def extend_volume(self, volume, size_gb):
volume_path = self.local_path(volume) volume_path = self.local_path(volume)
info = self._qemu_img_info(volume_path, volume['name']) info = self._qemu_img_info(volume_path, volume.name)
backing_fmt = info.file_format backing_fmt = info.file_format
if backing_fmt not in ['raw', 'qcow2']: if backing_fmt not in ['raw', 'qcow2']:
@ -230,7 +230,7 @@ class ScalityDriver(remotefs_drv.RemoteFSSnapDriver):
qcow2. qcow2.
""" """
info_path = self._local_path_volume_info(snapshot['volume']) info_path = self._local_path_volume_info(snapshot.volume)
# For BC compat' with version < 2 of this driver # For BC compat' with version < 2 of this driver
try: try:
@ -241,15 +241,15 @@ class ScalityDriver(remotefs_drv.RemoteFSSnapDriver):
else: else:
path_to_snap_img = self.local_path(snapshot) path_to_snap_img = self.local_path(snapshot)
else: else:
vol_path = self._local_volume_dir(snapshot['volume']) vol_path = self._local_volume_dir(snapshot.volume)
forward_file = snap_info[snapshot['id']] forward_file = snap_info[snapshot.id]
forward_path = os.path.join(vol_path, forward_file) forward_path = os.path.join(vol_path, forward_file)
# Find the file which backs this file, which represents the point # Find the file which backs this file, which represents the point
# when this snapshot was created. # when this snapshot was created.
img_info = self._qemu_img_info(forward_path, img_info = self._qemu_img_info(forward_path,
snapshot['volume']['name']) snapshot.volume.name)
path_to_snap_img = os.path.join(vol_path, img_info.backing_file) path_to_snap_img = os.path.join(vol_path, img_info.backing_file)
@ -270,7 +270,7 @@ class ScalityDriver(remotefs_drv.RemoteFSSnapDriver):
"""Create a new backup from an existing volume.""" """Create a new backup from an existing volume."""
volume = self.db.volume_get(context, backup['volume_id']) volume = self.db.volume_get(context, backup['volume_id'])
volume_local_path = self.local_path(volume) volume_local_path = self.local_path(volume)
LOG.info(_LI('Begin backup of volume %s.'), volume['name']) LOG.info(_LI('Begin backup of volume %s.'), volume.name)
qemu_img_info = image_utils.qemu_img_info(volume_local_path) qemu_img_info = image_utils.qemu_img_info(volume_local_path)
if qemu_img_info.file_format != 'raw': if qemu_img_info.file_format != 'raw':
@ -290,8 +290,8 @@ class ScalityDriver(remotefs_drv.RemoteFSSnapDriver):
def restore_backup(self, context, backup, volume, backup_service): def restore_backup(self, context, backup, volume, backup_service):
"""Restore an existing backup to a new or existing volume.""" """Restore an existing backup to a new or existing volume."""
LOG.info(_LI('Restoring backup %(backup)s to volume %(volume)s.'), LOG.info(_LI('Restoring backup %(backup)s to volume %(volume)s.'),
{'backup': backup['id'], 'volume': volume['name']}) {'backup': backup['id'], 'volume': volume.name})
volume_local_path = self.local_path(volume) volume_local_path = self.local_path(volume)
with utils.temporary_chown(volume_local_path): with utils.temporary_chown(volume_local_path):
with open(volume_local_path, 'wb') as volume_file: with open(volume_local_path, 'wb') as volume_file:
backup_service.restore(backup, volume['id'], volume_file) backup_service.restore(backup, volume.id, volume_file)

View File

@ -90,7 +90,7 @@ def update_allocation_data(delete=False):
if delete: if delete:
allocated_size_gb = None allocated_size_gb = None
else: else:
allocated_size_gb = requested_size or volume['size'] allocated_size_gb = requested_size or volume.size
inst.update_disk_allocation_data(volume, allocated_size_gb) inst.update_disk_allocation_data(volume, allocated_size_gb)
return ret_val return ret_val
@ -149,11 +149,11 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
active_file = self.get_active_image_from_info(volume) active_file = self.get_active_image_from_info(volume)
fmt = self.get_volume_format(volume) fmt = self.get_volume_format(volume)
data = {'export': volume['provider_location'], data = {'export': volume.provider_location,
'format': fmt, 'format': fmt,
'name': active_file} 'name': active_file}
if volume['provider_location'] in self.shares: if volume.provider_location in self.shares:
data['options'] = self.shares[volume['provider_location']] data['options'] = self.shares[volume.provider_location]
return { return {
'driver_volume_type': self.driver_volume_type, 'driver_volume_type': self.driver_volume_type,
'data': data, 'data': data,
@ -206,8 +206,8 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
self._allocation_data = json.load(f) self._allocation_data = json.load(f)
def update_disk_allocation_data(self, volume, virtual_size_gb=None): def update_disk_allocation_data(self, volume, virtual_size_gb=None):
volume_name = volume['name'] volume_name = volume.name
smbfs_share = volume['provider_location'] smbfs_share = volume.provider_location
if smbfs_share: if smbfs_share:
share_hash = self._get_hash_str(smbfs_share) share_hash = self._get_hash_str(smbfs_share)
else: else:
@ -257,7 +257,7 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
def _get_local_volume_path_template(self, volume): def _get_local_volume_path_template(self, volume):
local_dir = self._local_volume_dir(volume) local_dir = self._local_volume_dir(volume)
local_path_template = os.path.join(local_dir, volume['name']) local_path_template = os.path.join(local_dir, volume.name)
return local_path_template return local_path_template
def _lookup_local_volume_path(self, volume_path_template): def _lookup_local_volume_path(self, volume_path_template):
@ -271,9 +271,9 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
return '%s%s' % (self.local_path(volume), '.info') return '%s%s' % (self.local_path(volume), '.info')
def _get_new_snap_path(self, snapshot): def _get_new_snap_path(self, snapshot):
vol_path = self.local_path(snapshot['volume']) vol_path = self.local_path(snapshot.volume)
snap_path, ext = os.path.splitext(vol_path) snap_path, ext = os.path.splitext(vol_path)
snap_path += '.' + snapshot['id'] + ext snap_path += '.' + snapshot.id + ext
return snap_path return snap_path
def get_volume_format(self, volume, qemu_format=False): def get_volume_format(self, volume, qemu_format=False):
@ -285,7 +285,7 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
if ext in self._SUPPORTED_IMAGE_FORMATS: if ext in self._SUPPORTED_IMAGE_FORMATS:
volume_format = ext volume_format = ext
else: else:
info = self._qemu_img_info(volume_path, volume['name']) info = self._qemu_img_info(volume_path, volume.name)
volume_format = info.file_format volume_format = info.file_format
else: else:
volume_format = ( volume_format = (
@ -303,12 +303,12 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
@update_allocation_data(delete=True) @update_allocation_data(delete=True)
def delete_volume(self, volume): def delete_volume(self, volume):
"""Deletes a logical volume.""" """Deletes a logical volume."""
if not volume['provider_location']: if not volume.provider_location:
LOG.warning(_LW('Volume %s does not have provider_location ' LOG.warning(_LW('Volume %s does not have provider_location '
'specified, skipping.'), volume['name']) 'specified, skipping.'), volume.name)
return return
self._ensure_share_mounted(volume['provider_location']) self._ensure_share_mounted(volume.provider_location)
volume_dir = self._local_volume_dir(volume) volume_dir = self._local_volume_dir(volume)
mounted_path = os.path.join(volume_dir, mounted_path = os.path.join(volume_dir,
self.get_active_image_from_info(volume)) self.get_active_image_from_info(volume))
@ -343,7 +343,7 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
""" """
volume_format = self.get_volume_format(volume) volume_format = self.get_volume_format(volume)
volume_path = self.local_path(volume) volume_path = self.local_path(volume)
volume_size = volume['size'] volume_size = volume.size
LOG.debug("Creating new volume at %s.", volume_path) LOG.debug("Creating new volume at %s.", volume_path)
@ -470,7 +470,7 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
snapshot, backing_filename, new_snap_path) snapshot, backing_filename, new_snap_path)
def _check_snapshot_support(self, snapshot): def _check_snapshot_support(self, snapshot):
volume_format = self.get_volume_format(snapshot['volume']) volume_format = self.get_volume_format(snapshot.volume)
# qemu-img does not yet support differencing vhd/vhdx # qemu-img does not yet support differencing vhd/vhdx
if volume_format in (self._DISK_FORMAT_VHD, self._DISK_FORMAT_VHDX): if volume_format in (self._DISK_FORMAT_VHD, self._DISK_FORMAT_VHDX):
err_msg = _("Snapshots are not supported for this volume " err_msg = _("Snapshots are not supported for this volume "
@ -480,7 +480,7 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
@remotefs_drv.locked_volume_id_operation @remotefs_drv.locked_volume_id_operation
@update_allocation_data() @update_allocation_data()
def extend_volume(self, volume, size_gb): def extend_volume(self, volume, size_gb):
LOG.info(_LI('Extending volume %s.'), volume['id']) LOG.info(_LI('Extending volume %s.'), volume.id)
self._extend_volume(volume, size_gb) self._extend_volume(volume, size_gb)
def _extend_volume(self, volume, size_gb): def _extend_volume(self, volume, size_gb):
@ -489,7 +489,7 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
self._check_extend_volume_support(volume, size_gb) self._check_extend_volume_support(volume, size_gb)
LOG.info(_LI('Resizing file to %sG...'), size_gb) LOG.info(_LI('Resizing file to %sG...'), size_gb)
self._do_extend_volume(volume_path, size_gb, volume['name']) self._do_extend_volume(volume_path, size_gb, volume.name)
def _do_extend_volume(self, volume_path, size_gb, volume_name): def _do_extend_volume(self, volume_path, size_gb, volume_name):
info = self._qemu_img_info(volume_path, volume_name) info = self._qemu_img_info(volume_path, volume_name)
@ -523,12 +523,12 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
'driver when no snapshots exist.') 'driver when no snapshots exist.')
raise exception.InvalidVolume(msg) raise exception.InvalidVolume(msg)
extend_by = int(size_gb) - volume['size'] extend_by = int(size_gb) - volume.size
if not self._is_share_eligible(volume['provider_location'], if not self._is_share_eligible(volume.provider_location,
extend_by): extend_by):
raise exception.ExtendVolumeError(reason='Insufficient space to ' raise exception.ExtendVolumeError(reason='Insufficient space to '
'extend volume %s to %sG.' 'extend volume %s to %sG.'
% (volume['id'], size_gb)) % (volume.id, size_gb))
@remotefs_drv.locked_volume_id_operation @remotefs_drv.locked_volume_id_operation
@update_allocation_data() @update_allocation_data()
@ -544,22 +544,22 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
LOG.debug("Snapshot: %(snap)s, volume: %(vol)s, " LOG.debug("Snapshot: %(snap)s, volume: %(vol)s, "
"volume_size: %(size)s", "volume_size: %(size)s",
{'snap': snapshot['id'], {'snap': snapshot.id,
'vol': volume['id'], 'vol': volume.id,
'size': volume_size}) 'size': volume_size})
info_path = self._local_path_volume_info(snapshot['volume']) info_path = self._local_path_volume_info(snapshot.volume)
snap_info = self._read_info_file(info_path) snap_info = self._read_info_file(info_path)
vol_dir = self._local_volume_dir(snapshot['volume']) vol_dir = self._local_volume_dir(snapshot.volume)
out_format = self.get_volume_format(volume, qemu_format=True) out_format = self.get_volume_format(volume, qemu_format=True)
forward_file = snap_info[snapshot['id']] forward_file = snap_info[snapshot.id]
forward_path = os.path.join(vol_dir, forward_file) forward_path = os.path.join(vol_dir, forward_file)
# Find the file which backs this file, which represents the point # Find the file which backs this file, which represents the point
# when this snapshot was created. # when this snapshot was created.
img_info = self._qemu_img_info(forward_path, img_info = self._qemu_img_info(forward_path,
snapshot['volume']['name']) snapshot.volume.name)
path_to_snap_img = os.path.join(vol_dir, img_info.backing_file) path_to_snap_img = os.path.join(vol_dir, img_info.backing_file)
LOG.debug("Will copy from snapshot at %s", path_to_snap_img) LOG.debug("Will copy from snapshot at %s", path_to_snap_img)
@ -581,15 +581,15 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
self.configuration.volume_dd_blocksize) self.configuration.volume_dd_blocksize)
self._do_extend_volume(self.local_path(volume), self._do_extend_volume(self.local_path(volume),
volume['size'], volume.size,
volume['name']) volume.name)
data = image_utils.qemu_img_info(self.local_path(volume)) data = image_utils.qemu_img_info(self.local_path(volume))
virt_size = data.virtual_size / units.Gi virt_size = data.virtual_size / units.Gi
if virt_size != volume['size']: if virt_size != volume.size:
raise exception.ImageUnacceptable( raise exception.ImageUnacceptable(
image_id=image_id, image_id=image_id,
reason=(_("Expected volume size was %d") % volume['size']) reason=(_("Expected volume size was %d") % volume.size)
+ (_(" but size is now %d.") % virt_size)) + (_(" but size is now %d.") % virt_size))
@remotefs_drv.locked_volume_id_operation @remotefs_drv.locked_volume_id_operation
@ -639,38 +639,15 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
return flags.strip(',') return flags.strip(',')
def _get_volume_format_spec(self, volume): def _get_volume_format_spec(self, volume):
# This method needs to be able to parse metadata/volume type vol_type = volume.volume_type
# specs for volume SQLAlchemy objects and versioned objects, extra_specs = {}
# as the transition to versioned objects is not complete and the if vol_type and vol_type.extra_specs:
# driver may receive either of them. extra_specs = vol_type.extra_specs
#
# TODO(lpetrut): once the transition to oslo.versionedobjects is
# complete, we can skip some of those checks.
volume_metadata_specs = {}
volume_type_specs = {}
if volume.get('metadata') and isinstance(volume.metadata, dict): extra_specs.update(volume.metadata or {})
volume_metadata_specs.update(volume.metadata)
elif volume.get('volume_metadata'):
volume_metadata_specs.update(
{spec.key: spec.value for spec in volume.volume_metadata})
vol_type = volume.get('volume_type') return (extra_specs.get('volume_format') or
if vol_type: self.configuration.smbfs_default_volume_format)
specs = vol_type.get('extra_specs') or {}
if isinstance(specs, dict):
volume_type_specs.update(specs)
else:
volume_type_specs.update(
{spec.key: spec.value for spec in specs})
# In this case, we want the volume metadata specs to take
# precedence over the volume type specs.
for specs in [volume_metadata_specs, volume_type_specs]:
for key, val in specs.items():
if 'volume_format' in key:
return val
return None
def _is_file_size_equal(self, path, size): def _is_file_size_equal(self, path, size):
"""Checks if file size at path is equal to size.""" """Checks if file size at path is equal to size."""

View File

@ -110,10 +110,10 @@ class VZStorageDriver(remotefs_drv.RemoteFSSnapDriver):
active_file = self.get_active_image_from_info(volume) active_file = self.get_active_image_from_info(volume)
active_file_path = os.path.join(self._local_volume_dir(volume), active_file_path = os.path.join(self._local_volume_dir(volume),
active_file) active_file)
info = self._qemu_img_info(active_file_path, volume['name']) info = self._qemu_img_info(active_file_path, volume.name)
fmt = info.file_format fmt = info.file_format
data = {'export': volume['provider_location'], data = {'export': volume.provider_location,
'format': fmt, 'format': fmt,
'name': active_file, 'name': active_file,
} }
@ -228,7 +228,7 @@ class VZStorageDriver(remotefs_drv.RemoteFSSnapDriver):
@remotefs_drv.locked_volume_id_operation @remotefs_drv.locked_volume_id_operation
def extend_volume(self, volume, size_gb): def extend_volume(self, volume, size_gb):
LOG.info(_LI('Extending volume %s.'), volume['id']) LOG.info(_LI('Extending volume %s.'), volume.id)
self._extend_volume(volume, size_gb) self._extend_volume(volume, size_gb)
def _extend_volume(self, volume, size_gb): def _extend_volume(self, volume, size_gb):
@ -257,12 +257,12 @@ class VZStorageDriver(remotefs_drv.RemoteFSSnapDriver):
'driver when no snapshots exist.') 'driver when no snapshots exist.')
raise exception.InvalidVolume(msg) raise exception.InvalidVolume(msg)
extend_by = int(size_gb) - volume['size'] extend_by = int(size_gb) - volume.size
if not self._is_share_eligible(volume['provider_location'], if not self._is_share_eligible(volume.provider_location,
extend_by): extend_by):
raise exception.ExtendVolumeError(reason='Insufficient space to ' raise exception.ExtendVolumeError(reason='Insufficient space to '
'extend volume %s to %sG.' 'extend volume %s to %sG.'
% (volume['id'], size_gb)) % (volume.id, size_gb))
def _is_file_size_equal(self, path, size): def _is_file_size_equal(self, path, size):
"""Checks if file size at path is equal to size.""" """Checks if file size at path is equal to size."""
@ -279,23 +279,23 @@ class VZStorageDriver(remotefs_drv.RemoteFSSnapDriver):
LOG.debug("_copy_volume_from_snapshot: snapshot: %(snap)s, " LOG.debug("_copy_volume_from_snapshot: snapshot: %(snap)s, "
"volume: %(vol)s, volume_size: %(size)s.", "volume: %(vol)s, volume_size: %(size)s.",
{'snap': snapshot['id'], {'snap': snapshot.id,
'vol': volume['id'], 'vol': volume.id,
'size': volume_size, 'size': volume_size,
}) })
info_path = self._local_path_volume_info(snapshot['volume']) info_path = self._local_path_volume_info(snapshot.volume)
snap_info = self._read_info_file(info_path) snap_info = self._read_info_file(info_path)
vol_dir = self._local_volume_dir(snapshot['volume']) vol_dir = self._local_volume_dir(snapshot.volume)
out_format = "raw" out_format = "raw"
forward_file = snap_info[snapshot['id']] forward_file = snap_info[snapshot.id]
forward_path = os.path.join(vol_dir, forward_file) forward_path = os.path.join(vol_dir, forward_file)
# Find the file which backs this file, which represents the point # Find the file which backs this file, which represents the point
# when this snapshot was created. # when this snapshot was created.
img_info = self._qemu_img_info(forward_path, img_info = self._qemu_img_info(forward_path,
snapshot['volume']['name']) snapshot.volume.name)
path_to_snap_img = os.path.join(vol_dir, img_info.backing_file) path_to_snap_img = os.path.join(vol_dir, img_info.backing_file)
LOG.debug("_copy_volume_from_snapshot: will copy " LOG.debug("_copy_volume_from_snapshot: will copy "
@ -309,13 +309,13 @@ class VZStorageDriver(remotefs_drv.RemoteFSSnapDriver):
@remotefs_drv.locked_volume_id_operation @remotefs_drv.locked_volume_id_operation
def delete_volume(self, volume): def delete_volume(self, volume):
"""Deletes a logical volume.""" """Deletes a logical volume."""
if not volume['provider_location']: if not volume.provider_location:
msg = (_('Volume %s does not have provider_location ' msg = (_('Volume %s does not have provider_location '
'specified, skipping.') % volume['name']) 'specified, skipping.') % volume.name)
LOG.error(msg) LOG.error(msg)
raise exception.VzStorageException(msg) raise exception.VzStorageException(msg)
self._ensure_share_mounted(volume['provider_location']) self._ensure_share_mounted(volume.provider_location)
volume_dir = self._local_volume_dir(volume) volume_dir = self._local_volume_dir(volume)
mounted_path = os.path.join(volume_dir, mounted_path = os.path.join(volume_dir,
self.get_active_image_from_info(volume)) self.get_active_image_from_info(volume))