mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Add console session cleanup task (#7132)
This commit is contained in:
parent
9c4b3a6847
commit
89bf4750ab
@ -18,8 +18,24 @@ package org.apache.cloudstack.consoleproxy;
|
|||||||
|
|
||||||
import com.cloud.utils.component.Manager;
|
import com.cloud.utils.component.Manager;
|
||||||
import org.apache.cloudstack.api.command.user.consoleproxy.ConsoleEndpoint;
|
import org.apache.cloudstack.api.command.user.consoleproxy.ConsoleEndpoint;
|
||||||
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
|
import org.apache.cloudstack.framework.config.Configurable;
|
||||||
|
|
||||||
public interface ConsoleAccessManager extends Manager {
|
public interface ConsoleAccessManager extends Manager, Configurable {
|
||||||
|
|
||||||
|
ConfigKey<Integer> ConsoleSessionCleanupRetentionHours = new ConfigKey<>("Advanced", Integer.class,
|
||||||
|
"console.session.cleanup.retention.hours",
|
||||||
|
"240",
|
||||||
|
"Determines the hours to keep removed console session records before expunging them",
|
||||||
|
false,
|
||||||
|
ConfigKey.Scope.Global);
|
||||||
|
|
||||||
|
ConfigKey<Integer> ConsoleSessionCleanupInterval = new ConfigKey<>("Advanced", Integer.class,
|
||||||
|
"console.session.cleanup.interval",
|
||||||
|
"180",
|
||||||
|
"Determines the interval (in hours) to wait between the console session cleanup tasks",
|
||||||
|
false,
|
||||||
|
ConfigKey.Scope.Global);
|
||||||
|
|
||||||
ConsoleEndpoint generateConsoleEndpoint(Long vmId, String extraSecurityToken, String clientAddress);
|
ConsoleEndpoint generateConsoleEndpoint(Long vmId, String extraSecurityToken, String clientAddress);
|
||||||
|
|
||||||
@ -27,5 +43,5 @@ public interface ConsoleAccessManager extends Manager {
|
|||||||
|
|
||||||
void removeSessions(String[] sessionUuids);
|
void removeSessions(String[] sessionUuids);
|
||||||
|
|
||||||
void removeSession(String sessionUuid);
|
void acquireSession(String sessionUuid);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,6 +54,9 @@ public class ConsoleSessionVO {
|
|||||||
@Column(name = "host_id")
|
@Column(name = "host_id")
|
||||||
private long hostId;
|
private long hostId;
|
||||||
|
|
||||||
|
@Column(name = "acquired")
|
||||||
|
private boolean acquired;
|
||||||
|
|
||||||
@Column(name = "removed")
|
@Column(name = "removed")
|
||||||
private Date removed;
|
private Date removed;
|
||||||
|
|
||||||
@ -120,4 +123,12 @@ public class ConsoleSessionVO {
|
|||||||
public void setRemoved(Date removed) {
|
public void setRemoved(Date removed) {
|
||||||
this.removed = removed;
|
this.removed = removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isAcquired() {
|
||||||
|
return acquired;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAcquired(boolean acquired) {
|
||||||
|
this.acquired = acquired;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,10 +22,15 @@ package com.cloud.vm.dao;
|
|||||||
import com.cloud.vm.ConsoleSessionVO;
|
import com.cloud.vm.ConsoleSessionVO;
|
||||||
import com.cloud.utils.db.GenericDao;
|
import com.cloud.utils.db.GenericDao;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
public interface ConsoleSessionDao extends GenericDao<ConsoleSessionVO, Long> {
|
public interface ConsoleSessionDao extends GenericDao<ConsoleSessionVO, Long> {
|
||||||
|
|
||||||
void removeSession(String sessionUuid);
|
void removeSession(String sessionUuid);
|
||||||
|
|
||||||
boolean isSessionAllowed(String sessionUuid);
|
boolean isSessionAllowed(String sessionUuid);
|
||||||
|
|
||||||
|
int expungeSessionsOlderThanDate(Date date);
|
||||||
|
|
||||||
|
void acquireSession(String sessionUuid);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,11 +19,23 @@
|
|||||||
|
|
||||||
package com.cloud.vm.dao;
|
package com.cloud.vm.dao;
|
||||||
|
|
||||||
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
import com.cloud.vm.ConsoleSessionVO;
|
import com.cloud.vm.ConsoleSessionVO;
|
||||||
import com.cloud.utils.db.GenericDaoBase;
|
import com.cloud.utils.db.GenericDaoBase;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
public class ConsoleSessionDaoImpl extends GenericDaoBase<ConsoleSessionVO, Long> implements ConsoleSessionDao {
|
public class ConsoleSessionDaoImpl extends GenericDaoBase<ConsoleSessionVO, Long> implements ConsoleSessionDao {
|
||||||
|
|
||||||
|
private final SearchBuilder<ConsoleSessionVO> searchByRemovedDate;
|
||||||
|
|
||||||
|
public ConsoleSessionDaoImpl() {
|
||||||
|
searchByRemovedDate = createSearchBuilder();
|
||||||
|
searchByRemovedDate.and("removedNotNull", searchByRemovedDate.entity().getRemoved(), SearchCriteria.Op.NNULL);
|
||||||
|
searchByRemovedDate.and("removed", searchByRemovedDate.entity().getRemoved(), SearchCriteria.Op.LTEQ);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeSession(String sessionUuid) {
|
public void removeSession(String sessionUuid) {
|
||||||
ConsoleSessionVO session = findByUuid(sessionUuid);
|
ConsoleSessionVO session = findByUuid(sessionUuid);
|
||||||
@ -32,6 +44,26 @@ public class ConsoleSessionDaoImpl extends GenericDaoBase<ConsoleSessionVO, Long
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSessionAllowed(String sessionUuid) {
|
public boolean isSessionAllowed(String sessionUuid) {
|
||||||
return findByUuid(sessionUuid) != null;
|
ConsoleSessionVO consoleSessionVO = findByUuid(sessionUuid);
|
||||||
|
if (consoleSessionVO == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !consoleSessionVO.isAcquired();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int expungeSessionsOlderThanDate(Date date) {
|
||||||
|
SearchCriteria<ConsoleSessionVO> searchCriteria = searchByRemovedDate.create();
|
||||||
|
searchCriteria.setParameters("removed", date);
|
||||||
|
return expunge(searchCriteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void acquireSession(String sessionUuid) {
|
||||||
|
ConsoleSessionVO consoleSessionVO = findByUuid(sessionUuid);
|
||||||
|
consoleSessionVO.setAcquired(true);
|
||||||
|
update(consoleSessionVO.getId(), consoleSessionVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1480,6 +1480,7 @@ CREATE TABLE IF NOT EXISTS `cloud`.`console_session` (
|
|||||||
`user_id` bigint(20) unsigned NOT NULL COMMENT 'User who generated the session',
|
`user_id` bigint(20) unsigned NOT NULL COMMENT 'User who generated the session',
|
||||||
`instance_id` bigint(20) unsigned NOT NULL COMMENT 'VM for which the session was generated',
|
`instance_id` bigint(20) unsigned NOT NULL COMMENT 'VM for which the session was generated',
|
||||||
`host_id` bigint(20) unsigned NOT NULL COMMENT 'Host where the VM was when the session was generated',
|
`host_id` bigint(20) unsigned NOT NULL COMMENT 'Host where the VM was when the session was generated',
|
||||||
|
`acquired` int(1) NOT NULL DEFAULT 0 COMMENT 'True if the session was already used',
|
||||||
`removed` datetime COMMENT 'When the session was removed/used',
|
`removed` datetime COMMENT 'When the session was removed/used',
|
||||||
CONSTRAINT `fk_consolesession__account_id` FOREIGN KEY(`account_id`) REFERENCES `cloud`.`account` (`id`),
|
CONSTRAINT `fk_consolesession__account_id` FOREIGN KEY(`account_id`) REFERENCES `cloud`.`account` (`id`),
|
||||||
CONSTRAINT `fk_consolesession__user_id` FOREIGN KEY(`user_id`) REFERENCES `cloud`.`user`(`id`),
|
CONSTRAINT `fk_consolesession__user_id` FOREIGN KEY(`user_id`) REFERENCES `cloud`.`user`(`id`),
|
||||||
|
|||||||
@ -110,8 +110,8 @@ public abstract class AgentHookBase implements AgentHook {
|
|||||||
return new ConsoleAccessAuthenticationAnswer(cmd, false);
|
return new ConsoleAccessAuthenticationAnswer(cmd, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
s_logger.debug(String.format("Removing session [%s] as it was just used.", sessionUuid));
|
s_logger.debug(String.format("Acquiring session [%s] as it was just used.", sessionUuid));
|
||||||
consoleAccessManager.removeSession(sessionUuid);
|
consoleAccessManager.acquireSession(sessionUuid);
|
||||||
|
|
||||||
if (!ticket.equals(ticketInUrl)) {
|
if (!ticket.equals(ticketInUrl)) {
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
|
|||||||
@ -59,7 +59,9 @@ import com.cloud.uservm.UserVm;
|
|||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.Ternary;
|
import com.cloud.utils.Ternary;
|
||||||
import com.cloud.utils.component.ManagerBase;
|
import com.cloud.utils.component.ManagerBase;
|
||||||
|
import com.cloud.utils.concurrency.NamedThreadFactory;
|
||||||
import com.cloud.utils.db.EntityManager;
|
import com.cloud.utils.db.EntityManager;
|
||||||
|
import com.cloud.utils.db.GlobalLock;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.vm.ConsoleSessionVO;
|
import com.cloud.vm.ConsoleSessionVO;
|
||||||
import com.cloud.vm.UserVmDetailVO;
|
import com.cloud.vm.UserVmDetailVO;
|
||||||
@ -70,6 +72,13 @@ import com.cloud.vm.dao.ConsoleSessionDao;
|
|||||||
import com.cloud.vm.dao.UserVmDetailsDao;
|
import com.cloud.vm.dao.UserVmDetailsDao;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
|
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class ConsoleAccessManagerImpl extends ManagerBase implements ConsoleAccessManager {
|
public class ConsoleAccessManagerImpl extends ManagerBase implements ConsoleAccessManager {
|
||||||
|
|
||||||
@ -94,6 +103,8 @@ public class ConsoleAccessManagerImpl extends ManagerBase implements ConsoleAcce
|
|||||||
@Inject
|
@Inject
|
||||||
private ConsoleSessionDao consoleSessionDao;
|
private ConsoleSessionDao consoleSessionDao;
|
||||||
|
|
||||||
|
private ScheduledExecutorService executorService = null;
|
||||||
|
|
||||||
private static KeysManager secretKeysManager;
|
private static KeysManager secretKeysManager;
|
||||||
private final Gson gson = new GsonBuilder().create();
|
private final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
@ -106,9 +117,69 @@ public class ConsoleAccessManagerImpl extends ManagerBase implements ConsoleAcce
|
|||||||
@Override
|
@Override
|
||||||
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
||||||
ConsoleAccessManagerImpl.secretKeysManager = keysManager;
|
ConsoleAccessManagerImpl.secretKeysManager = keysManager;
|
||||||
|
executorService = Executors.newScheduledThreadPool(1, new NamedThreadFactory("ConsoleSession-Scavenger"));
|
||||||
return super.configure(name, params);
|
return super.configure(name, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean start() {
|
||||||
|
int consoleCleanupInterval = ConsoleAccessManager.ConsoleSessionCleanupInterval.value();
|
||||||
|
if (consoleCleanupInterval > 0) {
|
||||||
|
s_logger.info(String.format("The ConsoleSessionCleanupTask will run every %s hours", consoleCleanupInterval));
|
||||||
|
executorService.scheduleWithFixedDelay(new ConsoleSessionCleanupTask(), consoleCleanupInterval, consoleCleanupInterval, TimeUnit.HOURS);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getConfigComponentName() {
|
||||||
|
return ConsoleAccessManager.class.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigKey<?>[] getConfigKeys() {
|
||||||
|
return new ConfigKey[] {
|
||||||
|
ConsoleAccessManager.ConsoleSessionCleanupInterval,
|
||||||
|
ConsoleAccessManager.ConsoleSessionCleanupRetentionHours
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ConsoleSessionCleanupTask extends ManagedContextRunnable {
|
||||||
|
@Override
|
||||||
|
protected void runInContext() {
|
||||||
|
final GlobalLock gcLock = GlobalLock.getInternLock("ConsoleSession.Cleanup.Lock");
|
||||||
|
try {
|
||||||
|
if (gcLock.lock(3)) {
|
||||||
|
try {
|
||||||
|
reallyRun();
|
||||||
|
} finally {
|
||||||
|
gcLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
gcLock.releaseRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reallyRun() {
|
||||||
|
if (s_logger.isDebugEnabled()) {
|
||||||
|
s_logger.debug("Starting ConsoleSessionCleanupTask...");
|
||||||
|
}
|
||||||
|
Integer retentionHours = ConsoleAccessManager.ConsoleSessionCleanupRetentionHours.value();
|
||||||
|
Date dateBefore = DateTime.now().minusHours(retentionHours).toDate();
|
||||||
|
if (s_logger.isDebugEnabled()) {
|
||||||
|
s_logger.debug(String.format("Retention hours: %s, checking for removed console session " +
|
||||||
|
"records to expunge older than: %s", retentionHours, dateBefore));
|
||||||
|
}
|
||||||
|
int sessionsExpunged = consoleSessionDao.expungeSessionsOlderThanDate(dateBefore);
|
||||||
|
if (s_logger.isDebugEnabled()) {
|
||||||
|
s_logger.debug(sessionsExpunged > 0 ?
|
||||||
|
String.format("Expunged %s removed console session records", sessionsExpunged) :
|
||||||
|
"No removed console session records expunged on this cleanup task run");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConsoleEndpoint generateConsoleEndpoint(Long vmId, String extraSecurityToken, String clientAddress) {
|
public ConsoleEndpoint generateConsoleEndpoint(Long vmId, String extraSecurityToken, String clientAddress) {
|
||||||
try {
|
try {
|
||||||
@ -171,11 +242,15 @@ public class ConsoleAccessManagerImpl extends ManagerBase implements ConsoleAcce
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected void removeSession(String sessionUuid) {
|
||||||
public void removeSession(String sessionUuid) {
|
|
||||||
consoleSessionDao.removeSession(sessionUuid);
|
consoleSessionDao.removeSession(sessionUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void acquireSession(String sessionUuid) {
|
||||||
|
consoleSessionDao.acquireSession(sessionUuid);
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean checkSessionPermission(VirtualMachine vm, Account account) {
|
protected boolean checkSessionPermission(VirtualMachine vm, Account account) {
|
||||||
if (accountManager.isRootAdmin(account.getId())) {
|
if (accountManager.isRootAdmin(account.getId())) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import java.util.Hashtable;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
@ -68,6 +69,7 @@ public class ConsoleProxy {
|
|||||||
public static Method ensureRouteMethod;
|
public static Method ensureRouteMethod;
|
||||||
|
|
||||||
static Hashtable<String, ConsoleProxyClient> connectionMap = new Hashtable<String, ConsoleProxyClient>();
|
static Hashtable<String, ConsoleProxyClient> connectionMap = new Hashtable<String, ConsoleProxyClient>();
|
||||||
|
static Set<String> removedSessionsSet = ConcurrentHashMap.newKeySet();
|
||||||
static int httpListenPort = 80;
|
static int httpListenPort = 80;
|
||||||
static int httpCmdListenPort = 8001;
|
static int httpCmdListenPort = 8001;
|
||||||
static int reconnectMaxRetry = 5;
|
static int reconnectMaxRetry = 5;
|
||||||
@ -372,7 +374,7 @@ public class ConsoleProxy {
|
|||||||
s_logger.info("HTTP command port is disabled");
|
s_logger.info("HTTP command port is disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsoleProxyGCThread cthread = new ConsoleProxyGCThread(connectionMap);
|
ConsoleProxyGCThread cthread = new ConsoleProxyGCThread(connectionMap, removedSessionsSet);
|
||||||
cthread.setName("Console Proxy GC Thread");
|
cthread.setName("Console Proxy GC Thread");
|
||||||
cthread.start();
|
cthread.start();
|
||||||
}
|
}
|
||||||
@ -540,6 +542,7 @@ public class ConsoleProxy {
|
|||||||
for (Map.Entry<String, ConsoleProxyClient> entry : connectionMap.entrySet()) {
|
for (Map.Entry<String, ConsoleProxyClient> entry : connectionMap.entrySet()) {
|
||||||
if (entry.getValue() == viewer) {
|
if (entry.getValue() == viewer) {
|
||||||
connectionMap.remove(entry.getKey());
|
connectionMap.remove(entry.getKey());
|
||||||
|
removedSessionsSet.add(viewer.getSessionUuid());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,9 +18,10 @@ package com.cloud.consoleproxy;
|
|||||||
|
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Enumeration;
|
import java.util.Iterator;
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
@ -42,7 +43,7 @@ public class ConsoleProxyClientStatsCollector {
|
|||||||
removedSessions.addAll(removed);
|
removedSessions.addAll(removed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConsoleProxyClientStatsCollector(Hashtable<String, ConsoleProxyClient> connMap) {
|
public ConsoleProxyClientStatsCollector(Map<String, ConsoleProxyClient> connMap) {
|
||||||
setConnections(connMap);
|
setConnections(connMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,13 +57,14 @@ public class ConsoleProxyClientStatsCollector {
|
|||||||
gson.toJson(this, os);
|
gson.toJson(this, os);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setConnections(Hashtable<String, ConsoleProxyClient> connMap) {
|
private void setConnections(Map<String, ConsoleProxyClient> connMap) {
|
||||||
|
|
||||||
ArrayList<ConsoleProxyConnection> conns = new ArrayList<ConsoleProxyConnection>();
|
ArrayList<ConsoleProxyConnection> conns = new ArrayList<ConsoleProxyConnection>();
|
||||||
Enumeration<String> e = connMap.keys();
|
Set<String> e = connMap.keySet();
|
||||||
while (e.hasMoreElements()) {
|
Iterator<String> iterator = e.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
synchronized (connMap) {
|
synchronized (connMap) {
|
||||||
String key = e.nextElement();
|
String key = iterator.next();
|
||||||
ConsoleProxyClient client = connMap.get(key);
|
ConsoleProxyClient client = connMap.get(key);
|
||||||
|
|
||||||
ConsoleProxyConnection conn = new ConsoleProxyConnection();
|
ConsoleProxyConnection conn = new ConsoleProxyConnection();
|
||||||
|
|||||||
@ -18,9 +18,9 @@ package com.cloud.consoleproxy;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Enumeration;
|
import java.util.Iterator;
|
||||||
import java.util.Hashtable;
|
import java.util.Map;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
@ -35,11 +35,13 @@ public class ConsoleProxyGCThread extends Thread {
|
|||||||
|
|
||||||
private final static int MAX_SESSION_IDLE_SECONDS = 180;
|
private final static int MAX_SESSION_IDLE_SECONDS = 180;
|
||||||
|
|
||||||
private final Hashtable<String, ConsoleProxyClient> connMap;
|
private final Map<String, ConsoleProxyClient> connMap;
|
||||||
|
private final Set<String> removedSessionsSet;
|
||||||
private long lastLogScan = 0;
|
private long lastLogScan = 0;
|
||||||
|
|
||||||
public ConsoleProxyGCThread(Hashtable<String, ConsoleProxyClient> connMap) {
|
public ConsoleProxyGCThread(Map<String, ConsoleProxyClient> connMap, Set<String> removedSet) {
|
||||||
this.connMap = connMap;
|
this.connMap = connMap;
|
||||||
|
this.removedSessionsSet = removedSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cleanupLogging() {
|
private void cleanupLogging() {
|
||||||
@ -69,22 +71,22 @@ public class ConsoleProxyGCThread extends Thread {
|
|||||||
|
|
||||||
boolean bReportLoad = false;
|
boolean bReportLoad = false;
|
||||||
long lastReportTick = System.currentTimeMillis();
|
long lastReportTick = System.currentTimeMillis();
|
||||||
List<String> removedSessions = new ArrayList<>();
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
cleanupLogging();
|
cleanupLogging();
|
||||||
bReportLoad = false;
|
bReportLoad = false;
|
||||||
removedSessions.clear();
|
|
||||||
|
|
||||||
if (s_logger.isDebugEnabled())
|
if (s_logger.isDebugEnabled()) {
|
||||||
s_logger.debug("connMap=" + connMap);
|
s_logger.debug(String.format("connMap=%s, removedSessions=%s", connMap, removedSessionsSet));
|
||||||
Enumeration<String> e = connMap.keys();
|
}
|
||||||
while (e.hasMoreElements()) {
|
Set<String> e = connMap.keySet();
|
||||||
|
Iterator<String> iterator = e.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
String key;
|
String key;
|
||||||
ConsoleProxyClient client;
|
ConsoleProxyClient client;
|
||||||
|
|
||||||
synchronized (connMap) {
|
synchronized (connMap) {
|
||||||
key = e.nextElement();
|
key = iterator.next();
|
||||||
client = connMap.get(key);
|
client = connMap.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +96,6 @@ public class ConsoleProxyGCThread extends Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
synchronized (connMap) {
|
synchronized (connMap) {
|
||||||
removedSessions.add(client.getSessionUuid());
|
|
||||||
connMap.remove(key);
|
connMap.remove(key);
|
||||||
bReportLoad = true;
|
bReportLoad = true;
|
||||||
}
|
}
|
||||||
@ -107,13 +108,17 @@ public class ConsoleProxyGCThread extends Thread {
|
|||||||
if (bReportLoad || System.currentTimeMillis() - lastReportTick > 5000) {
|
if (bReportLoad || System.currentTimeMillis() - lastReportTick > 5000) {
|
||||||
// report load changes
|
// report load changes
|
||||||
ConsoleProxyClientStatsCollector collector = new ConsoleProxyClientStatsCollector(connMap);
|
ConsoleProxyClientStatsCollector collector = new ConsoleProxyClientStatsCollector(connMap);
|
||||||
collector.setRemovedSessions(removedSessions);
|
collector.setRemovedSessions(new ArrayList<>(removedSessionsSet));
|
||||||
String loadInfo = collector.getStatsReport();
|
String loadInfo = collector.getStatsReport();
|
||||||
ConsoleProxy.reportLoadInfo(loadInfo);
|
ConsoleProxy.reportLoadInfo(loadInfo);
|
||||||
lastReportTick = System.currentTimeMillis();
|
lastReportTick = System.currentTimeMillis();
|
||||||
|
synchronized (removedSessionsSet) {
|
||||||
|
removedSessionsSet.clear();
|
||||||
|
}
|
||||||
|
|
||||||
if (s_logger.isDebugEnabled())
|
if (s_logger.isDebugEnabled()) {
|
||||||
s_logger.debug("Report load change : " + loadInfo);
|
s_logger.debug("Report load change : " + loadInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -19,6 +19,7 @@ package com.cloud.consoleproxy;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.eclipse.jetty.websocket.api.Session;
|
import org.eclipse.jetty.websocket.api.Session;
|
||||||
|
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||||
|
|
||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
@ -125,12 +126,8 @@ public class ConsoleProxyNoVncClient implements ConsoleProxyClient {
|
|||||||
} else {
|
} else {
|
||||||
b = new byte[100];
|
b = new byte[100];
|
||||||
readBytes = client.read(b);
|
readBytes = client.read(b);
|
||||||
if (readBytes == -1) {
|
if (readBytes == -1 || (readBytes > 0 && !sendReadBytesToNoVNC(b, readBytes))) {
|
||||||
break;
|
connectionAlive = false;
|
||||||
}
|
|
||||||
if (readBytes > 0) {
|
|
||||||
session.getRemote().sendBytes(ByteBuffer.wrap(b, 0, readBytes));
|
|
||||||
updateFrontEndActivityTime();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,6 +141,17 @@ public class ConsoleProxyNoVncClient implements ConsoleProxyClient {
|
|||||||
worker.start();
|
worker.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean sendReadBytesToNoVNC(byte[] b, int readBytes) {
|
||||||
|
try {
|
||||||
|
session.getRemote().sendBytes(ByteBuffer.wrap(b, 0, readBytes));
|
||||||
|
updateFrontEndActivityTime();
|
||||||
|
} catch (WebSocketException | IOException e) {
|
||||||
|
s_logger.debug("Connection exception", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticate to VNC server when not using websockets
|
* Authenticate to VNC server when not using websockets
|
||||||
*
|
*
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user