refs #631 - Add 'stopUDPcast.py'

pull/1/head
Gerardo GIl Elizeire 2024-09-12 16:47:26 +02:00
parent f599e9d6fa
commit 98534c09a3
2 changed files with 207 additions and 12 deletions

View File

@ -18,7 +18,7 @@ La API de ogRepository proporciona una interfaz para facilitar la administració
El presente documento detalla los endpoints de la API, con sus respectivos parámetros de entrada, así como las acciones que llevan a cabo.
---
### Tabla de Contenido:
### Tabla de Contenido:
1. [Obtener Información de todas las Imágenes](#obtener-información-de-todas-las-imágenes) - `GET /ogrepository/v1/images/get-info`
2. [Obtener Información de una Imagen concreta](#obtener-información-de-una-imagen-concreta) - `GET /ogrepository/v1/images/get-info`
@ -33,8 +33,9 @@ El presente documento detalla los endpoints de la API, con sus respectivos pará
11. [Iniciar el Seeder P2P](#iniciar-el-seeder-p2p) - `POST /ogrepository/v1/images/run-seeder`
12. [Enviar una Imagen mediante UDPcast](#enviar-una-imagen-mediante-udpcast) - `POST /ogrepository/v1/images/send-udpcast`
13. [Enviar una Imagen mediante UFTP](#enviar-una-imagen-mediante-uftp) - `POST /ogrepository/v1/images/send-uftp`
14. [Ver Estado de Transmisiones Multicast-P2P](#ver-estado-de-transmisiones-multicast-p2p) -
15. [Cancelar Transmisión Multicast-P2P](#cancelar-transmisión-multicast-p2p) -
14. [Cancelar Transmisión UDPcast](#cancelar-transmisión-udpcast) - `POST /ogrepository/v1/images/stop-udpcast`
15. [Cancelar Transmisión P2P](#cancelar-transmisión-p2p) -
16. [Ver Estado de Transmisiones Multicast-P2P](#ver-estado-de-transmisiones-multicast-p2p) -
---
### Obtener Información de todas las Imágenes
@ -456,19 +457,41 @@ curl -X POST -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d
- **Código 400 Bad Request:** No se ha encontrado la imagen especificada.
- **Código 200 OK:** La imagen se ha enviado exitosamente.
---
### Cancelar Transmisión UDPcast
Se cancelará la transmisión por UDPcast existente de la imagen especificada como parámetro, deteniendo el proceso "udp-sender" asociado a dicha imagen.
Se puede hacer con el script "**stopUDPcast.py**", que hemos programado recientemente.
**URL:** `/ogrepository/v1/images/stop-udpcast`
**Método HTTP:** POST
**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/stop-udpcast
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al cancelar la transmisión.
- **Código 400 Bad Request:** No se ha encontrado la imagen especificada.
- **Código 200 OK:** La transmisión se ha cancelado exitosamente.
---
### Cancelar Transmisión P2P
Se cancelarán todas las transmisiones P2P activas en el ogRepository al que se envíe la orden, deteniendo los procesos "bttrack" y "btlaunchmany.bittornado".
Se debe programar un script para realizar esta tarea, ya que actualmente no hay ninguno.
**NOTA**: No he encontrado la forma de detener la transmisión de una imagen concreta, ya que "bttrack" hace tracking de todos los torrrents, y "btlaunchmany.bittornado" hace seed de todos los torrents existentes en la raíz del directorio especificado.
---
### Ver Estado de Transmisiones Multicast-P2P
Se devolverá información del estado de las transmisiones existentes, con un identificador de cada sesión multicast o P2P, y la imagen asociada.
Se debe estudiar como realizar esta tarea para cada uno de los protocolos de transmisión, ya que cada uno tiene sus particularidades, y habitualmente no tienen comandos asociados para comprobar el estado de las transmisiones.
Y tampoco está claro qué protocolo se utilizará para transimisiones Multicast (¿"UDPcast", "UFTP", o ambos?), ni qué programas se utilizarán para P2P (¿"ctorrent/bttrack" u "opentracker/Transmission"?).
**NOTA**: Posiblemente deba crearse un endpoint específico para cada uno de los protocolos que se utilicen.
---
### Cancelar Transmisión Multicast-P2P
Se cancelará la transmisión Multicast o P2P cuyo identificador se especifique como parámetro.
Aunque cancelar una transmisión Multicast o P2P es una tarea sencilla (independientemente del protocolo o programa que se utilice), en principio deberá crearse un script para cada uno de ellos.
Y la definición del endpoint depende de como se defina el endpoint anterior ("**Ver Estado de Transmisiones Multicast-P2P**"), ya que será el que determine cómo se especifica el identificador de la transmisión.
**NOTA**: Seguramente deba crearse un endpoint específico para cada uno de los protocolos que se utilicen.
---

View File

@ -0,0 +1,172 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Este script finaliza el proceso "udp-sender" asociado a la imagen que recibe como parámetro,
lo que en la práctica hará que se cancele la transmisión existente de dicha imagen mediante UDPcast.
Parámetros
------------
sys.argv[1] - Nombre completo de la imagen a cancelar su transmisión (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
Sintaxis
----------
./stopUDPcast.py [ou_subdir/]image_name|/image_path/image_name
Ejemplos
---------
./stopUDPcast.py image1.img
./stopUDPcast.py /opt/opengnsys/images/image1.img
./stopUDPcast.py ou_subdir/image1.img
./stopUDPcast.py /ou_subdir/image1.img
./stopUDPcast.py /opt/opengnsys/images/ou_subdir/image1.img
"""
# --------------------------------------------------------------------------------------------
# IMPORTS
# --------------------------------------------------------------------------------------------
import os
import sys
import subprocess
# --------------------------------------------------------------------------------------------
# VARIABLES
# --------------------------------------------------------------------------------------------
script_name = os.path.basename(__file__)
repo_path = '/opt/opengnsys/images/'
# --------------------------------------------------------------------------------------------
# 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/image1.img
Ejemplo3: {script_name} ou_subdir/image1.img
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 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 del archivo a chequear
(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 get_process_pid(file_path):
""" Busca un proceso que contenga "udp-sender" y la ruta de la imagen que recibe como parámetro,
y si lo encuentra almacena y retorna su pid asociado.
Si no encuentra ningún proceso que cumpla las condiciones (o si se produce una excepción) sale del script.
"""
try:
# Obtenemos todos los procesos, 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 "udp-sender" y la imagen especificada como parámetro:
filtered_lines = [line for line in out.split('\n') if 'udp-sender' in line and file_path in line]
# Si hemos encontrado un proceso retornamos su pid, y si no imprimimos un mensaje de error y salimos del script:
if filtered_lines != []:
pid = filtered_lines[0].split()[1]
return pid
else:
print("udp-sender process not found")
sys.exit(3)
# Si se ha producido una excepción, imprimimos el error y salimos del script:
except Exception as error_description:
print(f"Unexpected error: {error_description}")
sys.exit(4)
def kill_udp_sender(pid):
""" Finaliza el proceso asociado al pid que recibe como parámetro, e imprime el return code.
Si se produce una excepción, imprime el error y sale del script.
"""
try:
# Finalizamos el proceso asociado al pid especificado como parámetro, e imprimimos el return code:
result = subprocess.run(f"kill {pid}".split(), check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(f"ReturnCode: {result.returncode}")
# Si se ha producido una excepción, imprimimos el error y salimos del script:
except Exception as error_description:
print(f"Unexpected error: {error_description}")
sys.exit(5)
# --------------------------------------------------------------------------------------------
# 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 de imagen:
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)
# Obtenemos el pid del proceso "udp-sender" asociado a la imagen especificada:
pid = get_process_pid(file_path)
# Finalizamos el proceso "udp-sender" encontrado:
kill_udp_sender(pid)
# --------------------------------------------------------------------------------------------
if __name__ == "__main__":
main()
# --------------------------------------------------------------------------------------------