#!/usr/bin/python # Copyright 2012 Citrix Systems, Inc. Licensed under the # Apache License, Version 2.0 (the "License"); you may not use this # file except in compliance with the License. Citrix Systems, Inc. # reserves all rights not expressly granted by the License. # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Automatically generated by addcopyright.py at 04/03/2012 # nfs.py: NFS related utility functions import util, errno, os, xml.dom.minidom # NFS timeout on softmounts is as follows: # UDP: # As long as the request wasn't started more than timeo * (2 ^ retrans) # TCP: # As long as the request wasn't started more than timeo * (1 + retrans) # The time when the retrans may retry has been made will be: # For udp: timeo * (2 ^ retrans * 2 - 1) # For tcp: timeo * n! where n is the smallest n for which n! > 1 + retrans # (timeo+timeo). SOFTMOUNT_TIMEOUT = int((40.0/3.0) * 10.0) # 1/10 s SOFTMOUNT_RETRANS = 10 RPCINFO_BIN = "/usr/sbin/rpcinfo" SHOWMOUNT_BIN = "/usr/sbin/showmount" class NfsException(Exception): def __init__(self, errstr): self.errstr = errstr def check_server_tcp(server): """Make sure that NFS over TCP/IP V3 is supported on the server. Returns True if everything is OK, False otherwise.""" try: util.ioretry(lambda: util.pread([RPCINFO_BIN,"-t", "%s" % server, "nfs","3"]), errlist=[errno.EPERM], maxretry=2, nofail=True) except util.CommandException, inst: raise NfsException("rpcinfo failed or timed out: return code %d" % inst.code) def soft_mount(mountpoint, remoteserver, remotepath, transport): """Mount the remote NFS export at 'mountpoint'""" try: if not util.ioretry(lambda: util.isdir(mountpoint)): util.ioretry(lambda: util.makedirs(mountpoint)) except util.CommandException, inst: raise NfsException("Failed to make directory: code is %d" % inst.code) options = "soft,timeo=%d,retrans=%d,%s,noac" % (SOFTMOUNT_TIMEOUT, SOFTMOUNT_RETRANS, transport) try: util.ioretry(lambda: util.pread(["mount.nfs", "%s:%s" % (remoteserver, remotepath), mountpoint, "-o", options]), errlist=[errno.EPIPE, errno.EIO], maxretry=2, nofail=True) except util.CommandException, inst: raise NfsException("mount failed with return code %d" % inst.code) def unmount(mountpoint, rmmountpoint): """Unmount the mounted mountpoint""" try: util.pread(["umount", mountpoint]) except util.CommandException, inst: raise NfsException("umount failed with return code %d" % inst.code) if rmmountpoint: try: os.rmdir(mountpoint) except OSError, inst: raise NfsException("rmdir failed with error '%s'" % inst.strerror) def scan_exports(target): 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) (path, access) = val.split() 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) return dom def scan_srlist(path): dom = xml.dom.minidom.Document() element = dom.createElement("SRlist") dom.appendChild(element) for val in filter(util.match_uuid, util.ioretry( \ lambda: util.listdir(path))): fullpath = os.path.join(path, val) if not util.ioretry(lambda: util.isdir(fullpath)): continue entry = dom.createElement('SR') element.appendChild(entry) subentry = dom.createElement("UUID") entry.appendChild(subentry) textnode = dom.createTextNode(val) subentry.appendChild(textnode) return dom.toprettyxml()