Structure and file for the SNMP client

This commit is contained in:
Nicolargo 2014-05-02 10:00:10 +02:00
parent 037ec87c53
commit 879ec5eb58
3 changed files with 195 additions and 10 deletions

View File

@ -45,6 +45,9 @@ class GlancesClient():
self.args = args self.args = args
self.config = config self.config = config
# Client mode:
self.set_mode()
# Build the URI # Build the URI
if args.password != "": if args.password != "":
uri = 'http://%s:%s@%s:%d' % (args.username, args.password, args.bind_address, args.port) uri = 'http://%s:%s@%s:%d' % (args.username, args.password, args.bind_address, args.port)
@ -58,24 +61,46 @@ class GlancesClient():
print(_("Error: Couldn't create socket {0}: {1}").format(uri, err)) print(_("Error: Couldn't create socket {0}: {1}").format(uri, err))
sys.exit(2) sys.exit(2)
def set_mode(self, mode='glances'):
"""
Set the client mode
- 'glances' = Glances server (default)
- 'snmp' = SNMP (fallback)
"""
self.mode = mode
return self.mode
def get_mode(self):
"""
Return the client mode
- 'glances' = Glances server (default)
- 'snmp' = SNMP (fallback)
"""
return self.mode
def login(self): def login(self):
""" """
Logon to the server Logon to the server
""" """
ret = True
# First of all, trying to connect to a Glances server
try: try:
client_version = self.client.init() client_version = self.client.init()
except socket.error as err: except socket.error as err:
print(_("Error: Connection to server failed: {0}").format(err)) print(_("Error: Connection to {0} server failed").format(self.get_mode()))
sys.exit(2) # Fallback to SNMP
self.set_mode('snmp')
except ProtocolError as err: except ProtocolError as err:
# Others errors
if str(err).find(" 401 ") > 0: if str(err).find(" 401 ") > 0:
print(_("Error: Connection to server failed: Bad password")) print(_("Error: Connection to server failed: Bad password"))
else: else:
print(_("Error: Connection to server failed: {0}").format(err)) print(_("Error: Connection to server failed: {0}").format(err))
sys.exit(2) sys.exit(2)
# Test if client and server are "compatible" if self.get_mode() == 'glances' and __version__[:3] == client_version[:3]:
if __version__[:3] == client_version[:3]:
# Init stats # Init stats
self.stats = GlancesStatsClient() self.stats = GlancesStatsClient()
self.stats.set_plugins(json.loads(self.client.getAllPlugins())) self.stats.set_plugins(json.loads(self.client.getAllPlugins()))
@ -86,12 +111,43 @@ class GlancesClient():
# Init screen # Init screen
self.screen = glancesCurses(args=self.args) self.screen = glancesCurses(args=self.args)
# Debug ret = True
# print "Server version: {0}\nClient version: {1}\n".format(__version__, client_version)
return True
else: else:
return False ret = False
# Then fallback to SNMP if needed
if self.get_mode() == 'snmp':
from glances.core.glances_snmp import GlancesSNMPClient
# Test if SNMP is available on the server side
clientsnmp = GlancesSNMPClient()
try:
# !!! Simple request with system name
# !!! Had to have a standard method to check SNMP server
clientsnmp.get_by_oid("1.3.6.1.2.1.1.5.0")
except:
print(_("Error: Connection to {0} server failed").format(self.get_mode()))
sys.exit(2)
from glances.core.glances_stats import GlancesStatsClientSNMP
print(_("Fallback to {0}").format(self.get_mode()))
# Init stats
self.stats = GlancesStatsClientSNMP()
# Load limits from the configuration file
# Each client can choose its owns limits
self.stats.load_limits(self.config)
# Init screen
self.screen = glancesCurses(args=self.args)
return True
# Return result
return ret
def update(self): def update(self):
""" """
@ -101,6 +157,22 @@ class GlancesClient():
- Disconnected: Connection NOK - Disconnected: Connection NOK
""" """
# Update the stats # Update the stats
if self.get_mode() == 'glances':
return self.update_glances()
elif self.get_mode() == 'snmp':
return self.update_snmp()
else:
print(_("Error: Unknown server mode ({0})").format(self.get_mode()))
sys.exit(2)
def update_glances(self):
"""
Get stats from Glances server
Return the client/server connection status:
- Connected: Connection OK
- Disconnected: Connection NOK
"""
# Update the stats
try: try:
server_stats = json.loads(self.client.getAll()) server_stats = json.loads(self.client.getAll())
server_stats['monitor'] = json.loads(self.client.getAllMonitored()) server_stats['monitor'] = json.loads(self.client.getAllMonitored())
@ -112,6 +184,23 @@ class GlancesClient():
self.stats.update(server_stats) self.stats.update(server_stats)
return "Connected" return "Connected"
def update_snmp(self):
"""
Get stats from SNMP server
Return the client/server connection status:
- Connected: Connection OK
- Disconnected: Connection NOK
"""
# Update the stats
try:
self.stats.update()
except socket.error as e:
# Client can not get SNMP server stats
return "Disconnected"
else:
# Grab success
return "Connected"
def serve_forever(self): def serve_forever(self):
""" """
Main client loop Main client loop
@ -122,9 +211,12 @@ class GlancesClient():
# Update the screen # Update the screen
self.screen.update(self.stats, cs_status=cs_status) self.screen.update(self.stats, cs_status=cs_status)
# print self.stats
# print self.stats.getAll()
def end(self): def end(self):
""" """
End of the client session End of the client session
""" """
self.screen.end() self.screen.end()

View File

@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
#
# This file is part of Glances.
#
# Copyright (C) 2014 Nicolargo <nicolas@nicolargo.com>
#
# Glances is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Glances 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
try:
from pysnmp.entity.rfc3413.oneliner import cmdgen
except ImportError, e:
print("Error importing PySNMP lib: %s" % e)
print("Install using pip: # pip install pysnmp")
sys.exit(2)
class GlancesSNMPClient(object):
""" SNMP client class (based on PySNMP) """
def __init__(self, host = "localhost",
port = 161,
community = "public",
version = "SNMPv2-MIB"):
super(GlancesSNMPClient, self).__init__()
self.cmdGen = cmdgen.CommandGenerator()
self.host = host
self.port = port
self.community = community
self.version = version
def __result__(self, errorIndication, errorStatus, errorIndex, varBinds):
ret = {}
if not (errorIndication or errorStatus):
for name, val in varBinds:
ret[name.prettyPrint()] = val.prettyPrint()
return ret
def get_by_oid(self, *oid):
errorIndication, errorStatus, errorIndex, varBinds = self.cmdGen.getCmd(
cmdgen.CommunityData(self.community),
cmdgen.UdpTransportTarget((self.host, self.port)),
*oid
)
return self.__result__(errorIndication, errorStatus, errorIndex, varBinds)

View File

@ -87,6 +87,12 @@ class GlancesStats(object):
plugname = os.path.basename(plug)[len(header):-3].lower() plugname = os.path.basename(plug)[len(header):-3].lower()
self._plugins[plugname] = m.Plugin() self._plugins[plugname] = m.Plugin()
def getAllPlugins(self):
"""
Return the plugins list
"""
return [p for p in self._plugins]
def load_limits(self, config=None): def load_limits(self, config=None):
""" """
Load the stats limits Load the stats limits
@ -109,7 +115,7 @@ class GlancesStats(object):
# print "DEBUG: Update %s stats" % p # print "DEBUG: Update %s stats" % p
self._plugins[p].update() self._plugins[p].update()
else: else:
# For client mode # For Glances client mode
# Update plugin stats with items sent by the server # Update plugin stats with items sent by the server
for p in input_stats: for p in input_stats:
self._plugins[p].set_stats(input_stats[p]) self._plugins[p].set_stats(input_stats[p])
@ -118,6 +124,12 @@ class GlancesStats(object):
# Update the stats # Update the stats
self.__update__(input_stats) self.__update__(input_stats)
def getAll(self):
"""
Return all the stats
"""
return [ self._plugins[p].get_raw() for p in self._plugins ]
def get_plugin_list(self): def get_plugin_list(self):
# Return the plugin list # Return the plugin list
self._plugins self._plugins
@ -202,3 +214,27 @@ class GlancesStatsClient(GlancesStats):
# generate self._plugins_list["xxx"] = ... # generate self._plugins_list["xxx"] = ...
# print "DEBUG: Init %s plugin" % plug # print "DEBUG: Init %s plugin" % plug
self._plugins[plug] = m.Plugin() self._plugins[plug] = m.Plugin()
class GlancesStatsClientSNMP(GlancesStats):
"""
This class store, update and give stats for the SNMP client
"""
def __init__(self):
# Init the plugin list dict
self._plugins = collections.defaultdict(dict)
# Load plugins
self.load_plugins()
def update(self):
"""
Update the stats using SNMP
"""
# For each plugins, call the update method
for p in self._plugins:
# print "DEBUG: Update %s stats using SNMP request" % p
self._plugins[p].update()