Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
306 changes: 306 additions & 0 deletions cinder/tests/unit/test_sheepdog.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from cinder import utils
from cinder.volume import configuration as conf
from cinder.volume.drivers import sheepdog
from cinder.volume import utils as volutils

SHEEP_ADDR = '127.0.0.1'
SHEEP_PORT = 7000
Expand Down Expand Up @@ -105,6 +106,10 @@ def cmd_dog_vdi_resize(self, name, size):
return ('env', 'LC_ALL=C', 'LANG=C', 'dog', 'vdi', 'resize', name,
size, '-a', SHEEP_ADDR, '-p', SHEEP_PORT)

def cmd_dog_vdi_list(self, vdiname):
return ('env', 'LC_ALL=C', 'LANG=C', 'dog', 'vdi', 'list', vdiname,
'-a', SHEEP_ADDR, '-p', SHEEP_PORT)

CMD_DOG_CLUSTER_INFO = ('env', 'LC_ALL=C', 'LANG=C', 'dog', 'cluster',
'info', '-a', SHEEP_ADDR, '-p', SHEEP_PORT)

Expand Down Expand Up @@ -173,6 +178,11 @@ def cmd_dog_vdi_resize(self, name, size):
'QoS_support': False,
}

TEST_EXISTING_REF = {
'source-name': 'test-vdi',
'source-id': '',
}

COLLIE_CLUSTER_INFO_0_5 = """\
Cluster status: running

Expand Down Expand Up @@ -260,6 +270,27 @@ def cmd_dog_vdi_resize(self, name, size):

DOG_NODE_INFO_ERROR_GET_NO_NODE_INFO = """\
Cannot get information from any nodes
"""

DOG_VDI_LIST = """\
= test-vdi 0 10737418240 0 0 1442379755 7be7f9 3
"""

DOG_VDI_LIST_WITH_SNAPSHOT = """\
s test-vdi 1 10737418240 0 0 1442379755 7be7f9 3
= test-vdi 0 16106127360 0 0 1442381817 7be7fb 3
"""

DOG_VDI_LIST_CLONE = """\
c test-clone 0 10737418240 0 0 1442381753 ce8575 3
"""

DOG_VDI_LIST_SIZE_10G_MORE_1 = """\
= test-vdi 0 10737418241 0 0 1442379755 7be7f9 3
"""

DOG_VDI_LIST_SIZE_11G_LESS_1 = """\
= test-vdi 0 11811160063 0 0 1442379755 7be7f9 3
"""

DOG_COMMAND_ERROR_VDI_NOT_EXISTS = """\
Expand Down Expand Up @@ -971,6 +1002,17 @@ def test_clone_success(self, fake_execute):
self.client.clone(*args)
fake_execute.assert_called_once_with(*expected_cmd)

@mock.patch.object(sheepdog.SheepdogClient, '_run_qemu_img')
def test_clone_success_without_size(self, fake_execute):
args = (self._src_vdiname, self._snapname, self._dst_vdiname)
src_volume = 'sheepdog:%(src_vdiname)s:%(snapname)s' % {
'src_vdiname': self._src_vdiname, 'snapname': self._snapname}
dst_volume = 'sheepdog:%s' % self._dst_vdiname
expected_cmd = ('create', '-b', src_volume, dst_volume)
fake_execute.return_code = ("", "")
self.client.clone(*args)
fake_execute.assert_called_once_with(*expected_cmd)

@mock.patch.object(sheepdog.SheepdogClient, '_run_qemu_img')
@mock.patch.object(sheepdog, 'LOG')
def test_clone_fail_to_connect(self, fake_logger, fake_execute):
Expand Down Expand Up @@ -1603,6 +1645,169 @@ def test_get_disk_capacity_parse_stdout_error(self, fake_logger,
self.assertRaises(AttributeError, self.client.get_disk_capacity)
self.assertTrue(fake_logger.exception.called)

@mock.patch.object(sheepdog.SheepdogClient, '_run_dog')
def test_get_vdi_size_success(self, fake_execute):
expected_cmd = ('vdi', 'list', '-r', self._vdiname)
fake_execute.return_value = (self.test_data.DOG_VDI_LIST, '')

actual = self.client.get_vdi_size(self._vdiname)
fake_execute.assert_called_once_with(*expected_cmd)
self.assertEqual(10, actual)

@mock.patch.object(sheepdog.SheepdogClient, '_run_dog')
def test_get_vdi_size_with_snapshot_success(self, fake_execute):
expected_cmd = ('vdi', 'list', '-r', self._vdiname)
fake_execute.return_value = (self.test_data.DOG_VDI_LIST_WITH_SNAPSHOT,
'')
actual = self.client.get_vdi_size(self._vdiname)
fake_execute.assert_called_once_with(*expected_cmd)
self.assertEqual(15, actual)

@mock.patch.object(sheepdog.SheepdogClient, '_run_dog')
def test_get_vdi_size_clone_success(self, fake_execute):
expected_cmd = ('vdi', 'list', '-r', self._vdiname)
fake_execute.return_value = (self.test_data.DOG_VDI_LIST_CLONE, '')

actual = self.client.get_vdi_size(self._vdiname)
fake_execute.assert_called_once_with(*expected_cmd)
self.assertEqual(10, actual)

@mock.patch.object(sheepdog.SheepdogClient, '_run_dog')
def test_get_vdi_size_round_up_1_success(self, fake_execute):
expected_cmd = ('vdi', 'list', '-r', self._vdiname)
fake_execute.return_value = (
self.test_data.DOG_VDI_LIST_SIZE_10G_MORE_1, '')

actual = self.client.get_vdi_size(self._vdiname)
fake_execute.assert_called_once_with(*expected_cmd)
self.assertEqual(11, actual)

@mock.patch.object(sheepdog.SheepdogClient, '_run_dog')
def test_get_vdi_size_round_up_2_success(self, fake_execute):
expected_cmd = ('vdi', 'list', '-r', self._vdiname)
fake_execute.return_value = (
self.test_data.DOG_VDI_LIST_SIZE_11G_LESS_1, '')

actual = self.client.get_vdi_size(self._vdiname)
fake_execute.assert_called_once_with(*expected_cmd)
self.assertEqual(11, actual)

@mock.patch.object(sheepdog.SheepdogClient, '_run_dog')
def test_get_vdi_size_not_found_error(self, fake_execute):
stdout = ''
stderr = ''
fake_execute.return_value = (stdout, stderr)

self.assertRaises(exception.NotFound, self.client.get_vdi_size,
self._vdiname)

@mock.patch.object(sheepdog.SheepdogClient, '_run_dog')
@mock.patch.object(sheepdog, 'LOG')
def test_get_vdi_size_stdout_parse_error(self, fake_logger, fake_execute):
stdout = 'dummy'
stderr = ''
fake_execute.return_value = (stdout, stderr)

self.assertRaises(IndexError, self.client.get_vdi_size, self._vdiname)
self.assertTrue(fake_logger.exception.called)

@mock.patch.object(sheepdog.SheepdogClient, '_run_dog')
@mock.patch.object(sheepdog, 'LOG')
def test_get_vdi_size_failed_to_connect(self, fake_logger, fake_execute):
cmd = self.test_data.cmd_dog_vdi_list(self._vdiname)
exit_code = 2
stdout = 'stdout_dummy'
stderr = self.test_data.DOG_COMMAND_ERROR_FAIL_TO_CONNECT
expected_msg = self.test_data.sheepdog_cmd_error(cmd=cmd,
exit_code=exit_code,
stdout=stdout,
stderr=stderr)
fake_execute.side_effect = exception.SheepdogCmdError(
cmd=cmd, exit_code=exit_code, stdout=stdout.replace('\n', '\\n'),
stderr=stderr.replace('\n', '\\n'))

ex = self.assertRaises(exception.SheepdogCmdError,
self.client.get_vdi_size, self._vdiname)
self.assertTrue(fake_logger.exception.called)
self.assertEqual(expected_msg, ex.msg)

@mock.patch.object(sheepdog.SheepdogClient, '_run_dog')
@mock.patch.object(sheepdog, 'LOG')
def test_get_vdi_size_unknown_error(self, fake_logger, fake_execute):
cmd = self.test_data.cmd_dog_vdi_list(self._vdiname)
exit_code = 2
stdout = 'stdout_dummy'
stderr = 'unknown'
expected_msg = self.test_data.sheepdog_cmd_error(cmd=cmd,
exit_code=exit_code,
stdout=stdout,
stderr=stderr)
fake_execute.side_effect = exception.SheepdogCmdError(
cmd=cmd, exit_code=exit_code,
stdout=stdout.replace('\n', '\\n'),
stderr=stderr.replace('\n', '\\n'))

ex = self.assertRaises(exception.SheepdogCmdError,
self.client.get_vdi_size, self._vdiname)
self.assertTrue(fake_logger.exception.called)
self.assertEqual(expected_msg, ex.msg)

@mock.patch.object(sheepdog.SheepdogClient, 'delete')
@mock.patch.object(sheepdog.SheepdogClient, 'delete_snapshot')
@mock.patch.object(sheepdog.SheepdogClient, 'clone')
@mock.patch.object(sheepdog.SheepdogClient, 'create_snapshot')
def test_rename_success(self, fake_create_snapshot, fake_clone,
fake_delete_snapshot, fake_delete):
old_vdi_name = self._vdiname
new_vdi_name = self.test_data.TEST_EXISTING_REF['source-name']
snapshot_name = 'temp-rename-snapshot-' + old_vdi_name

self.client.rename(old_vdi_name, new_vdi_name)
fake_create_snapshot.assert_called_once_with(old_vdi_name,
snapshot_name)
fake_clone.assert_called_once_with(old_vdi_name, snapshot_name,
new_vdi_name)
fake_delete_snapshot.assert_called_once_with(old_vdi_name,
snapshot_name)
fake_delete.assert_called_once_with(old_vdi_name)

@mock.patch.object(sheepdog.SheepdogClient, 'delete')
@mock.patch.object(sheepdog.SheepdogClient, 'delete_snapshot')
@mock.patch.object(sheepdog.SheepdogClient, 'clone')
@mock.patch.object(sheepdog.SheepdogClient, 'create_snapshot')
@mock.patch.object(sheepdog, 'LOG')
def test_rename_failed_create_snapshot(self, fake_logger,
fake_create_snapshot, fake_clone,
fake_delete_snapshot, fake_delete):
old_vdi_name = self._vdiname
new_vdi_name = self.test_data.TEST_EXISTING_REF['source-name']
fake_create_snapshot.side_effect = exception.SheepdogCmdError(
cmd='dummy', exit_code=1, stdout='out dummy', stderr='err dummy')

self.assertRaises(exception.SheepdogCmdError,
self.client.rename, old_vdi_name, new_vdi_name)
self.assertTrue(fake_logger.error.called)

@mock.patch.object(sheepdog.SheepdogClient, 'delete')
@mock.patch.object(sheepdog.SheepdogClient, 'delete_snapshot')
@mock.patch.object(sheepdog.SheepdogClient, 'clone')
@mock.patch.object(sheepdog.SheepdogClient, 'create_snapshot')
@mock.patch.object(sheepdog, 'LOG')
def test_rename_failed_clone(self, fake_logger, fake_create_snapshot,
fake_clone, fake_delete_snapshot,
fake_delete):
old_vdi_name = self._vdiname
new_vdi_name = self.test_data.TEST_EXISTING_REF['source-name']
snapshot_name = 'temp-rename-snapshot-' + old_vdi_name
fake_clone.side_effect = exception.SheepdogCmdError(
cmd='dummy', exit_code=1, stdout='out dummy', stderr='err dummy')

self.assertRaises(exception.SheepdogCmdError,
self.client.rename, old_vdi_name, new_vdi_name)
fake_delete_snapshot.assert_called_once_with(old_vdi_name,
snapshot_name)
self.assertTrue(fake_logger.error.called)


class SheepdogDriverTestCase(test.TestCase):
def setUp(self):
Expand Down Expand Up @@ -2014,3 +2219,104 @@ def test_restore_backup(self, fake_backup_service):
self.assertEqual(fake_backup, call_backup)
self.assertEqual(fake_volume.id, call_volume_id)
self.assertIsInstance(call_sheepdog_fd, sheepdog.SheepdogIOWrapper)

@mock.patch.object(sheepdog.SheepdogClient, 'rename')
@mock.patch.object(volutils, 'check_already_managed_volume')
def test_manage_existing_success(self, fake_check_already_managed_volume,
fake_rename):
fake_volume = self.test_data.TEST_VOLUME
fake_ref = self.test_data.TEST_EXISTING_REF
fake_check_already_managed_volume.return_value = False

self.driver.manage_existing(fake_volume, fake_ref)
fake_check_already_managed_volume.assert_called_once_with(
self.db, fake_ref['source-name'])
fake_rename.assert_called_once_with(fake_ref['source-name'],
fake_volume.name)

@mock.patch.object(sheepdog.SheepdogClient, 'rename')
@mock.patch.object(volutils, 'check_already_managed_volume')
def test_manage_existing_fail_already_managed_volume(
self, fake_check_already_managed_volume, fake_rename):
fake_volume = self.test_data.TEST_VOLUME
fake_ref = self.test_data.TEST_EXISTING_REF
fake_check_already_managed_volume.return_value = True
self.assertRaises(exception.ManageExistingAlreadyManaged,
self.driver.manage_existing,
fake_volume, fake_ref)

@mock.patch.object(sheepdog.SheepdogClient, 'rename')
@mock.patch.object(volutils, 'check_already_managed_volume')
@mock.patch.object(sheepdog, 'LOG')
def test_manage_existing_fail_rename(self, fake_logger,
fake_check_already_managed_volume,
fake_rename):
fake_volume = self.test_data.TEST_VOLUME
fake_ref = self.test_data.TEST_EXISTING_REF
fake_check_already_managed_volume.return_value = False
fake_rename.side_effect = exception.SheepdogCmdError(
cmd='dummy', exit_code=1, stdout='dummy', stderr='dummy')

self.assertRaises(exception.SheepdogCmdError,
self.driver.manage_existing, fake_volume, fake_ref)
self.assertTrue(fake_logger.exception.called)
self.assertTrue(fake_check_already_managed_volume.called)
self.assertTrue(fake_rename.called)

@mock.patch.object(sheepdog.SheepdogClient, 'get_vdi_size')
def test_manage_existing_get_size_success(self, fake_get_vdi_size):
fake_get_vdi_size.return_value = 10
fake_ref = self.test_data.TEST_EXISTING_REF

size = self.driver.manage_existing_get_size(self.test_data.TEST_VOLUME,
fake_ref)
fake_get_vdi_size.assert_called_once_with(fake_ref['source-name'])
self.assertEqual(10, size)

@mock.patch.object(sheepdog.SheepdogClient, 'get_vdi_size')
def test_manage_existing_get_size_sourcename_key_empty(
self, fake_get_vdi_size):
fake_ref = {'source-id': ''}

self.assertRaises(exception.ManageExistingInvalidReference,
self.driver.manage_existing_get_size,
self.test_data.TEST_VOLUME, fake_ref)

@mock.patch.object(sheepdog.SheepdogClient, 'get_vdi_size')
def test_manage_existing_get_size_sourcename_value_empty(
self, fake_get_vdi_size):
fake_ref = {'source-name': '', 'source-id': ''}

self.assertRaises(exception.ManageExistingInvalidReference,
self.driver.manage_existing_get_size,
self.test_data.TEST_VOLUME, fake_ref)

@mock.patch.object(sheepdog.SheepdogClient, 'get_vdi_size')
def test_manage_existing_get_size_vdi_not_found(
self, fake_get_vdi_size):
fake_get_vdi_size.side_effect = exception.NotFound()

self.assertRaises(exception.ManageExistingInvalidReference,
self.driver.manage_existing_get_size,
self.test_data.TEST_VOLUME,
self.test_data.TEST_EXISTING_REF)

@mock.patch.object(sheepdog.SheepdogClient, 'rename')
def test_unmanage_success(self, fake_rename):
fake_volume = self.test_data.TEST_VOLUME
new_volume_name = fake_volume.name + '-unmanaged'

self.driver.unmanage(fake_volume)
fake_rename.assert_called_once_with(fake_volume.name, new_volume_name)

@mock.patch.object(sheepdog.SheepdogClient, 'rename')
@mock.patch.object(sheepdog, 'LOG')
def test_unmanage_fail_rename(self, fake_logger, fake_rename):
fake_volume = self.test_data.TEST_VOLUME
fake_rename.side_effect = exception.SheepdogCmdError(
cmd='dummy', exit_code=1, stdout='dummy', stderr='dummy')

self.assertRaises(exception.SheepdogCmdError, self.driver.unmanage,
fake_volume)
self.assertTrue(fake_logger.exception.called)
self.assertTrue(fake_rename.called)
Loading