#push all
This commit is contained in:
parent
babfcb3807
commit
90706f9b6c
5 changed files with 217 additions and 0 deletions
90
README.md
90
README.md
|
@ -0,0 +1,90 @@
|
|||
## Descripción
|
||||
|
||||
Este proyecto realiza de manera automatizada, la eliminación de trabajos (jobs) dentro de MISP que hayan quedado "colgados" (stuck) durante horas.
|
||||
|
||||
### Características:
|
||||
|
||||
- Funciona de forma local en servidor MISP (requerido)
|
||||
- Soporta todos los tipos de Jobs (pull, push, publish, etc)
|
||||
- Configuración de umbral de tiempo. Se puede definir hasta cuantas horas hacia atras desde la ejecución realize revision de Jobs. Por defecto (24h)
|
||||
|
||||
## Componentes
|
||||
|
||||
- Libreria PyMISP (pymisp): https://pypi.org/project/pymisp/
|
||||
- Libreria SQLAlchemy
|
||||
|
||||
## Descarga
|
||||
|
||||
1. Descargar ZIP del repositorio (https://git.csirt.gob.cl/public/misp-jobfixer/archive/main.zip)
|
||||
|
||||
2. Al descomprimir el archivo, mover carpeta "misp-jobfixer" dentro de carpeta "home" de usuario u otra ubicación definida.
|
||||
|
||||
## Configuración inicial
|
||||
|
||||
1. En el archivo config.py se debe definir los parametros según caso:
|
||||
|
||||
``` python
|
||||
|
||||
DB_DATA = {
|
||||
"user":"root",
|
||||
"pass":"<PASS DB MISP (ROOT)>",
|
||||
"host":"localhost",
|
||||
"port":3306,
|
||||
"dbname":"misp"
|
||||
}
|
||||
|
||||
CHECK_JOBS = {
|
||||
"hours_limit": 24
|
||||
}
|
||||
|
||||
```
|
||||
En config.py podemos:
|
||||
|
||||
- DB_DATA: Se definen valores de conexión a BD de MISP. Por defecto solo se necesita agregar pass de DB (En archivo de log de instalación de MISP se encuentra pass de DB)
|
||||
- CHECK_JOBS: En "hours_limit" se define el umbral máximo de tiempo que tiene la app para buscar jobs (Por defecto: 24 hrs)
|
||||
|
||||
|
||||
## Instalación en entorno virtual
|
||||
|
||||
Una vez configurado "config.py" procedemos con la instalación
|
||||
|
||||
1. Se crea entorno virtual de Python
|
||||
``` shell
|
||||
cd ./misp-jobfixer
|
||||
python3 -m venv venv
|
||||
```
|
||||
2. Se activa entorno virtual:
|
||||
``` shell
|
||||
source venv/bin/activate
|
||||
```
|
||||
3. Instalar librerias de Python:
|
||||
``` shell
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Agengar
|
||||
|
||||
Preparamos el archivo "run.sh" ajustando las rutas en "source" y "cd" para la ejecución correcta del archivo:
|
||||
|
||||
```shell
|
||||
#!/bin/bash
|
||||
|
||||
# Activate
|
||||
source /home/user/misp-jobfixer/venv/bin/activate
|
||||
|
||||
# Enter folder
|
||||
cd /home/user/misp-jobfixer/
|
||||
|
||||
# Llamar al script Python
|
||||
python main.py
|
||||
|
||||
# Deactivate
|
||||
deactivate
|
||||
```
|
||||
|
||||
Debemos crear en crontab una entrada con la ejecución programada, por ejemplo para que realice la revisión cada dia a las 00:00 (recomendado) :
|
||||
|
||||
``` shell
|
||||
@daily bash ./misp-jobfixer/run.sh
|
||||
```
|
||||
|
11
config.py
Normal file
11
config.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
DB_DATA = {
|
||||
"user":"root",
|
||||
"pass":"<PASS DB MISP (ROOT)>",
|
||||
"host":"localhost",
|
||||
"port":3306,
|
||||
"dbname":"misp"
|
||||
}
|
||||
|
||||
CHECK_JOBS = {
|
||||
"hours_limit": 24
|
||||
}
|
95
main.py
Normal file
95
main.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
from sqlalchemy import create_engine, Column, Integer, String, Text, DateTime, select
|
||||
from sqlalchemy.orm import sessionmaker, declarative_base
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from datetime import datetime, timedelta
|
||||
import config
|
||||
import os
|
||||
import logging
|
||||
from logging.handlers import RotatingFileHandler
|
||||
|
||||
|
||||
DIR_ACTUAL = os.getcwd()
|
||||
DIR_LOGS = os.path.join(DIR_ACTUAL,'logs')
|
||||
|
||||
os.makedirs(DIR_LOGS, exist_ok=True)
|
||||
|
||||
rotating_handler = RotatingFileHandler(os.path.join(DIR_LOGS,"misp_limpiajobs_"+datetime.now().strftime("%Y%m%d")+".log"), maxBytes=262144000, backupCount=10)
|
||||
logging.basicConfig(level=logging.INFO, handlers=[rotating_handler],
|
||||
format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
|
||||
# Configuración de la conexión para MariaDB con pymysql
|
||||
DATABASE_URL = "mariadb+pymysql://"+config.DB_DATA['user']+":"+config.DB_DATA['pass']+"@"+config.DB_DATA['host']+":"+str(config.DB_DATA['port'])+"/"+config.DB_DATA['dbname']
|
||||
|
||||
# Inicializa SQLAlchemy
|
||||
Base = declarative_base()
|
||||
engine = create_engine(DATABASE_URL)
|
||||
Session = sessionmaker(bind=engine)
|
||||
session = Session()
|
||||
|
||||
# Modelo de la tabla jobs
|
||||
class Job(Base):
|
||||
__tablename__ = 'jobs'
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
worker = Column(String(32), nullable=False)
|
||||
job_type = Column(String(32), nullable=False)
|
||||
job_input = Column(Text, nullable=False)
|
||||
status = Column(Integer, nullable=False, default=0)
|
||||
retries = Column(Integer, nullable=False, default=0)
|
||||
message = Column(Text, nullable=False)
|
||||
progress = Column(Integer, nullable=False, default=0)
|
||||
org_id = Column(Integer, nullable=False, default=0)
|
||||
process_id = Column(String(36), nullable=True)
|
||||
date_created = Column(DateTime, nullable=False)
|
||||
date_modified = Column(DateTime, nullable=False)
|
||||
|
||||
# Función para detener jobs no completados después de 24 horas
|
||||
def kill_stale_jobs():
|
||||
"""
|
||||
Identifica y detiene jobs que no han sido completados
|
||||
y llevan más de 24 horas sin cambios.
|
||||
"""
|
||||
try:
|
||||
time_limit = datetime.now() - timedelta(hours=config.CHECK_JOBS['hours_limit'])
|
||||
|
||||
# Consulta usando la sintaxis de SQLAlchemy 2.x
|
||||
stmt = select(Job).where(
|
||||
Job.status == 0, # Status 0: Sigue en progreso
|
||||
Job.progress < 100, # Menor a 100, sigue activo
|
||||
Job.date_modified < time_limit
|
||||
)
|
||||
|
||||
stale_jobs = session.execute(stmt).scalars().all()
|
||||
|
||||
if not stale_jobs:
|
||||
logging.info("No hay jobs pendientes que cumplan con las condiciones.")
|
||||
return
|
||||
|
||||
processed_count = 0
|
||||
failed_count = 0
|
||||
|
||||
for job in stale_jobs:
|
||||
try:
|
||||
job.status = 3 # Killed
|
||||
job.progress = 100
|
||||
job.message = "Killed job manually."
|
||||
session.commit()
|
||||
processed_count += 1
|
||||
logging.info(f"Job {job.id} detenido automáticamente.")
|
||||
except SQLAlchemyError as sql_error:
|
||||
session.rollback()
|
||||
failed_count += 1
|
||||
logging.error(f"Error al detener el Job {job.id}: {str(sql_error)}")
|
||||
|
||||
logging.info(f"Resumen: {processed_count} jobs detenidos exitosamente, {failed_count} errores.")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error al procesar los jobs: {str(e)}")
|
||||
|
||||
finally:
|
||||
session.close()
|
||||
logging.info("Sesión cerrada correctamente.")
|
||||
# Ejecución del script
|
||||
if __name__ == "__main__":
|
||||
logging.info("CuraJobs v1.0 comenzando")
|
||||
kill_stale_jobs()
|
2
requirements.txt
Normal file
2
requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
pymysql
|
||||
SQLAlchemy
|
19
run.sh
Normal file
19
run.sh
Normal file
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Activate
|
||||
source /home/user/misp-jobfixer/venv/bin/activate
|
||||
|
||||
# Enter folder
|
||||
cd /home/user/misp-jobfixer|/
|
||||
|
||||
# Llamar al script Python
|
||||
python main.py
|
||||
|
||||
# Deactivate
|
||||
deactivate
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Add table
Reference in a new issue