mirror of https://github.com/apache/cloudstack.git
add XenServer 5.6 FP1 support
This commit is contained in:
parent
d4cc53cda2
commit
d83bf43f0d
|
|
@ -0,0 +1,256 @@
|
|||
#!/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.
|
||||
#
|
||||
# FileSR: local-file storage repository
|
||||
|
||||
import SR, VDI, SRCommand, FileSR, util
|
||||
import errno
|
||||
import os, re, sys
|
||||
import time
|
||||
import xml.dom.minidom
|
||||
import xs_errors
|
||||
import nfs
|
||||
import vhdutil
|
||||
from lock import Lock
|
||||
import cleanup
|
||||
|
||||
CAPABILITIES = ["SR_PROBE","SR_UPDATE", "SR_CACHING", \
|
||||
"VDI_CREATE","VDI_DELETE","VDI_ATTACH","VDI_DETACH", \
|
||||
"VDI_UPDATE", "VDI_CLONE","VDI_SNAPSHOT","VDI_RESIZE", \
|
||||
"VDI_RESIZE_ONLINE", "VDI_RESET_ON_BOOT", "ATOMIC_PAUSE"]
|
||||
|
||||
CONFIGURATION = [ [ 'server', 'hostname or IP address of NFS server (required)' ], \
|
||||
[ 'serverpath', 'path on remote server (required)' ] ]
|
||||
|
||||
|
||||
DRIVER_INFO = {
|
||||
'name': 'NFS VHD',
|
||||
'description': 'SR plugin which stores disks as VHD files on a remote NFS filesystem',
|
||||
'vendor': 'Citrix Systems Inc',
|
||||
'copyright': '(C) 2008 Citrix Systems Inc',
|
||||
'driver_version': '1.0',
|
||||
'required_api_version': '1.0',
|
||||
'capabilities': CAPABILITIES,
|
||||
'configuration': CONFIGURATION
|
||||
}
|
||||
|
||||
|
||||
# The mountpoint for the directory when performing an sr_probe. All probes
|
||||
# are guaranteed to be serialised by xapi, so this single mountpoint is fine.
|
||||
PROBE_MOUNTPOINT = "probe"
|
||||
NFSPORT = 2049
|
||||
DEFAULT_TRANSPORT = "tcp"
|
||||
|
||||
|
||||
class NFSSR(FileSR.FileSR):
|
||||
"""NFS file-based storage repository"""
|
||||
def handles(type):
|
||||
return type == 'nfs'
|
||||
handles = staticmethod(handles)
|
||||
|
||||
|
||||
def load(self, sr_uuid):
|
||||
self.ops_exclusive = FileSR.OPS_EXCLUSIVE
|
||||
self.lock = Lock(vhdutil.LOCK_TYPE_SR, self.uuid)
|
||||
self.sr_vditype = SR.DEFAULT_TAP
|
||||
if not self.dconf.has_key('server'):
|
||||
raise xs_errors.XenError('ConfigServerMissing')
|
||||
self.remoteserver = self.dconf['server']
|
||||
self.path = os.path.join(SR.MOUNT_BASE, sr_uuid)
|
||||
|
||||
# Test for the optional 'nfsoptions' dconf attribute
|
||||
self.transport = DEFAULT_TRANSPORT
|
||||
if self.dconf.has_key('useUDP') and self.dconf['useUDP'] == 'true':
|
||||
self.transport = "udp"
|
||||
|
||||
|
||||
def validate_remotepath(self, scan):
|
||||
if not self.dconf.has_key('serverpath'):
|
||||
if scan:
|
||||
try:
|
||||
self.scan_exports(self.dconf['server'])
|
||||
except:
|
||||
pass
|
||||
raise xs_errors.XenError('ConfigServerPathMissing')
|
||||
if not self._isvalidpathstring(self.dconf['serverpath']):
|
||||
raise xs_errors.XenError('ConfigServerPathBad', \
|
||||
opterr='serverpath is %s' % self.dconf['serverpath'])
|
||||
|
||||
def check_server(self):
|
||||
try:
|
||||
nfs.check_server_tcp(self.remoteserver)
|
||||
except nfs.NfsException, exc:
|
||||
raise xs_errors.XenError('NFSVersion',
|
||||
opterr=exc.errstr)
|
||||
|
||||
|
||||
def mount(self, mountpoint, remotepath):
|
||||
try:
|
||||
nfs.soft_mount(mountpoint, self.remoteserver, remotepath, self.transport)
|
||||
except nfs.NfsException, exc:
|
||||
raise xs_errors.XenError('NFSMount', opterr=exc.errstr)
|
||||
|
||||
|
||||
def attach(self, sr_uuid):
|
||||
self.validate_remotepath(False)
|
||||
#self.remotepath = os.path.join(self.dconf['serverpath'], sr_uuid)
|
||||
self.remotepath = self.dconf['serverpath']
|
||||
util._testHost(self.dconf['server'], NFSPORT, 'NFSTarget')
|
||||
self.mount_remotepath(sr_uuid)
|
||||
|
||||
|
||||
def mount_remotepath(self, sr_uuid):
|
||||
if not self._checkmount():
|
||||
self.check_server()
|
||||
self.mount(self.path, self.remotepath)
|
||||
|
||||
return super(NFSSR, self).attach(sr_uuid)
|
||||
|
||||
|
||||
def probe(self):
|
||||
# Verify NFS target and port
|
||||
util._testHost(self.dconf['server'], NFSPORT, 'NFSTarget')
|
||||
|
||||
self.validate_remotepath(True)
|
||||
self.check_server()
|
||||
|
||||
temppath = os.path.join(SR.MOUNT_BASE, PROBE_MOUNTPOINT)
|
||||
|
||||
self.mount(temppath, self.dconf['serverpath'])
|
||||
try:
|
||||
return nfs.scan_srlist(temppath)
|
||||
finally:
|
||||
try:
|
||||
nfs.unmount(temppath, True)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def detach(self, sr_uuid):
|
||||
"""Detach the SR: Unmounts and removes the mountpoint"""
|
||||
if not self._checkmount():
|
||||
return
|
||||
util.SMlog("Aborting GC/coalesce")
|
||||
cleanup.abort(self.uuid)
|
||||
|
||||
# Change directory to avoid unmount conflicts
|
||||
os.chdir(SR.MOUNT_BASE)
|
||||
|
||||
try:
|
||||
nfs.unmount(self.path, True)
|
||||
except nfs.NfsException, exc:
|
||||
raise xs_errors.XenError('NFSUnMount', opterr=exc.errstr)
|
||||
|
||||
return super(NFSSR, self).detach(sr_uuid)
|
||||
|
||||
|
||||
def create(self, sr_uuid, size):
|
||||
util._testHost(self.dconf['server'], NFSPORT, 'NFSTarget')
|
||||
self.validate_remotepath(True)
|
||||
if self._checkmount():
|
||||
raise xs_errors.XenError('NFSAttached')
|
||||
|
||||
# Set the target path temporarily to the base dir
|
||||
# so that we can create the target SR directory
|
||||
self.remotepath = self.dconf['serverpath']
|
||||
try:
|
||||
self.mount_remotepath(sr_uuid)
|
||||
except Exception, exn:
|
||||
try:
|
||||
os.rmdir(self.path)
|
||||
except:
|
||||
pass
|
||||
raise exn
|
||||
|
||||
#newpath = os.path.join(self.path, sr_uuid)
|
||||
#if util.ioretry(lambda: util.pathexists(newpath)):
|
||||
# if len(util.ioretry(lambda: util.listdir(newpath))) != 0:
|
||||
# self.detach(sr_uuid)
|
||||
# raise xs_errors.XenError('SRExists')
|
||||
#else:
|
||||
# try:
|
||||
# util.ioretry(lambda: util.makedirs(newpath))
|
||||
# except util.CommandException, inst:
|
||||
# if inst.code != errno.EEXIST:
|
||||
# self.detach(sr_uuid)
|
||||
# raise xs_errors.XenError('NFSCreate',
|
||||
# opterr='remote directory creation error is %d'
|
||||
# % inst.code)
|
||||
self.detach(sr_uuid)
|
||||
|
||||
def delete(self, sr_uuid):
|
||||
# try to remove/delete non VDI contents first
|
||||
super(NFSSR, self).delete(sr_uuid)
|
||||
try:
|
||||
if self._checkmount():
|
||||
self.detach(sr_uuid)
|
||||
|
||||
# Set the target path temporarily to the base dir
|
||||
# so that we can remove the target SR directory
|
||||
self.remotepath = self.dconf['serverpath']
|
||||
self.mount_remotepath(sr_uuid)
|
||||
newpath = os.path.join(self.path, sr_uuid)
|
||||
|
||||
if util.ioretry(lambda: util.pathexists(newpath)):
|
||||
util.ioretry(lambda: os.rmdir(newpath))
|
||||
self.detach(sr_uuid)
|
||||
except util.CommandException, inst:
|
||||
self.detach(sr_uuid)
|
||||
if inst.code != errno.ENOENT:
|
||||
raise xs_errors.XenError('NFSDelete')
|
||||
|
||||
def vdi(self, uuid, loadLocked = False):
|
||||
if not loadLocked:
|
||||
return NFSFileVDI(self, uuid)
|
||||
return NFSFileVDI(self, uuid)
|
||||
|
||||
def _checkmount(self):
|
||||
return util.ioretry(lambda: util.pathexists(self.path)) \
|
||||
and util.ioretry(lambda: util.ismount(self.path))
|
||||
|
||||
def scan_exports(self, target):
|
||||
util.SMlog("scanning2 (target=%s)" % target)
|
||||
dom = nfs.scan_exports(target)
|
||||
print >>sys.stderr,dom.toprettyxml()
|
||||
|
||||
class NFSFileVDI(FileSR.FileVDI):
|
||||
def attach(self, sr_uuid, vdi_uuid):
|
||||
try:
|
||||
vdi_ref = self.sr.srcmd.params['vdi_ref']
|
||||
self.session.xenapi.VDI.remove_from_xenstore_data(vdi_ref, \
|
||||
"vdi-type")
|
||||
self.session.xenapi.VDI.remove_from_xenstore_data(vdi_ref, \
|
||||
"storage-type")
|
||||
self.session.xenapi.VDI.add_to_xenstore_data(vdi_ref, \
|
||||
"storage-type", "nfs")
|
||||
except:
|
||||
util.logException("NFSSR:attach")
|
||||
pass
|
||||
|
||||
return super(NFSFileVDI, self).attach(sr_uuid, vdi_uuid)
|
||||
|
||||
def clone(self, sr_uuid, vdi_uuid):
|
||||
timestamp_before = int(util.get_mtime(self.sr.path))
|
||||
ret = super(NFSFileVDI, self).clone(sr_uuid, vdi_uuid)
|
||||
timestamp_after = int(util.get_mtime(self.sr.path))
|
||||
if timestamp_after == timestamp_before:
|
||||
util.SMlog("SR dir timestamp didn't change, updating")
|
||||
timestamp_after += 1
|
||||
os.utime(self.sr.path, (timestamp_after, timestamp_after))
|
||||
return ret
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
SRCommand.run(NFSSR, DRIVER_INFO)
|
||||
else:
|
||||
SR.registerSR(NFSSR)
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
#!/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 = 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()
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# This file specifies the files that need
|
||||
# to be transferred over to the XenServer.
|
||||
# The format of this file is as follows:
|
||||
# [Name of file]=[source path],[file permission],[destination path]
|
||||
# [destination path] is required.
|
||||
# If [file permission] is missing, 755 is assumed.
|
||||
# If [source path] is missing, it looks in the same
|
||||
# directory as the patch file.
|
||||
# If [source path] starts with '/', then it is absolute path.
|
||||
# If [source path] starts with '~', then it is path relative to management server home directory.
|
||||
# If [source path] does not start with '/' or '~', then it is relative path to the location of the patch file.
|
||||
NFSSR.py=/opt/xensource/sm
|
||||
nfs.py=/opt/xensource/sm
|
||||
patch.tgz=..,0775,/opt/xensource/bin
|
||||
vmops=..,0755,/etc/xapi.d/plugins
|
||||
systemvm.zip=../../../../../vms,0755,/opt/xensource/bin
|
||||
hostvmstats.py=..,0755,/opt/xensource/sm
|
||||
network_info.sh=..,0755,/opt/xensource/bin
|
||||
prepsystemvm.sh=..,0755,/opt/xensource/bin
|
||||
setupxenserver.sh=..,0755,/opt/xensource/bin
|
||||
make_migratable.sh=..,0755,/opt/xensource/bin
|
||||
networkUsage.sh=..,0755,/opt/xensource/bin
|
||||
setup_iscsi.sh=..,0755,/opt/xensource/bin
|
||||
version=..,0755,/opt/xensource/bin
|
||||
pingtest.sh=../../..,0755,/opt/xensource/bin
|
||||
dhcp_entry.sh=../../../../network/domr/,0755,/opt/xensource/bin
|
||||
ipassoc.sh=../../../../network/domr/,0755,/opt/xensource/bin
|
||||
vm_data.sh=../../../../network/domr/,0755,/opt/xensource/bin
|
||||
save_password_to_domr.sh=../../../../network/domr/,0755,/opt/xensource/bin
|
||||
call_firewall.sh=../../../../network/domr/,0755,/opt/xensource/bin
|
||||
call_loadbalancer.sh=../../../../network/domr/,0755,/opt/xensource/bin
|
||||
Loading…
Reference in New Issue