From eaf153d1ade9af0c5fa52e4bf56fb182fad1edce Mon Sep 17 00:00:00 2001 From: Valeriy Ponomaryov Date: Wed, 14 Sep 2016 15:31:11 +0300 Subject: [PATCH] [ZFSonLinux] Fix share migration using remote host For the moment, share migration works only when manila-share and ZFS storage are located on the same host. So, fix it adding SSH command to migration command. Change-Id: I25f211de6a278c6f303ef3f33ff30f504146a0fa Closes-Bug: #1623379 --- manila/share/drivers/zfsonlinux/driver.py | 5 ++ .../share/drivers/zfsonlinux/test_driver.py | 54 +++++++++++++++---- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/manila/share/drivers/zfsonlinux/driver.py b/manila/share/drivers/zfsonlinux/driver.py index 3e14d3966b..47b1041d05 100644 --- a/manila/share/drivers/zfsonlinux/driver.py +++ b/manila/share/drivers/zfsonlinux/driver.py @@ -1380,6 +1380,10 @@ class ZFSonLinuxShareDriver(zfs_utils.ExecuteMixin, driver.ShareDriver): dst_dataset_name = self._get_dataset_name(destination_share) backend_name = share_utils.extract_host( destination_share['host'], level='backend_name') + ssh_cmd = '%(username)s@%(host)s' % { + 'username': self.configuration.zfs_ssh_username, + 'host': self.configuration.zfs_service_ip, + } config = get_backend_configuration(backend_name) remote_ssh_cmd = '%(username)s@%(host)s' % { 'username': config.zfs_ssh_username, @@ -1411,6 +1415,7 @@ class ZFSonLinuxShareDriver(zfs_utils.ExecuteMixin, driver.ShareDriver): # Send/receive temporary snapshot cmd = ( + 'ssh ' + ssh_cmd + ' ' 'sudo zfs send -vDR ' + src_snapshot_name + ' ' '| ssh ' + remote_ssh_cmd + ' ' 'sudo zfs receive -v ' + dst_dataset_name diff --git a/manila/tests/share/drivers/zfsonlinux/test_driver.py b/manila/tests/share/drivers/zfsonlinux/test_driver.py index 4dcee6ed21..82dfc7f54a 100644 --- a/manila/tests/share/drivers/zfsonlinux/test_driver.py +++ b/manila/tests/share/drivers/zfsonlinux/test_driver.py @@ -90,6 +90,15 @@ class FakeDriverPrivateStorage(object): self.storage.pop(entity_id, None) +class FakeTempDir(object): + + def __enter__(self, *args, **kwargs): + return '/foo/path' + + def __exit__(*args, **kwargs): + pass + + class GetBackendConfigurationTestCase(test.TestCase): def test_get_backend_configuration_success(self): @@ -2162,6 +2171,10 @@ class ZFSonLinuxShareDriverTestCase(test.TestCase): dst_backend_name) def test_migration_start(self): + username = self.driver.configuration.zfs_ssh_username + hostname = self.driver.configuration.zfs_service_ip + dst_username = username + '_dst' + dst_hostname = hostname + '_dst' src_share = { 'id': 'fake_src_share_id', 'host': 'foohost@foobackend#foopool', @@ -2186,16 +2199,19 @@ class ZFSonLinuxShareDriverTestCase(test.TestCase): 'get_backend_configuration', mock.Mock(return_value=type( 'FakeConfig', (object,), { - 'zfs_ssh_username': ( - self.driver.configuration.zfs_ssh_username), - 'zfs_service_ip': self.driver.configuration.zfs_service_ip, + 'zfs_ssh_username': dst_username, + 'zfs_service_ip': dst_hostname, }))) self.mock_object(self.driver, 'execute') - self.driver.private_storage.update( - src_share['id'], {'dataset_name': src_dataset_name}) - self.driver.migration_start( - self._context, src_share, dst_share) + self.mock_object( + zfs_driver.utils, 'tempdir', + mock.MagicMock(side_effect=FakeTempDir)) + + self.driver.private_storage.update( + src_share['id'], + {'dataset_name': src_dataset_name, + 'ssh_cmd': username + '@' + hostname}) src_snapshot_name = ( '%(dataset_name)s@%(snapshot_tag)s' % { @@ -2203,6 +2219,26 @@ class ZFSonLinuxShareDriverTestCase(test.TestCase): 'dataset_name': src_dataset_name, } ) + with mock.patch("six.moves.builtins.open", + mock.mock_open(read_data="data")) as mock_file: + self.driver.migration_start( + self._context, src_share, dst_share) + + expected_file_content = ( + 'ssh %(ssh_cmd)s sudo zfs send -vDR %(snap)s | ' + 'ssh %(dst_ssh_cmd)s sudo zfs receive -v %(dst_dataset)s' + ) % { + 'ssh_cmd': self.driver.private_storage.get( + src_share['id'], 'ssh_cmd'), + 'dst_ssh_cmd': self.driver.private_storage.get( + dst_share['id'], 'ssh_cmd'), + 'snap': src_snapshot_name, + 'dst_dataset': dst_dataset_name, + } + mock_file.assert_called_with("/foo/path/bar_dataset_name.sh", "w") + mock_file.return_value.write.assert_called_once_with( + expected_file_content) + self.driver.execute.assert_has_calls([ mock.call('sudo', 'zfs', 'snapshot', src_snapshot_name), mock.call('sudo', 'chmod', '755', mock.ANY), @@ -2215,9 +2251,7 @@ class ZFSonLinuxShareDriverTestCase(test.TestCase): for k, v in (('dataset_name', dst_dataset_name), ('migr_snapshot_tag', snapshot_tag), ('pool_name', 'barpool'), - ('ssh_cmd', - self.driver.configuration.zfs_ssh_username + '@' + - self.driver.configuration.zfs_service_ip)): + ('ssh_cmd', dst_username + '@' + dst_hostname)): self.assertEqual( v, self.driver.private_storage.get(dst_share['id'], k))