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 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 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, /// 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, } impl PartialEq for Planet { fn eq(&self, other: &Self) -> bool { self.uuid == other.uuid } } impl TryFrom for Planet { type Error = Error; fn try_from(d: Domain) -> Result { let c = d.get_connect()?; // This... feels wrong // // I know it probably works // // Based on code by Cadey in waifud let addr: Option = if d.is_active()? { let mut addr: Vec = 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 { let c = d.get_connect()?; // This... feels wrong // // I know it probably works // // Based on code by Cadey in waifud let addr: Option = if d.is_active()? { let mut addr: Vec = 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 { 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) } }