Merge "Use versionedobjects in remotefs.py"
This commit is contained in:
commit
5792f2f921
|
@ -34,8 +34,9 @@ from cinder import db
|
|||
from cinder import exception
|
||||
from cinder.i18n import _
|
||||
from cinder.image import image_utils
|
||||
from cinder.objects import fields
|
||||
from cinder import test
|
||||
from cinder.tests.unit import fake_snapshot
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder import utils
|
||||
from cinder.volume import driver as base_driver
|
||||
from cinder.volume.drivers import glusterfs
|
||||
|
@ -45,16 +46,6 @@ from cinder.volume.drivers import remotefs as remotefs_drv
|
|||
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):
|
||||
msg = "Tests are broken: mock this out."
|
||||
|
||||
|
@ -66,6 +57,17 @@ class FakeDb(object):
|
|||
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):
|
||||
"""Test case for GlusterFS driver."""
|
||||
|
||||
|
@ -75,12 +77,10 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
TEST_SIZE_IN_GB = 1
|
||||
TEST_MNT_POINT = '/mnt/glusterfs'
|
||||
TEST_MNT_POINT_BASE = '/mnt/test'
|
||||
TEST_LOCAL_PATH = '/mnt/glusterfs/volume-123'
|
||||
TEST_FILE_NAME = 'test.txt'
|
||||
TEST_SHARES_CONFIG_FILE = '/etc/cinder/test-shares.conf'
|
||||
TEST_TMP_FILE = '/tmp/tempfile'
|
||||
VOLUME_UUID = 'abcdefab-cdef-abcd-efab-cdefabcdefab'
|
||||
VOLUME_NAME = 'volume-%s' % VOLUME_UUID
|
||||
SNAP_UUID = 'bacadaca-baca-daca-baca-dacadacadaca'
|
||||
SNAP_UUID_2 = 'bebedede-bebe-dede-bebe-dedebebedede'
|
||||
|
||||
|
@ -102,6 +102,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
db=FakeDb())
|
||||
self._driver.shares = {}
|
||||
compute.API = mock.MagicMock()
|
||||
self.context = context.get_admin_context()
|
||||
|
||||
def assertRaisesAndMessageMatches(
|
||||
self, excClass, msg, callableObj, *args, **kwargs):
|
||||
|
@ -126,13 +127,12 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
self.TEST_MNT_POINT_BASE)
|
||||
drv = self._driver
|
||||
|
||||
volume = DumbVolume()
|
||||
volume['id'] = self.VOLUME_UUID
|
||||
volume['provider_location'] = self.TEST_EXPORT1
|
||||
volume['name'] = 'volume-123'
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
self.context,
|
||||
provider_location=self.TEST_EXPORT1)
|
||||
|
||||
self.assertEqual(
|
||||
'/mnt/test/ab03ab34eaca46a5fb81878f7e9b91fc/volume-123',
|
||||
'/mnt/test/ab03ab34eaca46a5fb81878f7e9b91fc/%s' % volume.name,
|
||||
drv.local_path(volume))
|
||||
|
||||
def test_mount_glusterfs(self):
|
||||
|
@ -470,17 +470,20 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
drv._find_share,
|
||||
self.TEST_SIZE_IN_GB)
|
||||
|
||||
def _simple_volume(self, id=None):
|
||||
volume = DumbVolume()
|
||||
volume['provider_location'] = self.TEST_EXPORT1
|
||||
def _simple_volume(self, id=None, **updates):
|
||||
if id is None:
|
||||
volume['id'] = self.VOLUME_UUID
|
||||
else:
|
||||
volume['id'] = id
|
||||
# volume['name'] mirrors format from db/sqlalchemy/models.py
|
||||
volume['name'] = 'volume-%s' % volume['id']
|
||||
volume['size'] = 10
|
||||
volume['status'] = 'available'
|
||||
id = self.VOLUME_UUID
|
||||
if 'id' not in updates:
|
||||
updates['id'] = self.VOLUME_UUID
|
||||
if 'name' not in updates:
|
||||
updates['name'] = 'volume-%s' % id
|
||||
if 'status' not in updates:
|
||||
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
|
||||
|
||||
|
@ -497,7 +500,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
drv._do_create_volume(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,
|
||||
volume_size)
|
||||
mock_set_rw_permissions_for_all.\
|
||||
|
@ -516,7 +519,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
drv._do_create_volume(volume)
|
||||
|
||||
volume_path = drv.local_path(volume)
|
||||
volume_size = volume['size']
|
||||
volume_size = volume.size
|
||||
mock_fallocate.assert_called_once_with(volume_path,
|
||||
volume_size)
|
||||
mock_set_rw_permissions_for_all.\
|
||||
|
@ -539,7 +542,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
drv._do_create_volume(volume)
|
||||
|
||||
volume_path = drv.local_path(volume)
|
||||
volume_size = volume['size']
|
||||
volume_size = volume.size
|
||||
mock_fallocate.assert_called_once_with(volume_path,
|
||||
volume_size)
|
||||
mock_create_regular_file.assert_called_once_with(volume_path,
|
||||
|
@ -556,9 +559,10 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
mock_do_create_volume,\
|
||||
mock.patch.object(drv, '_ensure_shares_mounted') as \
|
||||
mock_ensure_shares_mounted:
|
||||
volume = DumbVolume()
|
||||
volume['size'] = self.TEST_SIZE_IN_GB
|
||||
volume['id'] = self.VOLUME_UUID
|
||||
volume = fake_volume.fake_volume_obj(self.context,
|
||||
size=self.TEST_SIZE_IN_GB,
|
||||
id=self.VOLUME_UUID)
|
||||
mock_find_share.return_value = self.TEST_EXPORT2
|
||||
drv.create_volume(volume)
|
||||
self.assertTrue(mock_ensure_shares_mounted.called)
|
||||
self.assertTrue(mock_do_create_volume.called)
|
||||
|
@ -575,9 +579,9 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
mock_ensure_shares_mounted:
|
||||
mock_find_share.return_value = self.TEST_EXPORT1
|
||||
|
||||
volume = DumbVolume()
|
||||
volume['size'] = self.TEST_SIZE_IN_GB
|
||||
volume['id'] = self.VOLUME_UUID
|
||||
volume = fake_volume.fake_volume_obj(self.context,
|
||||
size=self.TEST_SIZE_IN_GB,
|
||||
id=self.VOLUME_UUID)
|
||||
result = drv.create_volume(volume)
|
||||
self.assertEqual(self.TEST_EXPORT1, result['provider_location'])
|
||||
self.assertTrue(mock_ensure_shares_mounted.called)
|
||||
|
@ -610,7 +614,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
self._driver.delete_volume(volume)
|
||||
|
||||
mock_ensure_share_mounted.assert_called_once_with(
|
||||
volume['provider_location'])
|
||||
volume.provider_location)
|
||||
mock_local_volume_dir.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,
|
||||
|
@ -827,10 +831,12 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
with mock.patch.object(drv, '_execute') as mock_execute,\
|
||||
mock.patch.object(drv, '_ensure_share_mounted') as \
|
||||
mock_ensure_share_mounted:
|
||||
volume = DumbVolume()
|
||||
volume['id'] = self.VOLUME_UUID
|
||||
volume['name'] = 'volume-123'
|
||||
volume['provider_location'] = self.TEST_EXPORT1
|
||||
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
self.context,
|
||||
id=self.VOLUME_UUID,
|
||||
display_name='volume-123',
|
||||
provider_location=self.TEST_EXPORT1)
|
||||
|
||||
drv.delete_volume(volume)
|
||||
|
||||
|
@ -845,10 +851,10 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
with mock.patch.object(drv, '_execute') as mock_execute,\
|
||||
mock.patch.object(drv, '_ensure_share_mounted') as \
|
||||
mock_ensure_share_mounted:
|
||||
volume = DumbVolume()
|
||||
volume['id'] = self.VOLUME_UUID
|
||||
volume['name'] = 'volume-123'
|
||||
volume['provider_location'] = None
|
||||
volume = fake_volume.fake_volume_obj(self.context,
|
||||
id=self.VOLUME_UUID,
|
||||
name='volume-123',
|
||||
provider_location=None)
|
||||
|
||||
drv.delete_volume(volume)
|
||||
|
||||
|
@ -868,10 +874,6 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
mock_read_file.return_value = '{"%(id)s": "volume-%(id)s"}' %\
|
||||
{'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)
|
||||
|
||||
self.assertEqual('volume-%s' % self.VOLUME_UUID,
|
||||
|
@ -897,7 +899,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
mock_qemu_img_info,\
|
||||
mock.patch.object(image_utils, 'resize_image') as \
|
||||
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_qemu_img_info.return_value = img_info
|
||||
|
||||
|
@ -940,9 +942,6 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
def test_create_snapshot_online(self):
|
||||
drv = self._driver
|
||||
|
||||
volume = self._simple_volume()
|
||||
volume['status'] = 'in-use'
|
||||
|
||||
hashed = drv._get_hash_str(self.TEST_EXPORT1)
|
||||
volume_file = 'volume-%s' % self.VOLUME_UUID
|
||||
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')
|
||||
|
||||
snap_ref = {'name': 'test snap (online)',
|
||||
'volume_id': self.VOLUME_UUID,
|
||||
'volume': volume,
|
||||
'id': self.SNAP_UUID,
|
||||
'context': ctxt,
|
||||
'status': fields.SnapshotStatus.CREATING,
|
||||
'progress': 'asdf'}
|
||||
snap_ref = fake_snapshot.fake_snapshot_obj(
|
||||
ctxt,
|
||||
display_name='test snap (online)',
|
||||
volume_id=self.VOLUME_UUID,
|
||||
id=self.SNAP_UUID,
|
||||
status='creating',
|
||||
progress='asdf')
|
||||
snap_ref.context = ctxt
|
||||
|
||||
snap_path = '%s.%s' % (volume_path, 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(drv, '_nova') as mock_nova,\
|
||||
mock.patch.object(time, 'sleep') as mock_sleep:
|
||||
create_info = {'snapshot_id': snap_ref['id'],
|
||||
create_info = {'snapshot_id': snap_ref.id,
|
||||
'type': 'qcow2',
|
||||
'new_file': snap_file}
|
||||
|
||||
snap_ref_progress = snap_ref.copy()
|
||||
snap_ref_progress['status'] = fields.SnapshotStatus.CREATING
|
||||
|
||||
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
|
||||
]
|
||||
mock_snapshot_get.side_effect = SideEffectList(
|
||||
snap_ref,
|
||||
progress = ['0%', '50%', '90%'])
|
||||
|
||||
drv._create_snapshot_online(snap_ref, snap_file, snap_path)
|
||||
mock_do_create_snapshot.\
|
||||
|
@ -999,7 +986,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
drv = self._driver
|
||||
|
||||
volume = self._simple_volume()
|
||||
volume['status'] = 'in-use'
|
||||
volume.status = 'in-use'
|
||||
|
||||
hashed = drv._get_hash_str(self.TEST_EXPORT1)
|
||||
volume_file = 'volume-%s' % self.VOLUME_UUID
|
||||
|
@ -1009,11 +996,12 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
|
||||
ctxt = context.RequestContext('fake_user', 'fake_project')
|
||||
|
||||
snap_ref = {'name': 'test snap (online)',
|
||||
'volume_id': self.VOLUME_UUID,
|
||||
'volume': volume,
|
||||
'id': self.SNAP_UUID,
|
||||
'context': ctxt}
|
||||
snap_ref = fake_snapshot.fake_snapshot_obj(
|
||||
ctxt,
|
||||
display_name='test snap (online)',
|
||||
volume_id=self.VOLUME_UUID,
|
||||
id=self.SNAP_UUID)
|
||||
snap_ref.context = ctxt
|
||||
|
||||
snap_path = '%s.%s' % (volume_path, 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(drv, '_nova') as mock_nova,\
|
||||
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()
|
||||
snap_ref_progress_0p['progress'] = '0%'
|
||||
|
||||
snap_ref_progress_50p = snap_ref_progress.copy()
|
||||
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
|
||||
]
|
||||
mock_snapshot_get.side_effect = SideEffectList(
|
||||
snap_ref,
|
||||
progress = ['0%', '50%', '99%'],
|
||||
status = ["creating", "creating", "error"])
|
||||
|
||||
self.assertRaisesAndMessageMatches(
|
||||
exception.RemoteFSException,
|
||||
|
@ -1054,15 +1030,19 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
drv = self._driver
|
||||
|
||||
volume = self._simple_volume()
|
||||
volume['status'] = 'in-use'
|
||||
volume.status = 'in-use'
|
||||
|
||||
ctxt = context.RequestContext('fake_user', 'fake_project')
|
||||
|
||||
snap_ref = {'name': 'test snap to delete (online)',
|
||||
'volume_id': self.VOLUME_UUID,
|
||||
'volume': volume,
|
||||
'id': self.SNAP_UUID,
|
||||
'context': ctxt}
|
||||
snap_ref = fake_snapshot.fake_snapshot_obj(
|
||||
ctxt,
|
||||
display_name='test snap to delete (online)',
|
||||
volume_id=self.VOLUME_UUID,
|
||||
status="deleting",
|
||||
id=self.SNAP_UUID)
|
||||
snap_ref.context = ctxt
|
||||
|
||||
snap_ref.volume = volume
|
||||
|
||||
hashed = drv._get_hash_str(self.TEST_EXPORT1)
|
||||
volume_file = 'volume-%s' % self.VOLUME_UUID
|
||||
|
@ -1120,22 +1100,8 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
'volume_id': self.VOLUME_UUID
|
||||
}
|
||||
|
||||
snap_ref_progress = snap_ref.copy()
|
||||
snap_ref_progress['status'] = 'deleting'
|
||||
|
||||
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
|
||||
]
|
||||
mock_snapshot_get.side_effect = SideEffectList(
|
||||
snap_ref, progress = ['0%', '50%', '90%'])
|
||||
|
||||
drv.delete_snapshot(snap_ref)
|
||||
|
||||
|
@ -1156,15 +1122,18 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
drv = self._driver
|
||||
|
||||
volume = self._simple_volume()
|
||||
volume['status'] = 'in-use'
|
||||
volume.status = 'in-use'
|
||||
|
||||
ctxt = context.RequestContext('fake_user', 'fake_project')
|
||||
|
||||
snap_ref = {'name': 'test snap to delete (online)',
|
||||
'volume_id': self.VOLUME_UUID,
|
||||
'volume': volume,
|
||||
'id': self.SNAP_UUID,
|
||||
'context': ctxt}
|
||||
snap_ref = fake_snapshot.fake_snapshot_obj(
|
||||
ctxt,
|
||||
display_name='test snap to delete (online)',
|
||||
volume_id=self.VOLUME_UUID,
|
||||
status='deleting',
|
||||
id=self.SNAP_UUID)
|
||||
snap_ref.volume = volume
|
||||
snap_ref.context = ctxt
|
||||
|
||||
hashed = drv._get_hash_str(self.TEST_EXPORT1)
|
||||
volume_file = 'volume-%s' % self.VOLUME_UUID
|
||||
|
@ -1225,21 +1194,8 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
'file_to_merge': snap_file,
|
||||
'volume_id': self.VOLUME_UUID}
|
||||
|
||||
snap_ref_progress = snap_ref.copy()
|
||||
snap_ref_progress['status'] = 'deleting'
|
||||
|
||||
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]
|
||||
mock_snapshot_get.side_effect = SideEffectList(
|
||||
snap_ref, progress = ['0%', '50%', '90%'])
|
||||
|
||||
drv.delete_snapshot(snap_ref)
|
||||
|
||||
|
@ -1260,15 +1216,17 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
drv = self._driver
|
||||
|
||||
volume = self._simple_volume()
|
||||
volume['status'] = 'in-use'
|
||||
volume.status = 'in-use'
|
||||
|
||||
ctxt = context.RequestContext('fake_user', 'fake_project')
|
||||
|
||||
snap_ref = {'name': 'test snap to delete (online)',
|
||||
'volume_id': self.VOLUME_UUID,
|
||||
'volume': volume,
|
||||
'id': self.SNAP_UUID,
|
||||
'context': ctxt}
|
||||
snap_ref = fake_snapshot.fake_snapshot_obj(
|
||||
ctxt,
|
||||
display_name='test snap to delete (online)',
|
||||
volume_id=self.VOLUME_UUID,
|
||||
id=self.SNAP_UUID)
|
||||
snap_ref.volume = volume
|
||||
snap_ref.context = ctxt
|
||||
|
||||
hashed = drv._get_hash_str(self.TEST_EXPORT1)
|
||||
volume_file = 'volume-%s' % self.VOLUME_UUID
|
||||
|
@ -1320,23 +1278,10 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
return paths[args[0]]
|
||||
|
||||
mock_qemu_img_info.side_effect = img_info_side_effect
|
||||
|
||||
snap_ref_progress = snap_ref.copy()
|
||||
snap_ref_progress['status'] = 'deleting'
|
||||
|
||||
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]
|
||||
mock_snapshot_get.side_effect = SideEffectList(
|
||||
snap_ref,
|
||||
progress = ['0%', '50%', '99%'],
|
||||
status = ['deleting', 'deleting', 'error'])
|
||||
self.assertRaisesAndMessageMatches(exception.RemoteFSException,
|
||||
'Unable to delete snapshot',
|
||||
drv.delete_snapshot,
|
||||
|
@ -1355,9 +1300,9 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
self.TEST_MNT_POINT_BASE)
|
||||
|
||||
volume = self._simple_volume()
|
||||
vol_filename = volume['name']
|
||||
vol_filename_2 = volume['name'] + '.abcd'
|
||||
vol_filename_3 = volume['name'] + '.efef'
|
||||
vol_filename = volume.name
|
||||
vol_filename_2 = volume.name + '.abcd'
|
||||
vol_filename_3 = volume.name + '.efef'
|
||||
hashed = drv._get_hash_str(self.TEST_EXPORT1)
|
||||
vol_dir = '%s/%s' % (self.TEST_MNT_POINT_BASE, hashed)
|
||||
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,
|
||||
drv._get_hash_str(self.TEST_EXPORT1))
|
||||
src_vol_path = os.path.join(vol_dir, src_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'],
|
||||
'size': src_volume['size'],
|
||||
'volume_size': src_volume['size'],
|
||||
'volume_id': src_volume['id'],
|
||||
'id': 'tmp-snap-%s' % src_volume['id'],
|
||||
'volume': src_volume}
|
||||
snap_file = dest_volume['name'] + '.' + snapshot['id']
|
||||
size = dest_volume['size']
|
||||
src_vol_path = os.path.join(vol_dir, src_volume.name)
|
||||
dest_vol_path = os.path.join(vol_dir, dest_volume.name)
|
||||
|
||||
snapshot = fake_snapshot.fake_snapshot_obj(
|
||||
self.context,
|
||||
volume_name=src_volume.name,
|
||||
display_name='clone-snap-%s' % src_volume.id,
|
||||
size=src_volume.size,
|
||||
volume_size=src_volume.size,
|
||||
volume_id=src_volume.id,
|
||||
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,
|
||||
snapshot['id']: snap_file}
|
||||
snapshot.id: snap_file}
|
||||
qemu_img_output = """image: %s
|
||||
file format: raw
|
||||
virtual size: 1.0G (1073741824 bytes)
|
||||
disk size: 173K
|
||||
backing file: %s
|
||||
""" % (snap_file, src_volume['name'])
|
||||
""" % (snap_file, src_volume.name)
|
||||
img_info = imageutils.QemuImgInfo(qemu_img_output)
|
||||
mock_qemu_img_info.return_value = img_info
|
||||
|
||||
|
@ -1464,18 +1413,20 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
drv = self._driver
|
||||
|
||||
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'}
|
||||
snap_ref = fake_snapshot.fake_snapshot_obj(
|
||||
self.context,
|
||||
volume_name=src_volume.name,
|
||||
display_name='clone-snap-%s' % src_volume.id,
|
||||
size=src_volume.size,
|
||||
volume_size=src_volume.size,
|
||||
volume_id=src_volume.id,
|
||||
id=self.SNAP_UUID,
|
||||
status='available')
|
||||
snap_ref.volume = src_volume
|
||||
|
||||
new_volume = DumbVolume()
|
||||
new_volume['id'] = self.VOLUME_UUID
|
||||
new_volume['size'] = snap_ref['size']
|
||||
new_volume = fake_volume.fake_volume_obj(self.context,
|
||||
id=self.VOLUME_UUID,
|
||||
size=snap_ref.volume.size)
|
||||
|
||||
with mock.patch.object(drv, '_ensure_shares_mounted') as \
|
||||
mock_ensure_shares_mounted,\
|
||||
|
@ -1492,7 +1443,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
mock_do_create_volume.assert_called_once_with(new_volume)
|
||||
mock_copy_volume.assert_called_once_with(snap_ref,
|
||||
new_volume,
|
||||
new_volume['size'])
|
||||
new_volume.size)
|
||||
|
||||
def test_initialize_connection(self):
|
||||
drv = self._driver
|
||||
|
@ -1502,14 +1453,14 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
file format: raw
|
||||
virtual size: 1.0G (1073741824 bytes)
|
||||
disk size: 173K
|
||||
""" % volume['name']
|
||||
""" % volume.name
|
||||
img_info = imageutils.QemuImgInfo(qemu_img_output)
|
||||
|
||||
with mock.patch.object(drv, 'get_active_image_from_info') as \
|
||||
mock_get_active_image_from_info,\
|
||||
mock.patch.object(image_utils, 'qemu_img_info') as \
|
||||
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
|
||||
|
||||
conn_info = drv.initialize_connection(volume, None)
|
||||
|
@ -1539,7 +1490,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
mock_backup_volume:
|
||||
ctxt = context.RequestContext('fake_user', 'fake_project')
|
||||
volume = self._simple_volume()
|
||||
backup = {'volume_id': volume['id']}
|
||||
backup = {'volume_id': volume.id}
|
||||
mock_volume_get.return_value = volume
|
||||
mock_get_active_image_from_info.return_value = '/some/path'
|
||||
|
||||
|
@ -1566,7 +1517,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
mock_backup_volume:
|
||||
ctxt = context.RequestContext('fake_user', 'fake_project')
|
||||
volume = self._simple_volume()
|
||||
backup = {'volume_id': volume['id']}
|
||||
backup = {'volume_id': volume.id}
|
||||
mock_volume_get.return_value = volume
|
||||
mock_get_active_image_from_info.return_value = '/some/file2'
|
||||
|
||||
|
@ -1586,7 +1537,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
mock_snapshot_get_all_for_volume:
|
||||
ctxt = context.RequestContext('fake_user', 'fake_project')
|
||||
volume = self._simple_volume()
|
||||
backup = {'volume_id': volume['id']}
|
||||
backup = {'volume_id': volume.id}
|
||||
mock_snapshot_get_all_for_volume.return_value = [
|
||||
{'snap1': 'a'},
|
||||
{'snap2': 'b'}
|
||||
|
@ -1606,7 +1557,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
mock_qemu_img_info:
|
||||
ctxt = context.RequestContext('fake_user', 'fake_project')
|
||||
volume = self._simple_volume()
|
||||
backup = {'volume_id': volume['id']}
|
||||
backup = {'volume_id': volume.id}
|
||||
mock_volume_get.return_value = volume
|
||||
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:
|
||||
ctxt = context.RequestContext('fake_user', 'fake_project')
|
||||
volume = self._simple_volume()
|
||||
backup = {'volume_id': volume['id']}
|
||||
backup = {'volume_id': volume.id}
|
||||
mock_volume_get.return_value = volume
|
||||
mock_get_active_image_from_info.return_value = '/some/path'
|
||||
|
||||
|
@ -1651,7 +1602,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
drv = self._driver
|
||||
|
||||
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'}
|
||||
|
||||
with mock.patch.object(drv, 'get_active_image_from_info') as \
|
||||
|
@ -1664,7 +1615,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
mock_upload_volume, \
|
||||
mock.patch.object(image_utils, 'create_temporary_file') as \
|
||||
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
|
||||
|
||||
|
@ -1674,7 +1625,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
file format: raw
|
||||
virtual size: 1.0G (1073741824 bytes)
|
||||
disk size: 173K
|
||||
""" % volume['name']
|
||||
""" % volume.name
|
||||
img_info = imageutils.QemuImgInfo(qemu_img_output)
|
||||
mock_qemu_img_info.return_value = img_info
|
||||
|
||||
|
@ -1694,7 +1645,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
drv = self._driver
|
||||
|
||||
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'}
|
||||
|
||||
with mock.patch.object(drv, 'get_active_image_from_info') as \
|
||||
|
@ -1709,7 +1660,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
mock_upload_volume, \
|
||||
mock.patch.object(image_utils, 'create_temporary_file') as \
|
||||
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
|
||||
|
||||
|
@ -1719,7 +1670,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
file format: qcow2
|
||||
virtual size: 1.0G (1073741824 bytes)
|
||||
disk size: 173K
|
||||
""" % volume['name']
|
||||
""" % volume.name
|
||||
img_info = imageutils.QemuImgInfo(qemu_img_output)
|
||||
mock_qemu_img_info.return_value = img_info
|
||||
|
||||
|
@ -1757,7 +1708,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||
mock_upload_volume, \
|
||||
mock.patch.object(image_utils, 'create_temporary_file') as \
|
||||
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
|
||||
|
||||
|
|
|
@ -23,9 +23,11 @@ import mock
|
|||
from mox3 import mox as mox_lib
|
||||
import six
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.image import image_utils
|
||||
from cinder import test
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder import utils as cinder_utils
|
||||
from cinder.volume import configuration as conf
|
||||
from cinder.volume.drivers.netapp import common
|
||||
|
@ -158,6 +160,7 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
|
|||
self._driver.ssc_library = mock.Mock()
|
||||
config = self._driver.configuration
|
||||
config.netapp_vserver = FAKE_VSERVER
|
||||
self.context = context.get_admin_context()
|
||||
|
||||
def test_create_snapshot(self):
|
||||
"""Test snapshot can be created and deleted."""
|
||||
|
@ -519,7 +522,8 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
|
|||
def test_clone_image_cloneableshare_raw(self):
|
||||
drv = self._driver
|
||||
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(drv, '_find_image_in_cache')
|
||||
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).\
|
||||
AndReturn(self.get_img_info('raw'))
|
||||
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._discover_file_till_timeout(mox_lib.IgnoreArg()).AndReturn(True)
|
||||
drv._set_rw_permissions('/mnt/vol')
|
||||
drv._resize_image_file({'name': 'vol'}, mox_lib.IgnoreArg())
|
||||
drv._set_rw_permissions('/mnt/%s' % volume_name)
|
||||
drv._resize_image_file({'name': volume_name}, mox_lib.IgnoreArg())
|
||||
|
||||
mox.ReplayAll()
|
||||
drv.clone_image(
|
||||
|
@ -559,7 +563,8 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
|
|||
def test_clone_image_cloneableshare_notraw(self):
|
||||
drv = self._driver
|
||||
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(drv, '_find_image_in_cache')
|
||||
mox.StubOutWithMock(drv, '_is_cloneable_share')
|
||||
|
@ -572,6 +577,7 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
|
|||
mox.StubOutWithMock(image_utils, 'convert_image')
|
||||
mox.StubOutWithMock(drv, '_register_image_in_cache')
|
||||
mox.StubOutWithMock(drv, '_is_share_clone_compatible')
|
||||
mox.StubOutWithMock(drv, '_do_qos_for_volume')
|
||||
|
||||
utils.get_volume_extra_specs(mox_lib.IgnoreArg())
|
||||
drv._find_image_in_cache(mox_lib.IgnoreArg()).AndReturn([])
|
||||
|
@ -585,13 +591,15 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
|
|||
image_utils.convert_image(mox_lib.IgnoreArg(),
|
||||
mox_lib.IgnoreArg(),
|
||||
'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'))
|
||||
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._discover_file_till_timeout(mox_lib.IgnoreArg()).AndReturn(True)
|
||||
drv._set_rw_permissions('/mnt/vol')
|
||||
drv._resize_image_file({'name': 'vol'}, mox_lib.IgnoreArg())
|
||||
drv._set_rw_permissions('/mnt/%s' % volume_name)
|
||||
drv._resize_image_file({'name': volume_name}, mox_lib.IgnoreArg())
|
||||
|
||||
mox.ReplayAll()
|
||||
drv.clone_image(
|
||||
|
@ -605,7 +613,8 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
|
|||
def test_clone_image_file_not_discovered(self):
|
||||
drv = self._driver
|
||||
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(drv, '_find_image_in_cache')
|
||||
mox.StubOutWithMock(drv, '_is_cloneable_share')
|
||||
|
@ -631,12 +640,12 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
|
|||
image_utils.convert_image(mox_lib.IgnoreArg(),
|
||||
mox_lib.IgnoreArg(),
|
||||
'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'))
|
||||
drv._register_image_in_cache(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)
|
||||
|
||||
mox.ReplayAll()
|
||||
|
@ -1180,6 +1189,8 @@ class NetAppCmodeNfsDriverOnlyTestCase(test.TestCase):
|
|||
'spec': None,
|
||||
}
|
||||
|
||||
self.context = context.get_admin_context()
|
||||
|
||||
@mock.patch.object(utils, 'LOG', mock.Mock())
|
||||
def test_create_volume(self):
|
||||
drv = self._driver
|
||||
|
@ -1234,47 +1245,48 @@ class NetAppCmodeNfsDriverOnlyTestCase(test.TestCase):
|
|||
|
||||
def test_copy_img_to_vol_copyoffload_success(self):
|
||||
drv = self._driver
|
||||
context = object()
|
||||
volume = {'id': 'vol_id', 'name': 'name'}
|
||||
volume = fake_volume.fake_volume_obj(self.context)
|
||||
image_service = object()
|
||||
image_id = 'image_id'
|
||||
drv.zapi_client.get_ontapi_version = mock.Mock(return_value=(1, 20))
|
||||
drv._copy_from_img_service = mock.Mock()
|
||||
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.copy_image_to_volume(context, volume, image_service, image_id)
|
||||
drv._copy_from_img_service.assert_called_once_with(context, volume,
|
||||
drv.copy_image_to_volume(self.context, volume, image_service, image_id)
|
||||
drv._copy_from_img_service.assert_called_once_with(self.context,
|
||||
volume,
|
||||
image_service,
|
||||
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):
|
||||
drv = self._driver
|
||||
context = object()
|
||||
volume = {'id': 'vol_id', 'name': 'name'}
|
||||
volume = fake_volume.fake_volume_obj(self.context)
|
||||
|
||||
image_service = object()
|
||||
image_id = 'image_id'
|
||||
drv.zapi_client.get_ontapi_version = mock.Mock(return_value=(1, 20))
|
||||
drv._copy_from_img_service = mock.Mock(side_effect=Exception())
|
||||
nfs_base.NetAppNfsDriver.copy_image_to_volume = mock.Mock()
|
||||
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.copy_image_to_volume(context, volume, image_service, image_id)
|
||||
drv._copy_from_img_service.assert_called_once_with(context, volume,
|
||||
drv.copy_image_to_volume(self.context, volume, image_service, image_id)
|
||||
drv._copy_from_img_service.assert_called_once_with(self.context,
|
||||
volume,
|
||||
image_service,
|
||||
image_id)
|
||||
nfs_base.NetAppNfsDriver.copy_image_to_volume. \
|
||||
assert_called_once_with(context, volume, image_service, image_id)
|
||||
drv._update_stale_vols.assert_called_once_with('vol')
|
||||
assert_called_once_with(self.context, volume,
|
||||
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):
|
||||
drv = self._driver
|
||||
context = object()
|
||||
volume = {'id': 'vol_id', 'name': 'name'}
|
||||
volume = fake_volume.fake_volume_obj(self.context)
|
||||
image_service = mock.Mock()
|
||||
image_service.get_location.return_value = (mock.Mock(), mock.Mock())
|
||||
image_service.show.return_value = {'size': 0}
|
||||
|
@ -1296,15 +1308,14 @@ class NetAppCmodeNfsDriverOnlyTestCase(test.TestCase):
|
|||
|
||||
# Verify the original error is propagated
|
||||
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')
|
||||
def test_img_service_raw_copyoffload_workflow_success(self,
|
||||
mock_qemu_img_info):
|
||||
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'
|
||||
context = object()
|
||||
image_service = mock.Mock()
|
||||
image_service.get_location.return_value = ('nfs://ip1/openstack/img',
|
||||
None)
|
||||
|
@ -1329,9 +1340,10 @@ class NetAppCmodeNfsDriverOnlyTestCase(test.TestCase):
|
|||
drv._clone_file_dst_exists = 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_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)
|
||||
|
||||
assert drv._execute.call_count == 1
|
||||
|
@ -1344,9 +1356,8 @@ class NetAppCmodeNfsDriverOnlyTestCase(test.TestCase):
|
|||
mock_qemu_img_info,
|
||||
mock_cvrt_image):
|
||||
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'
|
||||
context = object()
|
||||
image_service = mock.Mock()
|
||||
image_service.get_location.return_value = ('nfs://ip1/openstack/img',
|
||||
None)
|
||||
|
@ -1371,9 +1382,10 @@ class NetAppCmodeNfsDriverOnlyTestCase(test.TestCase):
|
|||
drv._clone_file_dst_exists = 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_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)
|
||||
assert mock_cvrt_image.call_count == 1
|
||||
assert drv._execute.call_count == 1
|
||||
|
@ -1393,6 +1405,7 @@ class NetApp7modeNfsDriverTestCase(NetAppCmodeNfsDriverTestCase):
|
|||
self._driver = netapp_nfs_7mode.NetApp7modeNfsDriver(
|
||||
configuration=create_configuration())
|
||||
self._driver.zapi_client = mock.Mock()
|
||||
self.context = context.get_admin_context()
|
||||
|
||||
def _prepare_delete_snapshot_mock(self, snapshot_exists):
|
||||
drv = self._driver
|
||||
|
|
|
@ -21,25 +21,16 @@ import os
|
|||
import mock
|
||||
from oslo_utils import units
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.image import image_utils
|
||||
from cinder import test
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder.volume import configuration as conf
|
||||
from cinder.volume.drivers import nfs
|
||||
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):
|
||||
TEST_FILE_NAME = 'test.txt'
|
||||
TEST_EXPORT = 'nas-host1:/export'
|
||||
|
@ -346,18 +337,19 @@ class NfsDriverTestCase(test.TestCase):
|
|||
mock_exc = mock.patch.object(self._driver, '_execute')
|
||||
self._execute = mock_exc.start()
|
||||
self.addCleanup(mock_exc.stop)
|
||||
self.context = context.get_admin_context()
|
||||
|
||||
def test_local_path(self):
|
||||
"""local_path common use case."""
|
||||
self.configuration.nfs_mount_point_base = self.TEST_MNT_POINT_BASE
|
||||
drv = self._driver
|
||||
|
||||
volume = DumbVolume()
|
||||
volume['provider_location'] = self.TEST_NFS_EXPORT1
|
||||
volume['name'] = 'volume-123'
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
self.context,
|
||||
provider_location=self.TEST_NFS_EXPORT1)
|
||||
|
||||
self.assertEqual(
|
||||
'/mnt/test/2f4f60214cf43c595666dd815f0360a4/volume-123',
|
||||
'/mnt/test/2f4f60214cf43c595666dd815f0360a4/%s' % volume.name,
|
||||
drv.local_path(volume))
|
||||
|
||||
@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):
|
||||
"""resize_image common case usage."""
|
||||
drv = self._driver
|
||||
TEST_IMG_SOURCE = 'foo.img'
|
||||
volume = {'size': self.TEST_SIZE_IN_GB, 'name': TEST_IMG_SOURCE}
|
||||
volume = fake_volume.fake_volume_obj(self.context,
|
||||
size=self.TEST_SIZE_IN_GB)
|
||||
TEST_IMG_SOURCE = 'volume-%s' % volume.id
|
||||
|
||||
with mock.patch.object(drv, 'local_path',
|
||||
return_value=TEST_IMG_SOURCE):
|
||||
|
@ -581,12 +574,10 @@ class NfsDriverTestCase(test.TestCase):
|
|||
self.assertEqual(2, mock_get_capacity_info.call_count)
|
||||
|
||||
def _simple_volume(self):
|
||||
volume = DumbVolume()
|
||||
volume['provider_location'] = '127.0.0.1:/mnt'
|
||||
volume['name'] = 'volume_name'
|
||||
volume['size'] = 10
|
||||
|
||||
return volume
|
||||
return fake_volume.fake_volume_obj(self.context,
|
||||
display_name='volume_name',
|
||||
provider_location='127.0.0.1:/mnt',
|
||||
size=10)
|
||||
|
||||
def test_create_sparsed_volume(self):
|
||||
drv = self._driver
|
||||
|
@ -626,13 +617,14 @@ class NfsDriverTestCase(test.TestCase):
|
|||
"""create_volume ensures shares provided in config are mounted."""
|
||||
drv = self._driver
|
||||
drv._find_share = mock.Mock()
|
||||
drv._find_share.return_value = self.TEST_NFS_EXPORT1
|
||||
drv._do_create_volume = mock.Mock()
|
||||
|
||||
with mock.patch.object(
|
||||
drv, '_ensure_share_mounted') as mock_ensure_share:
|
||||
drv._ensure_share_mounted()
|
||||
volume = DumbVolume()
|
||||
volume['size'] = self.TEST_SIZE_IN_GB
|
||||
volume = fake_volume.fake_volume_obj(self.context,
|
||||
size=self.TEST_SIZE_IN_GB)
|
||||
drv.create_volume(volume)
|
||||
|
||||
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:
|
||||
mock_find_share.return_value = self.TEST_NFS_EXPORT1
|
||||
volume = DumbVolume()
|
||||
volume['size'] = self.TEST_SIZE_IN_GB
|
||||
volume = fake_volume.fake_volume_obj(self.context,
|
||||
size=self.TEST_SIZE_IN_GB)
|
||||
result = drv.create_volume(volume)
|
||||
self.assertEqual(self.TEST_NFS_EXPORT1,
|
||||
result['provider_location'])
|
||||
|
@ -658,9 +650,10 @@ class NfsDriverTestCase(test.TestCase):
|
|||
drv = self._driver
|
||||
drv._ensure_share_mounted = mock.Mock()
|
||||
|
||||
volume = DumbVolume()
|
||||
volume['name'] = 'volume-123'
|
||||
volume['provider_location'] = self.TEST_NFS_EXPORT1
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
self.context,
|
||||
display_name='volume-123',
|
||||
provider_location=self.TEST_NFS_EXPORT1)
|
||||
|
||||
with mock.patch.object(drv, 'local_path') as mock_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):
|
||||
"""delete_volume should ensure that corresponding share is mounted."""
|
||||
drv = self._driver
|
||||
volume = DumbVolume()
|
||||
volume['name'] = 'volume-123'
|
||||
volume['provider_location'] = self.TEST_NFS_EXPORT1
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
self.context,
|
||||
display_name='volume-123',
|
||||
provider_location=self.TEST_NFS_EXPORT1)
|
||||
|
||||
with mock.patch.object(
|
||||
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):
|
||||
"""delete_volume shouldn't delete if provider_location missed."""
|
||||
drv = self._driver
|
||||
volume = DumbVolume()
|
||||
volume['name'] = 'volume-123'
|
||||
volume['provider_location'] = None
|
||||
volume = fake_volume.fake_volume_obj(self.context,
|
||||
name='volume-123',
|
||||
provider_location=None)
|
||||
|
||||
with mock.patch.object(drv, '_ensure_share_mounted'):
|
||||
drv.delete_volume(volume)
|
||||
|
@ -846,8 +840,11 @@ class NfsDriverTestCase(test.TestCase):
|
|||
def test_extend_volume(self):
|
||||
"""Extend a volume by 1."""
|
||||
drv = self._driver
|
||||
volume = {'id': '80ee16b6-75d2-4d54-9539-ffc1b4b0fb10', 'size': 1,
|
||||
'provider_location': 'nfs_share'}
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
self.context,
|
||||
id='80ee16b6-75d2-4d54-9539-ffc1b4b0fb10',
|
||||
size=1,
|
||||
provider_location='nfs_share')
|
||||
path = 'path'
|
||||
newSize = volume['size'] + 1
|
||||
|
||||
|
@ -865,8 +862,11 @@ class NfsDriverTestCase(test.TestCase):
|
|||
def test_extend_volume_failure(self):
|
||||
"""Error during extend operation."""
|
||||
drv = self._driver
|
||||
volume = {'id': '80ee16b6-75d2-4d54-9539-ffc1b4b0fb10', 'size': 1,
|
||||
'provider_location': 'nfs_share'}
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
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(drv, 'local_path', return_value='path'):
|
||||
|
@ -880,8 +880,11 @@ class NfsDriverTestCase(test.TestCase):
|
|||
def test_extend_volume_insufficient_space(self):
|
||||
"""Insufficient space on nfs_share during extend operation."""
|
||||
drv = self._driver
|
||||
volume = {'id': '80ee16b6-75d2-4d54-9539-ffc1b4b0fb10', 'size': 1,
|
||||
'provider_location': 'nfs_share'}
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
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(drv, 'local_path', return_value='path'):
|
||||
|
@ -1125,8 +1128,8 @@ class NfsDriverDoSetupTestCase(test.TestCase):
|
|||
def _test_update_migrated_volume(self, volume_status, rename_volume,
|
||||
rename_exception=False):
|
||||
drv = nfs.NfsDriver(configuration=self.configuration)
|
||||
fake_volume_id = 'vol1'
|
||||
fake_new_volume_id = 'vol2'
|
||||
fake_volume_id = 'f51b5730-13b7-11e6-a238-fa163e67a298'
|
||||
fake_new_volume_id = '12341234-13b7-11e6-a238-fa163e67a298'
|
||||
fake_provider_source = 'fake_provider_source'
|
||||
fake_provider = 'fake_provider'
|
||||
base_dir = '/dir_base/'
|
||||
|
@ -1135,27 +1138,34 @@ class NfsDriverDoSetupTestCase(test.TestCase):
|
|||
current_name = volume_name_template % fake_new_volume_id
|
||||
original_volume_path = base_dir + original_volume_name
|
||||
current_path = base_dir + current_name
|
||||
fake_volume = {'size': 1, 'id': fake_volume_id,
|
||||
'provider_location': fake_provider_source,
|
||||
'_name_id': None}
|
||||
fake_new_volume = {'size': 1, 'id': fake_new_volume_id,
|
||||
'provider_location': fake_provider,
|
||||
'_name_id': None}
|
||||
volume = fake_volume.fake_volume_obj(
|
||||
self.context,
|
||||
id=fake_volume_id,
|
||||
size=1,
|
||||
provider_location=fake_provider_source,
|
||||
_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:
|
||||
local_path.return_value = base_dir + current_name
|
||||
if volume_status == 'in-use':
|
||||
update = drv.update_migrated_volume(self.context,
|
||||
fake_volume,
|
||||
fake_new_volume,
|
||||
volume,
|
||||
new_volume,
|
||||
volume_status)
|
||||
self.assertEqual({'_name_id': fake_new_volume_id,
|
||||
'provider_location': fake_provider}, update)
|
||||
elif rename_exception:
|
||||
rename_volume.side_effect = OSError
|
||||
update = drv.update_migrated_volume(self.context,
|
||||
fake_volume,
|
||||
fake_new_volume,
|
||||
volume,
|
||||
new_volume,
|
||||
volume_status)
|
||||
rename_volume.assert_called_once_with(current_path,
|
||||
original_volume_path)
|
||||
|
@ -1163,8 +1173,8 @@ class NfsDriverDoSetupTestCase(test.TestCase):
|
|||
'provider_location': fake_provider}, update)
|
||||
else:
|
||||
update = drv.update_migrated_volume(self.context,
|
||||
fake_volume,
|
||||
fake_new_volume,
|
||||
volume,
|
||||
new_volume,
|
||||
volume_status)
|
||||
rename_volume.assert_called_once_with(current_path,
|
||||
original_volume_path)
|
||||
|
@ -1175,7 +1185,7 @@ class NfsDriverDoSetupTestCase(test.TestCase):
|
|||
"Ensure that driver.retype() is there."""
|
||||
|
||||
drv = nfs.NfsDriver(configuration=self.configuration)
|
||||
v1 = DumbVolume()
|
||||
v1 = fake_volume.fake_volume_obj(self.context)
|
||||
|
||||
ret = drv.retype(self.context,
|
||||
v1,
|
||||
|
|
|
@ -30,6 +30,8 @@ from cinder import context
|
|||
from cinder import exception
|
||||
from cinder.image import image_utils
|
||||
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.drivers import quobyte
|
||||
|
||||
|
@ -37,16 +39,6 @@ from cinder.volume.drivers import quobyte
|
|||
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):
|
||||
msg = "Tests are broken: mock this out."
|
||||
|
||||
|
@ -66,7 +58,6 @@ class QuobyteDriverTestCase(test.TestCase):
|
|||
TEST_SIZE_IN_GB = 1
|
||||
TEST_MNT_POINT = '/mnt/quobyte'
|
||||
TEST_MNT_POINT_BASE = '/mnt'
|
||||
TEST_LOCAL_PATH = '/mnt/quobyte/volume-123'
|
||||
TEST_FILE_NAME = 'test.txt'
|
||||
TEST_SHARES_CONFIG_FILE = '/etc/cinder/test-shares.conf'
|
||||
TEST_TMP_FILE = '/tmp/tempfile'
|
||||
|
@ -94,6 +85,7 @@ class QuobyteDriverTestCase(test.TestCase):
|
|||
db=FakeDb())
|
||||
self._driver.shares = {}
|
||||
self._driver.set_nas_security_options(is_new_cinder_install=False)
|
||||
self.context = context.get_admin_context()
|
||||
|
||||
def assertRaisesAndMessageMatches(
|
||||
self, excClass, msg, callableObj, *args, **kwargs):
|
||||
|
@ -115,13 +107,11 @@ class QuobyteDriverTestCase(test.TestCase):
|
|||
def test_local_path(self):
|
||||
"""local_path common use case."""
|
||||
drv = self._driver
|
||||
|
||||
volume = DumbVolume()
|
||||
volume['provider_location'] = self.TEST_QUOBYTE_VOLUME
|
||||
volume['name'] = 'volume-123'
|
||||
vol_id = self.VOLUME_UUID
|
||||
volume = self._simple_volume(_name_id=vol_id)
|
||||
|
||||
self.assertEqual(
|
||||
'/mnt/1331538734b757ed52d0e18c0a7210cd/volume-123',
|
||||
'/mnt/1331538734b757ed52d0e18c0a7210cd/volume-%s' % vol_id,
|
||||
drv.local_path(volume))
|
||||
|
||||
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.
|
||||
self.assertGreaterEqual(mock_get_available_capacity.call_count, 0)
|
||||
|
||||
def _simple_volume(self, uuid=None):
|
||||
volume = DumbVolume()
|
||||
volume['provider_location'] = self.TEST_QUOBYTE_VOLUME
|
||||
if uuid is None:
|
||||
volume['id'] = self.VOLUME_UUID
|
||||
else:
|
||||
volume['id'] = uuid
|
||||
# volume['name'] mirrors format from db/sqlalchemy/models.py
|
||||
volume['name'] = 'volume-%s' % volume['id']
|
||||
volume['size'] = 10
|
||||
volume['status'] = 'available'
|
||||
def _simple_volume(self, **kwargs):
|
||||
updates = {'id': self.VOLUME_UUID,
|
||||
'provider_location': self.TEST_QUOBYTE_VOLUME,
|
||||
'display_name': 'volume-%s' % self.VOLUME_UUID,
|
||||
'size': 10,
|
||||
'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):
|
||||
drv = self._driver
|
||||
|
@ -501,11 +490,11 @@ class QuobyteDriverTestCase(test.TestCase):
|
|||
|
||||
drv.LOG = mock.Mock()
|
||||
drv._find_share = mock.Mock()
|
||||
drv._find_share.return_value = self.TEST_QUOBYTE_VOLUME
|
||||
drv._do_create_volume = mock.Mock()
|
||||
drv._ensure_shares_mounted = mock.Mock()
|
||||
|
||||
volume = DumbVolume()
|
||||
volume['size'] = self.TEST_SIZE_IN_GB
|
||||
volume = self._simple_volume(size=self.TEST_SIZE_IN_GB)
|
||||
drv.create_volume(volume)
|
||||
|
||||
drv._find_share.assert_called_once_with(mock.ANY)
|
||||
|
@ -521,8 +510,7 @@ class QuobyteDriverTestCase(test.TestCase):
|
|||
drv._do_create_volume = mock.Mock()
|
||||
drv._find_share = mock.Mock(return_value=self.TEST_QUOBYTE_VOLUME)
|
||||
|
||||
volume = DumbVolume()
|
||||
volume['size'] = self.TEST_SIZE_IN_GB
|
||||
volume = self._simple_volume(size=self.TEST_SIZE_IN_GB)
|
||||
result = drv.create_volume(volume)
|
||||
self.assertEqual(self.TEST_QUOBYTE_VOLUME, result['provider_location'])
|
||||
|
||||
|
@ -575,9 +563,7 @@ class QuobyteDriverTestCase(test.TestCase):
|
|||
|
||||
drv._execute = mock.Mock()
|
||||
|
||||
volume = DumbVolume()
|
||||
volume['name'] = 'volume-123'
|
||||
volume['provider_location'] = self.TEST_QUOBYTE_VOLUME
|
||||
volume = self._simple_volume(display_name='volume-123')
|
||||
|
||||
drv._ensure_share_mounted = mock.Mock()
|
||||
|
||||
|
@ -596,9 +582,8 @@ class QuobyteDriverTestCase(test.TestCase):
|
|||
drv._ensure_share_mounted = mock.Mock()
|
||||
drv._execute = mock.Mock()
|
||||
|
||||
volume = DumbVolume()
|
||||
volume['name'] = 'volume-123'
|
||||
volume['provider_location'] = None
|
||||
volume = self._simple_volume(display_name='volume-123',
|
||||
provider_location=None)
|
||||
|
||||
drv.delete_volume(volume)
|
||||
|
||||
|
@ -638,7 +623,7 @@ class QuobyteDriverTestCase(test.TestCase):
|
|||
|
||||
# lots of test vars to be prepared at first
|
||||
dest_volume = self._simple_volume(
|
||||
'c1073000-0000-0000-0000-0000000c1073')
|
||||
id='c1073000-0000-0000-0000-0000000c1073')
|
||||
src_volume = self._simple_volume()
|
||||
|
||||
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'])
|
||||
info_path = os.path.join(vol_dir, src_volume['name']) + '.info'
|
||||
|
||||
snapshot = {'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}
|
||||
snapshot = fake_snapshot.fake_snapshot_obj(
|
||||
self.context,
|
||||
volume_name=src_volume.name,
|
||||
display_name='clone-snap-%s' % src_volume.id,
|
||||
size=src_volume.size,
|
||||
volume_size=src_volume.size,
|
||||
volume_id=src_volume.id,
|
||||
id=self.SNAP_UUID)
|
||||
snapshot.volume = src_volume
|
||||
|
||||
snap_file = dest_volume['name'] + '.' + snapshot['id']
|
||||
snap_path = os.path.join(vol_dir, snap_file)
|
||||
|
@ -692,17 +679,18 @@ class QuobyteDriverTestCase(test.TestCase):
|
|||
drv = self._driver
|
||||
|
||||
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()
|
||||
new_volume['size'] = snap_ref['size']
|
||||
snap_ref = fake_snapshot.fake_snapshot_obj(
|
||||
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,
|
||||
drv.create_volume_from_snapshot,
|
||||
|
@ -713,17 +701,18 @@ class QuobyteDriverTestCase(test.TestCase):
|
|||
drv = self._driver
|
||||
|
||||
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()
|
||||
new_volume['size'] = snap_ref['size']
|
||||
snap_ref = fake_snapshot.fake_snapshot_obj(
|
||||
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._find_share = mock.Mock(return_value=self.TEST_QUOBYTE_VOLUME)
|
||||
|
|
|
@ -12,15 +12,19 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import collections
|
||||
import copy
|
||||
import os
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.image import image_utils
|
||||
from cinder import test
|
||||
from cinder.tests.unit import fake_snapshot
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder import utils
|
||||
from cinder.volume.drivers import remotefs
|
||||
|
||||
|
@ -28,25 +32,7 @@ from cinder.volume.drivers import remotefs
|
|||
@ddt.ddt
|
||||
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_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):
|
||||
super(RemoteFsSnapDriverTestCase, self).setUp()
|
||||
|
@ -55,21 +41,32 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
|
|||
self._driver._execute = 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,
|
||||
stale_snapshot=False,
|
||||
is_active_image=True):
|
||||
# If the snapshot is not the active image, it is guaranteed that
|
||||
# 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,
|
||||
self._FAKE_SNAPSHOT['id']: fake_snapshot_name}
|
||||
self._fake_snapshot.id: fake_snapshot_name}
|
||||
fake_snap_img_info = mock.Mock()
|
||||
fake_base_img_info = mock.Mock()
|
||||
if stale_snapshot:
|
||||
fake_snap_img_info.backing_file = None
|
||||
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_base_img_info.backing_file = None
|
||||
fake_base_img_info.file_format = 'raw'
|
||||
|
@ -91,72 +88,71 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
|
|||
|
||||
expected_info = {
|
||||
'active': fake_snapshot_name,
|
||||
self._FAKE_SNAPSHOT_ID: fake_snapshot_name
|
||||
self._fake_snapshot.id: fake_snapshot_name
|
||||
}
|
||||
|
||||
if volume_in_use:
|
||||
fake_snapshot = copy.deepcopy(self._FAKE_SNAPSHOT)
|
||||
fake_snapshot['volume']['status'] = 'in-use'
|
||||
self._fake_snapshot.volume.status = 'in-use'
|
||||
|
||||
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:
|
||||
self._driver._delete_stale_snapshot.assert_called_once_with(
|
||||
fake_snapshot)
|
||||
self._fake_snapshot)
|
||||
else:
|
||||
expected_online_delete_info = {
|
||||
'active_file': fake_snapshot_name,
|
||||
'snapshot_file': fake_snapshot_name,
|
||||
'base_file': self._FAKE_VOLUME_NAME,
|
||||
'base_file': self._fake_volume.name,
|
||||
'base_id': None,
|
||||
'new_base_file': None
|
||||
}
|
||||
self._driver._delete_snapshot_online.assert_called_once_with(
|
||||
self._FAKE_CONTEXT, fake_snapshot,
|
||||
self.context, self._fake_snapshot,
|
||||
expected_online_delete_info)
|
||||
|
||||
elif is_active_image:
|
||||
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._FAKE_SNAPSHOT_PATH)
|
||||
self.assertNotIn(self._FAKE_SNAPSHOT_ID, fake_info)
|
||||
self._fake_snapshot_path)
|
||||
self.assertNotIn(self._fake_snapshot.id, fake_info)
|
||||
self._driver._write_info_file.assert_called_once_with(
|
||||
mock.sentinel.fake_info_path, fake_info)
|
||||
else:
|
||||
fake_upper_snap_id = 'fake_upper_snap_id'
|
||||
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_backing_chain = [
|
||||
{'filename': fake_upper_snap_name,
|
||||
'backing-filename': fake_snapshot_name},
|
||||
{'filename': fake_snapshot_name,
|
||||
'backing-filename': self._FAKE_VOLUME_NAME},
|
||||
{'filename': self._FAKE_VOLUME_NAME,
|
||||
'backing-filename': self._fake_volume.name},
|
||||
{'filename': self._fake_volume.name,
|
||||
'backing-filename': None}]
|
||||
|
||||
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
|
||||
|
||||
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._get_backing_chain_for_path = mock.Mock(
|
||||
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._FAKE_SNAPSHOT_PATH)
|
||||
self._fake_snapshot_path)
|
||||
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)
|
||||
self._driver._write_info_file.assert_called_once_with(
|
||||
mock.sentinel.fake_info_path, expected_info)
|
||||
|
@ -175,12 +171,12 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
|
|||
self._test_delete_snapshot(is_active_image=False)
|
||||
|
||||
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 = {
|
||||
'active': self._FAKE_VOLUME_NAME,
|
||||
self._FAKE_SNAPSHOT_ID: fake_snapshot_name
|
||||
'active': self._fake_volume.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(
|
||||
return_value=mock.sentinel.fake_info_path)
|
||||
|
@ -190,42 +186,41 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
|
|||
return_value=self._FAKE_MNT_POINT)
|
||||
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(
|
||||
mock.sentinel.fake_info_path, expected_info)
|
||||
|
||||
def test_do_create_snapshot(self):
|
||||
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(
|
||||
self._driver._local_volume_dir(),
|
||||
self._FAKE_VOLUME_NAME)
|
||||
self._fake_volume.name)
|
||||
|
||||
self._driver._execute = mock.Mock()
|
||||
self._driver._set_rw_permissions = mock.Mock()
|
||||
self._driver._qemu_img_info = mock.Mock(
|
||||
return_value=mock.Mock(file_format=mock.sentinel.backing_fmt))
|
||||
|
||||
self._driver._do_create_snapshot(self._FAKE_SNAPSHOT,
|
||||
self._FAKE_VOLUME_NAME,
|
||||
self._FAKE_SNAPSHOT_PATH)
|
||||
self._driver._do_create_snapshot(self._fake_snapshot,
|
||||
self._fake_volume.name,
|
||||
self._fake_snapshot_path)
|
||||
command1 = ['qemu-img', 'create', '-f', 'qcow2', '-o',
|
||||
'backing_file=%s' % fake_backing_path,
|
||||
self._FAKE_SNAPSHOT_PATH]
|
||||
self._fake_snapshot_path]
|
||||
command2 = ['qemu-img', 'rebase', '-u',
|
||||
'-b', self._FAKE_VOLUME_NAME,
|
||||
'-b', self._fake_volume.name,
|
||||
'-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(*command2, run_as_root=True)
|
||||
|
||||
def _test_create_snapshot(self, volume_in_use=False):
|
||||
fake_snapshot = copy.deepcopy(self._FAKE_SNAPSHOT)
|
||||
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(
|
||||
return_value=mock.sentinel.fake_info_path)
|
||||
|
@ -235,28 +230,28 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
|
|||
self._driver._create_snapshot_online = mock.Mock()
|
||||
self._driver._write_info_file = 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(
|
||||
return_value=self._FAKE_SNAPSHOT_PATH)
|
||||
return_value=self._fake_snapshot_path)
|
||||
|
||||
expected_snapshot_info = {
|
||||
'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:
|
||||
fake_snapshot['volume']['status'] = 'in-use'
|
||||
self._fake_snapshot.volume.status = 'in-use'
|
||||
expected_method_called = '_create_snapshot_online'
|
||||
else:
|
||||
fake_snapshot['volume']['status'] = 'available'
|
||||
self._fake_snapshot.volume.status = 'available'
|
||||
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.assert_called_with(
|
||||
fake_snapshot, self._FAKE_VOLUME_NAME,
|
||||
self._FAKE_SNAPSHOT_PATH)
|
||||
self._fake_snapshot, self._fake_volume.name,
|
||||
self._fake_snapshot_path)
|
||||
self._driver._write_info_file.assert_called_with(
|
||||
mock.sentinel.fake_info_path,
|
||||
expected_snapshot_info)
|
||||
|
@ -268,12 +263,10 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
|
|||
self._test_create_snapshot(volume_in_use=True)
|
||||
|
||||
def test_create_snapshot_invalid_volume(self):
|
||||
fake_snapshot = copy.deepcopy(self._FAKE_SNAPSHOT)
|
||||
fake_snapshot['volume']['status'] = 'error'
|
||||
|
||||
self._fake_snapshot.volume.status = 'error'
|
||||
self.assertRaises(exception.InvalidVolume,
|
||||
self._driver._create_snapshot,
|
||||
fake_snapshot)
|
||||
self._fake_snapshot)
|
||||
|
||||
@mock.patch('cinder.db.snapshot_get')
|
||||
@mock.patch('time.sleep')
|
||||
|
@ -294,18 +287,18 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
|
|||
mock_do_create_snapshot:
|
||||
self.assertRaises(exception.RemoteFSConcurrentRequest,
|
||||
self._driver._create_snapshot_online,
|
||||
self._FAKE_SNAPSHOT,
|
||||
self._FAKE_VOLUME_NAME,
|
||||
self._FAKE_SNAPSHOT_PATH)
|
||||
self._fake_snapshot,
|
||||
self._fake_volume.name,
|
||||
self._fake_snapshot_path)
|
||||
|
||||
mock_do_create_snapshot.assert_called_once_with(
|
||||
self._FAKE_SNAPSHOT, self._FAKE_VOLUME_NAME,
|
||||
self._FAKE_SNAPSHOT_PATH)
|
||||
self._fake_snapshot, self._fake_volume.name,
|
||||
self._fake_snapshot_path)
|
||||
self.assertEqual([mock.call(1), mock.call(1)],
|
||||
mock_sleep.call_args_list)
|
||||
self.assertEqual(3, mock_snapshot_get.call_count)
|
||||
mock_snapshot_get.assert_called_with(self._FAKE_SNAPSHOT['context'],
|
||||
self._FAKE_SNAPSHOT['id'])
|
||||
mock_snapshot_get.assert_called_with(self._fake_snapshot._context,
|
||||
self._fake_snapshot.id)
|
||||
|
||||
@mock.patch.object(utils, 'synchronized')
|
||||
def _locked_volume_operation_test_helper(self, mock_synchronized, func,
|
||||
|
@ -318,7 +311,7 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
|
|||
|
||||
mock_synchronized.side_effect = mock_decorator
|
||||
expected_lock = '%s-%s' % (self._driver.driver_prefix,
|
||||
self._FAKE_VOLUME_ID)
|
||||
self._fake_volume.id)
|
||||
|
||||
if expected_exception:
|
||||
self.assertRaises(expected_exception, func,
|
||||
|
@ -332,7 +325,8 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
|
|||
self.assertEqual(mock.sentinel.ret_val, ret_val)
|
||||
|
||||
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
|
||||
def synchronized_func(inst, volume):
|
||||
|
@ -342,7 +336,8 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
|
|||
volume=mock_volume)
|
||||
|
||||
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
|
||||
def synchronized_func(inst, snapshot):
|
||||
|
@ -432,22 +427,36 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
|
|||
mock.patch.object(drv, '_copy_volume_from_snapshot') as \
|
||||
mock_copy_volume_from_snapshot:
|
||||
|
||||
volume = self._FAKE_VOLUME.copy()
|
||||
src_vref = self._FAKE_VOLUME.copy()
|
||||
src_vref['id'] = '375e32b2-804a-49f2-b282-85d1d5a5b9e1'
|
||||
src_vref['name'] = 'volume-%s' % src_vref['id']
|
||||
volume_ref = {'id': volume['id'],
|
||||
'name': volume['name'],
|
||||
'status': volume['status'],
|
||||
'provider_location': volume['provider_location'],
|
||||
'size': volume['size']}
|
||||
snap_ref = {'volume_name': volume['name'],
|
||||
'name': 'clone-snap-%s' % src_vref['id'],
|
||||
'size': src_vref['size'],
|
||||
'volume_size': src_vref['size'],
|
||||
'volume_id': src_vref['id'],
|
||||
'id': 'tmp-snap-%s' % src_vref['id'],
|
||||
'volume': src_vref}
|
||||
volume = fake_volume.fake_volume_obj(self.context)
|
||||
src_vref_id = '375e32b2-804a-49f2-b282-85d1d5a5b9e1'
|
||||
src_vref = fake_volume.fake_volume_obj(
|
||||
self.context,
|
||||
id=src_vref_id,
|
||||
name='volume-%s' % src_vref_id)
|
||||
|
||||
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_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)
|
||||
|
||||
mock_create_snapshot.assert_called_once_with(snap_ref)
|
||||
|
|
|
@ -26,27 +26,26 @@ from six.moves import urllib
|
|||
from cinder import context
|
||||
from cinder import exception
|
||||
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
|
||||
import cinder.volume.drivers.scality as driver
|
||||
|
||||
_FAKE_VOLUME = {'name': 'volume-a79d463e-1fd5-11e5-a6ff-5b81bfee8544',
|
||||
'id': 'a79d463e-1fd5-11e5-a6ff-5b81bfee8544',
|
||||
'provider_location': 'fake_share'}
|
||||
_FAKE_SNAPSHOT = {'id': 'ae3d6da2-1fd5-11e5-967f-1b8cf3b401ab',
|
||||
'volume': _FAKE_VOLUME,
|
||||
'status': 'available',
|
||||
'provider_location': None,
|
||||
'volume_size': 1,
|
||||
'name': 'snapshot-ae3d6da2-1fd5-11e5-967f-1b8cf3b401ab'}
|
||||
_FAKE_VOLUME_ID = 'a79d463e-1fd5-11e5-a6ff-5b81bfee8544'
|
||||
_FAKE_VOLUME_NAME = 'volume-a79d463e-1fd5-11e5-a6ff-5b81bfee8544'
|
||||
|
||||
_FAKE_SNAPSHOT_ID = 'ae3d6da2-1fd5-11e5-967f-1b8cf3b401ab'
|
||||
_FAKE_SNAPSHOT_NAME = 'snapshot-ae3d6da2-1fd5-11e5-967f-1b8cf3b401ab'
|
||||
|
||||
_FAKE_BACKUP = {'id': '914849d2-2585-11e5-be54-d70ca0c343d6',
|
||||
'volume_id': _FAKE_VOLUME['id']}
|
||||
'volume_id': _FAKE_VOLUME_ID}
|
||||
|
||||
_FAKE_MNT_POINT = '/tmp'
|
||||
_FAKE_SOFS_CONFIG = '/etc/sfused.conf'
|
||||
_FAKE_VOLUME_DIR = 'cinder/volumes'
|
||||
_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_SNAP_PATH = os.path.join(_FAKE_VOL_BASEDIR, _FAKE_SNAPSHOT['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_MOUNTS_TABLE = [['tmpfs /dev/shm\n'],
|
||||
['fuse ' + _FAKE_MNT_POINT + '\n']]
|
||||
|
@ -66,6 +65,30 @@ class ScalityDriverTestCase(test.TestCase):
|
|||
self.drv = driver.ScalityDriver(configuration=self.cfg)
|
||||
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('os.access')
|
||||
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):
|
||||
info = imageutils.QemuImgInfo()
|
||||
info.file_format = 'raw'
|
||||
info.image = _FAKE_VOLUME['name']
|
||||
info.image = _FAKE_VOLUME_NAME
|
||||
mock_qemu_img_info.return_value = info
|
||||
|
||||
volume = self._simple_volume()
|
||||
with mock.patch.object(self.drv, 'get_active_image_from_info') as \
|
||||
mock_get_active_image_from_info:
|
||||
|
||||
mock_get_active_image_from_info.return_value = _FAKE_VOLUME['name']
|
||||
conn_info = self.drv.initialize_connection(_FAKE_VOLUME, None)
|
||||
mock_get_active_image_from_info.return_value = _FAKE_VOLUME_NAME
|
||||
conn_info = self.drv.initialize_connection(volume, None)
|
||||
|
||||
expected_conn_info = {
|
||||
'driver_volume_type': driver.ScalityDriver.driver_volume_type,
|
||||
'mount_point_base': _FAKE_MNT_POINT,
|
||||
'data': {
|
||||
'export': _FAKE_VOLUME['provider_location'],
|
||||
'name': _FAKE_VOLUME['name'],
|
||||
'sofs_path': 'cinder/volumes/00/' + _FAKE_VOLUME['name'],
|
||||
'export': volume.provider_location,
|
||||
'name': volume.name,
|
||||
'sofs_path': 'cinder/volumes/00/' + volume.name,
|
||||
'format': 'raw'
|
||||
}
|
||||
}
|
||||
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.patch("cinder.image.image_utils.resize_image")
|
||||
|
@ -236,7 +260,7 @@ class ScalityDriverTestCase(test.TestCase):
|
|||
info.file_format = 'raw'
|
||||
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)
|
||||
|
||||
|
@ -249,7 +273,7 @@ class ScalityDriverTestCase(test.TestCase):
|
|||
mock_qemu_img_info.return_value = info
|
||||
|
||||
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.convert_image")
|
||||
|
@ -260,8 +284,8 @@ class ScalityDriverTestCase(test.TestCase):
|
|||
mock.patch.object(self.drv, '_set_rw_permissions_for_all') as \
|
||||
mock_set_rw_permissions:
|
||||
mock_read_info_file.side_effect = IOError(errno.ENOENT, '')
|
||||
self.drv._copy_volume_from_snapshot(_FAKE_SNAPSHOT,
|
||||
_FAKE_VOLUME, 1)
|
||||
self.drv._copy_volume_from_snapshot(self._simple_snapshot(),
|
||||
self._simple_volume(), 1)
|
||||
|
||||
mock_read_info_file.assert_called_once_with("%s.info" % _FAKE_VOL_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,
|
||||
mock_convert_image, mock_resize_image):
|
||||
|
||||
new_volume = {'name': 'volume-3fa63b02-1fe5-11e5-b492-abf97a8fb23b',
|
||||
'id': '3fa63b02-1fe5-11e5-b492-abf97a8fb23b',
|
||||
'provider_location': 'fake_share'}
|
||||
new_vol_path = os.path.join(_FAKE_VOL_BASEDIR, new_volume['name'])
|
||||
new_volume = self._simple_volume(
|
||||
display_name='volume-3fa63b02-1fe5-11e5-b492-abf97a8fb23b',
|
||||
id='3fa63b02-1fe5-11e5-b492-abf97a8fb23b',
|
||||
provider_location='fake_share')
|
||||
new_vol_path = os.path.join(_FAKE_VOL_BASEDIR, new_volume.name)
|
||||
|
||||
info = imageutils.QemuImgInfo()
|
||||
info.file_format = 'raw'
|
||||
|
@ -290,7 +315,7 @@ class ScalityDriverTestCase(test.TestCase):
|
|||
mock_read_info_file, \
|
||||
mock.patch.object(self.drv, '_set_rw_permissions_for_all') as \
|
||||
mock_set_rw_permissions:
|
||||
self.drv._copy_volume_from_snapshot(_FAKE_SNAPSHOT,
|
||||
self.drv._copy_volume_from_snapshot(self._simple_snapshot(),
|
||||
new_volume, 1)
|
||||
|
||||
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'
|
||||
mock_qemu_img_info.return_value = info
|
||||
|
||||
backup = {'volume_id': _FAKE_VOLUME['id']}
|
||||
backup = {'volume_id': _FAKE_VOLUME_ID}
|
||||
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)
|
||||
|
||||
|
@ -330,7 +355,7 @@ class ScalityDriverTestCase(test.TestCase):
|
|||
info.file_format = 'qcow2'
|
||||
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,
|
||||
context, _FAKE_BACKUP, mock.MagicMock())
|
||||
|
@ -345,8 +370,8 @@ class ScalityDriverTestCase(test.TestCase):
|
|||
info.backing_file = 'fake.img'
|
||||
mock_qemu_img_info.return_value = info
|
||||
|
||||
backup = {'volume_id': _FAKE_VOLUME['id']}
|
||||
self.drv.db.volume_get.return_value = _FAKE_VOLUME
|
||||
backup = {'volume_id': _FAKE_VOLUME_ID}
|
||||
self.drv.db.volume_get.return_value = self._simple_volume()
|
||||
|
||||
self.assertRaises(exception.InvalidVolume, self.drv.backup_volume,
|
||||
context, backup, mock.MagicMock())
|
||||
|
@ -358,10 +383,10 @@ class ScalityDriverTestCase(test.TestCase):
|
|||
def test_restore_bakup(self, mock_open, mock_temporary_chown):
|
||||
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_temporary_chown.assert_called_once_with(_FAKE_VOL_PATH)
|
||||
mock_open.assert_called_once_with(_FAKE_VOL_PATH, 'wb')
|
||||
mock_backup_service.restore.assert_called_once_with(
|
||||
_FAKE_BACKUP, _FAKE_VOLUME['id'], mock_open().__enter__())
|
||||
_FAKE_BACKUP, _FAKE_VOLUME_ID, mock_open().__enter__())
|
||||
|
|
|
@ -21,11 +21,10 @@ import mock
|
|||
from oslo_utils import fileutils
|
||||
|
||||
from cinder import context
|
||||
from cinder import db
|
||||
from cinder import exception
|
||||
from cinder.image import image_utils
|
||||
from cinder import objects
|
||||
from cinder import test
|
||||
from cinder.tests.unit import fake_snapshot
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder.volume.drivers import remotefs
|
||||
from cinder.volume.drivers import smbfs
|
||||
|
@ -39,7 +38,7 @@ def requires_allocation_data_update(expected_size):
|
|||
inst._smbfs_driver,
|
||||
'update_disk_allocation_data') as fake_update:
|
||||
func(inst, *args, **kwargs)
|
||||
fake_update.assert_called_once_with(inst._FAKE_VOLUME,
|
||||
fake_update.assert_called_once_with(inst.volume,
|
||||
expected_size)
|
||||
return inner
|
||||
return wrapper
|
||||
|
@ -55,18 +54,10 @@ class SmbFsTestCase(test.TestCase):
|
|||
_FAKE_TOTAL_SIZE = '2048'
|
||||
_FAKE_TOTAL_AVAILABLE = '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_VOLUME_PATH = os.path.join(_FAKE_MNT_POINT, _FAKE_VOLUME_NAME)
|
||||
_FAKE_SNAPSHOT_ID = '5g811859-4928-4cb7-801a-a50c37ceacba'
|
||||
_FAKE_SNAPSHOT = {'id': _FAKE_SNAPSHOT_ID,
|
||||
'volume': _FAKE_VOLUME,
|
||||
'status': 'available',
|
||||
'volume_size': 1}
|
||||
_FAKE_VOLUME_SIZE = 1
|
||||
_FAKE_SNAPSHOT_ID = '50811859-4928-4cb7-801a-a50c37ceacba'
|
||||
_FAKE_SNAPSHOT_PATH = (
|
||||
_FAKE_VOLUME_PATH + '-snapshot' + _FAKE_SNAPSHOT_ID)
|
||||
_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._alloc_info_file_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)
|
||||
|
||||
|
@ -137,24 +144,24 @@ class SmbFsTestCase(test.TestCase):
|
|||
fake_alloc_data = self._get_fake_allocation_data()
|
||||
if volume_exists:
|
||||
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.update_disk_allocation_data(self._FAKE_VOLUME,
|
||||
self._smbfs_driver.update_disk_allocation_data(self.volume,
|
||||
virtual_size_gb)
|
||||
|
||||
vol_allocated_size = fake_alloc_data[self._FAKE_SHARE_HASH].get(
|
||||
self._FAKE_VOLUME_NAME, None)
|
||||
if not virtual_size_gb:
|
||||
expected_total_allocated = (self._FAKE_TOTAL_ALLOCATED -
|
||||
self._FAKE_VOLUME['size'])
|
||||
self.volume.size)
|
||||
|
||||
self.assertIsNone(vol_allocated_size)
|
||||
else:
|
||||
expected_total_allocated = (self._FAKE_TOTAL_ALLOCATED +
|
||||
virtual_size_gb -
|
||||
self._FAKE_VOLUME['size'])
|
||||
self.volume.size)
|
||||
self.assertEqual(virtual_size_gb, vol_allocated_size)
|
||||
|
||||
update_func.assert_called_once_with()
|
||||
|
@ -168,11 +175,11 @@ class SmbFsTestCase(test.TestCase):
|
|||
|
||||
def test_update_allocation_data_volume_extended(self):
|
||||
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):
|
||||
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)
|
||||
def test_delete_volume(self):
|
||||
|
@ -191,7 +198,7 @@ class SmbFsTestCase(test.TestCase):
|
|||
return_value=fake_vol_info)
|
||||
|
||||
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)
|
||||
drv._delete.assert_any_call(
|
||||
|
@ -266,12 +273,12 @@ class SmbFsTestCase(test.TestCase):
|
|||
if volume_exists:
|
||||
self.assertRaises(exception.InvalidVolume,
|
||||
self._smbfs_driver._do_create_volume,
|
||||
self._FAKE_VOLUME)
|
||||
self.volume)
|
||||
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,
|
||||
self._FAKE_VOLUME['size']]
|
||||
self.volume.size]
|
||||
if volume_format in [self._smbfs_driver._DISK_FORMAT_VHDX,
|
||||
self._smbfs_driver._DISK_FORMAT_VHD]:
|
||||
expected_create_args.append(volume_format)
|
||||
|
@ -320,14 +327,14 @@ class SmbFsTestCase(test.TestCase):
|
|||
if not mounted_shares:
|
||||
self.assertRaises(exception.SmbfsNoSharesMounted,
|
||||
self._smbfs_driver._find_share,
|
||||
self._FAKE_VOLUME['size'])
|
||||
self.volume.size)
|
||||
elif not eligible_shares:
|
||||
self.assertRaises(exception.SmbfsNoSuitableShareFound,
|
||||
self._smbfs_driver._find_share,
|
||||
self._FAKE_VOLUME['size'])
|
||||
self.volume.size)
|
||||
else:
|
||||
ret_value = self._smbfs_driver._find_share(
|
||||
self._FAKE_VOLUME['size'])
|
||||
self.volume.size)
|
||||
# The eligible share with the minimum allocated space
|
||||
# will be selected
|
||||
self.assertEqual('fake_share3', ret_value)
|
||||
|
@ -404,12 +411,12 @@ class SmbFsTestCase(test.TestCase):
|
|||
expected_vol_path if volume_exists else None)
|
||||
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:
|
||||
self.assertFalse(mock_get_volume_format.called)
|
||||
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)
|
||||
|
||||
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):
|
||||
mock_get_local_dir.return_value = self._FAKE_MNT_POINT
|
||||
ret_val = self._smbfs_driver._get_local_volume_path_template(
|
||||
self._FAKE_VOLUME)
|
||||
self.volume)
|
||||
self.assertEqual(self._FAKE_VOLUME_PATH, ret_val)
|
||||
|
||||
@mock.patch('os.path.exists')
|
||||
|
@ -457,7 +464,7 @@ class SmbFsTestCase(test.TestCase):
|
|||
mock_qemu_img_info.return_value.file_format = 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)
|
||||
|
||||
if volume_exists:
|
||||
|
@ -465,7 +472,7 @@ class SmbFsTestCase(test.TestCase):
|
|||
self._FAKE_VOLUME_NAME)
|
||||
self.assertFalse(mock_get_format_spec.called)
|
||||
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)
|
||||
|
||||
return ret_val
|
||||
|
@ -506,7 +513,7 @@ class SmbFsTestCase(test.TestCase):
|
|||
'data': fake_data,
|
||||
'mount_point_base': self._FAKE_MNT_BASE}
|
||||
ret_val = self._smbfs_driver.initialize_connection(
|
||||
self._FAKE_VOLUME, None)
|
||||
self.volume, None)
|
||||
|
||||
self.assertEqual(expected, ret_val)
|
||||
|
||||
|
@ -529,9 +536,9 @@ class SmbFsTestCase(test.TestCase):
|
|||
if extend_failed:
|
||||
self.assertRaises(exception.ExtendVolumeError,
|
||||
drv.extend_volume,
|
||||
self._FAKE_VOLUME, mock.sentinel.new_size)
|
||||
self.volume, mock.sentinel.new_size)
|
||||
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,
|
||||
drv._DISK_FORMAT_VHD_LEGACY):
|
||||
|
@ -576,14 +583,14 @@ class SmbFsTestCase(test.TestCase):
|
|||
if has_snapshots:
|
||||
self.assertRaises(exception.InvalidVolume,
|
||||
self._smbfs_driver._check_extend_volume_support,
|
||||
self._FAKE_VOLUME, 2)
|
||||
self.volume, 2)
|
||||
elif not is_eligible:
|
||||
self.assertRaises(exception.ExtendVolumeError,
|
||||
self._smbfs_driver._check_extend_volume_support,
|
||||
self._FAKE_VOLUME, 2)
|
||||
self.volume, 2)
|
||||
else:
|
||||
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._FAKE_SHARE, 1)
|
||||
|
||||
|
@ -596,35 +603,35 @@ class SmbFsTestCase(test.TestCase):
|
|||
def test_check_extend_volume_uneligible_share(self):
|
||||
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')
|
||||
def test_create_volume_base(self, mock_create_volume):
|
||||
self._smbfs_driver.create_volume(self._FAKE_VOLUME)
|
||||
mock_create_volume.assert_called_once_with(self._FAKE_VOLUME)
|
||||
self._smbfs_driver.create_volume(self.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,
|
||||
'_create_volume_from_snapshot')
|
||||
def test_create_volume_from_snapshot(self, mock_create_volume):
|
||||
self._smbfs_driver.create_volume_from_snapshot(self._FAKE_VOLUME,
|
||||
self._FAKE_SNAPSHOT)
|
||||
mock_create_volume.assert_called_once_with(self._FAKE_VOLUME,
|
||||
self._FAKE_SNAPSHOT)
|
||||
self._smbfs_driver.create_volume_from_snapshot(self.volume,
|
||||
self.snapshot)
|
||||
mock_create_volume.assert_called_once_with(self.volume,
|
||||
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')
|
||||
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_create_volume.assert_called_once_with(self._FAKE_VOLUME,
|
||||
mock_create_volume.assert_called_once_with(self.volume,
|
||||
mock.sentinel.src_vol)
|
||||
|
||||
def test_create_volume_from_in_use_snapshot(self):
|
||||
fake_snapshot = {'status': 'in-use'}
|
||||
def test_create_volume_from_unavailable_snapshot(self):
|
||||
self.snapshot.status = 'error'
|
||||
self.assertRaises(
|
||||
exception.InvalidSnapshot,
|
||||
self._smbfs_driver.create_volume_from_snapshot,
|
||||
self._FAKE_VOLUME, fake_snapshot)
|
||||
self.volume, self.snapshot)
|
||||
|
||||
def test_copy_volume_from_snapshot(self):
|
||||
drv = self._smbfs_driver
|
||||
|
@ -651,10 +658,10 @@ class SmbFsTestCase(test.TestCase):
|
|||
with mock.patch.object(image_utils, 'convert_image') as (
|
||||
fake_convert_image):
|
||||
drv._copy_volume_from_snapshot(
|
||||
self._FAKE_SNAPSHOT, self._FAKE_VOLUME,
|
||||
self._FAKE_VOLUME['size'])
|
||||
self.snapshot, self.volume,
|
||||
self.volume.size)
|
||||
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(
|
||||
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):
|
||||
drv = self._smbfs_driver
|
||||
|
||||
vol_size_bytes = self._FAKE_VOLUME['size'] << 30
|
||||
vol_size_bytes = self.volume.size << 30
|
||||
|
||||
fake_img_info = mock.MagicMock()
|
||||
|
||||
|
@ -696,12 +703,12 @@ class SmbFsTestCase(test.TestCase):
|
|||
self.assertRaises(
|
||||
exception.ImageUnacceptable,
|
||||
drv.copy_image_to_volume,
|
||||
mock.sentinel.context, self._FAKE_VOLUME,
|
||||
mock.sentinel.context, self.volume,
|
||||
mock.sentinel.image_service,
|
||||
mock.sentinel.image_id)
|
||||
else:
|
||||
drv.copy_image_to_volume(
|
||||
mock.sentinel.context, self._FAKE_VOLUME,
|
||||
mock.sentinel.context, self.volume,
|
||||
mock.sentinel.image_service,
|
||||
mock.sentinel.image_id)
|
||||
fake_fetch.assert_called_once_with(
|
||||
|
@ -711,8 +718,8 @@ class SmbFsTestCase(test.TestCase):
|
|||
mock.sentinel.block_size)
|
||||
drv._do_extend_volume.assert_called_once_with(
|
||||
self._FAKE_VOLUME_PATH,
|
||||
self._FAKE_VOLUME['size'],
|
||||
self._FAKE_VOLUME['name'])
|
||||
self.volume.size,
|
||||
self.volume.name)
|
||||
|
||||
def test_copy_image_to_volume(self):
|
||||
self._test_copy_image_to_volume()
|
||||
|
@ -740,43 +747,34 @@ class SmbFsTestCase(test.TestCase):
|
|||
self._FAKE_TOTAL_ALLOCATED)
|
||||
self.assertEqual(expected, ret_val)
|
||||
|
||||
@ddt.data([True, False, False],
|
||||
[False, False, False],
|
||||
[True, True, True],
|
||||
[False, True, True],
|
||||
[False, False, True],
|
||||
[True, False, True])
|
||||
@ddt.data([False, False],
|
||||
[True, True],
|
||||
[False, True])
|
||||
@ddt.unpack
|
||||
def test_get_volume_format_spec(self, volume_versioned_object,
|
||||
def test_get_volume_format_spec(self,
|
||||
volume_meta_contains_fmt,
|
||||
volume_type_contains_fmt):
|
||||
self._smbfs_driver.configuration = copy.copy(self._FAKE_SMBFS_CONFIG)
|
||||
|
||||
fake_vol_meta_fmt = 'vhd'
|
||||
fake_vol_type_fmt = 'vhdx'
|
||||
|
||||
volume_metadata = {}
|
||||
volume_type_extra_specs = {}
|
||||
|
||||
fake_vol_dict = fake_volume.fake_db_volume()
|
||||
del fake_vol_dict['name']
|
||||
|
||||
if volume_meta_contains_fmt:
|
||||
volume_metadata['volume_format'] = fake_vol_meta_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 = db.volume_type_create(
|
||||
ctxt, {'extra_specs': volume_type_extra_specs,
|
||||
'name': 'fake_vol_type'})
|
||||
fake_vol_dict.update(metadata=volume_metadata,
|
||||
volume_type_id=volume_type.id)
|
||||
# We want to get a 'real' SqlA model object, not just a dict.
|
||||
volume = db.volume_create(ctxt, fake_vol_dict)
|
||||
volume = db.volume_get(ctxt, volume.id)
|
||||
|
||||
if volume_versioned_object:
|
||||
volume = objects.Volume._from_db_object(ctxt, objects.Volume(),
|
||||
volume)
|
||||
volume_type = fake_volume.fake_volume_type_obj(self.context)
|
||||
volume = fake_volume.fake_volume_obj(self.context)
|
||||
# Optional arguments are not set in _from_db_object,
|
||||
# so have to set explicitly here
|
||||
volume.volume_type = volume_type
|
||||
volume.metadata = volume_metadata
|
||||
# Same for extra_specs and VolumeType
|
||||
volume_type.extra_specs = volume_type_extra_specs
|
||||
|
||||
resulted_fmt = self._smbfs_driver._get_volume_format_spec(volume)
|
||||
|
||||
|
@ -785,6 +783,6 @@ class SmbFsTestCase(test.TestCase):
|
|||
elif volume_type_contains_fmt:
|
||||
expected_fmt = fake_vol_type_fmt
|
||||
else:
|
||||
expected_fmt = None
|
||||
expected_fmt = self._FAKE_SMBFS_CONFIG.smbfs_default_volume_format
|
||||
|
||||
self.assertEqual(expected_fmt, resulted_fmt)
|
||||
|
|
|
@ -21,9 +21,12 @@ import mock
|
|||
from os_brick.remotefs import remotefs
|
||||
from oslo_utils import units
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.image import image_utils
|
||||
from cinder import test
|
||||
from cinder.tests.unit import fake_snapshot
|
||||
from cinder.tests.unit import fake_volume
|
||||
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_VOLUME_NAME = 'volume-4f711859-4928-4cb7-801a-a50c37ceaccc'
|
||||
_FAKE_VOLUME_PATH = os.path.join(_FAKE_MNT_POINT, _FAKE_VOLUME_NAME)
|
||||
_FAKE_VOLUME = {'id': '4f711859-4928-4cb7-801a-a50c37ceaccc',
|
||||
'size': 1,
|
||||
'provider_location': _FAKE_SHARE,
|
||||
'name': _FAKE_VOLUME_NAME,
|
||||
'status': 'available'}
|
||||
_FAKE_SNAPSHOT_ID = '5g811859-4928-4cb7-801a-a50c37ceacba'
|
||||
_FAKE_SNAPSHOT_ID = '50811859-4928-4cb7-801a-a50c37ceacba'
|
||||
_FAKE_SNAPSHOT_PATH = (
|
||||
_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.vzstorage_shares_config = '/fake/config/path'
|
||||
_FAKE_VZ_CONFIG.vzstorage_sparsed_volumes = False
|
||||
_FAKE_VZ_CONFIG.vzstorage_used_ratio = 0.7
|
||||
_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_permissions = 'auto'
|
||||
|
||||
|
@ -72,6 +67,26 @@ class VZStorageTestCase(test.TestCase):
|
|||
self._vz_driver._execute = mock.Mock()
|
||||
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):
|
||||
if path.startswith(self._FAKE_VZ_CONFIG.vzstorage_shares_config):
|
||||
return True
|
||||
|
@ -135,9 +150,13 @@ class VZStorageTestCase(test.TestCase):
|
|||
file_format = 'raw'
|
||||
info = mock.Mock()
|
||||
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):
|
||||
ret = drv.initialize_connection(self._FAKE_VOLUME, None)
|
||||
name = drv.get_active_image_from_info(self._FAKE_VOLUME)
|
||||
with mock.patch.object(drv, '_read_file',
|
||||
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',
|
||||
'data': {'export': self._FAKE_SHARE,
|
||||
'format': file_format,
|
||||
|
@ -197,9 +216,13 @@ class VZStorageTestCase(test.TestCase):
|
|||
drv._check_extend_volume_support = 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',
|
||||
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)
|
||||
|
||||
|
@ -218,13 +241,13 @@ class VZStorageTestCase(test.TestCase):
|
|||
if has_snapshots:
|
||||
self.assertRaises(exception.InvalidVolume,
|
||||
drv._check_extend_volume_support,
|
||||
self._FAKE_VOLUME, 2)
|
||||
self.vol, 2)
|
||||
elif not is_eligible:
|
||||
self.assertRaises(exception.ExtendVolumeError,
|
||||
drv._check_extend_volume_support,
|
||||
self._FAKE_VOLUME, 2)
|
||||
self.vol, 2)
|
||||
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)
|
||||
|
||||
def test_check_extend_support(self):
|
||||
|
@ -258,10 +281,10 @@ class VZStorageTestCase(test.TestCase):
|
|||
drv._extend_volume = mock.Mock()
|
||||
|
||||
drv._copy_volume_from_snapshot(
|
||||
self._FAKE_SNAPSHOT, self._FAKE_VOLUME,
|
||||
self._FAKE_VOLUME['size'])
|
||||
self.snap, self.vol,
|
||||
self.vol['size'])
|
||||
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(
|
||||
self._FAKE_VOLUME_PATH, self._FAKE_VOLUME_PATH[:-1], 'raw')
|
||||
|
||||
|
@ -281,7 +304,7 @@ class VZStorageTestCase(test.TestCase):
|
|||
return_value=fake_vol_info)
|
||||
|
||||
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)
|
||||
drv._delete.assert_any_call(
|
||||
|
|
|
@ -17,9 +17,12 @@ import os
|
|||
import mock
|
||||
from oslo_utils import units
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.image import image_utils
|
||||
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
|
||||
|
||||
|
||||
|
@ -35,12 +38,6 @@ class WindowsSmbFsTestCase(test.TestCase):
|
|||
_FAKE_TOTAL_SIZE = '2048'
|
||||
_FAKE_TOTAL_AVAILABLE = '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_VOLUME_PATH = os.path.join(_FAKE_MNT_POINT,
|
||||
_FAKE_VOLUME_NAME + '.vhdx')
|
||||
|
@ -56,6 +53,25 @@ class WindowsSmbFsTestCase(test.TestCase):
|
|||
self._smbfs_driver.local_path = mock.Mock(
|
||||
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'):
|
||||
self._smbfs_driver.create_dynamic_vhd = mock.MagicMock()
|
||||
fake_create = self._smbfs_driver._vhdutils.create_dynamic_vhd
|
||||
|
@ -63,15 +79,16 @@ class WindowsSmbFsTestCase(test.TestCase):
|
|||
return_value=volume_format)
|
||||
|
||||
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'):
|
||||
self.assertRaises(exception.InvalidVolume,
|
||||
self._smbfs_driver._do_create_volume,
|
||||
self._FAKE_VOLUME)
|
||||
volume)
|
||||
else:
|
||||
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_vol_path, self._FAKE_VOLUME['size'] << 30)
|
||||
fake_vol_path, volume.size << 30)
|
||||
|
||||
def test_create_volume(self):
|
||||
self._test_create_volume()
|
||||
|
@ -120,7 +137,7 @@ class WindowsSmbFsTestCase(test.TestCase):
|
|||
self._smbfs_driver._vhdutils.create_differencing_vhd)
|
||||
|
||||
self._smbfs_driver._do_create_snapshot(
|
||||
self._FAKE_SNAPSHOT,
|
||||
self._simple_snapshot(),
|
||||
os.path.basename(self._FAKE_VOLUME_PATH),
|
||||
self._FAKE_SNAPSHOT_PATH)
|
||||
|
||||
|
@ -156,8 +173,9 @@ class WindowsSmbFsTestCase(test.TestCase):
|
|||
|
||||
with mock.patch.object(image_utils, 'upload_volume') as (
|
||||
fake_upload_volume):
|
||||
volume = self._simple_volume()
|
||||
drv.copy_volume_to_image(
|
||||
mock.sentinel.context, self._FAKE_VOLUME,
|
||||
mock.sentinel.context, volume,
|
||||
mock.sentinel.image_service, fake_image_meta)
|
||||
|
||||
expected_conversion = (
|
||||
|
@ -165,7 +183,7 @@ class WindowsSmbFsTestCase(test.TestCase):
|
|||
|
||||
if expected_conversion:
|
||||
fake_temp_image_name = '%s.temp_image.%s.%s' % (
|
||||
self._FAKE_VOLUME['id'],
|
||||
volume.id,
|
||||
fake_image_meta['id'],
|
||||
drv._DISK_FORMAT_VHD)
|
||||
fake_temp_image_path = os.path.join(
|
||||
|
@ -209,8 +227,9 @@ class WindowsSmbFsTestCase(test.TestCase):
|
|||
|
||||
with mock.patch.object(image_utils,
|
||||
'fetch_to_volume_format') as fake_fetch:
|
||||
volume = self._simple_volume()
|
||||
drv.copy_image_to_volume(
|
||||
mock.sentinel.context, self._FAKE_VOLUME,
|
||||
mock.sentinel.context, volume,
|
||||
mock.sentinel.image_service,
|
||||
mock.sentinel.image_id)
|
||||
fake_fetch.assert_called_once_with(
|
||||
|
@ -221,13 +240,14 @@ class WindowsSmbFsTestCase(test.TestCase):
|
|||
mock.sentinel.block_size)
|
||||
drv._vhdutils.resize_vhd.assert_called_once_with(
|
||||
self._FAKE_VOLUME_PATH,
|
||||
self._FAKE_VOLUME['size'] * units.Gi,
|
||||
volume.size * units.Gi,
|
||||
is_file_max_size=False)
|
||||
|
||||
def test_copy_volume_from_snapshot(self):
|
||||
drv = self._smbfs_driver
|
||||
snapshot = self._simple_snapshot()
|
||||
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.backing_file = self._FAKE_VOLUME_NAME + '.vhdx'
|
||||
|
||||
|
@ -242,9 +262,9 @@ class WindowsSmbFsTestCase(test.TestCase):
|
|||
drv.local_path = mock.Mock(
|
||||
return_value=mock.sentinel.new_volume_path)
|
||||
|
||||
drv._copy_volume_from_snapshot(
|
||||
self._FAKE_SNAPSHOT, self._FAKE_VOLUME,
|
||||
self._FAKE_VOLUME['size'])
|
||||
volume = self._simple_volume()
|
||||
drv._copy_volume_from_snapshot(snapshot,
|
||||
volume, volume.size)
|
||||
|
||||
drv._delete.assert_called_once_with(mock.sentinel.new_volume_path)
|
||||
drv._vhdutils.convert_vhd.assert_called_once_with(
|
||||
|
@ -252,7 +272,7 @@ class WindowsSmbFsTestCase(test.TestCase):
|
|||
mock.sentinel.new_volume_path)
|
||||
drv._vhdutils.resize_vhd.assert_called_once_with(
|
||||
mock.sentinel.new_volume_path,
|
||||
self._FAKE_VOLUME['size'] * units.Gi,
|
||||
volume.size * units.Gi,
|
||||
is_file_max_size=False)
|
||||
|
||||
def test_rebase_img(self):
|
||||
|
|
|
@ -148,7 +148,7 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
|
|||
pass
|
||||
|
||||
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,
|
||||
hashed)
|
||||
return path
|
||||
|
@ -187,13 +187,13 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
|
|||
|
||||
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)
|
||||
|
||||
return {'provider_location': volume['provider_location']}
|
||||
return {'provider_location': volume.provider_location}
|
||||
|
||||
def _copy_volume_from_snapshot(self, snapshot, volume, volume_size):
|
||||
"""Copy data from snapshot to destination volume.
|
||||
|
@ -204,20 +204,20 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
|
|||
|
||||
LOG.debug("snapshot: %(snap)s, volume: %(vol)s, "
|
||||
"volume_size: %(size)s",
|
||||
{'snap': snapshot['id'],
|
||||
'vol': volume['id'],
|
||||
{'snap': snapshot.id,
|
||||
'vol': volume.id,
|
||||
'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)
|
||||
vol_path = self._local_volume_dir(snapshot['volume'])
|
||||
forward_file = snap_info[snapshot['id']]
|
||||
vol_path = self._local_volume_dir(snapshot.volume)
|
||||
forward_file = snap_info[snapshot.id]
|
||||
forward_path = os.path.join(vol_path, forward_file)
|
||||
|
||||
# Find the file which backs this file, which represents the point
|
||||
# when this snapshot was created.
|
||||
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_new_vol = self._local_path_volume(volume)
|
||||
|
@ -239,13 +239,13 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
|
|||
def delete_volume(self, 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 specified, '
|
||||
'skipping'), volume['name'])
|
||||
'skipping'), volume.name)
|
||||
return
|
||||
|
||||
self._ensure_share_mounted(volume['provider_location'])
|
||||
self._ensure_share_mounted(volume.provider_location)
|
||||
|
||||
mounted_path = self._active_volume_path(volume)
|
||||
|
||||
|
@ -266,7 +266,7 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
|
|||
def ensure_export(self, ctx, 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):
|
||||
"""Exports the volume."""
|
||||
|
@ -287,16 +287,16 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
|
|||
# Find active qcow2 file
|
||||
active_file = self.get_active_image_from_info(volume)
|
||||
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)
|
||||
|
||||
data = {'export': volume['provider_location'],
|
||||
data = {'export': volume.provider_location,
|
||||
'name': active_file}
|
||||
if volume['provider_location'] in self.shares:
|
||||
data['options'] = self.shares[volume['provider_location']]
|
||||
if volume.provider_location in self.shares:
|
||||
data['options'] = self.shares[volume.provider_location]
|
||||
|
||||
# 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
|
||||
if data['format'] not in ['raw', 'qcow2']:
|
||||
msg = _('%s must be a valid raw or qcow2 image.') % path
|
||||
|
@ -316,7 +316,7 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
|
|||
def extend_volume(self, volume, size_gb):
|
||||
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
|
||||
|
||||
if backing_fmt not in ['raw', 'qcow2']:
|
||||
|
@ -333,7 +333,7 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
|
|||
"""
|
||||
|
||||
volume_path = self.local_path(volume)
|
||||
volume_size = volume['size']
|
||||
volume_size = volume.size
|
||||
|
||||
LOG.debug("creating new volume at %s", volume_path)
|
||||
|
||||
|
@ -454,7 +454,7 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver,
|
|||
|
||||
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:
|
||||
LOG.error(_LE('No snapshots found in database, but %(path)s has '
|
||||
|
|
|
@ -302,13 +302,13 @@ class NfsDriver(driver.ExtendVD, remotefs.RemoteFSDriver):
|
|||
|
||||
def extend_volume(self, volume, new_size):
|
||||
"""Extend an existing volume to the new size."""
|
||||
LOG.info(_LI('Extending volume %s.'), volume['id'])
|
||||
extend_by = int(new_size) - volume['size']
|
||||
if not self._is_share_eligible(volume['provider_location'],
|
||||
LOG.info(_LI('Extending volume %s.'), volume.id)
|
||||
extend_by = int(new_size) - volume.size
|
||||
if not self._is_share_eligible(volume.provider_location,
|
||||
extend_by):
|
||||
raise exception.ExtendVolumeError(reason='Insufficient space to'
|
||||
' extend volume %s to %sG'
|
||||
% (volume['id'], new_size))
|
||||
% (volume.id, new_size))
|
||||
path = self.local_path(volume)
|
||||
LOG.info(_LI('Resizing file to %sG...'), new_size)
|
||||
image_utils.resize_image(path, new_size,
|
||||
|
@ -398,8 +398,8 @@ class NfsDriver(driver.ExtendVD, remotefs.RemoteFSDriver):
|
|||
# NFS snapshots are introduced.
|
||||
name_id = None
|
||||
if original_volume_status == 'available':
|
||||
current_name = CONF.volume_name_template % new_volume['id']
|
||||
original_volume_name = CONF.volume_name_template % volume['id']
|
||||
current_name = CONF.volume_name_template % new_volume.id
|
||||
original_volume_name = CONF.volume_name_template % volume.id
|
||||
current_path = self.local_path(new_volume)
|
||||
# Replace the volume name with the original volume name
|
||||
original_path = current_path.replace(current_name,
|
||||
|
@ -408,16 +408,16 @@ class NfsDriver(driver.ExtendVD, remotefs.RemoteFSDriver):
|
|||
os.rename(current_path, original_path)
|
||||
except OSError:
|
||||
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
|
||||
# volume id and provider_location should be set to the
|
||||
# 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:
|
||||
# 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,
|
||||
'provider_location': new_volume['provider_location']}
|
||||
'provider_location': new_volume.provider_location}
|
||||
|
||||
def _update_volume_stats(self):
|
||||
"""Retrieve stats info from volume group."""
|
||||
|
|
|
@ -187,20 +187,20 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
"""
|
||||
|
||||
LOG.debug("snapshot: %(snap)s, volume: %(vol)s, ",
|
||||
{'snap': snapshot['id'],
|
||||
'vol': volume['id'],
|
||||
{'snap': snapshot.id,
|
||||
'vol': volume.id,
|
||||
'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)
|
||||
vol_path = self._local_volume_dir(snapshot['volume'])
|
||||
forward_file = snap_info[snapshot['id']]
|
||||
vol_path = self._local_volume_dir(snapshot.volume)
|
||||
forward_file = snap_info[snapshot.id]
|
||||
forward_path = os.path.join(vol_path, forward_file)
|
||||
|
||||
# Find the file which backs this file, which represents the point
|
||||
# when this snapshot was created.
|
||||
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_new_vol = self._local_path_volume(volume)
|
||||
|
@ -223,12 +223,12 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
def delete_volume(self, 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 '
|
||||
'specified, skipping'), volume['name'])
|
||||
'specified, skipping'), volume.name)
|
||||
return
|
||||
|
||||
self._ensure_share_mounted(volume['provider_location'])
|
||||
self._ensure_share_mounted(volume.provider_location)
|
||||
|
||||
volume_dir = self._local_volume_dir(volume)
|
||||
mounted_path = os.path.join(volume_dir,
|
||||
|
@ -263,16 +263,16 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
# Find active qcow2 file
|
||||
active_file = self.get_active_image_from_info(volume)
|
||||
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)
|
||||
|
||||
data = {'export': volume['provider_location'],
|
||||
data = {'export': volume.provider_location,
|
||||
'name': active_file}
|
||||
if volume['provider_location'] in self.shares:
|
||||
data['options'] = self.shares[volume['provider_location']]
|
||||
if volume.provider_location in self.shares:
|
||||
data['options'] = self.shares[volume.provider_location]
|
||||
|
||||
# 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
|
||||
if data['format'] not in ['raw', 'qcow2']:
|
||||
msg = _('%s must be a valid raw or qcow2 image.') % path
|
||||
|
@ -301,7 +301,7 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
' driver when no snapshots exist.')
|
||||
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
|
||||
|
||||
if backing_fmt not in ['raw', 'qcow2']:
|
||||
|
@ -317,7 +317,7 @@ class QuobyteDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
:param volume: volume reference
|
||||
"""
|
||||
volume_path = self.local_path(volume)
|
||||
volume_size = volume['size']
|
||||
volume_size = volume.size
|
||||
|
||||
if self.configuration.quobyte_qcow2_volumes:
|
||||
self._create_qcow2_file(volume_path, volume_size)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import collections
|
||||
import hashlib
|
||||
import inspect
|
||||
import json
|
||||
|
@ -118,9 +119,9 @@ def locked_volume_id_operation(f, external=False):
|
|||
call_args = inspect.getcallargs(f, inst, *args, **kwargs)
|
||||
|
||||
if call_args.get('volume'):
|
||||
volume_id = call_args['volume']['id']
|
||||
volume_id = call_args['volume'].id
|
||||
elif call_args.get('snapshot'):
|
||||
volume_id = call_args['snapshot']['volume']['id']
|
||||
volume_id = call_args['snapshot'].volume.id
|
||||
else:
|
||||
err_msg = _('The decorated method must accept either a volume or '
|
||||
'a snapshot object')
|
||||
|
@ -163,10 +164,10 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
|
|||
:param volume: volume reference
|
||||
:param connector: connector reference
|
||||
"""
|
||||
data = {'export': volume['provider_location'],
|
||||
'name': volume['name']}
|
||||
if volume['provider_location'] in self.shares:
|
||||
data['options'] = self.shares[volume['provider_location']]
|
||||
data = {'export': volume.provider_location,
|
||||
'name': volume.name}
|
||||
if volume.provider_location in self.shares:
|
||||
data['options'] = self.shares[volume.provider_location]
|
||||
return {
|
||||
'driver_volume_type': self.driver_volume_type,
|
||||
'data': data,
|
||||
|
@ -232,13 +233,13 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
|
|||
"""
|
||||
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)
|
||||
|
||||
return {'provider_location': volume['provider_location']}
|
||||
return {'provider_location': volume.provider_location}
|
||||
|
||||
def _do_create_volume(self, volume):
|
||||
"""Create a volume on given remote share.
|
||||
|
@ -246,7 +247,7 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
|
|||
:param volume: volume reference
|
||||
"""
|
||||
volume_path = self.local_path(volume)
|
||||
volume_size = volume['size']
|
||||
volume_size = volume.size
|
||||
|
||||
if getattr(self.configuration,
|
||||
self.driver_prefix + '_sparsed_volumes'):
|
||||
|
@ -280,13 +281,13 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
|
|||
|
||||
:param volume: volume reference
|
||||
"""
|
||||
if not volume['provider_location']:
|
||||
if not volume.provider_location:
|
||||
LOG.warning(_LW('Volume %s does not have '
|
||||
'provider_location specified, '
|
||||
'skipping'), volume['name'])
|
||||
'skipping'), volume.name)
|
||||
return
|
||||
|
||||
self._ensure_share_mounted(volume['provider_location'])
|
||||
self._ensure_share_mounted(volume.provider_location)
|
||||
|
||||
mounted_path = self.local_path(volume)
|
||||
|
||||
|
@ -294,7 +295,7 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
|
|||
|
||||
def ensure_export(self, ctx, 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):
|
||||
"""Exports the volume.
|
||||
|
@ -387,9 +388,9 @@ class RemoteFSDriver(driver.LocalVD, driver.TransferVD, driver.BaseVD):
|
|||
|
||||
: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),
|
||||
volume['name'])
|
||||
volume.name)
|
||||
|
||||
def copy_image_to_volume(self, context, volume, image_service, image_id):
|
||||
"""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,
|
||||
self.local_path(volume),
|
||||
self.configuration.volume_dd_blocksize,
|
||||
size=volume['size'],
|
||||
size=volume.size,
|
||||
run_as_root=run_as_root)
|
||||
|
||||
# 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
|
||||
# this sets the size to the one asked in the first place by the user
|
||||
# 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)
|
||||
|
||||
data = image_utils.qemu_img_info(self.local_path(volume),
|
||||
run_as_root=run_as_root)
|
||||
virt_size = data.virtual_size / units.Gi
|
||||
if virt_size != volume['size']:
|
||||
if virt_size != volume.size:
|
||||
raise exception.ImageUnacceptable(
|
||||
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))
|
||||
|
||||
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()
|
||||
|
||||
def _local_volume_dir(self, volume):
|
||||
share = volume['provider_location']
|
||||
share = volume.provider_location
|
||||
local_dir = self._get_mount_point_for_share(share)
|
||||
return local_dir
|
||||
|
||||
def _local_path_volume(self, volume):
|
||||
path_to_disk = os.path.join(
|
||||
self._local_volume_dir(volume),
|
||||
volume['name'])
|
||||
volume.name)
|
||||
|
||||
return path_to_disk
|
||||
|
||||
def _get_new_snap_path(self, snapshot):
|
||||
vol_path = self.local_path(snapshot['volume'])
|
||||
snap_path = '%s.%s' % (vol_path, snapshot['id'])
|
||||
vol_path = self.local_path(snapshot.volume)
|
||||
snap_path = '%s.%s' % (vol_path, snapshot.id)
|
||||
return snap_path
|
||||
|
||||
def _local_path_volume_info(self, volume):
|
||||
|
@ -757,7 +758,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
|
||||
output = []
|
||||
|
||||
info = self._qemu_img_info(path, volume['name'])
|
||||
info = self._qemu_img_info(path, volume.name)
|
||||
new_info = {}
|
||||
new_info['filename'] = os.path.basename(path)
|
||||
new_info['backing-filename'] = info.backing_file
|
||||
|
@ -767,7 +768,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
while new_info['backing-filename']:
|
||||
filename = new_info['backing-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
|
||||
new_info = {}
|
||||
new_info['filename'] = filename
|
||||
|
@ -846,13 +847,13 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
active_file = self.get_active_image_from_info(volume)
|
||||
active_file_path = os.path.join(self._local_volume_dir(volume),
|
||||
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
|
||||
|
||||
root_file_fmt = info.file_format
|
||||
|
||||
tmp_params = {
|
||||
'prefix': '%s.temp_image.%s' % (volume['id'], image_meta['id']),
|
||||
'prefix': '%s.temp_image.%s' % (volume.id, image_meta['id']),
|
||||
'suffix': '.img'
|
||||
}
|
||||
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):
|
||||
LOG.info(_LI('Cloning volume %(src)s to volume %(dst)s'),
|
||||
{'src': src_vref['id'],
|
||||
'dst': volume['id']})
|
||||
{'src': src_vref.id,
|
||||
'dst': volume.id})
|
||||
|
||||
if src_vref['status'] != 'available':
|
||||
if src_vref.status != 'available':
|
||||
msg = _("Volume status must be 'available'.")
|
||||
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)
|
||||
try:
|
||||
self._copy_volume_from_snapshot(temp_snapshot,
|
||||
volume_info,
|
||||
volume['size'])
|
||||
volume.size)
|
||||
|
||||
finally:
|
||||
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):
|
||||
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)
|
||||
|
||||
snapshot_file = snap_info[snapshot['id']]
|
||||
active_file = self.get_active_image_from_info(snapshot['volume'])
|
||||
snapshot_file = snap_info[snapshot.id]
|
||||
active_file = self.get_active_image_from_info(snapshot.volume)
|
||||
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):
|
||||
return
|
||||
|
||||
LOG.info(_LI('Deleting stale snapshot: %s'), snapshot['id'])
|
||||
LOG.info(_LI('Deleting stale snapshot: %s'), snapshot.id)
|
||||
self._delete(snapshot_path)
|
||||
del(snap_info[snapshot['id']])
|
||||
del(snap_info[snapshot.id])
|
||||
self._write_info_file(info_path, snap_info)
|
||||
|
||||
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']:
|
||||
msg = _('Volume status must be "available" or "in-use".')
|
||||
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)
|
||||
|
||||
# Determine the true snapshot file for this snapshot
|
||||
# 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)
|
||||
|
||||
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
|
||||
# exist, do not attempt to delete.
|
||||
# (This happens, for example, if snapshot_create failed due to lack
|
||||
# of permission to write to the share.)
|
||||
LOG.info(_LI('Snapshot record for %s is not present, allowing '
|
||||
'snapshot_delete to proceed.'), snapshot['id'])
|
||||
'snapshot_delete to proceed.'), snapshot.id)
|
||||
return
|
||||
|
||||
snapshot_file = snap_info[snapshot['id']]
|
||||
snapshot_file = snap_info[snapshot.id]
|
||||
LOG.debug('snapshot_file for this snap is: %s', snapshot_file)
|
||||
snapshot_path = os.path.join(
|
||||
self._local_volume_dir(snapshot['volume']),
|
||||
self._local_volume_dir(snapshot.volume),
|
||||
snapshot_file)
|
||||
|
||||
snapshot_path_img_info = self._qemu_img_info(
|
||||
snapshot_path,
|
||||
snapshot['volume']['name'])
|
||||
snapshot.volume.name)
|
||||
|
||||
base_file = snapshot_path_img_info.backing_file
|
||||
if base_file is None:
|
||||
|
@ -996,15 +1009,15 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
|
||||
base_path = os.path.join(vol_path, base_file)
|
||||
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
|
||||
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)
|
||||
|
||||
if volume_status == 'in-use':
|
||||
# Online delete
|
||||
context = snapshot['context']
|
||||
context = snapshot._context
|
||||
|
||||
new_base_file = base_file_img_info.backing_file
|
||||
|
||||
|
@ -1048,7 +1061,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
# used here) | | ptr update) |
|
||||
|
||||
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
|
||||
# the active file.
|
||||
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)
|
||||
|
||||
# Remove snapshot_file from info
|
||||
del(snap_info[snapshot['id']])
|
||||
del(snap_info[snapshot.id])
|
||||
self._write_info_file(info_path, snap_info)
|
||||
|
||||
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)
|
||||
"""
|
||||
|
||||
if snapshot['status'] != 'available':
|
||||
if snapshot.status != 'available':
|
||||
msg = _('Snapshot status must be "available" to clone.')
|
||||
raise exception.InvalidSnapshot(msg)
|
||||
|
||||
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._copy_volume_from_snapshot(snapshot,
|
||||
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):
|
||||
raise NotImplementedError()
|
||||
|
@ -1116,7 +1129,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
"""
|
||||
|
||||
backing_path_full_path = os.path.join(
|
||||
self._local_volume_dir(snapshot['volume']),
|
||||
self._local_volume_dir(snapshot.volume),
|
||||
backing_filename)
|
||||
|
||||
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)
|
||||
|
||||
info = self._qemu_img_info(backing_path_full_path,
|
||||
snapshot['volume']['name'])
|
||||
snapshot.volume.name)
|
||||
backing_fmt = info.file_format
|
||||
|
||||
command = ['qemu-img', 'rebase', '-u',
|
||||
|
@ -1239,16 +1252,16 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
info file: { 'active': 'volume-1234' } (* changed!)
|
||||
"""
|
||||
|
||||
status = snapshot['volume']['status']
|
||||
status = snapshot.volume.status
|
||||
if status not in ['available', 'in-use']:
|
||||
msg = _('Volume status must be "available" or "in-use"'
|
||||
' for snapshot. (is %s)') % status
|
||||
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)
|
||||
backing_filename = self.get_active_image_from_info(
|
||||
snapshot['volume'])
|
||||
snapshot.volume)
|
||||
new_snap_path = self._get_new_snap_path(snapshot)
|
||||
|
||||
if status == 'in-use':
|
||||
|
@ -1261,13 +1274,13 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
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)
|
||||
|
||||
def _create_snapshot_online(self, snapshot, backing_filename,
|
||||
new_snap_path):
|
||||
# Perform online snapshot via Nova
|
||||
context = snapshot['context']
|
||||
context = snapshot._context
|
||||
|
||||
self._do_create_snapshot(snapshot,
|
||||
backing_filename,
|
||||
|
@ -1276,13 +1289,13 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
connection_info = {
|
||||
'type': 'qcow2',
|
||||
'new_file': os.path.basename(new_snap_path),
|
||||
'snapshot_id': snapshot['id']
|
||||
'snapshot_id': snapshot.id
|
||||
}
|
||||
|
||||
try:
|
||||
result = self._nova.create_volume_snapshot(
|
||||
context,
|
||||
snapshot['volume_id'],
|
||||
snapshot.volume_id,
|
||||
connection_info)
|
||||
LOG.debug('nova call result: %s', result)
|
||||
except Exception:
|
||||
|
@ -1296,7 +1309,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
increment = 1
|
||||
timeout = 600
|
||||
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',
|
||||
{'id': snapshot['id'],
|
||||
|
@ -1320,7 +1333,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
msg = _('Snapshot %(id)s has been asked to be deleted while '
|
||||
'waiting for it to become available. Perhaps a '
|
||||
'concurrent request was made.') % {'id':
|
||||
snapshot['id']}
|
||||
snapshot.id}
|
||||
raise exception.RemoteFSConcurrentRequest(msg)
|
||||
|
||||
if 10 < seconds_elapsed <= 20:
|
||||
|
@ -1332,13 +1345,13 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
|
||||
if seconds_elapsed > timeout:
|
||||
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)
|
||||
|
||||
def _delete_snapshot_online(self, context, snapshot, info):
|
||||
# Update info over the course of this method
|
||||
# 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)
|
||||
|
||||
if info['active_file'] == info['snapshot_file']:
|
||||
|
@ -1357,9 +1370,9 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
delete_info = {'file_to_merge': new_base,
|
||||
'merge_target_file': None, # current
|
||||
'type': 'qcow2',
|
||||
'volume_id': snapshot['volume']['id']}
|
||||
'volume_id': snapshot.volume.id}
|
||||
|
||||
del(snap_info[snapshot['id']])
|
||||
del(snap_info[snapshot.id])
|
||||
else:
|
||||
# blockCommit snapshot into base
|
||||
# info['base'] <= snapshot_file
|
||||
|
@ -1369,14 +1382,14 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
delete_info = {'file_to_merge': info['snapshot_file'],
|
||||
'merge_target_file': info['base_file'],
|
||||
'type': 'qcow2',
|
||||
'volume_id': snapshot['volume']['id']}
|
||||
'volume_id': snapshot.volume.id}
|
||||
|
||||
del(snap_info[snapshot['id']])
|
||||
del(snap_info[snapshot.id])
|
||||
|
||||
try:
|
||||
self._nova.delete_volume_snapshot(
|
||||
context,
|
||||
snapshot['id'],
|
||||
snapshot.id,
|
||||
delete_info)
|
||||
except Exception:
|
||||
LOG.exception(_LE('Call to Nova delete snapshot failed'))
|
||||
|
@ -1389,7 +1402,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
increment = 1
|
||||
timeout = 7200
|
||||
while True:
|
||||
s = db.snapshot_get(context, snapshot['id'])
|
||||
s = db.snapshot_get(context, snapshot.id)
|
||||
|
||||
if s['status'] == fields.SnapshotStatus.DELETING:
|
||||
if s['progress'] == '90%':
|
||||
|
@ -1397,12 +1410,12 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
break
|
||||
else:
|
||||
LOG.debug('status of snapshot %s is still "deleting"... '
|
||||
'waiting', snapshot['id'])
|
||||
'waiting', snapshot.id)
|
||||
time.sleep(increment)
|
||||
seconds_elapsed += increment
|
||||
else:
|
||||
msg = _('Unable to delete snapshot %(id)s, '
|
||||
'status: %(status)s.') % {'id': snapshot['id'],
|
||||
'status: %(status)s.') % {'id': snapshot.id,
|
||||
'status': s['status']}
|
||||
raise exception.RemoteFSException(msg)
|
||||
|
||||
|
@ -1416,7 +1429,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
if seconds_elapsed > timeout:
|
||||
msg = _('Timed out while waiting for Nova update '
|
||||
'for deletion of snapshot %(id)s.') %\
|
||||
{'id': snapshot['id']}
|
||||
{'id': snapshot.id}
|
||||
raise exception.RemoteFSException(msg)
|
||||
|
||||
# Write info file updated above
|
||||
|
@ -1424,7 +1437,7 @@ class RemoteFSSnapDriver(RemoteFSDriver, driver.SnapshotVD):
|
|||
|
||||
# Delete stale file
|
||||
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)
|
||||
|
||||
@locked_volume_id_operation
|
||||
|
|
|
@ -188,14 +188,14 @@ class ScalityDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
active_file = self.get_active_image_from_info(volume)
|
||||
path = '%s/%s' % (self._get_mount_point_for_share(), active_file)
|
||||
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,
|
||||
'sofs_path': sofs_rel_path}
|
||||
|
||||
# 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
|
||||
if data['format'] not in ['raw', 'qcow2']:
|
||||
msg = _('%s must be a valid raw or qcow2 image.') % path
|
||||
|
@ -215,7 +215,7 @@ class ScalityDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
def extend_volume(self, volume, size_gb):
|
||||
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
|
||||
|
||||
if backing_fmt not in ['raw', 'qcow2']:
|
||||
|
@ -232,7 +232,7 @@ class ScalityDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
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
|
||||
try:
|
||||
|
@ -243,15 +243,15 @@ class ScalityDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
else:
|
||||
path_to_snap_img = self.local_path(snapshot)
|
||||
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)
|
||||
|
||||
# Find the file which backs this file, which represents the point
|
||||
# when this snapshot was created.
|
||||
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)
|
||||
|
||||
|
@ -272,7 +272,7 @@ class ScalityDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
"""Create a new backup from an existing volume."""
|
||||
volume = self.db.volume_get(context, backup['volume_id'])
|
||||
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)
|
||||
if qemu_img_info.file_format != 'raw':
|
||||
|
@ -292,8 +292,8 @@ class ScalityDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
def restore_backup(self, context, backup, volume, backup_service):
|
||||
"""Restore an existing backup to a new or existing volume."""
|
||||
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)
|
||||
with utils.temporary_chown(volume_local_path):
|
||||
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)
|
||||
|
|
|
@ -91,7 +91,7 @@ def update_allocation_data(delete=False):
|
|||
if delete:
|
||||
allocated_size_gb = None
|
||||
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)
|
||||
return ret_val
|
||||
|
@ -151,11 +151,11 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
active_file = self.get_active_image_from_info(volume)
|
||||
fmt = self.get_volume_format(volume)
|
||||
|
||||
data = {'export': volume['provider_location'],
|
||||
data = {'export': volume.provider_location,
|
||||
'format': fmt,
|
||||
'name': active_file}
|
||||
if volume['provider_location'] in self.shares:
|
||||
data['options'] = self.shares[volume['provider_location']]
|
||||
if volume.provider_location in self.shares:
|
||||
data['options'] = self.shares[volume.provider_location]
|
||||
return {
|
||||
'driver_volume_type': self.driver_volume_type,
|
||||
'data': data,
|
||||
|
@ -208,8 +208,8 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
self._allocation_data = json.load(f)
|
||||
|
||||
def update_disk_allocation_data(self, volume, virtual_size_gb=None):
|
||||
volume_name = volume['name']
|
||||
smbfs_share = volume['provider_location']
|
||||
volume_name = volume.name
|
||||
smbfs_share = volume.provider_location
|
||||
if smbfs_share:
|
||||
share_hash = self._get_hash_str(smbfs_share)
|
||||
else:
|
||||
|
@ -259,7 +259,7 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
|
||||
def _get_local_volume_path_template(self, 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
|
||||
|
||||
def _lookup_local_volume_path(self, volume_path_template):
|
||||
|
@ -273,9 +273,9 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
return '%s%s' % (self.local_path(volume), '.info')
|
||||
|
||||
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 += '.' + snapshot['id'] + ext
|
||||
snap_path += '.' + snapshot.id + ext
|
||||
return snap_path
|
||||
|
||||
def get_volume_format(self, volume, qemu_format=False):
|
||||
|
@ -287,7 +287,7 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
if ext in self._SUPPORTED_IMAGE_FORMATS:
|
||||
volume_format = ext
|
||||
else:
|
||||
info = self._qemu_img_info(volume_path, volume['name'])
|
||||
info = self._qemu_img_info(volume_path, volume.name)
|
||||
volume_format = info.file_format
|
||||
else:
|
||||
volume_format = (
|
||||
|
@ -305,12 +305,12 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
@update_allocation_data(delete=True)
|
||||
def delete_volume(self, 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 '
|
||||
'specified, skipping.'), volume['name'])
|
||||
'specified, skipping.'), volume.name)
|
||||
return
|
||||
|
||||
self._ensure_share_mounted(volume['provider_location'])
|
||||
self._ensure_share_mounted(volume.provider_location)
|
||||
volume_dir = self._local_volume_dir(volume)
|
||||
mounted_path = os.path.join(volume_dir,
|
||||
self.get_active_image_from_info(volume))
|
||||
|
@ -345,7 +345,7 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
"""
|
||||
volume_format = self.get_volume_format(volume)
|
||||
volume_path = self.local_path(volume)
|
||||
volume_size = volume['size']
|
||||
volume_size = volume.size
|
||||
|
||||
LOG.debug("Creating new volume at %s.", volume_path)
|
||||
|
||||
|
@ -472,7 +472,7 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
snapshot, backing_filename, new_snap_path)
|
||||
|
||||
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
|
||||
if volume_format in (self._DISK_FORMAT_VHD, self._DISK_FORMAT_VHDX):
|
||||
err_msg = _("Snapshots are not supported for this volume "
|
||||
|
@ -482,7 +482,7 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
@remotefs_drv.locked_volume_id_operation
|
||||
@update_allocation_data()
|
||||
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)
|
||||
|
||||
def _extend_volume(self, volume, size_gb):
|
||||
|
@ -491,7 +491,7 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
self._check_extend_volume_support(volume, 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):
|
||||
info = self._qemu_img_info(volume_path, volume_name)
|
||||
|
@ -525,12 +525,12 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
'driver when no snapshots exist.')
|
||||
raise exception.InvalidVolume(msg)
|
||||
|
||||
extend_by = int(size_gb) - volume['size']
|
||||
if not self._is_share_eligible(volume['provider_location'],
|
||||
extend_by = int(size_gb) - volume.size
|
||||
if not self._is_share_eligible(volume.provider_location,
|
||||
extend_by):
|
||||
raise exception.ExtendVolumeError(reason='Insufficient space to '
|
||||
'extend volume %s to %sG.'
|
||||
% (volume['id'], size_gb))
|
||||
% (volume.id, size_gb))
|
||||
|
||||
@remotefs_drv.locked_volume_id_operation
|
||||
@update_allocation_data()
|
||||
|
@ -546,22 +546,22 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
|
||||
LOG.debug("Snapshot: %(snap)s, volume: %(vol)s, "
|
||||
"volume_size: %(size)s",
|
||||
{'snap': snapshot['id'],
|
||||
'vol': volume['id'],
|
||||
{'snap': snapshot.id,
|
||||
'vol': volume.id,
|
||||
'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)
|
||||
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)
|
||||
|
||||
forward_file = snap_info[snapshot['id']]
|
||||
forward_file = snap_info[snapshot.id]
|
||||
forward_path = os.path.join(vol_dir, forward_file)
|
||||
|
||||
# Find the file which backs this file, which represents the point
|
||||
# when this snapshot was created.
|
||||
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)
|
||||
|
||||
LOG.debug("Will copy from snapshot at %s", path_to_snap_img)
|
||||
|
@ -583,15 +583,15 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
self.configuration.volume_dd_blocksize)
|
||||
|
||||
self._do_extend_volume(self.local_path(volume),
|
||||
volume['size'],
|
||||
volume['name'])
|
||||
volume.size,
|
||||
volume.name)
|
||||
|
||||
data = image_utils.qemu_img_info(self.local_path(volume))
|
||||
virt_size = data.virtual_size / units.Gi
|
||||
if virt_size != volume['size']:
|
||||
if virt_size != volume.size:
|
||||
raise exception.ImageUnacceptable(
|
||||
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))
|
||||
|
||||
@remotefs_drv.locked_volume_id_operation
|
||||
|
@ -641,38 +641,15 @@ class SmbfsDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
return flags.strip(',')
|
||||
|
||||
def _get_volume_format_spec(self, volume):
|
||||
# This method needs to be able to parse metadata/volume type
|
||||
# specs for volume SQLAlchemy objects and versioned objects,
|
||||
# as the transition to versioned objects is not complete and the
|
||||
# driver may receive either of them.
|
||||
#
|
||||
# TODO(lpetrut): once the transition to oslo.versionedobjects is
|
||||
# complete, we can skip some of those checks.
|
||||
volume_metadata_specs = {}
|
||||
volume_type_specs = {}
|
||||
vol_type = volume.volume_type
|
||||
extra_specs = {}
|
||||
if vol_type and vol_type.extra_specs:
|
||||
extra_specs = vol_type.extra_specs
|
||||
|
||||
if volume.get('metadata') and isinstance(volume.metadata, dict):
|
||||
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})
|
||||
extra_specs.update(volume.metadata or {})
|
||||
|
||||
vol_type = volume.get('volume_type')
|
||||
if vol_type:
|
||||
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
|
||||
return (extra_specs.get('volume_format') or
|
||||
self.configuration.smbfs_default_volume_format)
|
||||
|
||||
def _is_file_size_equal(self, path, size):
|
||||
"""Checks if file size at path is equal to size."""
|
||||
|
|
|
@ -112,10 +112,10 @@ class VZStorageDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
active_file = self.get_active_image_from_info(volume)
|
||||
active_file_path = os.path.join(self._local_volume_dir(volume),
|
||||
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
|
||||
|
||||
data = {'export': volume['provider_location'],
|
||||
data = {'export': volume.provider_location,
|
||||
'format': fmt,
|
||||
'name': active_file,
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ class VZStorageDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
|
||||
@remotefs_drv.locked_volume_id_operation
|
||||
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)
|
||||
|
||||
def _extend_volume(self, volume, size_gb):
|
||||
|
@ -259,12 +259,12 @@ class VZStorageDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
'driver when no snapshots exist.')
|
||||
raise exception.InvalidVolume(msg)
|
||||
|
||||
extend_by = int(size_gb) - volume['size']
|
||||
if not self._is_share_eligible(volume['provider_location'],
|
||||
extend_by = int(size_gb) - volume.size
|
||||
if not self._is_share_eligible(volume.provider_location,
|
||||
extend_by):
|
||||
raise exception.ExtendVolumeError(reason='Insufficient space to '
|
||||
'extend volume %s to %sG.'
|
||||
% (volume['id'], size_gb))
|
||||
% (volume.id, size_gb))
|
||||
|
||||
def _is_file_size_equal(self, path, size):
|
||||
"""Checks if file size at path is equal to size."""
|
||||
|
@ -281,23 +281,23 @@ class VZStorageDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
|
||||
LOG.debug("_copy_volume_from_snapshot: snapshot: %(snap)s, "
|
||||
"volume: %(vol)s, volume_size: %(size)s.",
|
||||
{'snap': snapshot['id'],
|
||||
'vol': volume['id'],
|
||||
{'snap': snapshot.id,
|
||||
'vol': volume.id,
|
||||
'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)
|
||||
vol_dir = self._local_volume_dir(snapshot['volume'])
|
||||
vol_dir = self._local_volume_dir(snapshot.volume)
|
||||
out_format = "raw"
|
||||
|
||||
forward_file = snap_info[snapshot['id']]
|
||||
forward_file = snap_info[snapshot.id]
|
||||
forward_path = os.path.join(vol_dir, forward_file)
|
||||
|
||||
# Find the file which backs this file, which represents the point
|
||||
# when this snapshot was created.
|
||||
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)
|
||||
|
||||
LOG.debug("_copy_volume_from_snapshot: will copy "
|
||||
|
@ -311,13 +311,13 @@ class VZStorageDriver(remotefs_drv.RemoteFSSnapDriver):
|
|||
@remotefs_drv.locked_volume_id_operation
|
||||
def delete_volume(self, volume):
|
||||
"""Deletes a logical volume."""
|
||||
if not volume['provider_location']:
|
||||
if not volume.provider_location:
|
||||
msg = (_('Volume %s does not have provider_location '
|
||||
'specified, skipping.') % volume['name'])
|
||||
'specified, skipping.') % volume.name)
|
||||
LOG.error(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)
|
||||
mounted_path = os.path.join(volume_dir,
|
||||
self.get_active_image_from_info(volume))
|
||||
|
|
Loading…
Reference in New Issue