From: Anton Frolov Date: Tue, 28 May 2013 15:34:41 +0000 (+0400) Subject: Support for NFS shares with spaces in path. X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=924640705c05ba69e2ad2095920fc1d209d32b20;p=openstack-build%2Fcinder-build.git 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 --- diff --git a/cinder/tests/test_nfs.py b/cinder/tests/test_nfs.py index 3f967c6f2..b75319d4a 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 @@ class NfsDriverTestCase(test.TestCase): 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 @@ class NfsDriverTestCase(test.TestCase): 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 @@ class NfsDriverTestCase(test.TestCase): 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 a162a7d25..b6909168c 100644 --- a/cinder/volume/drivers/nfs.py +++ b/cinder/volume/drivers/nfs.py @@ -152,7 +152,7 @@ class RemoteFsDriver(driver.VolumeDriver): # 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 @@ class NfsDriver(RemoteFsDriver): """ 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)