Properly quote IPv6 address in RsyncDriver

When IPv6 address literal is used as host in rsync call, it should be
enclosed in square brackets.  This is already done for copy_file method
outside of driver in changeset Ia5f28673e79158d948980f2b3ce496c6a56882af

Create helper function format_remote_path(host, path) and use where
appropriate.

Closes-Bug: 1601822
Change-Id: Ifc386539f33684fb764f5f638a7ee0a10b1ef534
(cherry picked from commit 270be6906c)
This commit is contained in:
Alexey I. Froloff 2016-07-11 16:31:09 +03:00
parent 67cfb16a4f
commit fe21d29fa8
4 changed files with 74 additions and 3 deletions

View File

@ -218,6 +218,19 @@ class GenericUtilsTestCase(test.NoDBTestCase):
"::ffff:127.0.0.1"))
self.assertEqual("localhost", utils.safe_ip_format("localhost"))
def test_format_remote_path(self):
self.assertEqual("[::1]:/foo/bar",
utils.format_remote_path("::1", "/foo/bar"))
self.assertEqual("127.0.0.1:/foo/bar",
utils.format_remote_path("127.0.0.1", "/foo/bar"))
self.assertEqual("[::ffff:127.0.0.1]:/foo/bar",
utils.format_remote_path("::ffff:127.0.0.1",
"/foo/bar"))
self.assertEqual("localhost:/foo/bar",
utils.format_remote_path("localhost", "/foo/bar"))
self.assertEqual("/foo/bar", utils.format_remote_path(None,
"/foo/bar"))
def test_get_hash_str(self):
base_str = b"foo"
base_unicode = u"foo"

View File

@ -193,3 +193,45 @@ class RemoteFSTestCase(test.NoDBTestCase):
'/home/favourite',
on_completion=None,
on_execute=None)
@mock.patch('tempfile.mkdtemp', return_value='/tmp/Saturn')
def test_rsync_driver_ipv6(self, mock_mkdtemp):
with mock.patch('nova.utils.execute') as mock_execute:
remotefs.RsyncDriver().create_file('2600::', 'dest_dir', None,
None)
rsync_call_args = mock.call('rsync', '--archive', '--relative',
'--no-implied-dirs',
'/tmp/Saturn/./dest_dir', '[2600::]:/',
on_completion=None, on_execute=None)
self.assertEqual(mock_execute.mock_calls[2], rsync_call_args)
with mock.patch('nova.utils.execute') as mock_execute:
remotefs.RsyncDriver().create_dir('2600::', 'dest_dir', None, None)
rsync_call_args = mock.call('rsync', '--archive', '--relative',
'--no-implied-dirs',
'/tmp/Saturn/./dest_dir', '[2600::]:/',
on_completion=None, on_execute=None)
self.assertEqual(mock_execute.mock_calls[1], rsync_call_args)
with mock.patch('nova.utils.execute') as mock_execute:
remotefs.RsyncDriver().remove_file('2600::', 'dest', None, None)
rsync_call_args = mock.call('rsync', '--archive',
'--delete', '--include',
'dest', '--exclude', '*',
'/tmp/Saturn/', '[2600::]:',
on_completion=None, on_execute=None)
self.assertEqual(mock_execute.mock_calls[0], rsync_call_args)
with mock.patch('nova.utils.execute') as mock_execute:
remotefs.RsyncDriver().remove_dir('2600::', 'dest', None, None)
rsync_call_args = mock.call('rsync', '--archive',
'--delete-excluded', '/tmp/Saturn/',
'[2600::]:dest',
on_completion=None, on_execute=None)
self.assertEqual(mock_execute.mock_calls[0], rsync_call_args)
rsync_call_args = mock.call('rsync', '--archive',
'--delete', '--include',
'dest', '--exclude', '*',
'/tmp/Saturn/', '[2600::]:',
on_completion=None, on_execute=None)
self.assertEqual(mock_execute.mock_calls[1], rsync_call_args)

View File

@ -697,6 +697,20 @@ def safe_ip_format(ip):
return ip
def format_remote_path(host, path):
"""Returns remote path in format acceptable for scp/rsync.
If host is IPv6 address literal, return '[host]:path', otherwise
'host:path' is returned.
If host is None, only path is returned.
"""
if host is None:
return path
return "%s:%s" % (safe_ip_format(host), path)
def monkey_patch():
"""If the CONF.monkey_patch set as True,
this function patches a decorator

View File

@ -277,7 +277,7 @@ class RsyncDriver(RemoteFilesystemDriver):
# Remove remote directory's content
utils.execute('rsync', '--archive', '--delete-excluded',
kwargs['tmp_dir_path'] + os.path.sep,
'%s:%s' % (host, dst),
utils.format_remote_path(host, dst),
on_execute=on_execute, on_completion=on_completion)
# Delete empty directory
@ -300,7 +300,8 @@ class RsyncDriver(RemoteFilesystemDriver):
'--include', os.path.basename(os.path.normpath(dst)),
'--exclude', '*',
os.path.normpath(src) + os.path.sep,
'%s:%s' % (host, os.path.dirname(os.path.normpath(dst))),
utils.format_remote_path(host,
os.path.dirname(os.path.normpath(dst))),
on_execute=on_execute, on_completion=on_completion)
@staticmethod
@ -329,7 +330,8 @@ class RsyncDriver(RemoteFilesystemDriver):
# Do relative rsync local directory with remote root directory
utils.execute('rsync', '--archive', '--relative', '--no-implied-dirs',
relative_tmp_file_path, '%s:%s' % (host, os.path.sep),
relative_tmp_file_path,
utils.format_remote_path(host, os.path.sep),
on_execute=on_execute, on_completion=on_completion)
def copy_file(self, src, dst, on_execute, on_completion, compression):