UNPKG

domotz-remote-pawn

Version:

Domotz Agent

158 lines (144 loc) 7.17 kB
/** 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;