2125 lines
135 KiB
Python
2125 lines
135 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
|
|
import hashlib
|
|
import psutil
|
|
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
|
|
vm_path = '/opt/opengnsys/ogrepository/images_virtual/' # 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_DEBUG")
|
|
|
|
IPcore = None
|
|
with open(config_file, 'r') as file:
|
|
for line in file:
|
|
if line.startswith('IPcore'):
|
|
IPcore = line.split('=')[1].strip()
|
|
journal.send(f"ogCore IP obtained ({IPcore})", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'INFO', 'operation':'Run function get_IPcore', 'desc':'ogCore IP obtained ({IPcore})'}}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return IPcore
|
|
if IPcore is None:
|
|
journal.send("Can't obtain ogCore IP", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'operation':'Run function get_IPcore', 'desc':'Unable to obtain ogCore IP'}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return "IP no encontrada en el archivo de configuración"
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
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_DEBUG")
|
|
|
|
# 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')
|
|
journal.send("Image found in repository JSON file", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'operation':'Run function get_image_params', 'desc':'Image found in repository JSON file'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
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')
|
|
journal.send("Image found in trash JSON file", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'operation':'Run function get_image_params', 'desc':'Image found in trash JSON file'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return result
|
|
|
|
# Si no encontramos la imagen, retornamos "None":
|
|
journal.send("Image not found in JSON file", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'operation':'Run function get_image_params', 'desc':'Image not found in JSON file'}", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
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_DEBUG")
|
|
|
|
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_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'operation':'Run function search_process', 'desc':'Process found'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return True
|
|
else:
|
|
journal.send("Process not found", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'operation':'Run function search_process', 'desc':'Process not found'}", PRIORITY=journal.LOG_WARNING, 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 'search_process' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'operation':'Run function search_process', 'desc':'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_DEBUG")
|
|
|
|
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 (con claves):
|
|
ssh_client.connect(hostname=remote_ip, port=22, username=remote_user, passphrase='')
|
|
|
|
# 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_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'operation':'Run function check_remote_connection', 'desc':'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 'check_remote_connection' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'operation':'Run function check_remote_connection', 'desc':'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_DEBUG")
|
|
|
|
# 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 (con claves):
|
|
ssh_client.connect(hostname=remote_ip, port=22, username=remote_user, passphrase='')
|
|
|
|
# Iniciamos un cliente SFTP:
|
|
sftp_client = ssh_client.open_sftp()
|
|
|
|
# Si la imagen no existe, retornamos el mensaje correspondiente:
|
|
try:
|
|
sftp_client.stat(image_file_path)
|
|
except IOError:
|
|
return "Remote image not found"
|
|
|
|
# Si la imagen existe pero está bloqueada, retornamos el mensaje correspondiente:
|
|
try:
|
|
sftp_client.stat(f"{image_file_path}.lock")
|
|
return "Remote image is locked"
|
|
except IOError:
|
|
print("Remote image is not locked, as expected")
|
|
|
|
# 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, y si existe la imagen y sus archivos asociados.
|
|
Cuando ya no exista el archivo ".lock" (pero si los demás archivos), le comunicará a ogCore que la importación ha sido exitosa, y saldrá de bucle.
|
|
Cuando ya no exista el archivo ".lock" (pero tampoco los demás), le comunicará a ogCore que la importación ha fallado, y saldrá de bucle.
|
|
Mientras no se cumpla ninguna de las condiciones anteriores, y aun exista el archivo ".lock", seguirá haciendo la comprobación (repitiendo el bucle cada minuto).
|
|
"""
|
|
journal.send("Running function 'check_lock_local'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
|
|
# 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" (pero sí existen los demás), respondemos a ogCore (con "success: True") y salimos del bucle:
|
|
if not os.path.exists(f"{image_file_path}.lock") and os.path.exists(image_file_path) and os.path.exists(f"{image_file_path}.full.sum") and os.path.exists(f"{image_file_path}.info.checked") and os.path.exists(f"{image_file_path}.size") and os.path.exists(f"{image_file_path}.sum") and os.path.exists(f"{image_file_path}.torrent"):
|
|
journal.send("Task finalized (image unlocked)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'operation':'Run function check_lock_local', 'desc':'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,
|
|
'success': True
|
|
}
|
|
# Llamamos al endpoint de ogCore, enviando los datos del diccionario:
|
|
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id}, SUCCESS: True)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
recall_ogcore(data)
|
|
break
|
|
# Si no existe el archivo ".lock" (pero tampoco los demás), respondemos a ogCore (con "success: False") y salimos del bucle:
|
|
elif not os.path.exists(f"{image_file_path}.lock") and not os.path.exists(image_file_path) and not os.path.exists(f"{image_file_path}.full.sum") and not os.path.exists(f"{image_file_path}.info") and not os.path.exists(f"{image_file_path}.size") and not os.path.exists(f"{image_file_path}.sum") and not os.path.exists(f"{image_file_path}.torrent"):
|
|
journal.send("Imported image didn't pass the Integrity Check", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'operation':'Run function check_lock_local', 'desc':'Integrity check failed'}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos en un diccionario los datos a enviar a ogCore:
|
|
data = {
|
|
'job_id': job_id,
|
|
'success': False
|
|
}
|
|
# Llamamos al endpoint de ogCore, enviando los datos del diccionario:
|
|
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id}, SUCCESS: False)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
recall_ogcore(data)
|
|
break
|
|
# Si aun existe el archivo ".lock" (y no se han cumplido las condiciones anteriores), imprimimos un mensaje en la API:
|
|
elif os.path.exists(f"{image_file_path}.lock"):
|
|
journal.send("Task in process (.lock file exists)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
|
|
# Esperamos 1 minuto para volver a realizar la comprobación:
|
|
sleep(60)
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
def check_remote_backup(image_name, remote_ip, remote_user, remote_path, job_id):
|
|
""" Cada minuto comprueba si se ha copiado la imagen que recibe como primer parámetro (y sus archivos asociados) al equipo remoto que recibe como segundo parámetro,
|
|
y mientras eso no suceda seguirá haciendo la comprobación (en un bucle "while" que se ejecuta cada minuto).
|
|
Una vez copiados todos los archivos, chequea la integridad de la imagen, comparando el contenido de los archivos ".sum" y ".size" con los valores reales (que vuelve a calcular).
|
|
Si la comprobación es correcta saldrá del bucle, y si es incorrecta saldrá del bucle y borrará los archivos que se hayan copiado al equipo remoto
|
|
(y en ambos casos le comunicará a ogCore el resultado, llamando a la función "recall_ogcore").
|
|
"""
|
|
journal.send("Running function 'check_remote_backup'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
|
|
# 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 (con claves):
|
|
ssh_client.connect(hostname=remote_ip, port=22, username=remote_user, passphrase='')
|
|
# Iniciamos un cliente SFTP:
|
|
sftp_client = ssh_client.open_sftp()
|
|
|
|
# Esperamos 30 segundos antes de empezar a realizar la comprobación:
|
|
sleep(30)
|
|
|
|
# Creamos una lista con las extensiones de los archivos asociados a la imagen (incluyendo ninguna extensión, que corresponde a la propia imagen):
|
|
extensions = ['', '.size', '.sum', '.full.sum', '.info']
|
|
|
|
# Creamos un bucle infinito:
|
|
while True:
|
|
# Comprobamos si ya se ha copiado la imagen y cada uno de sus archivos asociados (y almacenamos el resultado):
|
|
try:
|
|
for ext in extensions:
|
|
sftp_client.stat(f"{remote_path}{image_name}{ext}")
|
|
all_files_copied = True
|
|
except IOError:
|
|
all_files_copied = False
|
|
|
|
# Si se han copiado todos los archivos, comprobamos la integridad de la imagen:
|
|
if all_files_copied == True:
|
|
journal.send("All files copied", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
|
|
try:
|
|
# Calculamos el tamaño del la imagen exportada ("size")
|
|
file_size = sftp_client.stat(f"{remote_path}{image_name}").st_size
|
|
|
|
# Calculamos el hash MD5 del último MB de la imagen exportada ("sum"):
|
|
last_mb_offset = max(0, file_size - 1024 * 1024)
|
|
with sftp_client.file(f"{remote_path}{image_name}", 'rb') as file:
|
|
file.seek(last_mb_offset)
|
|
last_mb = file.read(1024 * 1024)
|
|
file_sum = hashlib.md5(last_mb).hexdigest()
|
|
|
|
# Obtenemos el valor almacenado en el archivo ".size:
|
|
with sftp_client.file(f"{remote_path}{image_name}.size", 'r') as file:
|
|
stored_size = int(file.read().strip())
|
|
|
|
# Obtenemos el valor almacenado en el archivo ".sum:
|
|
with sftp_client.file(f"{remote_path}{image_name}.sum", 'r') as file:
|
|
stored_sum = file.read().strip().decode('utf-8')
|
|
|
|
except Exception as error:
|
|
journal.send(f"Integrity check returned an error: {error}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'operation':'Run function check_remote_backup', 'desc':'Integrity check returned an error'}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Borramos los archivos copiados, porque no hemos podido chequear la integridad de la imagen:
|
|
remove_remote_files(sftp_client, remote_path, image_name, extensions)
|
|
|
|
# Almacenamos en un diccionario los datos a enviar a ogCore:
|
|
data = {
|
|
'job_id': job_id,
|
|
'success': False
|
|
}
|
|
# Llamamos al endpoint de ogCore, enviando los datos del diccionario:
|
|
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id}, SUCCESS: False)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
recall_ogcore(data)
|
|
break
|
|
|
|
# Comprobamos si los datos almacenados coinciden con los datos obtenidos (en cuyo caso el backup habrá sido correcto):
|
|
if file_sum == stored_sum and file_size == stored_size:
|
|
journal.send("Task finalized (backup complete)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'operation':'Run function check_remote_backup', 'desc':'Backup complete'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos en un diccionario los datos a enviar a ogCore:
|
|
data = {
|
|
'job_id': job_id,
|
|
'success': True
|
|
}
|
|
# Llamamos al endpoint de ogCore, enviando los datos del diccionario:
|
|
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id}, SUCCESS: True)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
recall_ogcore(data)
|
|
break
|
|
else:
|
|
journal.send("Exported image didn't pass the Integrity Check", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'operation':'Run function check_remote_backup', 'desc':'Integrity check failed'}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Borramos los archivos copiados, porque el chequeo de la integridad de la imagen no ha sido exitoso:
|
|
remove_remote_files(sftp_client, remote_path, image_name, extensions)
|
|
|
|
# Almacenamos en un diccionario los datos a enviar a ogCore:
|
|
data = {
|
|
'job_id': job_id,
|
|
'success': False
|
|
}
|
|
# Llamamos al endpoint de ogCore, enviando los datos del diccionario:
|
|
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id}, SUCCESS: False)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
recall_ogcore(data)
|
|
break
|
|
else:
|
|
journal.send("Task in process (backup incomplete)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
|
|
# 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_DEBUG")
|
|
|
|
# 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"):
|
|
journal.send("Task in process (auxiliar files remaining)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
# Si ya se han creado todos los archivos auxiliares, imprimimos un mensaje en la API, respondemos a ogCore y salimos del bucle:
|
|
else:
|
|
journal.send("Task finalized (all auxilar files created)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'operation':'Run function check_aux_files', 'desc':'Auxiliar files created'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Obtenemos el valor del archivo "full.sum", que corresponde al ID:
|
|
with open(f"{image_file_path}.full.sum", 'r') as file:
|
|
image_id = file.read().strip('\n')
|
|
|
|
# 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_DEBUG")
|
|
recall_ogcore(data)
|
|
break
|
|
# Esperamos 10 segundos para volver a realizar la comprobación:
|
|
sleep(10)
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
def check_virtual_image_conversion(image_name, job_id):
|
|
""" Cada minuto comprueba si existe la imagen convertida (y sus archivos asociados), o si no existe ninguno de los archivos que se crean en el proceso.
|
|
Cuando ya no exista el archivo ".lock" (pero si los demás archivos), le comunicará a ogCore que la conversión ha sido exitosa, y saldrá de bucle.
|
|
Cuando no exista ninguno de los archivos que se crean en el proceso (incluyendo la imagen convertida), le comunicará a ogCore que la conversión ha fallado, y saldrá de bucle.
|
|
Mientras no se cumpla ninguna de las condiciones anteriores, seguirá haciendo la comprobación (repitiendo el bucle cada minuto).
|
|
Lo utiliza el endpoint "Convertir imagen virtual a imagen OpenGnsys".
|
|
"""
|
|
journal.send("Running function 'check_virtual_image_conversion'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
|
|
# Esperamos 30 segundos, para dar tiempo a que se cree algún archivo:
|
|
sleep(30)
|
|
|
|
# Construimos la ruta de la imagen (una vez convertida):
|
|
image_file_path = f"{repo_path}{image_name}.img"
|
|
|
|
# Creamos un bucle infinito:
|
|
while True:
|
|
# Si ya no existe el archivo ".lock" (pero sí existen los demás), respondemos a ogCore (con "success: True") y salimos del bucle:
|
|
if not os.path.exists(f"{image_file_path}.lock") and os.path.exists(image_file_path) and os.path.exists(f"{image_file_path}.full.sum") and os.path.exists(f"{image_file_path}.info.checked") and os.path.exists(f"{image_file_path}.size") and os.path.exists(f"{image_file_path}.sum") and os.path.exists(f"{image_file_path}.torrent"):
|
|
journal.send("Task finalized (Virtual image converted)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'operation':'Run function check_virtual_image_conversion', 'desc':'Virtual image converted'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos en un diccionario los datos a enviar a ogCore:
|
|
data = {
|
|
'job_id': job_id,
|
|
'success': True
|
|
}
|
|
# Llamamos al endpoint de ogCore, enviando los datos del diccionario:
|
|
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id}, SUCCESS: True)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
recall_ogcore(data)
|
|
break
|
|
|
|
# Si no existe ninguno de los archivos que se crean en el proceso (incluyendo la imagen convertida), respondemos a ogCore (con "success: False") y salimos del bucle:
|
|
elif not os.path.exists(f"{vm_path}{image_name}.raw") and not os.path.exists(f"{vm_path}{image_name}.img") and not os.path.exists(f"{vm_path}{image_name}.img.lzo") and not os.path.exists(f"{repo_path}{image_name}.img"):
|
|
journal.send("Virtual image conversion failed", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'operation':'Run function check_virtual_image_conversion', 'desc':'Virtual image conversion failed'}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos en un diccionario los datos a enviar a ogCore:
|
|
data = {
|
|
'job_id': job_id,
|
|
'success': False
|
|
}
|
|
# Llamamos al endpoint de ogCore, enviando los datos del diccionario:
|
|
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id}, SUCCESS: False)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
recall_ogcore(data)
|
|
break
|
|
# Si no se han cumplido las condiciones anteriores), imprimimos un mensaje en la API:
|
|
else:
|
|
journal.send("Task in process (Conversion not finalized)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
|
|
# Esperamos 1 minuto para volver a realizar la comprobación:
|
|
sleep(60)
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
def check_virtual_image_reconversion(image_name, vm_extension, job_id):
|
|
""" Cada minuto comprueba si existe la imagen virtual exportada y si ya no existe ninguno de los archivos que se crean en el proceso (o si ya no existen estos archivos ni la imagen exportada).
|
|
En el primer caso, le comunicará a ogCore que la conversión ha sido exitosa y saldrá de bucle, y en el segundo caso, le comunicará a ogCore que la conversión ha fallado, y saldrá de bucle.
|
|
Mientras no se cumpla ninguna de las condiciones anteriores, seguirá haciendo la comprobación (repitiendo el bucle cada minuto).
|
|
Lo utiliza el endpoint "Convertir imagen OpenGnsys a imagen virtual".
|
|
"""
|
|
journal.send("Running function 'check_virtual_image_reconversion'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
|
|
# Esperamos 30 segundos, para dar tiempo a que se cree algún archivo:
|
|
sleep(30)
|
|
|
|
# Construimos la ruta de la imagen virtual (una vez exportada), y la ruta de exportación:
|
|
virtual_image_file_path = f"{vm_path}export/{image_name}.{vm_extension}"
|
|
virtual_export_path = f"{vm_path}export/"
|
|
|
|
# Creamos un bucle infinito:
|
|
while True:
|
|
# Si ya no existen los archivos que se crean durante la conversión, pero si la imagen virtual exportada, respondemos a ogCore (con "success: True") y salimos del bucle:
|
|
if not os.path.exists(f"{virtual_export_path}disk.raw") and not os.path.exists(f"{virtual_export_path}{image_name}.img") and os.path.exists(virtual_image_file_path):
|
|
journal.send("Task finalized (Image converted to virtual)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'operation':'Run function check_virtual_image_reconversion', 'desc':'Image converted to virtual'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos en un diccionario los datos a enviar a ogCore:
|
|
data = {
|
|
'job_id': job_id,
|
|
'success': True
|
|
}
|
|
# Llamamos al endpoint de ogCore, enviando los datos del diccionario:
|
|
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id}, SUCCESS: True)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
recall_ogcore(data)
|
|
break
|
|
|
|
# Si no existen los archivos que se crean durante la conversión, pero tampoco la imagen virtual exportada, respondemos a ogCore (con "success: False") y salimos del bucle:
|
|
elif not os.path.exists(f"{virtual_export_path}disk.raw") and not os.path.exists(f"{virtual_export_path}{image_name}.img") and not os.path.exists(virtual_image_file_path):
|
|
journal.send("Image conversion to virtual failed", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'operation':'Run function check_virtual_image_reconversion', 'desc':'Image conversion to virtual failed'}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Almacenamos en un diccionario los datos a enviar a ogCore:
|
|
data = {
|
|
'job_id': job_id,
|
|
'success': False
|
|
}
|
|
# Llamamos al endpoint de ogCore, enviando los datos del diccionario:
|
|
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id}, SUCCESS: False)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
recall_ogcore(data)
|
|
break
|
|
# Si no se han cumplido las condiciones anteriores), imprimimos un mensaje en la API:
|
|
else:
|
|
journal.send("Task in process (Conversion not finalized)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
|
|
# Esperamos 1 minuto para volver a realizar la comprobación:
|
|
sleep(60)
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
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_DEBUG")
|
|
|
|
# Almacenamos la IP de ogCore:
|
|
ogcore_ip = get_IPcore()
|
|
|
|
# Almacenamos la URL del endpoint de ogCore:
|
|
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_DEBUG")
|
|
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:
|
|
journal.send(f"HTTP Status Code: {response.status_code}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
#journal.send(f"HTTP Response: {response.text}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'INFO', 'operation':'Run function recall_ogcore', 'desc':'HTTP Status Code response: {response.status_code}'}}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
def check_file_exists(file_path):
|
|
""" Comprueba la existencia del archivo cuya ruta recibe como parámetro.
|
|
Si el archivo existe devuelve "True", y si no devuelve "False".
|
|
"""
|
|
journal.send("Running function 'check_file_exists'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
|
|
# Comprobamos si existe el archivo de la ruta "file_path":
|
|
if os.path.exists(file_path):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
def remove_remote_files(sftp_client, remote_path, image_name, extensions):
|
|
""" Borra la imagen "image_name" y sus archivos asociados (cuyas extensiones están almacenadas en la lista "extensions")
|
|
del equipo remoto al que nos hemos conectado previamente (mediante el objeto "sftp_client", que recibe como primer parámetro).
|
|
Es llamada por la función "check_remote_backup", cuando la imagen exportada no pasa el test de integridad.
|
|
"""
|
|
journal.send("Running function 'remove_remote_files'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
|
|
# Iteramos las extensiones de la lista "extensions", para eliminar la imagen "image_name" y sus archivos asociados:
|
|
for ext in extensions:
|
|
try:
|
|
sftp_client.stat(f"{remote_path}{image_name}{ext}")
|
|
sftp_client.remove(f"{remote_path}{image_name}{ext}")
|
|
journal.send(f"File with extension {ext} removed", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
except IOError:
|
|
journal.send(f"File with extension {ext} doesn't exist", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
def check_free_space(image_name_full, path):
|
|
""" Comprueba si hay suficiente espacio en disco para convertir la imagen que recibe como parámetro
|
|
(4 veces el tamaño del archivo), devolviendo "True" si lo hay, y "False" si no lo hay.
|
|
Lo utilizan los endpoints "Convertir imagen virtual a imagen OpenGnsys" y "Convertir imagen OpenGnsys a imagen virtual".
|
|
"""
|
|
# Obtenemos el tamaño de la imagen:
|
|
img_size = int(os.path.getsize(f"{path}{image_name_full}"))
|
|
# Obtenemos la cantidad de espacio libre en disco:
|
|
disk = psutil.disk_usage('/')
|
|
free_space = int(disk.free)
|
|
|
|
# Si no hay suficiente espacio libre en disco (4 veces el tamaño de la imagen), devolvemos "False", y en caso contrario "True":
|
|
if free_space < (img_size * 4):
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
|
|
|
|
# --------------------------------------------------------------------------------------------
|
|
# 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_DEBUG")
|
|
|
|
try:
|
|
journal.send("Running script 'getRepoStatus.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
# Ejecutamos el script "getRepoStatus.py", y almacenamos el resultado:
|
|
result = subprocess.run(['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 'getRepoStatus.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script getRepoStatus.py', 'desc':'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 'getRepoStatus.py' result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script getRepoStatus.py', 'desc':'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 'getRepoStatus.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script getRepoStatus.py', 'desc':'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_DEBUG")
|
|
|
|
try:
|
|
journal.send("Running script 'getRepoInfo.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
# Ejecutamos el script "getRepoInfo.py" (con el parámetro "all"), y almacenamos el resultado:
|
|
result = subprocess.run(['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 'getRepoInfo.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script getRepoInfo.py', 'desc':'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 'getRepoInfo.py' result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script getRepoInfo.py', 'desc':'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 'getRepoInfo.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script getRepoInfo.py', 'desc':'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_DEBUG")
|
|
|
|
# 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 devolver un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['python3', f"{script_path}/getRepoInfo.py", f"{param_dict['name']}.{param_dict['extension']}"]
|
|
else:
|
|
journal.send("Image not found", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint get_repo_image_info', 'desc': 'Warning: Image not found'}", PRIORITY=journal.LOG_WARNING, 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_DEBUG")
|
|
# 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 'getRepoInfo.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script getRepoInfo.py', 'desc':'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 'getRepoInfo.py' result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script getRepoInfo.py', 'desc':'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 'getRepoInfo.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script getRepoInfo.py', 'desc':'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_DEBUG")
|
|
|
|
try:
|
|
journal.send("Running script 'updateRepoInfo.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
# Ejecutamos el script "updateRepoInfo.py" (sin parámetros), y almacenamos el resultado:
|
|
result = subprocess.run(['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 'updateRepoInfo.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script updateRepoInfo.py', 'desc':'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 'updateRepoInfo.py' result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script updateRepoInfo.py', 'desc':'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 'updateRepoInfo.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script updateRepoInfo.py', 'desc':'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_DEBUG")
|
|
|
|
# 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 devolver un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['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_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint check_image', 'desc':'Warning: Image not found'}", PRIORITY=journal.LOG_WARNING, 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_DEBUG")
|
|
# 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 'checkImage.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script checkImage.py', 'desc':'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 'checkImage.py' result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script checkImage.py', 'desc':'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 'checkImage.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script checkImage.py', 'desc':'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_DEBUG")
|
|
|
|
# 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 devolver un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
if method == "permanent":
|
|
cmd = ['python3', f"{script_path}/deleteImage.py", f"{param_dict['name']}.{param_dict['extension']}", '-p']
|
|
elif method == "trash":
|
|
cmd = ['python3', f"{script_path}/deleteImage.py", f"{param_dict['name']}.{param_dict['extension']}"]
|
|
else:
|
|
journal.send("Incorrect method (must be 'permanent' or 'trash')", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint delete_image', 'desc':'Warning: Incorrect method (must be permanent or trash)'}", PRIORITY=journal.LOG_WARNING, 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_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint delete_image', 'desc':'Warning: Image not found (inexistent or deleted)'}", PRIORITY=journal.LOG_WARNING, 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_DEBUG")
|
|
# 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 'deleteImage.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script deleteImage.py', 'desc':'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 'deleteImage.py' result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script deleteImage.py', 'desc':'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 'deleteImage.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script deleteImage.py', 'desc':'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_DEBUG")
|
|
|
|
# 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 devolver un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['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_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint recover_image', 'desc':'Warning: Image not found (inexistent or recovered previously)'}", PRIORITY=journal.LOG_WARNING, 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_DEBUG")
|
|
# 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 'recoverImage.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script recoverImage.py', 'desc':'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 'recoverImage.py' result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script recoverImage.py', 'desc':'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 'recoverImage.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script recoverImage.py', 'desc':'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_DEBUG")
|
|
|
|
# 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 devolver un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['python3', f"{script_path}/deleteTrashImage.py", f"{param_dict['name']}.{param_dict['extension']}"]
|
|
else:
|
|
journal.send("Image not found at trash", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint delete_trash_image', 'desc':'Warning: Image not found at trash'}", PRIORITY=journal.LOG_WARNING, 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_DEBUG")
|
|
# 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 'deleteTrashImage.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script deleteTrashImage.py', 'desc':'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 'deleteTrashImage.py' result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script deleteTrashImage.py', 'desc':'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 'deleteTrashImage.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script deleteTrashImage.py', 'desc':'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_DEBUG")
|
|
|
|
# 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_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'400', 'operation':'Run endpoint import_image', 'desc':'Unable to 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_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint import_image', 'desc':'Warning: Remote image not found'}", PRIORITY=journal.LOG_WARNING, 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_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint import_image', 'desc':'Warning: Remote image is locked'}", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Remote image is locked"
|
|
}), 400
|
|
|
|
# Construimos la llamada al script:
|
|
cmd = ['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_DEBUG")
|
|
# 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"TransferImage_{''.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_DEBUG")
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode is None:
|
|
journal.send("Script 'importImage.py' result OK (ReturnCode: None)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script importImage.py', 'desc':'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_DEBUG")
|
|
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 'importImage.py' result KO (Image import failed)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script importImage.py', 'desc':'Result KO (Error: 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 'importImage.py' result KO (Process Exception: {str(error)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script importImage.py', 'desc':'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 'importImage.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script importImage.py', 'desc':'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 "Hacer backup de una Imagen" (ASINCRONO):
|
|
@app.route("/ogrepository/v1/repo/images", methods=['PUT'])
|
|
def backup_image():
|
|
""" Este endpoint exporta la imagen especificada como primer parámetro (y todos sus archivos asociados), desde el servidor local a un equipo remoto (que no tiene por qué ser un repositorio).
|
|
Para ello, ejecuta el script "backupImage.py", con el nombre de la imagen como primer parámetro, la IP o hostname del equipo remoto como segundo parámetro,
|
|
el usuario con el que conectar al equipo remoto como tercer parámetro, y la ruta remota en la que copiar la imagen como cuarto parámetro.
|
|
"""
|
|
journal.send("Running endpoint 'Hacer backup de una Imagen'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
|
|
# 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")
|
|
remote_path = json_data.get("remote_path")
|
|
|
|
# Si el úitimo carácter de "remote_path" no es una barra, la añadimos:
|
|
if remote_path[-1] != "/":
|
|
remote_path = f"{remote_path}/"
|
|
|
|
# Obtenemos el nombre y la extensión de la imagen:
|
|
param_dict = get_image_params(image_id, "repo")
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir la ruta de la imagen, o para devolver un error si no se ha encontrado la imagen (o si está bloqueada):
|
|
if param_dict:
|
|
image_name = f"{param_dict['name']}.{param_dict['extension']}"
|
|
|
|
# Comprobamos si el archivo que bloquea la imagen existe, llamando a la función "check_file_exists":
|
|
image_lock_exists = check_file_exists(f"{repo_path}{image_name}.lock")
|
|
|
|
# Si la imagen existe pero está bloqueada, devolvemos un error:
|
|
if image_lock_exists == True:
|
|
journal.send("Image is locked", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint backup_image', 'desc':'Warning: Image is locked'}", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Image is locked"
|
|
}), 400
|
|
else:
|
|
journal.send("Image not found", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint backup_image', 'desc':'Warning: Image not found'}", PRIORITY=journal.LOG_WARNING, 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_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'400', 'operation':'Run endpoint backup_image', 'desc':'Unable to connect to remote host'}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Can't connect to remote host"
|
|
}), 400
|
|
|
|
# Construimos la llamada al script:
|
|
cmd = ['python3', f"{script_path}/backupImage.py", image_name, remote_ip, remote_user, remote_path]
|
|
|
|
try:
|
|
journal.send("Running script 'backupImage.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
# Ejecutamos el script "backupImage.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"BackupImage_{''.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_DEBUG")
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode is None:
|
|
journal.send("Script 'backupImage.py' result OK (ReturnCode: None)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script backupImage.py', 'desc':'Result OK (ReturnCode: None)'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
# Si el resultado es correcto, llamamos a la función "check_remote_backup" en un hilo paralelo
|
|
# (para que compruebe si la imagen se ha acabado de copiar exitosamente):
|
|
journal.send("Calling function 'check_remote_backup'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
threading.Thread(target=check_remote_backup, args=(image_name, remote_ip, remote_user, remote_path, job_id,)).start()
|
|
|
|
# Informamos que la imagen se está exportando, y salimos del endpoint:
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Making image backup...",
|
|
"job_id": job_id
|
|
}), 200
|
|
else:
|
|
journal.send("Script 'backupImage.py' result KO (Backup image failed)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script backupImage.py', 'desc':'Result KO (Backup image failed)'}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Backup image failed"
|
|
}), 500
|
|
except subprocess.CalledProcessError as error:
|
|
journal.send(f"Script 'backupImage.py' result KO (Process Exception: {str(error)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script backupImage.py', 'desc':'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 'backupImage.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script backupImage.py', 'desc':'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_DEBUG")
|
|
|
|
# Almacenamos los parámetros enviados en el JSON:
|
|
json_data = json.loads(request.data)
|
|
image_name = json_data.get("image")
|
|
|
|
# Comprobamos si la imagen existe, llamando a la función "check_file_exists":
|
|
image_exists = check_file_exists(f"{repo_path}{image_name}")
|
|
|
|
# Si la imagen no existe, retornamos un error y salimos del endpoint:
|
|
if image_exists == False:
|
|
journal.send("Image not found", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint create_torrent_sum', 'desc':'Warning: Image not found'}", PRIORITY=journal.LOG_WARNING, 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 = ['python3', f"{script_path}/createTorrentSum.py", image_file_path]
|
|
|
|
try:
|
|
journal.send("Running script 'createTorrentSum.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
# 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_DEBUG")
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode is None:
|
|
journal.send("Script 'createTorrentSum.py' result OK (ReturnCode: None)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script createTorrentSum.py', 'desc':'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_DEBUG")
|
|
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 'createTorrentSum.py' result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script createTorrentSum.py', 'desc':'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 'createTorrentSum.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script createTorrentSum.py', 'desc':'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_DEBUG")
|
|
|
|
# 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_DEBUG")
|
|
# Ejecutamos el script "sendWakeOnLan.py" (con los parámetros almacenados), y almacenamos el resultado:
|
|
result = subprocess.run(['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 'sendWakeOnLan.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script sendWakeOnLan.py', 'desc':'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 'sendWakeOnLan.py' result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script sendWakeOnLan.py', 'desc':'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 'sendWakeOnLan.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script sendWakeOnLan.py', 'desc':'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_DEBUG")
|
|
|
|
# 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:
|
|
param_dict = get_image_params(image_id, "repo")
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir la llamada al script, o para devolver un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['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_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint send_udpcast', 'desc':'Warning: Image not found'}", PRIORITY=journal.LOG_WARNING, 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_DEBUG")
|
|
# 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 'sendFileMcast.py' result OK (ReturnCode: None), and process running", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script sendFileMcast.py', 'desc':'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 'sendFileMcast.py' result KO (Image send failed)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script sendFileMcast.py', 'desc':'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 'sendFileMcast.py' result KO (Process Exception: {str(error)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script sendFileMcast.py', 'desc':'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 'sendFileMcast.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script sendFileMcast.py', 'desc':'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_DEBUG")
|
|
|
|
# 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:
|
|
param_dict = get_image_params(image_id, "repo")
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir la llamada al script, o para devolver un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['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_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint send_uftp', 'desc':'Warning: Image not found'}", PRIORITY=journal.LOG_WARNING, 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_DEBUG")
|
|
# 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 'sendFileUFTP.py' result OK (ReturnCode: None), and process running", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script sendFileUFTP.py', 'desc':'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 'sendFileUFTP.py' result KO (Image send failed)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script sendFileUFTP.py', 'desc':'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 'sendFileUFTP.py' result KO (Process Exception: {str(error)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script sendFileUFTP.py', 'desc':'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 'sendFileUFTP.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script sendFileUFTP.py', 'desc':'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_DEBUG")
|
|
|
|
# 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:
|
|
param_dict = get_image_params(image_id, "repo")
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir las llamadas a los scripts, o para devolver un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd_tracker = ['sudo', 'python3', f"{script_path}/runTorrentTracker.py"] # Este script si que requiere ser ejecutado con "sudo"
|
|
cmd_seeder = ['sudo', 'python3', f"{script_path}/runTorrentSeeder.py"] # Este script si que requiere ser ejecutado con "sudo"
|
|
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_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint send_p2p', 'desc':'Warning: Image not found'}", PRIORITY=journal.LOG_WARNING, 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_DEBUG")
|
|
subprocess.Popen(cmd_tracker)
|
|
|
|
journal.send("Running script 'runTorrentSeeder.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
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 'runTorrentTracker.py' and 'runTorrentSeeder.py' results OK (ReturnCodes: None), and processes running", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run scripts runTorrentTracker.py and runTorrentSeeder.py', 'desc':'Results OK (ReturnCodes: 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 'runTorrentTracker.py' and 'runTorrentSeeder.py' results KO (Tracker or/and Seeder not runnig)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run scripts runTorrentTracker.py and runTorrentSeeder.py', 'desc':'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_DEBUG")
|
|
|
|
try:
|
|
journal.send("Running script 'getUDPcastInfo.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
# Ejecutamos el script "getUDPcastInfo.py", y almacenamos el resultado:
|
|
result = subprocess.run(['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 'getUDPcastInfo.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script getUDPcastInfo.py', 'desc':'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 'getUDPcastInfo.py' result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script getUDPcastInfo.py', 'desc':'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_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run script getUDPcastInfo.py', 'desc':'Warning: No UDPcast active transmissions'}", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "No UDPCast active transmissions"
|
|
}), 400
|
|
else:
|
|
journal.send(f"Script 'getUDPcastInfo.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script getUDPcastInfo.py', 'desc':'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_DEBUG")
|
|
|
|
try:
|
|
journal.send("Running script 'getUFTPInfo.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
# Ejecutamos el script "getUFTPInfo.py", y almacenamos el resultado:
|
|
result = subprocess.run(['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 'getUFTPInfo.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script getUFTPInfo.py', 'desc':'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 'getUFTPInfo.py' result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script getUFTPInfo.py', 'desc':'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_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run script getUFTPInfo.py', 'desc':'Warning: No UFTP active transmissions'}", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "No UFTP active transmissions"
|
|
}), 400
|
|
else:
|
|
journal.send(f"Script 'getUFTPInfo.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script getUFTPInfo.py', 'desc':'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_DEBUG")
|
|
|
|
# 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 devolver un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['python3', f"{script_path}/stopUDPcast.py", f"{param_dict['name']}.{param_dict['extension']}"]
|
|
else:
|
|
journal.send("Image not found", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint stop_udpcast', 'desc':'Warning: Image not found'}", PRIORITY=journal.LOG_WARNING, 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_DEBUG")
|
|
# 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 'stopUDPcast.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script stopUDPcast.py', 'desc':'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 'stopUDPcast.py' result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script stopUDPcast.py', 'desc':'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_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run script stopUDPcast.py', 'desc':'Warning: No UDPCast active transmissions for specified image'}", PRIORITY=journal.LOG_WARNING, 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 'stopUDPcast.py' result KO (Unexpected error checking UDPcast transmissions)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script stopUDPcast.py', 'desc':'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 'stopUDPcast.py' result KO (Unexpected error finalizing UDPcast transmission)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script stopUDPcast.py', 'desc':'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 'stopUDPcast.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script stopUDPcast.py', 'desc':'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_DEBUG")
|
|
|
|
# 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 devolver un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
cmd = ['python3', f"{script_path}/stopUFTP.py", f"{param_dict['name']}.{param_dict['extension']}"]
|
|
else:
|
|
journal.send("Image not found", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint stop_uftp', 'desc':'Warning: Image not found'}", PRIORITY=journal.LOG_WARNING, 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_DEBUG")
|
|
# 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 'stopUFTP.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script stopUFTP.py', 'desc':'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 'stopUFTP.py' result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script stopUFTP.py', 'desc':'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_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run script stopUFTP.py', 'desc':'Warning: No UFTP active transmissions for specified image'}", PRIORITY=journal.LOG_WARNING, 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 'stopUFTP.py' result KO (Unexpected error checking UFTP transmissions)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script stopUFTP.py', 'desc':'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 'stopUFTP.py' result KO (Unexpected error finalizing UFTP transmission)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script stopUFTP.py', 'desc':'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 'stopUFTP.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script stopUFTP.py', 'desc':'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_DEBUG")
|
|
|
|
try:
|
|
journal.send("Running script 'stopP2P.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
# Ejecutamos el script "stopP2P.py", y almacenamos el resultado (este script si que requiere ser ejecutado con "sudo"):
|
|
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 'stopP2P.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script stopP2P.py', 'desc':'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 'stopP2P.py' result KO (Error: {result.stderr})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script stopP2P.py', 'desc':'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 'stopP2P.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script stopP2P.py', 'desc':'Result KO (Exception: {str(error_description)})'}}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 21 - Endpoint "Convertir imagen virtual a imagen OpenGnsys" (ASINCRONO):
|
|
@app.route("/ogrepository/v1/images/virtual", methods=['POST'])
|
|
def convert_virtual_image():
|
|
""" Este endpoint convierte la imagen virtual especificada como parámetro en una imagen "img" como las que se generan desde OpenGnsys
|
|
(con "partclone" y "lzop"), por lo que luego puede ser restaurada como cualquier otra imagen del repositorio.
|
|
Para ello, ejecuta el script "convertVMtoIMG.py", con el nombre de la imagen virtual como primer parámetro,
|
|
y el sistema de archivos de la partición a clonar (en formato "blkid") como segundo parámetro.
|
|
"""
|
|
journal.send("Running endpoint 'Convertir imagen virtual a imagen OpenGnsys'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
|
|
# Almacenamos los parámetros enviados en el JSON, y extraemos el nombre y la extensión:
|
|
json_data = json.loads(request.data)
|
|
vm_image_name_full = json_data.get("virtual_image")
|
|
vm_image_name = vm_image_name_full.split('.')[0]
|
|
vm_extension = vm_image_name_full.split('.')[1]
|
|
filesystem = json_data.get("filesystem").lower()
|
|
|
|
# Comprobamos si existe la imagen virtual, llamando a la función "check_file_exists":
|
|
vm_image_exists = check_file_exists(f"{vm_path}{vm_image_name_full}")
|
|
|
|
# Si la imagen virtual no existe, devolvemos un error:
|
|
if vm_image_exists == False:
|
|
journal.send("Virtual image not found", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint convert_virtual_image', 'desc':'Warning: Virtual image not found'}", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "Virtual image not found"
|
|
}), 400
|
|
|
|
# Comprobamos si ya existe una imagen "img" con el mismo nombre que la imagen virtual, llamando a la función "check_file_exists":
|
|
img_image_exists = check_file_exists(f"{repo_path}{vm_image_name}.img")
|
|
|
|
# Si existe una imagen con el mismo nombre que la imagen virtual (salvo por la extensión), devolvemos un error:
|
|
if img_image_exists == True:
|
|
journal.send("There is an image with the same name as the virtual image", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint convert_virtual_image', 'desc':'Warning: There is an image with the same name as the virtual image'}", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "There is an image with the same name as the virtual image"
|
|
}), 400
|
|
|
|
# Comprobamos si hay espacio suficiente en disco para convertir la imagen virtual (4 veces su tamaño):
|
|
enough_free_space = check_free_space(vm_image_name_full, vm_path)
|
|
|
|
# Si no hay suficiente espacio libre en disco, devolvemos un error:
|
|
if enough_free_space == False:
|
|
journal.send("There is not enough free disk space", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint convert_virtual_image', 'desc':'Warning: There is not enough free disk space'}", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "There is not enough free disk space"
|
|
}), 400
|
|
|
|
# Construimos la llamada al script:
|
|
cmd = ['python3', f"{script_path}/convertVMtoIMG.py", vm_image_name_full, filesystem]
|
|
|
|
try:
|
|
journal.send("Running script 'convertVMtoIMG.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
# Ejecutamos el script "convertVMtoIMG.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"ConvertImageFromVirtual_{''.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_DEBUG")
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode is None:
|
|
journal.send("Script 'convertVMtoIMG.py' result OK (ReturnCode: None)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script convertVMtoIMG.py', 'desc':'Result OK (ReturnCode: None)'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Si el resultado es correcto, llamamos a la función "check_virtual_image_conversion" en un hilo paralelo
|
|
# (para que compruebe si la imagen se ha acabado de convertir exitosamente):
|
|
journal.send("Calling function 'check_virtual_image_conversion'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
threading.Thread(target=check_virtual_image_conversion, args=(vm_image_name, job_id,)).start()
|
|
|
|
# Informamos que la imagen se está convirtiendo, y salimos del endpoint:
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Converting virtual image...",
|
|
"job_id": job_id
|
|
}), 200
|
|
else:
|
|
journal.send("Script 'convertVMtoIMG.py' result KO (Virtual image conversion failed)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script convertVMtoIMG.py', 'desc':'Result KO (Error: Virtual image conversion failed)'}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Virtual image conversion failed"
|
|
}), 500
|
|
except subprocess.CalledProcessError as error:
|
|
journal.send(f"Script 'convertVMtoIMG.py' result KO (Process Exception: {str(error)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script convertVMtoIMG.py', 'desc':'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 'convertVMtoIMG.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script convertVMtoIMG.py', 'desc':'Result KO (Exception: {str(error_description)})'}}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": str(error_description)
|
|
}), 500
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# 22 - Endpoint "Convertir imagen OpenGnsys a imagen virtual" (ASINCRONO):
|
|
@app.route("/ogrepository/v1/images/virtual", methods=['PUT'])
|
|
def convert_image_to_virtual():
|
|
""" Este endpoint convierte la imagen de OpenGnsys especificada como parámetro en una imagen virtual con la extensión especificada (".vdi", ".vmdk", etc).
|
|
Para ello, ejecuta el script "convertIMGtoVM.py", con el nombre de la imagen "img" como primer parámetro,
|
|
y la extensión del disco virtual destino (sin punto) como segundo parámetro.
|
|
"""
|
|
journal.send("Running endpoint 'Convertir imagen OpenGnsys a imagen virtual'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
|
|
# Almacenamos los parámetros enviados en el JSON,:
|
|
json_data = json.loads(request.data)
|
|
image_id = json_data.get("ID_img")
|
|
vm_extension = json_data.get("vm_extension").lower().lstrip('.')
|
|
|
|
# Obtenemos el nombre y la extensión de la imagen:
|
|
param_dict = get_image_params(image_id, "repo")
|
|
|
|
# Evaluamos los parámetros obtenidos, para construir la llamada al script, o para devolver un error si no se ha encontrado la imagen:
|
|
if param_dict:
|
|
image_name_full = f"{param_dict['name']}.{param_dict['extension']}"
|
|
image_name = f"{param_dict['name']}"
|
|
cmd = ['python3', f"{script_path}/convertIMGtoVM.py", image_name_full, vm_extension]
|
|
else:
|
|
journal.send("Image not found", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint convert_image_to_virtual', 'desc':'Warning: Image not found'}", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image not found"
|
|
}), 400
|
|
|
|
# Comprobamos si ya existe una imagen virtual exportada con el mismo nombre que la imagen "img" y la extensión especificada, llamando a la función "check_file_exists":
|
|
vm_image_exists = check_file_exists(f"{vm_path}export/{image_name}.{vm_extension}")
|
|
|
|
# Si existe una imagen con el mismo nombre que la imagen virtual (salvo por la extensión), devolvemos un error:
|
|
if vm_image_exists == True:
|
|
journal.send("There is an exported virtual image with the same name as the image", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint convert_image_to_virtual', 'desc':'Warning: There is an exported virtual image with the same name as the image'}", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "There is an exported virtual image with the same name as the image"
|
|
}), 400
|
|
|
|
# Comprobamos si hay espacio suficiente en disco para convertir la imagen "img" a virtual (4 veces su tamaño):
|
|
enough_free_space = check_free_space(image_name_full, repo_path)
|
|
|
|
# Si no hay suficiente espacio libre en disco, devolvemos un error:
|
|
if enough_free_space == False:
|
|
journal.send("There is not enough free disk space", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'http_code':'400', 'operation':'Run endpoint convert_image_to_virtual', 'desc':'Warning: There is not enough free disk space'}", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"exception": "There is not enough free disk space"
|
|
}), 400
|
|
|
|
try:
|
|
journal.send("Running script 'convertIMGtoVM.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
# Ejecutamos el script "convertIMGtoVM.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"ConvertImageToVirtual_{''.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_DEBUG")
|
|
|
|
# Evaluamos el resultado de la ejecución, y devolvemos una respuesta:
|
|
if result.returncode is None:
|
|
journal.send("Script 'convertIMGtoVM.py' result OK (ReturnCode: None)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script convertIMGtoVM.py', 'desc':'Result OK (ReturnCode: None)'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
|
|
# Si el resultado es correcto, llamamos a la función "check_virtual_image_reconversion" en un hilo paralelo
|
|
# (para que compruebe si la imagen se ha acabado de convertir exitosamente):
|
|
journal.send("Calling function 'check_virtual_image_reconversion'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
threading.Thread(target=check_virtual_image_reconversion, args=(image_name, vm_extension, job_id,)).start()
|
|
|
|
# Informamos que la imagen se está convirtiendo, y salimos del endpoint:
|
|
return jsonify({
|
|
"success": True,
|
|
"output": "Converting image to virtual...",
|
|
"job_id": job_id
|
|
}), 200
|
|
else:
|
|
journal.send("Script 'convertIMGtoVM.py' result KO (Image conversion to virtual failed)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script convertIMGtoVM.py', 'desc':'Result KO (Error: Image conversion to virtual failed)'}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Image conversion to virtual failed"
|
|
}), 500
|
|
except subprocess.CalledProcessError as error:
|
|
journal.send(f"Script 'convertIMGtoVM.py' result KO (Process Exception: {str(error)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script convertIMGtoVM.py', 'desc':'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 'convertIMGtoVM.py' result KO (Exception: {str(error_description)})", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
|
journal.send(f"{{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script convertIMGtoVM.py', 'desc':'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)
|
|
|
|
|
|
# --------------------------------------------------------------------------------------------
|