Init plugins structure

This commit is contained in:
Nicolas Hennion 2014-01-18 23:01:57 +01:00
parent 36e91f1686
commit 8da175d5fa
11 changed files with 1114 additions and 47 deletions

View File

@ -9,17 +9,19 @@ __init__.py Global module init
__main__.py Entry point for module
core/
glances_core.py Main script to rule them up...
glances_globals.py Share variables uppon modules
glances_config.py Manage configuration file
glances_timer.py Manage timer
glances_stats.py Inteface to grab stats
glances_client.py Glances client
glances_config.py Script to manage configuration file
glances_server.py Glances_server
plugins/
glances_plugins.py Main class for others plugins
glances_cpu.py Grab CPU stats
glances_load.py Grab LOAD stats
glances_mem.py Grab MEM (both RAM and SWAP) stats
glances_plugins.py "Father class" for others plugins
glances_cpu.py Manage CPU stats
glances_load.py Manage LOAD stats
glances_mem.py Manage MEM (both RAM and SWAP) stats
...
outputs/
glances_api.py The API interface
glances_curse.py The Curse (console) interface
glances_csv.py The CSV interface
glances_html.py The HTML interface

View File

@ -21,5 +21,41 @@
from .core.glances_core import GlancesCore
def main(argv=None):
glances_instance = GlancesCore()
glances_instance.start()
# Create the Glances core instance
core = GlancesCore()
# Glances can be ran in standalone, client or server mode
if (core.is_standalone()):
# !!!
print "Standalone mode"
elif (core.is_client()):
# !!!
print "Client mode"
elif (core.is_server()):
# Import the Glances server module
from .core.glances_server import GlancesServer
# Init the server
server = GlancesServer(bind_address=core.bind_ip,
bind_port=int(core.server_port),
cached_time=core.cached_time)
print(_("Glances server is running on") + " %s:%s" % (core.bind_ip, core.server_port))
# Set the server login/password (if -P/--password tag)
if (core.password != ""):
server.add_user(core.username, core.password)
# Init stats
# !!! Uncomment
# stats = GlancesStatsServer()
# stats.update({})
# Shutdown the server
# !!! How to close the server with CTRL-C
# !!! Call core.end() with parameters ?
server.server_close()

View File

@ -0,0 +1,143 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Glances - An eye on your system
#
# 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/>.
__appname__ = 'glances'
from ..core.glances_globals import *
# Import system libs
import os
try:
# Python 2
from ConfigParser import RawConfigParser
from ConfigParser import NoOptionError
except ImportError:
# Python 3
from configparser import RawConfigParser
from configparser import NoOptionError
class Config:
"""
This class is used to access/read config file, if it exists
:param location: the custom path to search for config file
:type location: str or None
"""
def __init__(self, location=None):
self.location = location
self.filename = 'glances.conf'
self.parser = RawConfigParser()
self.load()
def load(self):
"""
Load a config file from the list of paths, if it exists
"""
for path in self.get_paths_list():
if (os.path.isfile(path) and os.path.getsize(path) > 0):
try:
if (sys.version_info >= (3, 2)):
self.parser.read(path, encoding='utf-8')
else:
self.parser.read(path)
except UnicodeDecodeError as e:
print(_("Error decoding config file '%s': %s") % (path, e))
sys.exit(1)
break
def get_paths_list(self):
"""
Get a list of config file paths, taking into account of the OS,
priority and location.
* running from source: /path/to/glances/conf
* Linux: ~/.config/glances, /etc/glances
* BSD: ~/.config/glances, /usr/local/etc/glances
* Mac: ~/Library/Application Support/glances, /usr/local/etc/glances
* Windows: %APPDATA%\glances
The config file will be searched in the following order of priority:
* /path/to/file (via -C flag)
* /path/to/glances/conf
* user's home directory (per-user settings)
* {/usr/local,}/etc directory (system-wide settings)
"""
paths = []
conf_path = os.path.realpath(os.path.join(work_path, '..', 'conf'))
if self.location is not None:
paths.append(self.location)
if os.path.exists(conf_path):
paths.append(os.path.join(conf_path, self.filename))
if is_Linux or is_BSD:
paths.append(os.path.join(
os.environ.get('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'),
__appname__, self.filename))
elif is_Mac:
paths.append(os.path.join(
os.path.expanduser('~/Library/Application Support/'),
__appname__, self.filename))
elif is_Windows:
paths.append(os.path.join(
os.environ.get('APPDATA'), __appname__, self.filename))
if is_Linux:
paths.append(os.path.join('/etc', __appname__, self.filename))
elif is_BSD:
paths.append(os.path.join(
sys.prefix, 'etc', __appname__, self.filename))
elif is_Mac:
paths.append(os.path.join(
sys_prefix, 'etc', __appname__, self.filename))
return paths
def has_section(self, section):
"""
Return info about the existence of a section
"""
return self.parser.has_section(section)
def get_option(self, section, option):
"""
Get the float value of an option, if it exists
"""
try:
value = self.parser.getfloat(section, option)
except NoOptionError:
return
else:
return value
def get_raw_option(self, section, option):
"""
Get the raw value of an option, if it exists
"""
try:
value = self.parser.get(section, option)
except NoOptionError:
return
else:
return value

View File

@ -18,42 +18,26 @@
# 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/>.
# Glances informations
__appname__ = 'glances'
__version__ = "2.0_Alpha"
__author__ = "Nicolas Hennion <nicolas@nicolargo.com>"
__license__ = "LGPL"
# Import system libs
import sys
import os
import gettext
import locale
import signal
import argparse
# path definitions
work_path = os.path.realpath(os.path.dirname(__file__))
appname_path = os.path.split(sys.argv[0])[0]
sys_prefix = os.path.realpath(os.path.dirname(appname_path))
# i18n
locale.setlocale(locale.LC_ALL, '')
gettext_domain = __appname__
# get locale directory
i18n_path = os.path.realpath(os.path.join(work_path, '..', 'i18n'))
sys_i18n_path = os.path.join(sys_prefix, 'share', 'locale')
if os.path.exists(i18n_path):
locale_dir = i18n_path
elif os.path.exists(sys_i18n_path):
locale_dir = sys_i18n_path
else:
locale_dir = None
gettext.install(gettext_domain, locale_dir)
# Operating system flag
# Note: Somes libs depends of OS
is_BSD = sys.platform.find('bsd') != -1
is_Linux = sys.platform.startswith('linux')
is_Mac = sys.platform.startswith('darwin')
is_Windows = sys.platform.startswith('win')
# Import Glances libs
# !!! Todo: rename class
# GlancesExemple
from ..core.glances_globals import *
from ..core.glances_config import Config
from ..core.glances_limits import glancesLimits
from ..core.glances_monitor_list import monitorList
from ..core.glances_stats import GlancesStats, GlancesStatsServer
# Import PSUtil
# !!! Is it mandatory for client ?
@ -125,6 +109,7 @@ class GlancesCore(object):
# Default stats' refresh time is 3 seconds
refresh_time = 3
# Set the default cache lifetime to 1 second (only for server)
# !!! Todo: configuration from the command line
cached_time = 1
# Default network bitrate is display in bit per second
network_bytepersec_tag = False
@ -160,16 +145,74 @@ class GlancesCore(object):
def __init__(self):
self.parser = argparse.ArgumentParser(
prog=__appname__,
description='Glances, an eye on your system.')
# Init and manage command line arguments
self.init_arg()
self.parse_arg()
# Read the configuration file
if (self.conf_file_tag):
self.config = Config(self.conf_file)
else:
self.config = Config()
# Init the limits
self.limits = glancesLimits(self.config)
# Init the monitoring list
self.monitors = monitorList(self.config)
# Init stats
stats = GlancesStatsServer()
# Catch the CTRL-C signal
signal.signal(signal.SIGINT, self.__signal_handler)
def __signal_handler(self, signal, frame):
self.end()
def end(self):
"""
Stop the Glances core and exit
"""
if (self.is_standalone()):
# Stop the classical CLI loop
# !!! Uncomment
# screen.end()
pass
elif (self.is_client()):
# Stop the client loop
#~ client.client_quit()
pass
elif (self.is_server()):
# Stop the server loop
# !!! Uncomment
# server.server_close()
pass
# !!! Uncomment
# if (self.csv_tag):
# csvoutput.exit()
# !! Todo for htmloutput too
# The exit should generate a new HTML page
# to inform the user that data are not refreshed anymore
# The end...
sys.exit(0)
def init_arg(self):
"""
Init all the command line arguments
"""
self.parser = argparse.ArgumentParser(
prog=__appname__,
description='Glances, an eye on your system.')
# Version
self.parser.add_argument('-v', '--version',
action='version',
@ -250,12 +293,11 @@ class GlancesCore(object):
choices=self.output_list)
# Define output type flag to False (default is no output)
for o in self.output_list:
setattr(self, o+"_tag", False)
setattr(self, o + "_tag", False)
# Output file/folder
self.parser.add_argument('-f', '--file',
help=_('set the html output folder or csv file'))
def parse_arg(self):
"""
Parse command line argument
@ -264,6 +306,7 @@ class GlancesCore(object):
args = self.parser.parse_args()
# Change global variables regarding to user args
# !!! To be refactor to use directly the args list in the code
if (args.time is not None): self.refresh_time = args.time
self.network_bytepersec_tag = args.byte
self.diskio_tag = args.disable_diskio
@ -300,7 +343,7 @@ class GlancesCore(object):
output_folder = args.file
# !!! Debug
print args
# print args
def get_password(self, description='', confirm=False):
"""
@ -323,10 +366,21 @@ class GlancesCore(object):
sys.stdout.write(_("[Warning] Passwords did not match, please try again...\n"))
return self.get_password(description=description, confirm=confirm)
def start(self):
def is_standalone(self):
"""
Start the instance
It is the 'real' main function for Glances
Return True if Glances is running in standalone mode
"""
return not self.client_tag and not self.server_tag
def is_client(self):
"""
Return True if Glances is running in client mode
"""
return self.client_tag and not self.server_tag
def is_server(self):
"""
Return True if Glances is running in sserver mode
"""
return not self.client_tag and self.server_tag
self.parse_arg()

View File

@ -0,0 +1,51 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Glances - An eye on your system
#
# 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 system libs
import sys
import os
import gettext
import locale
# Path definitions
work_path = os.path.realpath(os.path.dirname(__file__))
appname_path = os.path.split(sys.argv[0])[0]
sys_prefix = os.path.realpath(os.path.dirname(appname_path))
# Operating system flag
# Note: Somes libs depends of OS
is_BSD = sys.platform.find('bsd') != -1
is_Linux = sys.platform.startswith('linux')
is_Mac = sys.platform.startswith('darwin')
is_Windows = sys.platform.startswith('win')
# i18n
locale.setlocale(locale.LC_ALL, '')
gettext_domain = 'glances'
# get locale directory
i18n_path = os.path.realpath(os.path.join(work_path, '..', 'i18n'))
sys_i18n_path = os.path.join(sys_prefix, 'share', 'locale')
if os.path.exists(i18n_path):
locale_dir = i18n_path
elif os.path.exists(sys_i18n_path):
locale_dir = sys_i18n_path
else:
locale_dir = None
gettext.install(gettext_domain, locale_dir)

View File

@ -0,0 +1,270 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Glances - An eye on your system
#
# 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/>.
class glancesLimits:
"""
Manage limits for each stats. A limit can be:
* a set of careful, warning and critical values
* a filter (for example: hide some network interfaces)
The limit list is stored in an hash table:
__limits_list[STAT] = [CAREFUL, WARNING, CRITICAL]
STD is for defaults limits (CPU/MEM/SWAP/FS)
CPU_IOWAIT limits (iowait in %)
CPU_STEAL limits (steal in %)
LOAD is for LOAD limits (5 min/15 min)
TEMP is for sensors limits (temperature in °C)
HDDTEMP is for hddtemp limits (temperature in °C)
FS is for partitions space limits
IODISK_HIDE is a list of disk (name) to hide
NETWORK_HIDE is a list of network interface (name) to hide
"""
__limits_list = {'STD': [50, 70, 90],
'CPU_USER': [50, 70, 90],
'CPU_SYSTEM': [50, 70, 90],
'CPU_IOWAIT': [40, 60, 80],
'CPU_STEAL': [10, 15, 20],
'LOAD': [0.7, 1.0, 5.0],
'MEM': [50, 70, 90],
'SWAP': [50, 70, 90],
'TEMP': [60, 70, 80],
'HDDTEMP': [45, 52, 60],
'FS': [50, 70, 90],
'PROCESS_CPU': [50, 70, 90],
'PROCESS_MEM': [50, 70, 90],
'IODISK_HIDE': [],
'NETWORK_HIDE': []}
def __init__(self, config):
"""
Init the limits with: default values and configuration file
"""
self.config = config
# Test if the configuration file has a limits section
if config.has_section('global'):
# Read STD limits
self.__setLimits('STD', 'global', 'careful')
self.__setLimits('STD', 'global', 'warning')
self.__setLimits('STD', 'global', 'critical')
if config.has_section('cpu'):
# Read CPU limits
self.__setLimits('CPU_USER', 'cpu', 'user_careful')
self.__setLimits('CPU_USER', 'cpu', 'user_warning')
self.__setLimits('CPU_USER', 'cpu', 'user_critical')
self.__setLimits('CPU_SYSTEM', 'cpu', 'system_careful')
self.__setLimits('CPU_SYSTEM', 'cpu', 'system_warning')
self.__setLimits('CPU_SYSTEM', 'cpu', 'system_critical')
self.__setLimits('CPU_IOWAIT', 'cpu', 'iowait_careful')
self.__setLimits('CPU_IOWAIT', 'cpu', 'iowait_warning')
self.__setLimits('CPU_IOWAIT', 'cpu', 'iowait_critical')
self.__setLimits('CPU_STEAL', 'cpu', 'steal_careful')
self.__setLimits('CPU_STEAL', 'cpu', 'steal_warning')
self.__setLimits('CPU_STEAL', 'cpu', 'steal_critical')
if config.has_section('load'):
# Read LOAD limits
self.__setLimits('LOAD', 'load', 'careful')
self.__setLimits('LOAD', 'load', 'warning')
self.__setLimits('LOAD', 'load', 'critical')
if config.has_section('memory'):
# Read MEM limits
self.__setLimits('MEM', 'memory', 'careful')
self.__setLimits('MEM', 'memory', 'warning')
self.__setLimits('MEM', 'memory', 'critical')
if config.has_section('swap'):
# Read MEM limits
self.__setLimits('SWAP', 'swap', 'careful')
self.__setLimits('SWAP', 'swap', 'warning')
self.__setLimits('SWAP', 'swap', 'critical')
if config.has_section('temperature'):
# Read TEMP limits
self.__setLimits('TEMP', 'temperature', 'careful')
self.__setLimits('TEMP', 'temperature', 'warning')
self.__setLimits('TEMP', 'temperature', 'critical')
if config.has_section('hddtemperature'):
# Read HDDTEMP limits
self.__setLimits('HDDTEMP', 'hddtemperature', 'careful')
self.__setLimits('HDDTEMP', 'hddtemperature', 'warning')
self.__setLimits('HDDTEMP', 'hddtemperature', 'critical')
if config.has_section('filesystem'):
# Read FS limits
self.__setLimits('FS', 'filesystem', 'careful')
self.__setLimits('FS', 'filesystem', 'warning')
self.__setLimits('FS', 'filesystem', 'critical')
if config.has_section('process'):
# Process limits
self.__setLimits('PROCESS_CPU', 'process', 'cpu_careful')
self.__setLimits('PROCESS_CPU', 'process', 'cpu_warning')
self.__setLimits('PROCESS_CPU', 'process', 'cpu_critical')
self.__setLimits('PROCESS_MEM', 'process', 'mem_careful')
self.__setLimits('PROCESS_MEM', 'process', 'mem_warning')
self.__setLimits('PROCESS_MEM', 'process', 'mem_critical')
if config.has_section('iodisk'):
# Hidden disks' list
self.__setHidden('IODISK_HIDE', 'iodisk', 'hide')
if config.has_section('network'):
# Network interfaces' list
self.__setHidden('NETWORK_HIDE', 'network', 'hide')
def __setHidden(self, stat, section, alert='hide'):
"""
stat: 'IODISK', 'NETWORK'
section: 'iodisk', 'network'
alert: 'hide'
"""
value = self.config.get_raw_option(section, alert)
# print("%s / %s = %s -> %s" % (section, alert, value, stat))
if (value is not None):
self.__limits_list[stat] = value.split(",")
def __setLimits(self, stat, section, alert):
"""
stat: 'CPU', 'LOAD', 'MEM', 'SWAP', 'TEMP', etc.
section: 'cpu', 'load', 'memory', 'swap', 'temperature', etc.
alert: 'careful', 'warning', 'critical'
"""
value = self.config.get_option(section, alert)
# print("%s / %s = %s -> %s" % (section, alert, value, stat))
if alert.endswith('careful'):
self.__limits_list[stat][0] = value
elif alert.endswith('warning'):
self.__limits_list[stat][1] = value
elif alert.endswith('critical'):
self.__limits_list[stat][2] = value
def setAll(self, newlimits):
self.__limits_list = newlimits
return True
def getAll(self):
return self.__limits_list
def getHide(self, stat):
try:
self.__limits_list[stat]
except KeyError:
return []
else:
return self.__limits_list[stat]
def getCareful(self, stat):
return self.__limits_list[stat][0]
def getWarning(self, stat):
return self.__limits_list[stat][1]
def getCritical(self, stat):
return self.__limits_list[stat][2]
# TO BE DELETED AFTER THE HTML output refactoring
def getSTDCareful(self):
return self.getCareful('STD')
def getSTDWarning(self):
return self.getWarning('STD')
def getSTDCritical(self):
return self.getCritical('STD')
# /TO BE DELETED AFTER THE HTML output refactoring
def getCPUCareful(self, stat):
return self.getCareful('CPU_' + stat.upper())
def getCPUWarning(self, stat):
return self.getWarning('CPU_' + stat.upper())
def getCPUCritical(self, stat):
return self.getCritical('CPU_' + stat.upper())
def getLOADCareful(self, core=1):
return self.getCareful('LOAD') * core
def getLOADWarning(self, core=1):
return self.getWarning('LOAD') * core
def getLOADCritical(self, core=1):
return self.getCritical('LOAD') * core
def getMEMCareful(self):
return self.getCareful('MEM')
def getMEMWarning(self):
return self.getWarning('MEM')
def getMEMCritical(self):
return self.getCritical('MEM')
def getSWAPCareful(self):
return self.getCareful('SWAP')
def getSWAPWarning(self):
return self.getWarning('SWAP')
def getSWAPCritical(self):
return self.getCritical('SWAP')
def getTEMPCareful(self):
return self.getCareful('TEMP')
def getTEMPWarning(self):
return self.getWarning('TEMP')
def getTEMPCritical(self):
return self.getCritical('TEMP')
def getHDDTEMPCareful(self):
return self.getCareful('HDDTEMP')
def getHDDTEMPWarning(self):
return self.getWarning('HDDTEMP')
def getHDDTEMPCritical(self):
return self.getCritical('HDDTEMP')
def getFSCareful(self):
return self.getCareful('FS')
def getFSWarning(self):
return self.getWarning('FS')
def getFSCritical(self):
return self.getCritical('FS')
def getProcessCareful(self, stat='', core=1):
if stat.upper() != 'CPU':
# Use core only for CPU
core = 1
return self.getCareful('PROCESS_' + stat.upper()) * core
def getProcessWarning(self, stat='', core=1):
if stat.upper() != 'CPU':
# Use core only for CPU
core = 1
return self.getWarning('PROCESS_' + stat.upper()) * core
def getProcessCritical(self, stat='', core=1):
if stat.upper() != 'CPU':
# Use core only for CPU
core = 1
return self.getCritical('PROCESS_' + stat.upper()) * core

View File

@ -0,0 +1,135 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Glances - An eye on your system
#
# 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/>.
class monitorList:
"""
This class describes the optionnal monitored processes list
A list of 'important' processes to monitor.
The list (Python list) is composed of items (Python dict)
An item is defined (Dict keys'):
* description: Description of the processes (max 16 chars)
* regex: regular expression of the processes to monitor
* command: (optional) shell command for extended stat
* countmin: (optional) minimal number of processes
* countmax: (optional) maximum number of processes
"""
# Maximum number of items in the list
__monitor_list_max_size = 10
# The list
__monitor_list = []
def __init__(self, config):
"""
Init the monitoring list from the configuration file
"""
if config.has_section('monitor'):
# Process monitoring list
self.__setMonitorList('monitor', 'list')
def __setMonitorList(self, section, key):
"""
Init the monitored processes list
The list is defined in the Glances configuration file
"""
for l in range(1, self.__monitor_list_max_size + 1):
value = {}
key = "list_" + str(l) + "_"
try:
description = config.get_raw_option(section, key + "description")
regex = config.get_raw_option(section, key + "regex")
command = config.get_raw_option(section, key + "command")
countmin = config.get_raw_option(section, key + "countmin")
countmax = config.get_raw_option(section, key + "countmax")
except Exception:
pass
else:
if description is not None and regex is not None:
# Build the new item
value["description"] = description
value["regex"] = regex
value["command"] = command
value["countmin"] = countmin
value["countmax"] = countmax
# Add the item to the list
self.__monitor_list.append(value)
def __str__(self):
return str(self.__monitor_list)
def __repr__(self):
return self.__monitor_list
def __getitem__(self, item):
return self.__monitor_list[item]
def __len__(self):
return len(self.__monitor_list)
def __get__(self, item, key):
"""
Meta function to return key value of item
None if not defined or item > len(list)
"""
if item < len(self.__monitor_list):
try:
return self.__monitor_list[item][key]
except Exception:
return None
else:
return None
def getAll(self):
return self.__monitor_list
def setAll(self, newlist):
self.__monitor_list = newlist
def description(self, item):
"""
Return the description of the item number (item)
"""
return self.__get__(item, "description")
def regex(self, item):
"""
Return the regular expression of the item number (item)
"""
return self.__get__(item, "regex")
def command(self, item):
"""
Return the stats command of the item number (item)
"""
return self.__get__(item, "command")
def countmin(self, item):
"""
Return the minimum number of processes of the item number (item)
"""
return self.__get__(item, "countmin")
def countmax(self, item):
"""
Return the maximum number of processes of the item number (item)
"""
return self.__get__(item, "countmax")

View File

@ -0,0 +1,288 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Glances - An eye on your system
#
# 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 system libs
import sys
import socket
from ..core.glances_timer import Timer
try:
# Python 2
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler
from SimpleXMLRPCServer import SimpleXMLRPCServer
except ImportError:
# Python 3
from xmlrpc.server import SimpleXMLRPCRequestHandler
from xmlrpc.server import SimpleXMLRPCServer
try:
# Python 2
from xmlrpclib import ServerProxy, ProtocolError
except ImportError:
# Python 3
from xmlrpc.client import ServerProxy, ProtocolError
class GlancesXMLRPCHandler(SimpleXMLRPCRequestHandler):
"""
Main XMLRPC handler
"""
rpc_paths = ('/RPC2', )
def end_headers(self):
# Hack to add a specific header
# Thk to: https://gist.github.com/rca/4063325
self.send_my_headers()
SimpleXMLRPCRequestHandler.end_headers(self)
def send_my_headers(self):
# Specific header is here (solved the issue #227)
self.send_header("Access-Control-Allow-Origin", "*")
def authenticate(self, headers):
# auth = headers.get('Authorization')
try:
(basic, _, encoded) = headers.get('Authorization').partition(' ')
except Exception:
# Client did not ask for authentidaction
# If server need it then exit
return not self.server.isAuth
else:
# Client authentication
(basic, _, encoded) = headers.get('Authorization').partition(' ')
assert basic == 'Basic', 'Only basic authentication supported'
# Encoded portion of the header is a string
# Need to convert to bytestring
encodedByteString = encoded.encode()
# Decode Base64 byte String to a decoded Byte String
decodedBytes = b64decode(encodedByteString)
# Convert from byte string to a regular String
decodedString = decodedBytes.decode()
# Get the username and password from the string
(username, _, password) = decodedString.partition(':')
# Check that username and password match internal global dictionary
return self.check_user(username, password)
def check_user(self, username, password):
# Check username and password in the dictionnary
if username in self.server.user_dict:
if self.server.user_dict[username] == md5(password).hexdigest():
return True
return False
def parse_request(self):
if SimpleXMLRPCRequestHandler.parse_request(self):
# Next we authenticate
if self.authenticate(self.headers):
return True
else:
# if authentication fails, tell the client
self.send_error(401, 'Authentication failed')
return False
def log_message(self, format, *args):
# No message displayed on the server side
pass
class GlancesXMLRPCServer(SimpleXMLRPCServer):
"""
Init a SimpleXMLRPCServer instance (IPv6-ready)
"""
def __init__(self, bind_address, bind_port=61209,
requestHandler=GlancesXMLRPCHandler):
try:
self.address_family = socket.getaddrinfo(bind_address, bind_port)[0][0]
except socket.error as e:
print(_("Couldn't open socket: %s") % e)
sys.exit(1)
SimpleXMLRPCServer.__init__(self, (bind_address, bind_port),
requestHandler)
class GlancesInstance():
"""
All the methods of this class are published as XML RPC methods
"""
def __init__(self, cached_time=1):
# cached_time is the minimum time interval between stats updates
# i.e. XML/RPC calls will not retrieve updated info until the time
# since last update is passed (will retrieve old cached info instead)
self.timer = Timer(0)
self.cached_time = cached_time
def __update__(self):
# Never update more than 1 time per cached_time
if self.timer.finished():
stats.update()
self.timer = Timer(self.cached_time)
def init(self):
# Return the Glances version
return __version__
def getAll(self):
# Update and return all the stats
self.__update__()
return json.dumps(stats.getAll())
def getAllLimits(self):
# Return all the limits
return json.dumps(limits.getAll())
def getAllMonitored(self):
# Return the processes monitored list
return json.dumps(monitors.getAll())
def getSystem(self):
# Return operating system info
# No need to update...
#~ self.__update__()
return json.dumps(stats.getSystem())
def getCore(self):
# Update and return number of Core
self.__update__()
return json.dumps(stats.getCore())
def getCpu(self):
# Update and return CPU stats
self.__update__()
return json.dumps(stats.getCpu())
def getLoad(self):
# Update and return LOAD stats
self.__update__()
return json.dumps(stats.getLoad())
def getMem(self):
# Update and return MEM stats
self.__update__()
return json.dumps(stats.getMem())
def getMemSwap(self):
# Update and return MEMSWAP stats
self.__update__()
return json.dumps(stats.getMemSwap())
def getSensors(self):
# Update and return SENSORS stats
self.__update__()
return json.dumps(stats.getSensors())
def getHDDTemp(self):
# Update and return HDDTEMP stats
self.__update__()
return json.dumps(stats.getHDDTemp())
def getNetwork(self):
# Update and return NET stats
self.__update__()
return json.dumps(stats.getNetwork())
def getDiskIO(self):
# Update and return DISK IO stats
self.__update__()
return json.dumps(stats.getDiskIO())
def getFs(self):
# Update and return FS stats
self.__update__()
return json.dumps(stats.getFs())
def getProcessCount(self):
# Update and return ProcessCount stats
self.__update__()
return json.dumps(stats.getProcessCount())
def getProcessList(self):
# Update and return ProcessList stats
self.__update__()
return json.dumps(stats.getProcessList())
def getBatPercent(self):
# Update and return total batteries percent stats
self.__update__()
return json.dumps(stats.getBatPercent())
def getNow(self):
# Update and return current date/hour
self.__update__()
return json.dumps(stats.getNow().strftime(_("%Y-%m-%d %H:%M:%S")))
def getUptime(self):
# Update and return system uptime
self.__update__()
return json.dumps(stats.getUptime().strftime(_("%Y-%m-%d %H:%M:%S")))
def __getTimeSinceLastUpdate(self, IOType):
assert(IOType in ['net', 'disk', 'process_disk'])
return getTimeSinceLastUpdate(IOType)
def getNetTimeSinceLastUpdate(self):
return getTimeSinceLastUpdate('net')
def getDiskTimeSinceLastUpdate(self):
return getTimeSinceLastUpdate('net')
def getProcessDiskTimeSinceLastUpdate(self):
return getTimeSinceLastUpdate('process_disk')
class GlancesServer():
"""
This class creates and manages the TCP client
"""
def __init__(self, bind_address="0.0.0.0", bind_port=61209,
requestHandler=GlancesXMLRPCHandler, cached_time=1):
# Init the XML RPC server
try:
self.server = GlancesXMLRPCServer(bind_address, bind_port, requestHandler)
except Exception, err:
print(_("Error: Can not start Glances server (%s)") % err)
sys.exit(2)
# The users dict
# username / MD5 password couple
# By default, no auth is needed
self.server.user_dict = {}
self.server.isAuth = False
# Register functions
self.server.register_introspection_functions()
self.server.register_instance(GlancesInstance(cached_time))
def add_user(self, username, password):
"""
Add an user to the dictionnary
"""
self.server.user_dict[username] = md5(password).hexdigest()
self.server.isAuth = True
def serve_forever(self):
self.server.serve_forever()
def server_close(self):
self.server.server_close()

View File

@ -0,0 +1,44 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Glances - An eye on your system
#
# 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 time
class Timer:
"""
The timer class
A simple chrono
"""
def __init__(self, duration):
self.duration = duration
self.start()
def start(self):
self.target = time.time() + self.duration
def reset(self):
self.start()
def set(self, duration):
self.duration = duration
def finished(self):
return time.time() > self.target

View File

@ -18,9 +18,10 @@
# 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/>.
from ..plugins.glances_plugin import GlancesPlugin
# from ..plugins.glances_plugin import GlancesPlugin
from glances_plugin import GlancesPlugin
class CpuPlugin(GlancesPlugin):
class Plugin(GlancesPlugin):
"""
Glances' Cpu Plugin

View File

@ -0,0 +1,43 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Glances - An eye on your system
#
# 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/>.
# from ..plugins.glances_plugin import GlancesPlugin
from glances_plugin import GlancesPlugin
class Plugin(GlancesPlugin):
"""
Glances' Host Plugin
stats is a ?
"""
def __init__(self):
GlancesPlugin.__init__(self)
self.update()
def update(self):
# !!! Example
self.stats = { 'os': 'linux' }
def __str__(self):
ret = "Host\n"
for k in self.stats:
ret += "{0} {1}\n".format(k, self.stats[k])
return ret