You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

298 lines
9.7 KiB

use ureq;
use crate::success;
use crate::external;
use serde_json;
use serde::{Serialize, Deserialize};
use serde_with::{
DisplayFromStr,
serde_as,
};
use uuid;
/// Defines a VM (used for requests using the VM section)
#[serde_as]
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct VirtualMachine {
#[serde_as(as="DisplayFromStr")]
vm_id: uuid::Uuid, // should be UUIDv4
name: String, // the name set by the user
#[serde_as(as="DisplayFromStr")]
plan_id: i32, // should be more strict
hostname: String, // the hostname set by the user
#[serde(rename="primaryip")]
primary_ip: std::net::Ipv4Addr,
#[serde(rename="privateip")]
private_ip: std::net::Ipv4Addr,
#[serde_as(as="DisplayFromStr")]
ram: i32, // in GB, may need to be a float
#[serde_as(as="DisplayFromStr")]
vcpu: i32, // CPU cores
#[serde_as(as="DisplayFromStr")]
storage: i32, // in GB
#[serde_as(as="DisplayFromStr")]
bandwidth: i32, // in GB/month
region: String, // could be more strict
os_status: String, // should be nmore strict
}
#[derive(Serialize, Deserialize, Debug)]
pub struct VMListResponse {
vms: Vec<VirtualMachine>,
#[serde(with="success")]
success: bool, // should be more strict "yes" or "no" as optiobs
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct VMInfoExtra {
#[serde_as(as="DisplayFromStr")]
/// bandwidth allowed over a month in GB
bandwidth: i32,
/// the hostname set by the user
hostname: String, // sufficiently vague
/// the name set by the user
name: String, // sufficiently vague
/// the status of the operating system; possible values: "active", ... TODO
os_status: String, // should be stricter
#[serde_as(as="DisplayFromStr")]
/// id of the plan being used on the VM
plan_id: i32,
#[serde(rename="primaryip")]
/// primary (floating) IP
primary_ip: std::net::Ipv4Addr,
#[serde(rename="privateip")]
/// the private (non-floating) IP to connect between nodes
private_ip: std::net::Ipv4Addr,
#[serde_as(as="DisplayFromStr")]
/// RAM meassured in MB
ram: i32,
/// the datacentre location the VM is running in
region: LNRegion,
#[serde_as(as="DisplayFromStr")]
/// the storage size of the VM in GB
storage: i32,
#[serde_as(as="DisplayFromStr")]
/// number of virtual CPU cores allocated to the VM
vcpu: i32,
#[serde_as(as="DisplayFromStr")]
/// UUIDv4 of the VM
vm_id: uuid::Uuid,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
pub enum IPAddress {
V4(std::net::Ipv4Addr),
V6(std::net::Ipv6Addr),
}
#[derive(Serialize, Deserialize, Debug)]
// TODO: (de)serialize as "4"/"6" respectively
pub enum IPAddressType {
#[serde(rename="4")]
V4,
#[serde(rename="6")]
V6,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct VMAddress {
addr: IPAddress,
#[serde(with="external")]
external: bool,
version: IPAddressType,
reverse: Option<String>, // optional rDNS; string is sufficient, since the server will not be able to set it to something invalid.
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct VMInfo {
#[serde(rename="additionalip")]
additional_ip: Vec<VMAddress>,
#[serde(rename="additionalprivateip")]
additional_private_ip: Vec<VMAddress>,
addresses: Vec<VMAddress>,
/// a possibly empty string containing an error message
error_detail: Option<String>,
/// some unkown string that doesn't seem to be a UUID... maybe the checksum?
host_id: String,
/// the name of the VM set at creation by the user
hostname: String,
/// the name of the image being used by the VM
image: String,
/// the primary, external IP of the VM
ip: std::net::Ipv4Addr,
/// a list of IPv6 addresses assigned to the VM
ipv6: Vec<std::net::Ipv6Addr>,
/// Login details from the VM; this could potentially be a bit more strict to support the storing of username and password separately.
/// Also, it's optional. The server may not even report this value at all, not only give a blank one. Fair enough. Seems more secure.
login_details: Option<String>,
/// the operating system (orignal image used to load the machine)
os: String, // sufficiently vague
#[serde(rename="privateip")]
/// the primary private IP assigned to the machine
private_ip: std::net::Ipv4Addr,
/// security groups by id that the VM belongs to; should be a vec of i32, but it might take some custom implementations
security_group_ids: Vec<String>,
/// security groups by name that the VM belongs to
security_groups: Vec<String>,
#[serde(rename="securitygroups")]
/// why is there a second one of these with a different name. This is stupid.
security_groups2: Vec<String>,
/// an HTML status of the machine
status: String,
/// the color of the status; this could be stricter
status_color: String, // could be more strict
/// the non-HTML status, this could potentially be more strict
status_nohtml: String,
/// A raw status-code string; this could for sure be more strict.
status_raw: String,
/// A possibly empty string, idk what task_state is tho
task_state: String, // a possibly empty string
/// A possibly empty string of attached volumes.
volumes: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct VMInfoResponse {
extra: VMInfoExtra,
info: VMInfo,
#[serde(with="success")]
success: bool,
}
#[derive(Serialize, Deserialize, Debug)]
pub enum LNPlanCategory {
#[serde(rename="Compute-Optimized")]
ComputeOptimized,
#[serde(rename="General Purpose")]
GeneralPurpose,
#[serde(rename="Memory-Optimized")]
MemoryOptimized,
#[serde(rename="SSD-Cached High-Memory")]
SSDCacheHighMemory,
#[serde(rename="SSD-Cached Standard")]
SSDCacheStandard,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "lowercase")]
pub enum LNRegion {
Montreal,
Roubaix,
Toronto
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct LNPlan {
#[serde_as(as="DisplayFromStr")]
all_regions: i32, // may need to be more strict?
#[serde_as(as="DisplayFromStr")]
bandwidth: i32, // in Mbps
category: LNPlanCategory, // could be more strict, "General Purpose", "Compute Optimized", "RAM Optimized"
#[serde_as(as="DisplayFromStr")]
cpu_points: f32, // no idea what this meas
name: String, // plan name, this could potentially be strictly typed as the types of plans don't often change "s.half", "s.1", "m.1", "m.2", etc.
#[serde_as(as="DisplayFromStr")]
plan_id: i32, // can be strictly typed, if needed
#[serde_as(as="DisplayFromStr")]
price: f32, // up to 7 decmial points (f32), and this is the number of US dollars per hour
price_monthly_nice: String, // instead of calculating it on your own, this provides a nice reading of the price for clients
price_nice: String, // same as above, but for the hour
#[serde_as(as="DisplayFromStr")]
ram: i32, // in MB
regions: Vec<LNRegion>, // list of regions by name
regions_nice: String, // list of regions concatonated with commans
#[serde_as(as="DisplayFromStr")]
storage: i32, // per GB
#[serde_as(as="DisplayFromStr")]
vcpu: i32, // number of vCPU cores
}
#[derive(Serialize, Deserialize, Debug)]
pub struct PlanListResponse {
plans: Vec<LNPlan>,
#[serde(with="success")]
success: bool, // should be more strict: "yes" or "no" as options
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct LNImage {
#[serde_as(as="DisplayFromStr")]
image_id: i32, // id of the image
name: String, // set by the user or LunaNode
region: LNRegion,
status: String, // should be stricter, at least "active", "inactive"(?)
}
#[derive(Serialize, Deserialize, Debug)]
pub struct LNImageDetails {
cache_mode: String, // should be stricter, at least "writeback",
checksum: String, // should be stricter, to check of checksum type
disk_format: String, // should be stricter, at least "iso"
hw_disk_bus: String, // should be stricter, at least "ide",
hw_video_model: String, // could, in theory, be stricter, at least: "cirrus",
hw_vif_model: String, // appropriately vague
#[serde(with="success")]
is_read_only: bool, // "yes"/"no"
libvrt_cpu_mode: String, // should be stricter, at least: "host-model",
metadata: Vec<()>, // vec of what?
name: String, // sufficiently vague
region: LNRegion, // sufficiently typed
size: i32, // in MB, maybe?
status: String, // should be stricter, at least: "active",
time_created: String, // should be a datetime
}
#[derive(Serialize, Deserialize, Debug)]
pub struct LNImageDetailResponse {
#[serde(with="success")]
success: bool,
details: LNImageDetails,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct LNImageListResponse {
images: Vec<LNImage>,
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct BillingCreditResponse {
/// Money left in the account in USD
#[serde_as(as="DisplayFromStr")]
credit: f32,
#[serde(with="success")]
success: bool, // this should be stricter
}
#[derive(Serialize, Deserialize, Debug)]
pub struct LunaNodeErrorResponse {
#[serde(with="success")]
success: bool,
error: String, // proper type, full accoutnign of the error from the API
}
impl std::fmt::Display for LunaNodeErrorResponse {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "An API error has occured! {}", self.error)
}
}
impl std::error::Error for LunaNodeErrorResponse {}
#[derive(Debug)]
pub enum LunaNodeError {
RequestError(ureq::Error),
DeserializationError(std::io::Error),
TimeError(std::time::SystemTimeError),
LunaNodeError(LunaNodeErrorResponse),
SerdeError(serde_json::Error, String), // the serde error, accompanied by a raw string
GetFuckedError,
}
impl std::fmt::Display for LunaNodeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "An error has occured! {}", self)
}
}
impl std::error::Error for LunaNodeError {}