mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			151 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/python
 | |
| # Copyright (C) 2006-2007 XenSource Ltd.
 | |
| # Copyright (C) 2008-2009 Citrix Ltd.
 | |
| #
 | |
| # This program is free software; you can redistribute it and/or modify 
 | |
| # it under the terms of the GNU Lesser General Public License as published 
 | |
| # by the Free Software Foundation; version 2.1 only.
 | |
| #
 | |
| # This program is distributed in the hope that it will be useful, 
 | |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 | |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 | |
| # GNU Lesser General Public License for more details.
 | |
| #
 | |
| # nfs.py: NFS related utility functions
 | |
| 
 | |
| import util, errno, os, xml.dom.minidom
 | |
| 
 | |
| # The algorithm for tcp and udp (at least in the linux kernel) for 
 | |
| # NFS timeout on softmounts is as follows:
 | |
| #
 | |
| # UDP:
 | |
| # As long as the request wasn't started more than timeo * (2 ^ retrans) 
 | |
| # in the past, keep doubling the timeout.
 | |
| #
 | |
| # TCP:
 | |
| # As long as the request wasn't started more than timeo * (1 + retrans) 
 | |
| # in the past, keep increaing the timeout by timeo.
 | |
| #
 | |
| # 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
 | |
| #
 | |
| # thus for retrans=1, timeo can be the same for both tcp and udp, 
 | |
| # because the first doubling (timeo*2) is the same as the first increment
 | |
| # (timeo+timeo).
 | |
| 
 | |
| SOFTMOUNT_TIMEOUT  = int((40.0/3.0) * 10.0) # 1/10 s
 | |
| SOFTMOUNT_RETRANS  = 0x10
 | |
| 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" % (SOFTMOUNT_TIMEOUT,
 | |
|                                                SOFTMOUNT_RETRANS,
 | |
|                                                transport)
 | |
| 
 | |
|     # CA-27534: don't cache directory attributes.
 | |
|     # so slaves follow snapshot name flips consistently.
 | |
|     options += ',acdirmin=0,acdirmax=0'
 | |
| 
 | |
|     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()
 |