domotz-remote-pawn
Version:
Domotz Agent
180 lines (162 loc) • 7.73 kB
JavaScript
/** This file is part of Domotz Agent.
* Copyright (C) 2016 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/>.
**/
/**
*
* Created by Massimiliano Cuzzoli <massi@domotz.com> on 05/10/16.
*
*/
const PROTOCOL_NAME = 'snmp';
const DISCOVERY_SEMAPHORE = 'SNMP_SEMAPHORE';
const OID_PORT_NUMBER = '1.3.6.1.2.1.2.1.0';
const snmpCommonDiscovery = require('./snmp_common');
var snmpDiscoveryFactory = function (resourceLocator, commandBuilder, responseRendering, snmpGetterFactory) {
'use strict';
var myConsole = resourceLocator.log.decorateLogs();
var snmpInterfacesNumberStorage = resourceLocator.snmpInterfacesNumberStorage;
var communitiesProvider = resourceLocator.snmpCommunitiesProvider;
var interfacesBinding = resourceLocator.interfacesBindingStorage;
var mutex = resourceLocator.utils.mutex;
var snmpDiscoverySnapshotData = {};
var snmpCommon = snmpCommonDiscovery.snmpCommonOptions();
var async = resourceLocator.async;
var host = resourceLocator.discovery.host;
var ipConflict = resourceLocator.networkTools.ipConflictDetection;
var snmpCheckStatus = resourceLocator.discovery.snmp_check_status_discovery;
var parallelLimit = resourceLocator.settingsManager.getSetting('configuration.settings.snmp.discovery.basic.parallel_limit', 30);
var deferredSnmpBulkGet = function (snmpCommand, host, options, mac, callback) {
var commandOptions = snmpCommon.getSnmpOptions(options);
myConsole.debug('Command Options are %s -> %s', mac, JSON.stringify(commandOptions));
var callbackCalled = false;
snmpGetterFactory(snmpCommand, resourceLocator).execute(function (result) {
myConsole.debug('Received result for %s -> %s', mac, JSON.stringify(result));
result.host = host;
result.mac = mac;
if (!callbackCalled) {
callbackCalled = true;
callback(null, result);
}
}, commandOptions);
};
var lockDiscovery = function () {
return mutex.lock(DISCOVERY_SEMAPHORE, 1);
};
var unlockDiscovery = function () {
mutex.unlock(DISCOVERY_SEMAPHORE, 1);
};
var renderSnmpResults = function (results) {
for (var i = 0; i < results.length; i++) {
var host = results[i].host;
var mac = results[i].mac;
var data = null;
try {
data = responseRendering(resourceLocator, results[i]);
} catch (e) {
data = undefined;
}
if (host === undefined || mac === undefined || data === null) {
myConsole.error('Something went wrong in rendering the SNMP result, skipping');
} else {
myConsole.debug('Parsed Result: %s - |%s|', mac, JSON.stringify(data));
if (!data.error) {
snmpDiscoverySnapshotData[mac] = data;
if (data.oids && data.oids[OID_PORT_NUMBER]) {
var number = parseInt(data.oids[OID_PORT_NUMBER], 10);
snmpInterfacesNumberStorage.store(mac, number);
}
}
}
}
};
var discover = function (callback, errCallback) {
if (!lockDiscovery()) {
myConsole.warn('WARNING: SNMP Discovery already in progress, ignoring the call');
return;
}
return communitiesProvider
.get()
.then(function (communities) {
var bulkGetList = [];
myConsole.debug('Found communities %s ', JSON.stringify(communities));
var oidsToDiscover = resourceLocator.settingsManager.getOidsToDiscover();
interfacesBinding.listFresh(true).forEach(function (device) {
/* Filter devices by removing the ones present in L3 Discovery Deny list */
if (!host.isDeviceMacInL3DiscoveryDenyList(device.mac)) {
if (!snmpCheckStatus.isSNMPEnabledForMacAddress(device.mac)) {
return;
}
var address = device.ip;
if (ipConflict.checkIfIpInConflict(address)) {
myConsole.warn('Skip SNMP basic discovery for conflicting IP: %s', address);
return;
}
var snmpCommand = commandBuilder.buildBulkGetCommand(oidsToDiscover, address);
myConsole.debug('Command for device %s [mac %s] %s ', device.ip, device.mac, JSON.stringify(snmpCommand));
myConsole.debug('Communities for device %s [mac %s] %s ', device.ip, device.mac, JSON.stringify(communities[device.mac]));
bulkGetList.push(deferredSnmpBulkGet.bind(null, snmpCommand, address, communities[device.mac], device.mac));
} else {
myConsole.debug('Skip SNMP Basic Discovery for device %s [mac %s] in L3 Discovery Deny List', device.ip, device.mac);
}
});
var startTime = new Date();
async.parallelLimit(bulkGetList, parallelLimit, function (error, result) {
renderSnmpResults(result);
var elapsed = (new Date() - startTime) / 1000;
myConsole.info('completed in %s s', elapsed);
unlockDiscovery();
if (callback) {
callback(snmpDiscoverySnapshotData);
}
});
})
.catch(function (err, err2) {
unlockDiscovery();
myConsole.error('Error on snmp information processing %s %s', err, err2);
if (errCallback) {
errCallback(err);
}
});
};
var applyFunctionToSnapshotEntries = function (functionToApply) {
myConsole.debug('post-processing: ' + JSON.stringify(snmpDiscoverySnapshotData));
for (var macAddress in snmpDiscoverySnapshotData) {
if (snmpDiscoverySnapshotData.hasOwnProperty(macAddress)) {
functionToApply(macAddress, snmpDiscoverySnapshotData[macAddress], PROTOCOL_NAME);
}
}
};
var searchEntryIntoSnapshot = function (deviceAddress) {
return snmpDiscoverySnapshotData[deviceAddress];
};
return {
discover: discover,
applyFunctionToSnapshotEntries: applyFunctionToSnapshotEntries,
searchEntryIntoSnapshot: searchEntryIntoSnapshot,
isDiscoveryInProgress: function () {
return mutex.isLocked(DISCOVERY_SEMAPHORE);
},
getProtocolName: function () {
return PROTOCOL_NAME;
},
getProtocolNameUpperCase: function () {
return PROTOCOL_NAME.toUpperCase();
},
getOidForInterfaceNumber: function () {
return OID_PORT_NUMBER;
},
};
};
module.exports.factory = snmpDiscoveryFactory;