109 lines
3.1 KiB
Rust
109 lines
3.1 KiB
Rust
//! Look up a known machine ID
|
|
use std::sync::Arc;
|
|
|
|
use serde_json::Value;
|
|
use tokio::task;
|
|
use tracing::{debug, error};
|
|
use uuid::Uuid;
|
|
|
|
use crate::config::Configuration;
|
|
use crate::libvirt;
|
|
|
|
/// Look up the machine ID for a host
|
|
///
|
|
/// This function will return the machine ID for a known host, either from the
|
|
/// static map stored in a JSON file or from a libvirt VM host. If no location
|
|
/// has a record for the machine, `None` is returned.
|
|
pub async fn get_machine_id(
|
|
hostname: &str,
|
|
config: Arc<Configuration>,
|
|
) -> Option<Uuid> {
|
|
if let Some(v) = from_map(hostname, config.clone()).await {
|
|
return parse_uuid(&v);
|
|
}
|
|
#[cfg(feature = "libvirt")]
|
|
if let Some(v) = from_libvirt(hostname, config.clone()).await {
|
|
return parse_uuid(&v);
|
|
}
|
|
None
|
|
}
|
|
|
|
/// Look up a machine ID in the JSON map file
|
|
///
|
|
/// This function reads the machine ID map stored in the JSON file. If the
|
|
/// file could not be opened, is not a valid JSON object, or does not contain
|
|
/// an entry for the specified hostname, `None` is returned.
|
|
async fn from_map(
|
|
hostname: &str,
|
|
config: Arc<Configuration>,
|
|
) -> Option<String> {
|
|
let data = match tokio::fs::read_to_string(&config.machine_ids).await {
|
|
Ok(d) => d,
|
|
Err(e) => {
|
|
error!("Failed to read machine ID map file: {}", e);
|
|
return None;
|
|
}
|
|
};
|
|
let res =
|
|
task::spawn_blocking(move || serde_json::from_str::<Value>(&data))
|
|
.await;
|
|
let map = match res {
|
|
Ok(Ok(r)) => r,
|
|
Ok(Err(e)) => {
|
|
error!("Error parsing machine ID map: {}", e);
|
|
return None;
|
|
}
|
|
Err(e) => {
|
|
error!("Unexpected error while parsing JSON: {}", e);
|
|
return None;
|
|
}
|
|
};
|
|
Some(map.as_object()?.get(hostname)?.as_str()?.to_owned())
|
|
}
|
|
|
|
/// Look up a machine ID on the configured libvirt VM hosts
|
|
///
|
|
/// This function iterates over the configured VM hosts and checks each one for
|
|
/// a domain matching the specified hostname. If no VM host is available or
|
|
/// none of the configured hosts have a matching domain, `None` is returned.
|
|
#[cfg(feature = "libvirt")]
|
|
async fn from_libvirt(
|
|
hostname: &str,
|
|
config: Arc<Configuration>,
|
|
) -> Option<String> {
|
|
let hostname = Arc::new(hostname.split('.').next().unwrap().to_string());
|
|
let res = task::spawn_blocking(move || {
|
|
for libvirt in &config.libvirt {
|
|
debug!("Checking {} for {}", libvirt.uri, hostname);
|
|
match libvirt::get_machine_id(&hostname, libvirt) {
|
|
Ok(v) => return Some(v),
|
|
Err(e) => {
|
|
debug!("libvirt error: {}", e);
|
|
}
|
|
};
|
|
}
|
|
None
|
|
})
|
|
.await;
|
|
match res {
|
|
Ok(v) => v,
|
|
Err(e) => {
|
|
error!("Unexpected error while querying libvirt: {}", e);
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Parse a UUID from a string
|
|
///
|
|
/// Returns `None` if the string does not contain a valid UUID.
|
|
fn parse_uuid(value: &str) -> Option<Uuid> {
|
|
Uuid::parse_str(value).map_or_else(
|
|
|e| {
|
|
error!("Invalid UUID: {}", e);
|
|
None
|
|
},
|
|
Some,
|
|
)
|
|
}
|