From 44c4ecf5690f9b38f276b6a3972aacedc5da4e0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20Sch=C3=A4fer?= Date: Sat, 24 Jan 2026 18:41:13 +0100 Subject: [PATCH 1/2] Add --force option for register command Allow to force writing the registration even if a registration of the same name already exists. Also update the man pages. --- doc/flake-ctl-firecracker-register.rst | 10 ++++ doc/flake-ctl-list.rst | 11 +++- doc/flake-ctl-podman-register.rst | 15 +++++- flake-ctl/src/app.rs | 8 ++- flake-ctl/src/cli.rs | 10 ++++ flake-ctl/src/main.rs | 72 ++++++++++++++++---------- 6 files changed, 94 insertions(+), 32 deletions(-) diff --git a/doc/flake-ctl-firecracker-register.rst b/doc/flake-ctl-firecracker-register.rst index 042886c..cc360df 100644 --- a/doc/flake-ctl-firecracker-register.rst +++ b/doc/flake-ctl-firecracker-register.rst @@ -17,6 +17,7 @@ SYNOPSIS OPTIONS: --app + --force --include-tar ... --include-path ... --no-net @@ -52,6 +53,15 @@ OPTIONS the target option, the application will be called with that path inside of the VM +--force + + Force writing the registration even if a registration + of the same name already exists. This is done by deleting + an eventual existing registration prio creating the new + registration. Please have in mind that a failed registration + still causes an eventual existing former registration to be + deleted in this case ! + --include-tar ... Name of a tar file to be included on top of the VM instance. diff --git a/doc/flake-ctl-list.rst b/doc/flake-ctl-list.rst index e5ad690..6b19ebc 100644 --- a/doc/flake-ctl-list.rst +++ b/doc/flake-ctl-list.rst @@ -15,8 +15,8 @@ SYNOPSIS flake-ctl list OPTIONS: - -h, --help Print help information - -V, --version Print version information + --user + --help DESCRIPTION @@ -24,6 +24,13 @@ DESCRIPTION List registered flake applications. +OPTIONS +------- + +--user + + List registered flake applications for the calling user + FILES ----- diff --git a/doc/flake-ctl-podman-register.rst b/doc/flake-ctl-podman-register.rst index 76c8ab3..78a3279 100644 --- a/doc/flake-ctl-podman-register.rst +++ b/doc/flake-ctl-podman-register.rst @@ -12,7 +12,7 @@ SYNOPSIS .. code:: bash USAGE: - flake-ctl podman register [OPTIONS] --container --app + flake-ctl podman [--user] register [OPTIONS] --container --app OPTIONS: --app @@ -20,6 +20,7 @@ SYNOPSIS --base --check_host_dependencies --container + --force --include-tar ... --include-path ... --info @@ -44,6 +45,9 @@ like a normal application on this host. For further details about the flake configuration please refer to the **podman-pilot** manual page. +For further details about the flake configuration when `--user` is +used please refer to the **flake-pilot** manual page. + NOTE ---- @@ -81,6 +85,15 @@ OPTIONS Check if the container has dependencies to the host When using a base container this check is enabled by default. +--force + + Force writing the registration even if a registration + of the same name already exists. This is done by deleting + an eventual existing registration prio creating the new + registration. Please have in mind that a failed registration + still causes an eventual existing former registration to be + deleted in this case ! + --include-tar ... Name of a tar file to be included on top of the container instance. diff --git a/flake-ctl/src/app.rs b/flake-ctl/src/app.rs index aa36f13..3619132 100644 --- a/flake-ctl/src/app.rs +++ b/flake-ctl/src/app.rs @@ -242,11 +242,15 @@ pub fn remove( "{}/{}.d", get_flakes_dir(usermode), &app_basename ); if ! Path::new(&config_file).exists() { - error!("No app config file found: {config_file}"); + if !silent { + error!("No app config file found: {config_file}"); + } return false } if ! Path::new(&app_config_dir).exists() { - error!("No app directory found: {app_config_dir}"); + if !silent { + error!("No app directory found: {app_config_dir}"); + } return false } diff --git a/flake-ctl/src/cli.rs b/flake-ctl/src/cli.rs index 766b7f6..746f13e 100644 --- a/flake-ctl/src/cli.rs +++ b/flake-ctl/src/cli.rs @@ -176,6 +176,11 @@ pub enum Firecracker { /// specified multiple times. #[clap(long, multiple = true, requires = "overlay-size")] include_path: Option>, + + /// Force writing the registration even if a registration + /// of the same name already exists + #[clap(long)] + force: bool, }, /// Remove application registration or entire VM #[clap(group( @@ -311,6 +316,11 @@ pub enum Podman { /// Print registration information from container if provided #[clap(long)] info: bool, + + /// Force writing the registration even if a registration + /// of the same name already exists + #[clap(long)] + force: bool, }, } diff --git a/flake-ctl/src/main.rs b/flake-ctl/src/main.rs index c2a342e..038025f 100644 --- a/flake-ctl/src/main.rs +++ b/flake-ctl/src/main.rs @@ -91,8 +91,16 @@ async fn main() -> Result> { // register cli::Firecracker::Register { vm, app, target, run_as, overlay_size, no_net, resume, - force_vsock, include_tar, include_path + force_vsock, include_tar, include_path, force } => { + if *force { + app::remove( + app, + defaults::FIRECRACKER_PILOT, + false, + true + ); + } if app::init(Some(app), false) { let mut ok = app::register( Some(app), target.as_ref(), @@ -165,43 +173,53 @@ async fn main() -> Result> { cli::Podman::Register { container, app, target, base, check_host_dependencies, layer, include_tar, include_path, resume, attach, - opt, info + opt, info, force } => { if *info { podman::print_container_info(container); - } else if app::init(app.as_ref(), user) { - let mut ok = app::register( - app.as_ref(), target.as_ref(), - defaults::PODMAN_PILOT, - user - ); - if ok { - ok = app::create_container_config( - container, - app.as_ref(), - target.as_ref(), - base.as_ref(), - *check_host_dependencies, - layer.as_ref().cloned(), - include_tar.as_ref().cloned(), - include_path.as_ref().cloned(), - *resume, - *attach, - user, - opt.as_ref().cloned() - ); - } - if ! ok { + } else { + if *force { app::remove( app.as_ref().map(String::as_str).unwrap(), defaults::PODMAN_PILOT, user, true ); + } + if app::init(app.as_ref(), user) { + let mut ok = app::register( + app.as_ref(), target.as_ref(), + defaults::PODMAN_PILOT, + user + ); + if ok { + ok = app::create_container_config( + container, + app.as_ref(), + target.as_ref(), + base.as_ref(), + *check_host_dependencies, + layer.as_ref().cloned(), + include_tar.as_ref().cloned(), + include_path.as_ref().cloned(), + *resume, + *attach, + user, + opt.as_ref().cloned(), + ); + } + if ! ok { + app::remove( + app.as_ref().map(String::as_str).unwrap(), + defaults::PODMAN_PILOT, + user, + true + ); + return Ok(ExitCode::FAILURE) + } + } else { return Ok(ExitCode::FAILURE) } - } else { - return Ok(ExitCode::FAILURE) } }, // remove From 776cf5fef62defe05bea42d868cddab36123427b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20Sch=C3=A4fer?= Date: Mon, 26 Jan 2026 12:38:12 +0100 Subject: [PATCH 2/2] Allow force registration with arbitrary data When using --force also register even if the eventually conflicting file does not belong to a flake registration --- flake-ctl/src/app.rs | 54 +++++++++++++++++++++++------------- flake-ctl/src/firecracker.rs | 2 +- flake-ctl/src/main.rs | 14 +++++++--- flake-ctl/src/podman.rs | 1 + 4 files changed, 46 insertions(+), 25 deletions(-) diff --git a/flake-ctl/src/app.rs b/flake-ctl/src/app.rs index 3619132..db00e35 100644 --- a/flake-ctl/src/app.rs +++ b/flake-ctl/src/app.rs @@ -216,7 +216,7 @@ pub fn create_vm_config( } pub fn remove( - app: &str, engine: &str, usermode: bool, silent: bool + app: &str, engine: &str, usermode: bool, silent: bool, force: bool ) -> bool { /*! Delete application link and config files @@ -254,32 +254,46 @@ pub fn remove( return false } - // remove pilot link if valid - match fs::read_link(app) { - Ok(link_name) => { - if link_name.into_os_string() == engine { - match fs::remove_file(app) { - Ok(_) => {} - Err(error) => { - if !silent { - error!("Error removing pilot link: {app}: {error:?}"); - }; - return false + if force { + match fs::remove_file(app) { + Ok(_) => {} + Err(error) => { + if !silent { + error!("Error removing: {app}: {error:?}"); + }; + return false + } + } + } else { + // remove pilot link if valid + match fs::read_link(app) { + Ok(link_name) => { + if link_name.into_os_string() == engine { + match fs::remove_file(app) { + Ok(_) => {} + Err(error) => { + if !silent { + error!( + "Error removing pilot link: {app}: {error:?}" + ); + }; + return false + } } + } else { + if !silent { + error!("Symlink not pointing to {engine}: {app}"); + }; + return false } - } else { + } + Err(error) => { if !silent { - error!("Symlink not pointing to {engine}: {app}"); + error!("Failed to read as symlink: {app}: {error:?}"); }; return false } } - Err(error) => { - if !silent { - error!("Failed to read as symlink: {app}: {error:?}"); - }; - return false - } } // remove config file and config directory match fs::remove_file(&config_file) { diff --git a/flake-ctl/src/firecracker.rs b/flake-ctl/src/firecracker.rs index 3bc5151..46d23bc 100644 --- a/flake-ctl/src/firecracker.rs +++ b/flake-ctl/src/firecracker.rs @@ -495,7 +495,7 @@ pub fn purge_vm(vm: &str) { { app::remove( &app_conf.vm.as_mut().unwrap().host_app_path, - defaults::FIRECRACKER_PILOT, false, false + defaults::FIRECRACKER_PILOT, false, false, false ); } }, diff --git a/flake-ctl/src/main.rs b/flake-ctl/src/main.rs index 038025f..b1e9afd 100644 --- a/flake-ctl/src/main.rs +++ b/flake-ctl/src/main.rs @@ -98,7 +98,8 @@ async fn main() -> Result> { app, defaults::FIRECRACKER_PILOT, false, - true + true, + *force ); } if app::init(Some(app), false) { @@ -125,7 +126,8 @@ async fn main() -> Result> { app::remove( app, defaults::FIRECRACKER_PILOT, false, - true + true, + *force ); return Ok(ExitCode::FAILURE) } @@ -139,6 +141,7 @@ async fn main() -> Result> { app.as_ref().map(String::as_str).unwrap(), defaults::FIRECRACKER_PILOT, false, + false, false ) { return Ok(ExitCode::FAILURE) @@ -183,7 +186,8 @@ async fn main() -> Result> { app.as_ref().map(String::as_str).unwrap(), defaults::PODMAN_PILOT, user, - true + true, + *force ); } if app::init(app.as_ref(), user) { @@ -213,7 +217,8 @@ async fn main() -> Result> { app.as_ref().map(String::as_str).unwrap(), defaults::PODMAN_PILOT, user, - true + true, + *force ); return Ok(ExitCode::FAILURE) } @@ -228,6 +233,7 @@ async fn main() -> Result> { app.as_ref().map(String::as_str).unwrap(), defaults::PODMAN_PILOT, user, + false, false ) { return Ok(ExitCode::FAILURE) diff --git a/flake-ctl/src/podman.rs b/flake-ctl/src/podman.rs index 9b32faa..aec1d51 100644 --- a/flake-ctl/src/podman.rs +++ b/flake-ctl/src/podman.rs @@ -213,6 +213,7 @@ pub fn purge_container(container: &str, usermode: bool) { &app_conf.container.as_mut().unwrap().host_app_path, defaults::PODMAN_PILOT, usermode, + false, false ); }