ogRepository - OpenGnsys Repository Manager
===========================================


Este repositorio GIT contiene la estructura de datos del repositorio de imágenes de OpenGnsys.

- **api** ------ API de ogRepository.    
- **bin** ------ Scripts en Python 3 y binarios de gestión de ogRepository.    
- **etc** ------ Ficheros y plantillas de configuración de ogRepository.  
- **packets** - Paquetes cuya instalación es requerida.        

---

## Requerimientos

Paquetes APT requeridos

  - **uftp** (se puede instalar con "sudo DEBIAN_FRONTEND=noninteractive apt install uftp -y", para que no pida la ruta predeterminada, y se debe deshabilitar el servicio)  
  - **udpcast** (se puede instalar con "sudo apt install ./udpcast_20230924_amd64.deb", apuntando al paquete)  
  - **ctorrent** (se puede instalar con "sudo apt install ctorrent")  
  - **bittorrent** (se puede instalar con "sudo apt install bittorrent", pero previamente hay que añadir un repositorio de Debian)  
  - **bittornado** (se puede instalar con "sudo apt install bittornado", pero previamente hay que añadir un repositorio de Debian)  
  - **wakeonlan** (se puede instalar con "sudo apt install wakeonlan")  
  - **qemu** (se puede instalar con "sudo apt install qemu-utils")
  - **partclone** (se puede instalar con "sudo apt install partclone") 
  - **lzop** (se puede instalar con "sudo apt install lzop")
  
Librerías Python requeridas

  - **flask** (se puede instalar con "sudo apt install python3-flask")    
  - **paramiko** (se puede instalar con "sudo apt install python3-paramiko")
  - **psutil** (se puede instalar con "sudo apt install python3-psutil")                          
  - **flasgger** (se puede instalar con "sudo apt install python3-flasgger")
  - **requests** (se puede instalar con "sudo apt install python3-requests", pero no es necesario en Ubuntu 24)

Para que todos los endpoints y scripts funcionen con la configuración actual deben existir los siguientes directorios

  - **/opt/opengnsys/ogrepository/images/**
  - **/opt/opengnsys/ogrepository/images_trash/** (debe estar en la misma partición que el anterior, o tardarán mucho las eliminaciones y restauraciones)
  - **/opt/opengnsys/ogrepository/images_virtual/** (aquí deben copiarse las imágenes virtuales que se quiera convertir a "img")  
  - **/opt/opengnsys/ogrepository/bin/** (aquí deben estar todos los scripts de Python, y el binario "udp-sender")
  - **/opt/opengnsys/ogrepository/api/** (aquí debe estar la API y el Swagger)  
  - **/opt/opengnsys/ogrepository/etc/** (aquí se guardan los archivos "repoinfo.json" y "trashinfo.json")
  - **/opt/opengnsys/ogrepository/log/** (aquí se guardan los logs)

Y también debe existir el siguiente archivo:
  - **/opt/opengnsys/ogrepository/etc/ogAdmRepo.cfg** (de aquí pilla su IP y la de ogCore)  

---

## API de ogRepository

La API de ogRepository proporciona una interfaz para facilitar la administración de las imágenes almacenadas en los repositorios de imágenes, permitiendo eliminarlas, enviarlas a clientes ogLive (con diferentes protocolos de transmisión), importarlas desde otros repositorios, etc.  

El presente documento detalla los endpoints de la API, con sus respectivos parámetros de entrada, así como las acciones que llevan a cabo.  

---
### Obtener Información de Estado de ogRepository    

Se  devolverá informacion de CPU, memoria RAM, disco duro, el estado de ciertos servicios y procesos de ogRepository, y el estado de instalación de ogGit, en formato JSON.   
Se puede utilizar el script "**getRepoStatus.py**, que debe ser llamado por el endpoint.    
**NOTA**: En los apartados "services" y "processes" he especificado los servicios y procesos que me han parecido interesantes, pero se puede añadir o eliminar los que se desee.   

**URL:** `/ogrepository/v1/status`    
**Método HTTP:** GET

**Ejemplo de Solicitud:**

```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/status  
```

**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al consultar y/o devolver la información de estado.
- **Código 200 OK:** La información de estado se obtuvo exitosamente.
  - **Contenido:** Información de estado en formato JSON.
    ```json
    {
        "oggit": {
            "installed": "True"
        },
        "cpu": {
            "used_percentage": "35%"
        },
        "ram": {
            "total": "7.8GB",
            "used": "0.3GB",
            "available": "7.2GB",
            "used_percentage": "7%"
        },
        "disk": {
            "total": "11.7GB",
            "used": "7.7GB",
            "available": "3.4GB",
            "used_percentage": "69%"
        },
        "services": {
            "ssh": "active",
            "smbd": "active",
            "rsync": "active"
        },
        "processes": {
            "udp-sender": "stopped",
            "uftp": "stopped",
            "bttrack": "stopped",
            "btlaunchmany.bittornado": "stopped"
        }
    }
    ```
---
### Obtener Información de todas las Imágenes  

Se devolverá la informacion contenida en el archivo "**/opt/opengnsys/ogrepository/etc/repoinfo.json**" (que corresponde a todas las imágenes almacenadas en el repositorio), y en el archivo "**/opt/opengnsys/ogrepository/etc/trashinfo.json**" (que corresponde a las imágenes que fueron eliminadas, que estarán en la papelera).  
Se puede utilizar el script "**getRepoInfo.py**, que debe ser llamado por el endpoint, que a su vez llama al script "**updateRepoInfo.py**", para actualizar previamente la información del repositorio.  
**NOTA**: El script requiere que en este caso se le pase "all" como parámetro, pero el endpoint se ejecuta sin parámetros.      

**URL:** `/ogrepository/v1/images`    
**Método HTTP:** GET

**Ejemplo de Solicitud:**

```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/images  
```

**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al consultar y/o devolver la información de las imágenes.
- **Código 200 OK:** La información de las imágenes se obtuvo exitosamente.
  - **Contenido:** Información de imágenes en formato JSON.
    ```json
    {
      "REPOSITORY": {
        "directory": "/opt/opengnsys/ogrepository/images",
        "images": [
          {
            "name": "Ubuntu24",
            "type": "img",
            "clientname": "Ubuntu24_clientname",
            "clonator": "partclone",
            "compressor": "lzop",
            "filesystem": "EXTFS",
            "datasize": 9859634200000,
            "size": 4505673214,
            "sum": "065a933c780ab1aaa044435ad5d4bf87",
            "fullsum": "33575b9070e4a8043371b8c6ae52b80e"
          },
          {
            "name": "Windows10",
            "type": "img",
            "clientname": "Windows10_clientname",
            "clonator": "partclone",
            "compressor": "lzop",
            "filesystem": "NTFS",
            "datasize": 24222105600000,
            "size": 13198910185,
            "sum": "8874d5ab84314f44841c36c69bb5aa82",
            "fullsum": "9e7cd32c606ebe5bd39ba212ce7aeb02"
          }
        ]
      },
      "TRASH": {
        "directory": "/opt/opengnsys/ogrepository/images_trash",
        "images": [
          {
            "name": "Ubuntu20",
            "type": "img",
            "clientname": "Ubuntu20_clientname",
            "clonator": "partclone",
            "compressor": "lzop",
            "filesystem": "EXTFS",
            "datasize": 8912896000000,
            "size": 3803794535,
            "sum": "081a933c780ab1aaa044435ad5d4bf56",
            "fullsum": "22735b9070e4a8043371b8c6ae52b90d"
          }
        ]
      }
    }
    ```
    - **name**: Nombre de la imagen, sin extensión.
    - **type**: Extensión de la imagen.
    - **clientname**: Nombre asignado al modelo del que se ha obtenido la imagen.
    - **clonator**: Programa utilizado para la clonación.
    - **compressor**: Programa utilizado para la compresión.
    - **filesystem**: Sistema de archivos utilizado en la partición clonada.
    - **datasize**: Tamaño de la imagen una vez restaurada, en bytes (tamaño de los datos).
    - **size**: Tamaño del archivo de imagen, en bytes.
    - **sum**: Hash MD5 del último MB del archivo de imagen.
    - **fullsum**: Hash MD5 de todo el archivo de imagen.

---
### Obtener Información de una Imagen concreta

Se devolverá la informacion de la imagen especificada, que puede estar en el archivo "**/opt/opengnsys/ogrepository/etc/repoinfo.json**" o en el archivo "**/opt/opengnsys/ogrepository/etc/trashinfo.json**" (en este último caso, si la imagen está en la papelera).  
Se puede utilizar el script "**getRepoInfo.py**, que debe ser llamado por el endpoint, que a su vez llama al script "**updateRepoInfo.py**", para actualizar previamente la información del repositorio.    
**NOTA**: El script requiere que en este caso se le pase el nombre de la imagen (con extensión) como parámetro. Este dato se obtiene en la API, a partir del ID de la imagen (que corresponde al contenido del archivo "full.sum").   

**URL:** `/ogrepository/v1/images/{ID_img}`  
**Método HTTP:** GET

**Ejemplo de Solicitud:**

```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/images/22735b9070e4a8043371b8c6ae52b90d
```

**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al consultar y/o devolver la información de la imagen.  
- **Código 400 Bad Request:** No se ha encontrado la imagen especificada.
- **Código 200 OK:** La información de la imagen se obtuvo exitosamente.
  - **Contenido:** Información de la imagen en formato JSON.
    ```json
    {
      "directory": "/opt/opengnsys/ogrepository/images",
      "images": [
        {
          "name": "Windows10",
          "type": "img",
          "clientname": "Windows10_clientname",
          "clonator": "partclone",
          "compressor": "lzop",
          "filesystem": "NTFS",
          "datasize": 9859634200000,
          "size": 4505673214,
          "sum": "065a933c780ab1aaa044435ad5d4bf87",
          "fullsum": "33575b9070e4a8043371b8c6ae52b80e"
        }
      ]
    }
    ```
    - **name**: Nombre de la imagen, sin extensión.
    - **type**: Extensión de la imagen.
    - **clientname**: Nombre asignado al modelo del que se ha obtenido la imagen.
    - **clonator**: Programa utilizado para la clonación.
    - **compressor**: Programa utilizado para la compresión.
    - **filesystem**: Sistema de archivos utilizado en la partición clonada.
    - **datasize**: Tamaño de la imagen una vez restaurada, en bytes (tamaño de los datos).
    - **size**: Tamaño del archivo de imagen, en bytes.
    - **sum**: Hash MD5 del último MB del archivo de imagen.
    - **fullsum**: Hash MD5 de todo el archivo de imagen.

---
### 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/ogrepository/etc/repoinfo.json**".  
Se puede hacer con el script "**updateRepoInfo.py**", que debe ser llamado por el endpoint (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

**Ejemplo de Solicitud:**

```bash
curl -X PUT -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/images
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al actualizar la información de las imágenes.
- **Código 200 OK:** La actualización se realizó exitosamente.

---
### Chequear Integridad de Imagen

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**: El script requiere que se le pase el nombre de la imagen (con extensión) como parámetro. Este dato se obtiene en la API, a partir del ID de la imagen (que corresponde al contenido del archivo "full.sum").     

**URL:** `/ogrepository/v1/status/images/{ID_img}`  
**Método HTTP:** GET

**Ejemplo de Solicitud:**

```bash
curl -X POST -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/status/images/22735b9070e4a8043371b8c6ae52b90d
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al chequear la imagen.
- **Código 400 Bad Request:** No se ha encontrado la imagen especificada.
- **Código 200 OK:** La imagen se ha chequeado exitosamente.
- **Código 200 KO:** La imagen se ha chequeado correctamente, pero no ha pasado el test.

---
### Eliminar una Imagen

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 debe ser llamado por el endpoint (y que incluye la funcionalidad "papelera"), y que a su vez llama al script "**updateRepoInfo.py**", para actualizar la información del repositorio.  
**NOTA**: El script requiere que se le pase el nombre de la imagen (con extensión) como primer parámetro, y el parámetro opcional "-p" (para que la eliminación sea permanente). El primer parámetro se obtiene en la API, a partir del ID de la imagen (que corresponde al contenido del archivo "full.sum"), pero también hay que especificar el método de eliminación en la URL, para enviar o no el parámetro opcional.   

**URL:** `/ogrepository/v1/images/{ID_img}?method={method}`  
**Método HTTP:** DELETE

**Parámetro adicional (en URL):**  
- **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/22735b9070e4a8043371b8c6ae52b90d?method=trash
```
**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 debe ser llamado por el endpoint, y que a su vez llama al script "**updateRepoInfo.py**", para actualizar la información del repositorio.  
**NOTA**: El script requiere que se le pase el nombre de la imagen (con extensión) como parámetro. Este dato se obtiene en la API, a partir del ID de la imagen (que corresponde al contenido del archivo "full.sum").   

**URL:** `/ogrepository/v1/trash/images`  
**Método HTTP:** POST

**Cuerpo de la Solicitud (JSON):**
- **ID_img**: Identificador de la imagen (correspondiente al contenido del archivo "full.sum" asociado).  

**Ejemplo de Solicitud:**

```bash
curl -X POST -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"ID_img":"22735b9070e4a8043371b8c6ae52b90d"}' http://example.com/ogrepository/v1/trash/images
```
**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.

---
### Eliminar una Imagen de la Papelera

Se eliminará permanentemente la imagen especificada como parámetro, desde la papelera.  
Se puede hacer con el script "**deleteTrashImage.py**", que debe ser llamado por el endpoint, y que a su vez llama al script "**updateTrashInfo.py**", para actualizar la información de la papelera.  
**NOTA**: El script requiere que se le pase el nombre de la imagen (con extensión) como parámetro. Este dato se obtiene en la API, a partir del ID de la imagen (que corresponde al contenido del archivo "full.sum").    

**URL:** `/ogrepository/v1/trash/images/{ID_img}`  
**Método HTTP:** DELETE

**Ejemplo de Solicitud:**

```bash
curl -X DELETE -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/trash/images/22735b9070e4a8043371b8c6ae52b90d
```
**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.

---
### Enviar una Imagen mediante UDPcast

Se enviará la imagen especificada por Multicast, mediante la aplicación UDPcast.  
Se puede hacer con el script "**sendFileMcast.py**", que a su vez llama al binario "**udp-sender**", que es quien realmente realiza el envío.   
**NOTA**: El script requiere que se le pase el nombre de la imagen (con extensión) como primer parámetro, y los datos de transferencia como segundo parámetro (en una cadena, con los datos separados por dos puntos). El primer parámetro se obtiene en la API, a partir del ID de la imagen (que corresponde al contenido del archivo "full.sum"), pero los datos de transferencia deben enviarse desde ogCore (y luego son tratados en la API, para construir la cadena correspondiente al parámetro).  
**NOTA2**: Este endpoint es asíncrono, ya que puede tardar mucho tiempo, por lo que solo informa de que la imagen se está enviando, y abre un proceso paralelo (pero no avisa a ogCore de su finalización, porque no puede comprobar cuando acaba la tarea de restauración de la imagen).     

**URL:** `/ogrepository/v1/udpcast`  
**Método HTTP:** POST

**Cuerpo de la Solicitud (JSON):**
- **ID_img**: Identificador de la imagen (correspondiente al contenido del archivo "full.sum" asociado).   
- **port**: Puerto Multicast.
- **method**: Modalidad half-duplex o full-duplex ("half" o "full").
- **ip**: IP Multicast.
- **bitrate**: Velocidad de transmisión (en Mbps).
- **nclients**: Número mínimo de clientes.
- **maxtime**: Tiempo máximo de espera.

**Ejemplo de Solicitud:**  

```bash
curl -X POST -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"ID_img":"22735b9070e4a8043371b8c6ae52b90d", "port":"9000", "method":"full", "ip":"239.194.17.2", "bitrate":"70M", "nclients":"20", "maxtime":"120"}' http://example.com/ogrepository/v1/udpcast
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al enviar la imagen.
- **Código 400 Bad Request:** No se ha encontrado la imagen especificada.
- **Código 200 OK:** La imagen se está enviando mediante UDPcast.

---
### Ver Estado de Transmisiones UDPcast

Se devolverá el pid de los procesos de transferencias UDPcast activas, y sus imágenes asociadas (con nombre e ID), en formato JSON, o un mensaje informativo si no hay procesos activos, o si se produce un error.      
Se puede hacer con el script "**getUDPcastInfo.py**", que debe ser llamado por el endpoint.     

**URL:** `/ogrepository/v1/udpcast`   
**Método HTTP:** GET

**Ejemplo de Solicitud:**

```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/udpcast
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al comprobar las transmisiones UDPcast.  
- **Código 400 Bad Request:** No se han encontrado transmisiones UDPcast activas.  
- **Código 200 OK:** La información de las transmisiones UDPcast activas se obtuvo exitosamente.  
  - **Contenido:** Información de las transmisiones UDPcast activas en formato JSON.  
    ```json
    {
        "6720": {
            "image_id": "22735b9070e4a8043371b8c6ae52b90d",
            "image_name": "Ubuntu20.img"
        },
        "6721": {
            "image_id": "9e7cd32c606ebe5bd39ba212ce7aeb02",
            "image_name": "Windows10.img"
        }
    }
    ```
---
### Cancelar Transmisión UDPcast  

Se cancelará la transmisión por UDPcast activa 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 debe ser llamado por el endpoint.     
**NOTA**: La versión actual de este script requiere que se le pase el nombre de la imagen (con extensión) como parámetro. Este dato se obtiene en la API, a partir del ID de la imagen (que corresponde al contenido del archivo "full.sum").     

**URL:** `/ogrepository/v1/udpcast/images/{ID_img}`   
**Método HTTP:** DELETE

**Ejemplo de Solicitud:**

```bash
curl -X DELETE -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/udpcast/images/22735b9070e4a8043371b8c6ae52b90d
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al cancelar la transmisión UDPcast.
- **Código 400 Bad Request:** No se ha encontrado la imagen especificada.
- **Código 400 Bad Request:** No hay transmisiones UDPcast activas para la imagen especificada.
- **Código 200 OK:** La transmisión UDPcast se ha cancelado exitosamente.
  
---
### Enviar una Imagen mediante UFTP

Se enviará la imagen especificada por Unicast o Multicast, mediante el protocolo "UFTP".  
Se puede hacer con el script "**sendFileUFTP.py**", que requiere que previamente los clientes ogLive destino se pongan en escucha con un daemon "UFTPD" (ejecutando el script "**listenUFTPD.py**"). Esto funciona al revés que "UDPcast", ya que primero se debe ejecutar un comando en los clientes, y luego en el servidor.    
**NOTA**: El script requiere que se le pase el nombre de la imagen (con extensión) como primer parámetro, y los datos de transferencia como segundo parámetro (en una cadena, con los datos separados por dos puntos). El primer parámetro se obtiene en la API, a partir del ID de la imagen (que corresponde al contenido del archivo "full.sum"), pero los datos de transferencia deben enviarse desde ogCore (y luego son tratados en la API, para construir la cadena correspondiente al parámetro).  
**NOTA2**: Este endpoint es asíncrono, ya que puede tardar mucho tiempo, por lo que solo informa de que la imagen se está enviando, y abre un proceso paralelo (pero no avisa a ogCore de su finalización, porque no puede comprobar cuando acaba la tarea de restauración de la imagen).   

**URL:** `/ogrepository/v1/uftp`   
**Método HTTP:** POST

**Cuerpo de la Solicitud (JSON):**
- **ID_img**: Identificador de la imagen (correspondiente al contenido del archivo "full.sum" asociado).  
- **port**: Puerto Multicast.
- **ip**: IP Unicast/Multicast.
- **bitrate**: Velocidad de transmisión (con "K" para Kbps, "M" para Mbps o "G" para Gbps).

**Ejemplo de Solicitud:**

```bash
curl -X POST -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"ID_img":"22735b9070e4a8043371b8c6ae52b90d", "port":"9000", "ip":"239.194.17.2", "bitrate":"1G"}' http://example.com/ogrepository/v1/uftp
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al enviar la imagen.
- **Código 400 Bad Request:** No se ha encontrado la imagen especificada.
- **Código 200 OK:** La imagen se está enviando mediante UFTP.

---
### Ver Estado de Transmisiones UFTP  

Se devolverá el pid de los procesos de transferencias UFTP activas, y sus imágenes asociadas (con nombre e ID), en formato JSON, o un mensaje informativo si no hay procesos activos, o si se produce un error.      
Se puede hacer con el script "**getUFTPInfo.py**", que debe ser llamado por el endpoint.     

**URL:** `/ogrepository/v1/uftp`   
**Método HTTP:** GET

**Ejemplo de Solicitud:**

```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/uftp
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al comprobar las transmisiones UFTP.  
- **Código 400 Bad Request:** No se han encontrado transmisiones UFTP activas.  
- **Código 200 OK:** La información de las transmisiones UFTP activas se obtuvo exitosamente.  
  - **Contenido:** Información de las transmisiones UFTP activas en formato JSON.  
    ```json
    {
        "3427": {
            "image_id": "22735b9070e4a8043371b8c6ae52b90d",
            "image_name": "Ubuntu20.img"
        },
        "4966": {
            "image_id": "9e7cd32c606ebe5bd39ba212ce7aeb02",
            "image_name": "Windows10.img"
        }
    }
    ```
---
### Cancelar Transmisión UFTP    

Se cancelará la transmisión por UFTP activa de la imagen especificada como parámetro, deteniendo el proceso "uftp" asociado a dicha imagen.    
Se puede hacer con el script "**stopUFTP.py**", que debe ser llamado por el endpoint.     
**NOTA**: La versión actual de este script requiere que se le pase el nombre de la imagen (con extensión) como parámetro. Este dato se obtiene en la API, a partir del ID de la imagen (que corresponde al contenido del archivo "full.sum").     

**URL:** `/ogrepository/v1/uftp/images/{ID_img}`   
**Método HTTP:** DELETE

**Ejemplo de Solicitud:**

```bash
curl -X DELETE -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/uftp/images/22735b9070e4a8043371b8c6ae52b90d
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al cancelar la transmisión UFTP.
- **Código 400 Bad Request:** No se ha encontrado la imagen especificada.
- **Código 400 Bad Request:** No hay transmisiones UFTP activas para la imagen especificada.
- **Código 200 OK:** La transmisión UFTP se ha cancelado exitosamente.

---
### Enviar una Imagen mediante P2P

Se enviará la imagen especificada mediante "P2P", iniciando el tracker y el seeder (que harán tracking y seed de los torrents contenidos en el directorio de imágenes).  
Se puede hacer con los scripts "**runTorrentTracker.py**" y "**runTorrentSeeder.py**", que deben ser llamados por el endpoint.   
**NOTA**: Estos scripts no reciben parámetros, pero es necesario que el endpoint compruebe si la imagen a enviar existe antes de llamarlos, por lo que se le debe enviar el ID de la imagen (que corresponde al contenido del archivo "full.sum") desde ogCore (en el JSON).  
**NOTA2**: Este endpoint es asíncrono, ya que puede tardar mucho tiempo, por lo que solo informa de que la imagen se está enviando, y abre un proceso paralelo (pero no avisa a ogCore de su finalización, porque no puede comprobar cuando acaba la tarea de restauración de la imagen).   

**URL:** `/ogrepository/v1/p2p`   
**Método HTTP:** POST

**Cuerpo de la Solicitud (JSON):**
- **ID_img**: Identificador de la imagen (correspondiente al contenido del archivo "full.sum" asociado).  

**Ejemplo de Solicitud:**

```bash
curl -X POST -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"ID_img":"22735b9070e4a8043371b8c6ae52b90d"}' http://example.com/ogrepository/v1/p2p
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al intentar enviar la imagen.
- **Código 400 Bad Request:** No se ha encontrado la imagen especificada.
- **Código 200 OK:** La imagen se está enviando mediante P2P.  

---
### Cancelar Transmisiones P2P

Se cancelarán las transmisiones P2P activas en el ogRepository al que se envíe la orden, deteniendo los procesos "bttrack" y "btlaunchmany.bittornado".  
Se puede hacer con el script "**stopP2P.py**", que debe ser llamado por el endpoint.    
**NOTA**: No he encontrado la forma de detener la transmisión de una imagen concreta, ya que "bttrack" y "btlaunchmany.bittornado" hacen tracking y seed (respectivamente) de todos los torrents existentes en la raíz del directorio especificado.  

**URL:** `/ogrepository/v1/p2p`   
**Método HTTP:** DELETE

**Ejemplo de Solicitud:**

```bash
curl -X DELETE -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/p2p
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al cancelar las transmisiones P2P.
- **Código 200 OK:** Las transmisiones P2P se han cancelado exitosamente.

---
### Transferir una Imagen entre Repositorios  

Se importará una imagen de un repositorio remoto al repositorio local (donde se ejecuta el endpoint).   
Se puede hacer con el script "**importImage.py**", que debe ser llamado por el endpoint.  
**NOTA**: El script requiere que se le pase el nombre de la imagen (con extensión) como primer parámetro, la IP o hostname del repositorio remoto como segundo parámetro, y el usuario remoto como tercer parámetro. Estos parámetros deben enviarse desde ogCore (en el JSON), porque el repositorio local no puede extraer la información de la imagen de un ID almacenado en un repositorio remoto.    
**NOTA2**: Este endpoint es asíncrono, ya que puede tardar mucho tiempo, por lo que solo informa de que la imagen se está transfiriendo, y abre un proceso paralelo, que avisará a ogCore cuando finalice la tarea (llamando a un endpoint de ogCore).   
**NOTA3**: Este endpoint comprueba si la importación se ha realizado correctamente, comparando el contenido de los archivos "sum" y "size" con los valores reales (que vuelve a calcular). Si la importación ha sido correcta llama al script "createTorrentSum.py", para crear el archivo ".torrent" (que debe crearse desde el repositorio en el que esté), y actualizar la info del repositorio. Si la importación no ha sido correcta (porque la imagen no ha pasado el check de integridad), borra los archivos importados.  

**URL:** `/ogrepository/v1/repo/images`  
**Método HTTP:** POST

**Cuerpo de la Solicitud (JSON):**
- **image**: Nombre de la imagen (con extensión).      
- **repo_ip**: Dirección IP del repositorio remoto (desde el que se importará la imagen).        
- **user**: Usuario con el que acceder al repositorio remoto.  
 
**Ejemplo de Solicitud:**

```bash
curl -X POST -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"image":"Windows10.img", "repo_ip":"192.168.56.100", "user":"opengnsys"}' http://example.com/ogrepository/v1/repo/images
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al transferir la imagen.
- **Código 400 Bad Request:** No se ha encontrado la imagen y/o el equipo remoto especificados.
- **Código 200 OK:** La imagen se está transfiriendo.

---
### Hacer Backup de una Imagen  

Se hará backup de una imagen en un equipo remoto, que no tiene por qué tener OpenGnsys instalado, pero que debe poder conectar por SSH (mediante claves) con el repositorio local.   
Se puede hacer con el script "**backupImage.py**", que debe ser llamado por el endpoint.   
**NOTA**: El script requiere que se le pase el nombre de la imagen (con extensión) como primer parámetro, la IP o hostname del repositorio remoto como segundo parámetro, el usuario remoto como tercer parámetro, y la ruta remota en la que se guardará el backup como cuarto parámetro. El primer parámetro se obtiene en la API, a partir del ID de la imagen (que corresponde al contenido del archivo "full.sum"), pero la IP del repositorio remoto, el usuario remoto y la ruta remota deben enviarse en el JSON.      
**NOTA2**: Este endpoint es asíncrono, ya que puede tardar mucho tiempo, por lo que solo informa de que la imagen se está exportando, y abre un proceso paralelo, que avisará a ogCore cuando finalice la tarea (llamando a un endpoint de ogCore).  
**NOTA3**: Este endpoint comprueba si el backup se ha realizado correctamente, comparando el contenido de los archivos "sum" y "size" con los valores reales (que vuelve a calcular). Si el backup no ha sido correcto (porque la imagen no ha pasado el check de integridad), borra los archivos exportados.   

**URL:** `/ogrepository/v1/repo/images`  
**Método HTTP:** PUT

**Cuerpo de la Solicitud (JSON):**
- **ID_img**: Identificador de la imagen (correspondiente al contenido del archivo "full.sum" asociado).  
- **repo_ip**: Dirección IP del repositorio remoto (al que se exportrará la imagen).  
- **user**: Usuario con el que acceder al repositorio remoto.   
- **remote_path**: Ruta remota en la que copiar la imagen.  
 
**Ejemplo de Solicitud:**

```bash
curl -X PUT -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"ID_img":"22735b9070e4a8043371b8c6ae52b90d", "repo_ip":"192.168.56.100", "user":"opengnsys", "remote_path":"/home/opengnsys"}' http://example.com/ogrepository/v1/repo/images
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al hacer backup de la imagen.
- **Código 400 Bad Request:** No se ha encontrado la imagen y/o el equipo remoto especificados.
- **Código 200 OK:** Se está haciendo backup de la imagen.  

---
### Convertir Imagen Virtual a Imagen OpenGnsys     

Se convertirá la imagen virtual especificada (que debe haberse copiado previamente en la ruta "opt/opengnsys/ogrepository/images_virtual") en una imagen "img" como las que se generan desde OpenGnsys (con "partclone" y "lzop").   
Se puede hacer con el script "**convertVMtoIMG.py**", que debe ser llamado por el endpoint.   
**NOTA**: El script requiere que se le pase el nombre de la imagen virtual (con extensión) como primer parámetro, y el sistema de archivos de la partición a clonar como segundo parámetro (en formato "blkid"). Estos parámetros deben enviarse desde ogCore (en el JSON).     
**NOTA2**: Este endpoint es asíncrono, ya que puede tardar mucho tiempo, por lo que solo informa de que la imagen virtual se está convirtiendo, y abre un proceso paralelo, que avisará a ogCore cuando finalice la tarea (llamando a un endpoint de ogCore).   

**URL:** `/ogrepository/v1/images/virtual`  
**Método HTTP:** POST

**Cuerpo de la Solicitud (JSON):**
- **virtual_image**: Nombre de la imagen virtual (con extensión).  
- **filesystem**: Sistema de archivos de la partición a clonar, en formato "blkid".       
  
**Ejemplo de Solicitud:**  

```bash
curl -X POST -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"virtual_image":"UbuntuVM.vdi", "filesystem":"ext4"}' http://example.com/ogrepository/v1/images/virtual
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al convertir la imagen virtual.
- **Código 400 Bad Request:** No se ha encontrado la imagen virtual especificada.
- **Código 200 OK:** La imagen virtual se está convirtiendo.  

---
### Convertir Imagen OpenGnsys a Imagen Virtual      

Se convertirá la imagen "img" especificada en una imagen virtual con la extensión especificada ("vdi", "vmdk", etc), guardándola en la ruta "opt/opengnsys/ogrepository/images_virtual/export".   
Se puede hacer con el script "**convertIMGtoVM.py**", que debe ser llamado por el endpoint.   
**NOTA**: El script requiere que se le pase el nombre de la imagen (con extensión) como primer parámetro, y la extensión del disco virtual destino ("vdi", "vmdk", etc) como segundo parámetro. El primer parámetro se obtiene en la API, a partir del ID de la imagen (que corresponde al contenido del archivo "full.sum"), pero la extensión del disco virtual debe enviarse en el JSON.      
**NOTA2**: Este endpoint es asíncrono, ya que puede tardar mucho tiempo, por lo que solo informa de que la imagen se está convirtiendo a virtual, y abre un proceso paralelo, que avisará a ogCore cuando finalice la tarea (llamando a un endpoint de ogCore).   

**URL:** `/ogrepository/v1/images/virtual`  
**Método HTTP:** PUT

**Cuerpo de la Solicitud (JSON):**
- **ID_img**: Identificador de la imagen (correspondiente al contenido del archivo "full.sum" asociado).     
- **vm_extension**: Extensión del disco virtual destino ("vdi", "vmdk", etc).         
  
**Ejemplo de Solicitud:**  

```bash
curl -X PUT -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"ID_img":"22735b9070e4a8043371b8c6ae52b90d", "vm_extension":"vdi"}' http://example.com/ogrepository/v1/images/virtual
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al convertir la imagen a virtual.
- **Código 400 Bad Request:** No se ha encontrado la imagen especificada.
- **Código 200 OK:** La imagen se está convirtiendo a virtual. 

---
### Renombrar una Imagen       

Se renombrará la imagen especificada como primer parámetro (y todos sus archivos asociados), asignando el nombre especificado como segundo parámetro.  
Se puede hacer con el script "**renameImage.py**", que debe ser llamado por el endpoint.   
**NOTA**: El script requiere que se le pase el nombre de la imagen (sin extensión) como primer parámetro, y el nuevo nombre a asignar como segundo parámetro. El primer parámetro se obtiene en la API, a partir del ID de la imagen (que corresponde al contenido del archivo "full.sum"), pero el nuevo nombre a asignar debe enviarse en el JSON.     

**URL:** `/ogrepository/v1/images/rename`  
**Método HTTP:** POST

**Cuerpo de la Solicitud (JSON):**
- **ID_img**: Identificador de la imagen (correspondiente al contenido del archivo "full.sum" asociado).   
- **image_new_name**: Nuevo nombre a asignar a la imagen.  
  
**Ejemplo de Solicitud:**  

```bash
curl -X POST -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"ID_img":"22735b9070e4a8043371b8c6ae52b90d", "image_new_name":"Ubuntu_BKP"}' http://example.com/ogrepository/v1/images/rename
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al renombrar la imagen.
- **Código 400 Bad Request:** No se ha encontrado la imagen especificada.
- **Código 200 OK:** La imagen se ha renombrado exitosamente.  

---
### Crear archivos auxiliares       

Se crearán los archivos ".sum", ".full.sum", ".size" y ".torrent", para la imagen especificada como parámetro.   
Se puede hacer con el script "**createTorrentSum.py**", que debe ser llamado por el endpoint.   
**NOTA**: El script requiere que se le pase el nombre de la imagen (con extensión) como parámetro. Este parámetro no puede obtenerse en la API, a partir del ID de imagen (como en otros casos), porque el ID corresponde al contenido del archivo "full.sum" asociado (que no estará creado hasta que no se ejecute este script).   
**NOTA2**: Este endpoint es asíncrono, ya que puede tardar cierto tiempo, por lo que solo informa de que los archivos auxiliares se están creando, y abre un proceso paralelo, que avisará a ogCore cuando finalice la tarea (llamando a un endpoint de ogCore).   

**URL:** `/ogrepository/v1/images/torrentsum`  
**Método HTTP:** POST

**Cuerpo de la Solicitud (JSON):**
- **image**: Nombre de la imagen (con extensión).    
  
**Ejemplo de Solicitud:**  

```bash
curl -X POST -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"image":"Windows10.img"}' http://example.com/ogrepository/v1/images/torrentsum
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al crear los archivos auxiliares.
- **Código 400 Bad Request:** No se ha encontrado la imagen especificada.
- **Código 200 OK:** Los archivos auxiliares se están creando.  

---
### Enviar paquete Wake On Lan    

Se enviará un paquete Wake On Lan a la dirección MAC especificada, a través de la IP de broadcast especificada.  
Se puede hacer con el script "**sendWakeOnLan.py**", que debe ser llamado por el endpoint.  
**NOTA**: Este script requiere que se le pase la dirección IP de broadcast como primer parámetro, y la dirección MAC destino como segundo parámetro. Estos datos deben enviarse desde ogCore (en el JSON).    

**URL:** `/ogrepository/v1/wol`  
**Método HTTP:** POST

**Cuerpo de la Solicitud (JSON):**
- **broadcast_ip**: IP de broadcast a la que enviar el paquete (puede ser "255.255.255.255", o la IP de broadcast de una subred).  
- **mac**: Dirección MAC del equipo que se desea encender via Wake On Lan.  

**Ejemplo de Solicitud:**  

```bash
curl -X POST -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"broadcast_ip":"255.255.255.255", "mac":"00:19:99:5c:bb:bb"}' http://example.com/ogrepository/v1/wol
```
**Respuestas:**
- **Código 500 Internal Server Error:** Ocurrió un error al enviar el paquete Wake On Lan.  
- **Código 200 OK:** El paquete Wake On Lan se ha enviado exitosamente.  

---
