domotz-remote-pawn
Version:
Domotz Agent
158 lines (144 loc) • 7.17 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 18/10/16.
*/
const DISCOVERY_SEMAPHORE = 'SNMP_INTERFACE_SEMAPHORE';
const OIDS_TO_DISCOVER = {
'1.3.6.1.2.1.2.2.1.3': 'int', // ifType
'1.3.6.1.2.1.31.1.1.1.1': 'string', // ifName
'1.3.6.1.2.1.2.2.1.2': 'string', // ifDescription
'1.3.6.1.2.1.31.1.1.1.15': 'int', // ifHighSpeed
'1.3.6.1.2.1.31.1.1.1.18': 'string', // ifAlias
'1.3.6.1.2.1.2.2.1.7': 'int', // ifAdminStatus
'1.3.6.1.2.1.2.2.1.8': 'int', // ifOperationalStatus
'1.3.6.1.2.1.2.2.1.10': 'int', // ifInOctets
'1.3.6.1.2.1.2.2.1.16': 'int', // ifOutOctets
'1.3.6.1.2.1.2.2.1.13': 'int', // ifInDiscards
'1.3.6.1.2.1.2.2.1.19': 'int', // ifOutDiscards
'1.3.6.1.2.1.2.2.1.14': 'int', // ifInErrors
'1.3.6.1.2.1.2.2.1.20': 'int', // ifOutErrors
};
const snmpCommonDiscovery = require('./snmp_common');
var snmpDiscoveryFactory = function (resourceLocator, commandBuilder, responseRendering, snmpSubtreeFactory) {
'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 engineRequest = resourceLocator.engineRequest;
var snmpDiscoverySnapshotData = {};
var snmpCommon = snmpCommonDiscovery.snmpCommonOptions();
var interfaceTypesToRender = resourceLocator.settingsManager.getInterfaceDiscoveryTypesSettings();
var parallelLimit = resourceLocator.settingsManager.getSetting('configuration.settings.snmp.discovery.interface.parallel_limit', 30);
var async = resourceLocator.async;
var ipConflict = resourceLocator.networkTools.ipConflictDetection;
var deferredSnmpSubtree = function (snmpCommand, host, options, mac, callback) {
var commandOptions = snmpCommon.getSnmpOptions(options);
myConsole.debug('Command Options are %s -> %s', mac, JSON.stringify(commandOptions));
snmpSubtreeFactory(snmpCommand, resourceLocator).execute(function (result) {
myConsole.debug('Received result for %s', host);
result.host = host;
result.mac = mac;
result.timestamp = new Date().toISOString();
callback(null, result);
}, commandOptions);
};
var lockDiscovery = function () {
return mutex.lock(DISCOVERY_SEMAPHORE, 1);
};
var unlockDiscovery = function () {
mutex.unlock(DISCOVERY_SEMAPHORE, 1);
};
var renderDiscoveryData = function (rawResultList) {
for (var i = 0; i < rawResultList.length; i++) {
var dataToRender = rawResultList[i];
myConsole.debug('Rendering discovery data for %s', dataToRender.host);
if (snmpDiscoverySnapshotData[dataToRender.mac] === undefined) {
snmpDiscoverySnapshotData[dataToRender.mac] = responseRendering(dataToRender, interfaceTypesToRender);
}
}
};
var interfaceDiscovery = function (callback) {
if (!lockDiscovery()) {
myConsole.warn('Already in progress, ignoring the call');
return;
}
return communitiesProvider
.get()
.then(function (communities) {
var deferredResultList = [];
myConsole.debug('Found communities %s ', JSON.stringify(communities));
interfacesBinding.listFresh(true).forEach(function (device) {
if (ipConflict.checkIfIpInConflict(device.ip)) {
myConsole.warn('Skip SNMP interface discovery for conflicting IP: %s', device.ip);
return;
}
var interfaces = snmpInterfacesNumberStorage.fetch(device.mac);
myConsole.debug('Device %s has %s interfaces', device.mac, interfaces);
if (interfaces > 0) {
myConsole.debug('Communities for device [mac %s] %s ', device.mac, JSON.stringify(communities[device.mac]));
var snmpCommand = commandBuilder.buildSubtreeCommand(OIDS_TO_DISCOVER, device.ip);
deferredResultList.push(deferredSnmpSubtree.bind(null, snmpCommand, device.ip, communities[device.mac], device.mac));
}
});
var startTime = new Date();
async.parallelLimit(deferredResultList, parallelLimit, function (error, results) {
var elapsed = (new Date() - startTime) / 1000;
myConsole.info('completed in %s s', elapsed);
renderDiscoveryData(results);
unlockDiscovery();
if (callback) {
callback(snmpDiscoverySnapshotData);
}
});
})
.catch(function (err) {
unlockDiscovery();
myConsole.error('Error retrieving communities %s', err.toString());
});
};
var sendDiscoveryDataToEngine = function (discoveryData) {
myConsole.info('Number of records to send %d', Object.keys(discoveryData).length);
try {
var logError = function (e) {
myConsole.error('Error sending snmp data to Engine: %s', JSON.stringify(e));
};
for (var mac in discoveryData) {
if (discoveryData.hasOwnProperty(mac) && discoveryData[mac] && discoveryData[mac].oids) {
myConsole.info('Sending data for device MAC=%s', mac);
engineRequest.sendWithPromise('/subnet/ip/device/' + mac + '/interface/snmp-info', 'PUT', discoveryData[mac]).catch(logError);
}
}
snmpDiscoverySnapshotData = {};
} catch (e) {
myConsole.error('Error preparing data to send %s', JSON.stringify(e));
}
};
return {
interfaceDiscovery: interfaceDiscovery,
sendDiscoveryDataToEngine: sendDiscoveryDataToEngine,
isDiscoveryInProgress: function () {
return mutex.isLocked(DISCOVERY_SEMAPHORE);
},
getCurrentSnapshotData: function () {
return snmpDiscoverySnapshotData;
},
};
};
module.exports.factory = snmpDiscoveryFactory;