From 0c47a50ecf9d482b299d2205c5c3ecd1b9ca22d2 Mon Sep 17 00:00:00 2001 From: ggil Date: Tue, 1 Oct 2024 17:26:24 +0200 Subject: [PATCH] refs #631 - Add 'deleteTrashImage.py' --- README.md | 18 ++--- bin/deleteTrashImage.py | 164 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 11 deletions(-) create mode 100644 bin/deleteTrashImage.py diff --git a/README.md b/README.md index 7d0e02e..fe5670a 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ El presente documento detalla los endpoints de la API, con sus respectivos pará 1. [Obtener Información de todas las Imágenes](#obtener-información-de-todas-las-imágenes) - `GET /ogrepository/v1/images` 2. [Obtener Información de una Imagen concreta](#obtener-información-de-una-imagen-concreta) - `GET /ogrepository/v1/images/{ID_img}` 3. [Actualizar Información del Repositorio](#actualizar-información-del-repositorio) - `PUT /ogrepository/v1/images` -4. [Chequear integridad de Imagen](#chequear-integridad-de-imagen) - `GET /ogrepository/v1/images/check-image` +4. [Chequear integridad de Imagen](#chequear-integridad-de-imagen) - `GET /ogrepository/v1/status/images/{ID_img}` 5. [Eliminar una Imagen](#eliminar-una-imagen) - `DELETE /ogrepository/v1/images/{ID_img}` 6. [Recuperar una Imagen](#recuperar-una-imagen) - `POST /ogrepository/v1/trash/images/{ID_img}` 7. [Eliminar una Imagen de la Papelera](#eliminar-una-imagen-de-la-papelera) - `DELETE /ogrepository/v1/trash/images/{ID_img}` @@ -218,19 +218,15 @@ curl -X PUT -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/imag Se comprobará la integridad del fichero de imagen especificado como parámetro. Se puede hacer con el script "**checkImage.py**", que compara el tamaño actual del archivo con el almacenado en el archivo "**.size**", y el hash MD5 del último MB del archivo con el almacenado en el archivo "**.sum**". -**NOTA**: En lugar del archivo "**.sum**", se podría usar el archivo "**.full.sum**" (que contiene el hash MD5 de todo el archivo), pero en ese caso la comprobación tardaría un poco, dependiendo del tamaño de la imagen. +**NOTA**: La versión actual de este script requiere que se le pase el nombre de la imagen (con extensión, e incluyendo el nombre del directorio correspondiente a la OU, si fuera el caso) como único parámetro. En principio, ogCore puede acceder a estos datos a partir del ID de la imagen (que hemos quedado que será el contenido del archivo "full.sum"), y la transformación de parámetros puede realizarse en el controlador PHP. -**URL:** `/ogrepository/v1/images/check-image` +**URL:** `/ogrepository/v1/status/images/{ID_img}` **Método HTTP:** GET -**Cuerpo de la Solicitud (JSON):** -- **image**: Nombre de la imagen (con extensión). -- **ou_subdir**: Subdirectorio correspondiente a la OU (o "none" si no es el caso). - **Ejemplo de Solicitud:** ```bash -curl -X POST -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"image":"Windows10.img", "ou_subdir":"none"}' http://example.com/ogrepository/v1/images/check-image +curl -X POST -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/status/images/{ID_img} ``` **Respuestas:** - **Código 500 Internal Server Error:** Ocurrió un error al chequear la imagen. @@ -285,8 +281,8 @@ curl -X POST -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/tra ### Eliminar una Imagen de la Papelera Se eliminará permanentemente la imagen especificada como parámetro, desde la papelera. -Se puede hacer con el script "**deleteimage.py**", que hemos programado recientemente, y que a su vez llama al script "**updateRepoInfo.py**", para actualizar la información del repositorio. -**NOTA**: La versión actual de este script requiere que se le pase la ruta y nombre de la imagen como primer parámetro, y el parámetro opcional "-p" (para que la eliminación sea permanente). En principio, ogCore puede acceder a estos datos a partir del ID de la imagen (que hemos quedado que será el contenido del archivo "full.sum"), y la transformación de parámetros puede realizarse en el controlador PHP. +Se puede hacer con el script "**deleteTrashImage.py**", que hemos programado recientemente, y que a su vez llama al script "**updateTrashInfo.py**", para actualizar la información de la papelera. +**NOTA**: La versión actual de este script requiere que se le pase el nombre de la imagen (con extensión, e incluyendo el nombre del directorio correspondiente a la OU, si fuera el caso) como único parámetro. En principio, ogCore puede acceder a estos datos a partir del ID de la imagen (que hemos quedado que será el contenido del archivo "full.sum"), y la transformación de parámetros puede realizarse en el controlador PHP. **URL:** `/ogrepository/v1/trash/images/{ID_img}` **Método HTTP:** DELETE @@ -306,7 +302,7 @@ curl -X DELETE -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/t Se importará una imagen de un repositorio remoto al repositorio local. Se puede hacer con el script "**importImage.py**", que hemos programado recientemente. -**NOTA**: La versión actual de este script requiere que se le pase el nombre de la imagen (con extensión, e incluyendo el nombre del directorio correspondiente a la OU, si fuera el caso) como primer parámetro, la IP o hostname del repositorio remoto como segundo parámetro, y el usuario remoto como tercer parámetro. En principio, ogCore puede acceder a estos datos a partir del ID de la imagen (que hemos quedado que será el contenido del archivo "full.sum"), y la transformación de parámetros puede realizarse en el controlador PHP, pero en principio habrá que especificar el usuario remoto en un json (en la URL). +**NOTA**: La versión actual de este script requiere que se le pase el nombre de la imagen (con extensión, e incluyendo el nombre del directorio correspondiente a la OU, si fuera el caso) como primer parámetro, la IP o hostname del repositorio remoto como segundo parámetro, y el usuario remoto como tercer parámetro. En principio, ogCore puede acceder a estos datos a partir del ID del repositorio y del ID de la imagen (que hemos quedado que será el contenido del archivo "full.sum"), y la transformación de parámetros puede realizarse en el controlador PHP, pero en principio habrá que especificar el usuario remoto en un json (en la URL). **URL:** `/ogrepository/v1/repo/{ID_repo}/images/{ID_img}` **Método HTTP:** POST diff --git a/bin/deleteTrashImage.py b/bin/deleteTrashImage.py new file mode 100644 index 0000000..df18372 --- /dev/null +++ b/bin/deleteTrashImage.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Este script elimina permanentemente la imagen que recibe como parámetro (y todos sus archivos asociados), desde la papelera. +Llama al script "updateTrashInfo.py", para actualizar la información de las imágenes de la papelera. + + Parámetros +------------ +sys.argv[1] - Nombre completo de la imagen a eliminar (con o sin ruta), pero incluyendo el subdirectorio correspondiente a la OU, si es el caso. + - Ejemplo1: image1.img + - Ejemplo2: /opt/opengnsys/images_trash/image1.img + - Ejemplo3: ou_subdir/image1.img + - Ejemplo4: /ou_subdir/image1.img + - Ejemplo5: /opt/opengnsys/images_trash/ou_subdir/image1.img + + Sintaxis +---------- +./deleteTrashImage.py [ou_subdir/]image_name|/image_path/image_name + + Ejemplos + --------- +./deleteTrashImage.py image1.img +./deleteTrashImage.py /opt/opengnsys/images_trash/image1.img +./deleteTrashImage.py ou_subdir/image1.img +./deleteTrashImage.py /ou_subdir/image1.img +./deleteTrashImage.py /opt/opengnsys/images_trash/ou_subdir/image1.img +""" + +# -------------------------------------------------------------------------------------------- +# IMPORTS +# -------------------------------------------------------------------------------------------- + +import os +import sys +import subprocess + + +# -------------------------------------------------------------------------------------------- +# VARIABLES +# -------------------------------------------------------------------------------------------- + +script_name = os.path.basename(__file__) +trash_path = '/opt/opengnsys/images_trash/' +update_trash_script = '/opt/opengnsys/bin/updateTrashInfo.py' + + +# -------------------------------------------------------------------------------------------- +# FUNCTIONS +# -------------------------------------------------------------------------------------------- + + + +def show_help(): + """ Imprime la ayuda, cuando se ejecuta el script con el parámetro "help". + """ + help_text = f""" + Sintaxis: {script_name} [ou_subdir/]image_name|/image_path/image_name + Ejemplo1: {script_name} image1.img + Ejemplo2: {script_name} /opt/opengnsys/images_trash/image1.img + Ejemplo3: {script_name} ou_subdir/image1.img + Ejemplo4: {script_name} /ou_subdir/image1.img + Ejemplo5: {script_name} /opt/opengnsys/images_trash/ou_subdir/image1.img + """ + print(help_text) + + +def check_params(): + """ Comprueba que se haya enviado la cantidad correcta de parámetros, y en el formato correcto. + Si no es así, muestra un mensaje de error, y sale del script. + LLama a la función "show_help" cuando se ejecuta el script con el parámetro "help". + """ + # Si se ejecuta el script con el parámetro "help", se muestra la ayuda, y se sale del script: + if len(sys.argv) == 2 and sys.argv[1] == "help": + show_help() + sys.exit(0) + # Si se ejecuta el script con más o menos de 1 parámetro, se muestra un error y la ayuda, y se sale del script: + elif len(sys.argv) != 2: + print(f"{script_name} Error: Formato incorrecto: Se debe especificar 1 parámetro") + show_help() + sys.exit(1) + + +def build_file_path(): + """ Construye la ruta completa al archivo a eliminar + (agregando "/opt/opengnsys/images_trash/" si no se ha especificado en el parámetro). + """ + param_path = sys.argv[1] + # Si la ruta comienza con una barra, pero que no corresponde a "trash_path" + # (porque corresponderá al subdirectorio de una OU), eliminamos la barra: + if param_path.startswith('/') and not param_path.startswith(trash_path): + param_path = param_path.lstrip('/') + # Construimos la ruta completa: + if not param_path.startswith(trash_path): + file_path = os.path.join(trash_path, param_path) + else: + file_path = param_path + return file_path + + +def delete_image(file_path, extensions): + """ Elimina permanentemente la imagen que recibe en el parámetro "file_path", y todos sus archivos asociados. + """ + # Iteramos las extensiones de los archivos, y construimos la ruta completa de cada uno de ellos: + for ext in extensions: + file_to_remove = f"{file_path}{ext}" + # Si el archivo actual existe, lo eliminamos permanentemente: + if os.path.exists(file_to_remove): + os.remove(file_to_remove) + + +def update_trash_info(): + """ Actualiza la información de la papelera, ejecutando el script "updateTrashInfo.py". + Como se ve, es necesario que el script se ejecute como sudo, o dará error. + """ + try: + result = subprocess.run(['sudo', 'python3', update_trash_script], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + except subprocess.CalledProcessError as error: + print(f"Error Output: {error.stderr.decode()}") + sys.exit(3) + except Exception as error: + print(f"Se ha producido un error inesperado: {error}") + sys.exit(4) + + + +# -------------------------------------------------------------------------------------------- +# MAIN +# -------------------------------------------------------------------------------------------- + + +def main(): + """ + """ + # Evaluamos si se ha enviado la cantidad correcta de parámetros, y en el formato correcto: + check_params() + + # Obtenemos la ruta completa al archivo a eliminar: + file_path = build_file_path() + + # Si no existe el archivo de imagen, imprimimos un mensaje de error y salimos del script: + if not os.path.exists(file_path): + print("Image file doesn't exist") + sys.exit(2) + + # 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', '.torrent', '.info', '.info.checked'] + + # Eliminamos la imagen y sus archivos asociados: + delete_image(file_path, extensions) + + # Actualizamos la información de la papelera, ejecutando el script "updateTrashInfo.py": + print("Updating Trash Info...") + update_trash_info() + + + +# -------------------------------------------------------------------------------------------- + +if __name__ == "__main__": + main() + +# --------------------------------------------------------------------------------------------