domotz-remote-pawn
Version:
Domotz Agent
134 lines (120 loc) • 5.8 kB
JavaScript
/** This file is part of Domotz Agent.
* Copyright (C) 2021 Domotz Ltd
*
* Domotz Agent 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
* (at your option) any later version.
*
* Domotz Agent 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 Domotz Agent. If not, see <http://www.gnu.org/licenses/>.
*
* A Remote is a device in the LAN that exposes WinRM and allows Basic Authentication
* HTTP connections.
*
* A Remote object has methods for executing commands on the remote machine and
* processing the output.
**/
module.exports.Remote = function (host, port, username, password, resourceLocator) {
var myConsole = resourceLocator.log.decorateLogs();
const client = require('./client').factory(resourceLocator);
const soap = require('./soap').factory(resourceLocator);
var commonOptions = {
host: host,
port: port,
path: '/wsman',
username: username,
password: password,
};
/**
* Executes a command on the Remote by opening a Shell, launching the command as a string,
* collecting the output (stdout, stderr) and the exit code, and finally closing the Shell
*
* Returns a promise that, once satisfied, yields the stdout of the command.
*
* Options available:
*
* - failOnErrors : default true. If true, an exception is raised if the remote command exited with a code != 0.
* If 'false', the exit code is ignored.
* - powershell: default true. If true, the command will be executed as powershell otherwise as cmd.exe
*
* @param command
* @param options
* @returns {*}
*/
function executeCommand(command, options) {
var executionContext = {
shellId: null
};
if (options === undefined) {
options = {};
}
options.failOnErrors = options.failOnErrors !== undefined ? options.failOnErrors : true;
options.powershell = options.powershell !== undefined ? options.powershell : true;
if (options.powershell) {
command = 'powershell.exe "' + command.replace(/"/gi, '\\"') + '"';
}
function waitForProcessFinish(data) {
if (data.exitCode === undefined) {
return client.executeRequest(commonOptions, soap.requests.getCommandOutput(data)).then(waitForProcessFinish);
}
if (options.failOnErrors && data.exitCode) {
myConsole.error('Command %s exited with error code: %s', data.commandId, data.exitCode);
return client.executeRequest(commonOptions, soap.requests.closeSession(executionContext.shellId))
.then(function () {
myConsole.info('Close Shell SUCCESS %s', executionContext.shellId);
})
.catch(function (error) {
myConsole.error('Cannot close shell shellId: %s - %s', executionContext.shellId, error);
})
.finally(function () {
throw new Error(
'Command ' + command + ' failed with exit code: ' + data.exitCode + ' - ' + (data.stdout || '') + ' ' + (data.stderr || '')
);
});
}
data.stdout = data.stdout || '';
myConsole.debug('Get Output SUCCESS - shellId: %s, commandId %s, output size: %s', data.shellId, data.commandId, data.stdout.length);
return client.executeRequest(commonOptions, soap.requests.closeSession(executionContext.shellId))
.then(function () {
myConsole.info('Close Shell SUCCESS %s', executionContext.shellId);
})
.catch(function (error) {
myConsole.error('Cannot close shell shellId: %s - %s', executionContext.shellId, error);
})
.then(function() {
return data;
});
}
return client
.executeRequest(commonOptions, soap.requests.startSession())
.then(function (shellId) {
myConsole.debug('Session SUCCESS - shellId: %s', shellId);
executionContext.shellId = shellId;
return client.executeRequest(commonOptions, soap.requests.executeCommand(command, shellId));
})
.then(function (data) {
myConsole.debug('Command SUCCESS - shellId: %s, commandId %s', data.shellId, data.commandId);
return client.executeRequest(commonOptions, soap.requests.getCommandOutput(data));
})
.then(waitForProcessFinish)
.catch(function (error) {
myConsole.error("Command FAILED - shellId: %s - error: %s", executionContext.shellId, JSON.stringify(error));
return client.executeRequest(commonOptions, soap.requests.closeSession(executionContext.shellId))
.then(function () {
myConsole.info('Close Shell SUCCESS %s', executionContext.shellId);
})
.catch(function (error) {
myConsole.error('Cannot close shell shellId: %s - %s', executionContext.shellId, error);
});
});
}
return {
executeCommand: executeCommand,
};
};