From 239d0f8999b47e9e76589ee1fa2d9f3459c47335 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Mon, 28 Sep 2020 15:45:53 -0700 Subject: use separate binary for activation, more cleanup --- src/activate.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/activate.rs (limited to 'src/activate.rs') diff --git a/src/activate.rs b/src/activate.rs new file mode 100644 index 0000000..c446ee0 --- /dev/null +++ b/src/activate.rs @@ -0,0 +1,54 @@ +use clap::Clap; + +extern crate pretty_env_logger; +#[macro_use] +extern crate log; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +mod utils; + +/// Activation portion of the simple Rust Nix deploy tool +#[derive(Clap, Debug)] +#[clap(version = "1.0", author = "notgne2 ")] +struct Opts { + profile_path: String, + closure: String, + + /// Command for activating the given profile + #[clap(long)] + activate_cmd: Option, + + /// Command for bootstrapping + #[clap(long)] + bootstrap_cmd: Option, + + /// Auto rollback if failure + #[clap(long)] + auto_rollback: bool, +} + + +#[tokio::main] +async fn main() -> Result<(), Box> { + if std::env::var("DEPLOY_LOG").is_err() { + std::env::set_var("DEPLOY_LOG", "info"); + } + + pretty_env_logger::init_custom_env("DEPLOY_LOG"); + + let opts: Opts = Opts::parse(); + + utils::activate::activate( + opts.profile_path, + opts.closure, + opts.activate_cmd, + opts.bootstrap_cmd, + opts.auto_rollback, + ) + .await?; + + Ok(()) +} \ No newline at end of file -- cgit v1.2.3 From e3c55575ca6bfd0c9166c52b4aac76b3761bb313 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Tue, 29 Sep 2020 12:40:32 -0700 Subject: Move all activation logic to activate.rs (the unused warnings got annoying) --- src/activate.rs | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) (limited to 'src/activate.rs') diff --git a/src/activate.rs b/src/activate.rs index c446ee0..8e22aea 100644 --- a/src/activate.rs +++ b/src/activate.rs @@ -1,5 +1,10 @@ use clap::Clap; +use std::process::Stdio; +use tokio::process::Command; + +use std::path::Path; + extern crate pretty_env_logger; #[macro_use] extern crate log; @@ -30,6 +35,109 @@ struct Opts { auto_rollback: bool, } +pub async fn activate( + profile_path: String, + closure: String, + activate_cmd: Option, + bootstrap_cmd: Option, + auto_rollback: bool, +) -> Result<(), Box> { + info!("Activating profile"); + + Command::new("nix-env") + .arg("-p") + .arg(&profile_path) + .arg("--set") + .arg(&closure) + .stdout(Stdio::null()) + .spawn()? + .await?; + + if let (Some(bootstrap_cmd), false) = (bootstrap_cmd, !Path::new(&profile_path).exists()) { + let bootstrap_status = Command::new("bash") + .arg("-c") + .arg(&bootstrap_cmd) + .env("PROFILE", &profile_path) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .await; + + match bootstrap_status { + Ok(s) if s.success() => (), + _ => { + tokio::fs::remove_file(&profile_path).await?; + good_panic!("Failed to execute bootstrap command"); + } + } + } + + if let Some(activate_cmd) = activate_cmd { + let activate_status = Command::new("bash") + .arg("-c") + .arg(&activate_cmd) + .env("PROFILE", &profile_path) + .status() + .await; + + match activate_status { + Ok(s) if s.success() => (), + _ if auto_rollback => { + Command::new("nix-env") + .arg("-p") + .arg(&profile_path) + .arg("--rollback") + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn()? + .await?; + + let c = Command::new("nix-env") + .arg("-p") + .arg(&profile_path) + .arg("--list-generations") + .output() + .await?; + let generations_list = String::from_utf8(c.stdout)?; + + let last_generation_line = generations_list + .lines() + .last() + .expect("Expected to find a generation in list"); + + let last_generation_id = last_generation_line + .split_whitespace() + .next() + .expect("Expected to get ID from generation entry"); + + debug!("Removing generation entry {}", last_generation_line); + warn!("Removing generation by ID {}", last_generation_id); + + Command::new("nix-env") + .arg("-p") + .arg(&profile_path) + .arg("--delete-generations") + .arg(last_generation_id) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn()? + .await?; + + // TODO: Find some way to make sure this command never changes, otherwise this will not work + Command::new("bash") + .arg("-c") + .arg(&activate_cmd) + .spawn()? + .await?; + + good_panic!("Failed to execute activation command"); + } + _ => {} + } + } + + Ok(()) +} #[tokio::main] async fn main() -> Result<(), Box> { @@ -41,7 +149,7 @@ async fn main() -> Result<(), Box> { let opts: Opts = Opts::parse(); - utils::activate::activate( + activate( opts.profile_path, opts.closure, opts.activate_cmd, -- cgit v1.2.3 From 8d21dd335e5259dadf832a5d1a7c72b9dd1f4400 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Tue, 29 Sep 2020 15:10:06 -0700 Subject: Add license information, reformat Nix files, clean up --- src/activate.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/activate.rs') diff --git a/src/activate.rs b/src/activate.rs index 8e22aea..3c7c16d 100644 --- a/src/activate.rs +++ b/src/activate.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2020 Serokell +// +// SPDX-License-Identifier: MPL-2.0 + use clap::Clap; use std::process::Stdio; -- cgit v1.2.3 From 05803e0ebaf417d9ba40645b6548a48bf51f9213 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Thu, 1 Oct 2020 20:24:09 -0700 Subject: Handle more command exits correctly --- src/activate.rs | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'src/activate.rs') diff --git a/src/activate.rs b/src/activate.rs index 3c7c16d..f75303f 100644 --- a/src/activate.rs +++ b/src/activate.rs @@ -87,22 +87,33 @@ pub async fn activate( match activate_status { Ok(s) if s.success() => (), _ if auto_rollback => { - Command::new("nix-env") + error!("Failed to execute activation command"); + + let nix_env_rollback_exit_status = Command::new("nix-env") .arg("-p") .arg(&profile_path) .arg("--rollback") .stdout(Stdio::null()) .stderr(Stdio::null()) - .spawn()? + .status() .await?; - let c = Command::new("nix-env") + if !nix_env_rollback_exit_status.success() { + good_panic!("`nix-env --rollback` failed"); + } + + let nix_env_list_generations_out = Command::new("nix-env") .arg("-p") .arg(&profile_path) .arg("--list-generations") .output() .await?; - let generations_list = String::from_utf8(c.stdout)?; + + if !nix_env_list_generations_out.status.success() { + good_panic!("Listing `nix-env` generations failed"); + } + + let generations_list = String::from_utf8(nix_env_list_generations_out.stdout)?; let last_generation_line = generations_list .lines() @@ -117,24 +128,32 @@ pub async fn activate( debug!("Removing generation entry {}", last_generation_line); warn!("Removing generation by ID {}", last_generation_id); - Command::new("nix-env") + let nix_env_delete_generation_exit_status = Command::new("nix-env") .arg("-p") .arg(&profile_path) .arg("--delete-generations") .arg(last_generation_id) .stdout(Stdio::null()) .stderr(Stdio::null()) - .spawn()? + .status() .await?; + if !nix_env_delete_generation_exit_status.success() { + good_panic!("Failed to delete failed generation"); + } + // TODO: Find some way to make sure this command never changes, otherwise this will not work - Command::new("bash") + let re_activate_exit_status = Command::new("bash") .arg("-c") .arg(&activate_cmd) - .spawn()? + .status() .await?; - good_panic!("Failed to execute activation command"); + if !re_activate_exit_status.success() { + good_panic!("Failed to re-activate the last generation"); + } + + std::process::exit(1); } _ => {} } @@ -163,4 +182,4 @@ async fn main() -> Result<(), Box> { .await?; Ok(()) -} \ No newline at end of file +} -- cgit v1.2.3 From 5674670a59168fb05f26e5b4fb41dd2662810e94 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Fri, 2 Oct 2020 12:58:11 -0700 Subject: General improvements, deprecate `activate` profile option in favor of executing $PROFILE/activate (Wrap It Yourself) to ensure successful rollback activations --- src/activate.rs | 168 +++++++++++++++++++++++++++----------------------------- 1 file changed, 82 insertions(+), 86 deletions(-) (limited to 'src/activate.rs') diff --git a/src/activate.rs b/src/activate.rs index f75303f..64baa4f 100644 --- a/src/activate.rs +++ b/src/activate.rs @@ -26,10 +26,6 @@ struct Opts { profile_path: String, closure: String, - /// Command for activating the given profile - #[clap(long)] - activate_cmd: Option, - /// Command for bootstrapping #[clap(long)] bootstrap_cmd: Option, @@ -42,21 +38,24 @@ struct Opts { pub async fn activate( profile_path: String, closure: String, - activate_cmd: Option, bootstrap_cmd: Option, auto_rollback: bool, ) -> Result<(), Box> { info!("Activating profile"); - Command::new("nix-env") + let nix_env_set_exit_status = Command::new("nix-env") .arg("-p") .arg(&profile_path) .arg("--set") .arg(&closure) .stdout(Stdio::null()) - .spawn()? + .status() .await?; + if !nix_env_set_exit_status.success() { + good_panic!("Failed to update nix-env generation"); + } + if let (Some(bootstrap_cmd), false) = (bootstrap_cmd, !Path::new(&profile_path).exists()) { let bootstrap_status = Command::new("bash") .arg("-c") @@ -76,87 +75,85 @@ pub async fn activate( } } - if let Some(activate_cmd) = activate_cmd { - let activate_status = Command::new("bash") - .arg("-c") - .arg(&activate_cmd) - .env("PROFILE", &profile_path) - .status() - .await; + let activate_status = Command::new(format!("{}/activate", profile_path)) + .env("PROFILE", &profile_path) + .status() + .await; + + match activate_status { + Ok(s) if s.success() => (), + _ if auto_rollback => { + error!("Failed to execute activation command"); + + let nix_env_rollback_exit_status = Command::new("nix-env") + .arg("-p") + .arg(&profile_path) + .arg("--rollback") + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .await?; + + if !nix_env_rollback_exit_status.success() { + good_panic!("`nix-env --rollback` failed"); + } - match activate_status { - Ok(s) if s.success() => (), - _ if auto_rollback => { - error!("Failed to execute activation command"); - - let nix_env_rollback_exit_status = Command::new("nix-env") - .arg("-p") - .arg(&profile_path) - .arg("--rollback") - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status() - .await?; - - if !nix_env_rollback_exit_status.success() { - good_panic!("`nix-env --rollback` failed"); - } - - let nix_env_list_generations_out = Command::new("nix-env") - .arg("-p") - .arg(&profile_path) - .arg("--list-generations") - .output() - .await?; - - if !nix_env_list_generations_out.status.success() { - good_panic!("Listing `nix-env` generations failed"); - } - - let generations_list = String::from_utf8(nix_env_list_generations_out.stdout)?; - - let last_generation_line = generations_list - .lines() - .last() - .expect("Expected to find a generation in list"); - - let last_generation_id = last_generation_line - .split_whitespace() - .next() - .expect("Expected to get ID from generation entry"); - - debug!("Removing generation entry {}", last_generation_line); - warn!("Removing generation by ID {}", last_generation_id); - - let nix_env_delete_generation_exit_status = Command::new("nix-env") - .arg("-p") - .arg(&profile_path) - .arg("--delete-generations") - .arg(last_generation_id) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status() - .await?; - - if !nix_env_delete_generation_exit_status.success() { - good_panic!("Failed to delete failed generation"); - } - - // TODO: Find some way to make sure this command never changes, otherwise this will not work - let re_activate_exit_status = Command::new("bash") - .arg("-c") - .arg(&activate_cmd) - .status() - .await?; - - if !re_activate_exit_status.success() { - good_panic!("Failed to re-activate the last generation"); - } - - std::process::exit(1); + debug!("Listing generations"); + + let nix_env_list_generations_out = Command::new("nix-env") + .arg("-p") + .arg(&profile_path) + .arg("--list-generations") + .output() + .await?; + + if !nix_env_list_generations_out.status.success() { + good_panic!("Listing `nix-env` generations failed"); } - _ => {} + + let generations_list = String::from_utf8(nix_env_list_generations_out.stdout)?; + + let last_generation_line = generations_list + .lines() + .last() + .expect("Expected to find a generation in list"); + + let last_generation_id = last_generation_line + .split_whitespace() + .next() + .expect("Expected to get ID from generation entry"); + + debug!("Removing generation entry {}", last_generation_line); + warn!("Removing generation by ID {}", last_generation_id); + + let nix_env_delete_generation_exit_status = Command::new("nix-env") + .arg("-p") + .arg(&profile_path) + .arg("--delete-generations") + .arg(last_generation_id) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .await?; + + if !nix_env_delete_generation_exit_status.success() { + good_panic!("Failed to delete failed generation"); + } + + info!("Attempting re-activate last generation"); + + let re_activate_exit_status = Command::new(format!("{}/activate", profile_path)) + .env("PROFILE", &profile_path) + .status() + .await?; + + if !re_activate_exit_status.success() { + good_panic!("Failed to re-activate the last generation"); + } + + std::process::exit(1); } + _ => {} } Ok(()) @@ -175,7 +172,6 @@ async fn main() -> Result<(), Box> { activate( opts.profile_path, opts.closure, - opts.activate_cmd, opts.bootstrap_cmd, opts.auto_rollback, ) -- cgit v1.2.3 From e463c62922ad09f016e4f1dd1d6d0cabccb0ff79 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Sun, 11 Oct 2020 15:08:02 -0700 Subject: Move activate script location, use buildEnv for setActivate --- src/activate.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/activate.rs') diff --git a/src/activate.rs b/src/activate.rs index 64baa4f..38fc832 100644 --- a/src/activate.rs +++ b/src/activate.rs @@ -75,7 +75,7 @@ pub async fn activate( } } - let activate_status = Command::new(format!("{}/activate", profile_path)) + let activate_status = Command::new(format!("{}/deploy-rs-activate", profile_path)) .env("PROFILE", &profile_path) .status() .await; @@ -142,7 +142,7 @@ pub async fn activate( info!("Attempting re-activate last generation"); - let re_activate_exit_status = Command::new(format!("{}/activate", profile_path)) + let re_activate_exit_status = Command::new(format!("{}/deploy-rs-activate", profile_path)) .env("PROFILE", &profile_path) .status() .await?; -- cgit v1.2.3 From e5bd558c5b6505621d3b5a27e9b39bf54f6788a1 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Sun, 11 Oct 2020 15:19:09 -0700 Subject: Set working directory during activation to the profile path --- src/activate.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/activate.rs') diff --git a/src/activate.rs b/src/activate.rs index 38fc832..0b7d28d 100644 --- a/src/activate.rs +++ b/src/activate.rs @@ -77,6 +77,7 @@ pub async fn activate( let activate_status = Command::new(format!("{}/deploy-rs-activate", profile_path)) .env("PROFILE", &profile_path) + .current_dir(&profile_path) .status() .await; @@ -144,6 +145,7 @@ pub async fn activate( let re_activate_exit_status = Command::new(format!("{}/deploy-rs-activate", profile_path)) .env("PROFILE", &profile_path) + .current_dir(&profile_path) .status() .await?; -- cgit v1.2.3 From 3bd43f92e6c59f65b6120886c4ee75b6a9391522 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Tue, 13 Oct 2020 18:27:27 -0700 Subject: Auto rollback if deployment is not confirmed --- src/activate.rs | 245 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 173 insertions(+), 72 deletions(-) (limited to 'src/activate.rs') diff --git a/src/activate.rs b/src/activate.rs index 0b7d28d..ce6b286 100644 --- a/src/activate.rs +++ b/src/activate.rs @@ -4,11 +4,20 @@ use clap::Clap; +use futures_util::FutureExt; use std::process::Stdio; +use tokio::fs; use tokio::process::Command; +use tokio::time::timeout; + +use std::time::Duration; + +use futures_util::StreamExt; use std::path::Path; +use inotify::Inotify; + extern crate pretty_env_logger; #[macro_use] extern crate log; @@ -25,6 +34,8 @@ mod utils; struct Opts { profile_path: String, closure: String, + temp_path: String, + max_time: u16, /// Command for bootstrapping #[clap(long)] @@ -35,11 +46,162 @@ struct Opts { auto_rollback: bool, } +pub async fn deactivate(profile_path: &str) -> Result<(), Box> { + error!("De-activating due to error"); + + let nix_env_rollback_exit_status = Command::new("nix-env") + .arg("-p") + .arg(&profile_path) + .arg("--rollback") + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .await?; + + if !nix_env_rollback_exit_status.success() { + good_panic!("`nix-env --rollback` failed"); + } + + debug!("Listing generations"); + + let nix_env_list_generations_out = Command::new("nix-env") + .arg("-p") + .arg(&profile_path) + .arg("--list-generations") + .output() + .await?; + + if !nix_env_list_generations_out.status.success() { + good_panic!("Listing `nix-env` generations failed"); + } + + let generations_list = String::from_utf8(nix_env_list_generations_out.stdout)?; + + let last_generation_line = generations_list + .lines() + .last() + .expect("Expected to find a generation in list"); + + let last_generation_id = last_generation_line + .split_whitespace() + .next() + .expect("Expected to get ID from generation entry"); + + debug!("Removing generation entry {}", last_generation_line); + warn!("Removing generation by ID {}", last_generation_id); + + let nix_env_delete_generation_exit_status = Command::new("nix-env") + .arg("-p") + .arg(&profile_path) + .arg("--delete-generations") + .arg(last_generation_id) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .await?; + + if !nix_env_delete_generation_exit_status.success() { + good_panic!("Failed to delete failed generation"); + } + + info!("Attempting re-activate last generation"); + + let re_activate_exit_status = Command::new(format!("{}/deploy-rs-activate", profile_path)) + .env("PROFILE", &profile_path) + .current_dir(&profile_path) + .status() + .await?; + + if !re_activate_exit_status.success() { + good_panic!("Failed to re-activate the last generation"); + } + + Ok(()) +} + +async fn deactivate_on_err(profile_path: &str, r: Result) -> A { + match r { + Ok(x) => x, + Err(err) => { + error!("Deactivating due to error: {:?}", err); + match deactivate(profile_path).await { + Ok(_) => (), + Err(err) => { + error!("Error de-activating, uh-oh: {:?}", err); + } + }; + + std::process::exit(1); + } + } +} + +pub async fn activation_confirmation( + profile_path: String, + temp_path: String, + max_time: u16, + closure: String, +) -> Result<(), Box> { + let lock_hash = &closure[11 /* /nix/store/ */ ..]; + let lock_path = format!("{}/activating-{}", temp_path, lock_hash); + + if let Some(parent) = Path::new(&lock_path).parent() { + fs::create_dir_all(parent).await?; + } + + fs::File::create(&lock_path).await?; + + let mut inotify = Inotify::init()?; + inotify.add_watch(lock_path, inotify::WatchMask::DELETE)?; + + match fork::daemon(false, false).map_err(|x| x.to_string())? { + fork::Fork::Child => { + std::thread::spawn(move || { + let mut rt = tokio::runtime::Runtime::new().unwrap(); + + rt.block_on(async move { + info!("Waiting for confirmation event..."); + + let mut buffer = [0; 32]; + let mut stream = + deactivate_on_err(&profile_path, inotify.event_stream(&mut buffer)).await; + + deactivate_on_err( + &profile_path, + deactivate_on_err( + &profile_path, + deactivate_on_err( + &profile_path, + timeout(Duration::from_secs(max_time as u64), stream.next()).await, + ) + .await + .ok_or("Watcher ended prematurely"), + ) + .await, + ) + .await; + }); + }) + .join() + .unwrap(); + + info!("Confirmation successful!"); + + std::process::exit(0); + } + fork::Fork::Parent(_) => { + std::process::exit(0); + } + } +} + pub async fn activate( profile_path: String, closure: String, bootstrap_cmd: Option, auto_rollback: bool, + temp_path: String, + max_time: u16, ) -> Result<(), Box> { info!("Activating profile"); @@ -83,80 +245,17 @@ pub async fn activate( match activate_status { Ok(s) if s.success() => (), - _ if auto_rollback => { - error!("Failed to execute activation command"); - - let nix_env_rollback_exit_status = Command::new("nix-env") - .arg("-p") - .arg(&profile_path) - .arg("--rollback") - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status() - .await?; - - if !nix_env_rollback_exit_status.success() { - good_panic!("`nix-env --rollback` failed"); - } - - debug!("Listing generations"); - - let nix_env_list_generations_out = Command::new("nix-env") - .arg("-p") - .arg(&profile_path) - .arg("--list-generations") - .output() - .await?; - - if !nix_env_list_generations_out.status.success() { - good_panic!("Listing `nix-env` generations failed"); - } - - let generations_list = String::from_utf8(nix_env_list_generations_out.stdout)?; - - let last_generation_line = generations_list - .lines() - .last() - .expect("Expected to find a generation in list"); - - let last_generation_id = last_generation_line - .split_whitespace() - .next() - .expect("Expected to get ID from generation entry"); - - debug!("Removing generation entry {}", last_generation_line); - warn!("Removing generation by ID {}", last_generation_id); - - let nix_env_delete_generation_exit_status = Command::new("nix-env") - .arg("-p") - .arg(&profile_path) - .arg("--delete-generations") - .arg(last_generation_id) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status() - .await?; - - if !nix_env_delete_generation_exit_status.success() { - good_panic!("Failed to delete failed generation"); - } - - info!("Attempting re-activate last generation"); - - let re_activate_exit_status = Command::new(format!("{}/deploy-rs-activate", profile_path)) - .env("PROFILE", &profile_path) - .current_dir(&profile_path) - .status() - .await?; + _ if auto_rollback => return Ok(deactivate(&profile_path).await?), + _ => (), + } - if !re_activate_exit_status.success() { - good_panic!("Failed to re-activate the last generation"); - } + info!("Activation succeeded, now performing post-activation checks"); - std::process::exit(1); - } - _ => {} - } + deactivate_on_err( + &profile_path, + activation_confirmation(profile_path.clone(), temp_path, max_time, closure).await, + ) + .await; Ok(()) } @@ -176,6 +275,8 @@ async fn main() -> Result<(), Box> { opts.closure, opts.bootstrap_cmd, opts.auto_rollback, + opts.temp_path, + opts.max_time, ) .await?; -- cgit v1.2.3 From ea717911bac5ff29d730d80d4b774fe17ed1e851 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Tue, 13 Oct 2020 19:06:40 -0700 Subject: Clean up some CLI arguments, make magic rollback optional --- src/activate.rs | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) (limited to 'src/activate.rs') diff --git a/src/activate.rs b/src/activate.rs index ce6b286..55ceb27 100644 --- a/src/activate.rs +++ b/src/activate.rs @@ -34,8 +34,18 @@ mod utils; struct Opts { profile_path: String, closure: String, + + /// Temp path for any temporary files that may be needed during activation + #[clap(long)] temp_path: String, - max_time: u16, + + /// Maximum time to wait for confirmation after activation + #[clap(long)] + confirm_timeout: u16, + + /// Wait for confirmation after deployment and rollback if not confirmed + #[clap(long)] + magic_rollback: bool, /// Command for bootstrapping #[clap(long)] @@ -139,7 +149,7 @@ async fn deactivate_on_err(profile_path: &str, r: Result pub async fn activation_confirmation( profile_path: String, temp_path: String, - max_time: u16, + confirm_timeout: u16, closure: String, ) -> Result<(), Box> { let lock_hash = &closure[11 /* /nix/store/ */ ..]; @@ -172,7 +182,8 @@ pub async fn activation_confirmation( &profile_path, deactivate_on_err( &profile_path, - timeout(Duration::from_secs(max_time as u64), stream.next()).await, + timeout(Duration::from_secs(confirm_timeout as u64), stream.next()) + .await, ) .await .ok_or("Watcher ended prematurely"), @@ -201,7 +212,8 @@ pub async fn activate( bootstrap_cmd: Option, auto_rollback: bool, temp_path: String, - max_time: u16, + confirm_timeout: u16, + magic_rollback: bool, ) -> Result<(), Box> { info!("Activating profile"); @@ -249,13 +261,17 @@ pub async fn activate( _ => (), } - info!("Activation succeeded, now performing post-activation checks"); + info!("Activation succeeded!"); - deactivate_on_err( - &profile_path, - activation_confirmation(profile_path.clone(), temp_path, max_time, closure).await, - ) - .await; + if magic_rollback { + info!("Performing activation confirmation steps"); + deactivate_on_err( + &profile_path, + activation_confirmation(profile_path.clone(), temp_path, confirm_timeout, closure) + .await, + ) + .await; + } Ok(()) } @@ -276,7 +292,8 @@ async fn main() -> Result<(), Box> { opts.bootstrap_cmd, opts.auto_rollback, opts.temp_path, - opts.max_time, + opts.confirm_timeout, + opts.magic_rollback, ) .await?; -- cgit v1.2.3 From 155f4bf45204b3090cc07271d2648ac7c024bbd1 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Sun, 25 Oct 2020 13:15:35 -0700 Subject: Fail correctly if initial activation fails --- src/activate.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src/activate.rs') diff --git a/src/activate.rs b/src/activate.rs index 55ceb27..4fdb59c 100644 --- a/src/activate.rs +++ b/src/activate.rs @@ -114,7 +114,7 @@ pub async fn deactivate(profile_path: &str) -> Result<(), Box (), - _ if auto_rollback => return Ok(deactivate(&profile_path).await?), - _ => (), - } + let activate_status_all = match activate_status { + Ok(s) if s.success() => Ok(()), + Ok(_) => Err(std::io::Error::new(std::io::ErrorKind::Other, "Activation did not succeed")), + Err(x) => Err(x), + }; + + deactivate_on_err(&profile_path, activate_status_all).await; info!("Activation succeeded!"); -- cgit v1.2.3