From 417a3c8c187a88594e3d298cd2d8774363510cf3 Mon Sep 17 00:00:00 2001 From: Alex Huang Date: Thu, 19 Aug 2010 11:27:30 -0700 Subject: [PATCH] bug 5764: More changes --- build/build.number | 4 +- .../consoleproxy/ConsoleProxyManager.java | 54 - .../AgentBasedConsoleProxyManager.java | 554 +-- ...entBasedStandaloneConsoleProxyManager.java | 18 +- .../src/com/cloud/consoleproxy/AgentHook.java | 19 + .../ConsoleProxyAlertEventArgs.java | 0 .../consoleproxy/ConsoleProxyListener.java | 45 +- .../consoleproxy/ConsoleProxyManager.java | 46 + .../consoleproxy/ConsoleProxyManagerImpl.java | 4296 ++++++++--------- .../StaticConsoleProxyManager.java | 30 +- .../cloud/server/ManagementServerImpl.java | 59 +- server/src/com/cloud/vm/VmManager.java | 12 +- 12 files changed, 2489 insertions(+), 2648 deletions(-) delete mode 100644 core/src/com/cloud/consoleproxy/ConsoleProxyManager.java create mode 100644 server/src/com/cloud/consoleproxy/AgentHook.java rename {core => server}/src/com/cloud/consoleproxy/ConsoleProxyAlertEventArgs.java (100%) rename {core => server}/src/com/cloud/consoleproxy/ConsoleProxyListener.java (76%) create mode 100644 server/src/com/cloud/consoleproxy/ConsoleProxyManager.java diff --git a/build/build.number b/build/build.number index 0216cfc6927..fd157380ba6 100644 --- a/build/build.number +++ b/build/build.number @@ -1,3 +1,3 @@ #Build Number for ANT. Do not edit! -#Thu Aug 19 09:21:10 PDT 2010 -build.number=65 +#Thu Aug 19 11:24:57 PDT 2010 +build.number=71 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/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,