Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions lib/endpoints/vms.js
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,92 @@ VM.vnc = function handlerVmVnc(req, res, next) {
};


/**
* Query the server for the VM's console host and port.
*
* Returns connection details for the VM's console (serial console for KVM,
* zone console for other brands).
*
* @name VmConsole
* @endpoint GET /servers/:server_uuid/vms/:uuid/console
* @section Virtual Machine API
*
* @response 200 Object Request succeeded
* @response 404 Object No such VM
* @response 404 Object No such server
*/

var vmConsoleTimeoutSeconds = 10;
VM.console = function handlerVmConsole(req, res, next) {
var responded;

if (validation.ensureParamsValid(req, res, vmValidationRules)) {
next();
return;
}

var timeout = setTimeout(function () {
responded = true;
next(new restify.InternalError(
'Time-out reached waiting for machine_load request to return'));
Copy link

Copilot AI Oct 8, 2025

Choose a reason for hiding this comment

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

The error message references 'machine_load request' but this endpoint is for console information, not machine loading. The message should be updated to reflect the actual operation.

Suggested change
'Time-out reached waiting for machine_load request to return'));
'Time-out reached waiting for VM console information to return'));

Copilot uses AI. Check for mistakes.
}, vmConsoleTimeoutSeconds * 1000);

var types = ['console'];

req.stash.vm.info(
{ req_id: req.getId(), types: types },
function (error, infoResponse) {
var vminfo;
clearTimeout(timeout);

if (responded && error) {
req.log.error(error.message);
return;
}

if (responded) {
req.log.warn('Got a reply back from an expired request');
return;
}

if (error) {
if (errDetails(error).restCode === 'VmNotFound') {
next(new restify.ResourceNotFoundError('VM ' +
req.params.uuid + ' not found'));
} else {
next(new restify.InternalError(error.message));
}
return;
}

try {
vminfo = JSON.parse(infoResponse);
} catch (e) {
req.log.error({infoResponse: infoResponse, err: e},
'failed to parse JSON');
next(new restify.InternalError(
'failed to parse JSON response from vm.info'));
return;
}

// Ensure console info exists
if (!vminfo.console || !vminfo.console.host || !vminfo.console.port) {
Copy link

Copilot AI Oct 8, 2025

Choose a reason for hiding this comment

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

The validation should also check for vminfo.console.type since it's used later and returned in the response. Missing type could cause undefined to be returned.

Suggested change
if (!vminfo.console || !vminfo.console.host || !vminfo.console.port) {
if (!vminfo.console || !vminfo.console.host || !vminfo.console.port || !vminfo.console.type) {

Copilot uses AI. Check for mistakes.
next(new restify.ResourceNotFoundError(
'Console information not available for VM ' + req.params.uuid));
return;
}

var host = vminfo.console.host;
var port = vminfo.console.port;
var type = vminfo.console.type;

res.send({host: host, port: port, type: type});
next();
return;
});
};


/**
* Modify the system parameters of the VM identified by `:uuid` on server with
* UUID `:server_uuid`.
Expand Down Expand Up @@ -1332,6 +1418,17 @@ function attachTo(http, app) {
}),
VM.vnc);

http.get(
{ path: '/servers/:server_uuid/vms/:uuid/console', name: 'VmConsole' },
ensure({
connectionTimeoutSeconds: 60 * 60,
app: app,
serverRunning: true,
prepopulate: ['server', 'vm'],
connected: ['moray']
}),
VM.console);

// Update VM's properties from the server (resize)
http.post(
{ path: '/servers/:server_uuid/vms/:uuid/update', name: 'VmUpdate' },
Expand Down