diff --git a/core/src/com/cloud/agent/api/ClusterSyncAnswer.java b/core/src/com/cloud/agent/api/ClusterSyncAnswer.java index 99fee2a9dd1..e5ea1f15aca 100644 --- a/core/src/com/cloud/agent/api/ClusterSyncAnswer.java +++ b/core/src/com/cloud/agent/api/ClusterSyncAnswer.java @@ -18,12 +18,12 @@ package com.cloud.agent.api; import java.util.HashMap; -import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; import com.cloud.vm.VirtualMachine.State; public class ClusterSyncAnswer extends Answer { private long _clusterId; - private HashMap> _newStates; + private HashMap> _newStates; private boolean _isExecuted=false; // this is here because a cron command answer is being sent twice @@ -38,7 +38,7 @@ public class ClusterSyncAnswer extends Answer { } - public ClusterSyncAnswer(long clusterId, HashMap> newStates){ + public ClusterSyncAnswer(long clusterId, HashMap> newStates){ _clusterId = clusterId; _newStates = newStates; result = true; @@ -48,7 +48,7 @@ public class ClusterSyncAnswer extends Answer { return _clusterId; } - public HashMap> getNewStates() { + public HashMap> getNewStates() { return _newStates; } diff --git a/core/src/com/cloud/agent/api/StartupRoutingCommand.java b/core/src/com/cloud/agent/api/StartupRoutingCommand.java index 5961ab0017e..d52666b7d9d 100755 --- a/core/src/com/cloud/agent/api/StartupRoutingCommand.java +++ b/core/src/com/cloud/agent/api/StartupRoutingCommand.java @@ -22,7 +22,7 @@ import java.util.Map; import com.cloud.host.Host; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.Networks.RouterPrivateIpStrategy; -import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; import com.cloud.vm.VirtualMachine.State; public class StartupRoutingCommand extends StartupCommand { @@ -48,7 +48,7 @@ public class StartupRoutingCommand extends StartupCommand { long dom0MinMemory; boolean poolSync; Map vms; - HashMap> _clusterVMStates; + HashMap> _clusterVMStates; String caps; String pool; HypervisorType hypervisorType; @@ -129,7 +129,7 @@ getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStr } } - public void setClusterVMStateChanges(HashMap> allStates){ + public void setClusterVMStateChanges(HashMap> allStates){ _clusterVMStates = allStates; } @@ -157,7 +157,7 @@ getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStr return vms; } - public HashMap> getClusterVMStateChanges() { + public HashMap> getClusterVMStateChanges() { return _clusterVMStates; } diff --git a/core/src/com/cloud/agent/api/StopAnswer.java b/core/src/com/cloud/agent/api/StopAnswer.java index 0af23853da5..614835e2a37 100755 --- a/core/src/com/cloud/agent/api/StopAnswer.java +++ b/core/src/com/cloud/agent/api/StopAnswer.java @@ -17,37 +17,34 @@ package com.cloud.agent.api; public class StopAnswer extends RebootAnswer { - Integer vncPort; + + private String hypervisortoolsversion; Integer timeOffset; protected StopAnswer() { } - public StopAnswer(StopCommand cmd, String details, Integer vncPort, Integer timeOffset, boolean success) { + public StopAnswer(StopCommand cmd, String details, String hypervisortoolsversion, Integer timeOffset, boolean success) { super(cmd, details, success); - this.vncPort = vncPort; + this.hypervisortoolsversion = hypervisortoolsversion; this.timeOffset = timeOffset; } - public StopAnswer(StopCommand cmd, String details, Integer vncPort, boolean success) { + public StopAnswer(StopCommand cmd, String details, boolean success) { super(cmd, details, success); - this.vncPort = vncPort; + this.hypervisortoolsversion = null; this.timeOffset = null; } - public StopAnswer(StopCommand cmd, String details, boolean success) { - super(cmd, details, success); - vncPort = null; - timeOffset = null; - } public StopAnswer(StopCommand cmd, Exception e) { super(cmd, e); + this.hypervisortoolsversion = null; + this.timeOffset = null; } - @Override - public Integer getVncPort() { - return vncPort; + public String getHypervisorToolsVersion() { + return hypervisortoolsversion; } public Integer getTimeOffset() { diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java index 8bf419f1a65..81b1cdc425d 100755 --- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -884,6 +884,16 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac StopCommand cmd = new StopCommand(vm, getExecuteInSequence()); StopAnswer answer = (StopAnswer)_agentMgr.easySend(destHostId, cmd); + if ( answer != null ) { + String hypervisortoolsversion = answer.getHypervisorToolsVersion(); + if (hypervisortoolsversion != null) { + UserVmVO userVm = _userVmDao.findById(vm.getId()); + _userVmDao.loadDetails(userVm); + userVm.setDetail("hypervisortoolsversion", hypervisortoolsversion); + _userVmDao.saveDetails(userVm); + } + } + if (answer == null || !answer.getResult()) { s_logger.warn("Unable to stop " + vm + " due to " + (answer != null ? answer.getDetails() : "no answers")); _haMgr.scheduleStop(vm, destHostId, WorkType.ForceStop); @@ -989,7 +999,16 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac VirtualMachine vm = profile.getVirtualMachine(); StopCommand stop = new StopCommand(vm, getExecuteInSequence()); try { - Answer answer = _agentMgr.send(vm.getHostId(), stop); + StopAnswer answer = (StopAnswer) _agentMgr.send(vm.getHostId(), stop); + if ( answer != null ) { + String hypervisortoolsversion = answer.getHypervisorToolsVersion(); + if (hypervisortoolsversion != null) { + UserVmVO userVm = _userVmDao.findById(vm.getId()); + _userVmDao.loadDetails(userVm); + userVm.setDetail("hypervisortoolsversion", hypervisortoolsversion); + _userVmDao.saveDetails(userVm); + } + } if (!answer.getResult()) { s_logger.debug("Unable to stop VM due to " + answer.getDetails()); return false; @@ -1185,6 +1204,16 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac StopAnswer answer = null; try { answer = (StopAnswer)_agentMgr.send(vm.getHostId(), stop); + + if ( answer != null ) { + String hypervisortoolsversion = answer.getHypervisorToolsVersion(); + if (hypervisortoolsversion != null) { + UserVmVO userVm = _userVmDao.findById(vm.getId()); + _userVmDao.loadDetails(userVm); + userVm.setDetail("hypervisortoolsversion", hypervisortoolsversion); + _userVmDao.saveDetails(userVm); + } + } stopped = answer.getResult(); if (!stopped) { throw new CloudRuntimeException("Unable to stop the virtual machine due to " + answer.getDetails()); @@ -1997,7 +2026,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac return commands; } - public void deltaSync(Map> newStates) { + + + public void deltaSync(Map> newStates) { Map states = convertToInfos(newStates); for (Map.Entry entry : states.entrySet()) { @@ -2032,9 +2063,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } } - public void fullSync(final long clusterId, Map> newStates) { - if (newStates == null) - return; + public void fullSync(final long clusterId, Map> newStates) { + if (newStates==null) + return; Map infos = convertToInfos(newStates); Set set_vms = Collections.synchronizedSet(new HashSet()); set_vms.addAll(_vmDao.listByClusterId(clusterId)); @@ -2162,24 +2193,27 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } - protected Map convertToInfos(final Map> newStates) { + + protected Map convertToInfos(final Map> newStates) { final HashMap map = new HashMap(); if (newStates == null) { return map; } boolean is_alien_vm = true; long alien_vm_count = -1; - for (Map.Entry> entry : newStates.entrySet()) { + for (Map.Entry> entry : newStates.entrySet()) { is_alien_vm = true; String name = entry.getKey(); VMInstanceVO vm = _vmDao.findVMByInstanceName(name); if (vm != null) { - map.put(vm.getId(), new AgentVmInfo(entry.getKey(), vm, entry.getValue().second(), entry.getValue().first())); + map.put(vm.getId(), new AgentVmInfo(entry.getKey(), vm, entry.getValue().second(), + entry.getValue().first(), entry.getValue().third())); is_alien_vm = false; } // alien VMs if (is_alien_vm) { - map.put(alien_vm_count--, new AgentVmInfo(entry.getKey(), null, entry.getValue().second(), entry.getValue().first())); + map.put(alien_vm_count--, new AgentVmInfo(entry.getKey(), null, entry.getValue().second(), + entry.getValue().first(), entry.getValue().third())); s_logger.warn("Found an alien VM " + entry.getKey()); } } @@ -2544,9 +2578,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac long agentId = agent.getId(); if (agent.getHypervisorType() == HypervisorType.XenServer) { // only for Xen - StartupRoutingCommand startup = (StartupRoutingCommand)cmd; - HashMap> allStates = startup.getClusterVMStateChanges(); - if (allStates != null) { + StartupRoutingCommand startup = (StartupRoutingCommand) cmd; + HashMap> allStates = startup.getClusterVMStateChanges(); + if (allStates != null){ fullSync(clusterId, allStates); } @@ -2625,22 +2659,35 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac public String name; public State state; public String hostUuid; + public String hvtoolsversion; public VMInstanceVO vm; - public AgentVmInfo(String name, VMInstanceVO vm, State state, String host) { + + @SuppressWarnings("unchecked") + public AgentVmInfo(String name, VMInstanceVO vm, State state, String host, String hvtoolsversion) { this.name = name; this.state = state; this.vm = vm; - hostUuid = host; + this.hostUuid = host; + this.hvtoolsversion= hvtoolsversion; + } - + + public AgentVmInfo(String name, VMInstanceVO vm, State state, String host) { + this(name, vm, state, host, null); + } + public AgentVmInfo(String name, VMInstanceVO vm, State state) { - this(name, vm, state, null); + this(name, vm, state, null, null); } public String getHostUuid() { return hostUuid; } + + public String getHvtoolsversion() { + return hvtoolsversion; + } } @Override diff --git a/engine/schema/src/com/cloud/storage/dao/VMTemplateDao.java b/engine/schema/src/com/cloud/storage/dao/VMTemplateDao.java index 700ccf574b6..58dc2ed0096 100755 --- a/engine/schema/src/com/cloud/storage/dao/VMTemplateDao.java +++ b/engine/schema/src/com/cloud/storage/dao/VMTemplateDao.java @@ -76,4 +76,7 @@ public interface VMTemplateDao extends GenericDao { List findTemplatesToSyncToS3(); + void loadDetails(VMTemplateVO tmpl); + + void saveDetails(VMTemplateVO tmpl); } diff --git a/engine/schema/src/com/cloud/storage/dao/VMTemplateDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VMTemplateDaoImpl.java index a96524cdd9f..901ae80d093 100755 --- a/engine/schema/src/com/cloud/storage/dao/VMTemplateDaoImpl.java +++ b/engine/schema/src/com/cloud/storage/dao/VMTemplateDaoImpl.java @@ -402,6 +402,23 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem return routerTmpltName; } + + @Override + public void loadDetails(VMTemplateVO tmpl) { + Map details = _templateDetailsDao.findDetails(tmpl.getId()); + tmpl.setDetails(details); + } + + @Override + public void saveDetails(VMTemplateVO tmpl) { + Map details = tmpl.getDetails(); + if (details == null) { + return; + } + _templateDetailsDao.persist(tmpl.getId(), details); + } + + /* * @Override public Set> searchSwiftTemplates(String name, * String keyword, TemplateFilter templateFilter, boolean isIso, diff --git a/framework/config/src/org/apache/cloudstack/framework/config/dao/ConfigurationDao.java b/framework/config/src/org/apache/cloudstack/framework/config/dao/ConfigurationDao.java index 2f4b6e225ff..58e8a69b371 100644 --- a/framework/config/src/org/apache/cloudstack/framework/config/dao/ConfigurationDao.java +++ b/framework/config/src/org/apache/cloudstack/framework/config/dao/ConfigurationDao.java @@ -55,6 +55,8 @@ public interface ConfigurationDao extends GenericDao { public String getValueAndInitIfNotExist(String name, String category, String initValue); + public String getValueAndInitIfNotExist(String name, String category, String initValue, String desc); + /** * returns whether or not this is a premium configuration diff --git a/framework/config/src/org/apache/cloudstack/framework/config/dao/ConfigurationDaoImpl.java b/framework/config/src/org/apache/cloudstack/framework/config/dao/ConfigurationDaoImpl.java index e4029888007..e98cbcc128c 100644 --- a/framework/config/src/org/apache/cloudstack/framework/config/dao/ConfigurationDaoImpl.java +++ b/framework/config/src/org/apache/cloudstack/framework/config/dao/ConfigurationDaoImpl.java @@ -168,8 +168,13 @@ public class ConfigurationDaoImpl extends GenericDaoBase data = _runningVms.get(vmName); if (data != null) { this.usedCpu -= data.first(); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 66b0cc64376..77e799d5c82 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -3857,11 +3857,11 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa if (getVmState(vmMo) != State.Stopped) { if (vmMo.safePowerOff(_shutdown_waitMs)) { state = State.Stopped; - return new StopAnswer(cmd, "Stop VM " + cmd.getVmName() + " Succeed", 0, true); + return new StopAnswer(cmd, "Stop VM " + cmd.getVmName() + " Succeed", true); } else { String msg = "Have problem in powering off VM " + cmd.getVmName() + ", let the process continue"; s_logger.warn(msg); - return new StopAnswer(cmd, msg, 0, true); + return new StopAnswer(cmd, msg, true); } } else { state = State.Stopped; @@ -3869,7 +3869,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa String msg = "VM " + cmd.getVmName() + " is already in stopped state"; s_logger.info(msg); - return new StopAnswer(cmd, msg, 0, true); + return new StopAnswer(cmd, msg, true); } finally { synchronized (_vms) { _vms.put(cmd.getVmName(), state); @@ -3882,7 +3882,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa String msg = "VM " + cmd.getVmName() + " is no longer in vSphere"; s_logger.info(msg); - return new StopAnswer(cmd, msg, 0, true); + return new StopAnswer(cmd, msg, true); } } catch (Exception e) { if (e instanceof RemoteException) { diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 0ac8b1c3130..f16a6f5e5d8 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -207,9 +207,9 @@ import com.cloud.storage.template.TemplateProp; import com.cloud.template.VirtualMachineTemplate.BootloaderType; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; import com.cloud.utils.S3Utils; import com.cloud.utils.StringUtils; -import com.cloud.utils.Ternary; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.DiskProfile; @@ -1349,8 +1349,18 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe throw new CloudRuntimeException("Unable to handle boot loader type: " + vmSpec.getBootloader()); } } + + try { + finalizeVmMetaData(vm, conn, vmSpec); + } catch ( Exception e) { + throw new CloudRuntimeException("Unable to finalize VM MetaData: " + vmSpec); + } return vm; } + + protected void finalizeVmMetaData(VM vm, Connection conn, VirtualMachineTO vmSpec) throws Exception { + } + protected String handleVmStartFailure(Connection conn, String vmName, VM vm, String message, Throwable th) { String msg = "Unable to start " + vmName + " due to " + message; @@ -2862,8 +2872,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return state == null ? State.Unknown : state; } - protected HashMap> getAllVms(Connection conn) { - final HashMap> vmStates = new HashMap>(); + protected HashMap> getAllVms(Connection conn) { + final HashMap> vmStates = new HashMap>(); Map vm_map = null; for (int i = 0; i < 2; i++) { try { @@ -2893,6 +2903,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe s_logger.trace("VM " + record.nameLabel + ": powerstate = " + ps + "; vm state=" + state.toString()); } Host host = record.residentOn; + String xstoolsversion = getVMXenToolsVersion(record.platform); String host_uuid = null; if( ! isRefNull(host) ) { try { @@ -2904,7 +2915,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } catch (XmlRpcException e) { s_logger.error("Failed to get host uuid for host " + host.toWireString(), e); } - vmStates.put(record.nameLabel, new Pair(host_uuid, state)); + vmStates.put(record.nameLabel, new Ternary(host_uuid, state, xstoolsversion)); } } @@ -3915,7 +3926,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe s_logger.info("VM does not exist on XenServer" + _host.uuid); s_vms.remove(_cluster, _name, vmName); } - return new StopAnswer(cmd, "VM does not exist", 0 , true); + return new StopAnswer(cmd, "VM does not exist", true); } for (VM vm : vms) { VM.Record vmr = vm.getRecord(conn); @@ -3972,6 +3983,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } catch (NumberFormatException e) { s_logger.error("Error while reading the platform:timeoffset field of the instance", e); } + String xentoolsversion = getVMXenToolsVersion(platform); Set vifs = vm.getVIFs(conn); List networks = new ArrayList(); @@ -3993,7 +4005,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe // network might be destroyed by other host } } - return new StopAnswer(cmd, "Stop VM " + vmName + " Succeed", 0, timeoffset, true); + return new StopAnswer(cmd, "Stop VM " + vmName + " Succeed", xentoolsversion, timeoffset, true); } } catch (XenAPIException e) { String msg = "VM destroy failed in Stop " + vmName + " Command due to " + e.toString(); @@ -4025,6 +4037,30 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return new StopAnswer(cmd, "Stop VM failed", false); } + + /*Override by subclass*/ + protected String getVMXenToolsVersion(Map platform) { + return "xenserver56"; + } + + + private List getVdis(Connection conn, VM vm) { + List vdis = new ArrayList(); + try { + Set vbds =vm.getVBDs(conn); + for( VBD vbd : vbds ) { + vdis.add(vbd.getVDI(conn)); + } + } catch (XenAPIException e) { + String msg = "getVdis can not get VPD due to " + e.toString(); + s_logger.warn(msg, e); + } catch (XmlRpcException e) { + String msg = "getVdis can not get VPD due to " + e.getMessage(); + s_logger.warn(msg, e); + } + return vdis; + } + protected String connect(Connection conn, final String vmName, final String ipAddress, final int port) { for (int i = 0; i <= _retry; i++) { try { @@ -4873,7 +4909,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe Host.Record hostr = poolr.master.getRecord(conn); if (_host.uuid.equals(hostr.uuid)) { - HashMap> allStates=fullClusterSync(conn); + HashMap> allStates=fullClusterSync(conn); cmd.setClusterVMStateChanges(allStates); } } catch (Throwable e) { @@ -7055,7 +7091,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } } - success = true; details = null; } else if (cmd.getCommandSwitch().equals(ManageSnapshotCommand.DESTROY_SNAPSHOT)) { @@ -7075,7 +7110,6 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe details += ", reason: " + e.toString(); s_logger.warn(details, e); } - return new ManageSnapshotAnswer(cmd, snapshotId, snapshotUUID, success, details); } @@ -7999,13 +8033,13 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } catch (Throwable e) { s_logger.warn("Check for master failed, failing the Cluster sync command"); return new Answer(cmd); - } - HashMap> newStates = deltaClusterSync(conn); + } + HashMap> newStates = deltaClusterSync(conn); return new ClusterSyncAnswer(cmd.getClusterId(), newStates); } - protected HashMap> fullClusterSync(Connection conn) { + protected HashMap> fullClusterSync(Connection conn) { synchronized (_cluster.intern()) { s_vms.clear(_cluster); } @@ -8018,12 +8052,13 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe String vm_name = record.nameLabel; VmPowerState ps = record.powerState; final State state = convertToState(ps); + String xstoolsversion = getVMXenToolsVersion(record.platform); Host host = record.residentOn; String host_uuid = null; if( ! isRefNull(host) ) { host_uuid = host.getUuid(conn); synchronized (_cluster.intern()) { - s_vms.put(_cluster, host_uuid, vm_name, state); + s_vms.put(_cluster, host_uuid, vm_name, state, xstoolsversion); } } if (s_logger.isTraceEnabled()) { @@ -8039,38 +8074,50 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } - protected HashMap> deltaClusterSync(Connection conn) { - final HashMap> changes = new HashMap>(); + protected HashMap> deltaClusterSync(Connection conn) { + final HashMap> changes = new HashMap>(); synchronized (_cluster.intern()) { - HashMap> newStates = getAllVms(conn); + HashMap> newStates = getAllVms(conn); if (newStates == null) { s_logger.warn("Unable to get the vm states so no state sync at this point."); return null; } - HashMap> oldStates = new HashMap>(s_vms.size(_cluster)); + HashMap> oldStates = new HashMap>(s_vms.size(_cluster)); oldStates.putAll(s_vms.getClusterVmState(_cluster)); - for (final Map.Entry> entry : newStates.entrySet()) { + for (final Map.Entry> entry : newStates.entrySet()) { final String vm = entry.getKey(); - + String xstoolsversion = entry.getValue().third(); State newState = entry.getValue().second(); String host_uuid = entry.getValue().first(); - final Pair oldState = oldStates.remove(vm); + final Ternary oldState = oldStates.remove(vm); + + // check if xstoolsversion changed + if (xstoolsversion != null && oldState != null){ + if (xstoolsversion != oldState.third() && newState != State.Stopped && newState != State.Stopping){ + s_logger.warn("Detecting a change in xstoolsversion for " + vm); + changes.put(vm, new Ternary(host_uuid, newState, xstoolsversion)); + s_logger.debug("11. The VM " + vm + " is in " + newState + " state"); + s_vms.put(_cluster, host_uuid, vm, newState, xstoolsversion); + continue; + } + } //check if host is changed if (host_uuid != null && oldState != null){ if (!host_uuid.equals(oldState.first()) && newState != State.Stopped && newState != State.Stopping){ s_logger.warn("Detecting a change in host for " + vm); - changes.put(vm, new Pair(host_uuid, newState)); + changes.put(vm, new Ternary(host_uuid, newState, null)); s_logger.debug("11. The VM " + vm + " is in " + newState + " state"); - s_vms.put(_cluster, host_uuid, vm, newState); + s_vms.put(_cluster, host_uuid, vm, newState, xstoolsversion); continue; } } + if (newState == State.Stopped && oldState != null && oldState.second() != State.Stopping && oldState.second() != State.Stopped) { newState = getRealPowerState(conn, vm); } @@ -8084,42 +8131,42 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe continue; } if (oldState == null) { - s_vms.put(_cluster, host_uuid, vm, newState); + s_vms.put(_cluster, host_uuid, vm, newState, xstoolsversion); s_logger.warn("Detecting a new state but couldn't find a old state so adding it to the changes: " + vm); - changes.put(vm, new Pair(host_uuid, newState)); + changes.put(vm, new Ternary(host_uuid, newState, null)); } else if (oldState.second() == State.Starting) { if (newState == State.Running) { s_logger.debug("12. The VM " + vm + " is in " + State.Running + " state"); - s_vms.put(_cluster, host_uuid, vm, newState); + s_vms.put(_cluster, host_uuid, vm, newState, xstoolsversion); } else if (newState == State.Stopped) { s_logger.warn("Ignoring vm " + vm + " because of a lag in starting the vm."); } } else if (oldState.second() == State.Migrating) { if (newState == State.Running) { s_logger.debug("Detected that an migrating VM is now running: " + vm); - s_vms.put(_cluster, host_uuid, vm, newState); + s_vms.put(_cluster, host_uuid, vm, newState, xstoolsversion); } } else if (oldState.second() == State.Stopping) { if (newState == State.Stopped) { s_logger.debug("13. The VM " + vm + " is in " + State.Stopped + " state"); - s_vms.put(_cluster, host_uuid, vm, newState); + s_vms.put(_cluster, host_uuid, vm, newState, xstoolsversion); } else if (newState == State.Running) { s_logger.warn("Ignoring vm " + vm + " because of a lag in stopping the vm. "); } } else if (oldState.second() != newState) { s_logger.debug("14. The VM " + vm + " is in " + newState + " state was " + oldState.second()); - s_vms.put(_cluster, host_uuid, vm, newState); + s_vms.put(_cluster, host_uuid, vm, newState, xstoolsversion); if (newState == State.Stopped) { /* * if (s_vmsKilled.remove(vm)) { s_logger.debug("VM " + vm + " has been killed for storage. "); * newState = State.Error; } */ } - changes.put(vm, new Pair(host_uuid, newState)); + changes.put(vm, new Ternary(host_uuid, newState, null)); } } - for (final Map.Entry> entry : oldStates.entrySet()) { + for (final Map.Entry> entry : oldStates.entrySet()) { final String vm = entry.getKey(); final State oldState = entry.getValue().second(); String host_uuid = entry.getValue().first(); @@ -8141,7 +8188,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe } else { State newState = State.Stopped; s_logger.warn("The VM is now missing marking it as Stopped " + vm); - changes.put(vm, new Pair(host_uuid, newState)); + changes.put(vm, new Ternary(host_uuid, newState, null)); } } } diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java index c3c0307ca1b..2603922fd18 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java @@ -452,5 +452,27 @@ public class XenServer610Resource extends XenServer56FP1Resource { @Override protected void plugDom0Vif(Connection conn, VIF dom0Vif) throws XmlRpcException, XenAPIException { // do nothing. In xenserver 6.1 and beyond this step isn't needed. + } + + @Override + protected String getVMXenToolsVersion(Map platform) { + if (platform.containsKey("device_id")) { + return "xenserver61"; + } + return "xenserver56"; } + + @Override + protected void finalizeVmMetaData(VM vm, Connection conn, VirtualMachineTO vmSpec) throws Exception { + Map details = vmSpec.getDetails(); + if ( details!= null ) { + String xentoolsversion = details.get("hypervisortoolsversion"); + if ( xentoolsversion == null || !xentoolsversion.equalsIgnoreCase("xenserver61") ) { + Map platform = vm.getPlatform(conn); + platform.remove("device_id"); + vm.setPlatform(conn, platform); + } + } + } + } diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerPoolVms.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerPoolVms.java index 33f2bf96606..f22fb286c8a 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerPoolVms.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerPoolVms.java @@ -20,20 +20,20 @@ import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; import java.util.concurrent.ConcurrentHashMap; -import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; import com.cloud.vm.VirtualMachine.State; public class XenServerPoolVms { private static final Logger s_logger = Logger.getLogger(XenServerPoolVms.class); - private final Map>> _cluster_vms = - new ConcurrentHashMap>>(); + private final Map>> _cluster_vms = + new ConcurrentHashMap>>(); - public HashMap> getClusterVmState(String clusterId){ - HashMap> _vms= _cluster_vms.get(clusterId); + public HashMap> getClusterVmState(String clusterId){ + HashMap> _vms= _cluster_vms.get(clusterId); if (_vms==null) { - HashMap> vmStates = new HashMap>(); + HashMap> vmStates = new HashMap>(); _cluster_vms.put(clusterId, vmStates); return vmStates; } @@ -41,40 +41,47 @@ public class XenServerPoolVms { } public void clear(String clusterId){ - HashMap> _vms= getClusterVmState(clusterId); + HashMap> _vms= getClusterVmState(clusterId); _vms.clear(); } public State getState(String clusterId, String name){ - HashMap> vms = getClusterVmState(clusterId); - Pair pv = vms.get(name); + HashMap> vms = getClusterVmState(clusterId); + Ternary pv = vms.get(name); return pv == null ? State.Stopped : pv.second(); // if a VM is absent on the cluster, it is effectively in stopped state. } + + + public void put(String clusterId, String hostUuid, String name, State state, String xstoolsversion){ + HashMap> vms= getClusterVmState(clusterId); + vms.put(name, new Ternary(hostUuid, state, xstoolsversion)); + } + public void put(String clusterId, String hostUuid, String name, State state){ - HashMap> vms= getClusterVmState(clusterId); - vms.put(name, new Pair(hostUuid, state)); + HashMap> vms= getClusterVmState(clusterId); + vms.put(name, new Ternary(hostUuid, state, null)); } public void remove(String clusterId, String hostUuid, String name){ - HashMap> vms= getClusterVmState(clusterId); + HashMap> vms= getClusterVmState(clusterId); vms.remove(name); } - public void putAll(String clusterId, HashMap> new_vms){ - HashMap> vms= getClusterVmState(clusterId); + public void putAll(String clusterId, HashMap> new_vms){ + HashMap> vms= getClusterVmState(clusterId); vms.putAll(new_vms); } public int size(String clusterId){ - HashMap> vms= getClusterVmState(clusterId); + HashMap> vms= getClusterVmState(clusterId); return vms.size(); } @Override public String toString(){ StringBuilder sbuf = new StringBuilder("PoolVms="); - for (HashMap> clusterVM: _cluster_vms.values()){ + for (HashMap> clusterVM: _cluster_vms.values()){ for (String vmname: clusterVM.keySet()){ sbuf.append(vmname).append("-").append(clusterVM.get(vmname).second()).append(","); } diff --git a/scripts/vm/hypervisor/xenserver/setupxenserver.sh b/scripts/vm/hypervisor/xenserver/setupxenserver.sh index e4b6f3e3372..311f2738bb3 100755 --- a/scripts/vm/hypervisor/xenserver/setupxenserver.sh +++ b/scripts/vm/hypervisor/xenserver/setupxenserver.sh @@ -49,7 +49,7 @@ sed -i 's/0\.0\.0\.0/127\.0\.0\.1/' /opt/xensource/libexec/qemu-dm-wrapper 2>&1 sed -i /NOZEROCONF/d /etc/sysconfig/network echo "NOZEROCONF=yes" >> /etc/sysconfig/network -[ -f /etc/cron.hourly/logrotate ] || mv /etc/cron.daily/logrotate /etc/cron.hourly 2>&1 +mv -n /etc/cron.daily/logrotate /etc/cron.hourly 2>&1 # more aio thread echo 1048576 >/proc/sys/fs/aio-max-nr diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index 857fdeb0190..3fdc3439092 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -246,6 +246,8 @@ public enum Config { XenHeartBeatInterval("Advanced", ManagementServer.class, Integer.class, "xen.heartbeat.interval", "60", "heartbeat to use when implementing XenServer Self Fencing", null), XenGuestNetwork("Hidden", ManagementServer.class, String.class, "xen.guest.network.device", null, "Specify for guest network name label", null), XenMaxNics("Advanced", AgentManager.class, Integer.class, "xen.nics.max", "7", "Maximum allowed nics for Vms created on Xen", null), + XenPVdriverVersion("Advanced", ManagementServer.class, String.class, "xen.pvdriver.version", "xenserver61", "default Xen PV driver version for registered template, valid value:xenserver56,xenserver61 ", "xenserver56,xenserver61"), + // VMware VmwareUseNexusVSwitch("Network", ManagementServer.class, Boolean.class, "vmware.use.nexus.vswitch", "false", "Enable/Disable Cisco Nexus 1000v vSwitch in VMware environment", null), VmwareUseDVSwitch("Network", ManagementServer.class, Boolean.class, "vmware.use.dvswitch", "false", "Enable/Disable Nexus/Vmware dvSwitch in VMware environment", null), diff --git a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java index 2ee6364b231..32c76931052 100644 --- a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java @@ -113,14 +113,10 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis to.setArch("x86_64"); } - long templateId = vm.getTemplateId(); - Map details = _templateDetailsDao.findDetails(templateId); - assert(details != null); Map detailsInVm = vm.getDetails(); if(detailsInVm != null) { - details.putAll(detailsInVm); + to.setDetails(detailsInVm); } - to.setDetails(details); // Workaround to make sure the TO has the UUID we need for Niciri integration VMInstanceVO vmInstance = _virtualMachineDao.findById(to.getId()); // check if XStools/VMWare tools are present in the VM and dynamic scaling feature is enabled (per zone/global) diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index 4c5c8a1c1cf..af1847a9a35 100755 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -292,6 +292,8 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio updateCloudIdentifier(); _configDepotAdmin.populateConfigurations(); + // setup XenServer default PV driver version + initiateXenServerPVDriverVersion(); // We should not update seed data UUID column here since this will be invoked in upgrade case as well. //updateUuids(); @@ -302,6 +304,84 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio _configDao.invalidateCache(); } + + private void templateDetailsInitIfNotExist(long id, String name, String value) { + Transaction txn = Transaction.currentTxn(); + PreparedStatement stmt = null; + PreparedStatement stmtInsert = null; + boolean insert = false; + try { + txn.start(); + stmt = txn.prepareAutoCloseStatement("SELECT id FROM vm_template_details WHERE template_id=? and name=?"); + stmt.setLong(1, id); + stmt.setString(2, name); + ResultSet rs = stmt.executeQuery(); + if(rs == null || !rs.next()) { + insert = true; + } + stmt.close(); + + if ( insert ) { + stmtInsert = txn.prepareAutoCloseStatement( + "INSERT INTO vm_template_details(template_id, name, value) VALUES(?, ?, ?)"); + stmtInsert.setLong(1, id); + stmtInsert.setString(2, name); + stmtInsert.setString(3, value); + if(stmtInsert.executeUpdate() < 1) { + throw new CloudRuntimeException("Unable to init template " + id + " datails: " + name); + } + } + txn.commit(); + } catch (Exception e) { + s_logger.warn("Unable to init template " + id + " datails: " + name, e); + throw new CloudRuntimeException("Unable to init template " + id + " datails: " + name); + } + } + + private void initiateXenServerPVDriverVersion() { + String pvdriverversion = Config.XenPVdriverVersion.getDefaultValue(); + Transaction txn = Transaction.currentTxn(); + PreparedStatement pstmt = null; + ResultSet rs1 = null; + ResultSet rs2 = null; + try { + String oldValue = _configDao.getValue(Config.XenPVdriverVersion.key()); + if ( oldValue == null ) { + String sql = "select resource from host where hypervisor_type='XenServer' and removed is null and status not in ('Error', 'Removed') group by resource" ; + pstmt = txn.prepareAutoCloseStatement(sql); + rs1 = pstmt.executeQuery(); + while (rs1.next()) { + String resouce = rs1.getString(1); //resource column + if ( resouce == null ) continue; + if ( resouce.equalsIgnoreCase("com.cloud.hypervisor.xen.resource.XenServer56Resource") + || resouce.equalsIgnoreCase("com.cloud.hypervisor.xen.resource.XenServer56FP1Resource") + || resouce.equalsIgnoreCase("com.cloud.hypervisor.xen.resource.XenServer56SP2Resource") + || resouce.equalsIgnoreCase("com.cloud.hypervisor.xen.resource.XenServer600Resource") + || resouce.equalsIgnoreCase("com.cloud.hypervisor.xen.resource.XenServer602Resource") ) { + pvdriverversion = "xenserver56"; + break; + } + } + _configDao.getValueAndInitIfNotExist(Config.XenPVdriverVersion.key(), + Config.XenPVdriverVersion.getCategory(), pvdriverversion, Config.XenPVdriverVersion.getDescription()); + sql = "select id from vm_template where hypervisor_type='XenServer' and format!='ISO' and removed is null"; + pstmt = txn.prepareAutoCloseStatement(sql); + rs2 = pstmt.executeQuery(); + List tmpl_ids = new ArrayList(); + while (rs2.next()) { + tmpl_ids.add(rs2.getLong(1)); + } + for( Long tmpl_id : tmpl_ids) { + templateDetailsInitIfNotExist(tmpl_id, "hypervisortoolsversion", pvdriverversion); + } + } + } catch (Exception e) { + s_logger.debug("initiateXenServerPVDriverVersion failed due to " + e.toString()); + // ignore + } + } + + /* private void updateUuids() { _identityDao.initializeDefaultUuid("disk_offering"); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 699f469aafe..4637da6b2b4 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -3440,7 +3440,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe // give us the same key if (_hashKey == null) { _hashKey = _configDao.getValueAndInitIfNotExist(Config.HashKey.key(), Config.HashKey.getCategory(), - getBase64EncodedRandomKey(128)); + getBase64EncodedRandomKey(128), Config.HashKey.getDescription()); } return _hashKey; } @@ -3450,7 +3450,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe if (_encryptionKey == null) { _encryptionKey = _configDao.getValueAndInitIfNotExist(Config.EncryptionKey.key(), Config.EncryptionKey.getCategory(), - getBase64EncodedRandomKey(128)); + getBase64EncodedRandomKey(128), Config.EncryptionKey.getDescription()); } return _encryptionKey; } @@ -3460,7 +3460,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe if (_encryptionIV == null) { _encryptionIV = _configDao.getValueAndInitIfNotExist(Config.EncryptionIV.key(), Config.EncryptionIV.getCategory(), - getBase64EncodedRandomKey(128)); + getBase64EncodedRandomKey(128), Config.EncryptionIV.getDescription()); } return _encryptionIV; } diff --git a/server/src/com/cloud/template/TemplateAdapterBase.java b/server/src/com/cloud/template/TemplateAdapterBase.java index a0d4c772072..6194e6e1f4c 100755 --- a/server/src/com/cloud/template/TemplateAdapterBase.java +++ b/server/src/com/cloud/template/TemplateAdapterBase.java @@ -18,6 +18,7 @@ package com.cloud.template; import java.util.List; import java.util.Map; +import java.util.HashMap; import javax.inject.Inject; @@ -36,6 +37,7 @@ import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import com.cloud.api.ApiDBUtils; +import com.cloud.configuration.Config; import com.cloud.configuration.Resource.ResourceType; import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.DataCenterDao; @@ -45,6 +47,7 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.org.Grouping; import com.cloud.projects.ProjectManager; @@ -214,6 +217,20 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat } } + if (hypervisorType.equals(Hypervisor.HypervisorType.XenServer) ) { + if( details == null || !details.containsKey("hypervisortoolsversion") + || details.get("hypervisortoolsversion") == null + || ((String)details.get("hypervisortoolsversion")).equalsIgnoreCase("none") ) { + String hpvs = _configDao.getValue(Config.XenPVdriverVersion.key()); + if ( hpvs != null) { + if ( details == null ) { + details = new HashMap(); + } + details.put("hypervisortoolsversion", hpvs); + } + } + } + Long id = _tmpltDao.getNextInSequence(Long.class, "id"); CallContext.current().setEventDetails("Id: " + id + " name: " + name); return new TemplateProfile(id, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, imgfmt, guestOSId, zoneId, diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 05663db61b1..2ec033ac651 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2458,7 +2458,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } @DB - protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, String hostName, String displayName, Account owner, Long diskOfferingId, + protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate tmplt, String hostName, String displayName, Account owner, Long diskOfferingId, Long diskSize, List networkList, List securityGroupIdList, String group, HTTPMethod httpmethod, String userData, String sshKeyPair, HypervisorType hypervisor, Account caller, Map requestedIps, IpAddresses defaultIps, Boolean isDisplayVmEnabled, String keyboard, List affinityGroupIdList) @@ -2470,7 +2470,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir throw new PermissionDeniedException( "The owner of vm to deploy is disabled: " + owner); } - + VMTemplateVO template = _templateDao.findById(tmplt.getId()); + if (template != null) { + _templateDao.loadDetails(template); + } + long accountId = owner.getId(); assert !(requestedIps != null && (defaultIps.getIp4Address() != null || defaultIps.getIp6Address() != null)) : "requestedIp list and defaultNetworkIp should never be specified together"; @@ -2807,7 +2811,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir long guestOSCategoryId = guestOS.getCategoryId(); GuestOSCategoryVO guestOSCategory = _guestOSCategoryDao.findById(guestOSCategoryId); - // If hypervisor is vSphere and OS is OS X, set special settings. if (hypervisorType.equals(HypervisorType.VMware)) { if (guestOS.getDisplayName().toLowerCase().contains("apple mac os")){ @@ -2818,6 +2821,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } } + Map details = template.getDetails(); + if ( details != null && !details.isEmpty() ) { + vm.details.putAll(details); + } + _vmDao.persist(vm); _vmDao.saveDetails(vm); diff --git a/server/test/com/cloud/vpc/dao/MockConfigurationDaoImpl.java b/server/test/com/cloud/vpc/dao/MockConfigurationDaoImpl.java index a0110b56dae..0802b7a324d 100644 --- a/server/test/com/cloud/vpc/dao/MockConfigurationDaoImpl.java +++ b/server/test/com/cloud/vpc/dao/MockConfigurationDaoImpl.java @@ -72,6 +72,15 @@ public class MockConfigurationDaoImpl extends GenericDaoBase