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.

586 lines
17 KiB

use ureq;
use crate::success;
use crate::external;
use crate::types::{
LunaNodeResponse,
LunaNodeRequest,
};
use lunanode_macros::lunanode_response;
use serde_json;
use serde::{Serialize, Deserialize};
use serde_with::{
DisplayFromStr,
serde_as,
};
use uuid;
#[serde_as]
#[derive(Serialize, Deserialize, PartialEq, Debug)]
/// Defines a VM (used for requests using the VM section)
pub struct VirtualMachine {
#[serde_as(as="DisplayFromStr")]
/// the UUID of the VM
vm_id: uuid::Uuid, // should be UUIDv4
/// the name of the VM set by the user
name: String, // the name set by the user
#[serde_as(as="DisplayFromStr")]
/// The plan ID, cross-reference with /plan/list/
plan_id: i32, // should be more strict
/// The hostname set by the user
hostname: String, // the hostname set by the user
#[serde(rename="primaryip")]
/// The primary (public) IP address of the VM.
primary_ip: std::net::Ipv4Addr,
#[serde(rename="privateip")]
/// The private IP address of the VM.
private_ip: std::net::Ipv4Addr,
#[serde_as(as="DisplayFromStr")]
/// RAM of the VM in GB
ram: i32, // in GB, may need to be a float
#[serde_as(as="DisplayFromStr")]
/// The number of virtual CPU cores
vcpu: i32, // CPU cores
#[serde_as(as="DisplayFromStr")]
/// The storage amount of the VM in GB
storage: i32, // in GB
#[serde_as(as="DisplayFromStr")]
/// bandwidth in GB/month
bandwidth: i32, // in GB/month
/// The region where the VM is located
region: LNRegion, // could be more strict
/// The status, which should be more strict than a String.
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
}
impl ToString for VMListResponse {
fn to_string(&self) -> String {
"N/A".to_string()
}
}
impl LunaNodeResponse for VMListResponse {}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all="lowercase")]
enum AttachmentType {
Unattached,
Vm,
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
struct FloatingIp {
attached_id: Option<uuid::Uuid>,
attached_name: Option<String>,
attached_type: AttachmentType,
hostname: String,
ip: std::net::Ipv4Addr,
region: LNRegion,
reverse: Option<String>,
#[serde_as(as="DisplayFromStr")]
time_updated: chrono::DateTime<chrono::Utc>,
}
#[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)]
/// A generic IP address type, with two variants: V4, and V6. This is used for generic types returned from the API. For example, a list of IP addresses without the IP type specified.
pub enum IPAddress {
V4(std::net::Ipv4Addr),
V6(std::net::Ipv6Addr),
}
#[derive(Serialize, Deserialize, Debug)]
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,
#[serde(rename="reverse")]
/// The reverse DNS assigned to the VM. This is optional.
rdns: Option<String>,
}
#[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, Hash, Eq, PartialEq)]
#[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,
#[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
}
#[lunanode_response]
pub struct PlanListResponse {
plans: Vec<LNPlan>,
}
#[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"(?)
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct Volume {
#[serde_as(as="DisplayFromStr")]
/// The personal ID used for the volume.
id: i32,
#[serde_as(as="DisplayFromStr")]
/// the UUID for the volume
identification: uuid::Uuid,
/// the name set by the user
name: String,
/// The region where the volume is located.
region: LNRegion,
/// The size of the volume, in GB
#[serde_as(as="DisplayFromStr")]
size: i32,
/// The status of the volume; this should be more string, but for now at least "active".
status: String,
#[serde_as(as="DisplayFromStr")]
/// a datetime (explicitly set to UTC) of when the volume was created
time_created: chrono::DateTime<chrono::Utc>,
#[serde_as(as="DisplayFromStr")]
/// ID of the user who created the volume
user_id: i32,
}
#[serde_as]
#[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",
#[serde_as(as="DisplayFromStr")]
/// An (explicitly UTC) datetime of when the VM was created
time_created: chrono::DateTime<chrono::Utc>, // should be a datetime
}
#[lunanode_response]
pub struct LNImageDetailResponse {
details: LNImageDetails,
}
#[lunanode_response]
pub struct LNImageListResponse {
images: Vec<LNImage>,
}
#[lunanode_response]
pub struct BillingCreditResponse {
/// Money left in the account in USD
#[serde_as(as="DisplayFromStr")]
credit: f32,
}
#[lunanode_response]
pub struct VolumeListResponse {
volumes: Vec<Volume>,
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct Network {
/// The name set by the user when creating the network.
name: String,
#[serde_as(as="DisplayFromStr")]
net_id: i32,
/// The network subnet. This should be strictly typed as an IP address w/ a subnet attached. TODO: subnet type
subnet: String,
}
#[lunanode_response]
pub struct NetworkListResponse {
networks: Vec<Network>,
}
#[lunanode_response]
pub struct FloatingIpListResponse {
ips: Vec<FloatingIp>,
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct Zone {
#[serde_as(as="DisplayFromStr")]
/// The lunanode id of the zone.
id: i32,
/// The domain (or subdomain) being managed by the zone.
name: String,
/// The default TTL used for this zone. This can be overridden manually when specifying new records.
#[serde_as(as="DisplayFromStr")]
ttl: i32,
}
#[lunanode_response]
pub struct ZoneListResponse {
zones: std::collections::HashMap<i32, Zone>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename="UPPERCASE")]
enum RecordType {
A,
AAAA,
CNAME,
ALIAS,
MX,
NS,
TXT,
SPF,
SRV
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct Record {
/// The record id
#[serde_as(as="DisplayFromStr")]
id: i32,
/// The record type, one of A, AAAA, CNAME, ALIAS, MX, NS, TXT, SPF, SRV
#[serde(rename="type")]
record_type: RecordType,
/// The name of the record (for example, if setting an ip address for example.org, this field would show: example.org."
name: String,
/// The data assigned to this record. It shoudl always be a IPv4/v6 address, unless it's an NS
data: String,
#[serde_as(as="DisplayFromStr")]
/// The auxiliary value, only used on some record types.
aux: i32,
#[serde_as(as="DisplayFromStr")]
/// The TTL for the record.
ttl: i32,
/// Unknown value
policy: String,
/// The region the record applies to, if specificed. Otherwise None. Currently a String due to type issues.
region: String,
#[serde(rename="regiongroup")]
/// This value can be any region group defined by the user or auto. This could be stricter.
region_group: String,
/// This value can be either Canada or France, and it should be stricter.
country: String,
/// The continent as set by the user for this record. May be none or auto.
continent: String,
#[serde_as(as="DisplayFromStr")]
/// Is the record for everywhere (global); this should be a bool
global: i32,
#[serde_as(as="DisplayFromStr")]
/// The latitude of the record, if given.
latitude: f32,
#[serde_as(as="DisplayFromStr")]
/// Longitude of a record, if given.
longitude: f32,
#[serde(with="external")]
/// Is active in inactive record.
status: bool,
#[serde_as(as="DisplayFromStr")]
/// Monitor id, if given.
monitor_id: i32,
/// Optional check name?
check_name: Option<String>,
/// The "nice" version of the status as a string.
status_nice: String,
}
#[lunanode_response]
pub struct RecordListResponse {
records: std::collections::HashMap<i32, Record>,
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct DynRecord {
#[serde_as(as="DisplayFromStr")]
id: i32,
name: String,
ip: IPAddress,
}
#[lunanode_response]
pub struct DynListResponse {
dyns: std::collections::HashMap<i32, DynRecord>,
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct SshKey {
#[serde_as(as="DisplayFromStr")]
id: i32,
/// Name of key, as specified by the user.
name: String,
/// The value of the SSH key; this is not more strict, only because the value is meant to be literal and not a "structured" representation of an SSH key. In addition, this would take a lot of extra boilerplate.
value: String,
}
#[lunanode_response]
pub struct RegionListResponse {
regions: std::collections::HashMap<LNRegion, String>,
}
#[lunanode_response]
pub struct SshKeyResponse {
#[serde(flatten)]
/// List of keys stored in the LunaNode cloud. The String is just an index that I can't get to flatten :grumpy programmer noises:
keys: std::collections::HashMap<String, SshKey>,
}
#[lunanode_response]
pub struct EmailUsageResponse {
#[serde_as(as="DisplayFromStr")]
domains: i32,
/// Usage of email in GB, this should be an i32.
storage: String,
/// Usage of email in GB with GB appended to the end of the string,
storage_nice: String,
#[serde_as(as="DisplayFromStr")]
messages: i32,
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct EmailDomainInfo {
#[serde_as(as="DisplayFromStr")]
id: i32,
name: String,
storage: String,
storage_nice: String,
}
#[lunanode_response]
pub struct EmailDomainListResponse {
#[serde(flatten)]
domains: std::collections::HashMap<String,EmailDomainInfo>,
}
#[lunanode_response]
pub struct MonitorCheckListResponse {
/// This is not done yet. A Check type will be required. TODO
checks: Vec<String>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
pub enum ParamType {
Single(String),
Options(std::collections::HashMap<String, String>),
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Param {
#[serde(with="external")]
required: bool,
r#type: ParamType,
name: String,
placeholder: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct MonitorTypes {
/// The name of the monitor type.
name: String,
/// The short name of the monitor type.
short_name: String,
params: std::collections::HashMap<String, Param>
}
#[lunanode_response]
pub struct MonitorCheckTypesResponse {
types: std::collections::HashMap<String, MonitorTypes>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all="lowercase")]
pub enum ContactType {
Email,
Sms,
Voice,
Http,
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct Contact {
#[serde_as(as="DisplayFromStr")]
id: i32,
r#type: ContactType,
data: String,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
pub enum Contacts {
/// Need an empty vec of some kind to hold the blank value, which appears as [].
Empty(Vec<String>),
/// Note that this HashMap should be indexed by i32, not String. This is a limitation of serde as far as I can tell.
Populated(std::collections::HashMap<String, Contact>),
}
#[lunanode_response]
pub struct MonitorContactListResponse {
/// A list of contacts in your LunaNode account. This should be deserialized as Option<HashMap<String, Contact>>, but I haven't gotten around to serializing this in that way. TODO.
contacts: Contacts,
}