From 924640705c05ba69e2ad2095920fc1d209d32b20 Mon Sep 17 00:00:00 2001 From: Anton Frolov Date: Tue, 28 May 2013 19:34:41 +0400 Subject: [PATCH] Support for NFS shares with spaces in path. Unescape share address string listed in nfs_shares_config so that 'x.y.z.w:/foo\040bar' would become 'x.y.z.w:/foo bar' to support mounting shares with spaces in name. Use stat command to get available and total space on device instead of df since it's output is easier to parse. Fixes: bug #1180984 Change-Id: I552aba91ca8db14130f854c739594a818186bbe2 --- cinder/tests/test_nfs.py | 51 +++++++++++++++++++++++++++++------- cinder/volume/drivers/nfs.py | 10 +++---- 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/cinder/tests/test_nfs.py b/cinder/tests/test_nfs.py index 3f967c6f2eb..b75319d4aba 100644 --- a/cinder/tests/test_nfs.py +++ b/cinder/tests/test_nfs.py @@ -115,6 +115,8 @@ class NfsDriverTestCase(test.TestCase): TEST_LOCAL_PATH = '/mnt/nfs/volume-123' TEST_FILE_NAME = 'test.txt' TEST_SHARES_CONFIG_FILE = '/etc/cinder/test-shares.conf' + TEST_NFS_EXPORT_SPACES = 'nfs-host3:/export this' + TEST_MNT_POINT_SPACES = '/ 0 0 0 /foo' def setUp(self): super(NfsDriverTestCase, self).setUp() @@ -261,12 +263,9 @@ def test_get_capacity_info(self): mox = self._mox drv = self._driver - df_total_size = 2620544 - df_avail = 2129984 - df_head = 'Filesystem 1K-blocks Used Available Use% Mounted on\n' - df_data = 'nfs-host:/export %d 996864 %d 41%% /mnt' % (df_total_size, - df_avail) - df_output = df_head + df_data + stat_total_size = 2620544 + stat_avail = 2129984 + stat_output = '1 %d %d' % (stat_total_size, stat_avail) du_used = 490560 du_output = '%d /mnt' % du_used @@ -276,8 +275,9 @@ def test_get_capacity_info(self): AndReturn(self.TEST_MNT_POINT) mox.StubOutWithMock(drv, '_execute') - drv._execute('df', '-P', '-B', '1', self.TEST_MNT_POINT, - run_as_root=True).AndReturn((df_output, None)) + drv._execute('stat', '-f', '-c', '%S %b %a', + self.TEST_MNT_POINT, + run_as_root=True).AndReturn((stat_output, None)) drv._execute('du', '-sb', '--apparent-size', '--exclude', '*snapshot*', @@ -286,11 +286,44 @@ def test_get_capacity_info(self): mox.ReplayAll() - self.assertEquals((df_total_size, df_avail, du_used), + self.assertEquals((stat_total_size, stat_avail, du_used), drv._get_capacity_info(self.TEST_NFS_EXPORT1)) mox.VerifyAll() + def test_get_capacity_info_for_share_and_mount_point_with_spaces(self): + """_get_capacity_info should calculate correct value.""" + mox = self._mox + drv = self._driver + + stat_total_size = 2620544 + stat_avail = 2129984 + stat_output = '1 %d %d' % (stat_total_size, stat_avail) + + du_used = 490560 + du_output = '%d /mnt' % du_used + + mox.StubOutWithMock(drv, '_get_mount_point_for_share') + drv._get_mount_point_for_share(self.TEST_NFS_EXPORT_SPACES).\ + AndReturn(self.TEST_MNT_POINT_SPACES) + + mox.StubOutWithMock(drv, '_execute') + drv._execute('stat', '-f', '-c', '%S %b %a', + self.TEST_MNT_POINT_SPACES, + run_as_root=True).AndReturn((stat_output, None)) + + drv._execute('du', '-sb', '--apparent-size', + '--exclude', '*snapshot*', + self.TEST_MNT_POINT_SPACES, + run_as_root=True).AndReturn((du_output, None)) + + mox.ReplayAll() + + self.assertEquals((stat_total_size, stat_avail, du_used), + drv._get_capacity_info(self.TEST_NFS_EXPORT_SPACES)) + + mox.VerifyAll() + def test_load_shares_config(self): mox = self._mox drv = self._driver diff --git a/cinder/volume/drivers/nfs.py b/cinder/volume/drivers/nfs.py index a162a7d256f..b6909168c34 100644 --- a/cinder/volume/drivers/nfs.py +++ b/cinder/volume/drivers/nfs.py @@ -152,7 +152,7 @@ def _load_shares_config(self, share_file): # results in share_info = # [ 'address:/vol', '-o options=123,rw --other' ] - share_address = share_info[0].strip() + share_address = share_info[0].strip().decode('unicode_escape') share_opts = share_info[1].strip() if len(share_info) > 1 else None self.shares[share_address] = share_opts @@ -384,11 +384,11 @@ def _get_capacity_info(self, nfs_share): """ mount_point = self._get_mount_point_for_share(nfs_share) - df, _ = self._execute('df', '-P', '-B', '1', mount_point, + df, _ = self._execute('stat', '-f', '-c', '%S %b %a', mount_point, run_as_root=True) - df = df.splitlines()[1] - total_available = float(df.split()[3]) - total_size = float(df.split()[1]) + block_size, blocks_total, blocks_avail = map(float, df.split()) + total_available = block_size * blocks_avail + total_size = block_size * blocks_total du, _ = self._execute('du', '-sb', '--apparent-size', '--exclude', '*snapshot*', mount_point, run_as_root=True)