Commit b5b6390f authored by Lutra Conseil's avatar Lutra Conseil Committed by Rafael Monnerat

Adding first work on resources monitor

parent a31304cf
from psutil import *
from psutil._error import NoSuchProcess, AccessDenied
from time import time, sleep
from datetime import datetime
import os
import ConfigParser
# Local import
from snapshot import Snapshot
from user import User
# XXX : this is BAAAAD !!
# ***************** Config *****************
GLOBAL_SLAPOS_CONFIGURATION = os.environ.get(
'SLAPOS_CONFIGURATION',
'/etc/opt/slapos/slapos.cfg'
)
# ******************************************
# XXX : should rebuild this to make it more explicit
def build_user_list():
config = ConfigParser.SafeConfigParser()
config.read(GLOBAL_SLAPOS_CONFIGURATION)
nb_user = int(config.get("slapformat", "partition_amount"))
name_prefix = config.get("slapformat", "user_base_name")
path_prefix = config.get("slapformat", "partition_base_name")
instance_root = config.get("slapos", "instance_root")
return {name: User(name, path)
for name, path in [
(
"%s%s" % (name_prefix, nb),
"%s/%s%s" % (instance_root, path_prefix, nb)
) for nb in range(nb_user)
]
}
def build_snapshot(proc):
assert type(proc) is Process
try:
return Snapshot(
proc.username,
# CPU percentage, we will have to get actual absolute value
cpu = proc.get_cpu_percent(None),
# Thread number, might not be really relevant
cpu_io = proc.get_num_threads(),
# Resident Set Size, virtual memory size is not accounted for
ram = proc.get_memory_info()[0],
# Byte count, Read and write. OSX NOT SUPPORTED
hd = proc.get_io_counters()[2] + proc.get_io_counters()[3],
# Read + write IO cycles
hd_io = proc.get_io_counters()[0] + proc.get_io_counters()[1],
)
except NoSuchProcess:
return None
def current_state():
"""
Iterator used to apply build_snapshot(...) on every single relevant process.
A process is considered relevant if its user matches our user list, i.e.
its user is a slapos user
"""
users = build_user_list()
pList = [p for p in process_iter() if p.username in users]
length = len(pList) / 5
for i, process in enumerate(pList):
if length > 0 and i % length == 0:
sleep(.5)
yield build_snapshot(process)
def main():
"""
Main function
The idea here is to poll system every so many seconds
For each poll, we get a list of Snapshots, holding informations about
processes. We iterate over that list to store datas on a per user basis:
Each user object is a dict, indexed on timestamp. We add every snapshot
matching the user so that we get informations for each users
"""
try:
while True:
users = build_user_list()
key = time()
try:
for snapshot in current_state():
if snapshot:
user = users[snapshot.username]
if key in user:
user[key] += snapshot
else:
user[key] = snapshot
except NoSuchProcess:
continue
except (KeyboardInterrupt, SystemExit):
break
# XXX: we should use a value from the config file and not a hardcoded one
for user in users.values():
user.dumpSummary(user.path + '/var/xml_report/consumption.xml')
except AccessDenied:
print "You HAVE TO execute this script with root permission."
if __name__ == '__main__':
main()
#!/usr/bin/env python
import os
from datetime import datetime
from time import sleep
import gzip
import sys
class Reporter:
def run(self, *args):
json = self._aggregate(*args)
if self._send(json):
self._archive(path_list)
else:
self._fallback(*args)
def _aggregate(self, paths):
json = ""
if paths:
for path in paths:
print ( path )
with open(path, 'r') as f:
json += f.read()
return json
# XXX : implement
def _send(self, json_str):
return False
def _archive(self, paths, archive_dir):
for path in paths:
dirname = os.path.dirname(path)
basename = os.path.basename(path)
f = open(path, 'r')
suffix = datetime.now() + '.gz'
zipfile = gzip.open(archive_dir + basename + suffix, 'w')
zipfile.writelines(f)
os.remove(path)
# XXX : set a more appropriate timer (like 1h or something)
def _fallback(self, *args):
sleep(30)
self.run(*args)
def check(args):
if not args:
print('missing argument : filename list')
sys.exit(-1)
for arg in args:
if not os.path.isfile(arg):
print(arg + ' is not a valid path')
sys.exit(-1)
if __name__ == '__main__':
reporter = Reporter()
# basically, we are waiting for a list of paths there
args = sys.argv[1:]
check(args)
reporter.run(args)
class Snapshot:
def __init__(self, username, cpu = 0, cpu_io = 0, ram = 0, hd = 0, hd_io = 0):
self.username = username
self.cpu = cpu
self.cpu_io = cpu_io
self.ram = ram
self.hd = hd
self.hd_io = hd_io
def __repr__(self):
return "%s : { cpu : {%s, %s}, ram : {%s, %s}, hd : {%s, %s}, net : {%s, %s} }" % (
self.username,
self.cpu, self.cpu_io,
self.ram, self.ram_io,
self.hd, self.hd_io,
self.net, self.net_io
)
def __add__(self, other):
assert self.username == other.username
return Snapshot(
self.username,
self.cpu + other.cpu,
self.cpu_io + other.cpu_io,
self.ram + other.ram,
self.hd + other.hd,
self.hd_io + other.hd_io,
)
def matters(self):
return self.cpu != 0 or self.cpu_io != 0 or self.ram != 0 or \
self.hd != 0 or self.hd_io != 0
from snapshot import Snapshot
class User(dict):
def __init__(self, name, path):
self.name = str(name)
self.path = str(path)
def dump(self, path):
with open(path, 'a') as f:
for v in self.values():
if v.matters():
f.write(v.__repr__() + "\n")
def dumpSummary(self, path):
summary = reduce(lambda x, y: x+y, self.values(), Snapshot(self.name))
if summary.matters():
with open(path, 'a') as f:
f.write(summary.__repr__() + "\n")
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment