Skip to content

Commit eea1352

Browse files
benjamreisWescoeur
authored andcommitted
Backport probe for NFS4 when rpcinfo does not include it
See: xapi-project#655 Signed-off-by: Benjamin Reis <[email protected]>
1 parent fe5a7b3 commit eea1352

File tree

2 files changed

+60
-15
lines changed

2 files changed

+60
-15
lines changed

drivers/nfs.py

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,14 @@ def check_server_service(server, transport):
8383
NFS_SERVICE_RETRY * NFS_SERVICE_WAIT
8484
"""
8585

86-
sv = get_supported_nfs_versions(server, transport)
87-
# Services are not present in NFS4 only, this doesn't mean there's no NFS
88-
if sv == ['4']:
89-
return True
86+
try:
87+
sv = get_supported_nfs_versions(server, transport)
88+
# Services are not present in NFS4 only, this doesn't mean there's no NFS
89+
if "4" in sv:
90+
return True
91+
except NfsException:
92+
# Server failed to give us supported versions
93+
pass
9094

9195
retries = 0
9296
errlist = [errno.EPERM, errno.EPIPE, errno.EIO]
@@ -309,6 +313,9 @@ def scan_srlist(path, transport, dconf):
309313
def _get_supported_nfs_version_rpcinfo(server):
310314
""" Return list of supported nfs versions.
311315
Using NFS3 services.
316+
*Might* return "4" in the list of supported NFS versions, but might not:
317+
There is no requirement for NFS4 to register with rpcbind, even though it can, so
318+
a server which supports NFS4 might still only return ["3"] from here.
312319
"""
313320

314321
valid_versions = set(["3", "4"])
@@ -340,20 +347,27 @@ def _is_nfs4_supported(server, transport):
340347

341348

342349
def get_supported_nfs_versions(server, transport):
343-
"""Return list of supported nfs versions."""
350+
"""
351+
Return list of supported nfs versions.
352+
First check list from rpcinfo and if that does not contain NFS4, probe for it and
353+
add it to the list if available.
354+
"""
355+
vers = []
344356
try:
345-
return _get_supported_nfs_version_rpcinfo(server)
357+
vers = _get_supported_nfs_version_rpcinfo(server)
346358
except Exception:
347359
util.SMlog("Unable to obtain list of valid nfs versions with %s, trying NFSv4" % RPCINFO_BIN)
348360

349-
# NFSv4 only
350-
if _is_nfs4_supported(server, transport):
351-
return ["4"]
361+
# Test for NFS4 if the rpcinfo query did not find it (NFS4 does not *have* to register with rpcbind)
362+
if "4" not in vers:
363+
if _is_nfs4_supported(server, transport):
364+
vers.append("4")
365+
366+
if vers:
367+
return vers
352368
else:
353-
util.SMlog("Unable to obtain list of valid nfs versions with NFSv4 pseudo FS mount")
369+
raise NfsException("Failed to read supported NFS version from server %s" % (server))
354370

355-
raise NfsException("Failed to read supported NFS version from server %s" %
356-
(server))
357371

358372
def get_nfs_timeout(other_config):
359373
nfs_timeout = 200

tests/test_nfs.py

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ class Test_nfs(unittest.TestCase):
99

1010
@mock.patch('util.pread', autospec=True)
1111
def test_check_server_tcp(self, pread):
12+
pread.return_value = " 100003 4,3,2 udp6,tcp6,udp,tcp nfs superuser"
1213
nfs.check_server_tcp('aServer', 'tcp')
1314

1415
pread.assert_called_once_with(['/usr/sbin/rpcinfo', '-s', 'aServer'], quiet=False)
1516

1617
@mock.patch('util.pread', autospec=True)
1718
def test_check_server_tcp_nfsversion(self, pread):
19+
pread.return_value = " 100003 4,3,2 udp6,tcp6,udp,tcp nfs superuser"
1820
nfs.check_server_tcp('aServer', 'tcp', 'aNfsversion')
1921

2022
pread.assert_called_once_with(['/usr/sbin/rpcinfo', '-s', 'aServer'], quiet=False)
@@ -42,23 +44,28 @@ def test_check_server_service(self, pread, get_supported_nfs_versions, sleep):
4244
# Mock==1.0.1 (all that is available in Epel) doesn't suport this
4345
#sleep.assert_not_called()
4446

47+
@mock.patch('nfs._is_nfs4_supported', autospec=True)
4548
@mock.patch('time.sleep', autospec=True)
4649
# Can't use autospec due to http://bugs.python.org/issue17826
4750
@mock.patch('util.pread')
48-
def test_check_server_service_with_retries(self, pread, sleep):
51+
def test_check_server_service_with_retries(self, pread, sleep, nfs4sup):
4952
pread.side_effect=["",
5053
"",
51-
" 100003 4,3,2 udp6,tcp6,udp,tcp nfs superuser"]
54+
" 100003 3,2 udp6,tcp6,udp,tcp nfs superuser"]
55+
nfs4sup.return_value = False
56+
5257
service_found = nfs.check_server_service('aServer', 'tcp')
5358

5459
self.assertTrue(service_found)
5560
self.assertEqual(len(pread.mock_calls), 3)
5661
pread.assert_called_with(['/usr/sbin/rpcinfo', '-s', 'aServer'])
5762

63+
@mock.patch('nfs._is_nfs4_supported', autospec=True)
5864
@mock.patch('time.sleep', autospec=True)
5965
@mock.patch('util.pread', autospec=True)
60-
def test_check_server_service_not_available(self, pread, sleep):
66+
def test_check_server_service_not_available(self, pread, sleep, nfs4sup):
6167
pread.return_value=""
68+
nfs4sup.return_value = False
6269

6370
service_found = nfs.check_server_service('aServer', 'tcp')
6471

@@ -86,6 +93,30 @@ def test_check_server_service_first_call_exception(self, pread, get_supported_nf
8693
self.assertTrue(service_found)
8794
self.assertEqual(len(pread.mock_calls), 2)
8895

96+
@mock.patch('nfs._is_nfs4_supported', autospec=True)
97+
@mock.patch('util.pread2')
98+
def test_get_supported_nfs_versions_rpc_nov4(self, pread2, nfs4sup):
99+
pread2.side_effect = [" 100003 3,2 udp6,tcp6,udp,tcp nfs superuser"]
100+
nfs4sup.return_value = True
101+
102+
versions = nfs.get_supported_nfs_versions('aServer', 'tcp')
103+
104+
self.assertEqual(versions, ['3', '4'])
105+
self.assertEqual(len(pread2.mock_calls), 1)
106+
pread2.assert_called_with(['/usr/sbin/rpcinfo', '-s', 'aServer'])
107+
108+
@mock.patch('nfs._is_nfs4_supported', autospec=True)
109+
@mock.patch('util.pread2')
110+
def test_get_supported_nfs_versions_nov4(self, pread2, nfs4sup):
111+
pread2.side_effect = [" 100003 3,2 udp6,tcp6,udp,tcp nfs superuser"]
112+
nfs4sup.return_value = False
113+
114+
versions = nfs.get_supported_nfs_versions('aServer', 'tcp')
115+
116+
self.assertEqual(versions, ['3'])
117+
self.assertEqual(len(pread2.mock_calls), 1)
118+
pread2.assert_called_with(['/usr/sbin/rpcinfo', '-s', 'aServer'])
119+
89120
def get_soft_mount_pread(self, binary, vers):
90121
return ([binary, 'remoteserver:remotepath', 'mountpoint', '-o',
91122
'soft,proto=transport,vers=%s,acdirmin=0,acdirmax=0' % vers])

0 commit comments

Comments
 (0)