Skip to main content

General Informations

STORAGE SERVER TECHNICAL OVERVIEW

In the following document is breefly presented some informations about how the Elemento Storage Server works. :::info This little guide is a way to create an initial documentation of how processes works and to introduce, eventually, new developers to the basics informations they may need to work on this topic. :::

General informations

API Call Rundown

:::info Every functionality is requested via Rest API. ::: :::info StorageServer responds to api calls on port 7772 ::: Here are reported functionality (and relative endpoints and purpose) for the storage server.

:::success IMPLEMENTED:

▢️ CREATE
purpose: Create a simple volume
endpoint: http://<server_ip>:7772/api/<version>/create

▢️ LIST ACCESSIBLE VOLUMES
purpose: returns the volumes a user can access
endpoint: http://<server_ip>:7772/api/<version>/accessible

▢️ SINGLE VOLUME INFORMATIONS
purpose: Get the informations about a single volume
endpoint: http://<server_ip>:7772/api/<version>/info

▢️ DESTROY
purpose: Destroy a volume
endpoint: http://<server_ip>:7772/api/<version>/destroy

▢️ RESIZE
purpose: Update the size of a volume
endpoint: http://<server_ip>:7772/api/<version>/update/resize

▢️ Convert
purpose: Convert a volume to another format
endpoint: http://<server_ip>:7772/api/<version>/update/convert

▢️ CLOUDINIT VOLUME
purpose: Create a cloudinit Volume
endpoint: http://<server_ip>:7772/api/<version>/cloudinit/create
purpose: Upload the needed cloudinit metadata files to create an iso volume for cloudinit utility
endpoint: http://<server_ip>:7772/api/<version>/cloudinit/metadata

▢️ CREATE ISO VOLUME
purpose: Create a volume containing a bootable iso, an OS Installer or a iso containing tools (driver and such)
endpoint: http://<server_ip>:7772/api/<version>/iso/create

▢️ UPDATE VOLUME METADATA
purpose: Update the volume metadata
endpoint: http://<server_ip>:7772/api/<version>/update

▢️ CREATE CEPH VOLUME - WIP
purpose: Create a volume on a ceph cluster using storage server as an interface
endpoint: http://<server_ip>:7772/api/<version>/iso/create

▢️ LIVE MIGRATION - PREPARE purpose: Prepare the storage server export structure to abilitate the live migration process endpoint: http://<server_ip>:7772/api/<version>/livemigration/prepare

▢️ LIVE MIGRATION - REVERT purpose: Return to normal esport state if live migration fails endpoint: http://<server_ip>:7772/api/<version>/livemigration/revert

▢️ LIVE MIGRATION - CONCLUDE purpose: Consolodate the state of the volumes if the live migration process was successful endpoint: http://<server_ip>:7772/api/<version>/livemigration/conclude :::

:::warning TODO or WIP:

▢️ TRANSFER PROPERTY - TODO purpose: Update the volume owner endpoint: http://<server_ip>:7772/api/<version>/transfer

▢️ CLONE - TODO purpose: Create a new volume cloning another one endpoint: http://<server_ip>:7772/api/<version>/clone :::

where are my volumes created into?

Inside the elemento's architecture a new volumes will be created folling this rules:

  1. A new volume will be created inside the /mnt path or in one of his first layer subdirectory
  2. For a path to be recognised as valid to allocate new volumes a settings.json file has to be present.
  3. Multiple paths inside /mnt are allowed, the system will chose from the available ones automatically.

This will be considered a valid structure where there are 3 different paths that can be choosen as location to create volumes:

/mnt/
β”œβ”€β”€ valid_path_1/
β”‚   β”œβ”€β”€ settings.json
β”‚   β”œβ”€β”€ volume_1A/
β”‚   β”œβ”€β”€ volume_1B/
β”‚   └── volume_1C/
β”œβ”€β”€ valid_path_2/
β”‚   β”œβ”€β”€ settings.json
|   β”œβ”€β”€ volume_2A/
β”‚   └── volume_2B/
β”œβ”€β”€ invalid_path_3/
β”‚   β”œβ”€β”€ random_file_1
β”‚   └── random_file_2
└── valid_path_4/
    β”œβ”€β”€ settings.json
    β”œβ”€β”€ volume_4A/
    β”œβ”€β”€ volume_4B/
    └── volume_4C/

:::warning Note that inside the path /mnt/invalid_path_3 is present a directory containing a settings.json file but the directory is not a valid path because is not at the higher nesting level that contains the settings.json file. :::

what is a settings.json file?

In this context a settings.json files is elemento's architecture tool to know that a path inside /mnt has to be considered as a place where volumes can be created and managed, and at the same time introducing some rules for the location.

settings.json contains informations following this structure:

{
 "max-volumes": 6,
 "max-volume-size": "50G",
 "max-total-size": "200G",
 "file-system": "default"
}

Where:

  • max-volumes is the number of volumes that can be created in this location and - max-volume-size is the maximum virtual size allowed for each volume.
  • max-total-size is the maximum virtual total size allowed the volume in this path
  • file-system chosen from default or unique allow the storage server to know what king of filesystem he has to create volumes on

what is a vid.<whatever_uid>.elimg?

Each of this kind of directory represent an elemento storage volume. The name of the folder that represent a volume always follows this structure: vid.<volume_uid>.elimg where <volume_uid> represent the unique id of the volume.

Each one of theese directories will contain the effective volume data.<ext> and the relative informations where <ext> represent the image format (for raw format the extension is img).

:::spoiler knowing this the previous directory tree will appear like this

/mnt/
β”œβ”€β”€ valid_path_1/
β”‚   β”œβ”€β”€ settings.json
β”‚   β”œβ”€β”€ vid.volume1A_uid.elimg/
β”‚   β”‚   β”œβ”€β”€ data.<ext>
β”‚   β”‚   └── meta.json
β”‚   β”œβ”€β”€ vid.volume2A_uid.elimg/
β”‚   β”‚   β”œβ”€β”€ data.<ext>
β”‚   β”‚   └── meta.json
β”‚   └── vid.volume3A_uid.elimg/
β”‚       β”œβ”€β”€ data.<ext>
β”‚       └── meta.json
β”œβ”€β”€ data_volumes/
β”‚   β”œβ”€β”€ valid_path_2/
β”‚   β”‚   β”œβ”€β”€ settings.json
β”‚   β”‚   β”œβ”€β”€ vol.volume2A_uid.elimg/
β”‚   |   |   β”œβ”€β”€ data.<ext>
β”‚   |   |   └── meta.json
β”‚   |   β”œβ”€β”€ vid.volume2B_uid.elimg/
β”‚   |       β”œβ”€β”€ data.<ext>
β”‚   |       └── meta.json
β”‚   └── valid_path_3/
β”‚       β”œβ”€β”€ settings.json
β”‚       β”œβ”€β”€ vid.volume3A_uid.elimg/
β”‚       |   β”œβ”€β”€ data.<ext>
β”‚       |   └── meta.json
β”‚       └── not_valid_path/
β”‚           └── settings.json
└── valid_path_4/
    β”œβ”€β”€ settings.json
    β”œβ”€β”€ vid.volume4A_uid.elimg/
    β”‚   β”œβ”€β”€ data.<ext>
    β”‚   └── meta.json
    └── vid.volume4B_uid.elimg/
        β”œβ”€β”€ data.<ext>
        └── meta.json

:::

Elemento Storage Volume tree

As follows is represented the structure of an Elemento volume (.elimg)

vid.<volume_id>.elimg/
β”œβ”€β”€ meta.json
β”œβ”€β”€ isoinfo.json # only present if the volume is contains a non cloudinit iso
β”œβ”€β”€ iqn.2004-10.cloud.elemento:01:<client_uid ^ volume_uid>.exported # if exported
β”œβ”€β”€ data.<ext>
└── cloud-init-metadata/ # this is present only if the vol is cloudinit
    β”œβ”€β”€ elemento.<n>.expected
    β”œβ”€β”€ user-data
    β”œβ”€β”€ network-data
    β”œβ”€β”€ meta-data
    β”œβ”€β”€ script_a.sh
    └── script_b.sh
    

here it is a more in depth explaination of how what each files or subdirectory does and what is their purpose in the context of the Elemento Volume.

meta.json

This file contains most of the informations about the volume, is a simple json file. When the system rescan in search for new volumes this file allows to retrive most of the informations necessary to perform the actions on the volume following the right steps.

This is an example of a meta.json (is formatted for better readability, but in the actual file is not)

{
    "creatorID": "5e96afa52c1a53348adc5c5663978058", 
    "name": "cloudinit-ubuntu", 
    "private": false, 
    "bootable": true, 
    "readonly": false, 
    "shareable": false, 
    "clonable": true, 
    "alg": "cp", 
    "format": "qcow2", 
    "bus": "virtio", 
    "cloudinit": true,
    "ceph": false
}

In the following are present the major informations about the data contained inside the json

key datatype purpose allowed values default
volumeID string uid of the volume
size int virtual size in bytes of the image
name str human readable name of the volume
format str format of the volume image raw, qcow2, rdb, iso raw
private bool if the volume can be seen just by the creator
bootable bool if the volume can be used to boot from
shareable bool if the volume can be exported multiple times
clonable bool if the volume can be cloned True
alg str the choosing of the algorithm used to clone the volume cp, rclone, rsync cp
bus str the choosed driver to connect the volume to a VM virtio, scsi, sata, ide virtio
cloudinit bool if the volume has cloudinit purposes False
ceph bool if the volume belongs to a ceph cluster False

data.<ext>

This file contains the actual volume image. The image can be in different formats:

  • raw
  • qcow2
  • rbd (on a ceph cluster)
  • iso

:::info Some things to note:

  • ext is representing the image format
  • if image format is raw ext is img ::: :::warning For ceph volumes the data.rbd file is actually "fake", the real volumes stays onto the ceph cluster, this file is just a tool to allow the storage server to manage the volume whitout coninuosly ask stuff to the ceph cluster. :::

cloud-init-metadata subdirectory

Cloudinit allows a VM to execute commands and import configurations in order to have the VM preconfigured at first boot. In addition to the cloudimage volume cloudinit also needs a set of metadata files (config files and scripts) that can read and use to apply the desired configuration: all of this informations will be transformed into an iso that can be mounted alongside the boot volume. This directory will contain all of that files.

A file named elemento.<n>.expected will be present in this directory too. This file allow the system to keep track of how many files it has to expect and when all the files are present.

The most commons files for a cloud init setup are 3:

  • meta-data
  • user-data
  • network-data

:::info Some things to note: script files can also be included to be used during installations process. Never the less this number is not fixed and can change. :::

::: warning For now is important to notice that there is no way to update this file via api. the fastest way will be to modify the files directly on the host or recreate the volume from scratch and sending along the updated files. :::

other files

:::spoiler

lock system

The files in the form of elemento.purpose.<operation_uid>.ignore are used to lock the volumes. This lock is implemented in order to avoid overlapping of actions on the same volume. While the volume is locked the system still knows his dimension, but does not return it to the user (still not implemented very well, but it works, this flow can be better managed). For smaller volume or a single user that has accesss to the volume is not a big deal beacuse actions are fast, but if the volume is pretty big or multiple user would execute operations onto the same volume this could've happened. For now this is a simpler method to avoid this kind of scenarios.

export system

If the volume is being exported a file in the form of iqn.<whatever_uid>.exported will be present in the volume as simple way to track this action. While exported the file is repetedly touched in the same location by a small container.

isoinfo.json

this file is for (non cloudinit) iso volumes. Is a simple json and allows the system to fetch again the informations about the iso: Some examples:

  • for tools:
{
    "isotype": "tool",
    "os_family": "windows",
    "scope": "driver",
    "version": "x.y"
}
  • for OS installer or bootable iso:
{
    "isotype": "os_generic",
    "os_family": "linux",
    "os_flavour": "debian"
    "os_version": "12.9"
}

:::

Export

General

This Graph represent if a volume can be exported based on its parameters and its status:

graph LR Start(["is volume exportable"]) Start --> P{is private?}
P -- Yes --> O{is owned?}

O -- Yes -->privateS{Condition 4?}

privateS{"is shareable?"}
privateS -- yes --> privateOwnedShareable["True"]
privateS -- no  --> privateOwnedNotShareable{"yet exported?<br>(conn is None)"}
privateOwnedNotShareable -- yes --> o1["true"]
privateOwnedNotShareable -- no  --> o2["false"]

O -- No  --> PrivateNotOwned["False"]

P -- No  --> notPrivateS{is shareable}

notPrivateS -- Yes --> notPrivateShaerable["True"]
notPrivateS -- No  --> notPrivateNotShaerable{"yet exported?<br>(conn is None)"}

notPrivateNotShaerable -- yes --> o3["true"]
notPrivateNotShaerable -- no  --> o4["false"]

:::info if a volume is bootable cannot be shaerable :::

Local export

Samba export

ISCSI export

Cloud-Init

cloudinit addon for storageserver

the cloudinitAddon object is our way to manage all the informations that a cloudinit volume needs to have to be correcly used to setup a VM (expecially its metadata)

Get the cloud image

Upload of the metadata

Create the iso

Api Endpoints

:::info StorageServer responds to api calls on port is 7772 ::: Here are reported functionality (and relative endpoints and purpose) for the storage server.

Create

purpose: Create a simple volume endpoint: http://<server_ip>:7772/api/<version>/create headers:"Content-Type": "application/json" Payload/body:

{
	"creatorID": "uuid_of_the_creator",
	"name": "name_of_the_volume",
	"private": false,
	"readonly": false,
	"shareable": false,
	"bootable": false,
	"clonable": false,
	"alg": "algorithm_of_choice_for_cloning",
	"format": "desired_volume_format",
	"bus": "mounting_driver_for_the_volume",
	"size": size_of_the_volume_in_GB
}

:::spoiler Requests examples πŸ›„ Example payload:

{
    "creatorID": "ffffffffffffffffffffffffffffffff"
    "name": "test-create",
    "private": false,
    "readonly": false,
    "shareable": false,
    "bootable": false,
    "clonable": false,
    "alg": "no",
    "format": "qcow2",
    "bus": "virtio",
    "size": 1
}

πŸ’» Bash:

curl -X POST "http://<server_ip>:7772/api/<version>/create \
     -H "Content-Type: application/json" \
     -d '{"creatorID": "ffffffffffffffffffffffffffffffff","name": "test-create", "private":false, "readonly": false, "shareable": false, "bootable": false, "clonable": false, "alg": "no", "format": "qcow2", "bus": "virtio", "size": 1}'

🐍 Python:

import requests

url = "http://<server_ip>:7772/api/<version>/create"
headers = {
    "Content-Type": "application/json",
}
payload = {
	"creatorID": "ffffffffffffffffffffffffffffffff",
	"name": "test-create",
	"private": false,
	"readonly": false,
	"shareable": false,
	"bootable": false,
	"clonable": false,
	"alg": "no",
	"format": "qcow2",
	"bus": "virtio",
	"size": 1
}
response = requests.post(url, json=payload, headers=headers)

# Then manage the response

::: :::spoiler Response examples

βœ… 200 - OK

{
	"alg": "no",
	"bootable": false,
	"bus": "virtio",
	"clonable": false,
	"creatorID": "ffffffffffffffffffffffffffffffff",
	"img_format": "qcow2",
	"name": "test-create",
	"private": false,
	"readonly": false,
	"shareable": false,
	"size": 1,
	"vid": "ffffffffffffffffffffffffffffffff"
}

note that the uuid of the newly created volume is included along the other parameters
⚠️ 400 - bad request

{
	"error": "request was badly formatted. 'the_required_key_that_is_missing'"
}

⚠️ 404 - unreachable

❌ 500 - internal server error

{
    "creatorID": "ffffffffffffffffffffffffffffffff"
    "name": "test-create",
    "private": false,
    "readonly": false,
    "shareable": false,
    "bootable": false,
    "clonable": false,
    "alg": "no",
    "format": "qcow2",
    "bus": "virtio",
    "size": 1
}

:::

List Accessible Volumes

purpose: returns the volumes a user can access endpoint: http://<server_ip>:7772/api/<version>/accessible headers:"Content-Type": "application/json" Payload/body:

{
	"client_uid": "uuid_of_the_user_that_ask_for_volumes",

}

:::spoiler Requests examples πŸ›„ Example payload:

{
    "client_uid": "ffffffffffffffffffffffffffffffff"
}

πŸ’» Bash:

curl -X POST "http://<server_ip>:7772/api/<version>/accessible \
     -H "Content-Type: application/json" \
     -d '{"client_uid": "ffffffffffffffffffffffffffffffff"}'

🐍 Python:

import requests

url = "http://<server_ip>:7772/api/<version>/accessible"
headers = {
    "Content-Type": "application/json",
}
payload = {
	"client_uid": "ffffffffffffffffffffffffffffffff"
}
response = requests.post(url, json=payload, headers=headers)

# Then manage the response

::: :::spoiler Response examples

βœ… 200 - OK

[
	{
		"volumeID": "155a8574f06542f1ac2fbe8790b35160",
		"creatorID": "ffffffffffffffffffffffffffffffff",
		"size": 4000000000,
		"name": "test",
		"format": "qcow2",
		"private": false,
		"bootable": false,
		"readonly": false,
		"shareable": false,
		"clonable": false,
		"alg": "no",
		"bus": "virtio",
		"cloudinit": false,
		"ceph": false,
		"exported": false,
		"sizeOnDisk": 196672,
		"lastUpdated": "2025-02-05 23:34:07.1850"
	},
	{
		"volumeID": "2bef4e8692674ff5b0adbf88c5882710",
		"creatorID": "ffffffffffffffffffffffffffffffff",
		"size": 6203355136,
		"name": "ubuntu-destop-iso",
		"format": "iso",
		"iso_type": "os_generic",
		"private": false,
		"bootable": true,
		"readonly": true,
		"shareable": false,
		"clonable": true,
		"alg": "cp",
		"bus": "sata",
		"cloudinit": false,
		"ceph": false,
		"exported": false,
		"sizeOnDisk": 6203355136,
		"lastUpdated": "2024-08-27 18:25:25.0000"
	}
]

⚠️ 400 - bad request
{
	"error": "request was badly formatted. 'the_required_key_that_is_missing'"
}

⚠️ 404 - unreachable

❌ 500 - internal server error

{
    "client_uid": "ffffffffffffffffffffffffffffffff"
}

:::

Single Volume Informations

purpose: Get the informations about a single volume endpoint: http://<server_ip>:7772/api/<version>/info headers:"Content-Type": "application/json" Payload/body:

{
	"volume_id": "uuid_of_the_volume_infos_are_asked_about",

}

:::spoiler Requests examples πŸ›„ Example payload:

{
    "volume_id": "ffffffffffffffffffffffffffffffff"
}

πŸ’» Bash:

curl -X POST "http://<server_ip>:7772/api/<version>/info \
     -H "Content-Type: application/json" \
     -d '{"volume_id": "ffffffffffffffffffffffffffffffff"}'

🐍 Python:

import requests

url = "http://<server_ip>:7772/api/<version>/info"
headers = {
    "Content-Type": "application/json",
}
payload = {
	"volume_id": "ffffffffffffffffffffffffffffffff"
}
response = requests.post(url, json=payload, headers=headers)

# Then manage the response

::: :::spoiler Response examples

βœ… 200 - OK

{
    "volumeID": "ffffffffffffffffffffffffffffffff",
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "size": 4000000000,
    "name": "test",
    "format": "qcow2",
    "private": false,
    "bootable": false,
    "readonly": false,
    "shareable": false,
    "clonable": false,
    "alg": "no",
    "bus": "virtio",
    "cloudinit": false,
    "ceph": false,
    "exported": false,
    "sizeOnDisk": 196672,
    "lastUpdated": "2025-02-05 23:34:07.1850"
}

⚠️ 400 - bad request
{
	"error": "request was badly formatted. 'the_required_key_that_is_missing'"
}

⚠️ 404 - unreachable

❌ 500 - internal server error

{
    "volume_id": "ffffffffffffffffffffffffffffffff"
}

:::

Destroy

purpose: Destroy a volume endpoint: http://<server_ip>:7772/api/<version>/destroy headers:"Content-Type": "application/json" Payload/body:

{
	"volume_id": "uuid_of_the_volume_to_destroy",

}

:::spoiler Requests examples πŸ›„ Example payload:

{
    "volume_id": "ffffffffffffffffffffffffffffffff"
}

πŸ’» Bash:

curl -X POST "http://<server_ip>:7772/api/<version>/destroy \
     -H "Content-Type: application/json" \
     -d '{"volume_id": "ffffffffffffffffffffffffffffffff"}'

🐍 Python:

import requests

url = "http://<server_ip>:7772/api/<version>/destroy"
headers = {
    "Content-Type": "application/json",
}
payload = {
	"volume_id": "ffffffffffffffffffffffffffffffff"
}
response = requests.post(url, json=payload, headers=headers)

# Then manage the response

::: :::spoiler Response examples

βœ… 200 - OK

{
    "vid": "ffffffffffffffffffffffffffffffff"
}

⚠️ 400 - bad request
{
	"error": "request was badly formatted. 'the_required_key_that_is_missing'"
}

⚠️ 404 - unreachable

❌ 500 - internal server error

{
    "volume_id": "ffffffffffffffffffffffffffffffff"
}

:::

Update Metadata

purpose: Update the volume metadata endpoint: http://<server_ip>:7772/api/<version>/update headers:"Content-Type": "application/json" Payload/body:

{
    "vid": "uuid_of_the_volume_to_modify",
    "creatorID": "uuid_of_the_client_asking_the_changes_on_the_volume",
    "name": "test-update",
    "private": false,
    "readonly": false,
    "shareable": false,
    "bootable": false,
    "clonable": true,
    "alg": "cp",
    "bus": "sata"
}

:::spoiler Requests examples πŸ›„ Example payload:

{
    "vid": "ffffffffffffffffffffffffffffffff",
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "name": "test-update",
    "private": false,
    "readonly": false,
    "shareable": false,
    "bootable": false,
    "clonable": true,
    "alg": "cp",
    "bus": "sata"
}

πŸ’» Bash:

curl -X POST "http://<server_ip>:7772/api/<version>/update/resize \
     -H "Content-Type: application/json" \
     -d '{"vid": "ffffffffffffffffffffffffffffffff", "creatorID": "ffffffffffffffffffffffffffffffff", "name": "test-update", "private": false, "readonly": false, "shareable": false, "bootable": false, "clonable": true, "alg": "cp", "bus": "sata"}'

🐍 Python:

import requests

url = "http://<server_ip>:7772/api/<version>/update"
headers = {
    "Content-Type": "application/json",
}
payload = {
    "vid": "ffffffffffffffffffffffffffffffff",
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "name": "test-update",
    "private": false,
    "readonly": false,
    "shareable": false,
    "bootable": false,
    "clonable": true,
    "alg": "cp",
    "bus": "sata"
}
response = requests.post(url, json=payload, headers=headers)

# Then manage the response

::: :::spoiler Response examples

βœ… 200 - OK

{
    "vid": "ffffffffffffffffffffffffffffffff",
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "name": "test-update",
    "private": false,
    "readonly": false,
    "shareable": false,
    "bootable": false,
    "clonable": true,
    "alg": "cp",
    "bus": "sata"
}

⚠️ 400 - bad request
{
	"error": "request was badly formatted. 'the_required_key_that_is_missing'"
}

⚠️ 404 - unreachable

❌ 500 - internal server error

{
    "vid": "ffffffffffffffffffffffffffffffff",
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "name": "test-update",
    "private": false,
    "readonly": false,
    "shareable": false,
    "bootable": false,
    "clonable": true,
    "alg": "cp",
    "bus": "sata"
}

:::

Resize

purpose: Update the size of a volume endpoint: http://<server_ip>:7772/api/<version>/update/resize headers:"Content-Type": "application/json" Payload/body:

{
    "vid": "ffffffffffffffffffffffffffffffff",
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "size": 10
}

:::spoiler Requests examples πŸ›„ Example payload:

{
    "vid": "ffffffffffffffffffffffffffffffff",
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "size": 10
}

πŸ’» Bash:

curl -X POST "http://<server_ip>:7772/api/<version>/update/resize \
     -H "Content-Type: application/json" \
     -d '{"vid": "ffffffffffffffffffffffffffffffff", "creatorID": "ffffffffffffffffffffffffffffffff", "size": 10}'

🐍 Python:

import requests

url = "http://<server_ip>:7772/api/<version>/update/resize"
headers = {
    "Content-Type": "application/json",
}
payload = {
    "vid": "ffffffffffffffffffffffffffffffff",
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "size": 10
}
response = requests.post(url, json=payload, headers=headers)

# Then manage the response

::: :::spoiler Response examples

βœ… 200 - OK

{
    "vid": "ffffffffffffffffffffffffffffffff",
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "size": 10
}

⚠️ 400 - bad request
{
	"error": "request was badly formatted. 'the_required_key_that_is_missing'"
}

⚠️ 404 - unreachable

❌ 500 - internal server error

{
    "vid": "ffffffffffffffffffffffffffffffff",
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "size": 10
}

:::

Convert

purpose: Convert a volume to another format endpoint: http://<server_ip>:7772/api/<version>/update/convert headers:"Content-Type": "application/json" Payload/body:

{
    "vid": "ffffffffffffffffffffffffffffffff",
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "format": "qcow2"
}

:::spoiler Requests examples πŸ›„ Example payload:

{
    "vid": "ffffffffffffffffffffffffffffffff",
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "format": "qcow2"
}

πŸ’» Bash:

curl -X POST "http://<server_ip>:7772/api/<version>/update/convert \
     -H "Content-Type: application/json" \
     -d '{"vid": "ffffffffffffffffffffffffffffffff", "creatorID": "ffffffffffffffffffffffffffffffff", "format": "qcow2"}'

🐍 Python:

import requests

url = "http://<server_ip>:7772/api/<version>/update/convert"
headers = {
    "Content-Type": "application/json",
}
payload = {
    "vid": "ffffffffffffffffffffffffffffffff",
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "format": "qcow2"
}
response = requests.post(url, json=payload, headers=headers)

# Then manage the response

::: :::spoiler Response examples

βœ… 200 - OK

{
    "vid": "ffffffffffffffffffffffffffffffff",
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "format": "qcow2"
}

⚠️ 400 - bad request
{
	"error": "request was badly formatted. 'the_required_key_that_is_missing'"
}

⚠️ 404 - unreachable

❌ 500 - internal server error

{
    "vid": "ffffffffffffffffffffffffffffffff",
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "format": "qcow2"
}

:::

Create Cloudinit Cloudimage volume

purpose: Create a cloudinit Volume endpoint: http://<server_ip>:7772/api/<version>/cloudinit/create

Cloudinit Metadata Volume

::: info TBH :::

1️⃣ First Call

purpose: Upload the needed cloudinit metadata files to create an iso volume for cloudinit utility endpoint: http://<server_ip>:7772/api/<version>/cloudinit/metadata

⏩ Following calls

purpose: Upload the needed cloudinit metadata files to create an iso volume for cloudinit utility endpoint: http://<server_ip>:7772/api/<version>/cloudinit/metadata

Create ISO volume

::: info this next two calls have different type of payload, but goes to the same endpoint :::

πŸ”¨iso volume with tool purpose

purpose: Create a volume containing a bootable iso(live) or an OS Installer. endpoint: http://<server_ip>:7772/api/<version>/iso/create headers:"Content-Type": "application/json" Payload/body:

{
	"creatorID": "uuid_of_the_client",
	"name": "virtio-win-driver",
	"private": false,
	"clonable": true,
	"alg": "cp",
	"isotype": "tool",
	"os_family": "windows",
	"scope": "drivers",
	"version": "2021",
	"size": 15
}

:::spoiler Requests examples πŸ›„ Example payload:

{
	"alg": "cp",
    "clonable": true,
	"creatorID": "ffffffffffffffffffffffffffffffff",
    "isotype": "tool",
	"name": "virtio-win-driver",
	"os_family": "windows",
	"os_flavour": null,
	"os_version": null,
	"private": false,
	"tool_scope": "drivers",
	"tool_version": "2021"
}

πŸ’» Bash:

curl -X POST "http://<server_ip>:7772/api/<version>/update/convert \
     -H "Content-Type: application/json" \
     -d '{"alg": "cp", "clonable": true, "creatorID": "ffffffffffffffffffffffffffffffff", "isotype": "tool", "name": "virtio-win-driver",	"os_family": "windows",	"os_flavour": null,	"os_version": null,	"private": false, "tool_scope": "drivers", "tool_version": "2021"}'

🐍 Python:

import requests

url = "http://<server_ip>:7772/api/<version>/iso/create"
headers = {
    "Content-Type": "application/json",
}
payload = {
	"alg": "cp",
    "clonable": true,
	"creatorID": "ffffffffffffffffffffffffffffffff",
    "isotype": "tool",
	"name": "virtio-win-driver",
	"os_family": "windows",
	"os_flavour": null,
	"os_version": null,
	"private": false,
	"tool_scope": "drivers",
	"tool_version": "2021"
}
response = requests.post(url, json=payload, headers=headers)

# Then manage the response

::: :::spoiler Response examples

βœ… 200 - OK

{
	"alg": "cp",
    "clonable": true,
	"creatorID": "ffffffffffffffffffffffffffffffff",
    "isotype": "tool",
	"name": "virtio-win-driver",
	"os_family": "windows",
	"os_flavour": null,
	"os_version": null,
	"private": false,
	"tool_scope": "drivers",
	"tool_version": "2021",
	"vid": "ffffffffffffffffffffffffffffffff"
}

⚠️ 400 - bad request
{
	"error": "request was badly formatted. 'the_required_key_that_is_missing'"
}

⚠️ 404 - unreachable

❌ 500 - internal server error

{
	"alg": "cp",
    "clonable": true,
	"creatorID": "ffffffffffffffffffffffffffffffff",
    "isotype": "tool",
	"name": "virtio-win-driver",
	"os_family": "windows",
	"private": false,
	"tool_scope": "drivers",
	"tool_version": "2021"
}

:::

πŸ’» iso volume for operative system installer or live

purpose: Create a volume containing tools (driver and such) iso. endpoint: http://<server_ip>:7772/api/<version>/iso/create headers:"Content-Type": "application/json" Payload/body:

{
	"creatorID": "uuid_of_the_client",
	"name": "dabian-iso",
	"private": false,
	"clonable": true,
	"alg": "cp",
	"isotype": "os_generic",
    "os_family": "linux",
    "os_flavour": "debian",
    "os_version": "12.10",
	"size": 15
}

:::spoiler Requests examples πŸ›„ Example payload:

{
	"creatorID": "ffffffffffffffffffffffffffffffff",
	"name": "dabian-iso",
	"private": false,
	"clonable": true,
	"alg": "cp",
	"isotype": "os_generic",
    "os_family": "linux",
    "os_flavour": "debian",
    "os_version": "12.10",
	"size": 15
}

πŸ’» Bash:

curl -X POST "http://<server_ip>:7772/api/<version>/update/convert \
     -H "Content-Type: application/json" \
     -d '{"creatorID": "ffffffffffffffffffffffffffffffff", "name": "dabian-iso", "private": false, "clonable": true, "alg": "cp", "isotype": "os_generic", "os_family": "linux", "os_flavour": "debian", "os_version": "12.10", "size": 15}'

🐍 Python:

import requests

url = "http://<server_ip>:7772/api/<version>/iso/create"
headers = {
    "Content-Type": "application/json",
}
payload = {
	"creatorID": "ffffffffffffffffffffffffffffffff",
	"name": "dabian-iso",
	"private": false,
	"clonable": true,
	"alg": "cp",
	"isotype": "os_generic",
    "os_family": "linux",
    "os_flavour": "debian",
    "os_version": "12.10",
	"size": 15
}
response = requests.post(url, json=payload, headers=headers)

# Then manage the response

::: :::spoiler Response examples

βœ… 200 - OK

{
    "alg": "cp",
    "clonable": true,
    "creatorID": "ffffffffffffffffffffffffffffffff",
    "isotype": "os_generic",
    "name": "dabian-iso",
    "os_family": "linux",
    "os_flavour": "debian",
    "os_version": "12.10",
    "private": false,
    "tool_scope": null,
    "tool_version": null,
    "vid": "ffffffffffffffffffffffffffffffff"
}

⚠️ 400 - bad request
{
	"error": "request was badly formatted. 'the_required_key_that_is_missing'"
}

⚠️ 404 - unreachable

❌ 500 - internal server error

{
	"creatorID": "ffffffffffffffffffffffffffffffff",
	"name": "dabian-iso",
	"private": false,
	"clonable": true,
	"alg": "cp",
	"isotype": "os_generic",
    "os_family": "linux",
    "os_flavour": "debian",
    "os_version": "12.10",
	"size": 15
}

:::

WIP or TODO API calls

▢️ TRANSFER PROPERTY - TODO purpose: Update the volume owner endpoint: http://<server_ip>:7772/api/<version>/transfer

▢️ CLONE - TODO purpose: Create a new volume cloning another one endpoint: http://<server_ip>:7772/api/<version>/clone

▢️ LIVE MIGRATION - PREPARE - WIP purpose: Prepare the storage server export structure to abilitate the live migration process endpoint: http://<server_ip>:7772/api/<version>/livemigration/prepare

▢️ LIVE MIGRATION - REVERT - WIP purpose: Return to normal esport state if live migration fails endpoint: http://<server_ip>:7772/api/<version>/livemigration/revert

▢️ LIVE MIGRATION - CONCLUDE - WIP purpose: Consolodate the state of the volumes if the live migration process was successful endpoint: http://<server_ip>:7772/api/<version>/livemigration/conclude