domotz-remote-pawn
Version:
Domotz Agent
191 lines (168 loc) • 7.76 kB
JavaScript
/** 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 GETNEXT_HARD_TIMEOUT_SETTING = 'configuration.settings.snmp.hard_timeout.getNext';
var DEFAULT_GETNEXT_HARD_TIMEOUT_VALUE = 12000;
var GETNEXT_SOFT_TIMEOUT_SETTING = 'configuration.settings.snmp.soft_timeout.getNext';
var DEFAULT_GETNEXT_SOFT_TIMEOUT_VALUE = 5000;
var TimedSnmpSession = require('./timedSnmpSession');
var snmpNext = function (message, resourceLocator) {
var snmp = resourceLocator.netSnmp;
var cmdUtils = resourceLocator.utils.command;
var snmpCommon = resourceLocator.snmpCommon;
var async = resourceLocator.async;
var settingsManager = resourceLocator.settingsManager;
var myConsole = resourceLocator.log.decorateLogs();
var cid = message.correlationId;
var options = message.payload;
var host = cmdUtils.extractFromOptions(options, 'host', 'localhost');
var hardTimeout = parseInt(settingsManager.getSetting(GETNEXT_HARD_TIMEOUT_SETTING, DEFAULT_GETNEXT_HARD_TIMEOUT_VALUE));
var softTimeout = parseInt(settingsManager.getSetting(GETNEXT_SOFT_TIMEOUT_SETTING, DEFAULT_GETNEXT_SOFT_TIMEOUT_VALUE));
options.timeout = options.timeout || softTimeout;
myConsole.debug('Hard Timeout %s, Soft Timeout %s ', hardTimeout, options.timeout);
var oids = options.oids;
delete options.oids;
myConsole.debug('(%s): Start with oids: %s', cid, oids.toString());
function extractOidResponse(oidCheck, response) {
myConsole.debug('(%s) - (%s)(%s): Got response', host, cid, oidCheck);
if (!response || response.length === 0) {
return {};
}
var value = response[0];
var oid = value.oid;
var valid = false;
if (!snmp.isVarbindError(value)) {
if (oid.startsWith(oidCheck)) {
myConsole.verbose('(%s) - (%s): - MATCHING SNMP value retrieved (%s): %s', host, cid, oidCheck, oid);
valid = true;
} else {
myConsole.verbose('(%s) - (%s): - UN-MATCHING SNMP value retrieved (%s): %s', host, cid, oidCheck, oid);
}
} else {
myConsole.warn('(%s) - (%s): ERROR SNMP get - error retrieving oid: %s => varbind error: s', host, cid, oid, snmp.varbindError(value));
}
return {
valid: valid,
oid: oid,
oidRoot: oidCheck,
};
}
function setInvalid(oid) {
myConsole.debug('(%s): Set oid invalid', oid);
return {
valid: false,
oidRoot: oid,
};
}
return {
execute: function (callback, authProvider) {
myConsole.debug(
'SNMP_NEXT - (%s): Start executing SNMP next request to host %s for oids: %s, with options %s',
cid,
host,
JSON.stringify(oids),
JSON.stringify(options)
);
var f = function (options, resourceLocator, host, oid, cb) {
try {
var bindings = snmpCommon.getInterfaceBindings(options, resourceLocator);
var snmpSession = null;
try {
snmpSession = snmpCommon.getSession(bindings, host, options, authProvider);
} catch (error) {
callback({ error: error.toString() });
return;
}
var timedSnmpSession = new TimedSnmpSession(snmpSession, { host: host, oids: oids }, myConsole);
snmpSession.on('error', function (error) {
var errorMessage = error.toString();
myConsole.error('(socket error) %s', errorMessage);
try {
snmpSession.close();
} catch (error) {
myConsole.error('cannot close session: ' + error);
cb(null);
}
});
timedSnmpSession.getNext(
[oid],
function (error, response) {
if (error) {
if (response && response.error && response.error.stack) {
delete response.error.stack;
}
myConsole.debug('(%s) - (%s): ERROR in response: %s', host, cid, oid, error.toString());
cb(null, setInvalid(oid));
} else if (response !== null && response !== undefined) {
cb(null, extractOidResponse(oid, response));
} else {
myConsole.debug('(%s) - (%s)(%s): ERROR no response', host, cid, oid);
cb(null, setInvalid(oid));
}
try {
snmpSession.close();
} catch (error) {
myConsole.error('cannot close session: ' + error);
}
},
hardTimeout
);
} catch (e) {
cb(null);
}
};
var allFunctions = [];
var chunkSize = 1; // Most conservative choice, on each host doing all oids in series
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(f.bind(null, options, resourceLocator, host, oid));
}
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) {
callback([]);
} else {
var totalResult = [];
for (var i = 0; i < results.length; i++) {
totalResult = totalResult.concat(results[i]);
}
callback(totalResult);
}
});
},
describe: function () {
return cid + ' - SNMP_NEXT - ' + host + ' - ' + JSON.stringify(oids);
},
};
};
module.exports.command = snmpNext;