RBD: use versioned objects

Change-Id: I4dff418ccdbd364c327b35ce78421271877bbf4e
This commit is contained in:
Jon Bernard 2016-02-09 17:46:53 -05:00 committed by Jon Bernard
parent 04b2cdf9b5
commit 39c11adaee
2 changed files with 148 additions and 148 deletions

View File

@ -23,12 +23,14 @@ import tempfile
import mock import mock
from oslo_utils import units from oslo_utils import units
from cinder import context
from cinder import exception from cinder import exception
from cinder.i18n import _ from cinder.i18n import _
import cinder.image.glance import cinder.image.glance
from cinder.image import image_utils from cinder.image import image_utils
from cinder import objects from cinder import objects
from cinder import test from cinder import test
from cinder.tests.unit import fake_snapshot
from cinder.tests.unit import fake_volume from cinder.tests.unit import fake_volume
from cinder.tests.unit import test_volume from cinder.tests.unit import test_volume
from cinder.tests.unit import utils from cinder.tests.unit import utils
@ -150,12 +152,22 @@ class RBDTestCase(test.TestCase):
configuration=self.cfg) configuration=self.cfg)
self.driver.set_initialized() self.driver.set_initialized()
self.volume_name = u'volume-00000001' self.context = context.get_admin_context()
self.snapshot_name = u'snapshot-00000001'
self.volume_size = 1 self.volume_a = fake_volume.fake_volume_obj(
self.volume = dict(name=self.volume_name, size=self.volume_size) self.context,
self.snapshot = dict(volume_name=self.volume_name, **{'name': u'volume-0000000a',
name=self.snapshot_name) 'id': '4c39c3c7-168f-4b32-b585-77f1b3bf0a38',
'size': 10})
self.volume_b = fake_volume.fake_volume_obj(
self.context,
**{'name': u'volume-0000000b',
'id': '0c7d1f44-5a06-403f-bb82-ae7ad0d693a6',
'size': 10})
self.snapshot = fake_snapshot.fake_snapshot_obj(
self.context, name='snapshot-0000000a')
@ddt.data({'cluster_name': None, 'pool_name': 'rbd'}, @ddt.data({'cluster_name': None, 'pool_name': 'rbd'},
{'cluster_name': 'volumes', 'pool_name': None}) {'cluster_name': 'volumes', 'pool_name': None})
@ -173,12 +185,12 @@ class RBDTestCase(test.TestCase):
client = self.mock_client.return_value client = self.mock_client.return_value
client.__enter__.return_value = client client.__enter__.return_value = client
self.driver.create_volume(self.volume) self.driver.create_volume(self.volume_a)
chunk_size = self.cfg.rbd_store_chunk_size * units.Mi chunk_size = self.cfg.rbd_store_chunk_size * units.Mi
order = int(math.log(chunk_size, 2)) order = int(math.log(chunk_size, 2))
args = [client.ioctx, str(self.volume_name), args = [client.ioctx, str(self.volume_a.name),
self.volume_size * units.Gi, order] self.volume_a.size * units.Gi, order]
kwargs = {'old_format': False, kwargs = {'old_format': False,
'features': client.features} 'features': client.features}
self.mock_rbd.RBD.return_value.create.assert_called_once_with( self.mock_rbd.RBD.return_value.create.assert_called_once_with(
@ -193,9 +205,9 @@ class RBDTestCase(test.TestCase):
with mock.patch.object(self.driver.rbd.Image(), 'close') \ with mock.patch.object(self.driver.rbd.Image(), 'close') \
as mock_rbd_image_close: as mock_rbd_image_close:
mock_rbd_image_size.return_value = 2 * units.Gi mock_rbd_image_size.return_value = 2 * units.Gi
existing_ref = {'source-name': self.volume_name} existing_ref = {'source-name': self.volume_a.name}
return_size = self.driver.manage_existing_get_size( return_size = self.driver.manage_existing_get_size(
self.volume, self.volume_a,
existing_ref) existing_ref)
self.assertEqual(2, return_size) self.assertEqual(2, return_size)
mock_rbd_image_size.assert_called_once_with() mock_rbd_image_size.assert_called_once_with()
@ -209,10 +221,10 @@ class RBDTestCase(test.TestCase):
with mock.patch.object(self.driver.rbd.Image(), 'close') \ with mock.patch.object(self.driver.rbd.Image(), 'close') \
as mock_rbd_image_close: as mock_rbd_image_close:
mock_rbd_image_size.return_value = 'abcd' mock_rbd_image_size.return_value = 'abcd'
existing_ref = {'source-name': self.volume_name} existing_ref = {'source-name': self.volume_a.name}
self.assertRaises(exception.VolumeBackendAPIException, self.assertRaises(exception.VolumeBackendAPIException,
self.driver.manage_existing_get_size, self.driver.manage_existing_get_size,
self.volume, existing_ref) self.volume_a, existing_ref)
mock_rbd_image_size.assert_called_once_with() mock_rbd_image_size.assert_called_once_with()
mock_rbd_image_close.assert_called_once_with() mock_rbd_image_close.assert_called_once_with()
@ -227,11 +239,11 @@ class RBDTestCase(test.TestCase):
exist_volume = 'vol-exist' exist_volume = 'vol-exist'
existing_ref = {'source-name': exist_volume} existing_ref = {'source-name': exist_volume}
mock_rbd_image_rename.return_value = 0 mock_rbd_image_rename.return_value = 0
self.driver.manage_existing(self.volume, existing_ref) self.driver.manage_existing(self.volume_a, existing_ref)
mock_rbd_image_rename.assert_called_with( mock_rbd_image_rename.assert_called_with(
client.ioctx, client.ioctx,
exist_volume, exist_volume,
self.volume_name) self.volume_a.name)
@common_mocks @common_mocks
def test_manage_existing_with_exist_rbd_image(self): def test_manage_existing_with_exist_rbd_image(self):
@ -245,7 +257,7 @@ class RBDTestCase(test.TestCase):
existing_ref = {'source-name': exist_volume} existing_ref = {'source-name': exist_volume}
self.assertRaises(self.mock_rbd.ImageExists, self.assertRaises(self.mock_rbd.ImageExists,
self.driver.manage_existing, self.driver.manage_existing,
self.volume, existing_ref) self.volume_a, existing_ref)
# Make sure the exception was raised # Make sure the exception was raised
self.assertEqual(RAISED_EXCEPTIONS, self.assertEqual(RAISED_EXCEPTIONS,
@ -275,11 +287,11 @@ class RBDTestCase(test.TestCase):
mock_delete_backup_snaps: mock_delete_backup_snaps:
mock_get_clone_info.return_value = (None, None, None) mock_get_clone_info.return_value = (None, None, None)
self.driver.delete_volume(self.volume) self.driver.delete_volume(self.volume_a)
mock_get_clone_info.assert_called_once_with( mock_get_clone_info.assert_called_once_with(
self.mock_rbd.Image.return_value, self.mock_rbd.Image.return_value,
self.volume_name, self.volume_a.name,
None) None)
(self.driver.rbd.Image.return_value (self.driver.rbd.Image.return_value
.list_snaps.assert_called_once_with()) .list_snaps.assert_called_once_with())
@ -295,7 +307,7 @@ class RBDTestCase(test.TestCase):
@common_mocks @common_mocks
def delete_volume_not_found(self): def delete_volume_not_found(self):
self.mock_rbd.Image.side_effect = self.mock_rbd.ImageNotFound self.mock_rbd.Image.side_effect = self.mock_rbd.ImageNotFound
self.assertIsNone(self.driver.delete_volume(self.volume)) self.assertIsNone(self.driver.delete_volume(self.volume_a))
self.mock_rbd.Image.assert_called_once_with() self.mock_rbd.Image.assert_called_once_with()
# Make sure the exception was raised # Make sure the exception was raised
self.assertEqual(RAISED_EXCEPTIONS, [self.mock_rbd.ImageNotFound]) self.assertEqual(RAISED_EXCEPTIONS, [self.mock_rbd.ImageNotFound])
@ -315,11 +327,11 @@ class RBDTestCase(test.TestCase):
with mock.patch.object(driver, 'RADOSClient') as \ with mock.patch.object(driver, 'RADOSClient') as \
mock_rados_client: mock_rados_client:
self.assertRaises(exception.VolumeIsBusy, self.assertRaises(exception.VolumeIsBusy,
self.driver.delete_volume, self.volume) self.driver.delete_volume, self.volume_a)
mock_get_clone_info.assert_called_once_with( mock_get_clone_info.assert_called_once_with(
self.mock_rbd.Image.return_value, self.mock_rbd.Image.return_value,
self.volume_name, self.volume_a.name,
None) None)
(self.mock_rbd.Image.return_value.list_snaps (self.mock_rbd.Image.return_value.list_snaps
.assert_called_once_with()) .assert_called_once_with())
@ -348,10 +360,10 @@ class RBDTestCase(test.TestCase):
mock_delete_backup_snaps: mock_delete_backup_snaps:
with mock.patch.object(driver, 'RADOSClient') as \ with mock.patch.object(driver, 'RADOSClient') as \
mock_rados_client: mock_rados_client:
self.assertIsNone(self.driver.delete_volume(self.volume)) self.assertIsNone(self.driver.delete_volume(self.volume_a))
mock_get_clone_info.assert_called_once_with( mock_get_clone_info.assert_called_once_with(
self.mock_rbd.Image.return_value, self.mock_rbd.Image.return_value,
self.volume_name, self.volume_a.name,
None) None)
(self.mock_rbd.Image.return_value.list_snaps (self.mock_rbd.Image.return_value.list_snaps
.assert_called_once_with()) .assert_called_once_with())
@ -367,28 +379,34 @@ class RBDTestCase(test.TestCase):
[self.mock_rbd.ImageNotFound]) [self.mock_rbd.ImageNotFound])
@common_mocks @common_mocks
def test_create_snapshot(self): @mock.patch('cinder.objects.Volume.get_by_id')
def test_create_snapshot(self, volume_get_by_id):
volume_get_by_id.return_value = self.volume_a
proxy = self.mock_proxy.return_value proxy = self.mock_proxy.return_value
proxy.__enter__.return_value = proxy proxy.__enter__.return_value = proxy
self.driver.create_snapshot(self.snapshot) self.driver.create_snapshot(self.snapshot)
args = [str(self.snapshot_name)] args = [str(self.snapshot.name)]
proxy.create_snap.assert_called_with(*args) proxy.create_snap.assert_called_with(*args)
proxy.protect_snap.assert_called_with(*args) proxy.protect_snap.assert_called_with(*args)
@common_mocks @common_mocks
def test_delete_snapshot(self): @mock.patch('cinder.objects.Volume.get_by_id')
def test_delete_snapshot(self, volume_get_by_id):
volume_get_by_id.return_value = self.volume_a
proxy = self.mock_proxy.return_value proxy = self.mock_proxy.return_value
proxy.__enter__.return_value = proxy proxy.__enter__.return_value = proxy
self.driver.delete_snapshot(self.snapshot) self.driver.delete_snapshot(self.snapshot)
proxy.remove_snap.assert_called_with(self.snapshot_name) proxy.remove_snap.assert_called_with(self.snapshot.name)
proxy.unprotect_snap.assert_called_with(self.snapshot_name) proxy.unprotect_snap.assert_called_with(self.snapshot.name)
@common_mocks @common_mocks
def test_delete_notfound_snapshot(self): @mock.patch('cinder.objects.Volume.get_by_id')
def test_delete_notfound_snapshot(self, volume_get_by_id):
volume_get_by_id.return_value = self.volume_a
proxy = self.mock_proxy.return_value proxy = self.mock_proxy.return_value
proxy.__enter__.return_value = proxy proxy.__enter__.return_value = proxy
@ -397,11 +415,13 @@ class RBDTestCase(test.TestCase):
self.driver.delete_snapshot(self.snapshot) self.driver.delete_snapshot(self.snapshot)
proxy.remove_snap.assert_called_with(self.snapshot_name) proxy.remove_snap.assert_called_with(self.snapshot.name)
proxy.unprotect_snap.assert_called_with(self.snapshot_name) proxy.unprotect_snap.assert_called_with(self.snapshot.name)
@common_mocks @common_mocks
def test_delete_unprotected_snapshot(self): @mock.patch('cinder.objects.Volume.get_by_id')
def test_delete_unprotected_snapshot(self, volume_get_by_id):
volume_get_by_id.return_value = self.volume_a
proxy = self.mock_proxy.return_value proxy = self.mock_proxy.return_value
proxy.__enter__.return_value = proxy proxy.__enter__.return_value = proxy
proxy.unprotect_snap.side_effect = self.mock_rbd.InvalidArgument proxy.unprotect_snap.side_effect = self.mock_rbd.InvalidArgument
@ -411,7 +431,9 @@ class RBDTestCase(test.TestCase):
self.assertTrue(proxy.remove_snap.called) self.assertTrue(proxy.remove_snap.called)
@common_mocks @common_mocks
def test_delete_busy_snapshot(self): @mock.patch('cinder.objects.Volume.get_by_id')
def test_delete_busy_snapshot(self, volume_get_by_id):
volume_get_by_id.return_value = self.volume_a
proxy = self.mock_proxy.return_value proxy = self.mock_proxy.return_value
proxy.__enter__.return_value = proxy proxy.__enter__.return_value = proxy
@ -431,7 +453,7 @@ class RBDTestCase(test.TestCase):
mock_get_children_info.assert_called_once_with( mock_get_children_info.assert_called_once_with(
proxy, proxy,
self.snapshot_name) self.snapshot.name)
self.assertTrue(mock_log.info.called) self.assertTrue(mock_log.info.called)
self.assertTrue(proxy.unprotect_snap.called) self.assertTrue(proxy.unprotect_snap.called)
@ -446,7 +468,7 @@ class RBDTestCase(test.TestCase):
volume.list_children.return_value = list_children volume.list_children.return_value = list_children
info = self.driver._get_children_info(volume, info = self.driver._get_children_info(volume,
self.snapshot_name) self.snapshot['name'])
self.assertEqual(list_children, info) self.assertEqual(list_children, info)
@ -455,10 +477,10 @@ class RBDTestCase(test.TestCase):
volume = self.mock_rbd.Image() volume = self.mock_rbd.Image()
volume.set_snap = mock.Mock() volume.set_snap = mock.Mock()
volume.parent_info = mock.Mock() volume.parent_info = mock.Mock()
parent_info = ('a', 'b', '%s.clone_snap' % (self.volume_name)) parent_info = ('a', 'b', '%s.clone_snap' % (self.volume_a.name))
volume.parent_info.return_value = parent_info volume.parent_info.return_value = parent_info
info = self.driver._get_clone_info(volume, self.volume_name) info = self.driver._get_clone_info(volume, self.volume_a.name)
self.assertEqual(parent_info, info) self.assertEqual(parent_info, info)
@ -470,12 +492,12 @@ class RBDTestCase(test.TestCase):
volume = self.mock_rbd.Image() volume = self.mock_rbd.Image()
volume.set_snap = mock.Mock() volume.set_snap = mock.Mock()
volume.parent_info = mock.Mock() volume.parent_info = mock.Mock()
parent_info = ('a', 'b', '%s.clone_snap' % (self.volume_name)) parent_info = ('a', 'b', '%s.clone_snap' % (self.volume_a.name))
volume.parent_info.return_value = parent_info volume.parent_info.return_value = parent_info
snapshot = self.mock_rbd.ImageSnapshot() snapshot = self.mock_rbd.ImageSnapshot()
info = self.driver._get_clone_info(volume, self.volume_name, info = self.driver._get_clone_info(volume, self.volume_a.name,
snap=snapshot) snap=snapshot)
self.assertEqual(parent_info, info) self.assertEqual(parent_info, info)
@ -492,7 +514,7 @@ class RBDTestCase(test.TestCase):
snapshot = self.mock_rbd.ImageSnapshot() snapshot = self.mock_rbd.ImageSnapshot()
info = self.driver._get_clone_info(volume, self.volume_name, info = self.driver._get_clone_info(volume, self.volume_a.name,
snap=snapshot) snap=snapshot)
self.assertEqual((None, None, None), info) self.assertEqual((None, None, None), info)
@ -507,11 +529,11 @@ class RBDTestCase(test.TestCase):
volume = self.mock_rbd.Image() volume = self.mock_rbd.Image()
volume.set_snap = mock.Mock() volume.set_snap = mock.Mock()
volume.parent_info = mock.Mock() volume.parent_info = mock.Mock()
parent_info = ('a', 'b', '%s.clone_snap' % (self.volume_name)) parent_info = ('a', 'b', '%s.clone_snap' % (self.volume_a.name))
volume.parent_info.return_value = parent_info volume.parent_info.return_value = parent_info
info = self.driver._get_clone_info(volume, info = self.driver._get_clone_info(volume,
"%s.deleted" % (self.volume_name)) "%s.deleted" % (self.volume_a.name))
self.assertEqual(parent_info, info) self.assertEqual(parent_info, info)
@ -520,9 +542,6 @@ class RBDTestCase(test.TestCase):
@common_mocks @common_mocks
def test_create_cloned_volume_same_size(self): def test_create_cloned_volume_same_size(self):
src_name = u'volume-00000001'
dst_name = u'volume-00000002'
self.cfg.rbd_max_clone_depth = 2 self.cfg.rbd_max_clone_depth = 2
with mock.patch.object(self.driver, '_get_clone_depth') as \ with mock.patch.object(self.driver, '_get_clone_depth') as \
@ -531,17 +550,14 @@ class RBDTestCase(test.TestCase):
with mock.patch.object(self.driver, '_resize') as mock_resize: with mock.patch.object(self.driver, '_resize') as mock_resize:
mock_get_clone_depth.return_value = 1 mock_get_clone_depth.return_value = 1
self.driver.create_cloned_volume({'name': dst_name, self.driver.create_cloned_volume(self.volume_b, self.volume_a)
'size': 10},
{'name': src_name,
'size': 10})
(self.mock_rbd.Image.return_value.create_snap (self.mock_rbd.Image.return_value.create_snap
.assert_called_once_with('.'.join((dst_name, .assert_called_once_with('.'.join(
'clone_snap')))) (self.volume_b.name, 'clone_snap'))))
(self.mock_rbd.Image.return_value.protect_snap (self.mock_rbd.Image.return_value.protect_snap
.assert_called_once_with('.'.join((dst_name, .assert_called_once_with('.'.join(
'clone_snap')))) (self.volume_b.name, 'clone_snap'))))
self.assertEqual( self.assertEqual(
1, self.mock_rbd.RBD.return_value.clone.call_count) 1, self.mock_rbd.RBD.return_value.clone.call_count)
self.mock_rbd.Image.return_value.close \ self.mock_rbd.Image.return_value.close \
@ -552,9 +568,6 @@ class RBDTestCase(test.TestCase):
@common_mocks @common_mocks
def test_create_cloned_volume_different_size(self): def test_create_cloned_volume_different_size(self):
src_name = u'volume-00000001'
dst_name = u'volume-00000002'
self.cfg.rbd_max_clone_depth = 2 self.cfg.rbd_max_clone_depth = 2
with mock.patch.object(self.driver, '_get_clone_depth') as \ with mock.patch.object(self.driver, '_get_clone_depth') as \
@ -563,17 +576,15 @@ class RBDTestCase(test.TestCase):
with mock.patch.object(self.driver, '_resize') as mock_resize: with mock.patch.object(self.driver, '_resize') as mock_resize:
mock_get_clone_depth.return_value = 1 mock_get_clone_depth.return_value = 1
self.driver.create_cloned_volume({'name': dst_name, self.volume_b.size = 20
'size': 20}, self.driver.create_cloned_volume(self.volume_b, self.volume_a)
{'name': src_name,
'size': 10})
(self.mock_rbd.Image.return_value.create_snap (self.mock_rbd.Image.return_value.create_snap
.assert_called_once_with('.'.join((dst_name, .assert_called_once_with('.'.join(
'clone_snap')))) (self.volume_b.name, 'clone_snap'))))
(self.mock_rbd.Image.return_value.protect_snap (self.mock_rbd.Image.return_value.protect_snap
.assert_called_once_with('.'.join((dst_name, .assert_called_once_with('.'.join(
'clone_snap')))) (self.volume_b.name, 'clone_snap'))))
self.assertEqual( self.assertEqual(
1, self.mock_rbd.RBD.return_value.clone.call_count) 1, self.mock_rbd.RBD.return_value.clone.call_count)
self.mock_rbd.Image.return_value.close \ self.mock_rbd.Image.return_value.close \
@ -584,34 +595,34 @@ class RBDTestCase(test.TestCase):
@common_mocks @common_mocks
def test_create_cloned_volume_w_flatten(self): def test_create_cloned_volume_w_flatten(self):
src_name = u'volume-00000001'
dst_name = u'volume-00000002'
self.cfg.rbd_max_clone_depth = 1 self.cfg.rbd_max_clone_depth = 1
with mock.patch.object(self.driver, '_get_clone_info') as \ with mock.patch.object(self.driver, '_get_clone_info') as \
mock_get_clone_info: mock_get_clone_info:
mock_get_clone_info.return_value = ( mock_get_clone_info.return_value = (
('fake_pool', dst_name, '.'.join((dst_name, 'clone_snap')))) ('fake_pool', self.volume_b.name,
'.'.join((self.volume_b.name, 'clone_snap'))))
with mock.patch.object(self.driver, '_get_clone_depth') as \ with mock.patch.object(self.driver, '_get_clone_depth') as \
mock_get_clone_depth: mock_get_clone_depth:
# Try with no flatten required # Try with no flatten required
mock_get_clone_depth.return_value = 1 mock_get_clone_depth.return_value = 1
self.assertRaises(self.mock_rbd.RBD.Error, self.driver.create_cloned_volume(self.volume_b, self.volume_a)
self.driver.create_cloned_volume,
dict(name=dst_name), dict(name=src_name))
(self.mock_rbd.Image.return_value.create_snap (self.mock_rbd.Image.return_value.create_snap
.assert_called_once_with('.'.join((dst_name, 'clone_snap')))) .assert_called_once_with('.'.join(
(self.volume_b.name, 'clone_snap'))))
(self.mock_rbd.Image.return_value.protect_snap (self.mock_rbd.Image.return_value.protect_snap
.assert_called_once_with('.'.join((dst_name, 'clone_snap')))) .assert_called_once_with('.'.join(
(self.volume_b.name, 'clone_snap'))))
self.assertEqual( self.assertEqual(
1, self.mock_rbd.RBD.return_value.clone.call_count) 1, self.mock_rbd.RBD.return_value.clone.call_count)
(self.mock_rbd.Image.return_value.unprotect_snap (self.mock_rbd.Image.return_value.unprotect_snap
.assert_called_once_with('.'.join((dst_name, 'clone_snap')))) .assert_called_once_with('.'.join(
(self.volume_b.name, 'clone_snap'))))
(self.mock_rbd.Image.return_value.remove_snap (self.mock_rbd.Image.return_value.remove_snap
.assert_called_once_with('.'.join((dst_name, 'clone_snap')))) .assert_called_once_with('.'.join(
(self.volume_b.name, 'clone_snap'))))
# We expect the driver to close both volumes, so 2 is expected # We expect the driver to close both volumes, so 2 is expected
self.assertEqual( self.assertEqual(
@ -620,9 +631,6 @@ class RBDTestCase(test.TestCase):
@common_mocks @common_mocks
def test_create_cloned_volume_w_clone_exception(self): def test_create_cloned_volume_w_clone_exception(self):
src_name = u'volume-00000001'
dst_name = u'volume-00000002'
self.cfg.rbd_max_clone_depth = 2 self.cfg.rbd_max_clone_depth = 2
self.mock_rbd.RBD.return_value.clone.side_effect = ( self.mock_rbd.RBD.return_value.clone.side_effect = (
self.mock_rbd.RBD.Error) self.mock_rbd.RBD.Error)
@ -633,18 +641,22 @@ class RBDTestCase(test.TestCase):
self.assertRaises(self.mock_rbd.RBD.Error, self.assertRaises(self.mock_rbd.RBD.Error,
self.driver.create_cloned_volume, self.driver.create_cloned_volume,
{'name': dst_name}, {'name': src_name}) self.volume_b, self.volume_a)
(self.mock_rbd.Image.return_value.create_snap (self.mock_rbd.Image.return_value.create_snap
.assert_called_once_with('.'.join((dst_name, 'clone_snap')))) .assert_called_once_with('.'.join(
(self.volume_b.name, 'clone_snap'))))
(self.mock_rbd.Image.return_value.protect_snap (self.mock_rbd.Image.return_value.protect_snap
.assert_called_once_with('.'.join((dst_name, 'clone_snap')))) .assert_called_once_with('.'.join(
(self.volume_b.name, 'clone_snap'))))
self.assertEqual( self.assertEqual(
1, self.mock_rbd.RBD.return_value.clone.call_count) 1, self.mock_rbd.RBD.return_value.clone.call_count)
(self.mock_rbd.Image.return_value.unprotect_snap (self.mock_rbd.Image.return_value.unprotect_snap
.assert_called_once_with('.'.join((dst_name, 'clone_snap')))) .assert_called_once_with('.'.join(
(self.volume_b.name, 'clone_snap'))))
(self.mock_rbd.Image.return_value.remove_snap (self.mock_rbd.Image.return_value.remove_snap
.assert_called_once_with('.'.join((dst_name, 'clone_snap')))) .assert_called_once_with('.'.join(
(self.volume_b.name, 'clone_snap'))))
self.mock_rbd.Image.return_value.close.assert_called_once_with() self.mock_rbd.Image.return_value.close.assert_called_once_with()
@common_mocks @common_mocks
@ -720,7 +732,7 @@ class RBDTestCase(test.TestCase):
with mock.patch.object(self.driver, 'delete_volume'): with mock.patch.object(self.driver, 'delete_volume'):
with mock.patch.object(self.driver, '_resize'): with mock.patch.object(self.driver, '_resize'):
mock_image_service = mock.MagicMock() mock_image_service = mock.MagicMock()
args = [None, {'name': 'test', 'size': 1}, args = [None, self.volume_a,
mock_image_service, None] mock_image_service, None]
self.driver.copy_image_to_volume(*args) self.driver.copy_image_to_volume(*args)
@ -811,23 +823,21 @@ class RBDTestCase(test.TestCase):
mock_get_mon_addrs: mock_get_mon_addrs:
mock_get_mon_addrs.return_value = (hosts, ports) mock_get_mon_addrs.return_value = (hosts, ports)
volume_id = '0a83f0a3-ef6e-47b6-a8aa-20436bc9ed01'
expected = { expected = {
'driver_volume_type': 'rbd', 'driver_volume_type': 'rbd',
'data': { 'data': {
'name': '%s/%s' % (self.cfg.rbd_pool, 'name': '%s/%s' % (self.cfg.rbd_pool,
self.volume_name), self.volume_a.name),
'hosts': hosts, 'hosts': hosts,
'ports': ports, 'ports': ports,
'auth_enabled': False, 'auth_enabled': False,
'auth_username': None, 'auth_username': None,
'secret_type': 'ceph', 'secret_type': 'ceph',
'secret_uuid': None, 'secret_uuid': None,
'volume_id': volume_id 'volume_id': self.volume_a.id
} }
} }
volume = dict(name=self.volume_name, id=volume_id) actual = self.driver.initialize_connection(self.volume_a, None)
actual = self.driver.initialize_connection(volume, None)
self.assertDictMatch(expected, actual) self.assertDictMatch(expected, actual)
self.assertTrue(mock_get_mon_addrs.called) self.assertTrue(mock_get_mon_addrs.called)
@ -849,10 +859,10 @@ class RBDTestCase(test.TestCase):
# capture both rados client used to perform the clone # capture both rados client used to perform the clone
client.__enter__.side_effect = mock__enter__(client) client.__enter__.side_effect = mock__enter__(client)
self.driver._clone(self.volume, src_pool, src_image, src_snap) self.driver._clone(self.volume_a, src_pool, src_image, src_snap)
args = [client_stack[0].ioctx, str(src_image), str(src_snap), args = [client_stack[0].ioctx, str(src_image), str(src_snap),
client_stack[1].ioctx, str(self.volume_name)] client_stack[1].ioctx, str(self.volume_a.name)]
kwargs = {'features': client.features} kwargs = {'features': client.features}
self.mock_rbd.RBD.return_value.clone.assert_called_once_with( self.mock_rbd.RBD.return_value.clone.assert_called_once_with(
*args, **kwargs) *args, **kwargs)
@ -861,14 +871,10 @@ class RBDTestCase(test.TestCase):
@common_mocks @common_mocks
def test_extend_volume(self): def test_extend_volume(self):
fake_size = '20' fake_size = '20'
fake_vol = {'project_id': 'testprjid', 'name': self.volume_name,
'size': fake_size,
'id': 'a720b3c0-d1f0-11e1-9b23-0800200c9a66'}
size = int(fake_size) * units.Gi size = int(fake_size) * units.Gi
with mock.patch.object(self.driver, '_resize') as mock_resize: with mock.patch.object(self.driver, '_resize') as mock_resize:
self.driver.extend_volume(fake_vol, fake_size) self.driver.extend_volume(self.volume_a, fake_size)
mock_resize.assert_called_once_with(fake_vol, size=size) mock_resize.assert_called_once_with(self.volume_a, size=size)
@common_mocks @common_mocks
def test_retype(self): def test_retype(self):
@ -910,27 +916,21 @@ class RBDTestCase(test.TestCase):
with mock.patch.object(self.driver.rbd.RBD(), 'rename') as mock_rename: with mock.patch.object(self.driver.rbd.RBD(), 'rename') as mock_rename:
context = {} context = {}
current_volume = {'id': 'curr_id',
'name': 'curr_name',
'provider_location': 'curr_provider_location'}
original_volume = {'id': 'orig_id',
'name': 'orig_name',
'provider_location': 'orig_provider_location'}
mock_rename.return_value = 0 mock_rename.return_value = 0
model_update = self.driver.update_migrated_volume(context, model_update = self.driver.update_migrated_volume(context,
original_volume, self.volume_a,
current_volume, self.volume_b,
'available') 'available')
mock_rename.assert_called_with(client.ioctx, mock_rename.assert_called_with(client.ioctx,
'volume-%s' % current_volume['id'], 'volume-%s' % self.volume_b.id,
'volume-%s' % original_volume['id']) 'volume-%s' % self.volume_a.id)
self.assertEqual({'_name_id': None, self.assertEqual({'_name_id': None,
'provider_location': None}, model_update) 'provider_location': None}, model_update)
def test_rbd_volume_proxy_init(self): def test_rbd_volume_proxy_init(self):
mock_driver = mock.Mock(name='driver') mock_driver = mock.Mock(name='driver')
mock_driver._connect_to_rados.return_value = (None, None) mock_driver._connect_to_rados.return_value = (None, None)
with driver.RBDVolumeProxy(mock_driver, self.volume_name): with driver.RBDVolumeProxy(mock_driver, self.volume_a.name):
self.assertEqual(1, mock_driver._connect_to_rados.call_count) self.assertEqual(1, mock_driver._connect_to_rados.call_count)
self.assertFalse(mock_driver._disconnect_from_rados.called) self.assertFalse(mock_driver._disconnect_from_rados.called)
@ -939,7 +939,7 @@ class RBDTestCase(test.TestCase):
mock_driver.reset_mock() mock_driver.reset_mock()
snap = u'snapshot-name' snap = u'snapshot-name'
with driver.RBDVolumeProxy(mock_driver, self.volume_name, with driver.RBDVolumeProxy(mock_driver, self.volume_a.name,
snapshot=snap): snapshot=snap):
self.assertEqual(1, mock_driver._connect_to_rados.call_count) self.assertEqual(1, mock_driver._connect_to_rados.call_count)
self.assertFalse(mock_driver._disconnect_from_rados.called) self.assertFalse(mock_driver._disconnect_from_rados.called)

View File

@ -454,8 +454,8 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
and that clone has rbd_max_clone_depth clones behind it, the source and that clone has rbd_max_clone_depth clones behind it, the source
volume will be flattened. volume will be flattened.
""" """
src_name = utils.convert_str(src_vref['name']) src_name = utils.convert_str(src_vref.name)
dest_name = utils.convert_str(volume['name']) dest_name = utils.convert_str(volume.name)
flatten_parent = False flatten_parent = False
# Do full copy if requested # Do full copy if requested
@ -520,27 +520,27 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
finally: finally:
src_volume.close() src_volume.close()
if volume['size'] != src_vref['size']: if volume.size != src_vref.size:
LOG.debug("resize volume '%(dst_vol)s' from %(src_size)d to " LOG.debug("resize volume '%(dst_vol)s' from %(src_size)d to "
"%(dst_size)d", "%(dst_size)d",
{'dst_vol': volume['name'], 'src_size': src_vref['size'], {'dst_vol': volume.name, 'src_size': src_vref.size,
'dst_size': volume['size']}) 'dst_size': volume.size})
self._resize(volume) self._resize(volume)
LOG.debug("clone created successfully") LOG.debug("clone created successfully")
def create_volume(self, volume): def create_volume(self, volume):
"""Creates a logical volume.""" """Creates a logical volume."""
size = int(volume['size']) * units.Gi size = int(volume.size) * units.Gi
LOG.debug("creating volume '%s'", volume['name']) LOG.debug("creating volume '%s'", volume.name)
chunk_size = self.configuration.rbd_store_chunk_size * units.Mi chunk_size = self.configuration.rbd_store_chunk_size * units.Mi
order = int(math.log(chunk_size, 2)) order = int(math.log(chunk_size, 2))
with RADOSClient(self) as client: with RADOSClient(self) as client:
self.RBDProxy().create(client.ioctx, self.RBDProxy().create(client.ioctx,
utils.convert_str(volume['name']), utils.convert_str(volume.name),
size, size,
order, order,
old_format=False, old_format=False,
@ -555,31 +555,31 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
def _clone(self, volume, src_pool, src_image, src_snap): def _clone(self, volume, src_pool, src_image, src_snap):
LOG.debug('cloning %(pool)s/%(img)s@%(snap)s to %(dst)s', LOG.debug('cloning %(pool)s/%(img)s@%(snap)s to %(dst)s',
dict(pool=src_pool, img=src_image, snap=src_snap, dict(pool=src_pool, img=src_image, snap=src_snap,
dst=volume['name'])) dst=volume.name))
with RADOSClient(self, src_pool) as src_client: with RADOSClient(self, src_pool) as src_client:
with RADOSClient(self) as dest_client: with RADOSClient(self) as dest_client:
self.RBDProxy().clone(src_client.ioctx, self.RBDProxy().clone(src_client.ioctx,
utils.convert_str(src_image), utils.convert_str(src_image),
utils.convert_str(src_snap), utils.convert_str(src_snap),
dest_client.ioctx, dest_client.ioctx,
utils.convert_str(volume['name']), utils.convert_str(volume.name),
features=src_client.features) features=src_client.features)
def _resize(self, volume, **kwargs): def _resize(self, volume, **kwargs):
size = kwargs.get('size', None) size = kwargs.get('size', None)
if not size: if not size:
size = int(volume['size']) * units.Gi size = int(volume.size) * units.Gi
with RBDVolumeProxy(self, volume['name']) as vol: with RBDVolumeProxy(self, volume.name) as vol:
vol.resize(size) vol.resize(size)
def create_volume_from_snapshot(self, volume, snapshot): def create_volume_from_snapshot(self, volume, snapshot):
"""Creates a volume from a snapshot.""" """Creates a volume from a snapshot."""
self._clone(volume, self.configuration.rbd_pool, self._clone(volume, self.configuration.rbd_pool,
snapshot['volume_name'], snapshot['name']) snapshot.volume_name, snapshot.name)
if self.configuration.rbd_flatten_volume_from_snapshot: if self.configuration.rbd_flatten_volume_from_snapshot:
self._flatten(self.configuration.rbd_pool, volume['name']) self._flatten(self.configuration.rbd_pool, volume.name)
if int(volume['size']): if int(volume.size):
self._resize(volume) self._resize(volume)
def _delete_backup_snaps(self, rbd_image): def _delete_backup_snaps(self, rbd_image):
@ -666,7 +666,7 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
"""Deletes a logical volume.""" """Deletes a logical volume."""
# NOTE(dosaboy): this was broken by commit cbe1d5f. Ensure names are # NOTE(dosaboy): this was broken by commit cbe1d5f. Ensure names are
# utf-8 otherwise librbd will barf. # utf-8 otherwise librbd will barf.
volume_name = utils.convert_str(volume['name']) volume_name = utils.convert_str(volume.name)
with RADOSClient(self) as client: with RADOSClient(self) as client:
try: try:
rbd_image = self.rbd.Image(client.ioctx, volume_name) rbd_image = self.rbd.Image(client.ioctx, volume_name)
@ -686,11 +686,11 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
try: try:
snaps = rbd_image.list_snaps() snaps = rbd_image.list_snaps()
for snap in snaps: for snap in snaps:
if snap['name'].endswith('.clone_snap'): if snap.name.endswith('.clone_snap'):
LOG.debug("volume has clone snapshot(s)") LOG.debug("volume has clone snapshot(s)")
# We grab one of these and use it when fetching parent # We grab one of these and use it when fetching parent
# info in case the volume has been flattened. # info in case the volume has been flattened.
clone_snap = snap['name'] clone_snap = snap.name
break break
raise exception.VolumeIsBusy(volume_name=volume_name) raise exception.VolumeIsBusy(volume_name=volume_name)
@ -739,8 +739,8 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
def create_snapshot(self, snapshot): def create_snapshot(self, snapshot):
"""Creates an rbd snapshot.""" """Creates an rbd snapshot."""
with RBDVolumeProxy(self, snapshot['volume_name']) as volume: with RBDVolumeProxy(self, snapshot.volume_name) as volume:
snap = utils.convert_str(snapshot['name']) snap = utils.convert_str(snapshot.name)
volume.create_snap(snap) volume.create_snap(snap)
volume.protect_snap(snap) volume.protect_snap(snap)
@ -748,8 +748,8 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
"""Deletes an rbd snapshot.""" """Deletes an rbd snapshot."""
# NOTE(dosaboy): this was broken by commit cbe1d5f. Ensure names are # NOTE(dosaboy): this was broken by commit cbe1d5f. Ensure names are
# utf-8 otherwise librbd will barf. # utf-8 otherwise librbd will barf.
volume_name = utils.convert_str(snapshot['volume_name']) volume_name = utils.convert_str(snapshot.volume_name)
snap_name = utils.convert_str(snapshot['name']) snap_name = utils.convert_str(snapshot.name)
with RBDVolumeProxy(self, volume_name) as volume: with RBDVolumeProxy(self, volume_name) as volume:
try: try:
@ -802,14 +802,14 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
'driver_volume_type': 'rbd', 'driver_volume_type': 'rbd',
'data': { 'data': {
'name': '%s/%s' % (self.configuration.rbd_pool, 'name': '%s/%s' % (self.configuration.rbd_pool,
volume['name']), volume.name),
'hosts': hosts, 'hosts': hosts,
'ports': ports, 'ports': ports,
'auth_enabled': (self.configuration.rbd_user is not None), 'auth_enabled': (self.configuration.rbd_user is not None),
'auth_username': self.configuration.rbd_user, 'auth_username': self.configuration.rbd_user,
'secret_type': 'ceph', 'secret_type': 'ceph',
'secret_uuid': self.configuration.rbd_secret_uuid, 'secret_uuid': self.configuration.rbd_secret_uuid,
'volume_id': volume['id'], 'volume_id': volume.id,
} }
} }
LOG.debug('connection data: %s', data) LOG.debug('connection data: %s', data)
@ -915,7 +915,7 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
image_utils.fetch_to_raw(context, image_service, image_id, image_utils.fetch_to_raw(context, image_service, image_id,
tmp.name, tmp.name,
self.configuration.volume_dd_blocksize, self.configuration.volume_dd_blocksize,
size=volume['size']) size=volume.size)
self.delete_volume(volume) self.delete_volume(volume)
@ -926,7 +926,7 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
args = ['rbd', 'import', args = ['rbd', 'import',
'--pool', self.configuration.rbd_pool, '--pool', self.configuration.rbd_pool,
'--order', order, '--order', order,
tmp.name, volume['name'], tmp.name, volume.name,
'--new-format'] '--new-format']
args.extend(self._ceph_args()) args.extend(self._ceph_args())
self._try_execute(*args) self._try_execute(*args)
@ -935,11 +935,11 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
def copy_volume_to_image(self, context, volume, image_service, image_meta): def copy_volume_to_image(self, context, volume, image_service, image_meta):
tmp_dir = self._image_conversion_dir() tmp_dir = self._image_conversion_dir()
tmp_file = os.path.join(tmp_dir, tmp_file = os.path.join(tmp_dir,
volume['name'] + '-' + image_meta['id']) volume.name + '-' + image_meta['id'])
with fileutils.remove_path_on_error(tmp_file): with fileutils.remove_path_on_error(tmp_file):
args = ['rbd', 'export', args = ['rbd', 'export',
'--pool', self.configuration.rbd_pool, '--pool', self.configuration.rbd_pool,
volume['name'], tmp_file] volume.name, tmp_file]
args.extend(self._ceph_args()) args.extend(self._ceph_args())
self._try_execute(*args) self._try_execute(*args)
image_utils.upload_volume(context, image_service, image_utils.upload_volume(context, image_service,
@ -948,9 +948,9 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
def backup_volume(self, context, backup, backup_service): def backup_volume(self, context, backup, backup_service):
"""Create a new backup from an existing volume.""" """Create a new backup from an existing volume."""
volume = self.db.volume_get(context, backup['volume_id']) volume = self.db.volume_get(context, backup.volume_id)
with RBDVolumeProxy(self, volume['name'], with RBDVolumeProxy(self, volume.name,
self.configuration.rbd_pool) as rbd_image: self.configuration.rbd_pool) as rbd_image:
rbd_meta = RBDImageMetadata(rbd_image, self.configuration.rbd_pool, rbd_meta = RBDImageMetadata(rbd_image, self.configuration.rbd_pool,
self.configuration.rbd_user, self.configuration.rbd_user,
@ -962,26 +962,26 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
def restore_backup(self, context, backup, volume, backup_service): def restore_backup(self, context, backup, volume, backup_service):
"""Restore an existing backup to a new or existing volume.""" """Restore an existing backup to a new or existing volume."""
with RBDVolumeProxy(self, volume['name'], with RBDVolumeProxy(self, volume.name,
self.configuration.rbd_pool) as rbd_image: self.configuration.rbd_pool) as rbd_image:
rbd_meta = RBDImageMetadata(rbd_image, self.configuration.rbd_pool, rbd_meta = RBDImageMetadata(rbd_image, self.configuration.rbd_pool,
self.configuration.rbd_user, self.configuration.rbd_user,
self.configuration.rbd_ceph_conf) self.configuration.rbd_ceph_conf)
rbd_fd = RBDImageIOWrapper(rbd_meta) rbd_fd = RBDImageIOWrapper(rbd_meta)
backup_service.restore(backup, volume['id'], rbd_fd) backup_service.restore(backup, volume.id, rbd_fd)
LOG.debug("volume restore complete.") LOG.debug("volume restore complete.")
def extend_volume(self, volume, new_size): def extend_volume(self, volume, new_size):
"""Extend an existing volume.""" """Extend an existing volume."""
old_size = volume['size'] old_size = volume.size
try: try:
size = int(new_size) * units.Gi size = int(new_size) * units.Gi
self._resize(volume, size=size) self._resize(volume, size=size)
except Exception: except Exception:
msg = _('Failed to Extend Volume ' msg = _('Failed to Extend Volume '
'%(volname)s') % {'volname': volume['name']} '%(volname)s') % {'volname': volume.name}
LOG.error(msg) LOG.error(msg)
raise exception.VolumeBackendAPIException(data=msg) raise exception.VolumeBackendAPIException(data=msg)
@ -1005,7 +1005,7 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
rbd_name = existing_ref['source-name'] rbd_name = existing_ref['source-name']
self.RBDProxy().rename(client.ioctx, self.RBDProxy().rename(client.ioctx,
utils.convert_str(rbd_name), utils.convert_str(rbd_name),
utils.convert_str(volume['name'])) utils.convert_str(volume.name))
def manage_existing_get_size(self, volume, existing_ref): def manage_existing_get_size(self, volume, existing_ref):
"""Return size of an existing image for manage_existing. """Return size of an existing image for manage_existing.
@ -1069,8 +1069,8 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
name_id = None name_id = None
provider_location = None provider_location = None
existing_name = CONF.volume_name_template % new_volume['id'] existing_name = CONF.volume_name_template % new_volume.id
wanted_name = CONF.volume_name_template % volume['id'] wanted_name = CONF.volume_name_template % volume.id
with RADOSClient(self) as client: with RADOSClient(self) as client:
try: try:
self.RBDProxy().rename(client.ioctx, self.RBDProxy().rename(client.ioctx,
@ -1078,11 +1078,11 @@ class RBDDriver(driver.TransferVD, driver.ExtendVD,
utils.convert_str(wanted_name)) utils.convert_str(wanted_name))
except self.rbd.ImageNotFound: except self.rbd.ImageNotFound:
LOG.error(_LE('Unable to rename the logical volume ' LOG.error(_LE('Unable to rename the logical volume '
'for volume %s.'), volume['id']) 'for volume %s.'), volume.id)
# If the rename fails, _name_id should be set to the new # If the rename fails, _name_id should be set to the new
# volume id and provider_location should be set to the # volume id and provider_location should be set to the
# one from the new volume as well. # one from the new volume as well.
name_id = new_volume['_name_id'] or new_volume['id'] name_id = new_volume._name_id or new_volume.id
provider_location = new_volume['provider_location'] provider_location = new_volume['provider_location']
return {'_name_id': name_id, 'provider_location': provider_location} return {'_name_id': name_id, 'provider_location': provider_location}