-
Notifications
You must be signed in to change notification settings - Fork 124
internals: Add new (experimental) bootc internals fsck
#1178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# bootc internals fsck | ||
|
||
Experimental features are subject to change or removal. Please | ||
do provide feedback on them. | ||
|
||
## Using `bootc internals fsck` | ||
|
||
This command expects a booted system, and performs consistency checks | ||
in a read-only fashion. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
//! # Perform consistency checking. | ||
//! | ||
//! This is an internal module, backing the experimental `bootc internals fsck` | ||
//! command. | ||
|
||
// Unfortunately needed here to work with linkme | ||
#![allow(unsafe_code)] | ||
|
||
use std::future::Future; | ||
use std::pin::Pin; | ||
use std::process::Command; | ||
|
||
use cap_std::fs::{Dir, MetadataExt as _}; | ||
use cap_std_ext::cap_std; | ||
use cap_std_ext::dirext::CapStdExtDirExt; | ||
use linkme::distributed_slice; | ||
|
||
use crate::store::Storage; | ||
|
||
/// A lint check has failed. | ||
#[derive(thiserror::Error, Debug)] | ||
struct FsckError(String); | ||
|
||
/// The outer error is for unexpected fatal runtime problems; the | ||
/// inner error is for the check failing in an expected way. | ||
type FsckResult = anyhow::Result<std::result::Result<(), FsckError>>; | ||
|
||
/// Everything is OK - we didn't encounter a runtime error, and | ||
/// the targeted check passed. | ||
fn fsck_ok() -> FsckResult { | ||
Ok(Ok(())) | ||
} | ||
|
||
/// We successfully found a failure. | ||
fn fsck_err(msg: impl AsRef<str>) -> FsckResult { | ||
Ok(Err(FsckError::new(msg))) | ||
} | ||
|
||
impl std::fmt::Display for FsckError { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
f.write_str(&self.0) | ||
} | ||
} | ||
|
||
impl FsckError { | ||
fn new(msg: impl AsRef<str>) -> Self { | ||
Self(msg.as_ref().to_owned()) | ||
} | ||
} | ||
|
||
type FsckFn = fn(&Storage) -> FsckResult; | ||
type AsyncFsckFn = fn(&Storage) -> Pin<Box<dyn Future<Output = FsckResult> + '_>>; | ||
#[derive(Debug)] | ||
enum FsckFnImpl { | ||
Sync(FsckFn), | ||
Async(AsyncFsckFn), | ||
} | ||
|
||
impl From<FsckFn> for FsckFnImpl { | ||
fn from(value: FsckFn) -> Self { | ||
Self::Sync(value) | ||
} | ||
} | ||
|
||
impl From<AsyncFsckFn> for FsckFnImpl { | ||
fn from(value: AsyncFsckFn) -> Self { | ||
Self::Async(value) | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
struct FsckCheck { | ||
name: &'static str, | ||
ordering: u16, | ||
f: FsckFnImpl, | ||
} | ||
|
||
#[distributed_slice] | ||
pub(crate) static FSCK_CHECKS: [FsckCheck]; | ||
|
||
impl FsckCheck { | ||
pub(crate) const fn new(name: &'static str, ordering: u16, f: FsckFnImpl) -> Self { | ||
FsckCheck { name, ordering, f } | ||
} | ||
} | ||
|
||
#[distributed_slice(FSCK_CHECKS)] | ||
static CHECK_RESOLVCONF: FsckCheck = | ||
FsckCheck::new("etc-resolvconf", 5, FsckFnImpl::Sync(check_resolvconf)); | ||
/// See https://github.com/containers/bootc/pull/1096 and https://github.com/containers/bootc/pull/1167 | ||
/// Basically verify that if /usr/etc/resolv.conf exists, it is not a zero-sized file that was | ||
/// probably injected by buildah and that bootc should have removed. | ||
/// | ||
/// Note that this fsck check can fail for systems upgraded from old bootc right now, as | ||
/// we need the *new* bootc to fix it. | ||
/// | ||
/// But at the current time fsck is an experimental feature that we should only be running | ||
/// in our CI. | ||
fn check_resolvconf(storage: &Storage) -> FsckResult { | ||
// For now we only check the booted deployment. | ||
if storage.booted_deployment().is_none() { | ||
return fsck_ok(); | ||
} | ||
// Read usr/etc/resolv.conf directly. | ||
let usr = Dir::open_ambient_dir("/usr", cap_std::ambient_authority())?; | ||
let Some(meta) = usr.symlink_metadata_optional("etc/resolv.conf")? else { | ||
return fsck_ok(); | ||
}; | ||
if meta.is_file() && meta.size() == 0 { | ||
return fsck_err("Found usr/etc/resolv.conf as zero-sized file"); | ||
} | ||
fsck_ok() | ||
} | ||
|
||
pub(crate) async fn fsck(storage: &Storage, mut output: impl std::io::Write) -> anyhow::Result<()> { | ||
let mut checks = FSCK_CHECKS.static_slice().iter().collect::<Vec<_>>(); | ||
checks.sort_by(|a, b| a.ordering.cmp(&b.ordering)); | ||
|
||
let mut errors = false; | ||
for check in checks.iter() { | ||
let name = check.name; | ||
let r = match check.f { | ||
FsckFnImpl::Sync(f) => f(&storage), | ||
FsckFnImpl::Async(f) => f(&storage).await, | ||
}; | ||
match r { | ||
Ok(Ok(())) => { | ||
println!("ok: {name}"); | ||
} | ||
Ok(Err(e)) => { | ||
errors = true; | ||
writeln!(output, "fsck error: {name}: {e}")?; | ||
} | ||
Err(e) => { | ||
errors = true; | ||
writeln!(output, "Unexpected runtime error in check {name}: {e}")?; | ||
} | ||
} | ||
} | ||
if errors { | ||
anyhow::bail!("Encountered errors") | ||
} | ||
|
||
// Run an `ostree fsck` (yes, ostree exposes enough APIs | ||
// that we could reimplement this in Rust, but eh) | ||
let st = Command::new("ostree") | ||
.arg("fsck") | ||
.stdin(std::process::Stdio::inherit()) | ||
.status()?; | ||
if !st.success() { | ||
anyhow::bail!("ostree fsck failed"); | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
use std assert | ||
use tap.nu | ||
|
||
tap begin "Run fsck" | ||
|
||
# That's it, just ensure we've run a fsck on our basic install. | ||
bootc internals fsck | ||
|
||
tap ok |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.