use std::io::ErrorKind;
use camino::Utf8Path;
use color_eyre::eyre::Report;
use tracing::{info, warn};
use super::password::has_cluster_marker;
use crate::{
error::{BootstrapError, BootstrapErrorKind, BootstrapResult},
observability::LOG_TARGET,
};
pub(super) fn discard_orphaned_password_file(
data_dir: &Utf8Path,
password_file: &Utf8Path,
) -> BootstrapResult<bool> {
if has_cluster_marker(data_dir).map_err(|failure| failure.error)? {
return Ok(false);
}
match std::fs::remove_file(password_file) {
Ok(()) => {
log_discarded(data_dir, password_file);
Ok(true)
}
Err(err) if err.kind() == ErrorKind::NotFound => Ok(false),
Err(err) => Err(removal_failed(data_dir, password_file, err)),
}
}
fn removal_failed(
data_dir: &Utf8Path,
password_file: &Utf8Path,
err: std::io::Error,
) -> BootstrapError {
warn!(
target: LOG_TARGET,
data_dir = %data_dir,
password_file = %password_file,
error_kind = ?err.kind(),
"stale password file could not be removed"
);
BootstrapError::new(
BootstrapErrorKind::ClusterPasswordUnreadable,
Report::new(err).wrap_err(format!(
"data directory {data_dir} holds no cluster, but the stale password file \
{password_file} cannot be removed; remove it before bootstrapping"
)),
)
}
fn log_discarded(data_dir: &Utf8Path, password_file: &Utf8Path) {
info!(
target: LOG_TARGET,
data_dir = %data_dir,
password_file = %password_file,
"discarded a password file left by a reaped cluster"
);
}
#[cfg(test)]
#[path = "stale_password_tests.rs"]
mod tests;