diff --git a/.gitignore b/.gitignore index 81eba9119a3..d7723b24bc6 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ dist/ *.bak cloud-*.tar.bz2 *.log +*.pyc +build.number diff --git a/api/src/com/cloud/hypervisor/Hypervisor.java b/api/src/com/cloud/hypervisor/Hypervisor.java index 36ef21f035b..c938bba26e4 100644 --- a/api/src/com/cloud/hypervisor/Hypervisor.java +++ b/api/src/com/cloud/hypervisor/Hypervisor.java @@ -24,7 +24,8 @@ public class Hypervisor { Xen, XenServer, KVM, - VMware; + VmWare, + VirtualBox, + Parralels; } - } diff --git a/api/src/com/cloud/storage/Volume.java b/api/src/com/cloud/storage/Volume.java index 3f6d9b1013e..c7a981eeb41 100755 --- a/api/src/com/cloud/storage/Volume.java +++ b/api/src/com/cloud/storage/Volume.java @@ -23,7 +23,7 @@ import com.cloud.user.OwnedBy; public interface Volume extends PartOf, OwnedBy, BasedOn { - enum VolumeType {UNKNOWN, ROOT, SWAP, DATADISK}; + enum VolumeType {UNKNOWN, ROOT, SWAP, DATADISK, ISO}; enum MirrorState {NOT_MIRRORED, ACTIVE, DEFUNCT}; diff --git a/api/src/com/cloud/template/VirtualMachineTemplate.java b/api/src/com/cloud/template/VirtualMachineTemplate.java index 8259206f52c..0cdffe856d8 100755 --- a/api/src/com/cloud/template/VirtualMachineTemplate.java +++ b/api/src/com/cloud/template/VirtualMachineTemplate.java @@ -21,7 +21,7 @@ import com.cloud.storage.Storage.FileSystem; public interface VirtualMachineTemplate { - public static enum BootloaderType { PyGrub, HVM, External }; + public static enum BootloaderType { PyGrub, HVM, External, CD }; /** * @return id. diff --git a/api/src/com/cloud/vm/NetworkConcierge.java b/api/src/com/cloud/vm/NetworkConcierge.java index 03ab6fae6df..92f99fdb2ed 100644 --- a/api/src/com/cloud/vm/NetworkConcierge.java +++ b/api/src/com/cloud/vm/NetworkConcierge.java @@ -17,7 +17,7 @@ import com.cloud.utils.component.Adapter; public interface NetworkConcierge extends Adapter { String getUniqueName(); - Pair reserve(long vmId, NetworkCharacteristics ch) throws InsufficientVirtualNetworkCapcityException; + Pair reserve(long vmId, NetworkCharacteristics ch) throws InsufficientVirtualNetworkCapcityException; boolean release(String uniqueName, String uniqueId); } diff --git a/build/build-cloud.xml b/build/build-cloud.xml index 09899cf25c5..db9e5a7c5af 100755 --- a/build/build-cloud.xml +++ b/build/build-cloud.xml @@ -101,7 +101,7 @@ - + @@ -137,7 +137,7 @@ - + @@ -176,7 +176,7 @@ - + @@ -223,7 +223,6 @@ - @@ -237,11 +236,15 @@ - + + + + + @@ -252,46 +255,41 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - @@ -305,12 +303,12 @@ - + - - - - + + + + @@ -344,7 +342,7 @@ - + @@ -518,20 +516,20 @@ - - - + + + - - - - - - - - - - + + + + + + + + + + @@ -563,8 +561,8 @@ - - + + diff --git a/build/build.number b/build/build.number deleted file mode 100644 index 0216cfc6927..00000000000 --- a/build/build.number +++ /dev/null @@ -1,3 +0,0 @@ -#Build Number for ANT. Do not edit! -#Thu Aug 19 09:21:10 PDT 2010 -build.number=65 diff --git a/build/package.xml b/build/package.xml index a8995cd2349..82781c61a2f 100755 --- a/build/package.xml +++ b/build/package.xml @@ -135,7 +135,7 @@ - + diff --git a/ui/resources/resource.properties b/client/WEB-INF/classes/resources/resource.properties similarity index 100% rename from ui/resources/resource.properties rename to client/WEB-INF/classes/resources/resource.properties diff --git a/ui/resources/resource_zh.properties b/client/WEB-INF/classes/resources/resource_zh.properties similarity index 100% rename from ui/resources/resource_zh.properties rename to client/WEB-INF/classes/resources/resource_zh.properties diff --git a/client/bindir/cloud-update-xenserver-licenses.in b/client/bindir/cloud-update-xenserver-licenses.in index 6249f7805fe..94b8e3e8ceb 100755 --- a/client/bindir/cloud-update-xenserver-licenses.in +++ b/client/bindir/cloud-update-xenserver-licenses.in @@ -125,7 +125,7 @@ except IndexError: e("The first argument must be the license file to use") if options.all: if len(args) != 0: e("IP addresses cannot be specified if -a is specified") - config = cloud_utils.read_properties(cfg) + config = read_properties(cfg) creds = getknownhosts(config["db.cloud.host"],config["db.cloud.username"],config["db.cloud.password"]) hosts = creds.keys() else: diff --git a/cloud.spec b/cloud.spec index b164ab03b7e..fd215a8ddfa 100644 --- a/cloud.spec +++ b/cloud.spec @@ -232,6 +232,9 @@ Requires: %{name}-daemonize Requires: /sbin/service Requires: /sbin/chkconfig Requires: kvm +%if 0%{?fedora} >= 13 +Requires: cloud-qemu-system-x86 +%endif Requires: libcgroup Requires: /usr/bin/uuidgen Requires: augeas >= 0.7.1 diff --git a/core/src/com/cloud/agent/api/Start2Answer.java b/core/src/com/cloud/agent/api/Start2Answer.java new file mode 100644 index 00000000000..7b6ec6eb740 --- /dev/null +++ b/core/src/com/cloud/agent/api/Start2Answer.java @@ -0,0 +1,21 @@ +/** + * + */ +package com.cloud.agent.api; + +public class Start2Answer extends Answer { + protected Start2Answer() { + } + + public Start2Answer(Start2Command cmd, String msg) { + super(cmd, false, msg); + } + + public Start2Answer(Start2Command cmd, Exception e) { + super(cmd, false, e.getMessage()); + } + + public Start2Answer(Start2Command cmd) { + super(cmd, true, null); + } +} diff --git a/core/src/com/cloud/agent/api/Start2Command.java b/core/src/com/cloud/agent/api/Start2Command.java new file mode 100644 index 00000000000..4414b888d44 --- /dev/null +++ b/core/src/com/cloud/agent/api/Start2Command.java @@ -0,0 +1,62 @@ +/** + * + */ +package com.cloud.agent.api; + +import com.cloud.agent.api.to.VirtualMachineTO; + +public class Start2Command extends Command { + VirtualMachineTO vm; + + public VirtualMachineTO getVirtualMachine() { + return vm; + } + + /* + long id; + String guestIpAddress; + String gateway; + int ramSize; + String imagePath; + String guestNetworkId; + String guestMacAddress; + String vncPassword; + String externalVlan; + String externalMacAddress; + int utilization; + int cpuWeight; + int cpu; + int networkRateMbps; + int networkRateMulticastMbps; + String hostName; + String arch; + String isoPath; + boolean bootFromISO; + String guestOSDescription; + + ---->console proxy + private ConsoleProxyVO proxy; + private int proxyCmdPort; + private String vncPort; + private String urlPort; + private String mgmt_host; + private int mgmt_port; + private boolean sslEnabled; + + ----->abstract + protected String vmName; + protected String storageHosts[] = new String[2]; + protected List volumes; + protected boolean mirroredVols = false; + protected BootloaderType bootloader = BootloaderType.PyGrub; + + */ + + @Override + public boolean executeInSequence() { + return true; + } + + public Start2Command() { + } +} diff --git a/core/src/com/cloud/agent/api/to/HostTO.java b/core/src/com/cloud/agent/api/to/HostTO.java index 717412f4c1e..91cfa65437e 100644 --- a/core/src/com/cloud/agent/api/to/HostTO.java +++ b/core/src/com/cloud/agent/api/to/HostTO.java @@ -18,7 +18,6 @@ package com.cloud.agent.api.to; import com.cloud.host.HostVO; -import com.cloud.vm.NetworkTO; public class HostTO { private String guid; diff --git a/api/src/com/cloud/vm/NetworkTO.java b/core/src/com/cloud/agent/api/to/NetworkTO.java similarity index 60% rename from api/src/com/cloud/vm/NetworkTO.java rename to core/src/com/cloud/agent/api/to/NetworkTO.java index 844b1943e12..d6e428831f3 100644 --- a/api/src/com/cloud/vm/NetworkTO.java +++ b/core/src/com/cloud/agent/api/to/NetworkTO.java @@ -15,7 +15,10 @@ * along with this program. If not, see . * */ -package com.cloud.vm; +package com.cloud.agent.api.to; + +import com.cloud.network.Network.BroadcastDomainType; +import com.cloud.network.Network.TrafficType; /** * Transfer object to transfer network settings. @@ -28,11 +31,65 @@ public class NetworkTO { private String mac; private String dns1; private String dns2; - private String vlan; + private Long vlan; + private BroadcastDomainType broadcastType; + private TrafficType type; - protected NetworkTO() { + public NetworkTO() { } + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public Long getVlan() { + return vlan; + } + + public void setVlan(Long vlan) { + this.vlan = vlan; + } + + public BroadcastDomainType getBroadcastType() { + return broadcastType; + } + + public void setBroadcastType(BroadcastDomainType broadcastType) { + this.broadcastType = broadcastType; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public void setNetmask(String netmask) { + this.netmask = netmask; + } + + public void setGateway(String gateway) { + this.gateway = gateway; + } + + public void setMac(String mac) { + this.mac = mac; + } + + public void setDns1(String dns1) { + this.dns1 = dns1; + } + + public void setDns2(String dns2) { + this.dns2 = dns2; + } + + public void setType(TrafficType type) { + this.type = type; + } + /** * This constructor is usually for hosts where the other information are not important. * @@ -56,7 +113,7 @@ public class NetworkTO { * @param dns1 * @param dns2 */ - public NetworkTO(String ip, String vlan, String netmask, String mac, String gateway, String dns1, String dns2) { + public NetworkTO(String ip, Long vlan, String netmask, String mac, String gateway, String dns1, String dns2) { this.ip = ip; this.netmask = netmask; this.mac = mac; @@ -89,4 +146,8 @@ public class NetworkTO { public String getDns2() { return dns2; } + + public TrafficType getType() { + return type; + } } diff --git a/core/src/com/cloud/agent/api/to/NicTO.java b/core/src/com/cloud/agent/api/to/NicTO.java new file mode 100644 index 00000000000..42e4f66bd94 --- /dev/null +++ b/core/src/com/cloud/agent/api/to/NicTO.java @@ -0,0 +1,36 @@ +/** + * + */ +package com.cloud.agent.api.to; + +public class NicTO extends NetworkTO { + int deviceId; + Integer controlPort; + Integer networkRateMbps; + Integer networkRateMulticastMbps; + + public NicTO() { + super(); + controlPort = null; + } + + public void setDeviceId(int deviceId) { + this.deviceId = deviceId; + } + + public int getDeviceId() { + return deviceId; + } + + public Integer getControlPort() { + return controlPort; + } + + public Integer getNetworkRateMbps() { + return networkRateMbps; + } + + public Integer getNetworkRateMulticastMbps() { + return networkRateMulticastMbps; + } +} diff --git a/core/src/com/cloud/agent/api/to/VirtualMachineTO.java b/core/src/com/cloud/agent/api/to/VirtualMachineTO.java new file mode 100644 index 00000000000..b37c2fd2426 --- /dev/null +++ b/core/src/com/cloud/agent/api/to/VirtualMachineTO.java @@ -0,0 +1,173 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It 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 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 . + * + */ +package com.cloud.agent.api.to; + +import java.util.Map; + +import com.cloud.template.VirtualMachineTemplate.BootloaderType; +import com.cloud.vm.VirtualMachine.Type; + +public class VirtualMachineTO { + private long id; + private String name; + private BootloaderType bootloader; + Type type; + int cpus; + Integer weight; + Integer utilization; + long minRam; + long maxRam; + String hostName; + String arch; + String os; + String bootArgs; + String[] bootupScripts; + boolean rebootOnCrash; + + VolumeTO[] disks; + NicTO[] nics; + + public VirtualMachineTO() { + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Type getType() { + return type; + } + + public BootloaderType getBootloader() { + return bootloader; + } + + public void setBootloader(BootloaderType bootloader) { + this.bootloader = bootloader; + } + + public int getCpus() { + return cpus; + } + + public void setCpus(int cpus) { + this.cpus = cpus; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getUtilization() { + return utilization; + } + + public void setUtiliziation(Integer utilization) { + this.utilization = utilization; + } + + public long getMinRam() { + return minRam; + } + + public void setRam(long minRam, long maxRam) { + this.minRam = minRam; + this.maxRam = maxRam; + } + + public long getMaxRam() { + return maxRam; + } + + public String getHostName() { + return hostName; + } + + public void setHostName(String hostName) { + this.hostName = hostName; + } + + public String getArch() { + return arch; + } + + public void setArch(String arch) { + this.arch = arch; + } + + public String getOs() { + return os; + } + + public void setOs(String os) { + this.os = os; + } + + public String getBootArgs() { + return bootArgs; + } + + public void setBootArgs(Map bootParams) { + StringBuilder buf = new StringBuilder(); + for (Map.Entry entry : bootParams.entrySet()) { + buf.append(" ").append(entry.getKey()).append("=").append(entry.getValue()); + } + bootArgs = buf.toString(); + } + + public String[] getBootupScripts() { + return bootupScripts; + } + + public void setBootupScripts(String[] bootupScripts) { + this.bootupScripts = bootupScripts; + } + + public VolumeTO[] getDisks() { + return disks; + } + + public void setDisks(VolumeTO[] disks) { + this.disks = disks; + } + + public NicTO[] getNetworks() { + return nics; + } + + public void setNics(NicTO[] nics) { + this.nics = nics; + } + +} diff --git a/core/src/com/cloud/agent/api/to/VmTO.java b/core/src/com/cloud/agent/api/to/VmTO.java deleted file mode 100644 index 5cacc391a1c..00000000000 --- a/core/src/com/cloud/agent/api/to/VmTO.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. - * - * This software is licensed under the GNU General Public License v3 or later. - * - * It 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 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 . - * - */ -package com.cloud.agent.api.to; - -import com.cloud.vm.NetworkTO; -import com.cloud.vm.VMInstanceVO; - -public class VmTO { - private long id; - private String name; - NetworkTO[] networks; - - public VmTO() { - } - - // FIXME: Preferrably NetworkTO is constructed inside the TO objects. - // But we're press for time so I'm going to let the conversion - // happen outside. - public VmTO(VMInstanceVO instance, NetworkTO[] networks) { - id = instance.getId(); - name = instance.getName(); - this.networks = networks; - } - -} diff --git a/core/src/com/cloud/agent/api/to/VolumeTO.java b/core/src/com/cloud/agent/api/to/VolumeTO.java index 39561f9d310..15853b13098 100644 --- a/core/src/com/cloud/agent/api/to/VolumeTO.java +++ b/core/src/com/cloud/agent/api/to/VolumeTO.java @@ -18,12 +18,11 @@ package com.cloud.agent.api.to; import com.cloud.storage.Storage; -import com.cloud.storage.Storage.StorageResourceType; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; -import com.cloud.storage.Storage.StoragePoolType; public class VolumeTO { @@ -39,6 +38,7 @@ public class VolumeTO { private Storage.StorageResourceType resourceType; private StoragePoolType storagePoolType; private long poolId; + private int deviceId; public VolumeTO(long id, Volume.VolumeType type, Storage.StorageResourceType resourceType, StoragePoolType poolType, String name, String mountPoint, String path, long size) { this.id = id; @@ -70,6 +70,10 @@ public class VolumeTO { this.storagePoolType = pool.getPoolType(); this.mountPoint = pool.getPath(); } + + public int getDeviceId() { + return deviceId; + } public Storage.StorageResourceType getResourceType() { return resourceType; diff --git a/core/src/com/cloud/consoleproxy/ConsoleProxyManager.java b/core/src/com/cloud/consoleproxy/ConsoleProxyManager.java deleted file mode 100644 index ca36c338f82..00000000000 --- a/core/src/com/cloud/consoleproxy/ConsoleProxyManager.java +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. - * - * This software is licensed under the GNU General Public License v3 or later. - * - * It 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 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 . - * - */ - -package com.cloud.consoleproxy; - -import com.cloud.agent.api.AgentControlAnswer; -import com.cloud.agent.api.ConsoleAccessAuthenticationCommand; -import com.cloud.agent.api.ConsoleProxyLoadReportCommand; -import com.cloud.agent.api.StartupCommand; -import com.cloud.host.HostVO; -import com.cloud.host.Status; -import com.cloud.utils.component.Manager; -import com.cloud.vm.ConsoleProxyVO; - -public interface ConsoleProxyManager extends Manager { - public static final int DEFAULT_PROXY_CAPACITY = 50; - public static final int DEFAULT_STANDBY_CAPACITY = 10; - public static final int DEFAULT_PROXY_VM_RAMSIZE = 1024; // 1G - - public static final int DEFAULT_PROXY_CMD_PORT = 8001; - public static final int DEFAULT_PROXY_VNC_PORT = 0; - public static final int DEFAULT_PROXY_URL_PORT = 80; - public static final int DEFAULT_PROXY_SESSION_TIMEOUT = 300000; // 5 minutes - - public static final String ALERT_SUBJECT = "proxy-alert"; - - public ConsoleProxyVO assignProxy(long dataCenterId, long userVmId); - - public ConsoleProxyVO startProxy(long proxyVmId, long startEventId); - public boolean stopProxy(long proxyVmId, long startEventId); - public boolean rebootProxy(long proxyVmId, long startEventId); - public boolean destroyProxy(long proxyVmId, long startEventId); - - public void onLoadReport(ConsoleProxyLoadReportCommand cmd); - public AgentControlAnswer onConsoleAccessAuthentication(ConsoleAccessAuthenticationCommand cmd); - - public void onAgentConnect(HostVO host, StartupCommand cmd); - public void onAgentDisconnect(long agentId, Status state); -} diff --git a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 21660ef71cb..bfda859aa7d 100644 --- a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -104,6 +104,8 @@ import com.cloud.agent.api.RebootCommand; import com.cloud.agent.api.RebootRouterCommand; import com.cloud.agent.api.SetupAnswer; import com.cloud.agent.api.SetupCommand; +import com.cloud.agent.api.Start2Answer; +import com.cloud.agent.api.Start2Command; import com.cloud.agent.api.StartAnswer; import com.cloud.agent.api.StartCommand; import com.cloud.agent.api.StartConsoleProxyAnswer; @@ -141,22 +143,26 @@ import com.cloud.agent.api.storage.DownloadAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; import com.cloud.agent.api.storage.ShareAnswer; import com.cloud.agent.api.storage.ShareCommand; +import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.StoragePoolTO; +import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.api.to.VolumeTO; import com.cloud.exception.InternalErrorException; import com.cloud.host.Host.Type; import com.cloud.hypervisor.Hypervisor; +import com.cloud.network.Network.BroadcastDomainType; +import com.cloud.network.Network.TrafficType; import com.cloud.resource.ServerResource; import com.cloud.storage.Storage; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.StoragePoolType; -import com.cloud.storage.Storage.StorageResourceType; import com.cloud.storage.StorageLayer; import com.cloud.storage.StoragePoolVO; import com.cloud.storage.Volume.VolumeType; import com.cloud.storage.VolumeVO; import com.cloud.storage.resource.StoragePoolResource; import com.cloud.storage.template.TemplateInfo; +import com.cloud.template.VirtualMachineTemplate.BootloaderType; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; @@ -169,6 +175,7 @@ import com.cloud.vm.DiskCharacteristics; import com.cloud.vm.DomainRouter; import com.cloud.vm.SecondaryStorageVmVO; import com.cloud.vm.State; +import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineName; import com.trilead.ssh2.SCPClient; import com.xensource.xenapi.APIVersion; @@ -683,10 +690,377 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR return execute((ModifySshKeysCommand) cmd); } else if (cmd instanceof PoolEjectCommand) { return execute((PoolEjectCommand) cmd); + } else if (cmd instanceof Start2Command) { + return execute((Start2Command)cmd); } else { return Answer.createUnsupportedCommandAnswer(cmd); } } + + Pair getNetworkForTraffic(Connection conn, TrafficType type) throws XenAPIException, XmlRpcException { + if (type == TrafficType.Guest) { + return new Pair(Network.getByUuid(conn, _host.guestNetwork), _host.guestPif); + } else if (type == TrafficType.LinkLocal) { + return new Pair(Network.getByUuid(conn, _host.linkLocalNetwork), null); + } else if (type == TrafficType.Management) { + return new Pair(Network.getByUuid(conn, _host.privateNetwork), _host.privatePif); + } else if (type == TrafficType.Public) { + return new Pair(Network.getByUuid(conn, _host.publicNetwork), _host.publicPif); + } else if (type == TrafficType.Storage) { + return new Pair(Network.getByUuid(conn, _host.storageNetwork1), _host.storagePif1); + } else if (type == TrafficType.Vpn) { + return new Pair(Network.getByUuid(conn, _host.publicNetwork), _host.publicPif); + } + + throw new CloudRuntimeException("Unsupported network type: " + type); + } + + protected VIF createVif(Connection conn, String vmName, VM vm, NicTO nic) throws XmlRpcException, XenAPIException { + VIF.Record vifr = new VIF.Record(); + vifr.VM = vm; + vifr.device = Integer.toString(nic.getDeviceId()); + vifr.MAC = nic.getMac(); + + Pair network = getNetworkForTraffic(conn, nic.getType()); + if (nic.getBroadcastType() == BroadcastDomainType.Vlan) { + vifr.network = enableVlanNetwork(conn, nic.getVlan(), network.first(), network.second()); + } else { + vifr.network = network.first(); + } + + if (nic.getNetworkRateMbps() != null) { + vifr.qosAlgorithmType = "ratelimit"; + vifr.qosAlgorithmParams = new HashMap(); + vifr.qosAlgorithmParams.put("kbps", Integer.toString(nic.getNetworkRateMbps() * 1000)); + } + + VIF vif = VIF.create(conn, vifr); + if (s_logger.isDebugEnabled()) { + vifr = vif.getRecord(conn); + s_logger.debug("Created a vif " + vifr.uuid + " on " + nic.getDeviceId()); + } + + return vif; + } + + protected VDI mount(Connection conn, String vmName, VolumeTO volume) throws XmlRpcException, XenAPIException { + if (volume.getType() == VolumeType.ISO) { + String isopath = volume.getPath(); + int index = isopath.lastIndexOf("/"); + + String mountpoint = isopath.substring(0, index); + URI uri; + try { + uri = new URI(mountpoint); + } catch (URISyntaxException e) { + throw new CloudRuntimeException("Incorrect uri " + mountpoint, e); + } + SR isoSr = createIsoSRbyURI(uri, vmName, false); + + String isoname = isopath.substring(index + 1); + + VDI isoVdi = getVDIbyLocationandSR(isoname, isoSr); + + if (isoVdi == null) { + throw new CloudRuntimeException("Unable to find ISO " + volume.getPath()); + } + return isoVdi; + } else { + return VDI.getByUuid(conn, volume.getPath()); + } + } + + protected VBD createVbd(Connection conn, String vmName, VM vm, VolumeTO volume, boolean patch) throws XmlRpcException, XenAPIException { + VolumeType type = volume.getType(); + + VDI vdi = mount(conn, vmName, volume); + + if (patch) { + if (!patchSystemVm(vdi, vmName)) { + throw new CloudRuntimeException("Unable to patch system vm"); + } + } + + VBD.Record vbdr = new VBD.Record(); + vbdr.VM = vm; + vbdr.VDI = vdi; + if (type == VolumeType.ROOT) { + vbdr.bootable = true; + } + vbdr.userdevice = Long.toString(volume.getDeviceId()); + if (volume.getType() == VolumeType.ISO) { + vbdr.mode = Types.VbdMode.RO; + vbdr.type = Types.VbdType.CD; + } else { + vbdr.mode = Types.VbdMode.RW; + vbdr.type = Types.VbdType.DISK; + + } + + VBD vbd = VBD.create(conn, vbdr); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("VBD " + vbd.getUuid(conn) + " created for " + volume); + } + + return vbd; + } + + protected Pair createVmFromTemplate(Connection conn, VirtualMachineTO vmSpec, Host host) throws XenAPIException, XmlRpcException { + String guestOsTypeName = getGuestOsType(vmSpec.getOs()); + 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 vm = template.createClone(conn, vmSpec.getName()); + vm.setAffinity(conn, host); + + VM.Record vmr = vm.getRecord(conn); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Created VM " + vmr.uuid + " for " + vmSpec.getName()); + } + + for (Console console : vmr.consoles) { + console.destroy(conn); + } + + vm.setIsATemplate(conn, false); + vm.removeFromOtherConfig(conn, "disks"); + vm.setNameLabel(conn, vmSpec.getName()); + setMemory(conn, vm, vmSpec.getMinRam()); + vm.setVCPUsAtStartup(conn, (long)vmSpec.getCpus()); + vm.setVCPUsMax(conn, (long)vmSpec.getCpus()); + vm.setVCPUsNumberLive(conn, (long)vmSpec.getCpus()); + + Map vcpuParams = new HashMap(); + + if (vmSpec.getWeight() != null) { + vcpuParams.put("weight", Integer.toString(vmSpec.getWeight())); + } + if (vmSpec.getUtilization() != null) { + vcpuParams.put("cap", Integer.toString(vmSpec.getUtilization())); + } + if (vcpuParams.size() > 0) { + vm.setVCPUsParams(conn, vcpuParams); + } + + vm.setActionsAfterCrash(conn, Types.OnCrashBehaviour.DESTROY); + vm.setActionsAfterShutdown(conn, Types.OnNormalExit.DESTROY); + + 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) { + vm.setPVBootloader(conn, "eliloader"); + 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 new Pair(vm, vmr.uuid); + } + + protected String handleVmStartFailure(String vmName, VM vm, String message, Throwable th) { + String msg = "Unable to start " + vmName + " due to " + message; + s_logger.warn(msg, th); + + if (vm == null) { + return msg; + } + + Connection conn = getConnection(); + try { + VM.Record vmr = vm.getRecord(conn); + if (vmr.powerState == VmPowerState.RUNNING) { + try { + vm.hardShutdown(conn); + } catch (Exception e) { + s_logger.warn("VM hardshutdown failed due to ", e); + } + } + if (vm.getPowerState(conn) == VmPowerState.HALTED) { + try { + vm.destroy(conn); + } catch (Exception e) { + s_logger.warn("VM destroy failed due to ", e); + } + } + for (VBD vbd : vmr.VBDs) { + try { + vbd.unplug(conn); + vbd.destroy(conn); + } catch (Exception e) { + s_logger.warn("Unable to clean up VBD due to ", e); + } + } + for (VIF vif : vmr.VIFs) { + try { + vif.unplug(conn); + vif.destroy(conn); + } catch (Exception e) { + s_logger.warn("Unable to cleanup VIF", e); + } + } + } catch (Exception e) { + s_logger.warn("VM getRecord failed due to ", e); + } + + return msg; + } + + protected Start2Answer execute(Start2Command cmd) { + VirtualMachineTO vmSpec = cmd.getVirtualMachine(); + String vmName = vmSpec.getName(); + + Connection conn = getConnection(); + State state = State.Stopped; + VM vm = null; + try { + Host host = Host.getByUuid(conn, _host.uuid); + synchronized (_vms) { + _vms.put(vmName, State.Starting); + } + + Pair v = createVmFromTemplate(conn, vmSpec, host); + vm = v.first(); + String vmUuid = v.second(); + + for (VolumeTO disk : vmSpec.getDisks()) { + createVbd(conn, vmName, vm, disk, disk.getType() == VolumeType.ROOT && vmSpec.getType() != VirtualMachine.Type.User); + } + + NicTO controlNic = null; + for (NicTO nic : vmSpec.getNetworks()) { + if (nic.getControlPort() != null) { + controlNic = nic; + } + createVif(conn, vmName, vm, nic); + } + + /* + * + VBD.Record vbdr = new VBD.Record(); + Ternary mount = mounts.get(0); + vbdr.VM = vm; + vbdr.VDI = mount.second(); + vbdr.bootable = !bootFromISO; + vbdr.userdevice = "0"; + vbdr.mode = Types.VbdMode.RW; + vbdr.type = Types.VbdType.DISK; + VBD.create(conn, vbdr); + + for (int i = 1; i < mounts.size(); i++) { + mount = mounts.get(i); + // vdi.setNameLabel(conn, cmd.getVmName() + "-DATA"); + vbdr.VM = vm; + vbdr.VDI = mount.second(); + vbdr.bootable = false; + vbdr.userdevice = Long.toString(mount.third().getDeviceId()); + vbdr.mode = Types.VbdMode.RW; + vbdr.type = Types.VbdType.DISK; + vbdr.unpluggable = true; + VBD.create(conn, vbdr); + + } + + VBD.Record cdromVBDR = new VBD.Record(); + cdromVBDR.VM = vm; + cdromVBDR.empty = true; + cdromVBDR.bootable = bootFromISO; + cdromVBDR.userdevice = "3"; + cdromVBDR.mode = Types.VbdMode.RO; + cdromVBDR.type = Types.VbdType.CD; + VBD cdromVBD = VBD.create(conn, cdromVBDR); + + String isopath = cmd.getISOPath(); + if (isopath != null) { + int index = isopath.lastIndexOf("/"); + + String mountpoint = isopath.substring(0, index); + URI uri = new URI(mountpoint); + isosr = createIsoSRbyURI(uri, cmd.getVmName(), false); + + String isoname = isopath.substring(index + 1); + + VDI isovdi = getVDIbyLocationandSR(isoname, isosr); + + if (isovdi == null) { + String msg = " can not find ISO " + cmd.getISOPath(); + s_logger.warn(msg); + return new StartAnswer(cmd, msg); + } else { + cdromVBD.insert(conn, isovdi); + } + + } + */ + + vm.startOn(conn, host, false, true); + + if (_canBridgeFirewall) { + String result = null; + if (vmSpec.getType() != VirtualMachine.Type.User) { + result = callHostPlugin("vmops", "default_network_rules_systemvm", "vmName", vmName); + } else { + } + + if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) { + s_logger.warn("Failed to program default network rules for " + vmName); + } else { + s_logger.info("Programmed default network rules for " + vmName); + } + } + + if (controlNic != null) { + String privateIp = controlNic.getIp(); + int cmdPort = controlNic.getControlPort(); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Ping command port, " + privateIp + ":" + cmdPort); + } + + String result = connect(vmName, privateIp, cmdPort); + if (result != null) { + throw new CloudRuntimeException("Can not ping System vm " + vmName + "due to:" + result); + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("Ping command port succeeded for vm " + vmName); + } + } + + state = State.Running; + return new Start2Answer(cmd); + } catch (XmlRpcException e) { + String msg = handleVmStartFailure(vmName, vm, "", e); + return new Start2Answer(cmd, msg); + } catch (XenAPIException e) { + String msg = handleVmStartFailure(vmName, vm, "", e); + return new Start2Answer(cmd, msg); + } catch (Exception e) { + String msg = handleVmStartFailure(vmName, vm, "", e); + return new Start2Answer(cmd, msg); + } finally { + synchronized (_vms) { + if (state != State.Stopped) { + _vms.put(vmName, state); + } else { + _vms.remove(vmName); + } + } + } + } protected Answer execute(ModifySshKeysCommand cmd) { String publickey = cmd.getPubKey(); @@ -1695,6 +2069,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR } } + @Override public DownloadAnswer execute(final PrimaryStorageDownloadCommand cmd) { SR tmpltsr = null; String tmplturl = cmd.getUrl(); @@ -3292,6 +3667,45 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR return null; } + protected synchronized Network getNetworkByName(Connection conn, String name, boolean lookForPif) throws XenAPIException, XmlRpcException { + Network found = null; + Set networks = Network.getByNameLabel(conn, name); + if (networks.size() == 1) { + found = networks.iterator().next(); + } else if (networks.size() > 1) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Found more than one network with the name " + name); + } + for (Network network : networks) { + if (!lookForPif) { + found = network; + break; + } + + Network.Record netr = network.getRecord(conn); + s_logger.debug("Checking network " + netr.uuid); + if (netr.PIFs.size() == 0) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Network " + netr.uuid + " has no pifs so skipping that."); + } + } else { + for (PIF pif : netr.PIFs) { + PIF.Record pifr = pif.getRecord(conn); + if (_host.uuid.equals(pifr.host.getUuid(conn))) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Network " + netr.uuid + " has a pif " + pifr.uuid + " for our host "); + } + found = network; + break; + } + } + } + } + } + + return found; + } + protected Network enableVlanNetwork(long tag, String networkUuid, String pifUuid) throws XenAPIException, XmlRpcException { // In XenServer, vlan is added by // 1. creating a network. @@ -3344,6 +3758,60 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR return vlanNetwork; } + protected Network enableVlanNetwork(Connection conn, long tag, Network network, String pifUuid) throws XenAPIException, XmlRpcException { + // In XenServer, vlan is added by + // 1. creating a network. + // 2. creating a vlan associating network with the pif. + // We always create + // 1. a network with VLAN[vlan id in decimal] + // 2. a vlan associating the network created with the pif to private + // network. + + Network vlanNetwork = null; + String name = "VLAN" + Long.toString(tag); + + vlanNetwork = getNetworkByName(conn, name, true); + if (vlanNetwork == null) { // Can't find it, then create it. + if (s_logger.isDebugEnabled()) { + s_logger.debug("Creating VLAN network for " + tag + " on host " + _host.ip); + } + Network.Record nwr = new Network.Record(); + nwr.nameLabel = name; + nwr.bridge = name; + vlanNetwork = Network.create(conn, nwr); + } + + PIF nPif = PIF.getByUuid(conn, pifUuid); + PIF.Record nPifr = nPif.getRecord(conn); + + Network.Record vlanNetworkr = vlanNetwork.getRecord(conn); + if (vlanNetworkr.PIFs != null) { + for (PIF pif : vlanNetworkr.PIFs) { + PIF.Record pifr = pif.getRecord(conn); + if (pifr.device.equals(nPifr.device) && pifr.host.equals(nPifr.host)) { + pif.plug(conn); + return vlanNetwork; + } + } + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Creating VLAN " + tag + " on host " + _host.ip + " on device " + nPifr.device); + } + VLAN vlan = VLAN.create(conn, nPif, tag, vlanNetwork); + VLAN.Record vlanr = vlan.getRecord(conn); + if (s_logger.isDebugEnabled()) { + s_logger.debug("VLAN is created for " + tag + ". The uuid is " + vlanr.uuid); + } + + PIF untaggedPif = vlanr.untaggedPIF; + if (!untaggedPif.getCurrentlyAttached(conn)) { + untaggedPif.plug(conn); + } + + return vlanNetwork; + } + protected void disableVlanNetwork(Network network) throws InternalErrorException { try { Connection conn = getConnection(); @@ -4264,6 +4732,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR } } + @Override public CreateAnswer execute(CreateCommand cmd) { StoragePoolTO pool = cmd.getPool(); DiskCharacteristics dskch = cmd.getDiskCharacteristics(); @@ -4763,6 +5232,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR } } + @Override public Answer execute(DestroyCommand cmd) { VolumeTO vol = cmd.getVolume(); @@ -4806,6 +5276,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR return new Answer(cmd, true, "Success"); } + @Override public ShareAnswer execute(final ShareCommand cmd) { if (!cmd.isShare()) { SR sr = getISOSRbyVmName(cmd.getVmName()); @@ -4825,6 +5296,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR return new ShareAnswer(cmd, new HashMap()); } + @Override public CopyVolumeAnswer execute(final CopyVolumeCommand cmd) { String volumeUUID = cmd.getVolumePath(); StoragePoolVO pool = cmd.getPool(); @@ -6077,10 +6549,12 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR _agentControl = agentControl; } + @Override public boolean IsRemoteAgent() { return _isRemoteAgent; } + @Override public void setRemoteAgent(boolean remote) { _isRemoteAgent = remote; } diff --git a/core/test/com/cloud/vmware/TestVMWare.java b/core/test/com/cloud/vmware/TestVMWare.java index a6754ded927..6ec9c9f3d3e 100644 --- a/core/test/com/cloud/vmware/TestVMWare.java +++ b/core/test/com/cloud/vmware/TestVMWare.java @@ -793,6 +793,35 @@ public class TestVMWare { VirtualNicManagerNetConfig[] netConfigs = (VirtualNicManagerNetConfig[])cb.getServiceUtil3().getDynamicProperty(morHost, "config.virtualNicManagerInfo.netConfig"); } + private void getHostVMs() throws Exception { + ManagedObjectReference morHost = new ManagedObjectReference(); + morHost.setType("HostSystem"); + morHost.set_value("host-48"); + + PropertySpec pSpec = new PropertySpec(); + pSpec.setType("VirtualMachine"); + pSpec.setPathSet(new String[] { "name", "runtime.powerState", "config.template" }); + + TraversalSpec host2VmTraversal = new TraversalSpec(); + host2VmTraversal.setType("HostSystem"); + host2VmTraversal.setPath("vm"); + host2VmTraversal.setName("host2VmTraversal"); + + ObjectSpec oSpec = new ObjectSpec(); + oSpec.setObj(morHost); + oSpec.setSkip(Boolean.TRUE); + oSpec.setSelectSet(new SelectionSpec[] { host2VmTraversal }); + + PropertyFilterSpec pfSpec = new PropertyFilterSpec(); + pfSpec.setPropSet(new PropertySpec[] { pSpec }); + pfSpec.setObjectSet(new ObjectSpec[] { oSpec }); + + ObjectContent[] ocs = cb.getServiceConnection3().getService().retrieveProperties( + cb.getServiceConnection3().getServiceContent().getPropertyCollector(), + new PropertyFilterSpec[] { pfSpec }); + this.printContent(ocs); + } + public static void main(String[] args) throws Exception { setupLog4j(); TestVMWare client = new TestVMWare(); @@ -819,7 +848,8 @@ public class TestVMWare { // client.addNicToNetwork(); // client.createDatacenter(); - client.getPropertyWithPath(); + // client.getPropertyWithPath(); + client.getHostVMs(); cb.disConnect(); } catch (Exception e) { diff --git a/python/lib/cloud_utils.pyc b/python/lib/cloud_utils.pyc deleted file mode 100644 index 061c199488c..00000000000 Binary files a/python/lib/cloud_utils.pyc and /dev/null differ diff --git a/server/src/com/cloud/api/commands/ListDomainChildrenCmd.java b/server/src/com/cloud/api/commands/ListDomainChildrenCmd.java index 6e17f9a862a..605e332627d 100644 --- a/server/src/com/cloud/api/commands/ListDomainChildrenCmd.java +++ b/server/src/com/cloud/api/commands/ListDomainChildrenCmd.java @@ -89,7 +89,13 @@ public class ListDomainChildrenCmd extends BaseCmd { } } - Criteria c = new Criteria("id", Boolean.TRUE, startIndex, Long.valueOf(pageSizeNum)); + //temporary solution at API level. We need a permanent solution for all "listXXXXXXX & pageSize = -1" in the future. + Criteria c; + if(pageSizeNum != -1) + c = new Criteria("id", Boolean.TRUE, startIndex, Long.valueOf(pageSizeNum)); + else + c = new Criteria("id", Boolean.TRUE, null, null); + if (keyword != null) { c.addCriteria(Criteria.KEYWORD, keyword); diff --git a/server/src/com/cloud/api/commands/ListDomainsCmd.java b/server/src/com/cloud/api/commands/ListDomainsCmd.java index 6b503a14fee..b722e9f1951 100644 --- a/server/src/com/cloud/api/commands/ListDomainsCmd.java +++ b/server/src/com/cloud/api/commands/ListDomainsCmd.java @@ -85,7 +85,13 @@ public class ListDomainsCmd extends BaseCmd { startIndex = Long.valueOf(pageSizeNum * (pageNum-1)); } } - Criteria c = new Criteria("id", Boolean.TRUE, startIndex, Long.valueOf(pageSizeNum)); + + //temporary solution at API level. We need a permanent solution for all "listXXXXXXX & pageSize = -1" in the future. + Criteria c; + if(pageSizeNum != -1) + c = new Criteria("id", Boolean.TRUE, startIndex, Long.valueOf(pageSizeNum)); + else + c = new Criteria("id", Boolean.TRUE, null, null); if (keyword != null) { c.addCriteria(Criteria.KEYWORD, keyword); diff --git a/server/src/com/cloud/async/executor/CreatePrivateTemplateExecutor.java b/server/src/com/cloud/async/executor/CreatePrivateTemplateExecutor.java index 32fda8b7ac9..d1f13bbcdf0 100644 --- a/server/src/com/cloud/async/executor/CreatePrivateTemplateExecutor.java +++ b/server/src/com/cloud/async/executor/CreatePrivateTemplateExecutor.java @@ -145,7 +145,7 @@ public class CreatePrivateTemplateExecutor extends VolumeOperationExecutor { jobStatus = AsyncJobResult.STATUS_SUCCEEDED; resultCode = 0; details = null; - String eventParams = "id="+template.getId()+"\nname=" + template.getName() +"\nsize="+volume.getSize(); + String eventParams = "id="+template.getId()+"\nname=" + template.getName() +"\nsize="+volume.getSize()+ "\ndcId="+volume.getDataCenterId(); managerServer.saveEvent(param.getUserId(), param.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_TEMPLATE_CREATE, "Successfully created Template " +param.getName(), eventParams ,param.getEventId()); resultObject = composeResultObject(template, templateHostRef, volume.getDataCenterId()); } diff --git a/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java b/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java index db02ce8b4da..9c333af2623 100644 --- a/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java +++ b/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java @@ -16,8 +16,8 @@ * */ -package com.cloud.consoleproxy; - +package com.cloud.consoleproxy; + import java.util.Map; import javax.ejb.Local; @@ -45,316 +45,274 @@ import com.cloud.ha.HighAvailabilityManager; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; +import com.cloud.info.ConsoleProxyInfo; import com.cloud.utils.NumbersUtil; import com.cloud.utils.component.ComponentLocator; +import com.cloud.utils.component.Inject; import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.VirtualMachineName; -import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; - -@Local(value={ConsoleProxyManager.class}) -public class AgentBasedConsoleProxyManager implements ConsoleProxyManager, VirtualMachineManager { - private static final Logger s_logger = Logger.getLogger(AgentBasedConsoleProxyManager.class); - - private String _name; - protected HostDao _hostDao; - protected UserVmDao _userVmDao; - private String _instance; - private VMInstanceDao _instanceDao; - private ConsoleProxyListener _listener; - - protected int _consoleProxyUrlPort = ConsoleProxyManager.DEFAULT_PROXY_URL_PORT; - protected boolean _sslEnabled = false; - AgentManager _agentMgr; - - public int getVncPort(VMInstanceVO vm) { - if (vm.getHostId() == null) { - return -1; - } - GetVncPortAnswer answer = (GetVncPortAnswer)_agentMgr.easySend(vm.getHostId(), new GetVncPortCommand(vm.getId(), vm.getName())); - return answer == null ? -1 : answer.getPort(); - } - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - - if(s_logger.isInfoEnabled()) - s_logger.info("Start configuring AgentBasedConsoleProxyManager"); - - _name = name; - - ComponentLocator locator = ComponentLocator.getCurrentLocator(); - ConfigurationDao configDao = locator.getDao(ConfigurationDao.class); - if (configDao == null) { - throw new ConfigurationException( - "Unable to get the configuration dao."); - } - - Map configs = configDao.getConfiguration( - "management-server", params); - String value = configs.get("consoleproxy.url.port"); - if (value != null) - _consoleProxyUrlPort = NumbersUtil.parseInt(value, ConsoleProxyManager.DEFAULT_PROXY_URL_PORT); - - _hostDao = locator.getDao(HostDao.class); - if (_hostDao == null) { - throw new ConfigurationException("Unable to get " - + HostDao.class.getName()); - } - - _instanceDao = locator.getDao(VMInstanceDao.class); - if (_instanceDao == null) - throw new ConfigurationException("Unable to get " + VMInstanceDao.class.getName()); - - _userVmDao = locator.getDao(UserVmDao.class); - if (_userVmDao == null) - throw new ConfigurationException("Unable to get " + UserVmDao.class.getName()); - - _agentMgr = locator.getManager(AgentManager.class); - if (_agentMgr == null) - throw new ConfigurationException("Unable to get " + AgentManager.class.getName()); - - value = configs.get("consoleproxy.sslEnabled"); - if(value != null && value.equalsIgnoreCase("true")) - _sslEnabled = true; - - _instance = configs.get("instance.name"); - - _listener = new ConsoleProxyListener(this); - _agentMgr.registerForHostEvents(_listener, true, true, false); - - HighAvailabilityManager haMgr = locator.getManager(HighAvailabilityManager.class); - haMgr.registerHandler(Type.ConsoleProxy, this); - - if(s_logger.isInfoEnabled()) - s_logger.info("AgentBasedConsoleProxyManager has been configured. SSL enabled: " + _sslEnabled); - return true; - } - - @Override - public boolean start() { - return true; - } - - @Override - public boolean stop() { - return true; - } - - HostVO findHost(VMInstanceVO vm) { - return _hostDao.findById(vm.getHostId()); - } - - protected ConsoleProxyVO allocateProxy(HostVO host, long dataCenterId) { - // only private IP, public IP, host id have meaningful values, rest of all are place-holder values - String publicIp = host.getPublicIpAddress(); - if(publicIp == null) { - if(s_logger.isDebugEnabled()) - s_logger.debug("Host " + host.getName() + "/" + host.getPrivateIpAddress() + - " does not have public interface, we will return its private IP for cosole proxy."); - publicIp = host.getPrivateIpAddress(); - } + +@Local(value = { ConsoleProxyManager.class }) +public class AgentBasedConsoleProxyManager implements ConsoleProxyManager, VirtualMachineManager, AgentHook { + private static final Logger s_logger = Logger.getLogger(AgentBasedConsoleProxyManager.class); + + private String _name; + @Inject + protected HostDao _hostDao; + @Inject + protected UserVmDao _userVmDao; + private String _instance; + @Inject + private VMInstanceDao _instanceDao; + private ConsoleProxyListener _listener; + + protected int _consoleProxyUrlPort = ConsoleProxyManager.DEFAULT_PROXY_URL_PORT; + protected int _consoleProxyPort = ConsoleProxyManager.DEFAULT_PROXY_VNC_PORT; + protected boolean _sslEnabled = false; + @Inject + AgentManager _agentMgr; + + public int getVncPort(VMInstanceVO vm) { + if (vm.getHostId() == null) { + return -1; + } + GetVncPortAnswer answer = (GetVncPortAnswer) _agentMgr.easySend(vm.getHostId(), new GetVncPortCommand(vm.getId(), vm.getName())); + return answer == null ? -1 : answer.getPort(); + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + + if (s_logger.isInfoEnabled()) + s_logger.info("Start configuring AgentBasedConsoleProxyManager"); + + _name = name; + + ComponentLocator locator = ComponentLocator.getCurrentLocator(); + ConfigurationDao configDao = locator.getDao(ConfigurationDao.class); + if (configDao == null) { + throw new ConfigurationException("Unable to get the configuration dao."); + } + + Map configs = configDao.getConfiguration("management-server", params); + String value = configs.get("consoleproxy.url.port"); + if (value != null) + _consoleProxyUrlPort = NumbersUtil.parseInt(value, ConsoleProxyManager.DEFAULT_PROXY_URL_PORT); - // FIXME: Removed State.Running does this affect the console proxy? - return new ConsoleProxyVO(1l, "EmbeddedProxy", null, null, null, - "02:02:02:02:02:02", - host.getPrivateIpAddress(), - "255.255.255.0", - 1l, - 1l, - "03:03:03:03:03:03", - publicIp, - "255.255.255.0", - null, - "untagged", - 1l, - dataCenterId, - "0.0.0.0", - host.getId(), - "dns1", - "dn2", - "domain", - 0, - 0); - } - - @Override - public ConsoleProxyVO assignProxy(long dataCenterId, long userVmId) { - UserVmVO userVm = _userVmDao.findById(userVmId); - if (userVm == null) { - s_logger.warn("User VM " + userVmId - + " no longer exists, return a null proxy for user vm:" - + userVmId); - return null; - } - - HostVO host = findHost(userVm); - if(host != null) { - if(s_logger.isDebugEnabled()) - s_logger.debug("Assign embedded console proxy running at " + host.getName() + " to user vm " + userVmId + " with public IP " + host.getPublicIpAddress()); - - // only private IP, public IP, host id have meaningful values, rest of all are place-holder values - String publicIp = host.getPublicIpAddress(); - if(publicIp == null) { - if(s_logger.isDebugEnabled()) - s_logger.debug("Host " + host.getName() + "/" + host.getPrivateIpAddress() + - " does not have public interface, we will return its private IP for cosole proxy."); - publicIp = host.getPrivateIpAddress(); - } - - ConsoleProxyVO proxy = allocateProxy(host, dataCenterId); - - if(host.getProxyPort() != null && host.getProxyPort().intValue() > 0) - proxy.setPort(host.getProxyPort().intValue()); - else - proxy.setPort(_consoleProxyUrlPort); - - proxy.setSslEnabled(_sslEnabled); - return proxy; - } else { - s_logger.warn("Host that VM is running is no longer available, console access to VM " + userVmId + " will be temporarily unavailable."); - } - return null; - } - - @Override - public void onLoadReport(ConsoleProxyLoadReportCommand cmd) { - } - - @Override - public AgentControlAnswer onConsoleAccessAuthentication(ConsoleAccessAuthenticationCommand cmd) { - long vmId = 0; - - if(cmd.getVmId() != null && cmd.getVmId().isEmpty()) { - if(s_logger.isTraceEnabled()) - s_logger.trace("Invalid vm id sent from proxy(happens when proxy session has terminated)"); - return new ConsoleAccessAuthenticationAnswer(cmd, false); - } - - try { - vmId = Long.parseLong(cmd.getVmId()); - } catch(NumberFormatException e) { - s_logger.error("Invalid vm id " + cmd.getVmId() + " sent from console access authentication", e); - return new ConsoleAccessAuthenticationAnswer(cmd, false); - } - - // TODO authentication channel between console proxy VM and management server needs to be secured, - // the data is now being sent through private network, but this is apparently not enough - VMInstanceVO vm = _instanceDao.findById(vmId); - if(vm == null) { - return new ConsoleAccessAuthenticationAnswer(cmd, false); - } - - if(vm.getHostId() == null) { - s_logger.warn("VM " + vmId + " lost host info, failed authentication request"); - return new ConsoleAccessAuthenticationAnswer(cmd, false); - } - - HostVO host = _hostDao.findById(vm.getHostId()); - if(host == null) { - s_logger.warn("VM " + vmId + "'s host does not exist, fail authentication request"); - return new ConsoleAccessAuthenticationAnswer(cmd, false); - } - - String sid = cmd.getSid(); - if(sid == null || !sid.equals(vm.getVncPassword())) { - s_logger.warn("sid " + sid + " in url does not match stored sid " + vm.getVncPassword()); - return new ConsoleAccessAuthenticationAnswer(cmd, false); - } - - return new ConsoleAccessAuthenticationAnswer(cmd, true); + value = configs.get("consoleproxy.port"); + if (value != null) + _consoleProxyPort = NumbersUtil.parseInt(value, ConsoleProxyManager.DEFAULT_PROXY_VNC_PORT); + + value = configs.get("consoleproxy.sslEnabled"); + if (value != null && value.equalsIgnoreCase("true")) + _sslEnabled = true; + + _instance = configs.get("instance.name"); + + _listener = new ConsoleProxyListener(this); + _agentMgr.registerForHostEvents(_listener, true, true, false); + + HighAvailabilityManager haMgr = locator.getManager(HighAvailabilityManager.class); + haMgr.registerHandler(Type.ConsoleProxy, this); + + if (s_logger.isInfoEnabled()) + s_logger.info("AgentBasedConsoleProxyManager has been configured. SSL enabled: " + _sslEnabled); + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + HostVO findHost(VMInstanceVO vm) { + return _hostDao.findById(vm.getHostId()); + } + + @Override + public ConsoleProxyInfo assignProxy(long dataCenterId, long userVmId) { + UserVmVO userVm = _userVmDao.findById(userVmId); + if (userVm == null) { + s_logger.warn("User VM " + userVmId + " no longer exists, return a null proxy for user vm:" + userVmId); + return null; + } + + HostVO host = findHost(userVm); + if (host != null) { + if (s_logger.isDebugEnabled()) + s_logger.debug("Assign embedded console proxy running at " + host.getName() + " to user vm " + userVmId + " with public IP " + + host.getPublicIpAddress()); + + // only private IP, public IP, host id have meaningful values, rest + // of all are place-holder values + String publicIp = host.getPublicIpAddress(); + if (publicIp == null) { + if (s_logger.isDebugEnabled()) + s_logger.debug("Host " + host.getName() + "/" + host.getPrivateIpAddress() + + " does not have public interface, we will return its private IP for cosole proxy."); + publicIp = host.getPrivateIpAddress(); + } + + int urlPort = _consoleProxyUrlPort; + + if (host.getProxyPort() != null && host.getProxyPort().intValue() > 0) + urlPort = host.getProxyPort().intValue(); + + return new ConsoleProxyInfo(_sslEnabled, publicIp, _consoleProxyPort, urlPort); + } else { + s_logger.warn("Host that VM is running is no longer available, console access to VM " + userVmId + " will be temporarily unavailable."); + } + return null; + } + + @Override + public void onLoadReport(ConsoleProxyLoadReportCommand cmd) { + } + + @Override + public AgentControlAnswer onConsoleAccessAuthentication(ConsoleAccessAuthenticationCommand cmd) { + long vmId = 0; + + if (cmd.getVmId() != null && cmd.getVmId().isEmpty()) { + if (s_logger.isTraceEnabled()) + s_logger.trace("Invalid vm id sent from proxy(happens when proxy session has terminated)"); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + try { + vmId = Long.parseLong(cmd.getVmId()); + } catch (NumberFormatException e) { + s_logger.error("Invalid vm id " + cmd.getVmId() + " sent from console access authentication", e); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + // TODO authentication channel between console proxy VM and management + // server needs to be secured, + // the data is now being sent through private network, but this is + // apparently not enough + VMInstanceVO vm = _instanceDao.findById(vmId); + if (vm == null) { + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + if (vm.getHostId() == null) { + s_logger.warn("VM " + vmId + " lost host info, failed authentication request"); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + HostVO host = _hostDao.findById(vm.getHostId()); + if (host == null) { + s_logger.warn("VM " + vmId + "'s host does not exist, fail authentication request"); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + String sid = cmd.getSid(); + if (sid == null || !sid.equals(vm.getVncPassword())) { + s_logger.warn("sid " + sid + " in url does not match stored sid " + vm.getVncPassword()); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + return new ConsoleAccessAuthenticationAnswer(cmd, true); } @Override public void onAgentConnect(HostVO host, StartupCommand cmd) { } - + @Override - public void onAgentDisconnect(long agentId, Status state) { + public void onAgentDisconnect(long agentId, Status state) { } - - @Override - public ConsoleProxyVO startProxy(long proxyVmId, long startEventId) { - return null; - } - - @Override - public boolean destroyProxy(long proxyVmId, long startEventId) { - return false; - } - - @Override - public boolean rebootProxy(long proxyVmId, long startEventId) { - return false; - } - - @Override - public boolean stopProxy(long proxyVmId, long startEventId) { - return false; - } - - @Override - public String getName() { - return _name; - } - - @Override - public Command cleanup(ConsoleProxyVO vm, String vmName) { - return new StopCommand(vm, vmName, null); - } - - @Override - public boolean completeMigration(ConsoleProxyVO vm, HostVO host) throws AgentUnavailableException, OperationTimedoutException { - return false; - } - - @Override - public void completeStartCommand(ConsoleProxyVO vm) { - } - - @Override - public void completeStopCommand(ConsoleProxyVO vm) { - } - - @Override - public Long convertToId(String vmName) { - if (!VirtualMachineName.isValidConsoleProxyName(vmName, _instance)) { - return null; - } - return VirtualMachineName.getConsoleProxyId(vmName); - } - - @Override - public boolean destroy(ConsoleProxyVO vm) throws AgentUnavailableException { - return false; - } - - @Override - public ConsoleProxyVO get(long id) { - return null; - } - - @Override - public boolean migrate(ConsoleProxyVO vm, HostVO host) throws AgentUnavailableException, OperationTimedoutException { - return false; - } - - @Override - public HostVO prepareForMigration(ConsoleProxyVO vm) throws InsufficientCapacityException, StorageUnavailableException { - return null; - } - - @Override - public ConsoleProxyVO start(long vmId, long startEventId) throws InsufficientCapacityException, StorageUnavailableException, ConcurrentOperationException { - return null; - } - - @Override - public boolean stop(ConsoleProxyVO vm, long startEventId) throws AgentUnavailableException { - return false; - } -} + + @Override + public ConsoleProxyVO startProxy(long proxyVmId, long startEventId) { + return null; + } + + @Override + public boolean destroyProxy(long proxyVmId, long startEventId) { + return false; + } + + @Override + public boolean rebootProxy(long proxyVmId, long startEventId) { + return false; + } + + @Override + public boolean stopProxy(long proxyVmId, long startEventId) { + return false; + } + + @Override + public String getName() { + return _name; + } + + @Override + public Command cleanup(ConsoleProxyVO vm, String vmName) { + return new StopCommand(vm, vmName, null); + } + + @Override + public boolean completeMigration(ConsoleProxyVO vm, HostVO host) throws AgentUnavailableException, OperationTimedoutException { + return false; + } + + @Override + public void completeStartCommand(ConsoleProxyVO vm) { + } + + @Override + public void completeStopCommand(ConsoleProxyVO vm) { + } + + @Override + public Long convertToId(String vmName) { + if (!VirtualMachineName.isValidConsoleProxyName(vmName, _instance)) { + return null; + } + return VirtualMachineName.getConsoleProxyId(vmName); + } + + @Override + public boolean destroy(ConsoleProxyVO vm) throws AgentUnavailableException { + return false; + } + + @Override + public ConsoleProxyVO get(long id) { + return null; + } + + @Override + public boolean migrate(ConsoleProxyVO vm, HostVO host) throws AgentUnavailableException, OperationTimedoutException { + return false; + } + + @Override + public HostVO prepareForMigration(ConsoleProxyVO vm) throws InsufficientCapacityException, StorageUnavailableException { + return null; + } + + @Override + public ConsoleProxyVO start(long vmId, long startEventId) throws InsufficientCapacityException, StorageUnavailableException, + ConcurrentOperationException { + return null; + } + + @Override + public boolean stop(ConsoleProxyVO vm, long startEventId) throws AgentUnavailableException { + return false; + } +} diff --git a/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java b/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java index 4b5f2fb4d4c..8b0858d6e1b 100644 --- a/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java +++ b/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java @@ -26,7 +26,7 @@ import org.apache.log4j.Logger; import com.cloud.host.Host; import com.cloud.host.HostVO; -import com.cloud.vm.ConsoleProxyVO; +import com.cloud.info.ConsoleProxyInfo; import com.cloud.vm.UserVmVO; @Local(value={ConsoleProxyManager.class}) @@ -35,7 +35,7 @@ AgentBasedConsoleProxyManager { private static final Logger s_logger = Logger.getLogger(AgentBasedStandaloneConsoleProxyManager.class); @Override - public ConsoleProxyVO assignProxy(long dataCenterId, long userVmId) { + public ConsoleProxyInfo assignProxy(long dataCenterId, long userVmId) { UserVmVO userVm = _userVmDao.findById(userVmId); if (userVm == null) { s_logger.warn("User VM " + userVmId @@ -81,15 +81,11 @@ AgentBasedConsoleProxyManager { publicIp = allocatedHost.getPrivateIpAddress(); } - ConsoleProxyVO proxy = allocateProxy(allocatedHost, dataCenterId); - - if(allocatedHost.getProxyPort() != null && allocatedHost.getProxyPort().intValue() > 0) - proxy.setPort(allocatedHost.getProxyPort().intValue()); - else - proxy.setPort(_consoleProxyUrlPort); - - proxy.setSslEnabled(_sslEnabled); - return proxy; + int urlPort = _consoleProxyUrlPort; + if(allocatedHost.getProxyPort() != null && allocatedHost.getProxyPort().intValue() > 0) + urlPort = allocatedHost.getProxyPort().intValue(); + + return new ConsoleProxyInfo(_sslEnabled, publicIp, _consoleProxyPort, urlPort); } else { s_logger.warn("Host that VM is running is no longer available, console access to VM " + userVmId + " will be temporarily unavailable."); } diff --git a/server/src/com/cloud/consoleproxy/AgentHook.java b/server/src/com/cloud/consoleproxy/AgentHook.java new file mode 100644 index 00000000000..a25e555e92f --- /dev/null +++ b/server/src/com/cloud/consoleproxy/AgentHook.java @@ -0,0 +1,19 @@ +/** + * + */ +package com.cloud.consoleproxy; + +import com.cloud.agent.api.AgentControlAnswer; +import com.cloud.agent.api.ConsoleAccessAuthenticationCommand; +import com.cloud.agent.api.ConsoleProxyLoadReportCommand; +import com.cloud.agent.api.StartupCommand; +import com.cloud.host.HostVO; +import com.cloud.host.Status; + +public interface AgentHook { + void onLoadReport(ConsoleProxyLoadReportCommand cmd); + AgentControlAnswer onConsoleAccessAuthentication(ConsoleAccessAuthenticationCommand cmd); + void onAgentConnect(HostVO host, StartupCommand cmd); + + public void onAgentDisconnect(long agentId, Status state); +} diff --git a/core/src/com/cloud/consoleproxy/ConsoleProxyAlertEventArgs.java b/server/src/com/cloud/consoleproxy/ConsoleProxyAlertEventArgs.java similarity index 100% rename from core/src/com/cloud/consoleproxy/ConsoleProxyAlertEventArgs.java rename to server/src/com/cloud/consoleproxy/ConsoleProxyAlertEventArgs.java diff --git a/core/src/com/cloud/consoleproxy/ConsoleProxyListener.java b/server/src/com/cloud/consoleproxy/ConsoleProxyListener.java similarity index 76% rename from core/src/com/cloud/consoleproxy/ConsoleProxyListener.java rename to server/src/com/cloud/consoleproxy/ConsoleProxyListener.java index e0aa2e5750a..a8a9d992bb4 100644 --- a/core/src/com/cloud/consoleproxy/ConsoleProxyListener.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyListener.java @@ -17,7 +17,6 @@ */ package com.cloud.consoleproxy; - import org.apache.log4j.Logger; import com.cloud.agent.Listener; @@ -33,13 +32,13 @@ import com.cloud.host.Status; public class ConsoleProxyListener implements Listener { private final static Logger s_logger = Logger.getLogger(ConsoleProxyListener.class); - - ConsoleProxyManager _proxyMgr = null; - public ConsoleProxyListener(ConsoleProxyManager proxyMgr) { + AgentHook _proxyMgr = null; + + public ConsoleProxyListener(AgentHook proxyMgr) { _proxyMgr = proxyMgr; } - + @Override public boolean isRecurring() { return true; @@ -47,46 +46,46 @@ public class ConsoleProxyListener implements Listener { @Override public boolean processAnswer(long agentId, long seq, Answer[] answers) { - return true; + return true; } @Override public boolean processCommand(long agentId, long seq, Command[] commands) { return false; } - + @Override public AgentControlAnswer processControlCommand(long agentId, AgentControlCommand cmd) { - if(cmd instanceof ConsoleProxyLoadReportCommand) { - _proxyMgr.onLoadReport((ConsoleProxyLoadReportCommand)cmd); - - // return dummy answer - return new AgentControlAnswer(cmd); - } else if(cmd instanceof ConsoleAccessAuthenticationCommand) { - return _proxyMgr.onConsoleAccessAuthentication((ConsoleAccessAuthenticationCommand)cmd); - } - return null; + if (cmd instanceof ConsoleProxyLoadReportCommand) { + _proxyMgr.onLoadReport((ConsoleProxyLoadReportCommand) cmd); + + // return dummy answer + return new AgentControlAnswer(cmd); + } else if (cmd instanceof ConsoleAccessAuthenticationCommand) { + return _proxyMgr.onConsoleAccessAuthentication((ConsoleAccessAuthenticationCommand) cmd); + } + return null; } @Override public boolean processConnect(HostVO host, StartupCommand cmd) { - _proxyMgr.onAgentConnect(host, cmd); + _proxyMgr.onAgentConnect(host, cmd); return true; } - + @Override public boolean processDisconnect(long agentId, Status state) { - _proxyMgr.onAgentDisconnect(agentId, state); + _proxyMgr.onAgentDisconnect(agentId, state); return true; } - + @Override public boolean processTimeout(long agentId, long seq) { - return true; + return true; } - + @Override public int getTimeout() { - return -1; + return -1; } } diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManager.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManager.java new file mode 100644 index 00000000000..8e9329875bf --- /dev/null +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManager.java @@ -0,0 +1,46 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It 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 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 . + * + */ + +package com.cloud.consoleproxy; + +import com.cloud.info.ConsoleProxyInfo; +import com.cloud.utils.component.Manager; +import com.cloud.vm.ConsoleProxyVO; + +public interface ConsoleProxyManager extends Manager { + public static final int DEFAULT_PROXY_CAPACITY = 50; + public static final int DEFAULT_STANDBY_CAPACITY = 10; + public static final int DEFAULT_PROXY_VM_RAMSIZE = 1024; // 1G + + public static final int DEFAULT_PROXY_CMD_PORT = 8001; + public static final int DEFAULT_PROXY_VNC_PORT = 0; + public static final int DEFAULT_PROXY_URL_PORT = 80; + public static final int DEFAULT_PROXY_SESSION_TIMEOUT = 300000; // 5 minutes + + public static final String ALERT_SUBJECT = "proxy-alert"; + + public ConsoleProxyInfo assignProxy(long dataCenterId, long userVmId); + + public ConsoleProxyVO startProxy(long proxyVmId, long startEventId); + + public boolean stopProxy(long proxyVmId, long startEventId); + + public boolean rebootProxy(long proxyVmId, long startEventId); + + public boolean destroyProxy(long proxyVmId, long startEventId); +} diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index 3cfbc1dacaf..36732052a9b 100644 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -61,15 +61,13 @@ import com.cloud.async.AsyncJobExecutor; import com.cloud.async.AsyncJobManager; import com.cloud.async.AsyncJobVO; import com.cloud.async.BaseAsyncJobExecutor; -import com.cloud.capacity.dao.CapacityDao; import com.cloud.cluster.ClusterManager; import com.cloud.configuration.Config; -import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; -import com.cloud.dc.VlanVO; import com.cloud.dc.Vlan.VlanType; +import com.cloud.dc.VlanVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.dc.dao.VlanDao; @@ -84,12 +82,12 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.OperationTimedoutException; import com.cloud.exception.StorageUnavailableException; import com.cloud.ha.HighAvailabilityManager; -import com.cloud.ha.dao.HighAvailabilityDao; import com.cloud.host.Host; -import com.cloud.host.HostVO; import com.cloud.host.Host.Type; +import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.info.ConsoleProxyConnectionInfo; +import com.cloud.info.ConsoleProxyInfo; import com.cloud.info.ConsoleProxyLoadInfo; import com.cloud.info.ConsoleProxyStatus; import com.cloud.info.RunningHostCountInfo; @@ -97,7 +95,6 @@ import com.cloud.info.RunningHostInfoAgregator; import com.cloud.info.RunningHostInfoAgregator.ZoneHostInfo; import com.cloud.maid.StackMaid; import com.cloud.network.IpAddrAllocator; -import com.cloud.network.NetworkManager; import com.cloud.network.IpAddrAllocator.networkInfo; import com.cloud.network.dao.IPAddressDao; import com.cloud.offering.ServiceOffering.GuestIpType; @@ -106,10 +103,9 @@ import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VolumeVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.storage.dao.StoragePoolDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; import com.cloud.storage.dao.VolumeDao; @@ -135,9 +131,9 @@ import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.State; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.VirtualMachineName; -import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.dao.ConsoleProxyDao; import com.cloud.vm.dao.VMInstanceDao; import com.google.gson.Gson; @@ -162,2202 +158,2088 @@ import com.google.gson.GsonBuilder; // because sooner or later, it will be driven into Running state // @Local(value = { ConsoleProxyManager.class }) -public class ConsoleProxyManagerImpl implements ConsoleProxyManager, - VirtualMachineManager { - private static final Logger s_logger = Logger - .getLogger(ConsoleProxyManagerImpl.class); - - private static final int DEFAULT_FIND_HOST_RETRY_COUNT = 2; - private static final int DEFAULT_CAPACITY_SCAN_INTERVAL = 30000; // 30 - // seconds - private static final int EXECUTOR_SHUTDOWN_TIMEOUT = 1000; // 1 second - - private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 3; // 3 - // seconds - private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC = 180; // 3 - // minutes - - private static final int API_WAIT_TIMEOUT = 5000; // 5 seconds (in - // milliseconds) - private static final int STARTUP_DELAY = 60000; // 60 seconds - - private int _consoleProxyPort = ConsoleProxyManager.DEFAULT_PROXY_VNC_PORT; - private int _consoleProxyUrlPort = ConsoleProxyManager.DEFAULT_PROXY_URL_PORT; - - private String _mgmt_host; - private int _mgmt_port = 8250; - - private String _name; - private Adapters _consoleProxyAllocators; - - private ConsoleProxyDao _consoleProxyDao; - private DataCenterDao _dcDao; - private VlanDao _vlanDao; - private VMTemplateDao _templateDao; - private IPAddressDao _ipAddressDao; - private VolumeDao _volsDao; - private HostPodDao _podDao; - private HostDao _hostDao; - private StoragePoolDao _storagePoolDao; - private ConfigurationDao _configDao; - - private VMInstanceDao _instanceDao; - private AccountDao _accountDao; - - private VMTemplateHostDao _vmTemplateHostDao; - private CapacityDao _capacityDao; - private HighAvailabilityDao _haDao; - - private AgentManager _agentMgr; - private NetworkManager _networkMgr; - private StorageManager _storageMgr; - private HighAvailabilityManager _haMgr; - private EventDao _eventDao; - @Inject - ServiceOfferingDao _offeringDao; - private IpAddrAllocator _IpAllocator; - - private ConsoleProxyListener _listener; - - private ServiceOfferingVO _serviceOffering; - private VMTemplateVO _template; - - private AsyncJobManager _asyncMgr; - - private final ScheduledExecutorService _capacityScanScheduler = Executors - .newScheduledThreadPool(1, new NamedThreadFactory("CP-Scan")); - private final ExecutorService _requestHandlerScheduler = Executors - .newCachedThreadPool(new NamedThreadFactory("Request-handler")); - - private long _capacityScanInterval = DEFAULT_CAPACITY_SCAN_INTERVAL; - private int _capacityPerProxy = ConsoleProxyManager.DEFAULT_PROXY_CAPACITY; - private int _standbyCapacity = ConsoleProxyManager.DEFAULT_STANDBY_CAPACITY; - - private int _proxyRamSize; - private int _find_host_retry = DEFAULT_FIND_HOST_RETRY_COUNT; - private int _ssh_retry; - private int _ssh_sleep; - private boolean _use_lvm; - private boolean _use_storage_vm; - - private String _domain; - private String _instance; - - // private String _privateNetmask; - private int _proxyCmdPort = DEFAULT_PROXY_CMD_PORT; - private int _proxySessionTimeoutValue = DEFAULT_PROXY_SESSION_TIMEOUT; - private boolean _sslEnabled = false; - - private final GlobalLock _capacityScanLock = GlobalLock - .getInternLock(getCapacityScanLockName()); - private final GlobalLock _allocProxyLock = GlobalLock - .getInternLock(getAllocProxyLockName()); - - public ConsoleProxyVO assignProxy(final long dataCenterId, final long vmId) { - - final Pair result = new Pair( - this, null); - - _requestHandlerScheduler.execute(new Runnable() { - public void run() { - Transaction txn = Transaction.open(Transaction.CLOUD_DB); - try { - ConsoleProxyVO proxy = doAssignProxy(dataCenterId, vmId); - synchronized (result) { - result.second(proxy); - result.notifyAll(); - } - } catch (Throwable e) { - s_logger.warn("Unexpected exception " + e.getMessage(), e); - } finally { - StackMaid.current().exitCleanup(); - txn.close(); - } - } - }); - - synchronized (result) { - try { - result.wait(API_WAIT_TIMEOUT); - } catch (InterruptedException e) { - s_logger.info("Waiting for console proxy assignment is interrupted"); - } - } - return result.second(); - } - - public ConsoleProxyVO doAssignProxy(long dataCenterId, long vmId) { - ConsoleProxyVO proxy = null; - VMInstanceVO vm = _instanceDao.findById(vmId); - if (vm == null) { - s_logger.warn("VM " + vmId + " no longer exists, return a null proxy for vm:" + vmId); - return null; - } - - Boolean[] proxyFromStoppedPool = new Boolean[1]; - if (_allocProxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { - try { - proxy = getOrAllocProxyResource(dataCenterId, vmId, proxyFromStoppedPool); - } finally { - _allocProxyLock.unlock(); - } - } else { - s_logger.error("Unable to acquire synchronization lock to get/allocate proxy resource for vm :" - + vmId + ". Previous console proxy allocation is taking too long"); - } - - if (proxy == null) { - s_logger.warn("Unable to find or allocate console proxy resource"); - return null; - } - - long proxyVmId = proxy.getId(); - GlobalLock proxyLock = GlobalLock.getInternLock(getProxyLockName(proxyVmId)); - try { - if (proxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { - try { - proxy = startProxy(proxyVmId, 0); - - if (proxy == null) { - // - // We had a situation with multi-pod configuration, where - // storage allocation of the console proxy VM may succeed, but later-on starting of it - // may fail because of running out of computing resource (CPU/memory). We - // currently don't support moving storage to another pod on the fly, to deal - // with the situation we will destroy this proxy VM and let it the whole proxy VM - // creation process re-start again, by hoping that new storage and computing - // resource may be allocated and assigned in another pod - // - if (s_logger.isInfoEnabled()) - s_logger.info("Unable to start console proxy, proxy vm Id : " + proxyVmId + " will recycle it and restart a new one"); - destroyProxy(proxyVmId, 0); - return null; - } else { - if (s_logger.isTraceEnabled()) - s_logger.trace("Console proxy " + proxy.getName() + " is started"); - - // if it is a new assignment or a changed assignment, update the - // record - if (vm.getProxyId() == null || vm.getProxyId().longValue() != proxy.getId()) - _instanceDao.updateProxyId(vmId, proxy.getId(), DateUtil.currentGMTTime()); - - proxy.setSslEnabled(_sslEnabled); - if (_sslEnabled) - proxy.setPort(443); - else - proxy.setPort(80); - return proxy; - } - } finally { - proxyLock.unlock(); - } - } else { - s_logger.error("Unable to acquire synchronization lock to start console proxy " - + proxyVmId + " for vm: " + vmId + ". It takes too long to start the proxy"); - - return null; - } - } finally { - proxyLock.releaseRef(); - } - } - - private ConsoleProxyVO getOrAllocProxyResource(long dataCenterId, - long vmId, Boolean[] proxyFromStoppedPool) { - ConsoleProxyVO proxy = null; - VMInstanceVO vm = this._instanceDao.findById(vmId); - - if (vm != null && vm.getState() != State.Running) { - if (s_logger.isInfoEnabled()) - s_logger.info("Detected that vm : " + vmId + " is not currently at running state, we will fail the proxy assignment for it"); - return null; - } - - if (vm != null && vm.getProxyId() != null) { - proxy = _consoleProxyDao.findById(vm.getProxyId()); - - if (proxy != null) { - if (!isInAssignableState(proxy)) { - if (s_logger.isInfoEnabled()) - s_logger.info("A previous assigned proxy is not assignable now, reassign console proxy for user vm : " + vmId); - proxy = null; - } else { - if (_consoleProxyDao.getProxyActiveLoad(proxy.getId()) < _capacityPerProxy - || hasPreviousSession(proxy, vm)) { - if (s_logger.isTraceEnabled()) - s_logger.trace("Assign previous allocated console proxy for user vm : " + vmId); - - if (proxy.getActiveSession() >= _capacityPerProxy) - s_logger.warn("Assign overloaded proxy to user VM as previous session exists, user vm : " + vmId); - } else { - proxy = null; - } - } - } - } - - if (proxy == null) - proxy = assignProxyFromRunningPool(dataCenterId); - - if (proxy == null) { - if (s_logger.isInfoEnabled()) - s_logger.info("No running console proxy is available, check to see if we can bring up a stopped one for data center : " + dataCenterId); - - proxy = assignProxyFromStoppedPool(dataCenterId); - if (proxy == null) { - if (s_logger.isInfoEnabled()) - s_logger.info("No stopped console proxy is available, need to allocate a new console proxy for data center : " + dataCenterId); - - proxy = startNew(dataCenterId); - } else { - if (s_logger.isInfoEnabled()) - s_logger.info("Found a stopped console proxy, bring it up to running pool. proxy vm id : " - + proxy.getId() + ", data center : " + dataCenterId); - - proxyFromStoppedPool[0] = new Boolean(true); - } - } - - return proxy; - } - - private static boolean isInAssignableState(ConsoleProxyVO proxy) { - // console proxies that are in states of being able to serve user VM - State state = proxy.getState(); - if (state == State.Running || state == State.Starting - || state == State.Creating || state == State.Migrating) - return true; - - return false; - } - - private boolean hasPreviousSession(ConsoleProxyVO proxy, VMInstanceVO vm) { - - ConsoleProxyStatus status = null; - try { - GsonBuilder gb = new GsonBuilder(); - gb.setVersion(1.3); - Gson gson = gb.create(); - - byte[] details = proxy.getSessionDetails(); - status = gson.fromJson(details != null ? new String(details, - Charset.forName("US-ASCII")) : null, - ConsoleProxyStatus.class); - } catch (Throwable e) { - s_logger.warn("Unable to parse proxy session details : " - + proxy.getSessionDetails()); - } - - if (status != null && status.getConnections() != null) { - ConsoleProxyConnectionInfo[] connections = status.getConnections(); - for (int i = 0; i < connections.length; i++) { - long taggedVmId = 0; - if (connections[i].tag != null) { - try { - taggedVmId = Long.parseLong(connections[i].tag); - } catch (NumberFormatException e) { - s_logger.warn( - "Unable to parse console proxy connection info passed through tag: " - + connections[i].tag, e); - } - } - if (taggedVmId == vm.getId()) - return true; - } - - // - // even if we are not in the list, it may because we haven't - // received load-update yet - // wait until session time - // - if (DateUtil.currentGMTTime().getTime() - vm.getProxyAssignTime().getTime() < _proxySessionTimeoutValue) - return true; - - return false; - } else { - s_logger.error("No proxy load info on an overloaded proxy ?"); - return false; - } - } - - @Override - public ConsoleProxyVO startProxy(long proxyVmId, long startEventId) { - try { - return start(proxyVmId, startEventId); - } catch (StorageUnavailableException e) { - s_logger.warn("Exception while trying to start console proxy", e); - return null; - } catch (InsufficientCapacityException e) { - s_logger.warn("Exception while trying to start console proxy", e); - return null; - } catch (ConcurrentOperationException e) { - s_logger.warn("Exception while trying to start console proxy", e); - return null; - } - } - - @Override - @DB - public ConsoleProxyVO start(long proxyId, long startEventId) - throws StorageUnavailableException, InsufficientCapacityException, - ConcurrentOperationException { - - AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor(); - if (asyncExecutor != null) { - AsyncJobVO job = asyncExecutor.getJob(); - - if (s_logger.isInfoEnabled()) - s_logger.info("Start console proxy " + proxyId + ", update async job-" + job.getId()); - _asyncMgr.updateAsyncJobAttachment(job.getId(), "console_proxy", proxyId); - } - - ConsoleProxyVO proxy = _consoleProxyDao.findById(proxyId); - if (proxy == null || proxy.getRemoved() != null) { - s_logger.debug("proxy is not found: " + proxyId); - return null; - } -/* - // don't insert event here, it may be called multiple times! - saveStartedEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, - EventTypes.EVENT_PROXY_START, - "Starting console proxy with Id: " + proxyId, startEventId); -*/ - - if (s_logger.isTraceEnabled()) { - s_logger.trace("Starting console proxy if it is not started, proxy vm id : " + proxyId); - } - - for (int i = 0; i < 2; i++) { - - State state = proxy.getState(); - - if (state == State.Starting /* || state == State.Migrating */) { - if (s_logger.isDebugEnabled()) - s_logger.debug("Waiting console proxy to be ready, proxy vm id : " + proxyId + " proxy VM state : " + state.toString()); - - if (proxy.getPrivateIpAddress() == null || connect(proxy.getPrivateIpAddress(), _proxyCmdPort) != null) { - if (proxy.getPrivateIpAddress() == null) - s_logger.warn("Retruning a proxy that is being started but private IP has not been allocated yet, proxy vm id : " + proxyId); - else - s_logger.warn("Waiting console proxy to be ready timed out, proxy vm id : " + proxyId); - - // TODO, it is very tricky here, if the startup process - // takes too long and it timed out here, - // we may give back a proxy that is not fully ready for - // functioning - } - return proxy; - } - - if (state == State.Running) { - if (s_logger.isTraceEnabled()) - s_logger.trace("Console proxy is already started: " + proxy.getName()); - return proxy; - } - - DataCenterVO dc = _dcDao.findById(proxy.getDataCenterId()); - HostPodVO pod = _podDao.findById(proxy.getPodId()); - List sps = _storageMgr.getStoragePoolsForVm(proxy.getId()); - StoragePoolVO sp = sps.get(0); // FIXME - - HashSet avoid = new HashSet(); - HostVO routingHost = (HostVO) _agentMgr.findHost(Host.Type.Routing, - dc, pod, sp, _serviceOffering, _template, proxy, null, - avoid); - - if (routingHost == null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Unable to find a routing host for " + proxy.toString()); - continue; - } - } - // to ensure atomic state transition to Starting state - if (!_consoleProxyDao.updateIf(proxy, Event.StartRequested, routingHost.getId())) { - if (s_logger.isDebugEnabled()) { - ConsoleProxyVO temp = _consoleProxyDao.findById(proxyId); - s_logger.debug("Unable to start console proxy " + proxy.getName() + " because it is not in a startable state : " - + ((temp != null) ? temp.getState().toString() : "null")); - } - continue; - } - - try { - Answer answer = null; - int retry = _find_host_retry; - - // Console proxy VM will be running at routing hosts as routing - // hosts have public access to outside network - do { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Trying to start console proxy on host " + routingHost.getName()); - } - - String privateIpAddress = allocPrivateIpAddress( - proxy.getDataCenterId(), routingHost.getPodId(), - proxy.getId(), proxy.getPrivateMacAddress()); - if (privateIpAddress == null && (_IpAllocator != null && !_IpAllocator.exteralIpAddressAllocatorEnabled())) { - s_logger.debug("Not enough ip addresses in " + routingHost.getPodId()); - avoid.add(routingHost); - continue; - } - - proxy.setPrivateIpAddress(privateIpAddress); - String guestIpAddress = _dcDao.allocateLinkLocalPrivateIpAddress(proxy.getDataCenterId(), routingHost.getPodId(), proxy.getId()); - proxy.setGuestIpAddress(guestIpAddress); - - _consoleProxyDao.updateIf(proxy, Event.OperationRetry, routingHost.getId()); - proxy = _consoleProxyDao.findById(proxy.getId()); - - List vols = _storageMgr.prepare(proxy, routingHost); - if (vols == null) { - s_logger.debug("Unable to prepare storage for " + routingHost); - avoid.add(routingHost); - continue; - } - - // _storageMgr.share(proxy, vols, null, true); - - // carry the console proxy port info over so that we don't - // need to configure agent on this - StartConsoleProxyCommand cmdStart = new StartConsoleProxyCommand( - _proxyCmdPort, proxy, proxy.getName(), "", vols, - Integer.toString(_consoleProxyPort), - Integer.toString(_consoleProxyUrlPort), - _mgmt_host, _mgmt_port, _sslEnabled); - - if (s_logger.isDebugEnabled()) - s_logger.debug("Sending start command for console proxy " + proxy.getName() + " to " + routingHost.getName()); - try { - answer = _agentMgr.send(routingHost.getId(), cmdStart); - - s_logger.debug("StartConsoleProxy Answer: " + (answer != null ? answer : "null")); - - if (s_logger.isDebugEnabled()) - s_logger.debug("Received answer on starting console proxy " + proxy.getName() + " on " + routingHost.getName()); - - if (answer != null && answer.getResult()) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Console proxy " + proxy.getName() + " started on " + routingHost.getName()); - } - - if (answer instanceof StartConsoleProxyAnswer) { - StartConsoleProxyAnswer rAnswer = (StartConsoleProxyAnswer) answer; - if (rAnswer.getPrivateIpAddress() != null) { - proxy.setPrivateIpAddress(rAnswer.getPrivateIpAddress()); - } - if (rAnswer.getPrivateMacAddress() != null) { - proxy.setPrivateMacAddress(rAnswer.getPrivateMacAddress()); - } - } - - final EventVO event = new EventVO(); - event.setUserId(User.UID_SYSTEM); - event.setAccountId(Account.ACCOUNT_ID_SYSTEM); - event.setType(EventTypes.EVENT_PROXY_START); - event.setLevel(EventVO.LEVEL_INFO); - event.setStartId(startEventId); - event.setDescription("Console proxy started - " + proxy.getName()); - _eventDao.persist(event); - break; - } - s_logger.debug("Unable to start " + proxy.toString() + " on host " + routingHost.toString() + " due to " + answer.getDetails()); - } catch (OperationTimedoutException e) { - if (e.isActive()) { - s_logger.debug("Unable to start vm " + proxy.getName() + " due to operation timed out and it is active so scheduling a restart."); - _haMgr.scheduleRestart(proxy, true); - return null; - } - } catch (AgentUnavailableException e) { - s_logger.debug("Agent " + routingHost.toString() + " was unavailable to start VM " - + proxy.getName()); - } - - avoid.add(routingHost); - proxy.setPrivateIpAddress(null); - freePrivateIpAddress(privateIpAddress, proxy.getDataCenterId(), proxy.getId()); - proxy.setGuestIpAddress(null); - _dcDao.releaseLinkLocalPrivateIpAddress(guestIpAddress, proxy.getDataCenterId(), proxy.getId()); - _storageMgr.unshare(proxy, vols, routingHost); - } while (--retry > 0 && (routingHost = (HostVO) _agentMgr.findHost(Host.Type.Routing, dc, pod, sp, - _serviceOffering, _template, proxy, null, avoid)) != null); - if (routingHost == null || retry <= 0) { - - SubscriptionMgr.getInstance().notifySubscribers( - ConsoleProxyManager.ALERT_SUBJECT, - this, - new ConsoleProxyAlertEventArgs( - ConsoleProxyAlertEventArgs.PROXY_START_FAILURE, - proxy.getDataCenterId(), proxy.getId(), proxy, - "Unable to find a routing host to run") - ); - - final EventVO event = new EventVO(); - event.setUserId(User.UID_SYSTEM); - event.setAccountId(Account.ACCOUNT_ID_SYSTEM); - event.setType(EventTypes.EVENT_PROXY_START); - event.setLevel(EventVO.LEVEL_ERROR); - event.setStartId(startEventId); - event.setDescription("Starting console proxy failed due to unable to find a host - " + proxy.getName()); - _eventDao.persist(event); - throw new ExecutionException("Couldn't find a routingHost to run console proxy"); - } - - _consoleProxyDao.updateIf(proxy, Event.OperationSucceeded, routingHost.getId()); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Console proxy is now started, vm id : " + proxy.getId()); - } - - // If starting the console proxy failed due to the external - // firewall not being reachable, send an alert. - if (answer != null && answer.getDetails() != null && answer.getDetails().equals("firewall")) { - - SubscriptionMgr.getInstance().notifySubscribers( - ConsoleProxyManager.ALERT_SUBJECT, - this, - new ConsoleProxyAlertEventArgs( - ConsoleProxyAlertEventArgs.PROXY_FIREWALL_ALERT, - proxy.getDataCenterId(), proxy - .getId(), proxy, null) - ); - } - - SubscriptionMgr.getInstance().notifySubscribers( - ConsoleProxyManager.ALERT_SUBJECT, - this, - new ConsoleProxyAlertEventArgs( - ConsoleProxyAlertEventArgs.PROXY_UP, proxy.getDataCenterId(), proxy.getId(), - proxy, null) - ); - - return proxy; - } catch (Throwable thr) { - s_logger.warn("Unexpected exception: ", thr); - - SubscriptionMgr.getInstance().notifySubscribers( - ConsoleProxyManager.ALERT_SUBJECT, - this, - new ConsoleProxyAlertEventArgs( - ConsoleProxyAlertEventArgs.PROXY_START_FAILURE, - proxy.getDataCenterId(), proxy.getId(), proxy, - "Unexpected exception: " + thr.getMessage())); - -/* - final EventVO event = new EventVO(); - event.setUserId(User.UID_SYSTEM); - event.setAccountId(Account.ACCOUNT_ID_SYSTEM); - event.setType(EventTypes.EVENT_PROXY_START); - event.setLevel(EventVO.LEVEL_ERROR); - event.setStartId(startEventId); - event.setDescription("Starting console proxy failed due to unhandled exception - " - + proxy.getName()); - _eventDao.persist(event); -*/ - - Transaction txn = Transaction.currentTxn(); - try { - txn.start(); - String privateIpAddress = proxy.getPrivateIpAddress(); - if (privateIpAddress != null) { - proxy.setPrivateIpAddress(null); - freePrivateIpAddress(privateIpAddress, proxy.getDataCenterId(), proxy.getId()); - } - - _consoleProxyDao.updateIf(proxy, Event.OperationFailed, null); - txn.commit(); - } catch (Exception e) { - s_logger.error("Caught exception during error recovery"); - } - - if (thr instanceof StorageUnavailableException) { - throw (StorageUnavailableException) thr; - } else if (thr instanceof ConcurrentOperationException) { - throw (ConcurrentOperationException) thr; - } else if (thr instanceof ExecutionException) { - s_logger.error("Error while starting console proxy due to " + thr.getMessage()); - } else { - s_logger.error("Error while starting console proxy ", thr); - } - return null; - } - } - - s_logger.warn("Starting console proxy encounters non-startable situation"); - return null; - } - - public ConsoleProxyVO assignProxyFromRunningPool(long dataCenterId) { - - if (s_logger.isTraceEnabled()) - s_logger.trace("Assign console proxy from running pool for request from data center : " + dataCenterId); - - ConsoleProxyAllocator allocator = getCurrentAllocator(); - assert (allocator != null); - List runningList = _consoleProxyDao.getProxyListInStates(dataCenterId, State.Running); - if (runningList != null && runningList.size() > 0) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("Running proxy pool size : " - + runningList.size()); - for (ConsoleProxyVO proxy : runningList) - s_logger.trace("Running proxy instance : " - + proxy.getName()); - } - - List> l = _consoleProxyDao.getProxyLoadMatrix(); - Map loadInfo = new HashMap(); - if (l != null) { - for (Pair p : l) { - loadInfo.put(p.first(), p.second()); - - if (s_logger.isTraceEnabled()) { - s_logger.trace("Running proxy instance allocation load { proxy id : " - + p.first() + ", load : " + p.second() + "}"); - } - } - } - return allocator.allocProxy(runningList, loadInfo, dataCenterId); - } else { - if (s_logger.isTraceEnabled()) - s_logger.trace("Empty running proxy pool for now in data center : " + dataCenterId); - } - return null; - } - - public ConsoleProxyVO assignProxyFromStoppedPool(long dataCenterId) { - List l = _consoleProxyDao.getProxyListInStates( - dataCenterId, State.Creating, State.Starting, State.Stopped, - State.Migrating); - if (l != null && l.size() > 0) - return l.get(0); - - return null; - } - - public ConsoleProxyVO startNew(long dataCenterId) { - - if (s_logger.isDebugEnabled()) - s_logger.debug("Assign console proxy from a newly started instance for request from data center : " + dataCenterId); - - Map context = createProxyInstance(dataCenterId); - - long proxyVmId = (Long) context.get("proxyVmId"); - if (proxyVmId == 0) { - if (s_logger.isTraceEnabled()) - s_logger.trace("Creating proxy instance failed, data center id : " + dataCenterId); - - // release critical system resource on failure - if (context.get("publicIpAddress") != null) - freePublicIpAddress((String) context.get("publicIpAddress"), dataCenterId, 0); - - return null; - } - - ConsoleProxyVO proxy = allocProxyStorage(dataCenterId, proxyVmId); - if (proxy != null) { - SubscriptionMgr.getInstance().notifySubscribers( - ConsoleProxyManager.ALERT_SUBJECT, - this, - new ConsoleProxyAlertEventArgs( - ConsoleProxyAlertEventArgs.PROXY_CREATED, - dataCenterId, proxy.getId(), proxy, null)); - return proxy; - } else { - if (s_logger.isDebugEnabled()) - s_logger.debug("Unable to allocate console proxy storage, remove the console proxy record from DB, proxy id: " + proxyVmId); - - SubscriptionMgr.getInstance().notifySubscribers( - ConsoleProxyManager.ALERT_SUBJECT, - this, - new ConsoleProxyAlertEventArgs( - ConsoleProxyAlertEventArgs.PROXY_CREATE_FAILURE, - dataCenterId, proxyVmId, null, - "Unable to allocate storage")); - - destroyProxyDBOnly(proxyVmId); - } - return null; - } - - @DB - protected Map createProxyInstance(long dataCenterId) { - - Map context = new HashMap(); - String publicIpAddress = null; - - Transaction txn = Transaction.currentTxn(); - try { - DataCenterVO dc = _dcDao.findById(dataCenterId); - assert (dc != null); - context.put("dc", dc); - - // this will basically allocate the pod based on data center id as - // we use system user id here - Set avoidPods = new HashSet(); - Pair pod = null; - networkInfo publicIpAndVlan = null; - - // About MAC address allocation - // MAC address used by User VM is inherited from DomR MAC address, - // with the least 16 bits overrided. to avoid - // potential conflicts, domP will mask bit 31 - // - String[] macAddresses = _dcDao.getNextAvailableMacAddressPair(dataCenterId, (1L << 31)); - String privateMacAddress = macAddresses[0]; - String publicMacAddress = macAddresses[1]; - macAddresses = _dcDao.getNextAvailableMacAddressPair(dataCenterId, (1L << 31)); - String guestMacAddress = macAddresses[0]; - while ((pod = _agentMgr.findPod(_template, _serviceOffering, dc, - Account.ACCOUNT_ID_SYSTEM, avoidPods)) != null) { - publicIpAndVlan = allocPublicIpAddress(dataCenterId, pod.first().getId(), publicMacAddress); - if (publicIpAndVlan == null) { - s_logger.warn("Unable to allocate public IP address for console proxy vm in data center : " - + dataCenterId + ", pod=" + pod.first().getId()); - avoidPods.add(pod.first().getId()); - } else { - break; - } - } - - if (pod == null || publicIpAndVlan == null) { - s_logger.warn("Unable to allocate pod for console proxy vm in data center : " + dataCenterId); - - context.put("proxyVmId", (long) 0); - return context; - } - - long id = _consoleProxyDao.getNextInSequence(Long.class, "id"); - - context.put("publicIpAddress", publicIpAndVlan._ipAddr); - context.put("pod", pod); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Pod allocated " + pod.first().getName()); - } - - String cidrNetmask = NetUtils.getCidrNetmask(pod.first().getCidrSize()); - - // Find the VLAN ID, VLAN gateway, and VLAN netmask for - // publicIpAddress - publicIpAddress = publicIpAndVlan._ipAddr; - - String vlanGateway = publicIpAndVlan._gateWay; - String vlanNetmask = publicIpAndVlan._netMask; - - txn.start(); - ConsoleProxyVO proxy; - String name = VirtualMachineName.getConsoleProxyName(id, _instance).intern(); - proxy = new ConsoleProxyVO(id, name, guestMacAddress, null, NetUtils.getLinkLocalNetMask(), - privateMacAddress, null, cidrNetmask, _template.getId(), - _template.getGuestOSId(), publicMacAddress, - publicIpAddress, vlanNetmask, publicIpAndVlan._vlanDbId, publicIpAndVlan._vlanid, pod.first().getId(), dataCenterId, - vlanGateway, null, dc.getDns1(), dc.getDns2(), _domain, - _proxyRamSize, 0); - - proxy.setLastHostId(pod.second()); - proxy = _consoleProxyDao.persist(proxy); - long proxyVmId = proxy.getId(); - - final EventVO event = new EventVO(); - event.setUserId(User.UID_SYSTEM); - event.setAccountId(Account.ACCOUNT_ID_SYSTEM); - event.setType(EventTypes.EVENT_PROXY_CREATE); - event.setLevel(EventVO.LEVEL_INFO); - event.setDescription("New console proxy created - " - + proxy.getName()); - _eventDao.persist(event); - txn.commit(); - - context.put("proxyVmId", proxyVmId); - return context; - } catch (Throwable e) { - s_logger.error("Unexpected exception : ", e); - - context.put("proxyVmId", (long) 0); - return context; - } - } - - @DB - protected ConsoleProxyVO allocProxyStorage(long dataCenterId, long proxyVmId) { - ConsoleProxyVO proxy = _consoleProxyDao.findById(proxyVmId); - assert (proxy != null); - - DataCenterVO dc = _dcDao.findById(dataCenterId); - HostPodVO pod = _podDao.findById(proxy.getPodId()); - final AccountVO account = _accountDao.findById(Account.ACCOUNT_ID_SYSTEM); - - try { - List vols = _storageMgr.create(account, proxy, _template, dc, pod, _serviceOffering, null,0); - if (vols == null) { - s_logger.error("Unable to alloc storage for console proxy"); - return null; - } - - Transaction txn = Transaction.currentTxn(); - txn.start(); - - // update pool id - ConsoleProxyVO vo = _consoleProxyDao.findById(proxy.getId()); - _consoleProxyDao.update(proxy.getId(), vo); - - // kick the state machine - _consoleProxyDao.updateIf(proxy, Event.OperationSucceeded, null); - - txn.commit(); - return proxy; - } catch (StorageUnavailableException e) { - s_logger.error("Unable to alloc storage for console proxy: ", e); - return null; - } catch (ExecutionException e) { - s_logger.error("Unable to alloc storage for console proxy: ", e); - return null; - } - } - - private networkInfo allocPublicIpAddress(long dcId, long podId, String macAddr) { - - if (_IpAllocator != null && _IpAllocator.exteralIpAddressAllocatorEnabled()) { - IpAddrAllocator.IpAddr ip = _IpAllocator.getPublicIpAddress(macAddr, dcId, podId); - networkInfo net = new networkInfo(ip.ipaddr, ip.netMask, ip.gateway, null, "untagged"); - return net; - } - - Pair ipAndVlan = _vlanDao.assignIpAddress(dcId, - Account.ACCOUNT_ID_SYSTEM, DomainVO.ROOT_DOMAIN, - VlanType.VirtualNetwork, true); - - if (ipAndVlan == null) { - s_logger.debug("Unable to get public ip address (type=Virtual) for console proxy vm for data center : " + dcId); - ipAndVlan = _vlanDao.assignPodDirectAttachIpAddress(dcId, podId, Account.ACCOUNT_ID_SYSTEM, DomainVO.ROOT_DOMAIN); - if (ipAndVlan == null) - s_logger.debug("Unable to get public ip address (type=DirectAttach) for console proxy vm for data center : " + dcId); - } - if (ipAndVlan != null) { - VlanVO vlan = ipAndVlan.second(); - networkInfo net = new networkInfo(ipAndVlan.first(), vlan.getVlanNetmask(), vlan.getVlanGateway(), vlan.getId(), vlan.getVlanId()); - return net; - } - return null; - } - - private String allocPrivateIpAddress(Long dcId, Long podId, Long proxyId, String macAddr) { - if (_IpAllocator != null && _IpAllocator.exteralIpAddressAllocatorEnabled()) { - return _IpAllocator.getPrivateIpAddress(macAddr, dcId, podId).ipaddr; - } else { - return _dcDao.allocatePrivateIpAddress(dcId, podId, proxyId); - } - } - - private void freePrivateIpAddress(String ipAddress, Long dcId, Long podId) { - if (_IpAllocator != null && _IpAllocator.exteralIpAddressAllocatorEnabled()) { - _IpAllocator.releasePrivateIpAddress(ipAddress, dcId, podId); - } else { - _dcDao.releasePrivateIpAddress(ipAddress, dcId, podId); - } - } - - private void freePublicIpAddress(String ipAddress, long dcId, long podId) { - if (_IpAllocator != null && _IpAllocator.exteralIpAddressAllocatorEnabled()) { - _IpAllocator.releasePublicIpAddress(ipAddress, dcId, podId); - } else { - _ipAddressDao.unassignIpAddress(ipAddress); - } - } - - private ConsoleProxyAllocator getCurrentAllocator() { - // for now, only one adapter is supported - Enumeration it = _consoleProxyAllocators.enumeration(); - if (it.hasMoreElements()) - return it.nextElement(); - - return null; - } - - protected String connect(String ipAddress, int port) { - for (int i = 0; i <= _ssh_retry; i++) { - SocketChannel sch = null; - try { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Trying to connect to " + ipAddress); - } - sch = SocketChannel.open(); - sch.configureBlocking(true); - sch.socket().setSoTimeout(5000); - - InetSocketAddress addr = new InetSocketAddress(ipAddress, port); - sch.connect(addr); - return null; - } catch (IOException e) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Could not connect to " + ipAddress); - } - } finally { - if (sch != null) { - try { - sch.close(); - } catch (IOException e) { - } - } - } - try { - Thread.sleep(_ssh_sleep); - } catch (InterruptedException ex) { - } - } - - s_logger.debug("Unable to logon to " + ipAddress); - - return "Unable to connect"; - } - - public void onLoadAnswer(ConsoleProxyLoadAnswer answer) { - if (answer.getDetails() == null) - return; - - ConsoleProxyStatus status = null; - try { - GsonBuilder gb = new GsonBuilder(); - gb.setVersion(1.3); - Gson gson = gb.create(); - status = gson.fromJson(answer.getDetails(), ConsoleProxyStatus.class); - } catch (Throwable e) { - s_logger.warn("Unable to parse load info from proxy, proxy vm id : " - + answer.getProxyVmId() + ", info : " + answer.getDetails()); - } - - if (status != null) { - int count = 0; - if (status.getConnections() != null) - count = status.getConnections().length; - - byte[] details = null; - if (answer.getDetails() != null) - details = answer.getDetails().getBytes(Charset.forName("US-ASCII")); - _consoleProxyDao.update(answer.getProxyVmId(), count, DateUtil.currentGMTTime(), details); - } else { - if (s_logger.isTraceEnabled()) - s_logger.trace("Unable to get console proxy load info, id : " + answer.getProxyVmId()); - - _consoleProxyDao.update(answer.getProxyVmId(), 0, DateUtil.currentGMTTime(), null); - // TODO : something is wrong with the VM, restart it? - } - } - - public void onLoadReport(ConsoleProxyLoadReportCommand cmd) { - if (cmd.getLoadInfo() == null) - return; - - ConsoleProxyStatus status = null; - try { - GsonBuilder gb = new GsonBuilder(); - gb.setVersion(1.3); - Gson gson = gb.create(); - status = gson.fromJson(cmd.getLoadInfo(), ConsoleProxyStatus.class); - } catch (Throwable e) { - s_logger.warn("Unable to parse load info from proxy, proxy vm id : " - + cmd.getProxyVmId() + ", info : " + cmd.getLoadInfo()); - } - - if (status != null) { - int count = 0; - if (status.getConnections() != null) - count = status.getConnections().length; - - byte[] details = null; - if (cmd.getLoadInfo() != null) - details = cmd.getLoadInfo().getBytes(Charset.forName("US-ASCII")); - _consoleProxyDao.update(cmd.getProxyVmId(), count, DateUtil.currentGMTTime(), details); - } else { - if (s_logger.isTraceEnabled()) - s_logger.trace("Unable to get console proxy load info, id : " + cmd.getProxyVmId()); - - _consoleProxyDao.update(cmd.getProxyVmId(), 0, DateUtil.currentGMTTime(), null); - } - } - - public AgentControlAnswer onConsoleAccessAuthentication( - ConsoleAccessAuthenticationCommand cmd) { - long vmId = 0; - - if (cmd.getVmId() != null && cmd.getVmId().isEmpty()) { - if (s_logger.isTraceEnabled()) - s_logger.trace("Invalid vm id sent from proxy(happens when proxy session has terminated)"); - return new ConsoleAccessAuthenticationAnswer(cmd, false); - } - - try { - vmId = Long.parseLong(cmd.getVmId()); - } catch (NumberFormatException e) { - s_logger.error("Invalid vm id " + cmd.getVmId() + " sent from console access authentication", e); - return new ConsoleAccessAuthenticationAnswer(cmd, false); - } - - // TODO authentication channel between console proxy VM and management - // server needs to be secured, - // the data is now being sent through private network, but this is - // apparently not enough - VMInstanceVO vm = _instanceDao.findById(vmId); - if (vm == null) { - return new ConsoleAccessAuthenticationAnswer(cmd, false); - } - - if (vm.getHostId() == null) { - s_logger.warn("VM " + vmId + " lost host info, failed authentication request"); - return new ConsoleAccessAuthenticationAnswer(cmd, false); - } - - HostVO host = _hostDao.findById(vm.getHostId()); - if (host == null) { - s_logger.warn("VM " + vmId + "'s host does not exist, fail authentication request"); - return new ConsoleAccessAuthenticationAnswer(cmd, false); - } - - String sid = cmd.getSid(); - if (sid == null || !sid.equals(vm.getVncPassword())) { - s_logger.warn("sid " + sid + " in url does not match stored sid " + vm.getVncPassword()); - return new ConsoleAccessAuthenticationAnswer(cmd, false); - } - - return new ConsoleAccessAuthenticationAnswer(cmd, true); - } - - private ConsoleProxyVO findConsoleProxyByHost(HostVO host) throws NumberFormatException { - String name = host.getName(); - long proxyVmId = 0; - ConsoleProxyVO proxy = null; - if (name != null && name.startsWith("v-")) { - String[] tokens = name.split("-"); - proxyVmId = Long.parseLong(tokens[1]); - proxy = this._consoleProxyDao.findById(proxyVmId); - } - return proxy; - } - @Override - public void onAgentConnect(HostVO host, StartupCommand cmd) { - if (host.getType() == Type.ConsoleProxy) { - // TODO we can use this event to mark the proxy is up and - // functioning instead of - // pinging the console proxy VM command port - // - // for now, just log a message - if (s_logger.isInfoEnabled()) - s_logger.info("Console proxy agent is connected. proxy: " + host.getName()); - - /* update public/private ip address */ - if (_IpAllocator != null && _IpAllocator.exteralIpAddressAllocatorEnabled()) { - try { - ConsoleProxyVO console = findConsoleProxyByHost(host); - if (console == null) { - s_logger.debug("Can't find console proxy "); - return; - } - console.setPrivateIpAddress(cmd.getPrivateIpAddress()); - console.setPrivateNetmask(cmd.getPrivateNetmask()); - console.setPublicIpAddress(cmd.getPublicIpAddress()); - console.setPublicNetmask(cmd.getPublicNetmask()); - _consoleProxyDao.persist(console); - } catch (NumberFormatException e) { - } - } - } - } - - @Override - public void onAgentDisconnect(long agentId, com.cloud.host.Status state) { - if (state == com.cloud.host.Status.Alert || state == com.cloud.host.Status.Disconnected) { - // be it either in alert or in disconnected state, the agent process - // may be gone in the VM, - // we will be reacting to stop the corresponding VM and let the scan - // process to - HostVO host = _hostDao.findById(agentId); - if (host.getType() == Type.ConsoleProxy) { - String name = host.getName(); - if (s_logger.isInfoEnabled()) - s_logger.info("Console proxy agent disconnected, proxy: " + name); - if (name != null && name.startsWith("v-")) { - String[] tokens = name.split("-"); - long proxyVmId = 0; - try { - proxyVmId = Long.parseLong(tokens[1]); - } catch (NumberFormatException e) { - s_logger.error("Unexpected exception " + e.getMessage(), e); - return; - } - - final ConsoleProxyVO proxy = this._consoleProxyDao.findById(proxyVmId); - if (proxy != null) { - Long hostId = proxy.getHostId(); - - // Disable this feature for now, as it conflicts with - // the case of allowing user to reboot console proxy - // when rebooting happens, we will receive disconnect - // here and we can't enter into stopping process, - // as when the rebooted one comes up, it will kick off a - // newly started one and trigger the process - // continue on forever - - /* - * _capacityScanScheduler.execute(new Runnable() { - * public void run() { if(s_logger.isInfoEnabled()) - * s_logger.info("Stop console proxy " + proxy.getName() - * + - * " VM because of that the agent running inside it has disconnected" - * ); stopProxy(proxy.getId()); } }); - */ - } else { - if (s_logger.isInfoEnabled()) - s_logger.info("Console proxy agent disconnected but corresponding console proxy VM no longer exists in DB, proxy: " + name); - } - } else { - assert (false) : "Invalid console proxy name: " + name; - } - } - } - } - - private void checkPendingProxyVMs() { - // drive state to change away from transient states - List l = _consoleProxyDao.getProxyListInStates(State.Creating); - if (l != null && l.size() > 0) { - for (ConsoleProxyVO proxy : l) { - if (proxy.getLastUpdateTime() == null - || (proxy.getLastUpdateTime() != null && System.currentTimeMillis() - proxy.getLastUpdateTime().getTime() > 60000)) { - try { - ConsoleProxyVO readyProxy = null; - if (_allocProxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { - try { - readyProxy = allocProxyStorage(proxy.getDataCenterId(), proxy.getId()); - } finally { - _allocProxyLock.unlock(); - } - - if (readyProxy != null) { - GlobalLock proxyLock = GlobalLock.getInternLock(getProxyLockName(readyProxy.getId())); - try { - if (proxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { - try { - readyProxy = start(readyProxy.getId(), 0); - } finally { - proxyLock.unlock(); - } - } else { - if (s_logger.isInfoEnabled()) - s_logger.info("Unable to acquire synchronization lock to start console proxy : " + readyProxy.getName()); - } - } finally { - proxyLock.releaseRef(); - } - } - } else { - if (s_logger.isInfoEnabled()) - s_logger.info("Unable to acquire synchronization lock to allocate proxy storage, wait for next turn"); - } - } catch (StorageUnavailableException e) { - s_logger.warn("Storage unavailable", e); - } catch (InsufficientCapacityException e) { - s_logger.warn("insuffiient capacity", e); - } catch (ConcurrentOperationException e) { - s_logger.debug("Concurrent operation: " - + e.getMessage()); - } - } - } - } - } - - private Runnable getCapacityScanTask() { - return new Runnable() { - - @Override - public void run() { - Transaction txn = Transaction.open(Transaction.CLOUD_DB); - try { - reallyRun(); - } catch (Throwable e) { - s_logger.warn("Unexpected exception " + e.getMessage(), e); - } finally { - StackMaid.current().exitCleanup(); - txn.close(); - } - } - - private void reallyRun() { - if (s_logger.isTraceEnabled()) - s_logger.trace("Begin console proxy capacity scan"); - - // config var for consoleproxy.restart check - String restart = _configDao.getValue("consoleproxy.restart"); - if(restart != null && restart.equalsIgnoreCase("false")) - { - s_logger.debug("Capacity scan disabled purposefully, consoleproxy.restart = false. This happens when the primarystorage is in maintenance mode"); - return; - } - - Map zoneHostInfoMap = getZoneHostInfo(); - if (isServiceReady(zoneHostInfoMap)) { - if (s_logger.isTraceEnabled()) - s_logger.trace("Service is ready, check to see if we need to allocate standby capacity"); - - if (!_capacityScanLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) { - if (s_logger.isTraceEnabled()) - s_logger.trace("Capacity scan lock is used by others, skip and wait for my turn"); - return; - } - - if (s_logger.isTraceEnabled()) - s_logger.trace("*** Begining capacity scan... ***"); - - try { - checkPendingProxyVMs(); - - // scan default data center first - long defaultId = 0; - - // proxy count info by data-centers (zone-id, zone-name, - // count) - List l = _consoleProxyDao.getDatacenterProxyLoadMatrix(); - - // running VM session count by data-centers (zone-id, - // zone-name, count) - List listVmCounts = _consoleProxyDao.getDatacenterSessionLoadMatrix(); - - // indexing load info by data-center id - Map mapVmCounts = new HashMap(); - if (listVmCounts != null) - for (ConsoleProxyLoadInfo info : listVmCounts) - mapVmCounts.put(info.getId(), info); - - for (ConsoleProxyLoadInfo info : l) { - if (info.getName().equals(_instance)) { - ConsoleProxyLoadInfo vmInfo = mapVmCounts.get(info.getId()); - - if (!checkCapacity(info, vmInfo != null ? vmInfo : new ConsoleProxyLoadInfo())) { - if (isZoneReady(zoneHostInfoMap, info.getId())) { - allocCapacity(info.getId()); - } else { - if (s_logger.isTraceEnabled()) - s_logger.trace("Zone " + info.getId() + " is not ready to alloc standy console proxy"); - } - } - - defaultId = info.getId(); - break; - } - } - - // scan rest of data-centers - for (ConsoleProxyLoadInfo info : l) { - if (info.getId() != defaultId) { - ConsoleProxyLoadInfo vmInfo = mapVmCounts.get(info.getId()); - - if (!checkCapacity(info, vmInfo != null ? vmInfo : new ConsoleProxyLoadInfo())) { - if (isZoneReady(zoneHostInfoMap, info.getId())) { - allocCapacity(info.getId()); - } else { - if (s_logger.isTraceEnabled()) - s_logger.trace("Zone " + info.getId() + " is not ready to alloc standy console proxy"); - } - } - } - } - - if (s_logger.isTraceEnabled()) - s_logger.trace("*** Stop capacity scan ***"); - } finally { - _capacityScanLock.unlock(); - } - - } else { - if (s_logger.isTraceEnabled()) - s_logger.trace("Service is not ready for capacity preallocation, wait for next time"); - } - - if (s_logger.isTraceEnabled()) - s_logger.trace("End of console proxy capacity scan"); - } - }; - } - - private boolean checkCapacity(ConsoleProxyLoadInfo proxyCountInfo, - ConsoleProxyLoadInfo vmCountInfo) { - - if (proxyCountInfo.getCount() * _capacityPerProxy - - vmCountInfo.getCount() <= _standbyCapacity) - return false; - - return true; - } - - private void allocCapacity(long dataCenterId) { - if (s_logger.isTraceEnabled()) - s_logger.trace("Allocate console proxy standby capacity for data center : " + dataCenterId); - - boolean proxyFromStoppedPool = false; - ConsoleProxyVO proxy = assignProxyFromStoppedPool(dataCenterId); - if (proxy == null) { - if (s_logger.isInfoEnabled()) - s_logger.info("No stopped console proxy is available, need to allocate a new console proxy"); - - if (_allocProxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { - try { - proxy = startNew(dataCenterId); - } finally { - _allocProxyLock.unlock(); - } - } else { - if (s_logger.isInfoEnabled()) - s_logger.info("Unable to acquire synchronization lock to allocate proxy resource for standby capacity, wait for next scan"); - return; - } - } else { - if (s_logger.isInfoEnabled()) - s_logger.info("Found a stopped console proxy, bring it up to running pool. proxy vm id : " + proxy.getId()); - proxyFromStoppedPool = true; - } - - if (proxy != null) { - long proxyVmId = proxy.getId(); - GlobalLock proxyLock = GlobalLock.getInternLock(getProxyLockName(proxyVmId)); - try { - if (proxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { - try { - proxy = startProxy(proxyVmId, 0); - } finally { - proxyLock.unlock(); - } - } else { - if (s_logger.isInfoEnabled()) - s_logger.info("Unable to acquire synchronization lock to start proxy for standby capacity, proxy vm id : " + proxy.getId()); - return; - } - } finally { - proxyLock.releaseRef(); - } - - if (proxy == null) { - if (s_logger.isInfoEnabled()) - s_logger.info("Unable to start console proxy for standby capacity, proxy vm Id : " - + proxyVmId + ", will recycle it and start a new one"); - - if (proxyFromStoppedPool) - destroyProxy(proxyVmId, 0); - } else { - if (s_logger.isInfoEnabled()) - s_logger.info("Console proxy " + proxy.getName() + " is started"); - } - } - } - - public boolean isServiceReady(Map zoneHostInfoMap) { - for (ZoneHostInfo zoneHostInfo : zoneHostInfoMap.values()) { - if (isZoneHostReady(zoneHostInfo)) { - if (s_logger.isInfoEnabled()) - s_logger.info("Zone " + zoneHostInfo.getDcId() + " is ready to launch"); - return true; - } - } - - return false; - } - - public boolean isZoneReady(Map zoneHostInfoMap, - long dataCenterId) { - ZoneHostInfo zoneHostInfo = zoneHostInfoMap.get(dataCenterId); - if (zoneHostInfo != null && isZoneHostReady(zoneHostInfo)) { - VMTemplateVO template = _templateDao.findConsoleProxyTemplate(); - HostVO secondaryStorageHost = _storageMgr.getSecondaryStorageHost(dataCenterId); - boolean templateReady = false; - - if (template != null && secondaryStorageHost != null) { - VMTemplateHostVO templateHostRef = _vmTemplateHostDao.findByHostTemplate(secondaryStorageHost.getId(), template.getId()); - templateReady = (templateHostRef != null) && (templateHostRef.getDownloadState() == Status.DOWNLOADED); - } - - if (templateReady) { - List> l = _consoleProxyDao.getDatacenterStoragePoolHostInfo(dataCenterId, _use_lvm); - if (l != null && l.size() > 0 && l.get(0).second().intValue() > 0) { - return true; - } else { - if (s_logger.isTraceEnabled()) - s_logger.trace("Primary storage is not ready, wait until it is ready to launch console proxy"); - } - } else { - if (s_logger.isTraceEnabled()) - s_logger.trace("Zone host is ready, but console proxy template is not ready"); - } - } - return false; - } - - private boolean isZoneHostReady(ZoneHostInfo zoneHostInfo) { - int expectedFlags = 0; - if (_use_storage_vm) - expectedFlags = RunningHostInfoAgregator.ZoneHostInfo.ROUTING_HOST_MASK; - else - expectedFlags = RunningHostInfoAgregator.ZoneHostInfo.ALL_HOST_MASK; - - return (zoneHostInfo.getFlags() & expectedFlags) == expectedFlags; - } - - private synchronized Map getZoneHostInfo() { - Date cutTime = DateUtil.currentGMTTime(); - List l = _hostDao.getRunningHostCounts(new Date(cutTime.getTime() - ClusterManager.DEFAULT_HEARTBEAT_THRESHOLD)); - - RunningHostInfoAgregator aggregator = new RunningHostInfoAgregator(); - if (l.size() > 0) - for (RunningHostCountInfo countInfo : l) - aggregator.aggregate(countInfo); - - return aggregator.getZoneHostInfoMap(); - } - - @Override - public String getName() { - return _name; - } - - @Override - public boolean start() { - if (s_logger.isInfoEnabled()) - s_logger.info("Start console proxy manager"); - - return true; - } - - @Override - public boolean stop() { - if (s_logger.isInfoEnabled()) - s_logger.info("Stop console proxy manager"); - _capacityScanScheduler.shutdownNow(); - - try { - _capacityScanScheduler.awaitTermination(EXECUTOR_SHUTDOWN_TIMEOUT, - TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - } - - _capacityScanLock.releaseRef(); - _allocProxyLock.releaseRef(); - return true; - } - - @Override - public boolean configure(String name, Map params) - throws ConfigurationException { - if (s_logger.isInfoEnabled()) - s_logger.info("Start configuring console proxy manager : " + name); - - _name = name; - - ComponentLocator locator = ComponentLocator.getCurrentLocator(); - ConfigurationDao configDao = locator.getDao(ConfigurationDao.class); - if (configDao == null) { - throw new ConfigurationException( - "Unable to get the configuration dao."); - } - - Map configs = configDao.getConfiguration( - "management-server", params); - - _proxyRamSize = NumbersUtil.parseInt(configs - .get("consoleproxy.ram.size"), DEFAULT_PROXY_VM_RAMSIZE); - - String value = configs.get("start.retry"); - _find_host_retry = NumbersUtil.parseInt(value, - DEFAULT_FIND_HOST_RETRY_COUNT); - - value = configs.get("consoleproxy.cmd.port"); - _proxyCmdPort = NumbersUtil.parseInt(value, DEFAULT_PROXY_CMD_PORT); - - value = configs.get("consoleproxy.sslEnabled"); - if (value != null && value.equalsIgnoreCase("true")) - _sslEnabled = true; - - value = configs.get("consoleproxy.capacityscan.interval"); - _capacityScanInterval = NumbersUtil.parseLong(value, DEFAULT_CAPACITY_SCAN_INTERVAL); - - _capacityPerProxy = NumbersUtil.parseInt(configs.get("consoleproxy.session.max"), DEFAULT_PROXY_CAPACITY); - _standbyCapacity = NumbersUtil.parseInt(configs.get("consoleproxy.capacity.standby"), DEFAULT_STANDBY_CAPACITY); - _proxySessionTimeoutValue = NumbersUtil.parseInt(configs.get("consoleproxy.session.timeout"), DEFAULT_PROXY_SESSION_TIMEOUT); - - value = configs.get("consoleproxy.port"); - if (value != null) - _consoleProxyPort = NumbersUtil.parseInt(value, ConsoleProxyManager.DEFAULT_PROXY_VNC_PORT); - - value = configs.get("consoleproxy.url.port"); - if (value != null) - _consoleProxyUrlPort = NumbersUtil.parseInt(value, ConsoleProxyManager.DEFAULT_PROXY_URL_PORT); - - value = configs.get("system.vm.use.local.storage"); - if (value != null && value.equalsIgnoreCase("true")) - _use_lvm = true; - - value = configs.get("secondary.storage.vm"); - if (value != null && value.equalsIgnoreCase("true")) - _use_storage_vm = true; - - if (s_logger.isInfoEnabled()) { - s_logger.info("Console proxy max session soft limit : " + _capacityPerProxy); - s_logger.info("Console proxy standby capacity : " + _standbyCapacity); - } - - _domain = configs.get("domain"); - if (_domain == null) { - _domain = "foo.com"; - } - - _instance = configs.get("instance.name"); - if (_instance == null) { - _instance = "DEFAULT"; - } - - value = (String) params.get("ssh.sleep"); - _ssh_sleep = NumbersUtil.parseInt(value, 5) * 1000; - - value = (String) params.get("ssh.retry"); - _ssh_retry = NumbersUtil.parseInt(value, 3); - - Map agentMgrConfigs = configDao.getConfiguration("AgentManager", params); - _mgmt_host = agentMgrConfigs.get("host"); - if (_mgmt_host == null) { - s_logger.warn("Critical warning! Please configure your management server host address right after you have started your management server and then restart it, otherwise you won't be able to do console access"); - } - - value = agentMgrConfigs.get("port"); - _mgmt_port = NumbersUtil.parseInt(value, 8250); - - _consoleProxyDao = locator.getDao(ConsoleProxyDao.class); - if (_consoleProxyDao == null) { - throw new ConfigurationException("Unable to get " + ConsoleProxyDao.class.getName()); - } - - _consoleProxyAllocators = locator.getAdapters(ConsoleProxyAllocator.class); - if (_consoleProxyAllocators == null || !_consoleProxyAllocators.isSet()) { - throw new ConfigurationException("Unable to get proxy allocators"); - } - - _dcDao = locator.getDao(DataCenterDao.class); - if (_dcDao == null) { - throw new ConfigurationException("Unable to get " + DataCenterDao.class.getName()); - } - - _templateDao = locator.getDao(VMTemplateDao.class); - if (_templateDao == null) { - throw new ConfigurationException("Unable to get " + VMTemplateDao.class.getName()); - } - - _ipAddressDao = locator.getDao(IPAddressDao.class); - if (_ipAddressDao == null) { - throw new ConfigurationException("Unable to get " + IPAddressDao.class.getName()); - } - - _volsDao = locator.getDao(VolumeDao.class); - if (_volsDao == null) { - throw new ConfigurationException("Unable to get " + VolumeDao.class.getName()); - } - - _podDao = locator.getDao(HostPodDao.class); - if (_podDao == null) { - throw new ConfigurationException("Unable to get " + HostPodDao.class.getName()); - } - - _hostDao = locator.getDao(HostDao.class); - if (_hostDao == null) { - throw new ConfigurationException("Unable to get " + HostDao.class.getName()); - } - - _eventDao = locator.getDao(EventDao.class); - if (_eventDao == null) { - throw new ConfigurationException("Unable to get " + EventDao.class.getName()); - } - - _storagePoolDao = locator.getDao(StoragePoolDao.class); - if (_storagePoolDao == null) { - throw new ConfigurationException("Unable to find " + StoragePoolDao.class); - } - - _configDao = locator.getDao(ConfigurationDao.class); - if (_configDao == null) { - throw new ConfigurationException("Unable to find " + ConfigurationDao.class); - } - - _vmTemplateHostDao = locator.getDao(VMTemplateHostDao.class); - if (_vmTemplateHostDao == null) { - throw new ConfigurationException("Unable to get " + VMTemplateHostDao.class.getName()); - } - - _instanceDao = locator.getDao(VMInstanceDao.class); - if (_instanceDao == null) - throw new ConfigurationException("Unable to get " + VMInstanceDao.class.getName()); - - _capacityDao = locator.getDao(CapacityDao.class); - if (_capacityDao == null) { - throw new ConfigurationException("Unable to get " + CapacityDao.class.getName()); - } - - _haDao = locator.getDao(HighAvailabilityDao.class); - if (_haDao == null) { - throw new ConfigurationException("Unable to get " + HighAvailabilityDao.class.getName()); - } - - _accountDao = locator.getDao(AccountDao.class); - if (_accountDao == null) { - throw new ConfigurationException("Unable to get " + AccountDao.class.getName()); - } - - _vlanDao = locator.getDao(VlanDao.class); - if (_vlanDao == null) { - throw new ConfigurationException("Unable to get " + VlanDao.class.getName()); - } - - _agentMgr = locator.getManager(AgentManager.class); - if (_agentMgr == null) { - throw new ConfigurationException("Unable to get " + AgentManager.class.getName()); - } - - _networkMgr = locator.getManager(NetworkManager.class); - if (_networkMgr == null) { - throw new ConfigurationException("Unable to get " + NetworkManager.class.getName()); - } - - _listener = new ConsoleProxyListener(this); - _agentMgr.registerForHostEvents(_listener, true, true, false); - - _haMgr = locator.getManager(HighAvailabilityManager.class); - if (_haMgr == null) { - throw new ConfigurationException("Unable to get " - + HighAvailabilityManager.class.getName()); - } - - _storageMgr = locator.getManager(StorageManager.class); - if (_storageMgr == null) { - throw new ConfigurationException("Unable to get " - + StorageManager.class.getName()); - } - - _asyncMgr = locator.getManager(AsyncJobManager.class); - if (_asyncMgr == null) { - throw new ConfigurationException("Unable to get " - + AsyncJobManager.class.getName()); - } - - Adapters ipAllocators = locator.getAdapters(IpAddrAllocator.class); - if (ipAllocators != null && ipAllocators.isSet()) { - Enumeration it = ipAllocators.enumeration(); - _IpAllocator = it.nextElement(); - } - - HighAvailabilityManager haMgr = locator.getManager(HighAvailabilityManager.class); - if (haMgr != null) { - haMgr.registerHandler(VirtualMachine.Type.ConsoleProxy, this); - } - - boolean useLocalStorage = Boolean.parseBoolean((String) params.get(Config.SystemVMUseLocalStorage.key())); - _serviceOffering = new ServiceOfferingVO("Fake Offering For DomP", 1, - _proxyRamSize, 0, 0, 0, false, null, GuestIpType.Virtualized, - useLocalStorage, true, null); - _serviceOffering.setUniqueName("Cloud.com-ConsoleProxy"); - _serviceOffering = _offeringDao.persistSystemServiceOffering(_serviceOffering); - _template = _templateDao.findConsoleProxyTemplate(); - if (_template == null) { - throw new ConfigurationException( - "Unable to find the template for console proxy VMs"); - } - - _capacityScanScheduler.scheduleAtFixedRate(getCapacityScanTask(), - STARTUP_DELAY, _capacityScanInterval, TimeUnit.MILLISECONDS); - - if (s_logger.isInfoEnabled()) - s_logger.info("Console Proxy Manager is configured."); - return true; - } - - protected ConsoleProxyManagerImpl() { - } - - @Override - public Command cleanup(ConsoleProxyVO vm, String vmName) { - if (vmName != null) { - return new StopCommand(vm, vmName, VirtualMachineName.getVnet(vmName)); - } else if (vm != null) { - ConsoleProxyVO vo = vm; - return new StopCommand(vo, null); - } else { - throw new CloudRuntimeException("Shouldn't even be here!"); - } - } - - @Override - public void completeStartCommand(ConsoleProxyVO vm) { - _consoleProxyDao.updateIf(vm, Event.AgentReportRunning, vm.getHostId()); - } - - @Override - public void completeStopCommand(ConsoleProxyVO vm) { - completeStopCommand(vm, Event.AgentReportStopped); - } - - @DB - protected void completeStopCommand(ConsoleProxyVO proxy, Event ev) { - Transaction txn = Transaction.currentTxn(); - try { - txn.start(); - String privateIpAddress = proxy.getPrivateIpAddress(); - if (privateIpAddress != null) { - proxy.setPrivateIpAddress(null); - freePrivateIpAddress(privateIpAddress, proxy.getDataCenterId(), proxy.getId()); - } - String guestIpAddress = proxy.getGuestIpAddress(); - if (guestIpAddress != null) { - proxy.setGuestIpAddress(null); - _dcDao.releaseLinkLocalPrivateIpAddress(guestIpAddress, proxy.getDataCenterId(), proxy.getId()); - } - - if (!_consoleProxyDao.updateIf(proxy, ev, null)) { - s_logger.debug("Unable to update the console proxy"); - return; - } - txn.commit(); - } catch (Exception e) { - s_logger.error("Unable to complete stop command due to ", e); - } - - if (_storageMgr.unshare(proxy, null) == null) { - s_logger.warn("Unable to set share to false for " + proxy.getId()); - } - } - - @Override - public ConsoleProxyVO get(long id) { - return _consoleProxyDao.findById(id); - } - - @Override - public Long convertToId(String vmName) { - if (!VirtualMachineName.isValidConsoleProxyName(vmName, _instance)) { - return null; - } - return VirtualMachineName.getConsoleProxyId(vmName); - } - - @Override - public boolean stopProxy(long proxyVmId, long startEventId) { - - AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor(); - if (asyncExecutor != null) { - AsyncJobVO job = asyncExecutor.getJob(); - - if (s_logger.isInfoEnabled()) - s_logger.info("Stop console proxy " + proxyVmId + ", update async job-" + job.getId()); - _asyncMgr.updateAsyncJobAttachment(job.getId(), "console_proxy", proxyVmId); - } - - ConsoleProxyVO proxy = _consoleProxyDao.findById(proxyVmId); - if (proxy == null) { - if (s_logger.isDebugEnabled()) - s_logger.debug("Stopping console proxy failed: console proxy " + proxyVmId + " no longer exists"); - return false; - } -/* - saveStartedEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, - EventTypes.EVENT_PROXY_STOP, "Stopping console proxy with Id: " - + proxyVmId, startEventId); -*/ - try { - return stop(proxy, startEventId); - } catch (AgentUnavailableException e) { - if (s_logger.isDebugEnabled()) - s_logger.debug("Stopping console proxy " + proxy.getName() + " faled : exception " + e.toString()); - return false; - } - } - - @Override - public boolean rebootProxy(long proxyVmId, long startEventId) { - AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor(); - if (asyncExecutor != null) { - AsyncJobVO job = asyncExecutor.getJob(); - - if (s_logger.isInfoEnabled()) - s_logger.info("Reboot console proxy " + proxyVmId + ", update async job-" + job.getId()); - _asyncMgr.updateAsyncJobAttachment(job.getId(), "console_proxy", proxyVmId); - } - - final ConsoleProxyVO proxy = _consoleProxyDao.findById(proxyVmId); - - if (proxy == null || proxy.getState() == State.Destroyed) { - return false; - } - -/* - saveStartedEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, - EventTypes.EVENT_PROXY_REBOOT, - "Rebooting console proxy with Id: " + proxyVmId, startEventId); -*/ - if (proxy.getState() == State.Running && proxy.getHostId() != null) { - final RebootCommand cmd = new RebootCommand(proxy.getInstanceName()); - final Answer answer = _agentMgr.easySend(proxy.getHostId(), cmd); - - if (answer != null) { - if (s_logger.isDebugEnabled()) - s_logger.debug("Successfully reboot console proxy " + proxy.getName()); - - SubscriptionMgr.getInstance().notifySubscribers( - ConsoleProxyManager.ALERT_SUBJECT, - this, - new ConsoleProxyAlertEventArgs( - ConsoleProxyAlertEventArgs.PROXY_REBOOTED, - proxy.getDataCenterId(), proxy.getId(), proxy, - null) - ); - - final EventVO event = new EventVO(); - event.setUserId(User.UID_SYSTEM); - event.setAccountId(Account.ACCOUNT_ID_SYSTEM); - event.setType(EventTypes.EVENT_PROXY_REBOOT); - event.setLevel(EventVO.LEVEL_INFO); - event.setStartId(startEventId); - event.setDescription("Console proxy rebooted - " + proxy.getName()); - _eventDao.persist(event); - return true; - } else { - if (s_logger.isDebugEnabled()) - s_logger.debug("failed to reboot console proxy : " + proxy.getName()); - - final EventVO event = new EventVO(); - event.setUserId(User.UID_SYSTEM); - event.setAccountId(Account.ACCOUNT_ID_SYSTEM); - event.setType(EventTypes.EVENT_PROXY_REBOOT); - event.setLevel(EventVO.LEVEL_ERROR); - event.setStartId(startEventId); - event.setDescription("Rebooting console proxy failed - " + proxy.getName()); - _eventDao.persist(event); - return false; - } - } else { - return startProxy(proxyVmId, 0) != null; - } - } - - @Override - public boolean destroy(ConsoleProxyVO proxy) throws AgentUnavailableException { - return destroyProxy(proxy.getId(), 0); - } - - @Override - @DB - public boolean destroyProxy(long vmId, long startEventId) { - AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor(); - if (asyncExecutor != null) { - AsyncJobVO job = asyncExecutor.getJob(); - - if (s_logger.isInfoEnabled()) - s_logger.info("Destroy console proxy " + vmId + ", update async job-" + job.getId()); - _asyncMgr.updateAsyncJobAttachment(job.getId(), "console_proxy", vmId); - } - - ConsoleProxyVO vm = _consoleProxyDao.findById(vmId); - if (vm == null || vm.getState() == State.Destroyed) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Unable to find vm or vm is destroyed: " + vmId); - } - return true; - } -/* - saveStartedEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, - EventTypes.EVENT_PROXY_DESTROY, - "Destroying console proxy with Id: " + vmId, startEventId); -*/ - if (s_logger.isDebugEnabled()) { - s_logger.debug("Destroying console proxy vm " + vmId); - } - - if (!_consoleProxyDao.updateIf(vm, Event.DestroyRequested, null)) { - s_logger.debug("Unable to destroy the vm because it is not in the correct state: " + vmId); - return false; - } - - Transaction txn = Transaction.currentTxn(); - List vols = null; - try { - vols = _volsDao.findByInstance(vmId); - if (vols.size() != 0) { - _storageMgr.destroy(vm, vols); - } - - return true; - } finally { - try { - txn.start(); - // release critical system resources used by the VM before we - // delete them - if (vm.getPublicIpAddress() != null) - freePublicIpAddress(vm.getPublicIpAddress(), vm.getDataCenterId(), vm.getPodId()); - vm.setPublicIpAddress(null); - - _consoleProxyDao.remove(vm.getId()); - - final EventVO event = new EventVO(); - event.setUserId(User.UID_SYSTEM); - event.setAccountId(Account.ACCOUNT_ID_SYSTEM); - event.setType(EventTypes.EVENT_PROXY_DESTROY); - event.setLevel(EventVO.LEVEL_INFO); - event.setStartId(startEventId); - event.setDescription("Console proxy destroyed - " - + vm.getName()); - _eventDao.persist(event); - - txn.commit(); - } catch (Exception e) { - s_logger.error("Caught this error: ", e); - txn.rollback(); - return false; - } finally { - s_logger.debug("console proxy vm is destroyed : " - + vm.getName()); - } - } - } - - @DB - public boolean destroyProxyDBOnly(long vmId) { - Transaction txn = Transaction.currentTxn(); - try { - txn.start(); - _volsDao.deleteVolumesByInstance(vmId); - - ConsoleProxyVO proxy = _consoleProxyDao.findById(vmId); - if (proxy != null) { - if (proxy.getPublicIpAddress() != null) - freePublicIpAddress(proxy.getPublicIpAddress(), proxy.getDataCenterId(), proxy.getPodId()); - - _consoleProxyDao.remove(vmId); - - final EventVO event = new EventVO(); - event.setUserId(User.UID_SYSTEM); - event.setAccountId(Account.ACCOUNT_ID_SYSTEM); - event.setType(EventTypes.EVENT_PROXY_DESTROY); - event.setLevel(EventVO.LEVEL_INFO); - event.setDescription("Console proxy destroyed - " - + proxy.getName()); - _eventDao.persist(event); - } - - txn.commit(); - return true; - } catch (Exception e) { - s_logger.error("Caught this error: ", e); - txn.rollback(); - return false; - } finally { - s_logger.debug("console proxy vm is destroyed from DB : " + vmId); - } - } - - @Override - public boolean stop(ConsoleProxyVO proxy, long startEventId) - throws AgentUnavailableException { - if (!_consoleProxyDao.updateIf(proxy, Event.StopRequested, proxy.getHostId())) { - s_logger.debug("Unable to stop console proxy: " + proxy.toString()); - return false; - } - - // IPAddressVO ip = _ipAddressDao.findById(proxy.getPublicIpAddress()); - // VlanVO vlan = _vlanDao.findById(new Long(ip.getVlanDbId())); - - GlobalLock proxyLock = GlobalLock.getInternLock(getProxyLockName(proxy.getId())); - try { - if (proxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { - try { - StopCommand cmd = new StopCommand(proxy, true, Integer.toString(_consoleProxyPort), - Integer.toString(_consoleProxyUrlPort), proxy.getPublicIpAddress()); - try { - Long proxyHostId = proxy.getHostId(); - if (proxyHostId == null) { - s_logger.debug("Unable to stop due to proxy " + proxy.getId() - + " as host is no longer available, proxy may already have been stopped"); - return false; - } - StopAnswer answer = (StopAnswer) _agentMgr.send(proxyHostId, cmd); - if (answer == null || !answer.getResult()) { - s_logger.debug("Unable to stop due to " + (answer == null ? "answer is null" : answer.getDetails())); - - final EventVO event = new EventVO(); - event.setUserId(User.UID_SYSTEM); - event.setAccountId(Account.ACCOUNT_ID_SYSTEM); - event.setType(EventTypes.EVENT_PROXY_STOP); - event.setLevel(EventVO.LEVEL_ERROR); - event.setStartId(startEventId); - event.setDescription("Stopping console proxy failed due to negative answer from agent - " + proxy.getName()); - _eventDao.persist(event); - return false; - } - completeStopCommand(proxy, Event.OperationSucceeded); - - SubscriptionMgr.getInstance().notifySubscribers( - ConsoleProxyManager.ALERT_SUBJECT, - this, - new ConsoleProxyAlertEventArgs( - ConsoleProxyAlertEventArgs.PROXY_DOWN, - proxy.getDataCenterId(), proxy.getId(), - proxy, null)); - - final EventVO event = new EventVO(); - event.setUserId(User.UID_SYSTEM); - event.setAccountId(Account.ACCOUNT_ID_SYSTEM); - event.setType(EventTypes.EVENT_PROXY_STOP); - event.setLevel(EventVO.LEVEL_INFO); - event.setStartId(startEventId); - event.setDescription("Console proxy stopped - " + proxy.getName()); - _eventDao.persist(event); - return true; - } catch (OperationTimedoutException e) { - final EventVO event = new EventVO(); - event.setUserId(User.UID_SYSTEM); - event.setAccountId(Account.ACCOUNT_ID_SYSTEM); - event.setType(EventTypes.EVENT_PROXY_STOP); - event.setLevel(EventVO.LEVEL_ERROR); - event.setStartId(startEventId); - event.setDescription("Stopping console proxy failed due to operation time out - " + proxy.getName()); - _eventDao.persist(event); - throw new AgentUnavailableException(proxy.getHostId()); - } - } finally { - proxyLock.unlock(); - } - } else { - s_logger.debug("Unable to acquire console proxy lock : " + proxy.toString()); - return false; - } - } finally { - proxyLock.releaseRef(); - } - } - - @Override - public boolean migrate(ConsoleProxyVO proxy, HostVO host) { - HostVO fromHost = _hostDao.findById(proxy.getId()); - - if (!_consoleProxyDao.updateIf(proxy, Event.MigrationRequested, proxy.getHostId())) { - s_logger.debug("State for " + proxy.toString() + " has changed so migration can not take place."); - return false; - } - - MigrateCommand cmd = new MigrateCommand(proxy.getInstanceName(), host.getPrivateIpAddress(), false); - Answer answer = _agentMgr.easySend(fromHost.getId(), cmd); - if (answer == null) { - return false; - } - - _storageMgr.unshare(proxy, fromHost); - - return true; - } - - @Override - public boolean completeMigration(ConsoleProxyVO proxy, HostVO host) - throws AgentUnavailableException, OperationTimedoutException { - - CheckVirtualMachineCommand cvm = new CheckVirtualMachineCommand(proxy.getInstanceName()); - CheckVirtualMachineAnswer answer = (CheckVirtualMachineAnswer) _agentMgr.send(host.getId(), cvm); - if (!answer.getResult()) { - s_logger.debug("Unable to complete migration for " + proxy.getId()); - _consoleProxyDao.updateIf(proxy, Event.AgentReportStopped, null); - return false; - } - - State state = answer.getState(); - if (state == State.Stopped) { - s_logger.warn("Unable to complete migration as we can not detect it on " + host.getId()); - _consoleProxyDao.updateIf(proxy, Event.AgentReportStopped, null); - return false; - } - - _consoleProxyDao.updateIf(proxy, Event.OperationSucceeded, host.getId()); - return true; - } - - @Override - public HostVO prepareForMigration(ConsoleProxyVO proxy) - throws StorageUnavailableException { - - VMTemplateVO template = _templateDao.findById(proxy.getTemplateId()); - long routerId = proxy.getId(); - boolean mirroredVols = proxy.isMirroredVols(); - DataCenterVO dc = _dcDao.findById(proxy.getDataCenterId()); - HostPodVO pod = _podDao.findById(proxy.getPodId()); - List sps = _storageMgr.getStoragePoolsForVm(proxy.getId()); - StoragePoolVO sp = sps.get(0); // FIXME - - List vols = _volsDao.findCreatedByInstance(routerId); - - String[] storageIps = new String[2]; - VolumeVO vol = vols.get(0); - storageIps[0] = vol.getHostIp(); - if (mirroredVols && (vols.size() == 2)) { - storageIps[1] = vols.get(1).getHostIp(); - } - - PrepareForMigrationCommand cmd = new PrepareForMigrationCommand(proxy.getName(), null, storageIps, vols, mirroredVols); - - HostVO routingHost = null; - HashSet avoid = new HashSet(); - - HostVO fromHost = _hostDao.findById(proxy.getHostId()); - if (fromHost.getClusterId() == null) { - s_logger.debug("The host is not in a cluster"); - return null; - } - avoid.add(fromHost); - - while ((routingHost = (HostVO) _agentMgr.findHost(Host.Type.Routing, dc, pod, sp, _serviceOffering, template, proxy, fromHost, avoid)) != null) { - avoid.add(routingHost); - - if (s_logger.isDebugEnabled()) { - s_logger.debug("Trying to migrate router to host " + routingHost.getName()); - } - - if (!_storageMgr.share(proxy, vols, routingHost, false)) { - s_logger.warn("Can not share " + proxy.getName()); - throw new StorageUnavailableException(vol.getPoolId()); - } - - Answer answer = _agentMgr.easySend(routingHost.getId(), cmd); - if (answer != null && answer.getResult()) { - return routingHost; - } - _storageMgr.unshare(proxy, vols, routingHost); - } - - return null; - } - - private String getCapacityScanLockName() { - // to improve security, it may be better to return a unique mashed - // name(for example MD5 hashed) - return "consoleproxy.capacity.scan"; - } - - private String getAllocProxyLockName() { - // to improve security, it may be better to return a unique mashed - // name(for example MD5 hashed) - return "consoleproxy.alloc"; - } - - private String getProxyLockName(long id) { - return "consoleproxy." + id; - } - - private Long saveStartedEvent(Long userId, Long accountId, String type, - String description, long startEventId) { - EventVO event = new EventVO(); - event.setUserId(userId); - event.setAccountId(accountId); - event.setType(type); - event.setState(EventState.Started); - event.setDescription(description); - event.setStartId(startEventId); - event = _eventDao.persist(event); - if (event != null) - return event.getId(); - return null; - } +public class ConsoleProxyManagerImpl implements ConsoleProxyManager, VirtualMachineManager, AgentHook { + private static final Logger s_logger = Logger.getLogger(ConsoleProxyManagerImpl.class); + + private static final int DEFAULT_FIND_HOST_RETRY_COUNT = 2; + private static final int DEFAULT_CAPACITY_SCAN_INTERVAL = 30000; // 30 + // seconds + private static final int EXECUTOR_SHUTDOWN_TIMEOUT = 1000; // 1 second + + private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 3; // 3 + // seconds + private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC = 180; // 3 + // minutes + + private static final int API_WAIT_TIMEOUT = 5000; // 5 seconds (in + // milliseconds) + private static final int STARTUP_DELAY = 60000; // 60 seconds + + private int _consoleProxyPort = ConsoleProxyManager.DEFAULT_PROXY_VNC_PORT; + private int _consoleProxyUrlPort = ConsoleProxyManager.DEFAULT_PROXY_URL_PORT; + + private String _mgmt_host; + private int _mgmt_port = 8250; + + private String _name; + private Adapters _consoleProxyAllocators; + + @Inject + private ConsoleProxyDao _consoleProxyDao; + @Inject + private DataCenterDao _dcDao; + @Inject + private VlanDao _vlanDao; + @Inject + private VMTemplateDao _templateDao; + @Inject + private IPAddressDao _ipAddressDao; + @Inject + private VolumeDao _volsDao; + @Inject + private HostPodDao _podDao; + @Inject + private HostDao _hostDao; + @Inject + private ConfigurationDao _configDao; + + @Inject + private VMInstanceDao _instanceDao; + @Inject + private AccountDao _accountDao; + + @Inject + private VMTemplateHostDao _vmTemplateHostDao; + + @Inject + private AgentManager _agentMgr; + @Inject + private StorageManager _storageMgr; + @Inject + private HighAvailabilityManager _haMgr; + @Inject + private EventDao _eventDao; + @Inject + ServiceOfferingDao _offeringDao; + @Inject + private IpAddrAllocator _IpAllocator; + + private ConsoleProxyListener _listener; + + private ServiceOfferingVO _serviceOffering; + private VMTemplateVO _template; + + @Inject + private AsyncJobManager _asyncMgr; + + private final ScheduledExecutorService _capacityScanScheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory("CP-Scan")); + private final ExecutorService _requestHandlerScheduler = Executors.newCachedThreadPool(new NamedThreadFactory("Request-handler")); + + private long _capacityScanInterval = DEFAULT_CAPACITY_SCAN_INTERVAL; + private int _capacityPerProxy = ConsoleProxyManager.DEFAULT_PROXY_CAPACITY; + private int _standbyCapacity = ConsoleProxyManager.DEFAULT_STANDBY_CAPACITY; + + private int _proxyRamSize; + private int _find_host_retry = DEFAULT_FIND_HOST_RETRY_COUNT; + private int _ssh_retry; + private int _ssh_sleep; + private boolean _use_lvm; + private boolean _use_storage_vm; + + private String _domain; + private String _instance; + + // private String _privateNetmask; + private int _proxyCmdPort = DEFAULT_PROXY_CMD_PORT; + private int _proxySessionTimeoutValue = DEFAULT_PROXY_SESSION_TIMEOUT; + private boolean _sslEnabled = false; + + private final GlobalLock _capacityScanLock = GlobalLock.getInternLock(getCapacityScanLockName()); + private final GlobalLock _allocProxyLock = GlobalLock.getInternLock(getAllocProxyLockName()); + + @Override + public ConsoleProxyInfo assignProxy(final long dataCenterId, final long vmId) { + + final Pair result = new Pair(this, null); + + _requestHandlerScheduler.execute(new Runnable() { + @Override + public void run() { + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + try { + ConsoleProxyVO proxy = doAssignProxy(dataCenterId, vmId); + synchronized (result) { + result.second(proxy); + result.notifyAll(); + } + } catch (Throwable e) { + s_logger.warn("Unexpected exception " + e.getMessage(), e); + } finally { + StackMaid.current().exitCleanup(); + txn.close(); + } + } + }); + + synchronized (result) { + try { + result.wait(API_WAIT_TIMEOUT); + } catch (InterruptedException e) { + s_logger.info("Waiting for console proxy assignment is interrupted"); + } + } + + ConsoleProxyVO proxy = result.second(); + if (proxy == null) + return null; + + return new ConsoleProxyInfo(proxy.isSslEnabled(), proxy.getPublicIpAddress(), _consoleProxyPort, proxy.getPort()); + } + + public ConsoleProxyVO doAssignProxy(long dataCenterId, long vmId) { + ConsoleProxyVO proxy = null; + VMInstanceVO vm = _instanceDao.findById(vmId); + if (vm == null) { + s_logger.warn("VM " + vmId + " no longer exists, return a null proxy for vm:" + vmId); + return null; + } + + Boolean[] proxyFromStoppedPool = new Boolean[1]; + if (_allocProxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { + try { + proxy = getOrAllocProxyResource(dataCenterId, vmId, proxyFromStoppedPool); + } finally { + _allocProxyLock.unlock(); + } + } else { + s_logger.error("Unable to acquire synchronization lock to get/allocate proxy resource for vm :" + vmId + + ". Previous console proxy allocation is taking too long"); + } + + if (proxy == null) { + s_logger.warn("Unable to find or allocate console proxy resource"); + return null; + } + + long proxyVmId = proxy.getId(); + GlobalLock proxyLock = GlobalLock.getInternLock(getProxyLockName(proxyVmId)); + try { + if (proxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { + try { + proxy = startProxy(proxyVmId, 0); + + if (proxy == null) { + // + // We had a situation with multi-pod configuration, + // where + // storage allocation of the console proxy VM may + // succeed, but later-on starting of it + // may fail because of running out of computing resource + // (CPU/memory). We + // currently don't support moving storage to another pod + // on the fly, to deal + // with the situation we will destroy this proxy VM and + // let it the whole proxy VM + // creation process re-start again, by hoping that new + // storage and computing + // resource may be allocated and assigned in another pod + // + if (s_logger.isInfoEnabled()) + s_logger.info("Unable to start console proxy, proxy vm Id : " + proxyVmId + " will recycle it and restart a new one"); + destroyProxy(proxyVmId, 0); + return null; + } else { + if (s_logger.isTraceEnabled()) + s_logger.trace("Console proxy " + proxy.getName() + " is started"); + + // if it is a new assignment or a changed assignment, + // update the + // record + if (vm.getProxyId() == null || vm.getProxyId().longValue() != proxy.getId()) + _instanceDao.updateProxyId(vmId, proxy.getId(), DateUtil.currentGMTTime()); + + proxy.setSslEnabled(_sslEnabled); + if (_sslEnabled) + proxy.setPort(443); + else + proxy.setPort(80); + return proxy; + } + } finally { + proxyLock.unlock(); + } + } else { + s_logger.error("Unable to acquire synchronization lock to start console proxy " + proxyVmId + " for vm: " + vmId + + ". It takes too long to start the proxy"); + + return null; + } + } finally { + proxyLock.releaseRef(); + } + } + + private ConsoleProxyVO getOrAllocProxyResource(long dataCenterId, long vmId, Boolean[] proxyFromStoppedPool) { + ConsoleProxyVO proxy = null; + VMInstanceVO vm = this._instanceDao.findById(vmId); + + if (vm != null && vm.getState() != State.Running) { + if (s_logger.isInfoEnabled()) + s_logger.info("Detected that vm : " + vmId + " is not currently at running state, we will fail the proxy assignment for it"); + return null; + } + + if (vm != null && vm.getProxyId() != null) { + proxy = _consoleProxyDao.findById(vm.getProxyId()); + + if (proxy != null) { + if (!isInAssignableState(proxy)) { + if (s_logger.isInfoEnabled()) + s_logger.info("A previous assigned proxy is not assignable now, reassign console proxy for user vm : " + vmId); + proxy = null; + } else { + if (_consoleProxyDao.getProxyActiveLoad(proxy.getId()) < _capacityPerProxy || hasPreviousSession(proxy, vm)) { + if (s_logger.isTraceEnabled()) + s_logger.trace("Assign previous allocated console proxy for user vm : " + vmId); + + if (proxy.getActiveSession() >= _capacityPerProxy) + s_logger.warn("Assign overloaded proxy to user VM as previous session exists, user vm : " + vmId); + } else { + proxy = null; + } + } + } + } + + if (proxy == null) + proxy = assignProxyFromRunningPool(dataCenterId); + + if (proxy == null) { + if (s_logger.isInfoEnabled()) + s_logger.info("No running console proxy is available, check to see if we can bring up a stopped one for data center : " + + dataCenterId); + + proxy = assignProxyFromStoppedPool(dataCenterId); + if (proxy == null) { + if (s_logger.isInfoEnabled()) + s_logger.info("No stopped console proxy is available, need to allocate a new console proxy for data center : " + dataCenterId); + + proxy = startNew(dataCenterId); + } else { + if (s_logger.isInfoEnabled()) + s_logger.info("Found a stopped console proxy, bring it up to running pool. proxy vm id : " + proxy.getId() + ", data center : " + + dataCenterId); + + proxyFromStoppedPool[0] = new Boolean(true); + } + } + + return proxy; + } + + private static boolean isInAssignableState(ConsoleProxyVO proxy) { + // console proxies that are in states of being able to serve user VM + State state = proxy.getState(); + if (state == State.Running || state == State.Starting || state == State.Creating || state == State.Migrating) + return true; + + return false; + } + + private boolean hasPreviousSession(ConsoleProxyVO proxy, VMInstanceVO vm) { + + ConsoleProxyStatus status = null; + try { + GsonBuilder gb = new GsonBuilder(); + gb.setVersion(1.3); + Gson gson = gb.create(); + + byte[] details = proxy.getSessionDetails(); + status = gson.fromJson(details != null ? new String(details, Charset.forName("US-ASCII")) : null, ConsoleProxyStatus.class); + } catch (Throwable e) { + s_logger.warn("Unable to parse proxy session details : " + proxy.getSessionDetails()); + } + + if (status != null && status.getConnections() != null) { + ConsoleProxyConnectionInfo[] connections = status.getConnections(); + for (int i = 0; i < connections.length; i++) { + long taggedVmId = 0; + if (connections[i].tag != null) { + try { + taggedVmId = Long.parseLong(connections[i].tag); + } catch (NumberFormatException e) { + s_logger.warn("Unable to parse console proxy connection info passed through tag: " + connections[i].tag, e); + } + } + if (taggedVmId == vm.getId()) + return true; + } + + // + // even if we are not in the list, it may because we haven't + // received load-update yet + // wait until session time + // + if (DateUtil.currentGMTTime().getTime() - vm.getProxyAssignTime().getTime() < _proxySessionTimeoutValue) + return true; + + return false; + } else { + s_logger.error("No proxy load info on an overloaded proxy ?"); + return false; + } + } + + @Override + public ConsoleProxyVO startProxy(long proxyVmId, long startEventId) { + try { + return start(proxyVmId, startEventId); + } catch (StorageUnavailableException e) { + s_logger.warn("Exception while trying to start console proxy", e); + return null; + } catch (InsufficientCapacityException e) { + s_logger.warn("Exception while trying to start console proxy", e); + return null; + } catch (ConcurrentOperationException e) { + s_logger.warn("Exception while trying to start console proxy", e); + return null; + } + } + + @Override + @DB + public ConsoleProxyVO start(long proxyId, long startEventId) throws StorageUnavailableException, InsufficientCapacityException, + ConcurrentOperationException { + + AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor(); + if (asyncExecutor != null) { + AsyncJobVO job = asyncExecutor.getJob(); + + if (s_logger.isInfoEnabled()) + s_logger.info("Start console proxy " + proxyId + ", update async job-" + job.getId()); + _asyncMgr.updateAsyncJobAttachment(job.getId(), "console_proxy", proxyId); + } + + ConsoleProxyVO proxy = _consoleProxyDao.findById(proxyId); + if (proxy == null || proxy.getRemoved() != null) { + s_logger.debug("proxy is not found: " + proxyId); + return null; + } + /* + * // don't insert event here, it may be called multiple times! + * saveStartedEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, + * EventTypes.EVENT_PROXY_START, "Starting console proxy with Id: " + + * proxyId, startEventId); + */ + + if (s_logger.isTraceEnabled()) { + s_logger.trace("Starting console proxy if it is not started, proxy vm id : " + proxyId); + } + + for (int i = 0; i < 2; i++) { + + State state = proxy.getState(); + + if (state == State.Starting /* || state == State.Migrating */) { + if (s_logger.isDebugEnabled()) + s_logger.debug("Waiting console proxy to be ready, proxy vm id : " + proxyId + " proxy VM state : " + state.toString()); + + if (proxy.getPrivateIpAddress() == null || connect(proxy.getPrivateIpAddress(), _proxyCmdPort) != null) { + if (proxy.getPrivateIpAddress() == null) + s_logger.warn("Retruning a proxy that is being started but private IP has not been allocated yet, proxy vm id : " + proxyId); + else + s_logger.warn("Waiting console proxy to be ready timed out, proxy vm id : " + proxyId); + + // TODO, it is very tricky here, if the startup process + // takes too long and it timed out here, + // we may give back a proxy that is not fully ready for + // functioning + } + return proxy; + } + + if (state == State.Running) { + if (s_logger.isTraceEnabled()) + s_logger.trace("Console proxy is already started: " + proxy.getName()); + return proxy; + } + + DataCenterVO dc = _dcDao.findById(proxy.getDataCenterId()); + HostPodVO pod = _podDao.findById(proxy.getPodId()); + List sps = _storageMgr.getStoragePoolsForVm(proxy.getId()); + StoragePoolVO sp = sps.get(0); // FIXME + + HashSet avoid = new HashSet(); + HostVO routingHost = (HostVO) _agentMgr.findHost(Host.Type.Routing, dc, pod, sp, _serviceOffering, _template, proxy, null, avoid); + + if (routingHost == null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Unable to find a routing host for " + proxy.toString()); + continue; + } + } + // to ensure atomic state transition to Starting state + if (!_consoleProxyDao.updateIf(proxy, Event.StartRequested, routingHost.getId())) { + if (s_logger.isDebugEnabled()) { + ConsoleProxyVO temp = _consoleProxyDao.findById(proxyId); + s_logger.debug("Unable to start console proxy " + proxy.getName() + " because it is not in a startable state : " + + ((temp != null) ? temp.getState().toString() : "null")); + } + continue; + } + + try { + Answer answer = null; + int retry = _find_host_retry; + + // Console proxy VM will be running at routing hosts as routing + // hosts have public access to outside network + do { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Trying to start console proxy on host " + routingHost.getName()); + } + + String privateIpAddress = allocPrivateIpAddress(proxy.getDataCenterId(), routingHost.getPodId(), proxy.getId(), + proxy.getPrivateMacAddress()); + if (privateIpAddress == null && (_IpAllocator != null && !_IpAllocator.exteralIpAddressAllocatorEnabled())) { + s_logger.debug("Not enough ip addresses in " + routingHost.getPodId()); + avoid.add(routingHost); + continue; + } + + proxy.setPrivateIpAddress(privateIpAddress); + String guestIpAddress = _dcDao.allocateLinkLocalPrivateIpAddress(proxy.getDataCenterId(), routingHost.getPodId(), proxy.getId()); + proxy.setGuestIpAddress(guestIpAddress); + + _consoleProxyDao.updateIf(proxy, Event.OperationRetry, routingHost.getId()); + proxy = _consoleProxyDao.findById(proxy.getId()); + + List vols = _storageMgr.prepare(proxy, routingHost); + if (vols == null) { + s_logger.debug("Unable to prepare storage for " + routingHost); + avoid.add(routingHost); + continue; + } + + // _storageMgr.share(proxy, vols, null, true); + + // carry the console proxy port info over so that we don't + // need to configure agent on this + StartConsoleProxyCommand cmdStart = new StartConsoleProxyCommand(_proxyCmdPort, proxy, proxy.getName(), "", vols, + Integer.toString(_consoleProxyPort), Integer.toString(_consoleProxyUrlPort), _mgmt_host, _mgmt_port, _sslEnabled); + + if (s_logger.isDebugEnabled()) + s_logger.debug("Sending start command for console proxy " + proxy.getName() + " to " + routingHost.getName()); + try { + answer = _agentMgr.send(routingHost.getId(), cmdStart); + + s_logger.debug("StartConsoleProxy Answer: " + (answer != null ? answer : "null")); + + if (s_logger.isDebugEnabled()) + s_logger.debug("Received answer on starting console proxy " + proxy.getName() + " on " + routingHost.getName()); + + if (answer != null && answer.getResult()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Console proxy " + proxy.getName() + " started on " + routingHost.getName()); + } + + if (answer instanceof StartConsoleProxyAnswer) { + StartConsoleProxyAnswer rAnswer = (StartConsoleProxyAnswer) answer; + if (rAnswer.getPrivateIpAddress() != null) { + proxy.setPrivateIpAddress(rAnswer.getPrivateIpAddress()); + } + if (rAnswer.getPrivateMacAddress() != null) { + proxy.setPrivateMacAddress(rAnswer.getPrivateMacAddress()); + } + } + + final EventVO event = new EventVO(); + event.setUserId(User.UID_SYSTEM); + event.setAccountId(Account.ACCOUNT_ID_SYSTEM); + event.setType(EventTypes.EVENT_PROXY_START); + event.setLevel(EventVO.LEVEL_INFO); + event.setStartId(startEventId); + event.setDescription("Console proxy started - " + proxy.getName()); + _eventDao.persist(event); + break; + } + s_logger.debug("Unable to start " + proxy.toString() + " on host " + routingHost.toString() + " due to " + + answer.getDetails()); + } catch (OperationTimedoutException e) { + if (e.isActive()) { + s_logger.debug("Unable to start vm " + proxy.getName() + + " due to operation timed out and it is active so scheduling a restart."); + _haMgr.scheduleRestart(proxy, true); + return null; + } + } catch (AgentUnavailableException e) { + s_logger.debug("Agent " + routingHost.toString() + " was unavailable to start VM " + proxy.getName()); + } + + avoid.add(routingHost); + proxy.setPrivateIpAddress(null); + freePrivateIpAddress(privateIpAddress, proxy.getDataCenterId(), proxy.getId()); + proxy.setGuestIpAddress(null); + _dcDao.releaseLinkLocalPrivateIpAddress(guestIpAddress, proxy.getDataCenterId(), proxy.getId()); + _storageMgr.unshare(proxy, vols, routingHost); + } while (--retry > 0 + && (routingHost = (HostVO) _agentMgr + .findHost(Host.Type.Routing, dc, pod, sp, _serviceOffering, _template, proxy, null, avoid)) != null); + if (routingHost == null || retry <= 0) { + + SubscriptionMgr.getInstance().notifySubscribers( + ConsoleProxyManager.ALERT_SUBJECT, + this, + new ConsoleProxyAlertEventArgs(ConsoleProxyAlertEventArgs.PROXY_START_FAILURE, proxy.getDataCenterId(), proxy.getId(), + proxy, "Unable to find a routing host to run")); + + final EventVO event = new EventVO(); + event.setUserId(User.UID_SYSTEM); + event.setAccountId(Account.ACCOUNT_ID_SYSTEM); + event.setType(EventTypes.EVENT_PROXY_START); + event.setLevel(EventVO.LEVEL_ERROR); + event.setStartId(startEventId); + event.setDescription("Starting console proxy failed due to unable to find a host - " + proxy.getName()); + _eventDao.persist(event); + throw new ExecutionException("Couldn't find a routingHost to run console proxy"); + } + + _consoleProxyDao.updateIf(proxy, Event.OperationSucceeded, routingHost.getId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Console proxy is now started, vm id : " + proxy.getId()); + } + + // If starting the console proxy failed due to the external + // firewall not being reachable, send an alert. + if (answer != null && answer.getDetails() != null && answer.getDetails().equals("firewall")) { + + SubscriptionMgr.getInstance().notifySubscribers( + ConsoleProxyManager.ALERT_SUBJECT, + this, + new ConsoleProxyAlertEventArgs(ConsoleProxyAlertEventArgs.PROXY_FIREWALL_ALERT, proxy.getDataCenterId(), proxy.getId(), + proxy, null)); + } + + SubscriptionMgr.getInstance().notifySubscribers(ConsoleProxyManager.ALERT_SUBJECT, this, + new ConsoleProxyAlertEventArgs(ConsoleProxyAlertEventArgs.PROXY_UP, proxy.getDataCenterId(), proxy.getId(), proxy, null)); + + return proxy; + } catch (Throwable thr) { + s_logger.warn("Unexpected exception: ", thr); + + SubscriptionMgr.getInstance().notifySubscribers( + ConsoleProxyManager.ALERT_SUBJECT, + this, + new ConsoleProxyAlertEventArgs(ConsoleProxyAlertEventArgs.PROXY_START_FAILURE, proxy.getDataCenterId(), proxy.getId(), proxy, + "Unexpected exception: " + thr.getMessage())); + + /* + * final EventVO event = new EventVO(); + * event.setUserId(User.UID_SYSTEM); + * event.setAccountId(Account.ACCOUNT_ID_SYSTEM); + * event.setType(EventTypes.EVENT_PROXY_START); + * event.setLevel(EventVO.LEVEL_ERROR); + * event.setStartId(startEventId); event.setDescription( + * "Starting console proxy failed due to unhandled exception - " + * + proxy.getName()); _eventDao.persist(event); + */ + + Transaction txn = Transaction.currentTxn(); + try { + txn.start(); + String privateIpAddress = proxy.getPrivateIpAddress(); + if (privateIpAddress != null) { + proxy.setPrivateIpAddress(null); + freePrivateIpAddress(privateIpAddress, proxy.getDataCenterId(), proxy.getId()); + } + + _consoleProxyDao.updateIf(proxy, Event.OperationFailed, null); + txn.commit(); + } catch (Exception e) { + s_logger.error("Caught exception during error recovery"); + } + + if (thr instanceof StorageUnavailableException) { + throw (StorageUnavailableException) thr; + } else if (thr instanceof ConcurrentOperationException) { + throw (ConcurrentOperationException) thr; + } else if (thr instanceof ExecutionException) { + s_logger.error("Error while starting console proxy due to " + thr.getMessage()); + } else { + s_logger.error("Error while starting console proxy ", thr); + } + return null; + } + } + + s_logger.warn("Starting console proxy encounters non-startable situation"); + return null; + } + + public ConsoleProxyVO assignProxyFromRunningPool(long dataCenterId) { + + if (s_logger.isTraceEnabled()) + s_logger.trace("Assign console proxy from running pool for request from data center : " + dataCenterId); + + ConsoleProxyAllocator allocator = getCurrentAllocator(); + assert (allocator != null); + List runningList = _consoleProxyDao.getProxyListInStates(dataCenterId, State.Running); + if (runningList != null && runningList.size() > 0) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Running proxy pool size : " + runningList.size()); + for (ConsoleProxyVO proxy : runningList) + s_logger.trace("Running proxy instance : " + proxy.getName()); + } + + List> l = _consoleProxyDao.getProxyLoadMatrix(); + Map loadInfo = new HashMap(); + if (l != null) { + for (Pair p : l) { + loadInfo.put(p.first(), p.second()); + + if (s_logger.isTraceEnabled()) { + s_logger.trace("Running proxy instance allocation load { proxy id : " + p.first() + ", load : " + p.second() + "}"); + } + } + } + return allocator.allocProxy(runningList, loadInfo, dataCenterId); + } else { + if (s_logger.isTraceEnabled()) + s_logger.trace("Empty running proxy pool for now in data center : " + dataCenterId); + } + return null; + } + + public ConsoleProxyVO assignProxyFromStoppedPool(long dataCenterId) { + List l = _consoleProxyDao.getProxyListInStates(dataCenterId, State.Creating, State.Starting, State.Stopped, State.Migrating); + if (l != null && l.size() > 0) + return l.get(0); + + return null; + } + + public ConsoleProxyVO startNewConsoleProxy(long dataCenterId) { + if (s_logger.isDebugEnabled()) + s_logger.debug("Assign console proxy from a newly started instance for request from data center : " + dataCenterId); + + Map context = createProxyInstance(dataCenterId); + + long proxyVmId = (Long) context.get("proxyVmId"); + if (proxyVmId == 0) { + if (s_logger.isTraceEnabled()) + s_logger.trace("Creating proxy instance failed, data center id : " + dataCenterId); + + // release critical system resource on failure + if (context.get("publicIpAddress") != null) + freePublicIpAddress((String) context.get("publicIpAddress"), dataCenterId, 0); + + return null; + } + + ConsoleProxyVO proxy = allocProxyStorage(dataCenterId, proxyVmId); + if (proxy != null) { + SubscriptionMgr.getInstance().notifySubscribers(ConsoleProxyManager.ALERT_SUBJECT, this, + new ConsoleProxyAlertEventArgs(ConsoleProxyAlertEventArgs.PROXY_CREATED, dataCenterId, proxy.getId(), proxy, null)); + return proxy; + } else { + if (s_logger.isDebugEnabled()) + s_logger.debug("Unable to allocate console proxy storage, remove the console proxy record from DB, proxy id: " + proxyVmId); + + SubscriptionMgr.getInstance().notifySubscribers( + ConsoleProxyManager.ALERT_SUBJECT, + this, + new ConsoleProxyAlertEventArgs(ConsoleProxyAlertEventArgs.PROXY_CREATE_FAILURE, dataCenterId, proxyVmId, null, + "Unable to allocate storage")); + + destroyProxyDBOnly(proxyVmId); + } + return null; + } + + public ConsoleProxyVO startNew(long dataCenterId) { + + if (s_logger.isDebugEnabled()) + s_logger.debug("Assign console proxy from a newly started instance for request from data center : " + dataCenterId); + + Map context = createProxyInstance(dataCenterId); + + long proxyVmId = (Long) context.get("proxyVmId"); + if (proxyVmId == 0) { + if (s_logger.isTraceEnabled()) + s_logger.trace("Creating proxy instance failed, data center id : " + dataCenterId); + + // release critical system resource on failure + if (context.get("publicIpAddress") != null) + freePublicIpAddress((String) context.get("publicIpAddress"), dataCenterId, 0); + + return null; + } + + ConsoleProxyVO proxy = allocProxyStorage(dataCenterId, proxyVmId); + if (proxy != null) { + SubscriptionMgr.getInstance().notifySubscribers(ConsoleProxyManager.ALERT_SUBJECT, this, + new ConsoleProxyAlertEventArgs(ConsoleProxyAlertEventArgs.PROXY_CREATED, dataCenterId, proxy.getId(), proxy, null)); + return proxy; + } else { + if (s_logger.isDebugEnabled()) + s_logger.debug("Unable to allocate console proxy storage, remove the console proxy record from DB, proxy id: " + proxyVmId); + + SubscriptionMgr.getInstance().notifySubscribers( + ConsoleProxyManager.ALERT_SUBJECT, + this, + new ConsoleProxyAlertEventArgs(ConsoleProxyAlertEventArgs.PROXY_CREATE_FAILURE, dataCenterId, proxyVmId, null, + "Unable to allocate storage")); + + destroyProxyDBOnly(proxyVmId); + } + return null; + } + + @DB + protected Map createProxyInstance(long dataCenterId) { + + Map context = new HashMap(); + String publicIpAddress = null; + + Transaction txn = Transaction.currentTxn(); + try { + DataCenterVO dc = _dcDao.findById(dataCenterId); + assert (dc != null); + context.put("dc", dc); + + // this will basically allocate the pod based on data center id as + // we use system user id here + Set avoidPods = new HashSet(); + Pair pod = null; + networkInfo publicIpAndVlan = null; + + // About MAC address allocation + // MAC address used by User VM is inherited from DomR MAC address, + // with the least 16 bits overrided. to avoid + // potential conflicts, domP will mask bit 31 + // + String[] macAddresses = _dcDao.getNextAvailableMacAddressPair(dataCenterId, (1L << 31)); + String privateMacAddress = macAddresses[0]; + String publicMacAddress = macAddresses[1]; + macAddresses = _dcDao.getNextAvailableMacAddressPair(dataCenterId, (1L << 31)); + String guestMacAddress = macAddresses[0]; + while ((pod = _agentMgr.findPod(_template, _serviceOffering, dc, Account.ACCOUNT_ID_SYSTEM, avoidPods)) != null) { + publicIpAndVlan = allocPublicIpAddress(dataCenterId, pod.first().getId(), publicMacAddress); + if (publicIpAndVlan == null) { + s_logger.warn("Unable to allocate public IP address for console proxy vm in data center : " + dataCenterId + ", pod=" + + pod.first().getId()); + avoidPods.add(pod.first().getId()); + } else { + break; + } + } + + if (pod == null || publicIpAndVlan == null) { + s_logger.warn("Unable to allocate pod for console proxy vm in data center : " + dataCenterId); + + context.put("proxyVmId", (long) 0); + return context; + } + + long id = _consoleProxyDao.getNextInSequence(Long.class, "id"); + + context.put("publicIpAddress", publicIpAndVlan._ipAddr); + context.put("pod", pod); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Pod allocated " + pod.first().getName()); + } + + String cidrNetmask = NetUtils.getCidrNetmask(pod.first().getCidrSize()); + + // Find the VLAN ID, VLAN gateway, and VLAN netmask for + // publicIpAddress + publicIpAddress = publicIpAndVlan._ipAddr; + + String vlanGateway = publicIpAndVlan._gateWay; + String vlanNetmask = publicIpAndVlan._netMask; + + txn.start(); + ConsoleProxyVO proxy; + String name = VirtualMachineName.getConsoleProxyName(id, _instance).intern(); + proxy = new ConsoleProxyVO(id, name, guestMacAddress, null, NetUtils.getLinkLocalNetMask(), privateMacAddress, null, cidrNetmask, + _template.getId(), _template.getGuestOSId(), publicMacAddress, publicIpAddress, vlanNetmask, publicIpAndVlan._vlanDbId, + publicIpAndVlan._vlanid, pod.first().getId(), dataCenterId, vlanGateway, null, dc.getDns1(), dc.getDns2(), _domain, + _proxyRamSize, 0); + + proxy.setLastHostId(pod.second()); + proxy = _consoleProxyDao.persist(proxy); + long proxyVmId = proxy.getId(); + + final EventVO event = new EventVO(); + event.setUserId(User.UID_SYSTEM); + event.setAccountId(Account.ACCOUNT_ID_SYSTEM); + event.setType(EventTypes.EVENT_PROXY_CREATE); + event.setLevel(EventVO.LEVEL_INFO); + event.setDescription("New console proxy created - " + proxy.getName()); + _eventDao.persist(event); + txn.commit(); + + context.put("proxyVmId", proxyVmId); + return context; + } catch (Throwable e) { + s_logger.error("Unexpected exception : ", e); + + context.put("proxyVmId", (long) 0); + return context; + } + } + + @DB + protected ConsoleProxyVO allocProxyStorage(long dataCenterId, long proxyVmId) { + ConsoleProxyVO proxy = _consoleProxyDao.findById(proxyVmId); + assert (proxy != null); + + DataCenterVO dc = _dcDao.findById(dataCenterId); + HostPodVO pod = _podDao.findById(proxy.getPodId()); + final AccountVO account = _accountDao.findById(Account.ACCOUNT_ID_SYSTEM); + + try { + List vols = _storageMgr.create(account, proxy, _template, dc, pod, _serviceOffering, null, 0); + if (vols == null) { + s_logger.error("Unable to alloc storage for console proxy"); + return null; + } + + Transaction txn = Transaction.currentTxn(); + txn.start(); + + // update pool id + ConsoleProxyVO vo = _consoleProxyDao.findById(proxy.getId()); + _consoleProxyDao.update(proxy.getId(), vo); + + // kick the state machine + _consoleProxyDao.updateIf(proxy, Event.OperationSucceeded, null); + + txn.commit(); + return proxy; + } catch (StorageUnavailableException e) { + s_logger.error("Unable to alloc storage for console proxy: ", e); + return null; + } catch (ExecutionException e) { + s_logger.error("Unable to alloc storage for console proxy: ", e); + return null; + } + } + + private networkInfo allocPublicIpAddress(long dcId, long podId, String macAddr) { + + if (_IpAllocator != null && _IpAllocator.exteralIpAddressAllocatorEnabled()) { + IpAddrAllocator.IpAddr ip = _IpAllocator.getPublicIpAddress(macAddr, dcId, podId); + networkInfo net = new networkInfo(ip.ipaddr, ip.netMask, ip.gateway, null, "untagged"); + return net; + } + + Pair ipAndVlan = _vlanDao.assignIpAddress(dcId, Account.ACCOUNT_ID_SYSTEM, DomainVO.ROOT_DOMAIN, VlanType.VirtualNetwork, + true); + + if (ipAndVlan == null) { + s_logger.debug("Unable to get public ip address (type=Virtual) for console proxy vm for data center : " + dcId); + ipAndVlan = _vlanDao.assignPodDirectAttachIpAddress(dcId, podId, Account.ACCOUNT_ID_SYSTEM, DomainVO.ROOT_DOMAIN); + if (ipAndVlan == null) + s_logger.debug("Unable to get public ip address (type=DirectAttach) for console proxy vm for data center : " + dcId); + } + if (ipAndVlan != null) { + VlanVO vlan = ipAndVlan.second(); + networkInfo net = new networkInfo(ipAndVlan.first(), vlan.getVlanNetmask(), vlan.getVlanGateway(), vlan.getId(), vlan.getVlanId()); + return net; + } + return null; + } + + private String allocPrivateIpAddress(Long dcId, Long podId, Long proxyId, String macAddr) { + if (_IpAllocator != null && _IpAllocator.exteralIpAddressAllocatorEnabled()) { + return _IpAllocator.getPrivateIpAddress(macAddr, dcId, podId).ipaddr; + } else { + return _dcDao.allocatePrivateIpAddress(dcId, podId, proxyId); + } + } + + private void freePrivateIpAddress(String ipAddress, Long dcId, Long podId) { + if (_IpAllocator != null && _IpAllocator.exteralIpAddressAllocatorEnabled()) { + _IpAllocator.releasePrivateIpAddress(ipAddress, dcId, podId); + } else { + _dcDao.releasePrivateIpAddress(ipAddress, dcId, podId); + } + } + + private void freePublicIpAddress(String ipAddress, long dcId, long podId) { + if (_IpAllocator != null && _IpAllocator.exteralIpAddressAllocatorEnabled()) { + _IpAllocator.releasePublicIpAddress(ipAddress, dcId, podId); + } else { + _ipAddressDao.unassignIpAddress(ipAddress); + } + } + + private ConsoleProxyAllocator getCurrentAllocator() { + // for now, only one adapter is supported + Enumeration it = _consoleProxyAllocators.enumeration(); + if (it.hasMoreElements()) + return it.nextElement(); + + return null; + } + + protected String connect(String ipAddress, int port) { + for (int i = 0; i <= _ssh_retry; i++) { + SocketChannel sch = null; + try { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Trying to connect to " + ipAddress); + } + sch = SocketChannel.open(); + sch.configureBlocking(true); + sch.socket().setSoTimeout(5000); + + InetSocketAddress addr = new InetSocketAddress(ipAddress, port); + sch.connect(addr); + return null; + } catch (IOException e) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Could not connect to " + ipAddress); + } + } finally { + if (sch != null) { + try { + sch.close(); + } catch (IOException e) { + } + } + } + try { + Thread.sleep(_ssh_sleep); + } catch (InterruptedException ex) { + } + } + + s_logger.debug("Unable to logon to " + ipAddress); + + return "Unable to connect"; + } + + public void onLoadAnswer(ConsoleProxyLoadAnswer answer) { + if (answer.getDetails() == null) + return; + + ConsoleProxyStatus status = null; + try { + GsonBuilder gb = new GsonBuilder(); + gb.setVersion(1.3); + Gson gson = gb.create(); + status = gson.fromJson(answer.getDetails(), ConsoleProxyStatus.class); + } catch (Throwable e) { + s_logger.warn("Unable to parse load info from proxy, proxy vm id : " + answer.getProxyVmId() + ", info : " + answer.getDetails()); + } + + if (status != null) { + int count = 0; + if (status.getConnections() != null) + count = status.getConnections().length; + + byte[] details = null; + if (answer.getDetails() != null) + details = answer.getDetails().getBytes(Charset.forName("US-ASCII")); + _consoleProxyDao.update(answer.getProxyVmId(), count, DateUtil.currentGMTTime(), details); + } else { + if (s_logger.isTraceEnabled()) + s_logger.trace("Unable to get console proxy load info, id : " + answer.getProxyVmId()); + + _consoleProxyDao.update(answer.getProxyVmId(), 0, DateUtil.currentGMTTime(), null); + // TODO : something is wrong with the VM, restart it? + } + } + + @Override + public void onLoadReport(ConsoleProxyLoadReportCommand cmd) { + if (cmd.getLoadInfo() == null) + return; + + ConsoleProxyStatus status = null; + try { + GsonBuilder gb = new GsonBuilder(); + gb.setVersion(1.3); + Gson gson = gb.create(); + status = gson.fromJson(cmd.getLoadInfo(), ConsoleProxyStatus.class); + } catch (Throwable e) { + s_logger.warn("Unable to parse load info from proxy, proxy vm id : " + cmd.getProxyVmId() + ", info : " + cmd.getLoadInfo()); + } + + if (status != null) { + int count = 0; + if (status.getConnections() != null) + count = status.getConnections().length; + + byte[] details = null; + if (cmd.getLoadInfo() != null) + details = cmd.getLoadInfo().getBytes(Charset.forName("US-ASCII")); + _consoleProxyDao.update(cmd.getProxyVmId(), count, DateUtil.currentGMTTime(), details); + } else { + if (s_logger.isTraceEnabled()) + s_logger.trace("Unable to get console proxy load info, id : " + cmd.getProxyVmId()); + + _consoleProxyDao.update(cmd.getProxyVmId(), 0, DateUtil.currentGMTTime(), null); + } + } + + @Override + public AgentControlAnswer onConsoleAccessAuthentication(ConsoleAccessAuthenticationCommand cmd) { + long vmId = 0; + + if (cmd.getVmId() != null && cmd.getVmId().isEmpty()) { + if (s_logger.isTraceEnabled()) + s_logger.trace("Invalid vm id sent from proxy(happens when proxy session has terminated)"); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + try { + vmId = Long.parseLong(cmd.getVmId()); + } catch (NumberFormatException e) { + s_logger.error("Invalid vm id " + cmd.getVmId() + " sent from console access authentication", e); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + // TODO authentication channel between console proxy VM and management + // server needs to be secured, + // the data is now being sent through private network, but this is + // apparently not enough + VMInstanceVO vm = _instanceDao.findById(vmId); + if (vm == null) { + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + if (vm.getHostId() == null) { + s_logger.warn("VM " + vmId + " lost host info, failed authentication request"); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + HostVO host = _hostDao.findById(vm.getHostId()); + if (host == null) { + s_logger.warn("VM " + vmId + "'s host does not exist, fail authentication request"); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + String sid = cmd.getSid(); + if (sid == null || !sid.equals(vm.getVncPassword())) { + s_logger.warn("sid " + sid + " in url does not match stored sid " + vm.getVncPassword()); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + return new ConsoleAccessAuthenticationAnswer(cmd, true); + } + + private ConsoleProxyVO findConsoleProxyByHost(HostVO host) throws NumberFormatException { + String name = host.getName(); + long proxyVmId = 0; + ConsoleProxyVO proxy = null; + if (name != null && name.startsWith("v-")) { + String[] tokens = name.split("-"); + proxyVmId = Long.parseLong(tokens[1]); + proxy = this._consoleProxyDao.findById(proxyVmId); + } + return proxy; + } + + @Override + public void onAgentConnect(HostVO host, StartupCommand cmd) { + if (host.getType() == Type.ConsoleProxy) { + // TODO we can use this event to mark the proxy is up and + // functioning instead of + // pinging the console proxy VM command port + // + // for now, just log a message + if (s_logger.isInfoEnabled()) + s_logger.info("Console proxy agent is connected. proxy: " + host.getName()); + + /* update public/private ip address */ + if (_IpAllocator != null && _IpAllocator.exteralIpAddressAllocatorEnabled()) { + try { + ConsoleProxyVO console = findConsoleProxyByHost(host); + if (console == null) { + s_logger.debug("Can't find console proxy "); + return; + } + console.setPrivateIpAddress(cmd.getPrivateIpAddress()); + console.setPrivateNetmask(cmd.getPrivateNetmask()); + console.setPublicIpAddress(cmd.getPublicIpAddress()); + console.setPublicNetmask(cmd.getPublicNetmask()); + _consoleProxyDao.persist(console); + } catch (NumberFormatException e) { + } + } + } + } + + @Override + public void onAgentDisconnect(long agentId, com.cloud.host.Status state) { + if (state == com.cloud.host.Status.Alert || state == com.cloud.host.Status.Disconnected) { + // be it either in alert or in disconnected state, the agent process + // may be gone in the VM, + // we will be reacting to stop the corresponding VM and let the scan + // process to + HostVO host = _hostDao.findById(agentId); + if (host.getType() == Type.ConsoleProxy) { + String name = host.getName(); + if (s_logger.isInfoEnabled()) + s_logger.info("Console proxy agent disconnected, proxy: " + name); + if (name != null && name.startsWith("v-")) { + String[] tokens = name.split("-"); + long proxyVmId = 0; + try { + proxyVmId = Long.parseLong(tokens[1]); + } catch (NumberFormatException e) { + s_logger.error("Unexpected exception " + e.getMessage(), e); + return; + } + + final ConsoleProxyVO proxy = this._consoleProxyDao.findById(proxyVmId); + if (proxy != null) { + Long hostId = proxy.getHostId(); + + // Disable this feature for now, as it conflicts with + // the case of allowing user to reboot console proxy + // when rebooting happens, we will receive disconnect + // here and we can't enter into stopping process, + // as when the rebooted one comes up, it will kick off a + // newly started one and trigger the process + // continue on forever + + /* + * _capacityScanScheduler.execute(new Runnable() { + * public void run() { if(s_logger.isInfoEnabled()) + * s_logger.info("Stop console proxy " + proxy.getName() + * + + * " VM because of that the agent running inside it has disconnected" + * ); stopProxy(proxy.getId()); } }); + */ + } else { + if (s_logger.isInfoEnabled()) + s_logger.info("Console proxy agent disconnected but corresponding console proxy VM no longer exists in DB, proxy: " + + name); + } + } else { + assert (false) : "Invalid console proxy name: " + name; + } + } + } + } + + private void checkPendingProxyVMs() { + // drive state to change away from transient states + List l = _consoleProxyDao.getProxyListInStates(State.Creating); + if (l != null && l.size() > 0) { + for (ConsoleProxyVO proxy : l) { + if (proxy.getLastUpdateTime() == null + || (proxy.getLastUpdateTime() != null && System.currentTimeMillis() - proxy.getLastUpdateTime().getTime() > 60000)) { + try { + ConsoleProxyVO readyProxy = null; + if (_allocProxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { + try { + readyProxy = allocProxyStorage(proxy.getDataCenterId(), proxy.getId()); + } finally { + _allocProxyLock.unlock(); + } + + if (readyProxy != null) { + GlobalLock proxyLock = GlobalLock.getInternLock(getProxyLockName(readyProxy.getId())); + try { + if (proxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { + try { + readyProxy = start(readyProxy.getId(), 0); + } finally { + proxyLock.unlock(); + } + } else { + if (s_logger.isInfoEnabled()) + s_logger.info("Unable to acquire synchronization lock to start console proxy : " + readyProxy.getName()); + } + } finally { + proxyLock.releaseRef(); + } + } + } else { + if (s_logger.isInfoEnabled()) + s_logger.info("Unable to acquire synchronization lock to allocate proxy storage, wait for next turn"); + } + } catch (StorageUnavailableException e) { + s_logger.warn("Storage unavailable", e); + } catch (InsufficientCapacityException e) { + s_logger.warn("insuffiient capacity", e); + } catch (ConcurrentOperationException e) { + s_logger.debug("Concurrent operation: " + e.getMessage()); + } + } + } + } + } + + private Runnable getCapacityScanTask() { + return new Runnable() { + + @Override + public void run() { + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + try { + reallyRun(); + } catch (Throwable e) { + s_logger.warn("Unexpected exception " + e.getMessage(), e); + } finally { + StackMaid.current().exitCleanup(); + txn.close(); + } + } + + private void reallyRun() { + if (s_logger.isTraceEnabled()) + s_logger.trace("Begin console proxy capacity scan"); + + // config var for consoleproxy.restart check + String restart = _configDao.getValue("consoleproxy.restart"); + if (restart != null && restart.equalsIgnoreCase("false")) { + s_logger.debug("Capacity scan disabled purposefully, consoleproxy.restart = false. This happens when the primarystorage is in maintenance mode"); + return; + } + + Map zoneHostInfoMap = getZoneHostInfo(); + if (isServiceReady(zoneHostInfoMap)) { + if (s_logger.isTraceEnabled()) + s_logger.trace("Service is ready, check to see if we need to allocate standby capacity"); + + if (!_capacityScanLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) { + if (s_logger.isTraceEnabled()) + s_logger.trace("Capacity scan lock is used by others, skip and wait for my turn"); + return; + } + + if (s_logger.isTraceEnabled()) + s_logger.trace("*** Begining capacity scan... ***"); + + try { + checkPendingProxyVMs(); + + // scan default data center first + long defaultId = 0; + + // proxy count info by data-centers (zone-id, zone-name, + // count) + List l = _consoleProxyDao.getDatacenterProxyLoadMatrix(); + + // running VM session count by data-centers (zone-id, + // zone-name, count) + List listVmCounts = _consoleProxyDao.getDatacenterSessionLoadMatrix(); + + // indexing load info by data-center id + Map mapVmCounts = new HashMap(); + if (listVmCounts != null) + for (ConsoleProxyLoadInfo info : listVmCounts) + mapVmCounts.put(info.getId(), info); + + for (ConsoleProxyLoadInfo info : l) { + if (info.getName().equals(_instance)) { + ConsoleProxyLoadInfo vmInfo = mapVmCounts.get(info.getId()); + + if (!checkCapacity(info, vmInfo != null ? vmInfo : new ConsoleProxyLoadInfo())) { + if (isZoneReady(zoneHostInfoMap, info.getId())) { + allocCapacity(info.getId()); + } else { + if (s_logger.isTraceEnabled()) + s_logger.trace("Zone " + info.getId() + " is not ready to alloc standy console proxy"); + } + } + + defaultId = info.getId(); + break; + } + } + + // scan rest of data-centers + for (ConsoleProxyLoadInfo info : l) { + if (info.getId() != defaultId) { + ConsoleProxyLoadInfo vmInfo = mapVmCounts.get(info.getId()); + + if (!checkCapacity(info, vmInfo != null ? vmInfo : new ConsoleProxyLoadInfo())) { + if (isZoneReady(zoneHostInfoMap, info.getId())) { + allocCapacity(info.getId()); + } else { + if (s_logger.isTraceEnabled()) + s_logger.trace("Zone " + info.getId() + " is not ready to alloc standy console proxy"); + } + } + } + } + + if (s_logger.isTraceEnabled()) + s_logger.trace("*** Stop capacity scan ***"); + } finally { + _capacityScanLock.unlock(); + } + + } else { + if (s_logger.isTraceEnabled()) + s_logger.trace("Service is not ready for capacity preallocation, wait for next time"); + } + + if (s_logger.isTraceEnabled()) + s_logger.trace("End of console proxy capacity scan"); + } + }; + } + + private boolean checkCapacity(ConsoleProxyLoadInfo proxyCountInfo, ConsoleProxyLoadInfo vmCountInfo) { + + if (proxyCountInfo.getCount() * _capacityPerProxy - vmCountInfo.getCount() <= _standbyCapacity) + return false; + + return true; + } + + private void allocCapacity(long dataCenterId) { + if (s_logger.isTraceEnabled()) + s_logger.trace("Allocate console proxy standby capacity for data center : " + dataCenterId); + + boolean proxyFromStoppedPool = false; + ConsoleProxyVO proxy = assignProxyFromStoppedPool(dataCenterId); + if (proxy == null) { + if (s_logger.isInfoEnabled()) + s_logger.info("No stopped console proxy is available, need to allocate a new console proxy"); + + if (_allocProxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { + try { + proxy = startNew(dataCenterId); + } finally { + _allocProxyLock.unlock(); + } + } else { + if (s_logger.isInfoEnabled()) + s_logger.info("Unable to acquire synchronization lock to allocate proxy resource for standby capacity, wait for next scan"); + return; + } + } else { + if (s_logger.isInfoEnabled()) + s_logger.info("Found a stopped console proxy, bring it up to running pool. proxy vm id : " + proxy.getId()); + proxyFromStoppedPool = true; + } + + if (proxy != null) { + long proxyVmId = proxy.getId(); + GlobalLock proxyLock = GlobalLock.getInternLock(getProxyLockName(proxyVmId)); + try { + if (proxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { + try { + proxy = startProxy(proxyVmId, 0); + } finally { + proxyLock.unlock(); + } + } else { + if (s_logger.isInfoEnabled()) + s_logger.info("Unable to acquire synchronization lock to start proxy for standby capacity, proxy vm id : " + proxy.getId()); + return; + } + } finally { + proxyLock.releaseRef(); + } + + if (proxy == null) { + if (s_logger.isInfoEnabled()) + s_logger.info("Unable to start console proxy for standby capacity, proxy vm Id : " + proxyVmId + + ", will recycle it and start a new one"); + + if (proxyFromStoppedPool) + destroyProxy(proxyVmId, 0); + } else { + if (s_logger.isInfoEnabled()) + s_logger.info("Console proxy " + proxy.getName() + " is started"); + } + } + } + + public boolean isServiceReady(Map zoneHostInfoMap) { + for (ZoneHostInfo zoneHostInfo : zoneHostInfoMap.values()) { + if (isZoneHostReady(zoneHostInfo)) { + if (s_logger.isInfoEnabled()) + s_logger.info("Zone " + zoneHostInfo.getDcId() + " is ready to launch"); + return true; + } + } + + return false; + } + + public boolean isZoneReady(Map zoneHostInfoMap, long dataCenterId) { + ZoneHostInfo zoneHostInfo = zoneHostInfoMap.get(dataCenterId); + if (zoneHostInfo != null && isZoneHostReady(zoneHostInfo)) { + VMTemplateVO template = _templateDao.findConsoleProxyTemplate(); + HostVO secondaryStorageHost = _storageMgr.getSecondaryStorageHost(dataCenterId); + boolean templateReady = false; + + if (template != null && secondaryStorageHost != null) { + VMTemplateHostVO templateHostRef = _vmTemplateHostDao.findByHostTemplate(secondaryStorageHost.getId(), template.getId()); + templateReady = (templateHostRef != null) && (templateHostRef.getDownloadState() == Status.DOWNLOADED); + } + + if (templateReady) { + List> l = _consoleProxyDao.getDatacenterStoragePoolHostInfo(dataCenterId, _use_lvm); + if (l != null && l.size() > 0 && l.get(0).second().intValue() > 0) { + return true; + } else { + if (s_logger.isTraceEnabled()) + s_logger.trace("Primary storage is not ready, wait until it is ready to launch console proxy"); + } + } else { + if (s_logger.isTraceEnabled()) + s_logger.trace("Zone host is ready, but console proxy template is not ready"); + } + } + return false; + } + + private boolean isZoneHostReady(ZoneHostInfo zoneHostInfo) { + int expectedFlags = 0; + if (_use_storage_vm) + expectedFlags = RunningHostInfoAgregator.ZoneHostInfo.ROUTING_HOST_MASK; + else + expectedFlags = RunningHostInfoAgregator.ZoneHostInfo.ALL_HOST_MASK; + + return (zoneHostInfo.getFlags() & expectedFlags) == expectedFlags; + } + + private synchronized Map getZoneHostInfo() { + Date cutTime = DateUtil.currentGMTTime(); + List l = _hostDao.getRunningHostCounts(new Date(cutTime.getTime() - ClusterManager.DEFAULT_HEARTBEAT_THRESHOLD)); + + RunningHostInfoAgregator aggregator = new RunningHostInfoAgregator(); + if (l.size() > 0) + for (RunningHostCountInfo countInfo : l) + aggregator.aggregate(countInfo); + + return aggregator.getZoneHostInfoMap(); + } + + @Override + public String getName() { + return _name; + } + + @Override + public boolean start() { + if (s_logger.isInfoEnabled()) + s_logger.info("Start console proxy manager"); + + return true; + } + + @Override + public boolean stop() { + if (s_logger.isInfoEnabled()) + s_logger.info("Stop console proxy manager"); + _capacityScanScheduler.shutdownNow(); + + try { + _capacityScanScheduler.awaitTermination(EXECUTOR_SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + } + + _capacityScanLock.releaseRef(); + _allocProxyLock.releaseRef(); + return true; + } + + @Override + public Command cleanup(ConsoleProxyVO vm, String vmName) { + if (vmName != null) { + return new StopCommand(vm, vmName, VirtualMachineName.getVnet(vmName)); + } else if (vm != null) { + ConsoleProxyVO vo = vm; + return new StopCommand(vo, null); + } else { + throw new CloudRuntimeException("Shouldn't even be here!"); + } + } + + @Override + public void completeStartCommand(ConsoleProxyVO vm) { + _consoleProxyDao.updateIf(vm, Event.AgentReportRunning, vm.getHostId()); + } + + @Override + public void completeStopCommand(ConsoleProxyVO vm) { + completeStopCommand(vm, Event.AgentReportStopped); + } + + @DB + protected void completeStopCommand(ConsoleProxyVO proxy, Event ev) { + Transaction txn = Transaction.currentTxn(); + try { + txn.start(); + String privateIpAddress = proxy.getPrivateIpAddress(); + if (privateIpAddress != null) { + proxy.setPrivateIpAddress(null); + freePrivateIpAddress(privateIpAddress, proxy.getDataCenterId(), proxy.getId()); + } + String guestIpAddress = proxy.getGuestIpAddress(); + if (guestIpAddress != null) { + proxy.setGuestIpAddress(null); + _dcDao.releaseLinkLocalPrivateIpAddress(guestIpAddress, proxy.getDataCenterId(), proxy.getId()); + } + + if (!_consoleProxyDao.updateIf(proxy, ev, null)) { + s_logger.debug("Unable to update the console proxy"); + return; + } + txn.commit(); + } catch (Exception e) { + s_logger.error("Unable to complete stop command due to ", e); + } + + if (_storageMgr.unshare(proxy, null) == null) { + s_logger.warn("Unable to set share to false for " + proxy.getId()); + } + } + + @Override + public ConsoleProxyVO get(long id) { + return _consoleProxyDao.findById(id); + } + + @Override + public Long convertToId(String vmName) { + if (!VirtualMachineName.isValidConsoleProxyName(vmName, _instance)) { + return null; + } + return VirtualMachineName.getConsoleProxyId(vmName); + } + + @Override + public boolean stopProxy(long proxyVmId, long startEventId) { + + AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor(); + if (asyncExecutor != null) { + AsyncJobVO job = asyncExecutor.getJob(); + + if (s_logger.isInfoEnabled()) + s_logger.info("Stop console proxy " + proxyVmId + ", update async job-" + job.getId()); + _asyncMgr.updateAsyncJobAttachment(job.getId(), "console_proxy", proxyVmId); + } + + ConsoleProxyVO proxy = _consoleProxyDao.findById(proxyVmId); + if (proxy == null) { + if (s_logger.isDebugEnabled()) + s_logger.debug("Stopping console proxy failed: console proxy " + proxyVmId + " no longer exists"); + return false; + } + /* + * saveStartedEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, + * EventTypes.EVENT_PROXY_STOP, "Stopping console proxy with Id: " + + * proxyVmId, startEventId); + */ + try { + return stop(proxy, startEventId); + } catch (AgentUnavailableException e) { + if (s_logger.isDebugEnabled()) + s_logger.debug("Stopping console proxy " + proxy.getName() + " faled : exception " + e.toString()); + return false; + } + } + + @Override + public boolean rebootProxy(long proxyVmId, long startEventId) { + AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor(); + if (asyncExecutor != null) { + AsyncJobVO job = asyncExecutor.getJob(); + + if (s_logger.isInfoEnabled()) + s_logger.info("Reboot console proxy " + proxyVmId + ", update async job-" + job.getId()); + _asyncMgr.updateAsyncJobAttachment(job.getId(), "console_proxy", proxyVmId); + } + + final ConsoleProxyVO proxy = _consoleProxyDao.findById(proxyVmId); + + if (proxy == null || proxy.getState() == State.Destroyed) { + return false; + } + + /* + * saveStartedEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, + * EventTypes.EVENT_PROXY_REBOOT, "Rebooting console proxy with Id: " + + * proxyVmId, startEventId); + */ + if (proxy.getState() == State.Running && proxy.getHostId() != null) { + final RebootCommand cmd = new RebootCommand(proxy.getInstanceName()); + final Answer answer = _agentMgr.easySend(proxy.getHostId(), cmd); + + if (answer != null) { + if (s_logger.isDebugEnabled()) + s_logger.debug("Successfully reboot console proxy " + proxy.getName()); + + SubscriptionMgr.getInstance() + .notifySubscribers( + ConsoleProxyManager.ALERT_SUBJECT, + this, + new ConsoleProxyAlertEventArgs(ConsoleProxyAlertEventArgs.PROXY_REBOOTED, proxy.getDataCenterId(), proxy.getId(), + proxy, null)); + + final EventVO event = new EventVO(); + event.setUserId(User.UID_SYSTEM); + event.setAccountId(Account.ACCOUNT_ID_SYSTEM); + event.setType(EventTypes.EVENT_PROXY_REBOOT); + event.setLevel(EventVO.LEVEL_INFO); + event.setStartId(startEventId); + event.setDescription("Console proxy rebooted - " + proxy.getName()); + _eventDao.persist(event); + return true; + } else { + if (s_logger.isDebugEnabled()) + s_logger.debug("failed to reboot console proxy : " + proxy.getName()); + + final EventVO event = new EventVO(); + event.setUserId(User.UID_SYSTEM); + event.setAccountId(Account.ACCOUNT_ID_SYSTEM); + event.setType(EventTypes.EVENT_PROXY_REBOOT); + event.setLevel(EventVO.LEVEL_ERROR); + event.setStartId(startEventId); + event.setDescription("Rebooting console proxy failed - " + proxy.getName()); + _eventDao.persist(event); + return false; + } + } else { + return startProxy(proxyVmId, 0) != null; + } + } + + @Override + public boolean destroy(ConsoleProxyVO proxy) throws AgentUnavailableException { + return destroyProxy(proxy.getId(), 0); + } + + @Override + @DB + public boolean destroyProxy(long vmId, long startEventId) { + AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor(); + if (asyncExecutor != null) { + AsyncJobVO job = asyncExecutor.getJob(); + + if (s_logger.isInfoEnabled()) + s_logger.info("Destroy console proxy " + vmId + ", update async job-" + job.getId()); + _asyncMgr.updateAsyncJobAttachment(job.getId(), "console_proxy", vmId); + } + + ConsoleProxyVO vm = _consoleProxyDao.findById(vmId); + if (vm == null || vm.getState() == State.Destroyed) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Unable to find vm or vm is destroyed: " + vmId); + } + return true; + } + /* + * saveStartedEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, + * EventTypes.EVENT_PROXY_DESTROY, "Destroying console proxy with Id: " + * + vmId, startEventId); + */ + if (s_logger.isDebugEnabled()) { + s_logger.debug("Destroying console proxy vm " + vmId); + } + + if (!_consoleProxyDao.updateIf(vm, Event.DestroyRequested, null)) { + s_logger.debug("Unable to destroy the vm because it is not in the correct state: " + vmId); + return false; + } + + Transaction txn = Transaction.currentTxn(); + List vols = null; + try { + vols = _volsDao.findByInstance(vmId); + if (vols.size() != 0) { + _storageMgr.destroy(vm, vols); + } + + return true; + } finally { + try { + txn.start(); + // release critical system resources used by the VM before we + // delete them + if (vm.getPublicIpAddress() != null) + freePublicIpAddress(vm.getPublicIpAddress(), vm.getDataCenterId(), vm.getPodId()); + vm.setPublicIpAddress(null); + + _consoleProxyDao.remove(vm.getId()); + + final EventVO event = new EventVO(); + event.setUserId(User.UID_SYSTEM); + event.setAccountId(Account.ACCOUNT_ID_SYSTEM); + event.setType(EventTypes.EVENT_PROXY_DESTROY); + event.setLevel(EventVO.LEVEL_INFO); + event.setStartId(startEventId); + event.setDescription("Console proxy destroyed - " + vm.getName()); + _eventDao.persist(event); + + txn.commit(); + } catch (Exception e) { + s_logger.error("Caught this error: ", e); + txn.rollback(); + return false; + } finally { + s_logger.debug("console proxy vm is destroyed : " + vm.getName()); + } + } + } + + @DB + public boolean destroyProxyDBOnly(long vmId) { + Transaction txn = Transaction.currentTxn(); + try { + txn.start(); + _volsDao.deleteVolumesByInstance(vmId); + + ConsoleProxyVO proxy = _consoleProxyDao.findById(vmId); + if (proxy != null) { + if (proxy.getPublicIpAddress() != null) + freePublicIpAddress(proxy.getPublicIpAddress(), proxy.getDataCenterId(), proxy.getPodId()); + + _consoleProxyDao.remove(vmId); + + final EventVO event = new EventVO(); + event.setUserId(User.UID_SYSTEM); + event.setAccountId(Account.ACCOUNT_ID_SYSTEM); + event.setType(EventTypes.EVENT_PROXY_DESTROY); + event.setLevel(EventVO.LEVEL_INFO); + event.setDescription("Console proxy destroyed - " + proxy.getName()); + _eventDao.persist(event); + } + + txn.commit(); + return true; + } catch (Exception e) { + s_logger.error("Caught this error: ", e); + txn.rollback(); + return false; + } finally { + s_logger.debug("console proxy vm is destroyed from DB : " + vmId); + } + } + + @Override + public boolean stop(ConsoleProxyVO proxy, long startEventId) throws AgentUnavailableException { + if (!_consoleProxyDao.updateIf(proxy, Event.StopRequested, proxy.getHostId())) { + s_logger.debug("Unable to stop console proxy: " + proxy.toString()); + return false; + } + + // IPAddressVO ip = _ipAddressDao.findById(proxy.getPublicIpAddress()); + // VlanVO vlan = _vlanDao.findById(new Long(ip.getVlanDbId())); + + GlobalLock proxyLock = GlobalLock.getInternLock(getProxyLockName(proxy.getId())); + try { + if (proxyLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) { + try { + StopCommand cmd = new StopCommand(proxy, true, Integer.toString(_consoleProxyPort), Integer.toString(_consoleProxyUrlPort), + proxy.getPublicIpAddress()); + try { + Long proxyHostId = proxy.getHostId(); + if (proxyHostId == null) { + s_logger.debug("Unable to stop due to proxy " + proxy.getId() + + " as host is no longer available, proxy may already have been stopped"); + return false; + } + StopAnswer answer = (StopAnswer) _agentMgr.send(proxyHostId, cmd); + if (answer == null || !answer.getResult()) { + s_logger.debug("Unable to stop due to " + (answer == null ? "answer is null" : answer.getDetails())); + + final EventVO event = new EventVO(); + event.setUserId(User.UID_SYSTEM); + event.setAccountId(Account.ACCOUNT_ID_SYSTEM); + event.setType(EventTypes.EVENT_PROXY_STOP); + event.setLevel(EventVO.LEVEL_ERROR); + event.setStartId(startEventId); + event.setDescription("Stopping console proxy failed due to negative answer from agent - " + proxy.getName()); + _eventDao.persist(event); + return false; + } + completeStopCommand(proxy, Event.OperationSucceeded); + + SubscriptionMgr.getInstance().notifySubscribers( + ConsoleProxyManager.ALERT_SUBJECT, + this, + new ConsoleProxyAlertEventArgs(ConsoleProxyAlertEventArgs.PROXY_DOWN, proxy.getDataCenterId(), proxy.getId(), proxy, + null)); + + final EventVO event = new EventVO(); + event.setUserId(User.UID_SYSTEM); + event.setAccountId(Account.ACCOUNT_ID_SYSTEM); + event.setType(EventTypes.EVENT_PROXY_STOP); + event.setLevel(EventVO.LEVEL_INFO); + event.setStartId(startEventId); + event.setDescription("Console proxy stopped - " + proxy.getName()); + _eventDao.persist(event); + return true; + } catch (OperationTimedoutException e) { + final EventVO event = new EventVO(); + event.setUserId(User.UID_SYSTEM); + event.setAccountId(Account.ACCOUNT_ID_SYSTEM); + event.setType(EventTypes.EVENT_PROXY_STOP); + event.setLevel(EventVO.LEVEL_ERROR); + event.setStartId(startEventId); + event.setDescription("Stopping console proxy failed due to operation time out - " + proxy.getName()); + _eventDao.persist(event); + throw new AgentUnavailableException(proxy.getHostId()); + } + } finally { + proxyLock.unlock(); + } + } else { + s_logger.debug("Unable to acquire console proxy lock : " + proxy.toString()); + return false; + } + } finally { + proxyLock.releaseRef(); + } + } + + @Override + public boolean migrate(ConsoleProxyVO proxy, HostVO host) { + HostVO fromHost = _hostDao.findById(proxy.getId()); + + if (!_consoleProxyDao.updateIf(proxy, Event.MigrationRequested, proxy.getHostId())) { + s_logger.debug("State for " + proxy.toString() + " has changed so migration can not take place."); + return false; + } + + MigrateCommand cmd = new MigrateCommand(proxy.getInstanceName(), host.getPrivateIpAddress(), false); + Answer answer = _agentMgr.easySend(fromHost.getId(), cmd); + if (answer == null) { + return false; + } + + _storageMgr.unshare(proxy, fromHost); + + return true; + } + + @Override + public boolean completeMigration(ConsoleProxyVO proxy, HostVO host) throws AgentUnavailableException, OperationTimedoutException { + + CheckVirtualMachineCommand cvm = new CheckVirtualMachineCommand(proxy.getInstanceName()); + CheckVirtualMachineAnswer answer = (CheckVirtualMachineAnswer) _agentMgr.send(host.getId(), cvm); + if (!answer.getResult()) { + s_logger.debug("Unable to complete migration for " + proxy.getId()); + _consoleProxyDao.updateIf(proxy, Event.AgentReportStopped, null); + return false; + } + + State state = answer.getState(); + if (state == State.Stopped) { + s_logger.warn("Unable to complete migration as we can not detect it on " + host.getId()); + _consoleProxyDao.updateIf(proxy, Event.AgentReportStopped, null); + return false; + } + + _consoleProxyDao.updateIf(proxy, Event.OperationSucceeded, host.getId()); + return true; + } + + @Override + public HostVO prepareForMigration(ConsoleProxyVO proxy) throws StorageUnavailableException { + + VMTemplateVO template = _templateDao.findById(proxy.getTemplateId()); + long routerId = proxy.getId(); + boolean mirroredVols = proxy.isMirroredVols(); + DataCenterVO dc = _dcDao.findById(proxy.getDataCenterId()); + HostPodVO pod = _podDao.findById(proxy.getPodId()); + List sps = _storageMgr.getStoragePoolsForVm(proxy.getId()); + StoragePoolVO sp = sps.get(0); // FIXME + + List vols = _volsDao.findCreatedByInstance(routerId); + + String[] storageIps = new String[2]; + VolumeVO vol = vols.get(0); + storageIps[0] = vol.getHostIp(); + if (mirroredVols && (vols.size() == 2)) { + storageIps[1] = vols.get(1).getHostIp(); + } + + PrepareForMigrationCommand cmd = new PrepareForMigrationCommand(proxy.getName(), null, storageIps, vols, mirroredVols); + + HostVO routingHost = null; + HashSet avoid = new HashSet(); + + HostVO fromHost = _hostDao.findById(proxy.getHostId()); + if (fromHost.getClusterId() == null) { + s_logger.debug("The host is not in a cluster"); + return null; + } + avoid.add(fromHost); + + while ((routingHost = (HostVO) _agentMgr.findHost(Host.Type.Routing, dc, pod, sp, _serviceOffering, template, proxy, fromHost, avoid)) != null) { + avoid.add(routingHost); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Trying to migrate router to host " + routingHost.getName()); + } + + if (!_storageMgr.share(proxy, vols, routingHost, false)) { + s_logger.warn("Can not share " + proxy.getName()); + throw new StorageUnavailableException(vol.getPoolId()); + } + + Answer answer = _agentMgr.easySend(routingHost.getId(), cmd); + if (answer != null && answer.getResult()) { + return routingHost; + } + _storageMgr.unshare(proxy, vols, routingHost); + } + + return null; + } + + private String getCapacityScanLockName() { + // to improve security, it may be better to return a unique mashed + // name(for example MD5 hashed) + return "consoleproxy.capacity.scan"; + } + + private String getAllocProxyLockName() { + // to improve security, it may be better to return a unique mashed + // name(for example MD5 hashed) + return "consoleproxy.alloc"; + } + + private String getProxyLockName(long id) { + return "consoleproxy." + id; + } + + private Long saveStartedEvent(Long userId, Long accountId, String type, String description, long startEventId) { + EventVO event = new EventVO(); + event.setUserId(userId); + event.setAccountId(accountId); + event.setType(type); + event.setState(EventState.Started); + event.setDescription(description); + event.setStartId(startEventId); + event = _eventDao.persist(event); + if (event != null) + return event.getId(); + return null; + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + if (s_logger.isInfoEnabled()) + s_logger.info("Start configuring console proxy manager : " + name); + + _name = name; + + ComponentLocator locator = ComponentLocator.getCurrentLocator(); + ConfigurationDao configDao = locator.getDao(ConfigurationDao.class); + if (configDao == null) { + throw new ConfigurationException("Unable to get the configuration dao."); + } + + Map configs = configDao.getConfiguration("management-server", params); + + _proxyRamSize = NumbersUtil.parseInt(configs.get("consoleproxy.ram.size"), DEFAULT_PROXY_VM_RAMSIZE); + + String value = configs.get("start.retry"); + _find_host_retry = NumbersUtil.parseInt(value, DEFAULT_FIND_HOST_RETRY_COUNT); + + value = configs.get("consoleproxy.cmd.port"); + _proxyCmdPort = NumbersUtil.parseInt(value, DEFAULT_PROXY_CMD_PORT); + + value = configs.get("consoleproxy.sslEnabled"); + if (value != null && value.equalsIgnoreCase("true")) + _sslEnabled = true; + + value = configs.get("consoleproxy.capacityscan.interval"); + _capacityScanInterval = NumbersUtil.parseLong(value, DEFAULT_CAPACITY_SCAN_INTERVAL); + + _capacityPerProxy = NumbersUtil.parseInt(configs.get("consoleproxy.session.max"), DEFAULT_PROXY_CAPACITY); + _standbyCapacity = NumbersUtil.parseInt(configs.get("consoleproxy.capacity.standby"), DEFAULT_STANDBY_CAPACITY); + _proxySessionTimeoutValue = NumbersUtil.parseInt(configs.get("consoleproxy.session.timeout"), DEFAULT_PROXY_SESSION_TIMEOUT); + + value = configs.get("consoleproxy.port"); + if (value != null) + _consoleProxyPort = NumbersUtil.parseInt(value, ConsoleProxyManager.DEFAULT_PROXY_VNC_PORT); + + value = configs.get("consoleproxy.url.port"); + if (value != null) + _consoleProxyUrlPort = NumbersUtil.parseInt(value, ConsoleProxyManager.DEFAULT_PROXY_URL_PORT); + + value = configs.get("system.vm.use.local.storage"); + if (value != null && value.equalsIgnoreCase("true")) + _use_lvm = true; + + value = configs.get("secondary.storage.vm"); + if (value != null && value.equalsIgnoreCase("true")) + _use_storage_vm = true; + + if (s_logger.isInfoEnabled()) { + s_logger.info("Console proxy max session soft limit : " + _capacityPerProxy); + s_logger.info("Console proxy standby capacity : " + _standbyCapacity); + } + + _domain = configs.get("domain"); + if (_domain == null) { + _domain = "foo.com"; + } + + _instance = configs.get("instance.name"); + if (_instance == null) { + _instance = "DEFAULT"; + } + + value = (String) params.get("ssh.sleep"); + _ssh_sleep = NumbersUtil.parseInt(value, 5) * 1000; + + value = (String) params.get("ssh.retry"); + _ssh_retry = NumbersUtil.parseInt(value, 3); + + Map agentMgrConfigs = configDao.getConfiguration("AgentManager", params); + _mgmt_host = agentMgrConfigs.get("host"); + if (_mgmt_host == null) { + s_logger.warn("Critical warning! Please configure your management server host address right after you have started your management server and then restart it, otherwise you won't be able to do console access"); + } + + value = agentMgrConfigs.get("port"); + _mgmt_port = NumbersUtil.parseInt(value, 8250); + + _consoleProxyAllocators = locator.getAdapters(ConsoleProxyAllocator.class); + if (_consoleProxyAllocators == null || !_consoleProxyAllocators.isSet()) { + throw new ConfigurationException("Unable to get proxy allocators"); + } + + _listener = new ConsoleProxyListener(this); + _agentMgr.registerForHostEvents(_listener, true, true, false); + + Adapters ipAllocators = locator.getAdapters(IpAddrAllocator.class); + if (ipAllocators != null && ipAllocators.isSet()) { + Enumeration it = ipAllocators.enumeration(); + _IpAllocator = it.nextElement(); + } + + HighAvailabilityManager haMgr = locator.getManager(HighAvailabilityManager.class); + if (haMgr != null) { + haMgr.registerHandler(VirtualMachine.Type.ConsoleProxy, this); + } + + boolean useLocalStorage = Boolean.parseBoolean((String) params.get(Config.SystemVMUseLocalStorage.key())); + _serviceOffering = new ServiceOfferingVO("Fake Offering For DomP", 1, _proxyRamSize, 0, 0, 0, false, null, GuestIpType.Virtualized, + useLocalStorage, true, null); + _serviceOffering.setUniqueName("Cloud.com-ConsoleProxy"); + _serviceOffering = _offeringDao.persistSystemServiceOffering(_serviceOffering); + _template = _templateDao.findConsoleProxyTemplate(); + if (_template == null) { + throw new ConfigurationException("Unable to find the template for console proxy VMs"); + } + + _capacityScanScheduler.scheduleAtFixedRate(getCapacityScanTask(), STARTUP_DELAY, _capacityScanInterval, TimeUnit.MILLISECONDS); + + if (s_logger.isInfoEnabled()) + s_logger.info("Console Proxy Manager is configured."); + return true; + } + + protected ConsoleProxyManagerImpl() { + } } diff --git a/server/src/com/cloud/consoleproxy/StaticConsoleProxyManager.java b/server/src/com/cloud/consoleproxy/StaticConsoleProxyManager.java index 285b51776f2..549e0081048 100644 --- a/server/src/com/cloud/consoleproxy/StaticConsoleProxyManager.java +++ b/server/src/com/cloud/consoleproxy/StaticConsoleProxyManager.java @@ -24,8 +24,9 @@ import javax.ejb.Local; import javax.naming.ConfigurationException; import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.host.HostVO; import com.cloud.host.Host.Type; +import com.cloud.host.HostVO; +import com.cloud.info.ConsoleProxyInfo; import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.component.Inject; import com.cloud.vm.ConsoleProxyVO; @@ -46,31 +47,8 @@ public class StaticConsoleProxyManager extends AgentBasedConsoleProxyManager imp } @Override - public ConsoleProxyVO assignProxy(long dataCenterId, long userVmId) { - ConsoleProxyVO proxy = new ConsoleProxyVO(1l, "EmbeddedProxy", null, null, null, - "02:02:02:02:02:02", - "127.0.0.1", - "255.255.255.0", - 1l, - 1l, - "03:03:03:03:03:03", - _ip, - "255.255.255.0", - null, - "untagged", - 1l, - dataCenterId, - "0.0.0.0", - 0L, - "dns1", - "dn2", - "domain", - 0, - 0); - - proxy.setPort(_consoleProxyUrlPort); - proxy.setSslEnabled(false); - return proxy; + public ConsoleProxyInfo assignProxy(long dataCenterId, long userVmId) { + return new ConsoleProxyInfo(false, _ip, _consoleProxyPort, _consoleProxyUrlPort); } @Override diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 54883bb42a6..2a5d57d5b8d 100644 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -351,9 +351,6 @@ public class ManagementServerImpl implements ManagementServer { private final Map _configs; private String _domain; - private int _consoleProxyPort = ConsoleProxyManager.DEFAULT_PROXY_VNC_PORT; - // private int _consoleProxyUrlPort = - // ConsoleProxyManager.DEFAULT_PROXY_URL_PORT; private final int _routerRamSize; private final int _proxyRamSize; @@ -447,16 +444,7 @@ public class ManagementServerImpl implements ManagementServer { _domain = "." + _domain; } - String value = _configs.get("consoleproxy.port"); - if (value != null) - _consoleProxyPort = NumbersUtil.parseInt(value, ConsoleProxyManager.DEFAULT_PROXY_VNC_PORT); - - // value = _configs.get("consoleproxy.url.port"); - // if(value != null) - // _consoleProxyUrlPort = NumbersUtil.parseInt(value, - // ConsoleProxyManager.DEFAULT_PROXY_URL_PORT); - - value = _configs.get("account.cleanup.interval"); + String value = _configs.get("account.cleanup.interval"); int cleanup = NumbersUtil.parseInt(value, 60 * 60 * 24); // 1 hour. // Parse the max number of UserVMs and public IPs from server-setup.xml, @@ -771,6 +759,7 @@ public class ManagementServerImpl implements ManagementServer { return user; } + @Override public User getUser(long userId, boolean active) { if (s_logger.isDebugEnabled()) { s_logger.debug("Retrieiving user with id: " + userId + " and active = " + active); @@ -1240,6 +1229,7 @@ public class ManagementServerImpl implements ManagementServer { /* * Save event after starting execution of an async job */ + @Override public Long saveStartedEvent(Long userId, Long accountId, String type, String description, long startEventId) { EventVO event = new EventVO(); event.setUserId(userId); @@ -2874,6 +2864,7 @@ public class ManagementServerImpl implements ManagementServer { return _hostDao.findById(hostId); } + @Override public void updateHost(long hostId, long guestOSCategoryId) throws InvalidParameterValueException { // Verify that the guest OS Category exists if (guestOSCategoryId > 0) { @@ -2885,6 +2876,7 @@ public class ManagementServerImpl implements ManagementServer { _agentMgr.updateHost(hostId, guestOSCategoryId); } + @Override public boolean deleteHost(long hostId) { return _agentMgr.deleteHost(hostId); } @@ -5950,6 +5942,7 @@ public class ManagementServerImpl implements ManagementServer { return _asyncMgr.submitAsyncJob(job); } + @Override public void deleteRule(long ruleId, long userId, long accountId) throws InvalidParameterValueException, PermissionDeniedException, InternalErrorException { Exception e = null; try { @@ -6006,6 +5999,7 @@ public class ManagementServerImpl implements ManagementServer { } } + @Override public long deleteRuleAsync(long id, long userId, long accountId) { DeleteRuleParam param = new DeleteRuleParam(id, userId, accountId); Gson gson = GsonHelper.getBuilder().create(); @@ -6019,10 +6013,12 @@ public class ManagementServerImpl implements ManagementServer { return _asyncMgr.submitAsyncJob(job); } + @Override public List listAllTemplates() { return _templateDao.listAll(); } + @Override public List listGuestOSByCriteria(Criteria c) { @@ -6047,6 +6043,7 @@ public class ManagementServerImpl implements ManagementServer { return _guestOSDao.search(sc, searchFilter); } + @Override public List listGuestOSCategoriesByCriteria(Criteria c) { Filter searchFilter = new Filter(GuestOSCategoryVO.class, c.getOrderBy(), c.getAscending(), c.getOffset(), c.getLimit()); @@ -6064,34 +6061,37 @@ public class ManagementServerImpl implements ManagementServer { return _guestOSCategoryDao.search(sc, searchFilter); } + @Override public String getConfigurationValue(String name) { return _configDao.getValue(name); } + @Override public ConsoleProxyInfo getConsoleProxy(long dataCenterId, long userVmId) { - ConsoleProxyVO proxy = _consoleProxyMgr.assignProxy(dataCenterId, userVmId); - if (proxy == null) - return null; - - return new ConsoleProxyInfo(proxy.isSslEnabled(), proxy.getPublicIpAddress(), _consoleProxyPort, proxy.getPort()); + return _consoleProxyMgr.assignProxy(dataCenterId, userVmId); } + @Override public ConsoleProxyVO startConsoleProxy(long instanceId, long startEventId) throws InternalErrorException { return _consoleProxyMgr.startProxy(instanceId, startEventId); } + @Override public boolean stopConsoleProxy(long instanceId, long startEventId) { return _consoleProxyMgr.stopProxy(instanceId, startEventId); } + @Override public boolean rebootConsoleProxy(long instanceId, long startEventId) { return _consoleProxyMgr.rebootProxy(instanceId, startEventId); } + @Override public boolean destroyConsoleProxy(long instanceId, long startEventId) { return _consoleProxyMgr.destroyProxy(instanceId, startEventId); } + @Override public long startConsoleProxyAsync(long instanceId) { long eventId = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_PROXY_START, "starting console proxy with Id: "+instanceId); VMOperationParam param = new VMOperationParam(0, instanceId, null, eventId); @@ -6106,6 +6106,7 @@ public class ManagementServerImpl implements ManagementServer { return _asyncMgr.submitAsyncJob(job, true); } + @Override public long stopConsoleProxyAsync(long instanceId) { long eventId = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_PROXY_STOP, "stopping console proxy with Id: "+instanceId); VMOperationParam param = new VMOperationParam(0, instanceId, null, eventId); @@ -6122,6 +6123,7 @@ public class ManagementServerImpl implements ManagementServer { return _asyncMgr.submitAsyncJob(job, true); } + @Override public long rebootConsoleProxyAsync(long instanceId) { long eventId = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_PROXY_REBOOT, "rebooting console proxy with Id: "+instanceId); VMOperationParam param = new VMOperationParam(0, instanceId, null, eventId); @@ -6138,6 +6140,7 @@ public class ManagementServerImpl implements ManagementServer { return _asyncMgr.submitAsyncJob(job, true); } + @Override public long destroyConsoleProxyAsync(long instanceId) { long eventId = saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, EventTypes.EVENT_PROXY_DESTROY, "destroying console proxy with Id: "+instanceId); VMOperationParam param = new VMOperationParam(0, instanceId, null, eventId); @@ -6152,6 +6155,7 @@ public class ManagementServerImpl implements ManagementServer { return _asyncMgr.submitAsyncJob(job); } + @Override public String getConsoleAccessUrlRoot(long vmId) { VMInstanceVO vm = this.findVMInstanceById(vmId); if (vm != null) { @@ -6162,6 +6166,7 @@ public class ManagementServerImpl implements ManagementServer { return null; } + @Override public int getVncPort(VirtualMachine vm) { if (vm.getHostId() == null) { s_logger.warn("VM " + vm.getName() + " does not have host, return -1 for its VNC port"); @@ -6180,10 +6185,12 @@ public class ManagementServerImpl implements ManagementServer { return port; } + @Override public ConsoleProxyVO findConsoleProxyById(long instanceId) { return _consoleProxyDao.findById(instanceId); } + @Override public List searchForDomains(Criteria c) { Filter searchFilter = new Filter(DomainVO.class, c.getOrderBy(), c.getAscending(), c.getOffset(), c.getLimit()); Long domainId = (Long) c.getCriteria(Criteria.ID); @@ -6223,6 +6230,7 @@ public class ManagementServerImpl implements ManagementServer { return _domainDao.search(sc, searchFilter); } + @Override public List searchForDomainChildren(Criteria c) { Filter searchFilter = new Filter(DomainVO.class, c.getOrderBy(), c.getAscending(), c.getOffset(), c.getLimit()); Long domainId = (Long) c.getCriteria(Criteria.ID); @@ -6354,6 +6362,7 @@ public class ManagementServerImpl implements ManagementServer { return success && deleteDomainSuccess; } + @Override public void updateDomain(Long domainId, String domainName) { SearchCriteria sc = _domainDao.createSearchCriteria(); sc.addAnd("name", SearchCriteria.Op.EQ, domainName); @@ -6368,6 +6377,7 @@ public class ManagementServerImpl implements ManagementServer { } } + @Override public Long findDomainIdByAccountId(Long accountId) { if (accountId == null) { return null; @@ -6381,6 +6391,7 @@ public class ManagementServerImpl implements ManagementServer { return null; } + @Override public DomainVO findDomainIdById(Long domainId) { return _domainDao.findById(domainId); } @@ -6447,6 +6458,7 @@ public class ManagementServerImpl implements ManagementServer { return _capacityDao.search(sc, searchFilter); } + @Override public long getMemoryUsagebyHost(Long hostId) { long mem = 0; List vms = _vmInstanceDao.listUpByHostIdTypes(hostId, VirtualMachine.Type.DomainRouter); @@ -8266,6 +8278,7 @@ public class ManagementServerImpl implements ManagementServer { return null; } + @Override public ArrayList getCloudIdentifierResponse(long userId) { Criteria c = new Criteria (); @@ -8477,12 +8490,14 @@ public class ManagementServerImpl implements ManagementServer { return _configMgr.addConfig(category, instance, component, name, value, description); } - public boolean preparePrimaryStorageForMaintenance(long primaryStorageId, long userId) { + @Override + public boolean preparePrimaryStorageForMaintenance(long primaryStorageId, long userId) { return _storageMgr.preparePrimaryStorageForMaintenance(primaryStorageId, userId); } - public long preparePrimaryStorageForMaintenanceAsync(long primaryStorageId) throws InvalidParameterValueException + @Override + public long preparePrimaryStorageForMaintenanceAsync(long primaryStorageId) throws InvalidParameterValueException { StoragePoolVO primaryStorage = _poolDao.findById(primaryStorageId); @@ -8512,12 +8527,14 @@ public class ManagementServerImpl implements ManagementServer { } + @Override public boolean cancelPrimaryStorageMaintenance(long primaryStorageId, long userId) { return _storageMgr.cancelPrimaryStorageForMaintenance(primaryStorageId, userId); } - public long cancelPrimaryStorageMaintenanceAsync(long primaryStorageId) throws InvalidParameterValueException + @Override + public long cancelPrimaryStorageMaintenanceAsync(long primaryStorageId) throws InvalidParameterValueException { StoragePoolVO primaryStorage = _poolDao.findById(primaryStorageId); diff --git a/server/src/com/cloud/vm/VmManager.java b/server/src/com/cloud/vm/VmManager.java index 068da4e084d..a9833ec82bf 100644 --- a/server/src/com/cloud/vm/VmManager.java +++ b/server/src/com/cloud/vm/VmManager.java @@ -32,12 +32,12 @@ import com.cloud.user.AccountVO; public interface VmManager { VMInstanceVO allocate(VMInstanceVO vm, - ServiceOfferingVO serviceOffering, - Long rootSize, - List networkOfferings, - Map diskOfferings, - DataCenterVO dc, - AccountVO owner); + ServiceOfferingVO serviceOffering, + Long rootSize, + List networkOfferings, + Map diskOfferings, + DataCenterVO dc, + AccountVO owner); VMInstanceVO allocate(VMInstanceVO vm, ServiceOfferingVO serviceOffering, diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 5f87093cb8a..43098ef070c 100644 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -77,6 +77,14 @@ DROP TABLE IF EXISTS `cloud`.`nics`; DROP TABLE IF EXISTS `cloud`.`network_profiles`; DROP TABLE IF EXISTS `cloud`.`network_offerings`; DROP TABLE IF EXISTS `cloud`.`host_master`; +DROP TABLE IF EXISTS `cloud`.`hypervisor_properties`; + +CREATE TABLE `cloud`.`hypervsior_properties` ( + `hypervisor` varchar(32) NOT NULL UNIQUE COMMENT 'hypervisor type', + `max_storage_devices` int(10) NOT NULL COMMENT 'maximum number of storage devices', + `cdrom_device` int(10) NOT NULL COMMENT 'device id reserved for cdrom', + `max_network_devices` int(10) NOT NULL COMMENT 'maximum number of network devices' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `cloud`.`network_profiles` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', diff --git a/ui/content/tab_storage.html b/ui/content/tab_storage.html index 90c75b95dba..3abfa48568f 100644 --- a/ui/content/tab_storage.html +++ b/ui/content/tab_storage.html @@ -611,7 +611,7 @@
Name
-
+
Type
@@ -631,7 +631,7 @@
Size
-
+
State
@@ -703,7 +703,7 @@
Name
-
+
Type
@@ -723,7 +723,7 @@
size
-
+
state
diff --git a/ui/scripts/cloud.core.domains.js b/ui/scripts/cloud.core.domains.js index 921b158b177..db94223d8f1 100644 --- a/ui/scripts/cloud.core.domains.js +++ b/ui/scripts/cloud.core.domains.js @@ -65,8 +65,8 @@ function showDomainsTab() { } function drawTree(id, level, container) { - $.ajax({ - data: createURL("command=listDomainChildren&id="+id+"&response=json"), + $.ajax({ + data: "command=listDomainChildren&id="+id+"&response=json&pageSize=-1", dataType: "json", async: false, success: function(json) { @@ -320,8 +320,8 @@ function showDomainsTab() { rightPanelDetailContent.hide(); rightPanelSearchResult.show(); var keyword = searchInput.val(); - $.ajax({ - data: createURL("command=listDomains&keyword="+keyword+"&response=json"+maxPageSize), + $.ajax({ + data: "command=listDomains&keyword="+keyword+"&response=json&pageSize=-1", //pageSize=-1 will return all items (no limitation) dataType: "json", async: false, success: function(json) { @@ -349,8 +349,8 @@ function showDomainsTab() { //draw root node function drawRootNode(rootDomainId) { treeContentBox.empty(); - $.ajax({ - data: createURL("command=listDomains&id="+rootDomainId+"&response=json"), + $.ajax({ + data: "command=listDomains&id="+rootDomainId+"&response=json&pageSize=-1", //pageSize=-1 will return all items (no limitation) dataType: "json", async: false, success: function(json) { diff --git a/wscript_configure b/wscript_configure index 5185f87fbf2..a7111b847cc 100644 --- a/wscript_configure +++ b/wscript_configure @@ -232,10 +232,13 @@ conf.env.USAGECLASSPATH = pathsep.join(usageclasspath) # 1. source directories (without including the JARs) # JARs are not included because in case of parallel compilation (IOW, all the time), javac picks up half-written JARs and die compilecp = []# list(srcdirs) -# 2.a) the thirdparty/ directory in the source if on Windows / Mac # 2.b) the deps/ directory in the source if on Linux -if conf.env.DISTRO in ["Windows","Mac"]: compilecp+= _glob(_join("cloudstack-proprietary","thirdparty","*.jar")) -else: compilecp+= _glob(_join("deps","*.jar")) +# 2.a) the thirdparty/ directory if available +if conf.env.DISTRO in ["Windows","Mac"]: + pass +else: + compilecp+= _glob(_join("deps","*.jar")) +compilecp+= _glob(_join("cloudstack-proprietary","thirdparty","*.jar")) # 3. the system classpath (system-installed JARs) compilecp+= [ conf.env.SYSTEMCLASSPATH ] compilecp+= _glob(_join(conf.env.TOMCATHOME,'bin',"*.jar"))