SEGUNDO PARCIAL DEL CURSO SISTEMAS OPERACIONALES
Los archivos utilizados para resolver el ejercicio fueron los siguientes:
Código fuente del proceso en background que captura y almacena los valores de como mínimo un check en una base de datos sqlite
Se definio el siguiente modelo para la base de datos en el archivo modelo.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/monitoreo.db'
db = SQLAlchemy(app)
class Monitoreo(db.Model):
id = db.Column(db.Integer, primary_key=True)
cpu = db.Column(db.String(10), nullable=True)
memory = db.Column(db.String(10), nullable=False)
disk = db.Column(db.String(10), nullable=False)
httpd = db.Column(db.String(20), nullable=False)
El proceso en background fue implementado en script.py. Este proceso registra los datos de % cpu utilizado, % memoria RAM utilizada, espacio en disco disponible y el estado del servicio httpd (Activo o inactivo)
from subprocess import Popen, PIPE, call
from modelo import db, Monitoreo
import time
while True:
#consumo de cpu
comandos_cpu = "ps -A -o pcpu | tail -n+2 | paste -sd+ | bc"
respuesta = Popen(comandos_cpu,shell=True, stdout=PIPE, stderr=PIPE).communicate()[0].split('\n')
pcpu = respuesta[0] + "%"
#consumo de memoria RAM
comandos_memory = "free -m | tail -n +2 | grep Mem | awk '{print ($3/$2)*100}'"
respuesta_memory = Popen(comandos_memory,shell=True, stdout=PIPE, stderr=PIPE).communicate()[0].split('\n')
pmemory = str(round(float(respuesta_memory[0]),2)) + "%"
#espacio disponible en disco
comandos_disk = "df -h /home |tail -1 | awk '{print $4}'"
respuesta_disk = Popen(comandos_disk,shell=True, stdout=PIPE, stderr=PIPE).communicate()[0].split('\n')
pdisk = respuesta_disk[0]
#estado del servicio httpd
comandos_estado = "/bin/systemctl status httpd.service | grep -o '\w*ctive '"
respuesta_estado = Popen(comandos_estado,shell=True, stdout=PIPE, stderr=PIPE).communicate()[0].split('\n')
pestado = respuesta_estado[0].strip()
registro = Monitoreo(cpu=pcpu, memory=pmemory, disk=pdisk, httpd=pestado)
#validacion de numero de registro
cantidad = len(Monitoreo.query.all())
if cantidad == 100:
todos = Monitoreo.query.all()
primero = todos[0]
db.session.delete(primero)
db.session.commit()
db.session.add(registro)
db.session.commit()
#registra cada 60 segundos
time.sleep(60)
Al final del script se valida la cantidad de registros en la base de datos. Cuando la cantidad es igual a 100, se hace rotacion de los datos, borrando el primer registro e ingresando el nuevo. Finalmente, el proceso continua con los registros cada 60 segundos.
La ejecucion del script para que realice sus funciones en background se realizo con el siguiente comando:
Para verificar el funcionamiento del script, se utilizo:
Código fuente de la implementación de la API de como mínimo un check y documentación con swagger
En este punto se utilizaron dos archivos: commands.py y web.py. En commands.py se tienen las funciones necesarias para obtener todos los registros de la base de datos y obtener una determinada cantidad de registros de %cpu utilizado.
from modelo import db, Monitoreo
def get_all_checks():
checks_list = []
todos = Monitoreo.query.all()
tamanio = len(todos)-1
for i in range(0,tamanio):
check = todos[i]
checkData = ['cpu:'+str(check.cpu),'memory:'+str(check.memory),'disk:'+str(check.disk),'httpd:'+str(check.httpd)]
checks_list.append(checkData)
return filter(None,checks_list)
def get_last_cpu_checks(size):
checks_list = []
todos = Monitoreo.query.order_by(Monitoreo.id.desc()).limit(int(size)).all()
tamanio = len(todos)
for i in range(0,tamanio):
check = todos[i]
checks_list.append(check.cpu)
return filter(None,checks_list)
En web.py se utilizan estas funciones, añadiendo los comandos necesarios de documentacion con swagger:
from flask import Flask, jsonify, abort, request
from modelo import db, Monitoreo
import json
from flask_restplus import Resource, Api
from flask_restplus import fields
from commands import get_all_checks,get_last_cpu_checks
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/monitoreo.db'
db.init_app(app)
api = Api(app,version='FINAL', title='API para monitoreo', description='Segundo parcial de Sistemas Operativos, Universidad Icesi')
ns = api.namespace('', description='Consulta de registros de monitoreo del Sistema operativo')
@ns.route('/checks')
class ChecksCollection(Resource):
@api.response(200, 'Lista de todos los checks registrados')
def get(self):
""" retorna todos los checks """
list = {}
list["checks: "] = get_all_checks()
return json.dumps(list), 200
@api.response(404, 'HTTP 404 NOT FOUND')
def post(self):
return 'HTTP 404 NOT FOUND', 404
@api.response(404, 'HTTP 404 NOT FOUND')
def put(self):
return 'HTTP 404 NOT FOUND', 404
@api.response(404, 'HTTP 404 NOT FOUND')
def delete(self):
return 'HTTP 404 NOT FOUND', 404
@ns.route('/checks/cpu/history')
class ChecksByHistory(Resource):
@api.response(200, 'Lista de los ultimos n checks registrados')
@api.doc(params={'size': 'el numero de registros a imprimir'})
def get(self):
size = request.args.get("size")
list = {}
list["cpu: "] = get_last_cpu_checks(size)
return json.dumps(list), 200
@api.response(404, 'HTTP 404 NOT FOUND')
def post(self):
return 'HTTP 404 NOT FOUND', 404
@api.response(404, 'HTTP 404 NOT FOUND')
def put(self):
return 'HTTP 404 NOT FOUND', 404
@api.response(404, 'HTTP 404 NOT FOUND')
def delete(self):
return 'HTTP 404 NOT FOUND', 404
if __name__ == "__main__":
app.run(host='0.0.0.0',port=5000,debug='True')
Pruebas de la solución a través de capturas de pantalla
Finalmente, se ejecuto el servicio web con el siguiente comando:
Al acceder con el navegador Google Chrome con la ruta http://172.30.192.3:5000 se obtiene la documentacion de swagger: