diff options
Diffstat (limited to 'src/planet.rs')
-rw-r--r-- | src/planet.rs | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/src/planet.rs b/src/planet.rs new file mode 100644 index 0000000..c29fb69 --- /dev/null +++ b/src/planet.rs @@ -0,0 +1,179 @@ +use std::convert::TryFrom; +use virt::{domain::{Domain, DomainState}}; +use serde::{Serialize, Deserialize}; + +use crate::errors::Error; + +/** + * Defines the amount of memory a planet has + */ +#[derive(Debug, Serialize, Deserialize)] +pub struct Memory(pub u64); + +impl From<u64> for Memory { + fn from(u: u64) -> Self { + Self(u) + } +} + +/** + * Defines the number of vCPUs a planet has + */ +#[derive(Debug, Serialize, Deserialize)] +pub struct CpuCount(pub u64); + +impl From<u64> for CpuCount { + fn from(u: u64) -> Self { + Self(u) + } +} + +/** + * Represents a virtual machine, that's active on some server + * + * In keeping with the theme, it's named [Planet] :) + * + * There is a private `domain` field that contains a reference to the actual domain. This will not + * be (de)serialized, and, if needed across a network, should be recreated from the `host` and + * `uuid` attributes using [virt::domain::lookup_from_uuid_string] + */ +#[derive(Debug, Serialize, Deserialize)] +pub struct Planet { + /// The reference name of the machine + pub name: String, + + /// The physical machine where this one lives + pub host: String, + + /// The UUID + pub uuid: String, + + /// The network address where this machine can be reached + pub addr: Option<String>, + + /// The amount of RAM (in MB) assigned to this machine + pub mem: Memory, + + /// The amount of vCPUs assigned to this machine + pub cpu_count: CpuCount, + + #[serde(skip)] + domain: Option<Domain>, +} + +impl PartialEq for Planet { + fn eq(&self, other: &Self) -> bool { + self.uuid == other.uuid + } +} + +impl TryFrom<Domain> for Planet { + type Error = Error; + + fn try_from(d: Domain) -> Result<Self, Self::Error> { + let c = d.get_connect()?; + + // This... feels wrong + // + // I know it probably works + // + // Based on code by Cadey in waifud + let addr: Option<String> = if d.is_active()? { + let mut addr: Vec<String> = d + .interface_addresses(virt::domain::VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE, 0)? + .into_iter() + .map(|iface| iface.addrs.clone()) + .filter(|addrs| addrs.get(0).is_some()) + .map(|addrs| addrs.get(0).unwrap().clone().addr) + .collect(); + + if addr.get(0).is_none() { + Some(String::from("localhost")) + } else { + Some(addr.swap_remove(0)) + } + } else { + None + }; + + Ok(Self { + name: d.get_name()?, + host: c.get_hostname()?, + addr, + uuid: d.get_uuid_string()?, + mem: d.get_max_memory()?.into(), + cpu_count: d.get_max_vcpus()?.into(), + domain: Some(d), + }) + } +} + + +impl TryFrom<&Domain> for Planet { + type Error = Error; + + fn try_from(d: &Domain) -> Result<Self, Self::Error> { + let c = d.get_connect()?; + + // This... feels wrong + // + // I know it probably works + // + // Based on code by Cadey in waifud + let addr: Option<String> = if d.is_active()? { + let mut addr: Vec<String> = d + .interface_addresses(virt::domain::VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE, 0)? + .into_iter() + .map(|iface| iface.addrs.clone()) + .filter(|addrs| addrs.get(0).is_some()) + .map(|addrs| addrs.get(0).unwrap().clone().addr) + .collect(); + + if addr.get(0).is_none() { + Some(String::from("localhost")) + } else { + Some(addr.swap_remove(0)) + } + } else { + None + }; + + Ok(Self { + name: d.get_name()?, + host: c.get_hostname()?, + addr, + uuid: d.get_uuid_string()?, + mem: d.get_max_memory()?.into(), + cpu_count: d.get_max_vcpus()?.into(), + domain: Some(*d), + }) + } +} + +#[repr(u32)] +#[derive(Serialize, Deserialize)] +pub enum Health { + Unknown = 0, + Running = 1, + Blocked = 2, + Paused = 3, + ShuttingDown = 4, + ShutDown = 5, + Crashed = 6, + GuestSuspended = 7 +} + +impl Planet { + fn get_status(&self) -> Result<Health, Error> { + let d = match self.domain { + Some(d) => d, + None => { + return Err(Error::Other(String::from("No domain connection found"))); + } + }; + + let state = d.get_state()?; + + Ok(state.0 as Health) + } +} |