Skip to content

Commit

Permalink
WIP: Retrieve bound images when staging new image
Browse files Browse the repository at this point in the history
Signed-off-by: Chris Kyrouac <ckyrouac@redhat.com>
  • Loading branch information
ckyrouac committed Jul 1, 2024
1 parent 5e9279d commit 29d0b99
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 14 deletions.
116 changes: 116 additions & 0 deletions lib/src/boundimage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use anyhow::Result;

use ostree_ext::ostree::Deployment;
use ostree_ext::sysroot::SysrootLock;

use std::fs;
use std::path::Path;

use crate::task::Task;

use tempfile::TempDir;

const BOOTC_QUADLET_DIR: &'static str = "/etc/containers/systemd/bootc";
const QUADLET_BINARY: &'static str = "/usr/lib/systemd/system-generators/podman-system-generator";
const SYSTEMD_DIR: &'static str = "/etc/systemd/system";

pub(crate) struct BoundImageManager {
quadlet_unit_dir: String,
units: Vec<String>,
temp_dir: TempDir,
}

impl BoundImageManager {
pub(crate) fn new(deployment: &Deployment, sysroot: &SysrootLock) -> Result<BoundImageManager> {
let deployment_dir = sysroot.deployment_dirpath(&deployment);
let quadlet_unit_dir = format!("/{deployment_dir}/{BOOTC_QUADLET_DIR}");

let temp_dir = TempDir::new()?;
let bound_image_manager = BoundImageManager {
quadlet_unit_dir,
units: Vec::new(),
temp_dir,
};
Ok(bound_image_manager)
}

pub(crate) fn run(&mut self) -> Result<()> {
if Path::new(&self.quadlet_unit_dir).exists() {
self.run_quadlet()?;
self.move_units()?;
self.restart_systemd()?;
self.start_new_services()?;
}

Ok(())
}

// Run podman-system-generator to generate the systemd units
// the output is written to a temporary directory
// in order to track the generated units.
// The generated units need to be moved to /etc/systemd/system
// to be started by systemd.
fn run_quadlet(&self) -> Result<()> {
Task::new(
format!("Running quadlet on {:#}", self.quadlet_unit_dir),
QUADLET_BINARY,
)
.arg(self.temp_dir.path())
.env(&"QUADLET_UNIT_DIRS".to_string(), &self.quadlet_unit_dir)
.run()?;

Ok(())
}

fn move_units(&mut self) -> Result<()> {
let entries = fs::read_dir(self.temp_dir.path())?;
for bound_image in entries {
let bound_image = bound_image?;
let bound_image_path = bound_image.path();
let unit_name = bound_image_path.file_name().unwrap().to_str().unwrap();

//move the unit file from the bootc subdirectory to the root systemd directory
let systemd_dst = format!("{SYSTEMD_DIR}/{unit_name}");
if !Path::new(systemd_dst.as_str()).exists() {
fs::copy(&bound_image_path, systemd_dst)?;
}

self.units.push(unit_name.to_string());
}

Ok(())
}

fn restart_systemd(&self) -> Result<()> {
Task::new_and_run("Reloading systemd", "/usr/bin/systemctl", ["daemon-reload"])?;
Ok(())
}

fn start_new_services(&self) -> Result<()> {
//TODO: do this in parallel
for unit in &self.units {
Task::new_and_run(
format!("Starting target: {:#}", unit),
"/usr/bin/systemctl",
["start", unit],
)?;
}
Ok(())
}
}

impl Drop for BoundImageManager {
//remove the generated units from the root systemd directory
//and stop them to remove the services from systemd
fn drop(&mut self) {
for unit in &self.units {
//TODO: error handling
let _ = fs::remove_file(format!("{SYSTEMD_DIR}/{unit}"));
let _ = Task::new_and_run(
format!("Starting target: {:#}", unit),
"/usr/bin/systemctl",
["stop", unit],
);
}
}
}
28 changes: 17 additions & 11 deletions lib/src/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,20 +278,21 @@ async fn deploy(
image: &ImageState,
origin: &glib::KeyFile,
opts: Option<ostree::SysrootDeployTreeOpts<'_>>,
) -> Result<()> {
) -> Result<Deployment> {
let stateroot = Some(stateroot);
let opts = opts.unwrap_or_default();
// Copy to move into thread
let cancellable = gio::Cancellable::NONE;
let _new_deployment = sysroot.stage_tree_with_options(
stateroot,
image.ostree_commit.as_str(),
Some(origin),
merge_deployment,
&opts,
cancellable,
)?;
Ok(())
return sysroot
.stage_tree_with_options(
stateroot,
image.ostree_commit.as_str(),
Some(origin),
merge_deployment,
&opts,
cancellable,
)
.map_err(Into::into);
}

#[context("Generating origin")]
Expand All @@ -317,7 +318,7 @@ pub(crate) async fn stage(
) -> Result<()> {
let merge_deployment = sysroot.merge_deployment(Some(stateroot));
let origin = origin_from_imageref(spec.image)?;
crate::deploy::deploy(
let deployment = crate::deploy::deploy(
sysroot,
merge_deployment.as_ref(),
stateroot,
Expand All @@ -326,6 +327,11 @@ pub(crate) async fn stage(
opts,
)
.await?;

//TODO: does this need to be mutable?
let mut bound_image_manager = crate::boundimage::BoundImageManager::new(&deployment, sysroot)?;
bound_image_manager.run()?;

crate::deploy::cleanup(sysroot).await?;
println!("Queued for next boot: {:#}", spec.image);
if let Some(version) = image.version.as_deref() {
Expand Down
16 changes: 16 additions & 0 deletions lib/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1204,6 +1204,22 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
anyhow::Ok(())
})
.context("Writing aleph version")?;

// TODO: add code to run quadlet/systemd against the bootc-bound-image directory
// let bound = query_bound_state(&inst.deployment)?;
// bound.print();
// if !bound.is_empty() {
// println!();
// Task::new("Mounting deployment /var", "mount")
// .args(["--bind", ".", "/var"])
// .cwd(&inst.var)?
// .run()?;
// // podman needs this
// Task::new("Initializing /var/tmp", "systemd-tmpfiles")
// .args(["--create", "--boot", "--prefix=/var/tmp"])
// .verbose()
// .run()?;
// crate::deploy::fetch_bound_state(&bound).await?;
}

crate::bootloader::install_via_bootupd(&rootfs.device, &rootfs.rootfs, &state.config_opts)?;
Expand Down
1 change: 1 addition & 0 deletions lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#![allow(clippy::needless_borrows_for_generic_args)]

pub mod cli;
mod boundimage;
pub(crate) mod deploy;
pub(crate) mod generator;
pub(crate) mod journal;
Expand Down
9 changes: 6 additions & 3 deletions lib/src/task.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use std::{
ffi::OsStr,
io::{Seek, Write},
process::{Command, Stdio},
ffi::OsStr, io::{Seek, Write}, process::{Command, Stdio}
};

use anyhow::{Context, Result};
Expand Down Expand Up @@ -76,6 +74,11 @@ impl Task {
self
}

pub(crate) fn env(mut self, k: &str, v: &str) -> Self {
self.cmd.env(k, v);
self
}

pub(crate) fn args<S: AsRef<OsStr>>(mut self, args: impl IntoIterator<Item = S>) -> Self {
self.cmd.args(args);
self
Expand Down

0 comments on commit 29d0b99

Please sign in to comment.