Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 24 additions & 8 deletions crates/system-reinstall-bootc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,36 @@ fn run() -> Result<()> {
let has_clean = podman::bootc_has_clean(&opts.image)?;
spinner.finish_and_clear();

let ssh_key_file = tempfile::NamedTempFile::new()?;
let ssh_key_file_path = ssh_key_file
.path()
.to_str()
.ok_or_else(|| anyhow::anyhow!("unable to create authorized_key temp file"))?;
let mut _ssh_key_tempfile = None;
let mut ssh_key_file_path = None;

if podman::image_has_cloud_init(&opts.image)? {
Comment on lines 73 to +79
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The podman::image_has_cloud_init check involves running a container, which can take a few seconds. It should be performed while the spinner is active to provide better feedback to the user and avoid a perceived hang in the UI.

Suggested change
let has_clean = podman::bootc_has_clean(&opts.image)?;
spinner.finish_and_clear();
let ssh_key_file = tempfile::NamedTempFile::new()?;
let ssh_key_file_path = ssh_key_file
.path()
.to_str()
.ok_or_else(|| anyhow::anyhow!("unable to create authorized_key temp file"))?;
let mut _ssh_key_tempfile = None;
let mut ssh_key_file_path = None;
if podman::image_has_cloud_init(&opts.image)? {
let has_clean = podman::bootc_has_clean(&opts.image)?;
let has_cloud_init = podman::image_has_cloud_init(&opts.image)?;
spinner.finish_and_clear();
let mut _ssh_key_tempfile = None;
let mut ssh_key_file_path = None;
if has_cloud_init {

let host_root_keys = std::path::Path::new("/root/.ssh/authorized_keys");
if host_root_keys.exists() {
Comment on lines +80 to +81
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The automatic inheritance logic only checks for keys in /root/.ssh/authorized_keys. This is a departure from the existing interactive behavior in get_ssh_keys, which scans all users on the host system. If a user is running this tool via sudo but has their keys in their own home directory (e.g., /home/user/.ssh/authorized_keys), they will not be inherited automatically, potentially leading to a lockout if the image relies on these keys and cloud-init has no other datasource. Consider using the existing multi-user key detection logic or at least checking the current user's keys.

println!("Detected cloud-init and host keys. Inheriting keys automatically.");
ssh_key_file_path = Some(host_root_keys.to_string_lossy().into_owned());
} else {
println!("Detected cloud-init. Proceeding without host key inheritance.");
}
} else {
let file = tempfile::NamedTempFile::new()?;
let file_path = file
.path()
.to_str()
.ok_or_else(|| anyhow::anyhow!("unable to create authorized_key temp file"))?;

tracing::trace!("ssh_key_file_path: {}", file_path);

tracing::trace!("ssh_key_file_path: {}", ssh_key_file_path);
prompt::get_ssh_keys(file_path)?;

prompt::get_ssh_keys(ssh_key_file_path)?;
ssh_key_file_path = Some(file_path.to_string());
_ssh_key_tempfile = Some(file);
}

prompt::mount_warning()?;

let mut reinstall_podman_command =
podman::reinstall_command(&opts, ssh_key_file_path, has_clean)?;
podman::reinstall_command(&opts, ssh_key_file_path.as_deref(), has_clean)?;

println!();
println!("Going to run command:");
Expand Down
35 changes: 28 additions & 7 deletions crates/system-reinstall-bootc/src/podman.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{ReinstallOpts, prompt};
use crate::{prompt, ReinstallOpts};

use super::ROOT_KEY_MOUNT_POINT;
use anyhow::{Context, Result, ensure};
use anyhow::{ensure, Context, Result};
use bootc_utils::CommandRunExt;
use fn_error_context::context;
use std::process::Command;
Expand All @@ -24,10 +24,29 @@ pub(crate) fn bootc_has_clean(image: &str) -> Result<bool> {
Ok(stdout_str.contains("--cleanup"))
}

#[context("image_has_cloud_init")]
pub(crate) fn image_has_cloud_init(image: &str) -> Result<bool> {
let result = Command::new("podman")
.args([
"run",
"--rm",
"--entrypoint",
"sh",
image,
"-c",
"command -v cloud-init",
])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()?;

Ok(result.success())
}

#[context("reinstall_command")]
pub(crate) fn reinstall_command(
opts: &ReinstallOpts,
ssh_key_file: &str,
ssh_key_file: Option<&str>,
has_clean: bool,
) -> Result<Command> {
let mut podman_command_and_args = [
Expand Down Expand Up @@ -88,11 +107,13 @@ pub(crate) fn reinstall_command(
bootc_command_and_args.push("--cleanup".to_string());
}

podman_command_and_args.push("-v".to_string());
podman_command_and_args.push(format!("{ssh_key_file}:{ROOT_KEY_MOUNT_POINT}"));
if let Some(ssh_key_file) = ssh_key_file {
podman_command_and_args.push("-v".to_string());
podman_command_and_args.push(format!("{ssh_key_file}:{ROOT_KEY_MOUNT_POINT}"));

bootc_command_and_args.push("--root-ssh-authorized-keys".to_string());
bootc_command_and_args.push(ROOT_KEY_MOUNT_POINT.to_string());
bootc_command_and_args.push("--root-ssh-authorized-keys".to_string());
bootc_command_and_args.push(ROOT_KEY_MOUNT_POINT.to_string());
}

let all_args = [
podman_command_and_args,
Expand Down
Loading