Skip to content

Commit 9f1064b

Browse files
committed
install: Extract a unified SourceInfo struct
This data keeps track of the container and ostree commit information. Prep for `install --takeover` where we want to serialize this data. Signed-off-by: Colin Walters <[email protected]>
1 parent aa9bc7c commit 9f1064b

File tree

1 file changed

+66
-55
lines changed

1 file changed

+66
-55
lines changed

lib/src/install.rs

Lines changed: 66 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use ostree_ext::prelude::Cast;
3131
use serde::{Deserialize, Serialize};
3232

3333
use self::baseline::InstallBlockDeviceOpts;
34+
use crate::containerenv::ContainerExecutionInfo;
3435
use crate::lsm::lsm_label;
3536
use crate::task::Task;
3637
use crate::utils::run_in_host_mountns;
@@ -158,17 +159,28 @@ pub(crate) struct InstallToFilesystemOpts {
158159
pub(crate) config_opts: InstallConfigOpts,
159160
}
160161

161-
// Shared read-only global state
162-
pub(crate) struct State {
162+
/// Global state captured from the container.
163+
#[derive(Debug, Clone)]
164+
pub(crate) struct SourceInfo {
163165
/// Image reference we'll pull from (today always containers-storage: type)
164-
source_imageref: ostree_container::ImageReference,
166+
pub(crate) imageref: ostree_container::ImageReference,
165167
/// The digest to use for pulls
166-
source_digest: String,
168+
pub(crate) digest: String,
169+
/// The embedded base OSTree commit checksum
170+
#[allow(dead_code)]
171+
pub(crate) commit: String,
172+
/// Whether or not SELinux appears to be enabled in the source commit
173+
pub(crate) selinux: bool,
174+
}
175+
176+
// Shared read-only global state
177+
pub(crate) struct State {
178+
pub(crate) source: SourceInfo,
167179
/// Force SELinux off in target system
168-
override_disable_selinux: bool,
169-
config_opts: InstallConfigOpts,
170-
target_opts: InstallTargetOpts,
171-
install_config: config::InstallConfiguration,
180+
pub(crate) override_disable_selinux: bool,
181+
pub(crate) config_opts: InstallConfigOpts,
182+
pub(crate) target_opts: InstallTargetOpts,
183+
pub(crate) install_config: config::InstallConfiguration,
172184
}
173185

174186
/// Path to initially deployed version information
@@ -261,6 +273,45 @@ impl FromStr for MountSpec {
261273
}
262274
}
263275

276+
impl SourceInfo {
277+
// Inspect container information and convert it to an ostree image reference
278+
// that pulls from containers-storage.
279+
#[context("Gathering source info from container env")]
280+
pub(crate) fn from_container(container_info: &ContainerExecutionInfo) -> Result<Self> {
281+
if !container_info.engine.starts_with("podman") {
282+
anyhow::bail!("Currently this command only supports being executed via podman");
283+
}
284+
if container_info.imageid.is_empty() {
285+
anyhow::bail!("Invalid empty imageid");
286+
}
287+
let imageref = ostree_container::ImageReference {
288+
transport: ostree_container::Transport::ContainerStorage,
289+
name: container_info.image.clone(),
290+
};
291+
let digest = crate::podman::imageid_to_digest(&container_info.imageid)?;
292+
let cancellable = ostree::gio::Cancellable::NONE;
293+
let commit = Task::new("Reading ostree commit", "ostree")
294+
.args(["--repo=/ostree/repo", "rev-parse", "--single"])
295+
.quiet()
296+
.read()?;
297+
let root = cap_std::fs::Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
298+
let repo = ostree::Repo::open_at_dir(&root, "ostree/repo")?;
299+
let root = repo
300+
.read_commit(commit.trim(), cancellable)
301+
.context("Reading commit")?
302+
.0;
303+
let root = root.downcast_ref::<ostree::RepoFile>().unwrap();
304+
let xattrs = root.xattrs(cancellable)?;
305+
let selinux = crate::lsm::xattrs_have_selinux(&xattrs);
306+
Ok(Self {
307+
imageref,
308+
digest,
309+
commit,
310+
selinux,
311+
})
312+
}
313+
}
314+
264315
mod config {
265316
use super::*;
266317

@@ -379,7 +430,7 @@ async fn initialize_ostree_root_from_self(
379430
} else {
380431
ostree_container::OstreeImageReference {
381432
sigverify: target_sigverify,
382-
imgref: state.source_imageref.clone(),
433+
imgref: state.source.imageref.clone(),
383434
}
384435
};
385436

@@ -420,15 +471,15 @@ async fn initialize_ostree_root_from_self(
420471
let src_imageref = if skopeo_supports_containers_storage()? {
421472
// We always use exactly the digest of the running image to ensure predictability.
422473
let spec =
423-
crate::utils::digested_pullspec(&state.source_imageref.name, &state.source_digest);
474+
crate::utils::digested_pullspec(&state.source.imageref.name, &state.source.digest);
424475
ostree_container::ImageReference {
425476
transport: ostree_container::Transport::ContainerStorage,
426477
name: spec,
427478
}
428479
} else {
429480
let td = tempfile::tempdir_in("/var/tmp")?;
430481
let path: &Utf8Path = td.path().try_into().unwrap();
431-
let r = copy_to_oci(&state.source_imageref, path)?;
482+
let r = copy_to_oci(&state.source.imageref, path)?;
432483
temporary_dir = Some(td);
433484
r
434485
};
@@ -562,39 +613,12 @@ impl RootSetup {
562613
}
563614
}
564615

565-
pub(crate) struct SourceData {
566-
/// The embedded base OSTree commit checksum
567-
#[allow(dead_code)]
568-
pub(crate) commit: String,
569-
/// Whether or not SELinux appears to be enabled in the source commit
570-
pub(crate) selinux: bool,
571-
}
572-
573-
#[context("Gathering source data")]
574-
fn gather_source_data() -> Result<SourceData> {
575-
let cancellable = ostree::gio::Cancellable::NONE;
576-
let commit = Task::new("Reading ostree commit", "ostree")
577-
.args(["--repo=/ostree/repo", "rev-parse", "--single"])
578-
.quiet()
579-
.read()?;
580-
let root = cap_std::fs::Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
581-
let repo = ostree::Repo::open_at_dir(&root, "ostree/repo")?;
582-
let root = repo
583-
.read_commit(commit.trim(), cancellable)
584-
.context("Reading commit")?
585-
.0;
586-
let root = root.downcast_ref::<ostree::RepoFile>().unwrap();
587-
let xattrs = root.xattrs(cancellable)?;
588-
let selinux = crate::lsm::xattrs_have_selinux(&xattrs);
589-
Ok(SourceData { commit, selinux })
590-
}
591-
592616
/// If we detect that the target ostree commit has SELinux labels,
593617
/// and we aren't passed an override to disable it, then ensure
594618
/// the running process is labeled with install_t so it can
595619
/// write arbitrary labels.
596620
pub(crate) fn reexecute_self_for_selinux_if_needed(
597-
srcdata: &SourceData,
621+
srcdata: &SourceInfo,
598622
override_disable_selinux: bool,
599623
) -> Result<bool> {
600624
let mut ret_did_override = false;
@@ -669,18 +693,7 @@ async fn prepare_install(
669693

670694
// This command currently *must* be run inside a privileged container.
671695
let container_info = crate::containerenv::get_container_execution_info()?;
672-
if !container_info.engine.starts_with("podman") {
673-
anyhow::bail!("Currently this command only supports being executed via podman");
674-
}
675-
if container_info.imageid.is_empty() {
676-
anyhow::bail!("Invalid empty imageid");
677-
}
678-
let source_imageref = ostree_container::ImageReference {
679-
transport: ostree_container::Transport::ContainerStorage,
680-
name: container_info.image.clone(),
681-
};
682-
// Find the exact digested image we are running
683-
let source_digest = crate::podman::imageid_to_digest(&container_info.imageid)?;
696+
let source = SourceInfo::from_container(&container_info)?;
684697

685698
// Even though we require running in a container, the mounts we create should be specific
686699
// to this process, so let's enter a private mountns to avoid leaking them.
@@ -698,9 +711,8 @@ async fn prepare_install(
698711
}
699712

700713
// Now, deal with SELinux state.
701-
let srcdata = gather_source_data()?;
702714
let override_disable_selinux =
703-
reexecute_self_for_selinux_if_needed(&srcdata, config_opts.disable_selinux)?;
715+
reexecute_self_for_selinux_if_needed(&source, config_opts.disable_selinux)?;
704716

705717
let install_config = config::load_config()?;
706718

@@ -711,8 +723,7 @@ async fn prepare_install(
711723
bind_mount_from_host("/var/tmp", "/var/tmp")?;
712724
let state = Arc::new(State {
713725
override_disable_selinux,
714-
source_imageref,
715-
source_digest,
726+
source,
716727
config_opts,
717728
target_opts,
718729
install_config,

0 commit comments

Comments
 (0)