use serde::{Deserialize, Serialize}; use std::{fmt, net::Ipv4Addr, str::FromStr}; use trust_dns_proto::rr::Name; use crate::net::{cidr::CidrV4, mac::MacAddr}; #[derive(Copy, Clone, Debug, Serialize, Deserialize)] #[repr(u32)] pub enum DomainState { NoState = 0u32, Running, Blocked, Paused, ShuttingDown, ShutOff, Crashed, Suspended, Unknown(u32), } impl Default for DomainState { fn default() -> Self { Self::NoState } } impl From for DomainState { fn from(value: u32) -> Self { match value { 0 => Self::NoState, 1 => Self::Running, 2 => Self::Blocked, 3 => Self::Paused, 4 => Self::ShuttingDown, 5 => Self::ShutOff, 6 => Self::Crashed, 7 => Self::Suspended, other => Self::Unknown(other), } } } impl fmt::Display for DomainState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{}", match self { Self::NoState => "no state".to_owned(), Self::Running => "running".to_owned(), Self::Blocked => "blocked".to_owned(), Self::Paused => "paused".to_owned(), Self::ShuttingDown => "shutting down".to_owned(), Self::ShutOff => "shut off".to_owned(), Self::Crashed => "crashed".to_owned(), Self::Suspended => "suspended".to_owned(), Self::Unknown(code) => format!("unknown ({})", code), } ) } } /// Struct representing a VM instance. #[derive(Debug, Serialize, Deserialize)] pub struct Instance { pub name: String, pub uuid: uuid::Uuid, pub lease: Option, pub state: DomainState, } /// Struct representing a logical "lease" held by a VM. #[derive(Debug, Serialize, Deserialize)] pub struct Lease { /// The IPv4 address held by the Lease pub addr: CidrV4, /// The MAC address associated by the Lease pub mac_addr: MacAddr, } /// Struct representing a subnet used by the host for virtual /// networking. #[derive(Debug, Serialize, Deserialize)] pub struct Subnet { /// The name of the interface the subnet is accessible via. pub ifname: IfaceStr, pub data: SubnetData, } #[derive(Debug, Serialize, Deserialize)] pub struct SubnetData { /// The network information for the subnet. pub network: CidrV4, /// The first host address that can be assigned dynamically /// on the subnet. pub start_host: Ipv4Addr, /// The last host address that can be assigned dynamically /// on the subnet. pub end_host: Ipv4Addr, /// The default gateway for the subnet. pub gateway4: Option, /// The primary DNS server for the subnet. pub dns: Vec, /// The base domain used for DNS lookup. pub domain_name: Option, } /// A wrapper struct for [u8; 16], representing the maximum length /// for an interface's name. #[derive(Debug, Serialize, Deserialize)] pub struct IfaceStr { name: [u8; 16], } impl AsRef<[u8]> for IfaceStr { fn as_ref(&self) -> &[u8] { &self.name } } #[derive(Debug, Serialize, Deserialize)] pub enum ParseError { BadSize(String), } impl fmt::Display for ParseError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Interface name must be at most 15 characters") } } impl std::error::Error for ParseError {} impl FromStr for IfaceStr { type Err = ParseError; fn from_str(s: &str) -> Result { if s.bytes().len() > 15 { Err(Self::Err::BadSize(s.to_owned())) } else { Ok(IfaceStr { name: { let mut ifstr = [0u8; 16]; let bytes = s.as_bytes(); ifstr[..bytes.len()].copy_from_slice(&bytes[..bytes.len()]); ifstr }, }) } } } impl fmt::Display for IfaceStr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{}", std::str::from_utf8(&self.name) .map(|a| a.trim_end_matches(char::from(0))) .map_err(|_| fmt::Error)? ) } }