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


This GIT repository contains the data structure of the OpenGnsys image repository.

- **api** ------ ogRepository API    
- **bin** ------ Python 3 scripts and management binaries for ogRepository.    
- **etc** ------ Configuration files and templates for ogRepository.  
- **packets** - Packages whose installation is required.        

---

## Requirements

APT Packages required

  - **uftp** (can be installed with "sudo DEBIAN_FRONTEND=noninteractive apt install uftp -y" to avoid prompting for the default path; the service must be disabled)  
  - **udpcast** (can be installed with "sudo apt install ./udpcast_20230924_amd64.deb", pointing to the package)  
  - **ctorrent** (can be installed with "sudo apt install ctorrent")  
  - **bittorrent** (can be installed with "sudo apt install bittorrent", but you must first add a Debian repository)  
  - **bittornado** (can be installed with "sudo apt install bittornado", but you must first add a Debian repository)  
  - **wakeonlan** (can be installed with "sudo apt install wakeonlan")  
  - **qemu** (can be installed with "sudo apt install qemu-utils")  
  - **partclone** (can be installed with "sudo apt install partclone")  
  - **lzop** (can be installed with "sudo apt install lzop")
  
Python libraries required

  - **flask** (can be installed with "sudo apt install python3-flask")    
  - **paramiko** (can be installed with "sudo apt install python3-paramiko")  
  - **psutil** (can be installed with "sudo apt install python3-psutil")                          
  - **flasgger** (can be installed with "sudo apt install python3-flasgger")  
  - **requests** (can be installed with "sudo apt install python3-requests", but it is not necessary on Ubuntu 24)

For all endpoints and scripts to work with the current configuration, the following directories must exist

  - **/opt/opengnsys/ogrepository/images/**
  - **/opt/opengnsys/ogrepository/images_trash/** (must be on the same partition as the previous one, or deletions and restorations will be slow)  
  - **/opt/opengnsys/ogrepository/images_virtual/** (virtual images to be converted to "img" should be copied here)  
  - **/opt/opengnsys/ogrepository/bin/** (all Python scripts and the "udp-sender" binary should be here)  
  - **/opt/opengnsys/ogrepository/api/** (the API and Swagger should be here)  
  - **/opt/opengnsys/ogrepository/etc/** (stores the "repoinfo.json" and "trashinfo.json" files)  
  - **/opt/opengnsys/ogrepository/log/** (stores the logs)

And the following file must also exist:  
  - **/opt/opengnsys/ogrepository/etc/ogAdmRepo.cfg** (from here it obtains its IP and that of ogCore)  

---

## ogRepository API

The ogRepository API provides an interface to facilitate the management of images stored in image repositories, allowing you to delete them, send them to ogLive clients (using different transmission protocols), import them from other repositories, etc.  

This document details the API endpoints, with their respective input parameters, as well as the actions they perform.  

---
### Get ogRepository Status Information    

It returns CPU, RAM, disk information, the status of certain ogRepository services and processes, and the installation status of ogGit, in JSON format.  
You can use the script "**getRepoStatus.py**", which should be called by the endpoint.  
**NOTE**: In the "services" and "processes" sections I have specified the services and processes that I found interesting, but you can add or remove as desired.

**URL:** `/ogrepository/v1/status`  
**HTTP Method:** GET

**Request Example:**

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

**Responses:**
- **500 Internal Server Error:** An error occurred while querying and/or returning the status information.
- **200 OK:** The status information was successfully retrieved.
  - **Content:** Status information in JSON format.
    ```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"
        }
    }
    ```
---
### Get Information for All Images  

It returns the information contained in the "**/opt/opengnsys/ogrepository/etc/repoinfo.json**" file (for all images stored in the repository) and in the "**/opt/opengnsys/ogrepository/etc/trashinfo.json**" file (for images in the trash).  
You can use the script "**getRepoInfo.py**", which should be called by the endpoint, and which calls "**updateRepoInfo.py**" beforehand to refresh the repository information.  
**NOTE**: The script requires passing "all" as a parameter, but the endpoint itself takes no parameters.

**URL:** `/ogrepository/v1/images`  
**HTTP Method:** GET

**Request Example:**

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

**Responses:**
- **500 Internal Server Error:** An error occurred while querying and/or returning the image information.
- **200 OK:** The image information was successfully retrieved.
  - **Content:** Image information in JSON format.
    ```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**: Image name, without extension.
    - **type**: Image extension.
    - **clientname**: Name assigned to the model from which the image was obtained.
    - **clonator**: Program used for cloning.
    - **compressor**: Program used for compression.
    - **filesystem**: Filesystem used on the cloned partition.
    - **datasize**: Image size once restored, in bytes (data size).
    - **size**: Image file size, in bytes.
    - **sum**: MD5 hash of the last MB of the image file.
    - **fullsum**: MD5 hash of the entire image file.

---
### Get Information for a Specific Image

It returns the information for the specified image, which may be in "**/opt/opengnsys/ogrepository/etc/repoinfo.json**" or in "**/opt/opengnsys/ogrepository/etc/trashinfo.json**" (if the image is in the trash).  
You can use the script "**getRepoInfo.py**", which should be called by the endpoint, and which calls "**updateRepoInfo.py**" beforehand to refresh the repository information.  
**NOTE**: The script requires passing the image name (with extension) as a parameter. This is determined in the API from the image ID (the content of the "full.sum" file).

**URL:** `/ogrepository/v1/images/{ID_img}`  
**HTTP Method:** GET

**Request Example:**

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

**Responses:**
- **500 Internal Server Error:** An error occurred while querying and/or returning the image information.
- **400 Bad Request:** The specified image was not found.
- **200 OK:** The image information was successfully retrieved.
  - **Content:** Image information in JSON format.
    ```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**: Image name, without extension.
    - **type**: Image extension.
    - **clientname**: Name assigned to the model from which the image was obtained.
    - **clonator**: Program used for cloning.
    - **compressor**: Program used for compression.
    - **filesystem**: Filesystem used on the cloned partition.
    - **datasize**: Image size once restored, in bytes (data size).
    - **size**: Image file size, in bytes.
    - **sum**: MD5 hash of the last MB of the image file.
    - **fullsum**: MD5 hash of the entire image file.

---
### Update Repository Information

Updates the information of images stored in the repository, writing to "**/opt/opengnsys/ogrepository/etc/repoinfo.json**".  
Use the script "**updateRepoInfo.py**", which should be called by the endpoint (similar to the original bash script "**checkrepo**").  
This endpoint is invoked by "**deleteImage.py**" (to refresh info after deletion) and should also be called by ogCore or ogLive when a new image is created.

**URL:** `/ogrepository/v1/images`  
**HTTP Method:** PUT

**Request Example:**

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

**Responses:**
- **500 Internal Server Error:** An error occurred while updating the image information.
- **200 OK:** Update completed successfully.

---
### Check Image Integrity

Checks the integrity of the specified image file.  
Use the script "**checkImage.py**", which compares the current file size against the ".size" file and the MD5 hash of the last MB against the ".sum" file.  
**NOTE**: The script requires passing the image name (with extension) as a parameter. This is determined in the API from the image ID (content of "full.sum").

**URL:** `/ogrepository/v1/status/images/{ID_img}`  
**HTTP Method:** GET

**Request Example:**

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

**Responses:**
- **500 Internal Server Error:** An error occurred while checking the image.
- **400 Bad Request:** The specified image was not found.
- **200 OK:** The image was successfully checked.
- **200 KO:** The image was checked but failed the test.

---
### Delete an Image

Deletes the specified image, either permanently or by moving it to the trash.  
Use the script "**deleteimage.py**", which includes trash functionality and calls "**updateRepoInfo.py**" to refresh repository info.  
**NOTE**: The script requires passing the image name (with extension) as the first parameter and "-p" for permanent deletion. The image name is determined by the API from the image ID ("full.sum"), and the deletion method is specified via the URL.

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

**URL Parameter:**  
- **method**: Deletion method ("trash" or "permanent").

**Request Example:**

```bash
curl -X DELETE -H "Authorization: $API_KEY" http://example.com/ogrepository/v1/images/22735b9070e4a8043371b8c6ae52b90d?method=trash
```

**Responses:**
- **500 Internal Server Error:** An error occurred while deleting the image.
- **400 Bad Request:** The specified image was not found.
- **200 OK:** The image was deleted successfully.

---
### Recover an Image

Recovers the specified image from the trash.  
Use the script "**recoverImage.py**", which calls "**updateRepoInfo.py**" to refresh repository info.  
**NOTE**: The script requires passing the image name (with extension) as a parameter, determined from the image ID ("full.sum").

**URL:** `/ogrepository/v1/trash/images`  
**HTTP Method:** POST

**Request Body (JSON):**
- **ID_img**: Image identifier (content of the associated "full.sum" file).

**Request Example:**

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

**Responses:**
- **500 Internal Server Error:** An error occurred while recovering the image.
- **400 Bad Request:** The specified image was not found.
- **200 OK:** The image was recovered successfully.

---
### Permanently Delete an Image from the Trash

Permanently deletes the specified image from the trash.  
Use the script "**deleteTrashImage.py**", which calls "**updateTrashInfo.py**" to refresh trash info.  
**NOTE**: The script requires passing the image name (with extension) as a parameter, determined from the image ID ("full.sum").

**URL:** `/ogrepository/v1/trash/images/{ID_img}`  
**HTTP Method:** DELETE

**Request Example:**

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

**Responses:**
- **500 Internal Server Error:** An error occurred while deleting the image.
- **400 Bad Request:** The specified image was not found.
- **200 OK:** The image was deleted successfully.

---
### Send an Image via UDPcast

Sends the specified image over Multicast using UDPcast.  
Use the script "**sendFileMcast.py**", which invokes the "**udp-sender**" binary to perform the transmission.  
**NOTE**: The script requires passing the image name (with extension) as the first parameter and transfer details as the second parameter (colon-separated). The image name is determined by the API from the image ID ("full.sum"), and the transfer details are supplied by ogCore.  
**NOTE2**: This endpoint is asynchronous, so it only reports that the image is being sent and spawns a background process (it does not notify ogCore upon completion).

**URL:** `/ogrepository/v1/udpcast`  
**HTTP Method:** POST

**Request Body (JSON):**
- **ID_img**: Image identifier (content of the associated "full.sum" file).  
- **port**: Multicast port.  
- **method**: Transmission mode ("half" or "full").  
- **ip**: Multicast IP.  
- **bitrate**: Rate (in Mbps).  
- **nclients**: Minimum number of clients.  
- **maxtime**: Maximum wait time (in seconds).

**Request Example:**

```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
```

**Responses:**
- **500 Internal Server Error:** An error occurred while sending the image.
- **400 Bad Request:** The specified image was not found.
- **200 OK:** The image is being sent via UDPcast.

---
### Get UDPcast Transmission Status

Returns PIDs of active UDPcast transmission processes and their associated images (name and ID) in JSON format, or an informational message if none are active or on error.  
Use the script "**getUDPcastInfo.py**", which should be called by the endpoint.

**URL:** `/ogrepository/v1/udpcast`  
**HTTP Method:** GET

**Request Example:**

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

**Responses:**
- **500 Internal Server Error:** An error occurred while checking UDPcast transmissions.  
- **400 Bad Request:** No active UDPcast transmissions were found.  
- **200 OK:** Active UDPcast transmission information was successfully retrieved.  
  - **Content:** Active UDPcast transmission information in JSON format.  
    ```json
    {
        "6720": {
            "image_id": "22735b9070e4a8043371b8c6ae52b90d",
            "image_name": "Ubuntu20.img"
        },
        "6721": {
            "image_id": "9e7cd32c606ebe5bd39ba212ce7aeb02",
            "image_name": "Windows10.img"
        }
    }
    ```
---
### Cancel UDPcast Transmission

Cancels the active UDPcast transmission for the specified image by stopping its "udp-sender" process.  
Use the script "**stopUDPcast.py**", which should be called by the endpoint.  
**NOTE**: This script requires passing the image name (with extension) as a parameter, determined from the image ID ("full.sum").

**URL:** `/ogrepository/v1/udpcast/images/{ID_img}`  
**HTTP Method:** DELETE

**Request Example:**

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

**Responses:**
- **500 Internal Server Error:** An error occurred while canceling the UDPcast transmission.
- **400 Bad Request:** The specified image was not found.
- **400 Bad Request:** No active UDPcast transmissions were found for the specified image.
- **200 OK:** The UDPcast transmission was successfully canceled.

---
### Send an Image via UFTP

Sends the specified image via Unicast or Multicast using UFTP.  
Use the script "**sendFileUFTP.py**", which requires destination ogLive clients to run a UFTPD daemon first (via "**listenUFTPD.py**"). This is the inverse of UDPcast: clients listen first, then the server sends.  
**NOTE**: The script requires passing the image name (with extension) as the first parameter and transfer details (colon-separated) as the second parameter. The image name is determined by the API from the image ID ("full.sum"), and the transfer details come from ogCore.  
**NOTE2**: This endpoint is asynchronous, so it only reports that the image is being sent and spawns a background process (no completion callback).

**URL:** `/ogrepository/v1/uftp`  
**HTTP Method:** POST

**Request Body (JSON):**
- **ID_img**: Image identifier (content of the associated "full.sum" file).  
- **port**: Multicast port.  
- **ip**: Unicast/Multicast IP.  
- **bitrate**: Rate ("K" for Kbps, "M" for Mbps, or "G" for Gbps).

**Request Example:**

```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
```

**Responses:**
- **500 Internal Server Error:** An error occurred while sending the image.
- **400 Bad Request:** The specified image was not found.
- **200 OK:** The image is being sent via UFTP.

---
### Get UFTP Transmission Status

Returns PIDs of active UFTP transmission processes and their associated images (name and ID) in JSON format, or an informational message if none are active or on error.  
Use the script "**getUFTPInfo.py**", which should be called by the endpoint.

**URL:** `/ogrepository/v1/uftp`  
**HTTP Method:** GET

**Request Example:**

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

**Responses:**
- **500 Internal Server Error:** An error occurred while checking UFTP transmissions.  
- **400 Bad Request:** No active UFTP transmissions were found.  
- **200 OK:** Active UFTP transmission information was successfully retrieved.  
  - **Content:** Active UFTP transmission information in JSON format.  
    ```json
    {
        "3427": {
            "image_id": "22735b9070e4a8043371b8c6ae52b90d",
            "image_name": "Ubuntu20.img"
        },
        "4966": {
            "image_id": "9e7cd32c606ebe5bd39ba212ce7aeb02",
            "image_name": "Windows10.img"
        }
    }
    ```
---
### Cancel UFTP Transmission

Cancels the active UFTP transmission for the specified image by stopping its "uftp" process.  
Use the script "**stopUFTP.py**", which should be called by the endpoint.  
**NOTE**: This script requires passing the image name (with extension) as a parameter, determined from the image ID ("full.sum").

**URL:** `/ogrepository/v1/uftp/images/{ID_img}`  
**HTTP Method:** DELETE

**Request Example:**

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

**Responses:**
- **500 Internal Server Error:** An error occurred while canceling the UFTP transmission.
- **400 Bad Request:** The specified image was not found.
- **400 Bad Request:** No active UFTP transmissions were found for the specified image.
- **200 OK:** The UFTP transmission was successfully canceled.

---
### Send an Image via P2P

Sends the specified image via P2P by starting the tracker and seeder (which will track and seed all torrents in the images directory).  
Use the scripts "**runTorrentTracker.py**" and "**runTorrentSeeder.py**", called by the endpoint.  
**NOTE**: These scripts take no parameters, but the endpoint must verify the image exists before invoking them, so ogCore must send the image ID ("full.sum") in the JSON.  
**NOTE2**: This endpoint is asynchronous, reporting the send has started and running in the background (no completion callback).

**URL:** `/ogrepository/v1/p2p`  
**HTTP Method:** POST

**Request Body (JSON):**
- **ID_img**: Image identifier (content of the associated "full.sum" file).

**Request Example:**

```bash
curl -X POST -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"ID_img":"22735b9070e4a8043371b8c6ae52b90d"}' http://example.com/ogrepository/v1/p2p
```

**Responses:**
- **500 Internal Server Error:** An error occurred while attempting to send the image.
- **400 Bad Request:** The specified image was not found.
- **200 OK:** The image is being sent via P2P.

---
### Cancel P2P Transmissions

Cancels all active P2P transmissions on this ogRepository by stopping "bttrack" and "btlaunchmany.bittornado" processes.  
Use the script "**stopP2P.py**", called by the endpoint.  
**NOTE**: There is no way to cancel a single-image transfer, as both services handle all torrents in the directory.

**URL:** `/ogrepository/v1/p2p`  
**HTTP Method:** DELETE

**Request Example:**

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

**Responses:**
- **500 Internal Server Error:** An error occurred while canceling P2P transmissions.
- **200 OK:** P2P transmissions were canceled successfully.

---
### Transfer an Image between Repositories

Imports an image from a remote repository into the local repository.  
Use the script "**importImage.py**", called by the endpoint.  
**NOTE**: The script requires passing the image name (with extension), the remote repository’s IP or hostname, and the remote user as parameters. These must be sent from ogCore (the local repository cannot derive them from a stored ID).  
**NOTE2**: This endpoint is asynchronous, reporting the transfer has started and spawning a background process that will notify ogCore upon completion.  
**NOTE3**: After import, it verifies integrity by comparing "sum" and "size" files; if successful, it runs "createTorrentSum.py" to generate the ".torrent" file and update repo info; if not, it deletes the imported files.

**URL:** `/ogrepository/v1/repo/images`  
**HTTP Method:** POST

**Request Body (JSON):**
- **image**: Image name (with extension).      
- **repo_ip**: Remote repository IP or hostname.        
- **user**: User for remote access.  

**Request Example:**

```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
```

**Responses:**
- **500 Internal Server Error:** An error occurred while transferring the image.
- **400 Bad Request:** The specified image and/or remote host was not found.
- **200 OK:** The image is being transferred.

---
### Backup an Image

Backs up an image to a remote host (which need not have OpenGnsys installed) over SSH key authentication.  
Use the script "**backupImage.py**", called by the endpoint.  
**NOTE**: The script requires passing the image ID ("full.sum"), remote host IP/hostname, remote user, and remote path as parameters. The image ID is determined by the API; the others must be sent in the JSON.  
**NOTE2**: This endpoint is asynchronous, reporting the backup has started and spawning a background process that will notify ogCore upon completion.  
**NOTE3**: After backup, it verifies integrity by comparing "sum" and "size" files; if it fails, it deletes the backup.

**URL:** `/ogrepository/v1/repo/images`  
**HTTP Method:** PUT

**Request Body (JSON):**
- **ID_img**: Image identifier (content of the associated "full.sum" file).  
- **repo_ip**: Remote host IP or hostname.  
- **user**: User for SSH access.  
- **remote_path**: Remote path to store the backup.  

**Request Example:**

```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
```

**Responses:**
- **500 Internal Server Error:** An error occurred while backing up the image.
- **400 Bad Request:** The specified image and/or remote host was not found.
- **200 OK:** The backup is in progress.

---
### Convert Virtual Image to OpenGnsys Image     

Converts a virtual image (previously copied to "opt/opengnsys/ogrepository/images_virtual") into an OpenGnsys "img" using partclone and lzop.  
Use the script "**convertVMtoIMG.py**", called by the endpoint.  
**NOTE**: The script requires passing the virtual image name (with extension) and the filesystem type (blkid format) as parameters; these come from ogCore in the JSON.  
**NOTE2**: This endpoint is asynchronous, reporting the conversion has started and spawning a background process that will notify ogCore upon completion.

**URL:** `/ogrepository/v1/images/virtual`  
**HTTP Method:** POST

**Request Body (JSON):**
- **virtual_image**: Virtual image name (with extension).  
- **filesystem**: Filesystem of the partition to clone (blkid format).       

**Request Example:**  

```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
```

**Responses:**
- **500 Internal Server Error:** An error occurred while converting the virtual image.
- **400 Bad Request:** The specified virtual image was not found.
- **200 OK:** The virtual image is being converted.

---
### Convert OpenGnsys Image to Virtual Image      

Converts an OpenGnsys "img" into a virtual disk (vdi, vmdk, etc.) and stores it in "opt/opengnsys/ogrepository/images_virtual/export".  
Use the script "**convertIMGtoVM.py**", called by the endpoint.  
**NOTE**: The script requires passing the image name (with extension) and the target virtual disk extension ("vdi", "vmdk", etc.) as parameters; the image name comes from ogCore via the API, and the extension via JSON.  
**NOTE2**: This endpoint is asynchronous, reporting the conversion has started and spawning a background process that will notify ogCore upon completion.

**URL:** `/ogrepository/v1/images/virtual`  
**HTTP Method:** PUT

**Request Body (JSON):**
- **ID_img**: Image identifier (content of the associated "full.sum" file).     
- **vm_extension**: Target virtual disk extension ("vdi", "vmdk", etc.).         

**Request Example:**  

```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
```

**Responses:**
- **500 Internal Server Error:** An error occurred while converting the image to virtual.
- **400 Bad Request:** The specified image was not found.
- **200 OK:** The image is being converted to virtual.

---
### Rename an Image       

Renames the specified image (and all associated files) to the new name.  
Use the script "**renameImage.py**", called by the endpoint.  
**NOTE**: The script requires passing the current image name (without extension) and the new name as parameters. The current name is determined by the API from the image ID ("full.sum"), and the new name is provided via JSON.

**URL:** `/ogrepository/v1/images/rename`  
**HTTP Method:** POST  

**Request Body (JSON):**  
- **ID_img**: Image identifier (corresponding to the content of the associated "full.sum" file).  
- **image_new_name**: New name to assign to the image.  
  
**Example Request:**  

```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
```
**Responses:**  
- **500 Internal Server Error:** An error occurred while renaming the image.  
- **400 Bad Request:** The specified image was not found.  
- **200 OK:** The image was successfully renamed.  

---
### Create auxiliary files       

Auxiliary files ".sum", ".full.sum", ".size" and ".torrent" will be created for the specified image.  
This can be done with the "**createTorrentSum.py**" script, which must be called by the endpoint.  
**NOTE**: The script requires that the image name (with extension) be passed as a parameter. This parameter cannot be retrieved via the API from the image ID (as in other cases), because the ID corresponds to the content of the associated "full.sum" file (which will not be created until this script is executed).  
**NOTE2**: This endpoint is asynchronous, as it may take some time. It only reports that the auxiliary files are being created and spawns a parallel process that will notify ogCore when the task is complete (by calling an ogCore endpoint).  

**URL:** `/ogrepository/v1/images/torrentsum`  
**HTTP Method:** POST  

**Request Body (JSON):**  
- **image**: The name of the image (with extension).    
  
**Example Request:**  

```bash
curl -X POST -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"image":"Windows10.img"}' http://example.com/ogrepository/v1/images/torrentsum
```
**Responses:**  
- **500 Internal Server Error:** An error occurred while creating the auxiliary files.  
- **400 Bad Request:** The specified image was not found.  
- **200 OK:** The auxiliary files are being created.  

---
### Send Wake On Lan packet    

A Wake On Lan packet will be sent to the specified MAC address via the specified broadcast IP.  
This can be done with the "**sendWakeOnLan.py**" script, which must be called by the endpoint.  
**NOTE**: This script requires the broadcast IP address as the first parameter and the destination MAC address as the second parameter. These data must be sent from ogCore (in JSON).    

**URL:** `/ogrepository/v1/wol`  
**HTTP Method:** POST  

**Request Body (JSON):**  
- **broadcast_ip**: Broadcast IP to which to send the packet (can be "255.255.255.255" or a subnet broadcast IP).  
- **mac**: MAC address of the device to be powered on via Wake On Lan.  

**Example Request:**  

```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
```
**Responses:**  
- **500 Internal Server Error:** An error occurred while sending the Wake On Lan packet.  
- **200 OK:** The Wake On Lan packet was sent successfully.  

---
