You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
5.2 KiB
Python
165 lines
5.2 KiB
Python
"""
|
|
This program is designed to inspect an application environment
|
|
This program should only be run on unix friendly systems
|
|
|
|
We enable the engines to be able to run a several configurations
|
|
Similarly to what a visitor design-pattern would do
|
|
"""
|
|
from __future__ import division
|
|
import os
|
|
import subprocess
|
|
from sets import Set
|
|
import re
|
|
import datetime
|
|
|
|
class Analysis:
|
|
def __init__(self):
|
|
self.logs = []
|
|
pass
|
|
def post(self,object):
|
|
self.logs.append(object)
|
|
def init(self):
|
|
d = datetime.datetime.now()
|
|
self.now = {"month":d.month,"year":d.year, "day":d.day,"hour":d.hour}
|
|
"""
|
|
This class is designed to analyze environment variables. Environment variables can either be folders, files or simple values
|
|
The class returns a quantifiable assessment of the environment variables (expected 100%)
|
|
"""
|
|
class Env(Analysis):
|
|
def __init__(self):
|
|
Analysis.__init__(self)
|
|
def init(self,values):
|
|
Analysis.init(self)
|
|
self.values = values
|
|
"""
|
|
This function evaluate the validity of an environment variable by returning a 1 or 0 (computable)
|
|
The function will use propositional logic (https://en.wikipedia.org/wiki/Propositional_calculus)
|
|
"""
|
|
def evaluate(self,id):
|
|
|
|
if id in os.environ :
|
|
#
|
|
# We can inspect to make sure the environment variable is not a path or filename.
|
|
# Using propositional logic we proceed as follows:
|
|
# - (p) We determine if the value is an folder or file name (using regex)
|
|
# - (q) In case of a file or folder we check for existance
|
|
# The final result is a conjuction of p and q
|
|
#
|
|
value = os.environ[id]
|
|
expressions = [os.sep,'(\\.\w+)$']
|
|
p = sum([ re.search(xchar,value) is not None for xchar in expressions])
|
|
q = os.path.exists(value)
|
|
|
|
return int(p and q)
|
|
else:
|
|
return 0
|
|
|
|
def composite (self):
|
|
r = [ self.evaluate(id) for id in self.values] ;
|
|
N = len(r)
|
|
n = sum(r)
|
|
value = n/N
|
|
missing = [self.values[i] for i in range(0,N) if r[i] == 0]
|
|
return {"value":value,"missing":missing}
|
|
|
|
class Sandbox(Analysis):
|
|
def __init__(self):
|
|
Analysis.__init__(self)
|
|
def init(self,conf):
|
|
Analysis.init(self)
|
|
self.sandbox_path = conf['sandbox']
|
|
self.requirements_path = conf['requirements']
|
|
def get_requirements (self):
|
|
f = open(self.requirements_path)
|
|
return [ name.replace('-',' ').replace('_',' ') for name in f.read().split('\n') if name != '']
|
|
"""
|
|
This function will return the modules installed in the sandbox (virtual environment)
|
|
"""
|
|
def get_sandbox_requirements(self):
|
|
cmd = ['freeze']
|
|
xchar = ''.join([os.sep]*2)
|
|
pip_vm = ''.join([self.sandbox_path,os.sep,'bin',os.sep,'pip']).replace(xchar,os.sep)
|
|
cmd = [pip_vm]+cmd
|
|
r = subprocess.check_output(cmd).split('\n')
|
|
return [row.replace('-',' ').replace('_',' ') for row in r if row.strip() != '']
|
|
def evaluate(self):
|
|
pass
|
|
"""
|
|
This function returns the ratio of existing modules relative to the ones expected
|
|
"""
|
|
def composite(self):
|
|
required_modules= self.get_requirements()
|
|
sandbox_modules = self.get_sandbox_requirements()
|
|
N = len(required_modules)
|
|
n = len(Set(required_modules) - Set(sandbox_modules))
|
|
value = 1 - (n/N)
|
|
missing = list(Set(required_modules) - Set(sandbox_modules))
|
|
return {"value":value,"missing":missing}
|
|
|
|
"""
|
|
This class performs the analysis of a list of processes and determines
|
|
The class provides a quantifiable measure of how many processes it found over all
|
|
"""
|
|
class ProcessCounter(Analysis):
|
|
def __init__(self):
|
|
Analysis.__init__(self)
|
|
def init(self,names):
|
|
Analysis.init(self)
|
|
self.names = names
|
|
def evaluate(self,name):
|
|
cmd = "".join(['ps -eo comm |grep ',name,' |wc -l'])
|
|
handler = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
|
|
|
|
return int(handler.communicate()[0].replace("\n","") )
|
|
def composite(self):
|
|
r = {}
|
|
for name in self.names :
|
|
r[name] = self.evaluate(name)
|
|
|
|
#N = len(r)
|
|
#n = sum(r)
|
|
#return n/N
|
|
return r
|
|
"""
|
|
This class returns an application's both memory and cpu usage
|
|
"""
|
|
class DetailProcess(Analysis):
|
|
def __init__(self):
|
|
Analysis.__init__(self)
|
|
def init (self,names):
|
|
Analysis.init(self)
|
|
self.names = names;
|
|
def evaluate(self,name) :
|
|
cmd = "ps -eo pmem,pcpu,vsize,comm|grep :app"
|
|
handler = subprocess.Popen(cmd.replace(":app",name),shell=True,stdout=subprocess.PIPE)
|
|
ostream = handler.communicate()[0].split('\n')
|
|
ostream = [ row.split(' ') for row in ostream if row != '']
|
|
|
|
if len(ostream) == 0:
|
|
|
|
ostream = [['0','0','0',name]]
|
|
r = []
|
|
for row in ostream :
|
|
#
|
|
# Though the comm should only return the name as specified,
|
|
# On OSX it has been observed that the fully qualified path is sometimes returned (go figure)
|
|
#
|
|
row = [float(value) for value in row if value.strip() != '' and name not in value ] +[name]
|
|
r.append(row)
|
|
return r
|
|
def format(self,row):
|
|
return {"memory_usage":row[0],"cpu_usage":row[1],"memory_available":row[2]/1000,"label":row[3]}
|
|
def composite(self):
|
|
#value = self.evaluate(self.name)
|
|
#row= {"memory_usage":value[0],"cpu_usage":value[1]}
|
|
#return row
|
|
#ma = [self.evaluate(name) for name in self.names]
|
|
ma = []
|
|
for name in self.names:
|
|
matrix = self.evaluate(name)
|
|
ma += [self.format(row) for row in matrix]
|
|
|
|
#return [{"memory_usage":row[0],"cpu_usage":row[1],"memory_available":row[2]/1000,"label":row[3]} for row in ma]
|
|
|
|
return ma
|