/* * VM.java * Copyright (C) 2011,2012 Wannes De Smet * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.xenmaster.api.entity; import java.util.*; import org.apache.commons.collections.CollectionUtils; import org.xenmaster.controller.BadAPICallException; import org.xenmaster.monitoring.LogEntry; import org.xenmaster.monitoring.LogKeeper; /** * * @created Oct 2, 2011 * @author double-u */ public class VM extends NamedEntity { @ConstructorArgument protected int userVersion = 1; @ConstructorArgument protected ShutdownAction actionsAfterReboot; @ConstructorArgument protected ShutdownAction actionsAfterShutdown; @ConstructorArgument protected CrashedAction actionsAfterCrash; @ConstructorArgument protected int startupVCPUs, maxVCPUs; @ConstructorArgument protected long minimumStaticMemory, minimumDynamicMemory; @ConstructorArgument protected long maximumStaticMemory; @ConstructorArgument protected long maximumDynamicMemory; protected int domainId; @ConstructorArgument protected boolean template; protected boolean controlDomain; protected String poolName; protected boolean autoPowerOn; @ConstructorArgument protected String pvArgs, pvRamdisk, pvBootloader, pvKernel, pvBootloaderArgs; protected PowerState powerState; @ConstructorArgument protected String hvmBootPolicy; @Fill @ConstructorArgument protected Map<String, String> hvmBootParams; @ConstructorArgument @Fill protected Map<String, String> platform; @ConstructorArgument protected String pciBus; protected String metrics, guestMetrics; protected String host; @ConstructorArgument protected String hostAffinity; @Fill protected Object[] vbds, vifs, consoles; @Fill @ConstructorArgument protected Map<String, String> vcpuParams; @Fill @ConstructorArgument protected Map<String, String> otherConfig; @ConstructorArgument protected String recommendations; protected static final int MEGABYTE = 1024 * 1024; public VM() { this.actionsAfterReboot = ShutdownAction.RESTART; this.actionsAfterShutdown = ShutdownAction.DESTROY; this.actionsAfterCrash = CrashedAction.DESTROY; this.platform = new HashMap<>(); } public VM(String ref, boolean autoFill) { super(ref, autoFill); } public VM(String ref) { super(ref); } public VM(UUID uuid, boolean autoFill) { super(uuid, autoFill); } public String create(int maxVCPUs) throws BadAPICallException { this.maxVCPUs = maxVCPUs; if (startupVCPUs == 0) { startupVCPUs = maxVCPUs; } if (startupVCPUs < 1 || maxVCPUs < 1 || startupVCPUs > maxVCPUs) { throw new IllegalArgumentException("VM CPU count is zero or startup VCPU count is larger than max VCPU count"); } Map<String, Object> ctorArgs = collectConstructorArgs(); // Not putting legacy args in the model, we don't do legacy ctorArgs.put("PV_legacy_args", ""); this.reference = (String) dispatch("create", ctorArgs); return this.reference; } public void destroy() throws BadAPICallException { dispatch("destroy"); } public void start(boolean startPaused, boolean force) throws BadAPICallException { start(startPaused, force, null); } public void start(boolean startPaused, boolean force, Host host) throws BadAPICallException { try { easeStart(); if (host != null) { dispatch("start_on", host.getReference(), startPaused, force); } else { dispatch("start", startPaused, force); } } catch (BadAPICallException ex) { switch (ex.getErrorName()) { case "VM_BAD_POWER_STATE": ex.redefineErrorName("VM_ALREADY_RUNNING"); break; case "VM_HVM_REQUIRED": ex.setErrorDescription("Your CPU(s) does not support VT-x or AMD-v, which this VM requires"); break; case "NO_HOST_AVAILABLE": ex.setErrorDescription("There are no hosts available for this machine to run on"); break; } throw ex; } } /** * Check if this VM will be able to start up properly * * @return */ public void easeStart() throws BadAPICallException { for (VBD vbd : this.getVBDs()) { if (vbd.getType() != VBD.Type.DISK) { continue; } if (vbd.getVDI() == null) { LogKeeper.log(new LogEntry(vbd.getReference(), getClass(), "VM_START_COULD_NOT_PLUG_VBD", LogEntry.Level.WARNING)); continue; } for (PBD pbd : vbd.getVDI().getSR().getPBDs()) { if (!pbd.isPlugged()) { LogKeeper.log(new LogEntry(pbd.getReference(), getClass(), "PLUGGING_IN_PBD", new Object[]{vbd.getVDI().getSR().getName()}, LogEntry.Level.INFORMATION)); pbd.plug(); } } } } public void pause() throws BadAPICallException { try { dispatch("pause"); } catch (BadAPICallException ex) { switch (ex.getMessage()) { case "BAD_POWER_STATE": ex.setErrorDescription("The VM has a bad power state. It might be already paused"); } throw ex; } } public void resume() throws BadAPICallException { try { dispatch("unpause"); } catch (BadAPICallException ex) { switch (ex.getMessage()) { case "BAD_POWER_STATE": ex.setErrorDescription("The VM has a bad power state. It might be already running"); } throw ex; } } /** * Stop the VM * * @param polite it's up to you to keep your manners */ public void stop(boolean polite) throws BadAPICallException { try { if (polite) { dispatch("clean_shutdown"); } else { dispatch("hard_shutdown"); } } catch (BadAPICallException ex) { switch (ex.getMessage()) { case "BAD_POWER_STATE": ex.redefineErrorName("VM_ALREADY_HALTED"); } throw ex; } } /** * Reboot the VM * * @param polite it's up to you to keep your manners */ public void reboot(boolean polite) throws BadAPICallException { try { if (polite) { dispatch("clean_reboot"); } else { dispatch("hard_reboot"); } } catch (BadAPICallException ex) { switch (ex.getMessage()) { case "BAD_POWER_STATE": ex.setErrorDescription("The VM has a bad power state. It might not be running"); } throw ex; } } public void suspend() throws BadAPICallException { try { dispatch("suspend"); } catch (BadAPICallException ex) { switch (ex.getMessage()) { case "BAD_POWER_STATE": ex.setErrorDescription("The VM has a bad power state. It might not be running"); } throw ex; } } public void wake(boolean startPaused, boolean force) throws BadAPICallException { try { dispatch("resume", startPaused, force); } catch (BadAPICallException ex) { switch (ex.getMessage()) { case "BAD_POWER_STATE": ex.setErrorDescription("The VM has a bad power state. It might not be suspended"); } throw ex; } } public void migrateInsidePool(Host host, Map<String, String> options) throws BadAPICallException { if (options == null) { options = new HashMap<>(); } try { dispatch("pool_migrate", host.getReference(), options); } catch (BadAPICallException ex) { switch (ex.getMessage()) { case "BAD_POWER_STATE": ex.setErrorDescription("The VM has a bad power state. It might not be running"); } throw ex; } } public int computeMemoryOverhead() throws BadAPICallException { return (int) dispatch("compute_memory_overhead"); } public void sendSysRq(String sysrq) throws BadAPICallException { dispatch("send_sysrq", sysrq); } public void sendTrigger(String trigger) throws BadAPICallException { dispatch("send_trigger", trigger); } // todo check what this does and decide on good name // public int computeMaximumAvailableMemory() throws BadAPICallException { // // } public List<Object> getDataSources() throws BadAPICallException { Object[] result = (Object[]) dispatch("get_data_sources"); ArrayList<Object> arrr = new ArrayList<>(); CollectionUtils.addAll(arrr, result); return arrr; } public int[] getFreeVBDIndexes() throws BadAPICallException { Object[] result = (Object[]) dispatch("get_allowed_VBD_devices"); int[] indexes = new int[result.length]; for (int i = 0; i < result.length; i++) { indexes[i] = Integer.parseInt(result[i].toString()); } return indexes; } public int getNextAvailableVBDIndex() throws BadAPICallException { int[] freeVBDIndexes = getFreeVBDIndexes(); if (freeVBDIndexes.length < 1) { return -1; } return freeVBDIndexes[0]; } public int[] getFreeVIFIndexes() throws BadAPICallException { Object[] result = (Object[]) dispatch("get_allowed_VIF_devices"); int[] indexes = new int[result.length]; for (int i = 0; i < result.length; i++) { indexes[i] = Integer.parseInt(result[i].toString()); } return indexes; } public int getNextAvailableVIFIndex() throws BadAPICallException { int[] freeVIFIndexes = getFreeVIFIndexes(); if (freeVIFIndexes.length < 1) { return -1; } return freeVIFIndexes[0]; } public VMMetrics getMetrics() { this.metrics = value(this.metrics, "get_vm_metrics"); return new VMMetrics(this.metrics); } public GuestMetrics getGuestMetrics() { this.guestMetrics = value(this.guestMetrics, "get_guest_metrics"); return new GuestMetrics(this.guestMetrics); } public static List<VM> getAll() throws BadAPICallException { List<VM> allVMs = getAllEntities(VM.class); for (ListIterator<VM> it = allVMs.listIterator(); it.hasNext();) { if (it.next().isTemplate()) { it.remove(); } } return allVMs; } public static List<VM> getTemplates() throws BadAPICallException { List<VM> allVMs = getAllEntities(VM.class); for (ListIterator<VM> it = allVMs.listIterator(); it.hasNext();) { if (!it.next().isTemplate()) { it.remove(); } } return allVMs; } public List<VBD> getVBDs() { return getEntities(VBD.class, "get_VBDs"); } public List<VIF> getVIFs() { return getEntities(VIF.class, "get_VIFs"); } public List<Console> getConsoles() { return getEntities(Console.class, "get_consoles"); } public Map<String, String> getVCPUParams() { if (vcpuParams == null) { vcpuParams = new HashMap<>(); } return vcpuParams; } public Map<String, String> getOtherConfig() { return this.otherConfig; } public void addOtherConfig(Map<String, String> data) throws BadAPICallException { otherConfig.putAll(data); setOtherConfig(otherConfig); } public void setOtherConfig(Map<String, String> data) throws BadAPICallException { this.otherConfig = setter(data, "set_other_config"); } public void setMemoryLimits(double maxStaticMemMb, double minStaticMemMb, double maxDynMemMb, double minDynMemMb) throws BadAPICallException { dispatch("set_memory_limits", minStaticMemMb * MEGABYTE, maxStaticMemMb * MEGABYTE, minDynMemMb * MEGABYTE, maxDynMemMb * MEGABYTE); } public void setActionsAfterCrash(CrashedAction actionsAfterCrash) throws BadAPICallException { this.actionsAfterCrash = setter(actionsAfterCrash, "set_actions_after_crash"); } public void setActionsAfterReboot(ShutdownAction actionsAfterReboot) throws BadAPICallException { this.actionsAfterReboot = setter(actionsAfterReboot, "set_actions_after_reboot"); } public void setActionsAfterShutdown(ShutdownAction actionsAfterShutdown) throws BadAPICallException { this.actionsAfterShutdown = setter(actionsAfterShutdown, "set_actions_after_shutdown"); } public String getHVMBootPolicy() { return hvmBootPolicy; } public void setDefaultHVMBootPolicy() throws BadAPICallException { setHVMBootPolicy("BIOS order"); } public void setHVMBootPolicy(String policy) throws BadAPICallException { this.hvmBootPolicy = setter(policy, "set_HVM_boot_policy"); } public Map<String, String> getHVMBootParams() { return hvmBootParams; } public void setHVMBootParams(Map<String, String> params) throws BadAPICallException { this.hvmBootParams = setter(params, "set_HVM_boot_params"); } public Platform getPlatform() { return new Platform(platform); } public void setPlatform(Platform platform) throws BadAPICallException { this.platform = setter(platform.getMap(), "set_platform"); } public String getPVargs() { return pvArgs; } public String getPVBootloader() { return pvBootloader; } public void setPVBootloader(String bootloader) throws BadAPICallException { this.pvBootloader = setter(bootloader, "set_PV_bootloader"); } public String getPVBootloaderArgs() { return pvBootloader; } public void setPVBootloaderArgs(String bootloaderargs) throws BadAPICallException { this.pvBootloaderArgs = setter(bootloaderargs, "set_PV_bootloader_args"); } public String getPVKernel() { return pvKernel; } public void setPVKernel(String kernel) throws BadAPICallException { this.pvKernel = setter(kernel, "set_PV_kernel"); } public String getPVRamdisk() { return pvRamdisk; } public void setPVRamdisk(String ramdisk) throws BadAPICallException { this.pvRamdisk = setter(ramdisk, "set_PV_ramdisk"); } public CrashedAction getActionsAfterCrash() { return actionsAfterCrash; } public ShutdownAction getActionsAfterReboot() { return actionsAfterReboot; } public ShutdownAction getActionsAfterShutdown() { return actionsAfterShutdown; } public boolean isAutoPowerOn() { return autoPowerOn; } public int getDomainId() { return domainId; } public boolean isControlDomain() { return controlDomain; } public boolean isTemplate() { return template; } public int getMaximumVCPUs() { return maxVCPUs; } public int getStartupVCPUs() { return value(startupVCPUs, "getVCPUs_at_startup"); } public void setStartupVCPUs(int startupVCPUs) throws BadAPICallException { this.startupVCPUs = setter(startupVCPUs, "set_VCPUs_at_startup"); } public long getMaximumDynamicMemory() { return maximumDynamicMemory; } public void setMaximumDynamicMemory(double mdmMb) throws BadAPICallException { this.maximumDynamicMemory = setter((long) mdmMb * MEGABYTE, "set_memory_dynamic_max"); } public long getMaximumStaticMemory() { return value(maximumStaticMemory, "get_memory_static_max"); } public void setMaximumStaticMemory(double msmMb) throws BadAPICallException { this.maximumStaticMemory = setter((long) msmMb * MEGABYTE, "set_memory_static_max"); } public long getMinimumStaticMemory() { return minimumStaticMemory; } public String getPoolName() { poolName = value(poolName, "get_pool_name"); return poolName; } public PowerState getPowerState() { powerState = value(powerState, "get_power_state"); return powerState; } public int getVCPUs() { return startupVCPUs; } public void setVCPUs(int count, boolean live) throws BadAPICallException { if (getPowerState() == PowerState.RUNNING && live) { dispatch("set_VCPUs_number_live", count); startupVCPUs = count; } else { startupVCPUs = count; } } public int getUserVersion() { return userVersion; } public Host getHost() { return new Host(value(host, "get_resident_on")); } public Host getAffinityHost() { return new Host(hostAffinity); } @Override protected Map<String, String> interpretation() { HashMap<String, String> map = (HashMap<String, String>) super.interpretation(); map.put("startupVCPUcount", "VCPUs_at_startup"); map.put("minimumStaticMemory", "memory_static_min"); map.put("maximumStaticMemory", "memory_static_max"); map.put("maximumDynamicMemory", "memory_dynamic_max"); map.put("minimumDynamicMemory", "memory_dynamic_min"); map.put("template", "is_a_template"); map.put("controlDomain", "is_control_domain"); map.put("domainId", "domid"); map.put("pvArgs", "PV_args"); map.put("pvRamdisk", "PV_ramdisk"); map.put("pvKernel", "PV_kernel"); map.put("pvBootloader", "PV_bootloader"); map.put("pvBootloaderArgs", "PV_bootloader_args"); map.put("hvmBootPolicy", "HVM_boot_policy"); map.put("hvmBootParams", "HVM_boot_params"); map.put("startupVCPUs", "VCPUs_at_startup"); map.put("maxVCPUs", "VCPUs_max"); map.put("host", "resident_on"); map.put("hostAffinity", "affinity"); map.put("vcpuParams", "VCPUs_params"); map.put("pciBus", "PCI_bus"); return map; } public enum ShutdownAction { /** * The value does not belong to this enumeration */ UNRECOGNIZED, /** * destroy the VM state */ DESTROY, /** * restart the VM */ RESTART }; public enum CrashedAction { /** * The value does not belong to this enumeration */ UNRECOGNIZED, /** * destroy the VM state */ DESTROY, /** * record a coredump and then destroy the VM state */ COREDUMP_AND_DESTROY, /** * restart the VM */ RESTART, /** * record a coredump and then restart the VM */ COREDUMP_AND_RESTART, /** * leave the crashed VM paused */ PRESERVE, /** * rename the crashed VM and start a new copy */ RENAME_RESTART }; public enum PowerState { /** * The value does not belong to this enumeration */ UNRECOGNIZED, /** * VM is offline and not using any resources */ HALTED, /** * All resources have been allocated but the VM itself is paused and its vCPUs are not running */ PAUSED, /** * Running */ RUNNING, /** * VM state has been saved to disk and it is no longer running. Note that disks remain in-use while the VM is suspended. */ SUSPENDED }; }