SEGUNDO PARCIAL DEL CURSO SISTEMAS OPERACIONALES

Los archivos utilizados para resolver el ejercicio fueron los siguientes:

archivos

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:

commando python

Para verificar el funcionamiento del script, se utilizo:

datos1

datos2

datos3

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:

python web

Al acceder con el navegador Google Chrome con la ruta http://172.30.192.3:5000 se obtiene la documentacion de swagger:

evidencia1

evidencia2

evidencia3

evidencia4

evidencia5