Skip to content

Commit 71f5ace

Browse files
Johan-Liebert1cgwalters
authored andcommitted
composefs/update: Ensure idempotency on update
Handle the following cases we can encounter on `bootc udpate` 1. The verity is the same as that of the currently booted deployment - Nothing to do here in case of update as we're currently booted. But if we're switching then we update the target imageref in the .origin file for the deployment 2. The verity is the same as that of the staged deployment - Nothing to do, as we only get a "staged" deployment if we have /run/composefs/staged-deployment which is the last thing we create while upgrading 3. The verity is the same as that of the rollback deployment or any other deployment we have already deployed - Nothing to do since this is a rollback deployment which means this was unstaged at some point 4. The verity is not found - The update/switch might've been canceled before /run/composefs/staged-deployment was created, or at any other point in time, or it's a new one. Any which way, we can overwrite everything. In this case we remove all the staged bootloader entries, if any, and remove the entire state directory, as it would most probably be in an inconsistent state. Signed-off-by: Pragyan Poudyal <[email protected]>
1 parent e747216 commit 71f5ace

File tree

2 files changed

+272
-68
lines changed

2 files changed

+272
-68
lines changed

crates/lib/src/bootc_composefs/state.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
use std::io::Write;
2+
use std::ops::Deref;
13
use std::os::unix::fs::symlink;
4+
use std::path::Path;
25
use std::{fs::create_dir_all, process::Command};
36

47
use anyhow::{Context, Result};
@@ -8,7 +11,7 @@ use bootc_mount::tempmount::TempMount;
811
use bootc_utils::CommandRunExt;
912
use camino::Utf8PathBuf;
1013
use cap_std_ext::cap_std::ambient_authority;
11-
use cap_std_ext::cap_std::fs::Dir;
14+
use cap_std_ext::cap_std::fs::{Dir, Permissions, PermissionsExt};
1215
use cap_std_ext::dirext::CapStdExtDirExt;
1316
use composefs::fsverity::{FsVerityHashValue, Sha512HashValue};
1417
use fn_error_context::context;
@@ -23,6 +26,7 @@ use crate::bootc_composefs::boot::BootType;
2326
use crate::bootc_composefs::repo::get_imgref;
2427
use crate::bootc_composefs::status::get_sorted_type1_boot_entries;
2528
use crate::parsers::bls_config::BLSConfigType;
29+
use crate::store::{BootedComposefs, Storage};
2630
use crate::{
2731
composefs_consts::{
2832
COMPOSEFS_CMDLINE, COMPOSEFS_STAGED_DEPLOYMENT_FNAME, COMPOSEFS_TRANSIENT_STATE_DIR,
@@ -104,6 +108,49 @@ pub(crate) fn copy_etc_to_state(
104108
cp_ret
105109
}
106110

111+
/// Updates the currently booted image's target imgref
112+
pub(crate) fn update_target_imgref_in_origin(
113+
storage: &Storage,
114+
booted_cfs: &BootedComposefs,
115+
imgref: &ImageReference,
116+
) -> Result<()> {
117+
let path = Path::new(STATE_DIR_RELATIVE).join(booted_cfs.cmdline.digest.deref());
118+
119+
let state_dir = storage
120+
.physical_root
121+
.open_dir(path)
122+
.context("Opening state dir")?;
123+
124+
let origin_filename = format!("{}.origin", booted_cfs.cmdline.digest.deref());
125+
126+
let origin_file = state_dir
127+
.read_to_string(&origin_filename)
128+
.context("Reading origin file")?;
129+
130+
let mut ini =
131+
tini::Ini::from_string(&origin_file).context("Failed to parse file origin file as ini")?;
132+
133+
// Replace the origin
134+
ini = ini.section("origin").item(
135+
ORIGIN_CONTAINER,
136+
format!("ostree-unverified-image:{imgref}"),
137+
);
138+
139+
state_dir
140+
.atomic_replace_with(origin_filename, move |f| -> std::io::Result<_> {
141+
f.write_all(ini.to_string().as_bytes())?;
142+
f.flush()?;
143+
144+
let perms = Permissions::from_mode(0o644);
145+
f.get_mut().as_file_mut().set_permissions(perms)?;
146+
147+
Ok(())
148+
})
149+
.context("Writing to origin file")?;
150+
151+
Ok(())
152+
}
153+
107154
/// Creates and populates /sysroot/state/deploy/image_id
108155
#[context("Writing composefs state")]
109156
pub(crate) fn write_composefs_state(

0 commit comments

Comments
 (0)