UNPKG

domotz-remote-pawn

Version:

Domotz Agent

214 lines (188 loc) 9.2 kB
/** This file is part of Domotz Agent. * Copyright (C) 2020 Domotz UK LLP * * 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/>. **/ var GET_HARD_TIMEOUT_SETTING = 'configuration.settings.snmp.hard_timeout.get'; var DEFAULT_GET_HARD_TIMEOUT_VALUE = 12000; // more than DEFAULT_GET_SOFT_TIMEOUT_VALUE * 2 due to default retries = 1 var GET_SOFT_TIMEOUT_SETTING = 'configuration.settings.snmp.soft_timeout.get'; var DEFAULT_GET_SOFT_TIMEOUT_VALUE = 5000; var TimedSnmpSession = require('./timedSnmpSession'); var snmpGetChunked = function (message, resourceLocator) { var snmp = resourceLocator.netSnmp; var cmdUtils = resourceLocator.utils.command; var snmpCommon = resourceLocator.snmpCommon; var async = resourceLocator.async; var commandBuilder = resourceLocator.snmpCommandBuilder; var snmpCommonTransformer = resourceLocator.snmpCommon; var settingsManager = resourceLocator.settingsManager; var chunkSize = settingsManager.getSetting('configuration.settings.snmp.get_chunked.chunk_size', 1); var cid = message.correlationId; var myConsole = resourceLocator.log.decorateLogs().decorate(String(cid)); myConsole.info('Init (message %s)', JSON.stringify(message)); var options = message.payload; var oidsMapping = cmdUtils.extractFromOptions(options, 'oids', {}); var host = cmdUtils.extractFromOptions(options, 'host', 'localhost'); var oids = snmpCommon.extractOids(oidsMapping); var transformer = message.customTransformer ? message.customTransformer : snmpCommon.transformer; var hardTimeout = parseInt(settingsManager.getSetting(GET_HARD_TIMEOUT_SETTING, DEFAULT_GET_HARD_TIMEOUT_VALUE)); var softTimeout = parseInt(settingsManager.getSetting(GET_SOFT_TIMEOUT_SETTING, DEFAULT_GET_SOFT_TIMEOUT_VALUE)); options.timeout = options.timeout || softTimeout; myConsole.debug('Hard Timeout %s, Soft Timeout %s ', hardTimeout, options.timeout); function extractOidResponse(mainOid, response) { myConsole.debug('Got response: %s', JSON.stringify(response)); var values = {}; for (var i = 0; i < response.length; i++) { var oid = response[i].oid; if (!snmp.isVarbindError(response[i])) { var value = transformer(oidsMapping[oid])(response[i].value, response[i].type); myConsole.verbose('SNMP value retrieved: %s=%s', oid, value); values[oid] = value; } else { myConsole.warn('SNMP get - error retrieving oid: %s => varbind error: %s', oid, snmp.varbindError(response[i])); } } myConsole.verbose('Partial value (host %s) (values %s)', host, JSON.stringify(values)); return values; } var executeGet = function (host, oid, authProvider, cb) { var bindings = snmpCommon.getInterfaceBindings(options, resourceLocator); var snmpSession = null; try { snmpSession = snmpCommon.getSession(bindings, host, options, authProvider); } catch (error) { cb({ error: error.toString() }); return; } myConsole.info('Sending SNMP GET (snmp-version %d) (host %s) (oid %s)', snmpSession.version, host, JSON.stringify(oid)); var callbackHasBeenCalled = false; function _cb(error, result) { if (!callbackHasBeenCalled) { callbackHasBeenCalled = true; cb(error, result); } else { myConsole.debug('Ignoring async callback if called again'); } } snmpSession.on('error', function (error) { var errorMessage = error.toString(); myConsole.error('socket error %s', errorMessage); if (error.name === 'RangeError') { myConsole.error('RangeError Detected, falling back to getNative (socket error) %s', errorMessage); var oidToSend = {}; oidToSend[oid] = oidsMapping[oid]; var snmpCommand = commandBuilder.buildBulkGetCommand(oidToSend, host, options.timeout); snmpCommand.customTransformer = snmpCommonTransformer.transformerTypeInvariant; myConsole.info('Using the getNative (command %s)', JSON.stringify(snmpCommand)); var getNative = resourceLocator.snmpGetNative(JSON.parse(JSON.stringify(snmpCommand)), resourceLocator); var parserGetNative = function (rawResult) { myConsole.info('getNative received result (values %s)', JSON.stringify(rawResult)); if (rawResult.oids !== undefined) { _cb(null, rawResult.oids); } else { _cb(null, {}); } try { snmpSession.close(); } catch (error) { myConsole.error('Cannot close session: ' + error); } }; getNative.execute(parserGetNative); } else { try { snmpSession.close(); } catch (error) { myConsole.error('Cannot close session: ' + error); } finally { _cb(null, {}); } } }); var timedSnmpSession = new TimedSnmpSession(snmpSession, { host: host, oids: oids }, myConsole); timedSnmpSession.get( [oid], function (error, response) { if (error) { myConsole.info('(%s) - (%s)(%s): ERROR in response: %s', host, cid, oid, error.toString()); _cb(null, {}); } else if (response !== null && response !== undefined) { _cb(null, extractOidResponse(oid, response)); } else { myConsole.info('(%s): Set oid invalid', oid); _cb(null, {}); } try { snmpSession.close(); } catch (error) { myConsole.error('cannot close session: ' + error); } }, hardTimeout ); }; return { execute: function (callback, authProvider) { var allFunctions = []; var chunks = []; for (var i = 0; i < oids.length; i += chunkSize) { chunks.push(oids.slice(i, i + chunkSize)); } chunks.forEach(function (tempOIDs) { var fChunk = function (cb) { var functions = []; for (var z = 0; z < tempOIDs.length; z++) { var oid = tempOIDs[z]; functions.push(executeGet.bind(null, host, oid, authProvider)); } async.parallel(functions, function (err, results) { if (err !== null) { // This should not happen cb(err, results); } else { cb(null, results); } }); }; allFunctions.push(fChunk); }); async.series(allFunctions, function (err, results) { if (err !== null) { myConsole.info('Final Result (host %s) error', host); callback({ error: 'Cant retrieve oids' }); } else { var totalResult = {}; for (var i = 0; i < results.length; i++) { for (var j = 0; j < results[i].length; j++) { myConsole.verbose('Checking values (host %s) (values %s)', host, JSON.stringify(results[i][j])); Object.assign(totalResult, results[i][j]); } } myConsole.info('Final Result (host %s) (result %s)', host, JSON.stringify(totalResult)); if (Object.keys(totalResult).length === 0) { callback({ error: 'Nothing retrieved' }); } else { callback({ oids: totalResult }); } } }); }, describe: function () { return cid + ' - snmpGetChunked - ' + host + ' - ' + JSON.stringify(oids); }, // Testing only _executeGet: executeGet, }; }; module.exports.command = snmpGetChunked;