Skip to content

Commit

Permalink
Add version and exports
Browse files Browse the repository at this point in the history
Signed-off-by: BenjiReis <[email protected]>
  • Loading branch information
benjamreis committed May 3, 2023
1 parent f093ab0 commit e00c477
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 45 deletions.
8 changes: 4 additions & 4 deletions drivers/NFSSR.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,12 @@ def validate_remotepath(self, scan):

def check_server(self):
try:
if not nfs.is_nfs_4(self.nfsversion) and PROBEVERSION in self.dconf:
sv = nfs.get_supported_nfs_versions(self.remoteserver)
if PROBEVERSION in self.dconf:
sv = nfs.get_supported_nfs_versions(self.remoteserver, self.transport)
if len(sv):
self.nfsversion = sv[0]
else:
nfs.check_server_tcp(self.remoteserver, self.nfsversion)
nfs.check_server_tcp(self.remoteserver, self.transport, self.nfsversion)
except nfs.NfsException as exc:
raise xs_errors.XenError('NFSVersion',
opterr=exc.errstr)
Expand Down Expand Up @@ -250,7 +250,7 @@ def vdi(self, uuid, loadLocked=False):

def scan_exports(self, target):
util.SMlog("scanning2 (target=%s)" % target)
dom = nfs.scan_exports(target)
dom = nfs.scan_exports(target, self.transport)
print(dom.toprettyxml(), file=sys.stderr)

def set_transport(self):
Expand Down
133 changes: 92 additions & 41 deletions drivers/nfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@

RPCINFO_BIN = "/usr/sbin/rpcinfo"
SHOWMOUNT_BIN = "/usr/sbin/showmount"
NFS_STAT = "/usr/sbin/nfsstat"
LS = "/usr/bin/ls"

DEFAULT_NFSVERSION = '3'

Expand All @@ -50,41 +52,38 @@
NFS_SERVICE_WAIT = 30
NFS_SERVICE_RETRY = 6

NSFv4_PSEUDOFS = "/"
NFS4_TMP_MOUNTPOINT = "/tmp/mnt"

class NfsException(Exception):

def __init__(self, errstr):
self.errstr = errstr

def is_nfs_4(nfsversion):
return validate_nfsversion(nfsversion) and nfsversion != DEFAULT_NFSVERSION

def check_server_tcp(server, nfsversion=DEFAULT_NFSVERSION):
def check_server_tcp(server, transport, nfsversion=DEFAULT_NFSVERSION):
"""Make sure that NFS over TCP/IP V3 is supported on the server.
Returns True if everything is OK
False otherwise.
"""

if is_nfs_4(nfsversion):
return True

try:
sv = get_supported_nfs_versions(server)
sv = get_supported_nfs_versions(server, transport)
return (True if nfsversion in sv else False)
except util.CommandException as inst:
raise NfsException("rpcinfo failed or timed out: return code %d" %
inst.code)


def check_server_service(server, nfsversion=DEFAULT_NFSVERSION):
def check_server_service(server, transport):
"""Ensure NFS service is up and available on the remote server.
Returns False if fails to detect service after
NFS_SERVICE_RETRY * NFS_SERVICE_WAIT
"""

if is_nfs_4(nfsversion):
sv = get_supported_nfs_versions(server, transport)
if sv == ['4']:
return True

retries = 0
Expand Down Expand Up @@ -141,7 +140,7 @@ def soft_mount(mountpoint, remoteserver, remotepath, transport, useroptions='',

# Wait for NFS service to be available
try:
if not check_server_service(remoteserver, nfsversion):
if not check_server_service(remoteserver, transport):
raise util.CommandException(
code=errno.EOPNOTSUPP,
reason='No NFS service on server: `%s`' % remoteserver
Expand Down Expand Up @@ -195,38 +194,74 @@ def unmount(mountpoint, rmmountpoint):
raise NfsException("rmdir failed with error '%s'" % inst.strerror)


def scan_exports(target):
def scan_exports(target, transport):
"""Scan target and return an XML DOM with target, path and accesslist."""
util.SMlog("scanning")
cmd = [SHOWMOUNT_BIN, "--no-headers", "-e", target]
dom = xml.dom.minidom.Document()
element = dom.createElement("nfs-exports")
dom.appendChild(element)
for val in util.pread2(cmd).split('\n'):
if not len(val):
continue
entry = dom.createElement('Export')
element.appendChild(entry)

subentry = dom.createElement("Target")
entry.appendChild(subentry)
textnode = dom.createTextNode(target)
subentry.appendChild(textnode)

# Access is not always provided by showmount return
# If none is provided we need to assume "*"
array = val.split()
path = array[0]
access = array[1] if len(array) >= 2 else "*"
subentry = dom.createElement("Path")
entry.appendChild(subentry)
textnode = dom.createTextNode(path)
subentry.appendChild(textnode)
fail = True
try:
cmd = [SHOWMOUNT_BIN, "--no-headers", "-e", target]
for val in util.pread2(cmd).split('\n'):
if not len(val):
continue
entry = dom.createElement('Export')
element.appendChild(entry)

subentry = dom.createElement("Target")
entry.appendChild(subentry)
textnode = dom.createTextNode(target)
subentry.appendChild(textnode)

# Access is not always provided by showmount return
# If none is provided we need to assume "*"
array = val.split()
path = array[0]
access = array[1] if len(array) >= 2 else "*"
subentry = dom.createElement("Path")
entry.appendChild(subentry)
textnode = dom.createTextNode(path)
subentry.appendChild(textnode)

subentry = dom.createElement("Accesslist")
entry.appendChild(subentry)
textnode = dom.createTextNode(access)
subentry.appendChild(textnode)
fail = False
except Exception:
util.SMlog("Unable to scan exports with rpcingo, trying NFSv4")

subentry = dom.createElement("Accesslist")
entry.appendChild(subentry)
textnode = dom.createTextNode(access)
subentry.appendChild(textnode)
try:
mountpoint = "%s/%s" % NFS4_TMP_MOUNTPOINT, target
soft_mount(mountpoint, target, NSFv4_PSEUDOFS, transport, nfsversion='4')
paths = util.pread2([LS])
unmount(mountpoint, NSFv4_PSEUDOFS)
for path in paths.split("\n"):
entry = dom.createElement('Export')
element.appendChild(entry)

subentry = dom.createElement("Target")
entry.appendChild(subentry)
textnode = dom.createTextNode(target)
subentry.appendChild(textnode)
subentry = dom.createElement("Path")
entry.appendChild(subentry)
textnode = dom.createTextNode(path)
subentry.appendChild(textnode)

subentry = dom.createElement("Accesslist")
entry.appendChild(subentry)
# Assume everyone as we do not have any info about it
textnode = dom.createTextNode("*")
subentry.appendChild(textnode)
fail = False
except Exception:
util.SMlog("Unable to scan exports with NFSv4 pseudo FS mount")

if fail:
raise NfsException('Failed to read NFS export paths from server %s' %
(target))

return dom

Expand Down Expand Up @@ -270,10 +305,11 @@ def scan_srlist(path, dconf):
return dom.toprettyxml()


def get_supported_nfs_versions(server):
def get_supported_nfs_versions(server, transport):
"""Return list of supported nfs versions."""
valid_versions = set(['3', '4'])
cv = set()
res = None
try:
ns = util.pread2([RPCINFO_BIN, "-s", "%s" % server])
ns = ns.split("\n")
Expand All @@ -282,11 +318,26 @@ def get_supported_nfs_versions(server):
cvi = ns[i].split()[1].split(",")
for j in range(len(cvi)):
cv.add(cvi[j])
return sorted(cv & valid_versions)
except:
util.SMlog("Unable to obtain list of valid nfs versions")
res = sorted(cv & valid_versions)
except Exception:
util.SMlog("Unable to obtain list of valid nfs versions with rpcinfo, trying NSFv4")

try:
mountpoint = "%s/%s" % NFS4_TMP_MOUNTPOINT, server
soft_mount(mountpoint, server, NSFv4_PSEUDOFS, transport, nfsversion='4')
util.pread2([NFS_STAT, '-m'])
unmount(mountpoint, NSFv4_PSEUDOFS)
if res is None:
res = ['4']
else:
res.add('4')
except Exception:
util.SMlog("Unable to obtain list of valid nfs versions with NSFv4 pseudo FS mount")

if res is None:
raise NfsException('Failed to read supported NFS version from server %s' %
(server))
return res


def get_nfs_timeout(other_config):
Expand Down

0 comments on commit e00c477

Please sign in to comment.