From c74f34eadd60844eb72555e5a828c0c000ec58fc Mon Sep 17 00:00:00 2001 From: anthony Date: Wed, 28 Sep 2011 20:34:50 -0700 Subject: [PATCH] bug 11552: This bug also happens in XenServer 5.6 FP1, but this issue is hidden by bug 11564. There are two issues here 1. in XenServer 5.6 FP1/SP2, when a slave host is down ( NIC is unplugged), and before master detect the slave is down( it takes about 10 minutes), template.createClone doesn't work sometime, it complains can not contact slave host, looks like XenServer try to start VM on this slave host, we use VM.create instead, we can specify host in VM.create API, so it will not try to connect the slave 2. in XenServer 5.6 FP1/SP2, host tag is introduced into VDI, however in HA case, VM.reset_powerstate and VM.destory doesn't remove this host tag, when CloudStack try to start this VM on other host, XenServer complains this VDI is already used ( or mount as RW). CloudStack will manually remove the host tage in VDI in FenceCommand status 11552: resolved fixed --- .../xen/resource/XenServer56FP1Resource.java | 155 ++++++++++++++++++ .../xen/resource/XenServer56SP2Resource.java | 2 +- 2 files changed, 156 insertions(+), 1 deletion(-) diff --git a/core/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java b/core/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java index 3aa91889ad3..9cf0103f8aa 100644 --- a/core/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java +++ b/core/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java @@ -19,14 +19,33 @@ package com.cloud.hypervisor.xen.resource; import java.io.File; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import javax.ejb.Local; import org.apache.log4j.Logger; +import org.apache.xmlrpc.XmlRpcException; +import com.cloud.agent.api.FenceAnswer; +import com.cloud.agent.api.FenceCommand; +import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.agent.api.to.VolumeTO; import com.cloud.resource.ServerResource; +import com.cloud.storage.Volume; +import com.cloud.template.VirtualMachineTemplate.BootloaderType; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; +import com.xensource.xenapi.Connection; +import com.xensource.xenapi.Console; +import com.xensource.xenapi.Host; +import com.xensource.xenapi.Types; +import com.xensource.xenapi.VBD; +import com.xensource.xenapi.VDI; +import com.xensource.xenapi.VM; +import com.xensource.xenapi.Types.XenAPIException; @Local(value=ServerResource.class) public class XenServer56FP1Resource extends XenServer56Resource { @@ -55,4 +74,140 @@ public class XenServer56FP1Resource extends XenServer56Resource { } + @Override + protected FenceAnswer execute(FenceCommand cmd) { + Connection conn = getConnection(); + try { + String result = callHostPluginPremium(conn, "check_heartbeat", "host", cmd.getHostGuid(), "interval", + Integer.toString(_heartbeatInterval * 2)); + if (!result.contains("> DEAD <")) { + s_logger.debug("Heart beat is still going so unable to fence"); + return new FenceAnswer(cmd, false, "Heartbeat is still going on unable to fence"); + } + + Set vms = VM.getByNameLabel(conn, cmd.getVmName()); + for (VM vm : vms) { + Set vdis = new HashSet(); + Set vbds = vm.getVBDs(conn); + for( VBD vbd : vbds ) { + VDI vdi = vbd.getVDI(conn); + if( !isRefNull(vdi) ) { + vdis.add(vdi); + } + } + vm.powerStateReset(conn); + vm.destroy(conn); + for (VDI vdi : vdis) { + Map smConfig = vdi.getSmConfig(conn); + for (String key : smConfig.keySet()) { + if (key.startsWith("host_")) { + vdi.removeFromSmConfig(conn, key); + break; + } + } + } + } + return new FenceAnswer(cmd); + } catch (XmlRpcException e) { + s_logger.warn("Unable to fence", e); + return new FenceAnswer(cmd, false, e.getMessage()); + } catch (XenAPIException e) { + s_logger.warn("Unable to fence", e); + return new FenceAnswer(cmd, false, e.getMessage()); + } + } + + @Override + protected VM createVmFromTemplate(Connection conn, VirtualMachineTO vmSpec, Host host) throws XenAPIException, XmlRpcException { + String guestOsTypeName = getGuestOsType(vmSpec.getOs(), vmSpec.getBootloader() == BootloaderType.CD); + Set templates = VM.getByNameLabel(conn, guestOsTypeName); + assert templates.size() == 1 : "Should only have 1 template but found " + templates.size(); + VM template = templates.iterator().next(); + + VM.Record record = template.getRecord(conn); + record.affinity = host; + record.otherConfig.remove("disks"); + record.otherConfig.remove("default_template"); + record.isATemplate = false; + record.nameLabel = vmSpec.getName(); + record.actionsAfterCrash = Types.OnCrashBehaviour.DESTROY; + record.actionsAfterShutdown = Types.OnNormalExit.DESTROY; + record.memoryDynamicMax = vmSpec.getMinRam(); + record.memoryDynamicMin = vmSpec.getMinRam(); + record.memoryStaticMax = vmSpec.getMinRam(); + record.memoryStaticMin = vmSpec.getMinRam(); + record.VCPUsMax = (long) vmSpec.getCpus(); + record.VCPUsAtStartup = (long) vmSpec.getCpus(); + record.consoles.clear(); + + VM vm = VM.create(conn, record); + VM.Record vmr = vm.getRecord(conn); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Created VM " + vmr.uuid + " for " + vmSpec.getName()); + } + + Map vcpuParams = new HashMap(); + + Integer speed = vmSpec.getSpeed(); + if (speed != null) { + + int cpuWeight = _maxWeight; // cpu_weight + int utilization = 0; // max CPU cap, default is unlimited + + // weight based allocation + cpuWeight = (int) ((speed * 0.99) / _host.speed * _maxWeight); + if (cpuWeight > _maxWeight) { + cpuWeight = _maxWeight; + } + + if (vmSpec.getLimitCpuUse()) { + utilization = (int) ((speed * 0.99) / _host.speed * 100); + } + + vcpuParams.put("weight", Integer.toString(cpuWeight)); + vcpuParams.put("cap", Integer.toString(utilization)); + + } + + if (vcpuParams.size() > 0) { + vm.setVCPUsParams(conn, vcpuParams); + } + + String bootArgs = vmSpec.getBootArgs(); + if (bootArgs != null && bootArgs.length() > 0) { + String pvargs = vm.getPVArgs(conn); + pvargs = pvargs + vmSpec.getBootArgs(); + if (s_logger.isDebugEnabled()) { + s_logger.debug("PV args are " + pvargs); + } + vm.setPVArgs(conn, pvargs); + } + + if (!(guestOsTypeName.startsWith("Windows") || guestOsTypeName.startsWith("Citrix") || guestOsTypeName.startsWith("Other"))) { + if (vmSpec.getBootloader() == BootloaderType.CD) { + VolumeTO[] disks = vmSpec.getDisks(); + for (VolumeTO disk : disks) { + if (disk.getType() == Volume.Type.ISO && disk.getOsType() != null) { + String isoGuestOsName = getGuestOsType(disk.getOsType(), vmSpec.getBootloader() == BootloaderType.CD); + if (!isoGuestOsName.equals(guestOsTypeName)) { + vmSpec.setBootloader(BootloaderType.PyGrub); + } + } + } + } + if (vmSpec.getBootloader() == BootloaderType.CD) { + vm.setPVBootloader(conn, "eliloader"); + if (!vm.getOtherConfig(conn).containsKey("install-repository")) { + vm.addToOtherConfig(conn, "install-repository", "cdrom"); + } + } else if (vmSpec.getBootloader() == BootloaderType.PyGrub) { + vm.setPVBootloader(conn, "pygrub"); + } else { + vm.destroy(conn); + throw new CloudRuntimeException("Unable to handle boot loader type: " + vmSpec.getBootloader()); + } + } + return vm; + } + } diff --git a/core/src/com/cloud/hypervisor/xen/resource/XenServer56SP2Resource.java b/core/src/com/cloud/hypervisor/xen/resource/XenServer56SP2Resource.java index 7ab27491d41..38f7f61d1fd 100644 --- a/core/src/com/cloud/hypervisor/xen/resource/XenServer56SP2Resource.java +++ b/core/src/com/cloud/hypervisor/xen/resource/XenServer56SP2Resource.java @@ -30,7 +30,7 @@ import com.cloud.utils.script.Script; @Local(value=ServerResource.class) -public class XenServer56SP2Resource extends XenServer56Resource { +public class XenServer56SP2Resource extends XenServer56FP1Resource { private static final Logger s_logger = Logger.getLogger(XenServer56SP2Resource.class); public XenServer56SP2Resource() {