#![allow(missing_docs)]
#[allow(unused_imports)]
use crate::disk::{
DiskPressureError, DiskPressureProbe, DiskPressureReport, HostDiskPressureProbe,
RuntimeDiskPressureGuard,
};
#[allow(unused_imports)]
use firkin_types::Size;
#[allow(unused_imports)]
use std::fmt::Display;
#[allow(unused_imports)]
use std::path::{Path, PathBuf};
#[allow(unused_imports)]
use thiserror::Error as ThisError;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RuntimePreflight {
pub(crate) snapshot_root: PathBuf,
pub(crate) log_root: PathBuf,
minimum_free_disk: Size,
}
impl RuntimePreflight {
#[must_use]
pub fn new(
snapshot_root: impl Into<PathBuf>,
log_root: impl Into<PathBuf>,
minimum_free_disk: Size,
) -> Self {
Self {
snapshot_root: snapshot_root.into(),
log_root: log_root.into(),
minimum_free_disk,
}
}
#[must_use]
pub fn snapshot_root(&self) -> &Path {
&self.snapshot_root
}
#[must_use]
pub fn log_root(&self) -> &Path {
&self.log_root
}
#[must_use]
pub const fn minimum_free_disk(&self) -> Size {
self.minimum_free_disk
}
pub fn check(&self) -> Result<RuntimePreflightReport, RuntimePreflightError> {
let mut probe = HostDiskPressureProbe::new();
self.check_with_disk_probe(&mut probe)
}
pub fn check_with_disk_probe<P>(
&self,
disk_probe: &mut P,
) -> Result<RuntimePreflightReport, RuntimePreflightError>
where
P: DiskPressureProbe,
P::Error: Display,
{
Self::check_required_root(&self.snapshot_root)?;
Self::check_required_root(&self.log_root)?;
let snapshot_disk =
RuntimeDiskPressureGuard::new(self.snapshot_root.clone(), self.minimum_free_disk)
.check(disk_probe)
.map_err(|error| RuntimePreflightError::from_disk(&error))?;
let log_disk = RuntimeDiskPressureGuard::new(self.log_root.clone(), self.minimum_free_disk)
.check(disk_probe)
.map_err(|error| RuntimePreflightError::from_disk(&error))?;
Ok(RuntimePreflightReport::new(
self.snapshot_root.clone(),
self.log_root.clone(),
snapshot_disk,
log_disk,
))
}
fn check_required_root(path: &Path) -> Result<(), RuntimePreflightError> {
if path.is_dir() {
Ok(())
} else {
Err(RuntimePreflightError::MissingRoot {
path: path.to_path_buf(),
})
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RuntimePreflightReport {
pub(crate) snapshot_root: PathBuf,
pub(crate) log_root: PathBuf,
snapshot_disk: DiskPressureReport,
log_disk: DiskPressureReport,
}
impl RuntimePreflightReport {
#[must_use]
pub fn new(
snapshot_root: PathBuf,
log_root: PathBuf,
snapshot_disk: DiskPressureReport,
log_disk: DiskPressureReport,
) -> Self {
Self {
snapshot_root,
log_root,
snapshot_disk,
log_disk,
}
}
#[must_use]
pub fn snapshot_root(&self) -> &Path {
&self.snapshot_root
}
#[must_use]
pub fn log_root(&self) -> &Path {
&self.log_root
}
#[must_use]
pub const fn snapshot_disk(&self) -> &DiskPressureReport {
&self.snapshot_disk
}
#[must_use]
pub const fn log_disk(&self) -> &DiskPressureReport {
&self.log_disk
}
}
#[derive(Clone, Debug, PartialEq, Eq, ThisError)]
pub enum RuntimePreflightError {
#[error("required runtime root is missing: {path}")]
MissingRoot {
path: PathBuf,
},
#[error("runtime disk preflight failed: {reason}")]
Disk {
reason: String,
},
}
impl RuntimePreflightError {
fn from_disk<E>(error: &DiskPressureError<E>) -> Self
where
E: Display,
{
Self::Disk {
reason: error.to_string(),
}
}
}