From 16cccf1261bc916f951de5819160b3d4b724f314 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 | 53 ++++++++++++++++++++++++++++ src/bootupd.rs | 15 ++++++++ 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 +++-- 7 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 src/failpoints.rs diff --git a/Cargo.lock b/Cargo.lock index 2cbaafb9..6498eb3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,6 +82,7 @@ dependencies = [ "bincode", "cap-std-ext", "camino", + "cap-std-ext", "chrono", "clap", "env_logger", @@ -167,6 +168,58 @@ version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +[[package]] +name = "cap-primitives" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d00bd8d26c4270d950eaaa837387964a2089a1c3c349a690a1fa03221d29531" +dependencies = [ + "ambient-authority", + "fs-set-times", + "io-extras", + "io-lifetimes", + "ipnet", + "maybe-owned", + "rustix", + "windows-sys 0.52.0", + "winx", +] + +[[package]] +name = "cap-std" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19eb8e3d71996828751c1ed3908a439639752ac6bdc874e41469ef7fc15fbd7f" +dependencies = [ + "cap-primitives", + "io-extras", + "io-lifetimes", + "rustix", +] + +[[package]] +name = "cap-std-ext" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0279cf1f7b6cbeeb98e6946e8fea58136f691d4d0aa8c775f4439a05030a481" +dependencies = [ + "cap-primitives", + "cap-tempfile", + "rustix", +] + +[[package]] +name = "cap-tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53880047c3f37cd64947775f0526795498d614182603a718c792616b762ce777" +dependencies = [ + "cap-std", + "rand", + "rustix", + "uuid", +] + [[package]] name = "cc" version = "1.0.83" 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/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}