refs #631 - Add deleteImage.py

ogrepository_installer
Gerardo GIl Elizeire 2024-08-19 15:49:35 +02:00
parent 2467dd30e7
commit 9e5edcdbdf
2 changed files with 283 additions and 19 deletions

View File

@ -23,17 +23,18 @@ El presente documento detalla los endpoints de la API, con sus respectivos pará
2. [Obtener Información de una Imagen concreta](#obtener-información-de-una-imagen-concreta) - `GET /ogrepository/v1/images/{name}`
3. [Actualizar Información del Repositorio](#actualizar-información-del-repositorio) - `PUT /ogrepository/v1/images`
4. [Eliminar una Imagen](#eliminar-una-imagen) - `DELETE /ogrepository/v1/images/{name}`
5. [Importar una Imagen](#importar-una-imagen) - `POST /ogrepository/v1/images/import-image`
6. [Enviar una Imagen mediante UDPcast](#enviar-una-imagen-mediante-udpcast) - `POST /ogrepository/v1/images/{protocol}`
7. [Enviar una Imagen mediante UFTP](#enviar-una-imagen-mediante-uftp) - `POST /ogrepository/v1/images/{protocol}`
8. [Crear archivo ".torrent"](#crear-archivo-torrent) - `POST /ogrepository/v1/images/create-torrent`
9. [Enviar una Imagen mediante P2P](#enviar-una-imagen-mediante-p2p) - `POST /ogrepository/v1/images/{protocol}`
10. [Chequear integridad de Imagen](#chequear-integridad-de-imagen) - `GET /ogrepository/v1/images/check-image`
11. [Exportar una Imagen](#exportar-una-imagen) - `POST /ogrepository/v1/images/export-image`
12. [Definir Imagen Global](#definir-imagen-global) - `PUT /ogrepository/v1/images/set-global`
13. [Definir Imagen Local](#definir-imagen-local) - `PUT /ogrepository/v1/images/set-local`
14. [Ver Estado de Transmisiones Multicast-P2P](#ver-estado-de-transmisiones-multicast-p2p) -
15. [Cancelar Transmisión Multicast-P2P](#cancelar-transmisión-multicast-p2p) -
5. [Recuperar una Imagen](#recuperar-una-imagen) - `POST /ogrepository/v1/images/{name}`
6. [Importar una Imagen](#importar-una-imagen) - `POST /ogrepository/v1/images/import-image`
7. [Enviar una Imagen mediante UDPcast](#enviar-una-imagen-mediante-udpcast) - `POST /ogrepository/v1/images/{protocol}`
8. [Enviar una Imagen mediante UFTP](#enviar-una-imagen-mediante-uftp) - `POST /ogrepository/v1/images/{protocol}`
9. [Crear archivo ".torrent"](#crear-archivo-torrent) - `POST /ogrepository/v1/images/create-torrent`
10. [Enviar una Imagen mediante P2P](#enviar-una-imagen-mediante-p2p) - `POST /ogrepository/v1/images/{protocol}`
11. [Chequear integridad de Imagen](#chequear-integridad-de-imagen) - `GET /ogrepository/v1/images/check-image`
12. [Exportar una Imagen](#exportar-una-imagen) - `POST /ogrepository/v1/images/export-image`
13. [Definir Imagen Global](#definir-imagen-global) - `PUT /ogrepository/v1/images/set-global`
14. [Definir Imagen Local](#definir-imagen-local) - `PUT /ogrepository/v1/images/set-local`
15. [Ver Estado de Transmisiones Multicast-P2P](#ver-estado-de-transmisiones-multicast-p2p) -
16. [Cancelar Transmisión Multicast-P2P](#cancelar-transmisión-multicast-p2p) -
---
### Obtener Información de todas las Imágenes
@ -134,8 +135,8 @@ curl -X GET -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/imag
### Actualizar Información del Repositorio
Se actualizará la información de las imágenes almacenadas en el repositorio, reflejándola en el archivo "**/opt/opengnsys/etc/repoinfo.json**".
Se puede hacer con el script "**checkrepo**", que actualmente se ejecuta a cada minuto por crontab (indirectamente, porque es llamado por el script "**deletepreimage**", que es el que realmente se ejecuta por crontab).
Creemos que este endpoint debe ser llamado por ogCore u ogLive cada vez que se haya creado una imagen, y ejecutado desde el propio ogRepository cada vez que se elimine una imagen.
Se puede hacer con el script "**updateRepoInfo.py**", que hemos programado recientemente (y que es similar al script bash original "**checkrepo**").
Este endpoint es llamado por el script "**deleteImage.py**" (para actualizar la información cada vez que se elimine una imagen), y creemos que también debe ser llamado por ogCore u ogLive cada vez que se haya creado una imagen.
**URL:** `/ogrepository/v1/images`
**Método HTTP:** PUT
@ -152,25 +153,48 @@ curl -X PUT -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/imag
---
### Eliminar una Imagen
Se eliminará la imagen especificada como parámetro.
Se puede hacer con el script "**deleteimage**", que actualmente no se utiliza (lo que se hace ahora es eliminar todas las imágenes marcadas con ".delete", mediante el script "deletepreimage", que se ejecuta por crontab a cada minuto).
Además, el script "deleteimage" debería llamar al script "**checkrepo**", para actualizar la información del repositorio una vez eliminada la imagen.
**NOTA**: En el pliego se solicita una función "papelera", para lo que habría que modificar los scripts existentes (y posiblemente crear otros endpoints, como "recuperar imagen de la papelera", por ejemplo).
Se eliminará la imagen especificada como parámetro, pudiendo eliminarla permanentemente o enviarla a la papelera.
Se puede hacer con el script "**deleteimage.py**", que hemos programado recientemente (y que incluye la funcionalidad "papelera"), y que a su vez llama al script "**updateRepoInfo.py**", para actualizar la información del repositorio.
**URL:** `/ogrepository/v1/images/{name}`
**Método HTTP:** DELETE
**Cuerpo de la Solicitud (JSON):**
- **ou_subdir**: Subdirectorio correspondiente a la OU (o "none" si no es el caso).
- **method**: Método de eliminación (puede ser "trash" o "permanent").
**Ejemplo de Solicitud:**
```bash
curl -X DELETE -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/images/Windows10
curl -X DELETE -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"ou_subdir":"none", "method":"trash"}' http://example.com/ogrepository/v1/images/Windows10.img
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al eliminar la imagen.
- **Código 400 Bad Request:** No se ha encontrado la imagen especificada.
- **Código 200 OK:** La imagen se eliminó exitosamente.
---
### Recuperar una Imagen
Se recuperará la imagen especificada como parámetro, desde la papelera.
Se puede hacer con el script "**recoverImage.py**", que hemos programado recientemente, y que a su vez llama al script "**updateRepoInfo.py**", para actualizar la información del repositorio.
**URL:** `/ogrepository/v1/images/{name}`
**Método HTTP:** POST
**Cuerpo de la Solicitud (JSON):**
- **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 '{"ou_subdir":"none"}' http://example.com/ogrepository/v1/images/Windows10.img
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al recuperar la imagen.
- **Código 400 Bad Request:** No se ha encontrado la imagen especificada.
- **Código 200 OK:** La imagen se recuperó exitosamente.
---
### Importar una Imagen

View File

@ -0,0 +1,240 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Este script elimina la imagen que recibe como parámetro (y todos sus archivos asociados), moviendo los archivos a la papelera
(respetando el subdirectorio correspondiente a la OU, si fuera el caso), o eliminándolos permanentemente si se especifica el parámetro "-p".
Es similar al script bash original (cuyo nombre es "deleteimage", a secas), pero este no incluía la funcionalidad papelera.
Llama al script "updateRepoInfo.py", para actualizar la información del repositorio.
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/image1.img
- Ejemplo3: ou_subdir/image1.img
- Ejemplo4: /ou_subdir/image1.img
- Ejemplo5: /opt/opengnsys/images/ou_subdir/image1.img
sys.argv[2] - Parámetro opcional para especificar que la eliminación sea permanente (sin papelera).
- Ejemplo: -p
Sintaxis
----------
./deleteImage.py [ou_subdir/]image_name|/image_path/image_name [-p]
Ejemplos
---------
./deleteImage.py image1.img -p
./deleteImage.py /opt/opengnsys/images/image1.img -p
./deleteImage.py ou_subdir/image1.img -p
./deleteImage.py /ou_subdir/image1.img
./deleteImage.py /opt/opengnsys/images/ou_subdir/image1.img
"""
# --------------------------------------------------------------------------------------------
# IMPORTS
# --------------------------------------------------------------------------------------------
import os
import sys
import shutil
import pwd
import grp
import subprocess
# --------------------------------------------------------------------------------------------
# VARIABLES
# --------------------------------------------------------------------------------------------
script_name = os.path.basename(__file__)
repo_path = '/opt/opengnsys/images/'
trash_path = '/opt/opengnsys/images_trash/'
update_repo_script = '/opt/opengnsys/py_scripts/updateRepoInfo.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 [-p]
Ejemplo1: {script_name} image1.img -p
Ejemplo2: {script_name} /opt/opengnsys/images/image1.img -p
Ejemplo3: {script_name} ou_subdir/image1.img -p
Ejemplo4: {script_name} /ou_subdir/image1.img
Ejemplo5: {script_name} /opt/opengnsys/images/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 sin parámetros, se muestra un error y la ayuda, y se sale del script:
if len(sys.argv) == 1:
print(f"{script_name} Error: Formato incorrecto: Se debe especificar al menos 1 parámetro")
show_help()
sys.exit(0)
# Si se ejecuta el script con el parámetro "help", se muestra la ayuda, y se sale del script:
elif len(sys.argv) == 2 and sys.argv[1] == "help":
show_help()
sys.exit(1)
# Si se ejecuta el script con el parámetro "help" y más parámetros, se muestra un error y la ayuda, y se sale del script:
elif len(sys.argv) > 2 and sys.argv[1] == "help":
print(f"{script_name} Error: Formato incorrecto: Para invocar la ayuda, se debe especificar 'help' como único parámetro")
show_help()
sys.exit(2)
# Si se ejecuta el script con 2 parámetros y el segundo es diferente de "-p", se muestra un error y la ayuda, y se sale del script:
elif len(sys.argv) == 3 and sys.argv[2] != "-p":
print(f"{script_name} Error: Formato incorrecto: El segundo parámetro solo puede ser '-p'")
show_help()
sys.exit(3)
# Si se ejecuta el script con más de 2 parámetros, se muestra un error y la ayuda, y se sale del script:
elif len(sys.argv) > 3:
print(f"{script_name} Error: Formato incorrecto: Se debe especificar 1 o 2 parámetros")
show_help()
sys.exit(4)
def build_file_path():
""" Construye la ruta completa al archivo a eliminar
(agregando "/opt/opengnsys/images/" 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 "repo_path"
# (porque corresponderá al subdirectorio de una OU), eliminamos la barra:
if param_path.startswith('/') and not param_path.startswith(repo_path):
param_path = param_path.lstrip('/')
# Construimos la ruta completa:
if not param_path.startswith(repo_path):
file_path = os.path.join(repo_path, param_path)
else:
file_path = param_path
return file_path
def create_trash_folder():
""" Crea el directorio correspondiente a la papelera, y le asigna propietarios y permisos.
Evidentemente, esta función solo es llamada cuando no existe el directorio.
"""
# Obtenemos el UID del usuario "root" y el GID del grupo "opengnsys":
uid = pwd.getpwnam('root').pw_uid
gid = grp.getgrnam('opengnsys').gr_gid
# Creamos el directorio correspondiente a la papelera:
os.mkdir(trash_path)
# Asignamos el usuario y el grupo propietarios del directorio:
os.chown(trash_path, uid, gid)
# Asignamos permisos "775" al directorio :
os.chmod(trash_path, 0o775)
def delete_normal_image(file_path, method, extensions):
""" Elimina la imagen "normal" que recibe en el parámetro "file_path", y todos sus archivos asociados,
moviéndolos a la papelera o eliminándolos permanentemente (en función del parámetro "method").
"""
# 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 o lo movemos a la papelera
# (dependiendo del valor del parámetro "method"):
if os.path.exists(file_to_remove):
if method == 'trash':
shutil.move(file_to_remove, trash_path)
elif method == 'permanent':
os.remove(file_to_remove)
def delete_ou_image(file_path, method, extensions):
""" Elimina la imagen basada en OU que recibe en el parámetro "file_path", y todos sus archivos asociados,
moviéndolos a la papelera o eliminándolos permanentemente (en función del parámetro "method").
"""
# 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 o lo movemos a la papelera (dependiendo del valor del parámetro "method"),
# y en el último caso lo situamos en un subdirectorio correspondiente a la OU:
if os.path.exists(file_to_remove):
if method == 'trash':
ou_subdir = file_to_remove.split('/')[4]
# Comprobamos si en la papelera existe un subdirectorio correspondiente a la OU (y si no existe lo creamos):
if not os.path.exists(f"{trash_path}{ou_subdir}"):
os.mkdir(f"{trash_path}{ou_subdir}")
shutil.move(file_to_remove, f"{trash_path}{ou_subdir}")
elif method == 'permanent':
os.remove(file_to_remove)
def update_repo_info():
""" Actualiza la información del repositorio, ejecutando el script "updateRepoInfo.py".
Como se ve, es necesario que el script se ejecute como sudo, o dará error.
"""
try:
result = subprocess.run(['sudo', 'python3', update_repo_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()
# Comprobamos si existe el directorio correspondiente a la papelera, y en caso contrario lo creamos:
if not os.path.exists(trash_path):
print("Creating trash folder...")
create_trash_folder()
# Especificamos el método de eliminación (permanente o utilizando la papelera):
if len(sys.argv) == 3 and sys.argv[2] == "-p":
method = 'permanent'
else:
method = 'trash'
# Creamos una lista con las extensiones de los archivos asociados a la imagen
# (incluyendo ninguna extensión, que corresponde a la propia imagen):
extensions = ['', '.sum', '.full.sum', '.torrent', '.info', '.info.checked']
# Evaluamos la cantidad de barras que hay en la ruta de la imagen, para diferenciar entre imágenes "normales" y basadas en OU
# (y llamamos a la función correspondiente para eliminarla):
if file_path.count('/') == 4:
print("Deleting normal image...")
delete_normal_image(file_path, method, extensions)
elif file_path.count('/') == 5:
print("Deleting OU based image...")
delete_ou_image(file_path, method, extensions)
# Actualizamos la información del repositorio, ejecutando el script "updateRepoInfo.py":
print("Updating Repository Info...")
update_repo_info()
# --------------------------------------------------------------------------------------------
if __name__ == "__main__":
main()
# --------------------------------------------------------------------------------------------