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 2f5feaf
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 14 deletions.
129 changes: 129 additions & 0 deletions lib/src/boundimage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
use anyhow::Result;

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

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

use crate::task::Task;


const BOOTC_SYSTEMD_DIR: &'static str = "/etc/systemd/system/bootc";
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>,
}

impl BoundImageManager {
pub(crate) fn new(deployment: Deployment, sysroot: &SysrootLock) -> BoundImageManager {
let deployment_dir = sysroot.deployment_dirpath(&deployment);
let quadlet_unit_dir = "/".to_string() + deployment_dir.as_str() + BOOTC_QUADLET_DIR.to_string().as_str();

BoundImageManager {
quadlet_unit_dir,
units: Vec::new(),
}
}

pub(crate) fn run(&mut self) -> Result<()> {
match self.sync_images() {
Ok(_) => println!("Successfully synced images"),
Err(e) => {
self.clean_up()?;
drop(e);
}
}

Ok(())
}

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

Ok(())
}

// Run podman-system-generator to generate the systemd units
// the output is written to /etc/systemd/system/bootc
// 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<()> {
fs::create_dir_all(BOOTC_SYSTEMD_DIR)?;

Task::new(
format!("Running quadlet on {:#}", self.quadlet_unit_dir),
QUADLET_BINARY,
)
.arg(BOOTC_SYSTEMD_DIR)
.env(&"QUADLET_UNIT_DIRS".to_string(), &self.quadlet_unit_dir)
.run()?;

Ok(())
}

fn move_units(&mut self) -> Result<()> {
let entries = fs::read_dir(BOOTC_SYSTEMD_DIR)?;
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::rename(bound_image_path.clone(), systemd_dst.clone())?;
}

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(())
}

fn clean_up(&self) -> Result<()> {
//remove the temp directory used for the generated units
if Path::new(BOOTC_SYSTEMD_DIR).exists() {
fs::remove_dir_all(BOOTC_SYSTEMD_DIR)?
}

//remove the generated units from the root systemd directory
for unit in &self.units {
fs::remove_file(format!("{}/{}", SYSTEMD_DIR, unit))?;
}

Ok(())
}
}
26 changes: 15 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,9 @@ pub(crate) async fn stage(
opts,
)
.await?;

crate::boundimage::BoundImageManager::new(deployment, sysroot).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: &String, v: &String) -> 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 2f5feaf

Please sign in to comment.