Skip to content

Commit 4e8ec8b

Browse files
committed
feat(edit): allow setting usrOverlay
Allows setting the usrOverlay within "bootc edit". Since there's no clean ways (that I'm aware of) for switching back from a writable /usr to a readonly one, this follows the recommended commands in the docs, and lazily unmounts /usr.
1 parent 6783c9d commit 4e8ec8b

File tree

5 files changed

+106
-23
lines changed

5 files changed

+106
-23
lines changed

lib/src/cli.rs

+18-23
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
55
use std::ffi::{CString, OsStr, OsString};
66
use std::io::Seek;
7-
use std::os::unix::process::CommandExt;
8-
use std::process::Command;
97

108
use anyhow::{ensure, Context, Result};
119
use camino::Utf8PathBuf;
@@ -26,11 +24,11 @@ use schemars::schema_for;
2624
use serde::{Deserialize, Serialize};
2725

2826
use crate::deploy::RequiredHostSpec;
29-
use crate::lints;
3027
use crate::progress_jsonl::{ProgressWriter, RawProgressFd};
31-
use crate::spec::Host;
3228
use crate::spec::ImageReference;
29+
use crate::spec::{FilesystemOverlay, Host};
3330
use crate::utils::sigpolicy_from_opt;
31+
use crate::{lints, overlay};
3432

3533
/// Shared progress options
3634
#[derive(Debug, Parser, PartialEq, Eq)]
@@ -968,23 +966,25 @@ async fn edit(opts: EditOpts) -> Result<()> {
968966
println!("Edit cancelled, no changes made.");
969967
return Ok(());
970968
}
969+
971970
host.spec.verify_transition(&new_host.spec)?;
972971
let new_spec = RequiredHostSpec::from_spec(&new_host.spec)?;
973972

974-
let prog = ProgressWriter::default();
975-
976-
// We only support two state transitions right now; switching the image,
977-
// or flipping the bootloader ordering.
978-
if host.spec.boot_order != new_host.spec.boot_order {
979-
return crate::deploy::rollback(sysroot).await;
973+
if new_host.spec.usr_overlay != host.spec.usr_overlay {
974+
if let Some(overlay) = new_host.spec.usr_overlay {
975+
crate::overlay::set_usr_overlay(overlay)?;
976+
}
977+
}
978+
if new_host.spec.boot_order != host.spec.boot_order {
979+
crate::deploy::rollback(sysroot).await?;
980+
}
981+
if new_host.spec.image != host.spec.image {
982+
let prog = ProgressWriter::default();
983+
let fetched =
984+
crate::deploy::pull(repo, new_spec.image, None, opts.quiet, prog.clone()).await?;
985+
let stateroot = booted_deployment.osname();
986+
crate::deploy::stage(sysroot, &stateroot, &fetched, &new_spec, prog.clone()).await?;
980987
}
981-
982-
let fetched = crate::deploy::pull(repo, new_spec.image, None, opts.quiet, prog.clone()).await?;
983-
984-
// TODO gc old layers here
985-
986-
let stateroot = booted_deployment.osname();
987-
crate::deploy::stage(sysroot, &stateroot, &fetched, &new_spec, prog.clone()).await?;
988988

989989
sysroot.update_mtime()?;
990990

@@ -993,12 +993,7 @@ async fn edit(opts: EditOpts) -> Result<()> {
993993

994994
/// Implementation of `bootc usroverlay`
995995
async fn usroverlay() -> Result<()> {
996-
// This is just a pass-through today. At some point we may make this a libostree API
997-
// or even oxidize it.
998-
Err(Command::new("ostree")
999-
.args(["admin", "unlock"])
1000-
.exec()
1001-
.into())
996+
overlay::set_usr_overlay(FilesystemOverlay::ReadWrite)
1002997
}
1003998

1004999
/// Perform process global initialization. This should be called as early as possible
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
apiVersion: org.containers.bootc/v1alpha1
2+
kind: BootcHost
3+
metadata:
4+
name: host
5+
spec:
6+
image:
7+
image: quay.io/example/someimage:latest
8+
transport: registry
9+
signature: insecure
10+
usrOverlay: readWrite
11+
status:
12+
staged:
13+
image:
14+
image:
15+
image: quay.io/example/someimage:latest
16+
transport: registry
17+
signature: insecure
18+
architecture: arm64
19+
version: nightly
20+
# This one has nanoseconds, which should be dropped for human consumption
21+
timestamp: 2023-10-14T19:22:15.42Z
22+
imageDigest: sha256:16dc2b6256b4ff0d2ec18d2dbfb06d117904010c8cf9732cdb022818cf7a7566
23+
incompatible: false
24+
pinned: false
25+
ostree:
26+
checksum: 3c6dad657109522e0b2e49bf44b5420f16f0b438b5b9357e5132211cfbad135d
27+
deploySerial: 0
28+
booted:
29+
image:
30+
image:
31+
image: quay.io/example/someimage:latest
32+
transport: registry
33+
signature: insecure
34+
architecture: arm64
35+
version: nightly
36+
timestamp: 2023-09-30T19:22:16Z
37+
imageDigest: sha256:736b359467c9437c1ac915acaae952aad854e07eb4a16a94999a48af08c83c34
38+
incompatible: false
39+
pinned: false
40+
ostree:
41+
checksum: 26836632adf6228d64ef07a26fd3efaf177104efd1f341a2cf7909a3e4e2c72c
42+
deploySerial: 0
43+
rollback: null
44+
isContainer: false

lib/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ mod status;
2727
mod store;
2828
mod task;
2929
mod utils;
30+
mod overlay;
3031

3132
#[cfg(feature = "docgen")]
3233
mod docgen;

lib/src/mount.rs

+15
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,21 @@ pub(crate) fn mount(dev: &str, target: &Utf8Path) -> Result<()> {
129129
)
130130
}
131131

132+
pub(crate) fn unmount(target: &Utf8Path, lazy: bool) -> Result<()> {
133+
let args = if lazy {
134+
vec!["-l", target.as_str()]
135+
} else {
136+
vec![target.as_str()]
137+
};
138+
139+
let description = if lazy {
140+
format!("Lazily unmounting {target}.\nThis may leave lingering mounts if in use")
141+
} else {
142+
format!("Unmounting {target}")
143+
};
144+
Task::new_and_run(description, "umount", args)
145+
}
146+
132147
/// If the fsid of the passed path matches the fsid of the same path rooted
133148
/// at /proc/1/root, it is assumed that these are indeed the same mounted
134149
/// filesystem between container and host.

lib/src/overlay.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//! Handling of deployment overlays
2+
3+
use std::{os::unix::process::CommandExt, process::Command};
4+
5+
use anyhow::Result;
6+
use fn_error_context::context;
7+
8+
use crate::spec;
9+
10+
#[context("Setting /usr overlay")]
11+
pub(crate) fn set_usr_overlay(state: spec::FilesystemOverlay) -> Result<()> {
12+
match state {
13+
spec::FilesystemOverlay::Readonly => {
14+
tracing::info!("Setting /usr overlay to read-only");
15+
// There's no clean way to remove the readwrite overlay, so we lazily unmount it.
16+
crate::mount::unmount(camino::Utf8Path::new("/usr"), true)?;
17+
}
18+
spec::FilesystemOverlay::ReadWrite => {
19+
tracing::info!("Setting /usr overlay to read-write");
20+
// This is just a pass-through today. At some point we may make this a libostree API
21+
// or even oxidize it.
22+
Err(anyhow::Error::from(
23+
Command::new("ostree").args(["admin", "unlock"]).exec(),
24+
))?;
25+
}
26+
}
27+
return Ok({});
28+
}

0 commit comments

Comments
 (0)