support xenserver 5.6 fp1 in oss

This commit is contained in:
anthony 2010-12-20 14:17:47 -08:00
parent 228eba363b
commit 2be0b45297
7 changed files with 444 additions and 47 deletions

View File

@ -103,6 +103,8 @@ import com.cloud.agent.api.ReadyCommand;
import com.cloud.agent.api.RebootAnswer;
import com.cloud.agent.api.RebootCommand;
import com.cloud.agent.api.RebootRouterCommand;
import com.cloud.agent.api.SecurityIngressRuleAnswer;
import com.cloud.agent.api.SecurityIngressRulesCmd;
import com.cloud.agent.api.SetupAnswer;
import com.cloud.agent.api.SetupCommand;
import com.cloud.agent.api.StartAnswer;
@ -433,6 +435,8 @@ public abstract class CitrixResourceBase implements ServerResource {
return execute((VpnUsersCfgCommand)cmd);
} else if (cmd instanceof CheckSshCommand) {
return execute((CheckSshCommand)cmd);
} else if (cmd instanceof SecurityIngressRulesCmd) {
return execute((SecurityIngressRulesCmd) cmd);
} else {
return Answer.createUnsupportedCommandAnswer(cmd);
}
@ -3194,10 +3198,6 @@ public abstract class CitrixResourceBase implements ServerResource {
return com.cloud.host.Host.Type.Routing;
}
protected boolean can_bridge_firewall(Connection conn) {
return false;
}
protected boolean getHostInfo(Connection conn) throws IllegalArgumentException{
try {
Host myself = Host.getByUuid(conn, _host.uuid);
@ -3663,6 +3663,39 @@ public abstract class CitrixResourceBase implements ServerResource {
}
}
protected boolean can_bridge_firewall(Connection conn) {
return Boolean.valueOf(callHostPlugin(conn, "vmops", "can_bridge_firewall", "host_uuid", _host.uuid));
}
private Answer execute(SecurityIngressRulesCmd cmd) {
Connection conn = getConnection();
if (s_logger.isTraceEnabled()) {
s_logger.trace("Sending network rules command to " + _host.ip);
}
if (!_canBridgeFirewall) {
s_logger.info("Host " + _host.ip + " cannot do bridge firewalling");
return new SecurityIngressRuleAnswer(cmd, false, "Host " + _host.ip + " cannot do bridge firewalling");
}
String result = callHostPlugin(conn, "vmops", "network_rules",
"vmName", cmd.getVmName(),
"vmIP", cmd.getGuestIp(),
"vmMAC", cmd.getGuestMac(),
"vmID", Long.toString(cmd.getVmId()),
"signature", cmd.getSignature(),
"seqno", Long.toString(cmd.getSeqNum()),
"rules", cmd.stringifyRules());
if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) {
s_logger.warn("Failed to program network rules for vm " + cmd.getVmName());
return new SecurityIngressRuleAnswer(cmd, false, "programming network rules failed");
} else {
s_logger.info("Programmed network rules for vm " + cmd.getVmName() + " guestIp=" + cmd.getGuestIp() + ", numrules=" + cmd.getRuleSet().length);
return new SecurityIngressRuleAnswer(cmd);
}
}
protected Answer execute(DeleteStoragePoolCommand cmd) {
Connection conn = getConnection();

View File

@ -46,15 +46,6 @@ public class XenServerResource extends CitrixResourceBase {
super();
}
@Override
public Answer executeRequest(Command cmd) {
if (cmd instanceof SecurityIngressRulesCmd) {
return execute((SecurityIngressRulesCmd) cmd);
} else {
return super.executeRequest(cmd);
}
}
@Override
protected String getGuestOsType(String stdType, boolean bootFromCD) {
return CitrixHelper.getXenServerGuestOsType(stdType);
@ -77,39 +68,6 @@ public class XenServerResource extends CitrixResourceBase {
files.add(file);
return files;
}
@Override
protected boolean can_bridge_firewall(Connection conn) {
return Boolean.valueOf(callHostPlugin(conn, "vmops", "can_bridge_firewall", "host_uuid", _host.uuid));
}
private Answer execute(SecurityIngressRulesCmd cmd) {
Connection conn = getConnection();
if (s_logger.isTraceEnabled()) {
s_logger.trace("Sending network rules command to " + _host.ip);
}
if (!_canBridgeFirewall) {
s_logger.info("Host " + _host.ip + " cannot do bridge firewalling");
return new SecurityIngressRuleAnswer(cmd, false, "Host " + _host.ip + " cannot do bridge firewalling");
}
String result = callHostPlugin(conn, "vmops", "network_rules",
"vmName", cmd.getVmName(),
"vmIP", cmd.getGuestIp(),
"vmMAC", cmd.getGuestMac(),
"vmID", Long.toString(cmd.getVmId()),
"signature", cmd.getSignature(),
"seqno", Long.toString(cmd.getSeqNum()),
"rules", cmd.stringifyRules());
if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) {
s_logger.warn("Failed to program network rules for vm " + cmd.getVmName());
return new SecurityIngressRuleAnswer(cmd, false, "programming network rules failed");
} else {
s_logger.info("Programmed network rules for vm " + cmd.getVmName() + " guestIp=" + cmd.getGuestIp() + ", numrules=" + cmd.getRuleSet().length);
return new SecurityIngressRuleAnswer(cmd);
}
}
}

View File

@ -14,6 +14,7 @@ nfs.py=/opt/xensource/sm
vmops=..,0755,/etc/xapi.d/plugins
vmopsSnapshot=..,0755,/etc/xapi.d/plugins
hostvmstats.py=..,0755,/opt/xensource/sm
systemvm.iso=../../../../../vms,0644,/opt/xensource/packages/iso
id_rsa.cloud=..,0600,/root/.ssh
network_info.sh=..,0755,/opt/xensource/bin
setupxenserver.sh=..,0755,/opt/xensource/bin

View File

@ -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)

View File

@ -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()

View File

@ -53,6 +53,7 @@ import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.hypervisor.xen.resource.CitrixResourceBase;
import com.cloud.hypervisor.xen.resource.XcpServerResource;
import com.cloud.hypervisor.xen.resource.XenServer56FP1Resource;
import com.cloud.hypervisor.xen.resource.XenServerConnectionPool;
import com.cloud.hypervisor.xen.resource.XenServerResource;
import com.cloud.resource.Discoverer;
@ -375,7 +376,10 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L
if(prodBrand.equals("XenServer") && prodVersion.equals("5.6.0"))
return new XenServerResource();
String msg = "Only support XCP 0.1.1 and XenServer 5.6 , but this one is " + prodBrand + " " + prodVersion;
if(prodBrand.equals("XenServer") && prodVersion.equals("5.6.100"))
return new XenServer56FP1Resource();
String msg = "Only support XCP 0.1.1, XenServer 5.6 and XenServer 5.6 FP1 , but this one is " + prodBrand + " " + prodVersion;
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, msg, msg);
s_logger.debug(msg);
throw new RuntimeException(msg);