1563 lines
78 KiB
Python
1563 lines
78 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
API de ogRepository, programada en Flask.
|
|
|
|
Responde a peticiones HTTP (en principio, enviadas desde ogCore) mediante endpoints, que a su vez ejecutan los scripts Python almacenados en ogRepository.
|
|
En ciertos casos, transforma los parámetros recibidos desde el portal, para adaptarlos a los que es necesario enviar a los scripts
|
|
(por ejemplo, a partir del ID de una imagen obtiene su nombre y su extensión).
|
|
|
|
Librerías Python requeridas: - flask (se puede instalar con "sudo apt install python3-flask")
|
|
- paramiko (se puede instalar con "sudo apt install python3-paramiko")
|
|
- requests (se puede instalar con "sudo apt install python3-requests") - No es necesario instalarlo en Ubuntu 24
|
|
- flasgger (se puede instalar con "sudo apt install python3-flasgger")
|
|
"""
|
|
|
|
# --------------------------------------------------------------------------------------------
|
|
# IMPORTS
|
|
# --------------------------------------------------------------------------------------------
|
|
|
|
from flask import Flask, jsonify, request
|
|
import os
|
|
import subprocess
|
|
import json
|
|
from time import sleep
|
|
import paramiko
|
|
import logging
|
|
import threading
|
|
import requests
|
|
import random
|
|
from systemd import journal
|
|
# Imports para Swagger:
|
|
from flasgger import Swagger
|
|
import yaml
|
|
|
|
|
|
# --------------------------------------------------------------------------------------------
|
|
# VARIABLES
|
|
# --------------------------------------------------------------------------------------------
|
|
|
|
repo_path = '/opt/opengnsys/ogrepository/images/' # No borrar la barra final
|
|
script_path = '/opt/opengnsys/ogrepository/bin'
|
|
repo_file = '/opt/opengnsys/ogrepository/etc/repoinfo.json'
|
|
trash_file = '/opt/opengnsys/ogrepository/etc/trashinfo.json'
|
|
config_file = '/opt/opengnsys/ogrepository/etc/ogAdmRepo.cfg'
|
|
|
|
|
|
# --------------------------------------------------------------------------------------------
|
|
# FUNCTIONS
|
|
# --------------------------------------------------------------------------------------------
|
|
|
|
|
|
# Creamos una instancia de la aplicación Flask:
|
|
app = Flask(__name__)
|
|
|
|
# Cargamos el contenido del archivo "swagger.yaml":
|
|
with open("swagger.yaml", "r") as file:
|
|
swagger_template = yaml.safe_load(file)
|
|
|
|
# Así cambiamos el nombre de la página (por defecto, es 'Flasgger'):
|
|
swagger_config = Swagger.DEFAULT_CONFIG
|
|
swagger_config['title'] = 'ogRepository API'
|
|
|
|
swagger = Swagger(app, template=swagger_template)
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
def get_IPcore():
|
|
""" Obtiene el valor asociado a la variable "IPcore", desde el archivo '/opt/opengnsys/ogrepository/etc/ogAdmRepo.cfg'.
|
|
Retorna la IP encontrada (que corresponde a la IP de ogCore), o un error (si no la encuentra).
|
|
"""
|
|
journal.send("Running function 'get_IPcore'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
IPcore = None
|
|
with open(config_file, 'r') as file:
|
|
for line in file:
|
|
if line.startswith('IPcore'):
|
|
IPcore = line.split('=')[1].strip()
|
|
return IPcore
|
|
if IPcore is None:
|
|
journal.send("Can't obtain ogCore IP", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return "IP no encontrada en el archivo de configuración"
|
|
|
|
|
|
# Almacenamos la IP de ogCore:
|
|
ogcore_ip = get_IPcore()
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
def get_image_params(image_id, search='all'):
|
|
""" A partir de un ID de imagen (que corresponde al "fullsum"), busca la imagen en el repositorio y/o en la papelera (dependiendo del parámetro "search").
|
|
Si encuentra la imagen devuelve su nombre y su extensión en un diccionario, y si no encuentra la imagen especificada retorna "None".
|
|
El parámtro "search" tiene el valor predeterminado "all" (que hará que busque tanto en el repo como en la papelera),
|
|
pero se le puede pasar el valor "repo" (para que busque solo en el repo) o "trash" (para que busque solo en la papelera).
|
|
"""
|
|
journal.send("Running function 'get_image_params'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Creamos un diccionario vacío, para almacenar los resultados:
|
|
result = {}
|
|
|
|
# Abrimos y almacenamos el archivo "repoinfo.json" (solo si se ha de buscar en el repo, y si el archivo tiene contenido):
|
|
if (search == 'all' or search == 'repo') and os.path.getsize(repo_file) > 0:
|
|
with open(repo_file, 'r') as file:
|
|
repo_data = json.load(file)
|
|
# Iteramos la clave "images" y buscamos la imagen (y si la encontramos almacenamos el nombre y la extension):
|
|
for image in repo_data.get('images', []):
|
|
if image.get('fullsum') == image_id:
|
|
result['name'] = image.get('name')
|
|
result['extension'] = image.get('type')
|
|
return result
|
|
|
|
# Abrimos y almacenamos el archivo "trashinfo.json" (solo si se ha de buscar en la papelera, y si el archivo tiene contenido):
|
|
if (search == 'all' or search == 'trash') and os.path.getsize(trash_file) > 0:
|
|
with open(trash_file, 'r') as file:
|
|
trash_data = json.load(file)
|
|
# Iteramos la clave "images" y buscamos la imagen (y si la encontramos almacenamos el nombre y la extension):
|
|
for image in trash_data.get('images', []):
|
|
if image.get('fullsum') == image_id:
|
|
result['name'] = image.get('name')
|
|
result['extension'] = image.get('type')
|
|
return result
|
|
|
|
# Si no encontramos la imagen, retornamos "None":
|
|
return None
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
def search_process(process, string_to_search):
|
|
""" Busca procesos que contengan el valor del parámetro "process" y el valor del parámetro "string_to_search" (la ruta de la imagen, normalmente).
|
|
Si encuentra alguno retorna "True", y si no encuentra ninguno retorna "False".
|
|
"""
|
|
journal.send("Running function 'search_process'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
try:
|
|
# Obtenemos todos los procesos que están corriendo, y almacenamos la salida y los errores:
|
|
result = subprocess.Popen(['ps', '-aux'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
out, error = result.communicate()
|
|
|
|
# Almacenamos en una lista los procesos que contengan el proceso del parámetro y la cadena a buscar:
|
|
process_list = [line for line in out.split('\n') if process in line and string_to_search in line]
|
|
|
|
# Si hemos encontrado algún proceso que cumpla las condiciones, retornamos "True", y si no retornamos "False":
|
|
if process_list != []:
|
|
journal.send("Process found", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return True
|
|
else:
|
|
journal.send("Process not found", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return False
|
|
# Si se ha producido una excepción, imprimimos el error:
|
|
except Exception as error_description:
|
|
journal.send(f"Function result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
print(f"Unexpected error: {error_description}")
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
def check_remote_connection(remote_ip, remote_user):
|
|
""" Comprueba la conexión SSH/SFTP con el servidor remoto que recibe como primer parámetro.
|
|
Se utiliza para chequear la conexión antes de importar o exportar una imagen.
|
|
"""
|
|
journal.send("Running function 'check_remote_connection'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
try:
|
|
# Iniciamos un cliente SSH:
|
|
ssh_client = paramiko.SSHClient()
|
|
# Establecemos la política por defecto para localizar la llave del host localmente:
|
|
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
|
|
# Conectamos con el equipo remoto por SSH:
|
|
ssh_client.connect(remote_ip, 22, remote_user) # Así se hace con claves
|
|
#ssh_client.connect(remote_ip, 22, remote_user, 'opengnsys') # Así se haría con password
|
|
|
|
# Iniciamos un cliente SFTP:
|
|
sftp_client = ssh_client.open_sftp()
|
|
|
|
# Cerramos el cliente SSH y el cliente SFTP:
|
|
ssh_client.close()
|
|
sftp_client.close()
|
|
|
|
# Retornamos "True", porque hemos conseguido conectar:
|
|
journal.send("Connection OK", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return True
|
|
|
|
# Si se produce una excepción, retornamos "False":
|
|
except Exception as error_description:
|
|
journal.send(f"Function result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return False
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
def check_remote_image(remote_ip, remote_user, image_file_path):
|
|
""" Conecta con el servidor remoto que recibe como primer parámetro,
|
|
para comprobar si la imagen que recibe como tercer parámetro existe, o si está bloqueada.
|
|
Se utiliza para chequear la imagen antes de importarla.
|
|
"""
|
|
journal.send("Running function 'check_remote_image'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Iniciamos un cliente SSH:
|
|
ssh_client = paramiko.SSHClient()
|
|
# Establecemos la política por defecto para localizar la llave del host localmente:
|
|
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
|
|
# Conectamos con el equipo remoto por SSH:
|
|
ssh_client.connect(remote_ip, 22, remote_user) # Así se hace con claves
|
|
#ssh_client.connect(remote_ip, 22, remote_user, 'opengnsys') # Así se haría con password
|
|
|
|
# Iniciamos un cliente SFTP:
|
|
sftp_client = ssh_client.open_sftp()
|
|
|
|
# Si la imagen no existe, retornamos el mensaje correspondiente:
|
|
if not os.path.exists(image_file_path):
|
|
return "Remote image not found"
|
|
|
|
# Si la imagen existe pero está bloqueada, retornamos el mensaje correspondiente:
|
|
if os.path.exists(f"{image_file_path}.lock"):
|
|
return "Remote image is locked"
|
|
|
|
# Cerramos el cliente SSH y el cliente SFTP:
|
|
ssh_client.close()
|
|
sftp_client.close()
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
def check_lock_local(image_file_path, job_id):
|
|
""" Cada minuto comprueba si existe un archivo ".lock" asociado a la imagen que recibe como parámetro
|
|
(lo que significará que hay una tarea en curso), en el repositorio local.
|
|
Cuando no encuentre el archivo ".lock" lo comunicará a ogCore, llamando a un endpoint,
|
|
y dejará de realizar la comprobación (saliendo del bucle).
|
|
"""
|
|
journal.send("Running function 'check_lock_local'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Esperamos 30 segundos, para dar tiempo a que se cree el archivo ".lock":
|
|
sleep(30)
|
|
|
|
# Creamos un bucle infinito:
|
|
while True:
|
|
# Si ya no existe el archivo ".lock", imprimimos un mensaje en la API, respondemos a ogCore y salimos del bucle:
|
|
if not os.path.exists(f"{image_file_path}.lock"):
|
|
app.logger.info("Task finalized (no .lock file)")
|
|
app.logger.info(f"Job_ID: {job_id}")
|
|
journal.send("Image unlocked", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos en un diccionario los datos a enviar a ogCore:
|
|
data = {
|
|
'job_id': job_id
|
|
}
|
|
# Llamamos al endpoint de ogCore, enviando los datos del diccionario:
|
|
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id})", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
recall_ogcore(data)
|
|
break
|
|
# Si aun existe el archivo ".lock", imprimimos un mensaje en la API:
|
|
else:
|
|
app.logger.info("Task in process (.lock file exists)")
|
|
# Esperamos 1 minuto para volver a realizar la comprobación:
|
|
sleep(60)
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
def check_lock_remote(image_file_path, remote_host, remote_user, job_id):
|
|
""" Cada minuto comprueba si existe un archivo ".lock" asociado a la imagen que recibe como parámetro
|
|
(lo que significará que hay una tarea en curso), en un repositorio remoto (al que conecta por SSH/SFTP).
|
|
Cuando no encuentre el archivo ".lock" lo comunicará a ogCore, llamando a un endpoint,
|
|
y dejará de realizar la comprobación (saliendo del bucle).
|
|
"""
|
|
journal.send("Running function 'check_lock_remote'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Iniciamos un cliente SSH:
|
|
ssh_client = paramiko.SSHClient()
|
|
# Establecemos la política por defecto para localizar la llave del host localmente:
|
|
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
|
|
# Conectamos con el equipo remoto por SSH:
|
|
ssh_client.connect(remote_host, 22, remote_user) # Así se hace con claves
|
|
#ssh_client.connect(remote_host, 22, remote_user, 'opengnsys') # Así se haría con password
|
|
|
|
# Iniciamos un cliente SFTP:
|
|
sftp_client = ssh_client.open_sftp()
|
|
# Esperamos 30 segundos, para dar tiempo a que se cree el archivo ".lock":
|
|
sleep(30)
|
|
|
|
# Creamos un bucle infinito:
|
|
while True:
|
|
try:
|
|
# Si aun existe el archivo ".lock", imprimimos un mensaje en la API:
|
|
sftp_client.stat(f"{image_file_path}.lock")
|
|
app.logger.info("Task in process (.lock file exists)")
|
|
except IOError:
|
|
# Si ya no existe el archivo ".lock", imprimimos un mensaje en la API, respondemos a ogCore y salimos del bucle:
|
|
app.logger.info("Task finalized (no .lock file)")
|
|
app.logger.info(f"Job_ID: {job_id}")
|
|
journal.send("Remote image unlocked", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos en un diccionario los datos a enviar a ogCore:
|
|
data = {
|
|
'job_id': job_id
|
|
}
|
|
# Llamamos al endpoint de ogCore, enviando los datos del diccionario:
|
|
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id})", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
recall_ogcore(data)
|
|
break
|
|
# Esperamos 1 minuto para volver a realizar la comprobación:
|
|
sleep(60)
|
|
|
|
# Ya fuera del bucle, cerramos el cliente SSH y el cliente SFTP:
|
|
ssh_client.close()
|
|
sftp_client.close()
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
def check_aux_files(image_file_path, job_id):
|
|
""" Cada 10 segundos comprueba si se han creado todos los archivos auxiliares de la imagen que recibe como parámetro,
|
|
en cuyo caso lo comunicará a ogCore, llamando a un endpoint, y dejará de realizar la comprobación.
|
|
También obtiene el valor del archivo ".full.sum" (que corresonde al ID), y se lo comunica a ogCore.
|
|
"""
|
|
journal.send("Running function 'check_aux_files'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Creamos un bucle infinito:
|
|
while True:
|
|
# Si faltan archivos auxiliares por crear, imprimimos un mensaje en la API:
|
|
if not os.path.exists(f"{image_file_path}.size") or not os.path.exists(f"{image_file_path}.sum") or not os.path.exists(f"{image_file_path}.full.sum") or not os.path.exists(f"{image_file_path}.torrent") or not os.path.exists(f"{image_file_path}.info.checked"):
|
|
app.logger.info("Task in process (auxiliar files remaining)")
|
|
# Si ya se han creado todos los archivos auxiliares, imprimimos un mensaje en la API, respondemos a ogCore y salimos del bucle:
|
|
else:
|
|
app.logger.info("Task finalized (all auxilar files created)")
|
|
journal.send("Auxiliar files created", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Obtenemos el valor del archivo "full.sum", que corresponde al ID, y lo imprimimos:
|
|
with open(f"{image_file_path}.full.sum", 'r') as file:
|
|
image_id = file.read().strip('\n')
|
|
app.logger.info(f"Job_ID: {job_id}")
|
|
app.logger.info(f"Image_ID: {image_id}")
|
|
|
|
# Almacenamos en un diccionario los datos a enviar a ogCore:
|
|
data = {
|
|
'job_id': job_id,
|
|
'image_id': image_id
|
|
}
|
|
# Llamamos al endpoint de ogCore, enviando los datos del diccionario:
|
|
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id}, IMAGE_ID: {image_id})", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
recall_ogcore(data)
|
|
break
|
|
# Esperamos 10 segundos para volver a realizar la comprobación:
|
|
sleep(10)
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
def recall_ogcore(data):
|
|
""" Hace una petición HTTP de tipo POST a un endpoint de ogCore, enviando datos que dependen del caso.
|
|
Se utiliza para informar a ogCore del resultado de una tarea asíncrona,
|
|
que estaba corriendo en un proceso independiente (no controlado por los endpoints).
|
|
"""
|
|
journal.send("Running function 'recall_ogcore'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos la URL del endpoint de ogCore (prueba):
|
|
#endpoint_url = f"http://{ogcore_ip}:8006/ogcore/v1/test"
|
|
endpoint_url = f"https://{ogcore_ip}:8443/og-repository/webhook"
|
|
|
|
# Almacenamos los headers, y convertiomos "data" a JSON:
|
|
headers = {'content-type': 'application/json'}
|
|
data = json.dumps(data)
|
|
|
|
# Hacemos una petición POST al endpoint, enviando lo almacenado en "data":
|
|
journal.send("Sending HTTP request...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
response = requests.post(endpoint_url, data=data, headers=headers, verify=False)
|
|
|
|
# Imprimimos el código de estado de la petición y la respuesta de ogCore:
|
|
app.logger.info(f"HTTP Status Code: {response.status_code}")
|
|
app.logger.info(f"HTTP Response: {response.text}")
|
|
journal.send(f"HTTP Status Code: {response.status_code}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
#journal.send(f"HTTP Response: {response.text}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
|
|
|
|
# --------------------------------------------------------------------------------------------
|
|
# ENDPOINTS
|
|
# --------------------------------------------------------------------------------------------
|
|
|
|
|
|
# 1 - Endpoint "Obtener Información de Estado de ogRepository" (SINCRONO):
|
|
@app.route("/ogrepository/v1/status", methods=['GET'])
|
|
def get_repo_status():
|
|
""" Este endpoint devuelve información de CPU, memoria RAM, disco duro y el estado de ciertos servicios y procesos de ogRepository, en formato json.
|
|
Para ello, ejecuta el script "getRepoStatus.py", que no recibe parámetros.
|
|
"""
|
|
journal.send("Running endpoint 'Obtener Información de Estado de ogRepository'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
try:
|
|
journal.send("Running script 'getRepoStatus.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "getRepoStatus.py", y almacenamos el resultado:
|
|
result = subprocess.run(['sudo', 'python3', f"{script_path}/getRepoStatus.py"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos la respuesta:
|
|
if result.returncode == 0:
|
|
journal.send("Script result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": json.loads(result.stdout)
|
|
}), 200
|
|
else:
|
|
journal.send(f"Script result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": result.stderr
|
|
}), 500
|
|
except Exception as error_description:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 2 - Endpoint "Obtener Información de todas las Imágenes" (SINCRONO):
|
|
@app.route("/ogrepository/v1/images", methods=['GET'])
|
|
def get_repo_info():
|
|
""" Este endpoint devuelve información de todas las imágenes contenidas en el repositorio (incluída la papelera), en formato json.
|
|
Para ello, ejecuta el script "getRepoInfo.py", con el parámetro "all".
|
|
"""
|
|
journal.send("Running endpoint 'Obtener Información de todas las Imágenes'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
try:
|
|
journal.send("Running script 'getRepoInfo.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "getRepoInfo.py" (con el parámetro "all"), y almacenamos el resultado:
|
|
result = subprocess.run(['sudo', 'python3', f"{script_path}/getRepoInfo.py", 'all'], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos la respuesta:
|
|
if result.returncode == 0:
|
|
journal.send("Script result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": json.loads(result.stdout)
|
|
}), 200
|
|
else:
|
|
journal.send(f"Script result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": result.stderr
|
|
}), 500
|
|
except Exception as error_description:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 3 - Endpoint "Obtener Información de una Imagen concreta" (SINCRONO):
|
|
@app.route("/ogrepository/v1/images/<string:imageId>", methods=['GET'])
|
|
def get_repo_image_info(imageId):
|
|
""" Este endpoint devuelve información de la imagen especificada como parámetro, en formato json.
|
|
Para ello, ejecuta el script "getRepoInfo.py", con el nombre de la imagen como parámetro.
|
|
"""
|
|
journal.send("Running endpoint 'Obtener Información de una Imagen concreta'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Obtenemos el nombre y la extensión de la imagen:
|
|
param_dict = get_image_params(imageId)
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir la llamada al script, o para devover un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['sudo', 'python3', f"{script_path}/getRepoInfo.py", f"{param_dict['name']}.{param_dict['extension']}"]
|
|
else:
|
|
journal.send("Image not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image not found"
|
|
}), 400
|
|
|
|
try:
|
|
journal.send("Running script 'getRepoInfo.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "getRepoInfo.py" (con los parámetros almacenados), y almacenamos el resultado:
|
|
result = subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos la respuesta:
|
|
if result.returncode == 0:
|
|
journal.send("Script result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": json.loads(result.stdout)
|
|
}), 200
|
|
else:
|
|
journal.send(f"Script result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": result.stderr
|
|
}), 500
|
|
except Exception as error_description:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 4 - Endpoint "Actualizar Información del Repositorio" (SINCRONO):
|
|
@app.route("/ogrepository/v1/images", methods=['PUT'])
|
|
def update_repo_info():
|
|
""" Este endpoint actualiza la información del repositorio y de la papelera, reflejándola en los archivos "repoinfo.json" y "trashinfo.josn".
|
|
Para ello, ejecuta el script "updateRepoInfo.py", que a su vez ejecuta el script "updateTrashInfo.py".
|
|
"""
|
|
journal.send("Running endpoint 'Actualizar Información del Repositorio'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
try:
|
|
journal.send("Running script 'updateRepoInfo.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "updateRepoInfo.py" (sin parámetros), y almacenamos el resultado:
|
|
result = subprocess.run(['sudo', 'python3', f"{script_path}/updateRepoInfo.py"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode == 0:
|
|
journal.send("Script result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Repository info updated successfully"
|
|
}), 200
|
|
else:
|
|
journal.send(f"Script result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": result.stderr
|
|
}), 500
|
|
except Exception as error_description:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 5 - Endpoint "Chequear Integridad de Imagen" (SINCRONO):
|
|
@app.route("/ogrepository/v1/status/images/<string:imageId>", methods=['GET'])
|
|
def check_image(imageId):
|
|
""" Este endpoint comprueba la integridad de la imagen especificada como parámetro,
|
|
comparando el tamaño y el hash MD5 del último MB con los valores almacenados en los archivos "size" y "sum".
|
|
Para ello, ejecuta el script "checkImage.py", con el nombre de la imagen como único parámetro.
|
|
"""
|
|
journal.send("Running endpoint 'Chequear Integridad de Imagen'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Obtenemos el nombre y la extensión de la imagen:
|
|
param_dict = get_image_params(imageId, "repo")
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir la llamada al script, o para devover un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['sudo', 'python3', f"{script_path}/checkImage.py", f"{param_dict['name']}.{param_dict['extension']}"]
|
|
else:
|
|
journal.send("Image not found (inexistent or deleted)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image not found (inexistent or deleted)"
|
|
}), 400
|
|
|
|
try:
|
|
journal.send("Running script 'checkImage.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "checkImage.py" (con los parámetros almacenados), y almacenamos el resultado:
|
|
result = subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos la respuesta:
|
|
if result.returncode == 0:
|
|
journal.send("Script result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
if "Error" in result.stdout:
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Image file didn't pass the Integrity Check"
|
|
}), 200
|
|
else:
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Image file passed the Integrity Check correctly"
|
|
}), 200
|
|
else:
|
|
journal.send(f"Script result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": result.stderr
|
|
}), 500
|
|
except Exception as error_description:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 6 - Endpoint "Eliminar una Imagen" (SINCRONO):
|
|
@app.route("/ogrepository/v1/images/<string:imageId>", methods=['DELETE'])
|
|
def delete_image(imageId):
|
|
""" Este endpoint elimina la imagen especificada como parámetro (y todos sus archivos asociados),
|
|
moviéndolos a la papelera o eliminándolos permanentemente (dependiendo del parámetro "method").
|
|
Para ello, ejecuta el script "deleteImage.py", con el nombre de la imagen como primer parámetro, y el parámetro opcional "-p".
|
|
"""
|
|
journal.send("Running endpoint 'Eliminar una Imagen'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Obtenemos el nombre y la extensión de la imagen:
|
|
param_dict = get_image_params(imageId, "repo")
|
|
# Almacenams el método de eliminación ("trash" o "permanent")
|
|
method = request.values.get('method')
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir la llamada al script, o para devover un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
if method == "permanent":
|
|
cmd = ['sudo', 'python3', f"{script_path}/deleteImage.py", f"{param_dict['name']}.{param_dict['extension']}", '-p']
|
|
elif method == "trash":
|
|
cmd = ['sudo', 'python3', f"{script_path}/deleteImage.py", f"{param_dict['name']}.{param_dict['extension']}"]
|
|
else:
|
|
journal.send("Incorret method (must be 'permanent' or 'trash')", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Incorrect method (must be 'permanent' or 'trash')"
|
|
}), 400
|
|
else:
|
|
journal.send("Image not found (inexistent or deleted)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image not found (inexistent or deleted)"
|
|
}), 400
|
|
|
|
try:
|
|
journal.send("Running script 'deleteImage.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "deleteImage.py" (con los parámetros almacenados), y almacenamos el resultado:
|
|
result = subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode == 0:
|
|
journal.send("Script result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Image deleted successfully"
|
|
}), 200
|
|
else:
|
|
journal.send(f"Script result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": result.stderr
|
|
}), 500
|
|
except Exception as error_description:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 7 - Endpoint "Recuperar una Imagen" (SINCRONO):
|
|
@app.route("/ogrepository/v1/trash/images", methods=['POST'])
|
|
def recover_image():
|
|
""" Este endpoint recupera la imagen especificada como parámetro (y todos sus archivos asociados),
|
|
moviéndolos nuevamente al repositorio de imágenes, desde la papelera.
|
|
Para ello, ejecuta el script "recoverImage.py", con el nombre de la imagen como único parámetro.
|
|
"""
|
|
journal.send("Running endpoint 'Recuperar una Imagen'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos el parámetro "ID_img" (enviado por JSON):
|
|
json_data = json.loads(request.data)
|
|
image_id = json_data.get("ID_img")
|
|
|
|
# Obtenemos el nombre y la extensión de la imagen:
|
|
param_dict = get_image_params(image_id, "trash")
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir la llamada al script, o para devover un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['sudo', 'python3', f"{script_path}/recoverImage.py", f"{param_dict['name']}.{param_dict['extension']}"]
|
|
else:
|
|
journal.send("Image not found (inexistent or recovered previously)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image not found (inexistent or recovered previously)"
|
|
}), 400
|
|
|
|
try:
|
|
journal.send("Running script 'recoverImage.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "recoverImage.py" (con los parámetros almacenados), y almacenamos el resultado:
|
|
result = subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode == 0:
|
|
journal.send("Script result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Image recovered successfully"
|
|
}), 200
|
|
else:
|
|
journal.send(f"Script result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": result.stderr
|
|
}), 500
|
|
except Exception as error_description:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 8 - Endpoint "Eliminar una Imagen de la Papelera" (SINCRONO):
|
|
@app.route("/ogrepository/v1/trash/images/<string:imageId>", methods=['DELETE'])
|
|
def delete_trash_image(imageId):
|
|
""" Este endpoint elimina permanentemente la imagen especificada como parámetro (y todos sus archivos asociados), desde la papelera.
|
|
Para ello, ejecuta el script "deleteTrashImage.py", con el nombre de la imagen como único parámetro.
|
|
"""
|
|
journal.send("Running endpoint 'Eliminar una Imagen de la Papelera'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Obtenemos el nombre y la extensión de la imagen:
|
|
param_dict = get_image_params(imageId, "trash")
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir la llamada al script, o para devover un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['sudo', 'python3', f"{script_path}/deleteTrashImage.py", f"{param_dict['name']}.{param_dict['extension']}"]
|
|
else:
|
|
journal.send("Image not found at trash", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image not found at trash"
|
|
}), 400
|
|
|
|
try:
|
|
journal.send("Running script 'deleteTrashImage.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "deleteTrashImage.py" (con los parámetros almacenados), y almacenamos el resultado:
|
|
result = subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode == 0:
|
|
journal.send("Script result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Image deleted successfully"
|
|
}), 200
|
|
else:
|
|
journal.send(f"Script result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": result.stderr
|
|
}), 500
|
|
except Exception as error_description:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 9 - Endpoint "Importar una Imagen" (ASINCRONO):
|
|
@app.route("/ogrepository/v1/repo/images", methods=['POST'])
|
|
def import_image():
|
|
""" Este endpoint importa la imagen especificada como primer parámetro (y todos sus archivos asociados), desde un servidor remoto al servidor local.
|
|
Para ello, ejecuta el script "importImage.py", con el nombre de la imagen como primer parámetro,
|
|
la IP o hostname del servidor remoto como segundo parámetro, y el usuario con el que conectar al servidor como tercer parámetro.
|
|
"""
|
|
journal.send("Running endpoint 'Importar una Imagen'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos los parámetros enviados en el JSON:
|
|
json_data = json.loads(request.data)
|
|
image_name = json_data.get("image")
|
|
remote_ip = json_data.get("repo_ip")
|
|
remote_user = json_data.get("user")
|
|
|
|
# Comprobamos la conexión con el equipo remoto, y si falla salimos del endpoint, retornando un error:
|
|
connection_OK = check_remote_connection(remote_ip, remote_user)
|
|
if connection_OK == False:
|
|
journal.send("Can't connect to remote server", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Can't connect to remote server"
|
|
}), 400
|
|
|
|
# Construimos la ruta de la imagen:
|
|
image_file_path = f"{repo_path}{image_name}"
|
|
|
|
# Comprobamos si la imagen remota no existe o está bloqueada, en cuyos casos salimos del endpoint y retornamos el error correspondiente:
|
|
check_image = check_remote_image(remote_ip, remote_user, image_file_path)
|
|
if check_image == "Remote image not found":
|
|
journal.send("Remote image not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Remote image not found"
|
|
}), 400
|
|
elif check_image == "Remote image is locked":
|
|
journal.send("Remote image is locked", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Remote image is locked"
|
|
}), 400
|
|
|
|
# Construimos la llamada al script:
|
|
cmd = ['sudo', 'python3', f"{script_path}/importImage.py", image_file_path, remote_ip, remote_user]
|
|
|
|
try:
|
|
journal.send("Running script 'importImage.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "importImage.py" (con los parámetros almacenados), y almacenamos el resultado (pero sin esperar a que termine el proceso):
|
|
result = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Generamos el ID para identificar el trabajo asíncrono:
|
|
job_id = f"ImportImage_{''.join(random.choice('0123456789abcdef') for char in range(8))}"
|
|
journal.send(f"JOB ID generated ({job_id})", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode is None:
|
|
journal.send("Script result OK (ReturnCode: None)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Si el resultado es correcto, llamamos a la función "check_lock_local" en un hilo paralelo
|
|
# (para que compruebe si la imagen se ha acabado de importar exitosamente):
|
|
journal.send("Calling function 'check_lock_local'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
threading.Thread(target=check_lock_local, args=(image_file_path, job_id,)).start()
|
|
|
|
# Informamos que la imagen se está importando, y salimos del endpoint:
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Importing image...",
|
|
"job_id": job_id
|
|
}), 200
|
|
else:
|
|
journal.send("Script result KO (Image import failed)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image import failed"
|
|
}), 500
|
|
except subprocess.CalledProcessError as error:
|
|
journal.send(f"Script result KO (Process Exception: {str(error)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"process exception": str(error)
|
|
}), 500
|
|
except Exception as error_description:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 10 - Endpoint "Exportar una Imagen" (ASINCRONO):
|
|
@app.route("/ogrepository/v1/repo/images", methods=['PUT'])
|
|
def export_image():
|
|
""" Este endpoint exporta la imagen especificada como primer parámetro (y todos sus archivos asociados), desde el servidor local a un servidor remoto.
|
|
Para ello, ejecuta el script "exportImage.py", con el nombre de la imagen como primer parámetro,
|
|
la IP o hostname del servidor remoto como segundo parámetro, y el usuario con el que conectar al servidor como tercer parámetro.
|
|
"""
|
|
journal.send("Running endpoint 'Exportar una Imagen'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos los parámetros enviados en el JSON:
|
|
json_data = json.loads(request.data)
|
|
image_id = json_data.get("ID_img")
|
|
remote_ip = json_data.get("repo_ip")
|
|
remote_user = json_data.get("user")
|
|
|
|
# Obtenemos el nombre y la extensión de la imagen (y el subdirectorio de OU, si fuera el caso):
|
|
param_dict = get_image_params(image_id, "repo")
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir la ruta de la imagen, o para devover un error si no se ha encontrado la imagen (o si está bloqueada):
|
|
if param_dict:
|
|
image_file_path = f"{param_dict['name']}.{param_dict['extension']}"
|
|
# Si la imagen existe pero está bloqueada, devolvemos un error:
|
|
if os.path.exists(f"{repo_path}{image_file_path}.lock"):
|
|
journal.send("Image is locked", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Image is locked"
|
|
}), 400
|
|
else:
|
|
journal.send("Image not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image not found"
|
|
}), 400
|
|
|
|
# Comprobamos la conexión con el equipo remoto, y si falla salimos del endpoint, retornando un error:
|
|
connection_OK = check_remote_connection(remote_ip, remote_user)
|
|
|
|
if connection_OK == False:
|
|
journal.send("Can't connect to remote server", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Can't connect to remote server"
|
|
}), 400
|
|
|
|
# Construimos la llamada al script:
|
|
cmd = ['sudo', 'python3', f"{script_path}/exportImage.py", image_file_path, remote_ip, remote_user]
|
|
|
|
try:
|
|
journal.send("Running script 'exportImage.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "exportImage.py" (con los parámetros almacenados), y almacenamos el resultado (pero sin esperar a que termine el proceso):
|
|
result = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Generamos el ID para identificar el trabajo asíncrono:
|
|
job_id = f"ExportImage_{''.join(random.choice('0123456789abcdef') for char in range(8))}"
|
|
journal.send(f"JOB ID generated ({job_id})", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode is None:
|
|
journal.send("Script result OK (ReturnCode: None)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Si el resultado es correcto, llamamos a la función "check_lock_remote" en un hilo paralelo
|
|
# (para que compruebe si la imagen se ha acabado de exportar exitosamente):
|
|
journal.send("Calling function 'check_lock_remote'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
threading.Thread(target=check_lock_remote, args=(f"{repo_path}{image_file_path}", remote_ip, remote_user, job_id,)).start()
|
|
|
|
# Informamos que la imagen se está exportando, y salimos del endpoint:
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Exporting image...",
|
|
"job_id": job_id
|
|
}), 200
|
|
else:
|
|
journal.send("Script result KO (Export image failed)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Export image failed"
|
|
}), 500
|
|
except subprocess.CalledProcessError as error:
|
|
journal.send(f"Script result KO (Process Exception: {str(error)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"process exception": str(error)
|
|
}), 500
|
|
except Exception as error_description:
|
|
if "exit status 5" in str(error_description):
|
|
journal.send("Image already exists on remote server", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Image already exists on remote server"
|
|
}), 400
|
|
else:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 11 - Endpoint "Crear archivos auxiliares" (ASINCRONO):
|
|
@app.route("/ogrepository/v1/images/torrentsum", methods=['POST'])
|
|
def create_torrent_sum():
|
|
""" Este endpoint crea los archivos ".size", ".sum", ".full.sum" y ".torrent" para la imagen que recibe como parámetro.
|
|
Para ello, ejecuta el script "createTorrentSum.py", con el nombre de la imagen como único parámetro.
|
|
"""
|
|
journal.send("Running endpoint 'Crear archivos auxiliares'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos los parámetros enviados en el JSON:
|
|
json_data = json.loads(request.data)
|
|
image_name = json_data.get("image")
|
|
|
|
# Si la imagen no existe, retornamos un error y salimos del endpoint:
|
|
if not os.path.exists(f"{repo_path}{image_name}"):
|
|
journal.send("Image not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Image not found"
|
|
}), 400
|
|
|
|
# Construimos la ruta de la imagen (relativa a "repo_path"):
|
|
image_file_path = image_name
|
|
|
|
# Construimos la llamada al script:
|
|
cmd = ['sudo', 'python3', f"{script_path}/createTorrentSum.py", image_file_path]
|
|
|
|
try:
|
|
journal.send("Running script 'createTorrentSum.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "createTorrentSum.py" (con los parámetros almacenados), y almacenamos el resultado (pero sin esperar a que termine el proceso):
|
|
result = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Generamos el ID para identificar el trabajo asíncrono:
|
|
job_id = f"CreateAuxiliarFiles_{''.join(random.choice('0123456789abcdef') for char in range(8))}"
|
|
journal.send(f"JOB ID generated ({job_id})", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode is None:
|
|
journal.send("Script result OK (ReturnCode: None)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Si el resultado es correcto, llamamos a la función "check_aux_files" en un hilo paralelo
|
|
# (para que compruebe si se han creado todos los archivos auxiliares exitosamente):
|
|
journal.send("Calling function 'check_aux_files'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
threading.Thread(target=check_aux_files, args=(f"{repo_path}{image_file_path}", job_id,)).start()
|
|
|
|
# Informamos que los archivos auxiliares se están creando, y salimos del endpoint:
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Creating auxiliar files...",
|
|
"job_id": job_id
|
|
}), 200
|
|
else:
|
|
journal.send(f"Script result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": result.stderr
|
|
}), 500
|
|
except Exception as error_description:
|
|
if "exit status 2" in str(error_description):
|
|
journal.send("Image not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Image not found"
|
|
}), 400
|
|
elif "exit status 3" in str(error_description):
|
|
journal.send("Image is locked", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Image is locked"
|
|
}), 400
|
|
else:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 12 - Endpoint "Enviar paquete Wake On Lan" (SINCRONO):
|
|
@app.route("/ogrepository/v1/wol", methods=['POST'])
|
|
def send_wakeonlan():
|
|
""" Este endpoint envía un paquete mágico Wake On Lan a la dirección MAC especificada, a través de la IP de broadcast especificadac.
|
|
Para ello, ejecuta el script "sendWakeOnLan.py", con la IP de broadcast como primer parámetro, y la MAC como segundo parámetro.
|
|
"""
|
|
journal.send("Running endpoint 'Enviar paquete Wake On Lan'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos los parámetros enviados en el JSON:
|
|
json_data = json.loads(request.data)
|
|
broadcast_ip = json_data.get("broadcast_ip")
|
|
mac = json_data.get("mac")
|
|
|
|
try:
|
|
journal.send("Running script 'sendWakeOnLan.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "sendWakeOnLan.py" (con los parámetros almacenados), y almacenamos el resultado:
|
|
result = subprocess.run(['sudo', 'python3', f"{script_path}/sendWakeOnLan.py", broadcast_ip, mac], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode == 0:
|
|
journal.send("Script result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Wake On Lan packet sended successfully"
|
|
}), 200
|
|
else:
|
|
journal.send(f"Script result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": result.stderr
|
|
}), 500
|
|
except Exception as error_description:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 13 - Endpoint "Enviar una Imagen mediante UDPcast" (ASINCRONO):
|
|
@app.route("/ogrepository/v1/udpcast", methods=['POST'])
|
|
def send_udpcast():
|
|
""" Este endpoint envía mediante UDPcast la imagen que recibe como primer parámetro, con los datos de transferencia que recibe en los demás parámetros.
|
|
Para ello, ejecuta el script "sendFileMcast.py", con la imagen como primer parámetro, y los demás en una cadena (como segundo parámetro).
|
|
"""
|
|
journal.send("Running endpoint 'Enviar una Imagen mediante UDPcast'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos los parámetros enviados en el JSON:
|
|
json_data = json.loads(request.data)
|
|
image_id = json_data.get("ID_img")
|
|
port = json_data.get("port")
|
|
method = json_data.get("method")
|
|
ip = json_data.get("ip")
|
|
bitrate = json_data.get("bitrate")
|
|
nclients = json_data.get("nclients")
|
|
maxtime = json_data.get("maxtime")
|
|
|
|
# Obtenemos el nombre y la extensión de la imagen (y el subdirectorio de OU, si fuera el caso):
|
|
param_dict = get_image_params(image_id, "repo")
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir la llamada al script, o para devover un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['sudo', 'python3', f"{script_path}/sendFileMcast.py", f"{param_dict['name']}.{param_dict['extension']}", f"{port}:{method}:{ip}:{bitrate}:{nclients}:{maxtime}"]
|
|
else:
|
|
journal.send("Image not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image not found"
|
|
}), 400
|
|
|
|
try:
|
|
journal.send("Running script 'sendFileMcast.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "sendFileMcast.py" (con los parámetros almacenados), y almacenamos el resultado (pero sin esperar a que termine el proceso):
|
|
result = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Comprobamos si está corriendo el proceso correspondiente de "udp-sender" (esperando 5 segundos para darle tiempo a iniciarse):
|
|
sleep(5)
|
|
process_running = search_process('udp-sender', f"{param_dict['name']}.{param_dict['extension']}")
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode is None and process_running == True:
|
|
journal.send("Script result OK (ReturnCode: None), and process running", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Sending image..."
|
|
}), 200
|
|
else:
|
|
journal.send("Script result KO (Image send failed)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image send failed"
|
|
}), 500
|
|
except subprocess.CalledProcessError as error:
|
|
journal.send(f"Script result KO (Process Exception: {str(error)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"process exeption": str(error)
|
|
}), 500
|
|
except Exception as error_description:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 14 - Endpoint "Enviar una Imagen mediante UFTP" (ASINCRONO):
|
|
@app.route("/ogrepository/v1/uftp", methods=['POST'])
|
|
def send_uftp():
|
|
""" Este endpoint envía mediante UFTP la imagen que recibe como primer parámetro, con los datos de transferencia que recibe en los demás parámetros.
|
|
Para ello, ejecuta el script "sendFileUFTP.py", con la imagen como primer parámetro, y los demás en una cadena (como segundo parámetro).
|
|
NOTA: Es necesario que los clientes se hayan puesto en escucha previamente (ejecutando el script "listenUFTPD.py").
|
|
"""
|
|
journal.send("Running endpoint 'Enviar una Imagen mediante UFTP'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos los parámetros enviados en el JSON:
|
|
json_data = json.loads(request.data)
|
|
image_id = json_data.get("ID_img")
|
|
port = json_data.get("port")
|
|
ip = json_data.get("ip")
|
|
bitrate = json_data.get("bitrate")
|
|
|
|
# Obtenemos el nombre y la extensión de la imagen (y el subdirectorio de OU, si fuera el caso):
|
|
param_dict = get_image_params(image_id, "repo")
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir la llamada al script, o para devover un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['sudo', 'python3', f"{script_path}/sendFileUFTP.py", f"{param_dict['name']}.{param_dict['extension']}", f"{port}:{ip}:{bitrate}"]
|
|
else:
|
|
journal.send("Image not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image not found"
|
|
}), 400
|
|
|
|
try:
|
|
journal.send("Running script 'sendFileUFTP.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "sendFileUFTP.py" (con los parámetros almacenados), y almacenamos el resultado (pero sin esperar a que termine el proceso):
|
|
result = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Comprobamos si está corriendo el proceso correspondiente de "uftp" (esperando 5 segundos para darle tiempo a iniciarse):
|
|
sleep(5)
|
|
process_running = search_process('uftp', f"{param_dict['name']}.{param_dict['extension']}")
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode is None and process_running == True:
|
|
journal.send("Script result OK (ReturnCode: None), and process running", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Sending image..."
|
|
}), 200
|
|
else:
|
|
journal.send("Script result KO (Image send failed)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image send failed"
|
|
}), 500
|
|
except subprocess.CalledProcessError as error:
|
|
journal.send(f"Script result KO (Process Exception: {str(error)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"process exeption": str(error)
|
|
}), 500
|
|
except Exception as error_description:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 15 - Endpoint "Enviar una Imagen mediante P2P" (ASINCRONO):
|
|
@app.route("/ogrepository/v1/p2p", methods=['POST'])
|
|
def send_p2p():
|
|
""" Este endpoint inicia el tracker "bttrack" y el seeder "bittornado", en el directorio de imágenes (sirviendo todas las imágenes).
|
|
Para ello, ejecuta los scripts "runTorrentTracker.py" y "runTorrentSeeder.py", que no reciben parámetros.
|
|
"""
|
|
journal.send("Running endpoint 'Enviar una Imagen mediante P2P'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos los parámetros enviados en el JSON:
|
|
json_data = json.loads(request.data)
|
|
image_id = json_data.get("ID_img")
|
|
|
|
# Obtenemos el nombre y la extensión de la imagen (y el subdirectorio de OU, si fuera el caso):
|
|
param_dict = get_image_params(image_id, "repo")
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir las llamadas a los scripts, o para devover un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd_tracker = ['sudo', 'python3', f"{script_path}/runTorrentTracker.py"]
|
|
cmd_seeder = ['sudo', 'python3', f"{script_path}/runTorrentSeeder.py"]
|
|
base_path = repo_path.rstrip('/') # Le quito la última barra para poder buscar correctamente en los procesos
|
|
else:
|
|
journal.send("Image not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image not found"
|
|
}), 400
|
|
|
|
# Ejecutamos los scripts "runTorrentSeeder.py" y "runTorrentSeeder.py", que no reciben parámetros.
|
|
# NOTA: No almacenamos la salida ni comprobamos los errores, porque los procesos quedarán corriendo hasta que se finalicen manualmente,
|
|
# por lo que no podemos comprobar el returncode (luego comprobaremos si los procesos se han iniciado correctamente).
|
|
journal.send("Running script 'runTorrentTracker.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
subprocess.Popen(cmd_tracker)
|
|
|
|
journal.send("Running script 'runTorrentSeeder.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
subprocess.Popen(cmd_seeder)
|
|
|
|
# Comprobamos si el tracker y el seeder están corriendo, y si apuntan al directorio que le hemos pasado
|
|
# (esperamos 10 segundos antes de hacerlo, porque los procesos no se inician inmediatamente):
|
|
sleep(10)
|
|
tracker_running = search_process('bttrack', base_path)
|
|
seeder_running = search_process('btlaunchmany', base_path)
|
|
|
|
# Evaluamos las comprobaciones anteriores, para devolver la respuesta que corresponda:
|
|
if tracker_running and seeder_running:
|
|
journal.send("Scripts results OK (ReturnCode: None), and processes running", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Tracker and Seeder serving image correctly"
|
|
}), 200
|
|
else:
|
|
journal.send("Scripts results KO (Tracker or/and Seeder not runnig)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Tracker or Seeder (or both) not running"
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 16 - Endpoint "Ver Estado de Transmisiones UDPcast" (SINCRONO):
|
|
@app.route("/ogrepository/v1/udpcast", methods=['GET'])
|
|
def get_udpcast_info():
|
|
""" Este endpoint devuelve información sobre los procesos de "udp-sender" activos, en formato json,
|
|
lo que en la práctica permite comprobar las transferencias UDPcast activas.
|
|
Para ello, ejecuta el script "getUDPcastInfo.py", que no recibe parámetros.
|
|
"""
|
|
journal.send("Running endpoint 'Ver Estado de Transmisiones UDPcast'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
try:
|
|
journal.send("Running script 'getUDPcastInfo.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "getUDPcastInfo.py", y almacenamos el resultado:
|
|
result = subprocess.run(['sudo', 'python3', f"{script_path}/getUDPcastInfo.py"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos la respuesta:
|
|
if result.returncode == 0:
|
|
journal.send("Script result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": json.loads(result.stdout)
|
|
}), 200
|
|
else:
|
|
journal.send(f"Script result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": result.stderr
|
|
}), 500
|
|
except Exception as error_description:
|
|
if "exit status 1" in str(error_description):
|
|
journal.send("No UDPcast active transmissions", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "No UDPCast active transmissions"
|
|
}), 400
|
|
else:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 17 - Endpoint "Ver Estado de Transmisiones UFTP" (SINCRONO):
|
|
@app.route("/ogrepository/v1/uftp", methods=['GET'])
|
|
def get_uftp_info():
|
|
""" Este endpoint devuelve información sobre los procesos de "uftp" activos, en formato json,
|
|
lo que en la práctica permite comprobar las transferencias UFTP activas.
|
|
Para ello, ejecuta el script "getUFTPInfo.py", que no recibe parámetros.
|
|
"""
|
|
journal.send("Running endpoint 'Ver Estado de Transmisiones UFTP'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
try:
|
|
journal.send("Running script 'getUFTPInfo.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "getUFTPInfo.py", y almacenamos el resultado:
|
|
result = subprocess.run(['sudo', 'python3', f"{script_path}/getUFTPInfo.py"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos la respuesta:
|
|
if result.returncode == 0:
|
|
journal.send("Script result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": json.loads(result.stdout)
|
|
}), 200
|
|
else:
|
|
journal.send(f"Script result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": result.stderr
|
|
}), 500
|
|
except Exception as error_description:
|
|
if "exit status 1" in str(error_description):
|
|
journal.send("No UFTP active transmissions", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "No UFTP active transmissions"
|
|
}), 400
|
|
else:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 18 - Endpoint "Cancelar Transmisión UDPcast" (SINCRONO):
|
|
@app.route("/ogrepository/v1/udpcast/images/<string:imageId>", methods=['DELETE'])
|
|
def stop_udpcast(imageId):
|
|
""" Este endpoint cancela la transmisión UDPcast de la imagen que recibe como parámetro, finalizando el proceso "udp-sender" asociado.
|
|
Para ello, ejecuta el script "stopUDPcast.py", pasándole el nombre de la imagen.
|
|
"""
|
|
journal.send("Running endpoint 'Cancelar Transmisión UDPcast'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Obtenemos el nombre y la extensión de la imagen:
|
|
param_dict = get_image_params(imageId, "repo")
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir la llamada al script, o para devover un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['sudo', 'python3', f"{script_path}/stopUDPcast.py", f"{param_dict['name']}.{param_dict['extension']}"]
|
|
else:
|
|
journal.send("Image not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image not found"
|
|
}), 400
|
|
|
|
try:
|
|
journal.send("Running script 'stopUDPcast.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "stopUDPcast.py" (con los parámetros almacenados), y almacenamos el resultado:
|
|
result = subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode == 0:
|
|
journal.send("Script result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Image transmission canceled successfully"
|
|
}), 200
|
|
else:
|
|
journal.send(f"Script result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": result.stderr
|
|
}), 500
|
|
except Exception as error_description:
|
|
if "exit status 3" in str(error_description):
|
|
journal.send("No UDPCast active transmissions for specified image", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "No UDPCast active transmissions for specified image"
|
|
}), 400
|
|
elif "exit status 4" in str(error_description):
|
|
journal.send("Script result KO (Unexpected error checking UDPcast transmissions)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Unexpected error checking UDPcast transmissions"
|
|
}), 500
|
|
elif "exit status 5" in str(error_description):
|
|
journal.send("Script result KO (Unexpected error finalizing UDPcast transmission)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Unexpected error finalizing UDPcast transmission"
|
|
}), 500
|
|
else:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 19 - Endpoint "Cancelar Transmisión UFTP" (SINCRONO):
|
|
@app.route("/ogrepository/v1/uftp/images/<string:imageId>", methods=['DELETE'])
|
|
def stop_uftp(imageId):
|
|
""" Este endpoint cancela la transmisión UFTP de la imagen que recibe como parámetro, finalizando el proceso "uftp" asociado.
|
|
Para ello, ejecuta el script "stopUFTP.py", pasándole el nombre de la imagen.
|
|
"""
|
|
journal.send("Running endpoint 'Cancelar Transmisión UFTP'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Obtenemos el nombre y la extensión de la imagen (y el subdirectorio de OU, si fuera el caso):
|
|
param_dict = get_image_params(imageId, "repo")
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir la llamada al script, o para devover un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['sudo', 'python3', f"{script_path}/stopUFTP.py", f"{param_dict['name']}.{param_dict['extension']}"]
|
|
else:
|
|
journal.send("Image not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image not found"
|
|
}), 400
|
|
|
|
try:
|
|
journal.send("Running script 'stopUFTP.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "stopUFTP.py" (con los parámetros almacenados), y almacenamos el resultado:
|
|
result = subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode == 0:
|
|
journal.send("Script result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Image transmission canceled successfully"
|
|
}), 200
|
|
else:
|
|
journal.send(f"Script result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": result.stderr
|
|
}), 500
|
|
except Exception as error_description:
|
|
if "exit status 3" in str(error_description):
|
|
journal.send("No UFTP active transmissions for specified image", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "No UFTP active transmissions for specified image"
|
|
}), 400
|
|
elif "exit status 4" in str(error_description):
|
|
journal.send("Script result KO (Unexpected error checking UFTP transmissions)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Unexpected error checking UFTP transmissions"
|
|
}), 500
|
|
elif "exit status 5" in str(error_description):
|
|
journal.send("Script result KO (Unexpected error finalizing UFTP transmission)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Unexpected error finalizing UFTP transmission"
|
|
}), 500
|
|
else:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 20 - Endpoint "Cancelar Transmisiones P2P" (SINCRONO):
|
|
@app.route("/ogrepository/v1/p2p", methods=['DELETE'])
|
|
def stop_p2p():
|
|
""" Este endpoint cancela las transmisiones P2P activas, finalizando los procesos "btlaunchmany.bittornado" (seeder) y "bttrack" (tracker).
|
|
Para ello, ejecuta el script "stopP2P.py", que no recibe parámetros.
|
|
"""
|
|
journal.send("Running endpoint 'Cancelar Transmisiones P2P'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
try:
|
|
journal.send("Running script 'stopP2P.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Ejecutamos el script "stopP2P.py", y almacenamos el resultado:
|
|
result = subprocess.run(['sudo', 'python3', f"{script_path}/stopP2P.py"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos la respuesta:
|
|
if result.returncode == 0:
|
|
journal.send("Script result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "P2P transmissions canceled successfully"
|
|
}), 200
|
|
else:
|
|
journal.send(f"Script result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": result.stderr
|
|
}), 500
|
|
except Exception as error_description:
|
|
journal.send(f"Script result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
|
|
# --------------------------------------------------------------------------------------------
|
|
|
|
|
|
# Ejecutamos la aplicación, en el puerto "8006":
|
|
if __name__ == '__main__':
|
|
app.run(debug=True, host='0.0.0.0', port=8006)
|
|
|
|
|
|
# --------------------------------------------------------------------------------------------
|