From 2c05c92c2474b98cdc97ffa3b50f8763f8197b57 Mon Sep 17 00:00:00 2001 From: HuijingHei Date: Thu, 11 Jul 2024 18:55:59 +0800 Subject: [PATCH] filetree: add failpoint when doing exchange Inspired by https://github.com/coreos/bootupd/pull/669#issuecomment-2220760948 --- Cargo.lock | 12 +++++++----- src/bootupd.rs | 15 +++++++++++++++ src/efi.rs | 2 +- src/failpoints.rs | 21 +++++++++++++++++++++ src/filetree.rs | 2 +- src/main.rs | 2 ++ tests/e2e-update/e2e-update-in-vm.sh | 7 ++++++- tests/e2e-update/e2e-update.sh | 8 ++++++-- 8 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 src/failpoints.rs diff --git a/Cargo.lock b/Cargo.lock index 2cbaafb9..1fe5c1b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,8 +80,8 @@ version = "0.2.20" dependencies = [ "anyhow", "bincode", - "cap-std-ext", "camino", + "cap-std-ext", "chrono", "clap", "env_logger", @@ -111,6 +111,12 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +[[package]] +name = "camino" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" + [[package]] name = "cap-primitives" version = "3.2.0" @@ -162,10 +168,6 @@ dependencies = [ "rustix", "uuid", ] -name = "camino" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" [[package]] name = "cc" diff --git a/src/bootupd.rs b/src/bootupd.rs index 72d025d0..4f029e83 100644 --- a/src/bootupd.rs +++ b/src/bootupd.rs @@ -396,6 +396,7 @@ pub(crate) fn print_status(status: &Status) -> Result<()> { } pub(crate) fn client_run_update() -> Result<()> { + crate::try_fail_point!("update"); let status: Status = status()?; if status.components.is_empty() && status.adoptable.is_empty() { println!("No components installed."); @@ -489,3 +490,17 @@ pub(crate) fn client_run_validate() -> Result<()> { } Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_failpoint_update() { + let guard = fail::FailScenario::setup(); + fail::cfg("update", "return").unwrap(); + let r = client_run_update(); + assert_eq!(r.is_err(), true); + guard.teardown(); + } +} diff --git a/src/efi.rs b/src/efi.rs index ecaee822..ed53e854 100644 --- a/src/efi.rs +++ b/src/efi.rs @@ -141,7 +141,7 @@ impl Efi { log::debug!("Not booted via EFI, skipping firmware update"); return Ok(()); } - let sysroot = Dir::open_ambient_dir(&Path::new("/"), cap_std::ambient_authority())?; + let sysroot = Dir::open_ambient_dir("/", cap_std::ambient_authority())?; let product_name = get_product_name(&sysroot)?; log::debug!("Get product name: {product_name}"); assert!(product_name.len() > 0); diff --git a/src/failpoints.rs b/src/failpoints.rs new file mode 100644 index 00000000..78dce44f --- /dev/null +++ b/src/failpoints.rs @@ -0,0 +1,21 @@ +//! Wrappers and utilities on top of the `fail` crate. +// SPDX-License-Identifier: Apache-2.0 OR MIT + +/// TODO: Use https://github.com/tikv/fail-rs/pull/68 once it merges +/// copy from https://github.com/coreos/rpm-ostree/commit/aa8d7fb0ceaabfaf10252180e2ddee049d07aae3#diff-adcc419e139605fae34d17b31418dbaf515af2fe9fb766fcbdb2eaad862b3daa +#[macro_export] +macro_rules! try_fail_point { + ($name:expr) => {{ + if let Some(e) = fail::eval($name, |msg| { + let msg = msg.unwrap_or_else(|| "synthetic failpoint".to_string()); + anyhow::Error::msg(msg) + }) { + return Err(From::from(e)); + } + }}; + ($name:expr, $cond:expr) => {{ + if $cond { + $crate::try_fail_point!($name); + } + }}; +} diff --git a/src/filetree.rs b/src/filetree.rs index 047ca384..8234dcba 100644 --- a/src/filetree.rs +++ b/src/filetree.rs @@ -395,6 +395,7 @@ pub(crate) fn apply_diff( .local_rename(tmp, dst) .with_context(|| format!("rename for {} and {:?}", tmp, dst))?; } + crate::try_fail_point!("update::exchange"); } // Ensure all of the updates & changes are written persistently to disk if !opts.skip_sync { @@ -705,7 +706,6 @@ mod tests { let b_btime_foo_new = fs::metadata(pb.join(foo))?.created()?; assert_eq!(b_btime_foo_new, b_btime_foo); } - Ok(()) } } diff --git a/src/main.rs b/src/main.rs index b075bde0..7c7cb40c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,6 +24,7 @@ mod component; mod coreos; #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] mod efi; +mod failpoints; mod filesystem; mod filetree; #[cfg(any( @@ -43,6 +44,7 @@ use clap::crate_name; /// Binary entrypoint, for both daemon and client logic. fn main() { + let _scenario = fail::FailScenario::setup(); let exit_code = run_cli(); std::process::exit(exit_code); } diff --git a/tests/e2e-update/e2e-update-in-vm.sh b/tests/e2e-update/e2e-update-in-vm.sh index fd969cad..0956bdfa 100755 --- a/tests/e2e-update/e2e-update-in-vm.sh +++ b/tests/e2e-update/e2e-update-in-vm.sh @@ -67,7 +67,12 @@ tmpefimount=$(mount_tmp_efi) assert_not_has_file ${tmpefimount}/EFI/fedora/test-bootupd.efi -bootupctl update | tee out.txt +if env FAILPOINTS='update::exchange=return' bootupctl update -vvv 2>err.txt; then + fatal "should have errored" +fi +assert_file_has_content err.txt "error: .*synthetic failpoint" + +bootupctl update -vvv | tee out.txt assert_file_has_content out.txt "Previous EFI: .*" assert_file_has_content out.txt "Updated EFI: ${TARGET_GRUB_PKG}.*,test-bootupd-payload-1.0" diff --git a/tests/e2e-update/e2e-update.sh b/tests/e2e-update/e2e-update.sh index e45623f7..5fc19e87 100755 --- a/tests/e2e-update/e2e-update.sh +++ b/tests/e2e-update/e2e-update.sh @@ -24,10 +24,14 @@ export test_tmpdir=${testtmp} # This is new content for our update test_bootupd_payload_file=/boot/efi/EFI/fedora/test-bootupd.efi +test_bootupd_payload_file1=/boot/efi/EFI/BOOT/test-bootupd1.efi build_rpm test-bootupd-payload \ - files ${test_bootupd_payload_file} \ + files "${test_bootupd_payload_file} + ${test_bootupd_payload_file1}" \ install "mkdir -p %{buildroot}/$(dirname ${test_bootupd_payload_file}) - echo test-payload > %{buildroot}/${test_bootupd_payload_file}" + echo test-payload > %{buildroot}/${test_bootupd_payload_file} + mkdir -p %{buildroot}/$(dirname ${test_bootupd_payload_file1}) + echo test-payload1 > %{buildroot}/${test_bootupd_payload_file1}" # Start in cosa dir cd ${COSA_DIR}