Skip to content

Backport: Honour consoleproxy.session.timeout for noVNC console sessions#13058

Open
dheeraj12347 wants to merge 1 commit intoapache:4.20from
dheeraj12347:backport-12810-consoleproxy-timeout-4.20
Open

Backport: Honour consoleproxy.session.timeout for noVNC console sessions#13058
dheeraj12347 wants to merge 1 commit intoapache:4.20from
dheeraj12347:backport-12810-consoleproxy-timeout-4.20

Conversation

@dheeraj12347
Copy link
Copy Markdown
Contributor

Description

This PR backports the console proxy/noVNC timeout fix to the 4.20 branch.

It ensures that consoleproxy.session.timeout is honoured for noVNC console
sessions, so idle sessions are cleaned up correctly and do not linger
indefinitely.

Key points:

  • Wire consoleproxy.session.timeout through the console proxy server for
    noVNC-based console sessions.
  • Apply the timeout in the WebSocket handler and GC thread so idle sessions
    are closed after the configured period.
  • Keep the change minimal and compatible with 4.20: do not introduce the
    newer sessionRequiresNewViewer API on ConsoleProxyClientParam, only
    remove the references that exist in later branches.

Related work

  • Backport of the console proxy timeout fix from the main branch.
  • Intended to address the same behaviour as the upstream change that fixed
    idle noVNC sessions not respecting consoleproxy.session.timeout.

Testing

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to backport the fix to ensure consoleproxy.session.timeout is honored for noVNC console sessions on the 4.20 branch, so idle sessions are cleaned up and don’t linger indefinitely.

Changes:

  • Updates the noVNC WebSocket handler with additional logging, parameter validation, and safer frame/error handling.
  • Refactors the console proxy GC thread loop and related logging around idle session cleanup.
  • Adjusts console proxy startup/authentication reflection and noVNC viewer creation/replacement logic.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxyNoVNCHandler.java WebSocket connect/frame/error handling changes intended to support correct idle-session cleanup.
services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxyGCThread.java GC loop refactor and idle session timeout constant/comment updates.
services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxy.java Console proxy startup/auth reflection changes and noVNC viewer lifecycle adjustments.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Class<?> contextClazz = loader.loadClass("com.cloud.agent.resource.consoleproxy.ConsoleProxyResource");
authMethod = contextClazz.getDeclaredMethod("authenticateConsoleAccess", String.class, String.class,
String.class, String.class, String.class, Boolean.class, String.class);
String.class, String.class, String.class, Boolean.class, String.class, String.class);
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reflective lookup of ConsoleProxyResource.authenticateConsoleAccess(...) now expects an extra String parameter, but in this branch ConsoleProxyResource defines authenticateConsoleAccess(host, port, vmId, sid, ticket, isReauthentication, sessionToken) with 7 params. This will trigger NoSuchMethodException at startup, leaving authMethod unset and causing authenticateConsoleAccess(...) to fall back to "offline mode" (success=true) which effectively bypasses management-server authentication. Align the getDeclaredMethod(...) signature (and corresponding invoke call) with the actual ConsoleProxyResource method in 4.20, or add a backwards-compatible lookup that tries both signatures.

Suggested change
String.class, String.class, String.class, Boolean.class, String.class, String.class);
String.class, String.class, String.class, Boolean.class, String.class);

Copilot uses AI. Check for mistakes.
Comment on lines 236 to 240
result =
authMethod.invoke(ConsoleProxy.context, param.getClientHostAddress(), String.valueOf(param.getClientHostPort()), param.getClientTag(),
param.getClientHostPassword(), param.getTicket(), reauthentication, param.getSessionUuid());
authMethod.invoke(ConsoleProxy.context, param.getClientHostAddress(), String.valueOf(param.getClientHostPort()),
param.getClientTag(), param.getClientHostPassword(), param.getTicket(), reauthentication,
param.getSessionUuid(), param.getClientIp());
} catch (IllegalAccessException e) {
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authenticateConsoleAccess(...) now invokes authMethod with an extra param.getClientIp() argument. On 4.20, ConsoleProxyResource.authenticateConsoleAccess(...) only accepts 7 arguments, so this call will fail if/when authMethod is resolved. Keep the invocation arguments consistent with the reflected method signature (or implement a dual-signature invocation path).

Copilot uses AI. Check for mistakes.
try {
authenticationExternally(param);
} catch (Exception e) {
LOGGER.error("Authentication failed for param: " + param);
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In getNoVncViewer(...), the AuthenticationException path logs "Authentication failed" without including the caught exception, which loses the stack trace/context needed to debug auth failures. Log the exception (and preferably include key identifiers like sessionUuid/clientKey) when catching the failure.

Suggested change
LOGGER.error("Authentication failed for param: " + param);
LOGGER.error("Authentication failed for sessionUuid={}, clientKey={}, param={}",
param.getSessionUuid(), clientKey, param, e);

Copilot uses AI. Check for mistakes.
Comment on lines +39 to +41
* This value should be kept in sync with ConsoleProxy.VIEWER_LINGER_SECONDS.
*/
private static final int MAX_SESSION_IDLE_SECONDS = 180;
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAX_SESSION_IDLE_SECONDS is still hard-coded to 180s, which does not match the documented/expected behavior of honoring the global consoleproxy.session.timeout (default 300000ms) and is also duplicating ConsoleProxy.VIEWER_LINGER_SECONDS. To honor the setting and avoid drift, derive the idle timeout from the configured consoleproxy.session.timeout and use a single shared value for both GC and viewer liveness checks.

Suggested change
* This value should be kept in sync with ConsoleProxy.VIEWER_LINGER_SECONDS.
*/
private static final int MAX_SESSION_IDLE_SECONDS = 180;
* Reuse the shared viewer linger timeout so GC honors the configured
* consoleproxy.session.timeout and does not drift from viewer liveness checks.
*/
private static final int MAX_SESSION_IDLE_SECONDS = ConsoleProxy.VIEWER_LINGER_SECONDS;

Copilot uses AI. Check for mistakes.
String websocketUrl = queryMap.get("websocketUrl");
String sessionUuid = queryMap.get("sessionUuid");
String clientIp = session.getRemoteAddress().getAddress().getHostAddress();
boolean sessionRequiresNewViewer = Boolean.parseBoolean(queryMap.get("sessionRequiresNewViewer"));
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sessionRequiresNewViewer is parsed from the query string but never used. If this branch intentionally does not support that behavior (per the PR description), remove this local variable (and possibly the query param handling) to avoid confusion and dead code.

Suggested change
boolean sessionRequiresNewViewer = Boolean.parseBoolean(queryMap.get("sessionRequiresNewViewer"));

Copilot uses AI. Check for mistakes.
if (viewer == null) {
logger.debug("Ignoring WebSocket frame because viewer is not initialized yet.");
return;
}
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NoVNC session idle tracking relies on getClientLastFrontEndActivityTime(), but this handler does not update the viewer's front-end activity timestamp when frames arrive from the browser. As a result, GC/linger logic may not reflect actual browser activity and can prevent consoleproxy.session.timeout from being enforced. Update the viewer's front-end activity time on each received WebSocket frame (and ensure the timestamp isn't continuously refreshed by backend reads alone).

Suggested change
}
}
viewer.setClientLastFrontEndActivityTime(System.currentTimeMillis());

Copilot uses AI. Check for mistakes.
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 28, 2026

Codecov Report

❌ Patch coverage is 0.96154% with 103 lines in your changes missing coverage. Please review.
✅ Project coverage is 16.26%. Comparing base (9f96c9d) to head (57356f8).

Files with missing lines Patch % Lines
...main/java/com/cloud/consoleproxy/ConsoleProxy.java 1.31% 75 Missing ⚠️
...m/cloud/consoleproxy/ConsoleProxyNoVNCHandler.java 0.00% 15 Missing ⚠️
...a/com/cloud/consoleproxy/ConsoleProxyGCThread.java 0.00% 13 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##               4.20   #13058   +/-   ##
=========================================
  Coverage     16.26%   16.26%           
- Complexity    13435    13437    +2     
=========================================
  Files          5665     5665           
  Lines        500556   500569   +13     
  Branches      60790    60801   +11     
=========================================
+ Hits          81416    81433   +17     
+ Misses       410036   410028    -8     
- Partials       9104     9108    +4     
Flag Coverage Δ
uitests 4.15% <ø> (ø)
unittests 17.12% <0.96%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Global setting "consoleproxy.session.timeout " is not honoured

2 participants