mirror of
https://github.com/nicolargo/glances.git
synced 2024-12-01 22:14:06 +03:00
SNMP client: SNMP grab for network interface is optimized with a SNMP bulk command :)
This commit is contained in:
parent
58e95d6ed3
commit
05e31d19ea
@ -48,7 +48,7 @@ class GlancesSNMPClient(object):
|
||||
self.user = user
|
||||
self.auth = auth
|
||||
|
||||
def __result__(self, errorIndication, errorStatus, errorIndex, varBinds):
|
||||
def __get_result__(self, errorIndication, errorStatus, errorIndex, varBinds):
|
||||
"""
|
||||
Put results in table
|
||||
"""
|
||||
@ -64,7 +64,10 @@ class GlancesSNMPClient(object):
|
||||
|
||||
def get_by_oid(self, *oid):
|
||||
"""
|
||||
Process to an SNMP request (list of OID)
|
||||
SNMP simple request (list of OID)
|
||||
One request per OID list
|
||||
* oid: oid list
|
||||
> Return a dict
|
||||
"""
|
||||
|
||||
if (self.version == '3'):
|
||||
@ -79,4 +82,49 @@ class GlancesSNMPClient(object):
|
||||
cmdgen.UdpTransportTarget((self.host, self.port)),
|
||||
*oid
|
||||
)
|
||||
return self.__result__(errorIndication, errorStatus, errorIndex, varBinds)
|
||||
return self.__get_result__(errorIndication, errorStatus, errorIndex, varBinds)
|
||||
|
||||
def __bulk_result__(self, errorIndication, errorStatus, errorIndex, varBindTable):
|
||||
ret = []
|
||||
if not (errorIndication or errorStatus):
|
||||
for varBindTableRow in varBindTable:
|
||||
item = {}
|
||||
for name, val in varBindTableRow:
|
||||
if (str(val) == ''):
|
||||
item[name.prettyPrint()] = ''
|
||||
else:
|
||||
item[name.prettyPrint()] = val.prettyPrint()
|
||||
ret.append(item)
|
||||
return ret
|
||||
|
||||
def getbulk_by_oid(self, non_repeaters, max_repetitions, *oid):
|
||||
"""
|
||||
SNMP getbulk request
|
||||
In contrast to snmpwalk, this information will typically be gathered in a
|
||||
single transaction with the agent, rather than one transaction per variable found.
|
||||
* non_repeaters: This specifies the number of supplied variables that should not be iterated over.
|
||||
* max_repetitions: This specifies the maximum number of iterations over the repeating variables.
|
||||
* oid: oid list
|
||||
> Return a list of dicts
|
||||
"""
|
||||
|
||||
if self.version.startswith('3'):
|
||||
errorIndication, errorStatus, errorIndex, varBinds = self.cmdGen.getCmd(
|
||||
cmdgen.UsmUserData(self.user, self.auth),
|
||||
cmdgen.UdpTransportTarget((self.host, self.port)),
|
||||
non_repeaters,
|
||||
max_repetitions,
|
||||
*oid
|
||||
)
|
||||
if self.version.startswith('2'):
|
||||
errorIndication, errorStatus, errorIndex, varBindTable = self.cmdGen.bulkCmd(
|
||||
cmdgen.CommunityData(self.community),
|
||||
cmdgen.UdpTransportTarget((self.host, self.port)),
|
||||
non_repeaters,
|
||||
max_repetitions,
|
||||
*oid
|
||||
)
|
||||
else:
|
||||
# Bulk request are not available with SNMP version 1
|
||||
return []
|
||||
return self.__bulk_result__(errorIndication, errorStatus, errorIndex, varBindTable)
|
||||
|
@ -263,6 +263,6 @@ class GlancesStatsClientSNMP(GlancesStats):
|
||||
try:
|
||||
self._plugins[p].update(input='snmp')
|
||||
except Exception as e:
|
||||
# print "ERROR: Update %s failed (%s)" % (p, e)
|
||||
pass
|
||||
print "ERROR: Update %s failed (%s)" % (p, e)
|
||||
# pass
|
||||
|
||||
|
@ -29,11 +29,10 @@ from glances.plugins.glances_plugin import GlancesPlugin
|
||||
|
||||
# SNMP OID
|
||||
# http://www.net-snmp.org/docs/mibs/interfaces.html
|
||||
ifNumber_oid = { 'ifNumber': '1.3.6.1.2.1.2.1.0' }
|
||||
ifIndex_oid = { 'ifIndex': '1.3.6.1.2.1.2.2.1.1.' }
|
||||
snmp_oid = { 'interface_name': '1.3.6.1.2.1.2.2.1.2.',
|
||||
'cumulative_rx': '1.3.6.1.2.1.2.2.1.10.',
|
||||
'cumulative_tx': '1.3.6.1.2.1.2.2.1.16.' }
|
||||
# Dict key = interface_name
|
||||
snmp_oid = { 'interface_name': '1.3.6.1.2.1.2.2.1.2',
|
||||
'cumulative_rx': '1.3.6.1.2.1.2.2.1.10',
|
||||
'cumulative_tx': '1.3.6.1.2.1.2.2.1.16' }
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
@ -123,56 +122,53 @@ class Plugin(GlancesPlugin):
|
||||
|
||||
elif input == 'snmp':
|
||||
# Update stats using SNMP
|
||||
# !!! High CPU consumption on the client side
|
||||
# !!! To be optimized with getbulk
|
||||
|
||||
time_since_update = getTimeSinceLastUpdate('net')
|
||||
|
||||
# Get number of network interfaces
|
||||
try:
|
||||
# IfNumber is available directly
|
||||
ifNumber = int(self.set_stats_snmp(snmp_oid=ifNumber_oid)['ifNumber']) + 1
|
||||
except:
|
||||
# Or not...
|
||||
# Walk through ifIndex
|
||||
ifNumber = 1
|
||||
while self.set_stats_snmp(snmp_oid={'ifIndex': ifIndex_oid['ifIndex'] + str(ifNumber)})['ifIndex'] != '':
|
||||
ifNumber += 1
|
||||
# SNMP bulk command to get all network interface in one shot
|
||||
netiocounters = self.set_stats_snmp(snmp_oid=snmp_oid, bulk=True)
|
||||
|
||||
# Loop over network interfaces
|
||||
network_new = {}
|
||||
ifIndex = 1
|
||||
ifCpt = 1
|
||||
while (ifCpt < ifNumber) and (ifIndex < 1024):
|
||||
# Add interface index to netif OID
|
||||
net_oid = dict((k, v + str(ifIndex)) for (k, v) in snmp_oid.items())
|
||||
net_stat = self.set_stats_snmp(snmp_oid=net_oid)
|
||||
if str(net_stat['interface_name']) == '':
|
||||
ifIndex += 1
|
||||
continue
|
||||
else:
|
||||
ifCpt += 1
|
||||
network_new[ifIndex] = net_stat
|
||||
if hasattr(self, 'network_old'):
|
||||
net_stat['time_since_update'] = time_since_update
|
||||
net_stat['rx'] = (float(network_new[ifIndex]['cumulative_rx']) -
|
||||
float(self.network_old[ifIndex]['cumulative_rx']))
|
||||
net_stat['tx'] = (float(network_new[ifIndex]['cumulative_tx']) -
|
||||
float(self.network_old[ifIndex]['cumulative_tx']))
|
||||
net_stat['cumulative_cx'] = (float(net_stat['cumulative_rx']) +
|
||||
float(net_stat['cumulative_tx']))
|
||||
net_stat['cx'] = net_stat['rx'] + net_stat['tx']
|
||||
self.stats.append(net_stat)
|
||||
ifIndex += 1
|
||||
|
||||
# Save stats to compute next bitrate
|
||||
self.network_old = network_new
|
||||
# Previous network interface stats are stored in the network_old variable
|
||||
if not hasattr(self, 'network_old'):
|
||||
# First call, we init the network_old var
|
||||
try:
|
||||
self.network_old = netiocounters
|
||||
except (IOError, UnboundLocalError):
|
||||
pass
|
||||
else:
|
||||
# See description in the 'local' block
|
||||
time_since_update = getTimeSinceLastUpdate('net')
|
||||
|
||||
# Loop over interfaces
|
||||
network_new = netiocounters
|
||||
|
||||
for net in network_new:
|
||||
try:
|
||||
# Try necessary to manage dynamic network interface
|
||||
netstat = {}
|
||||
netstat['interface_name'] = net
|
||||
netstat['time_since_update'] = time_since_update
|
||||
netstat['cumulative_rx'] = float(network_new[net]['cumulative_rx'])
|
||||
netstat['rx'] = (float(network_new[net]['cumulative_rx']) -
|
||||
float(self.network_old[net]['cumulative_rx']))
|
||||
netstat['cumulative_tx'] = float(network_new[net]['cumulative_tx'])
|
||||
netstat['tx'] = (float(network_new[net]['cumulative_tx']) -
|
||||
float(self.network_old[net]['cumulative_tx']))
|
||||
netstat['cumulative_cx'] = (netstat['cumulative_rx'] +
|
||||
netstat['cumulative_tx'])
|
||||
netstat['cx'] = netstat['rx'] + netstat['tx']
|
||||
except KeyError:
|
||||
continue
|
||||
else:
|
||||
self.stats.append(netstat)
|
||||
|
||||
# Save stats to compute next bitrate
|
||||
self.network_old = network_new
|
||||
|
||||
return self.stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""
|
||||
Return the dict to display in the curse interface
|
||||
Return the dict to displayoid in the curse interface
|
||||
"""
|
||||
|
||||
#!!! TODO: Add alert on network interface bitrate
|
||||
|
@ -59,10 +59,9 @@ class GlancesPlugin(object):
|
||||
self.stats = input_stats
|
||||
return self.stats
|
||||
|
||||
def set_stats_snmp(self, snmp_oid={}):
|
||||
def set_stats_snmp(self, bulk=False, snmp_oid={}):
|
||||
# Update stats using SNMP
|
||||
# TODO: optimisation with bulk command:
|
||||
# http://pysnmp.sourceforge.net/examples/4.x/v3arch/oneliner/manager/bulkgen.html
|
||||
# If bulk=True, use a bulk request instead of a get request
|
||||
from glances.core.glances_snmp import GlancesSNMPClient
|
||||
|
||||
# Init the SNMP request
|
||||
@ -72,12 +71,34 @@ class GlancesPlugin(object):
|
||||
community=self.args.snmp_community)
|
||||
|
||||
# Process the SNMP request
|
||||
snmpresult = clientsnmp.get_by_oid(*snmp_oid.values())
|
||||
|
||||
# Build the internal dict with the SNMP result
|
||||
ret = {}
|
||||
for key in snmp_oid.iterkeys():
|
||||
ret[key] = snmpresult[snmp_oid[key]]
|
||||
if bulk:
|
||||
# Bulk request
|
||||
snmpresult = clientsnmp.getbulk_by_oid(0, 10, *snmp_oid.values())
|
||||
|
||||
# Build the internal dict with the SNMP result
|
||||
# key is the first item in the snmp_oid
|
||||
index = 1
|
||||
for item in snmpresult:
|
||||
item_stats = {}
|
||||
item_key = None
|
||||
for key in snmp_oid.iterkeys():
|
||||
oid = snmp_oid[key] + '.' + str(index)
|
||||
if oid in item:
|
||||
if item_key is None:
|
||||
item_key = item[oid]
|
||||
else:
|
||||
item_stats[key] = item[oid]
|
||||
if item_stats != {}:
|
||||
ret[item_key] = item_stats
|
||||
index += 1
|
||||
else:
|
||||
# Simple get request
|
||||
snmpresult = clientsnmp.get_by_oid(*snmp_oid.values())
|
||||
|
||||
# Build the internal dict with the SNMP result
|
||||
for key in snmp_oid.iterkeys():
|
||||
ret[key] = snmpresult[snmp_oid[key]]
|
||||
|
||||
return ret
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user