From 815814529eec6f739eb1618fdf356e526b3879e1 Mon Sep 17 00:00:00 2001 From: Bernardo Meurer Date: Sun, 24 Jan 2021 23:38:44 -0800 Subject: changed: remove 2015-style extern crate --- Cargo.lock | 4 +++- Cargo.toml | 5 ++--- src/bin/activate.rs | 5 +---- src/bin/deploy.rs | 11 +++-------- src/data.rs | 2 +- src/deploy.rs | 4 ++-- src/lib.rs | 6 ------ src/push.rs | 4 ++-- 8 files changed, 14 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a96a33..ddd4787 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -144,7 +144,6 @@ dependencies = [ "notify", "rnix", "serde", - "serde_derive", "serde_json", "signal-hook", "smol_str", @@ -770,6 +769,9 @@ name = "serde" version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +dependencies = [ + "serde_derive", +] [[package]] name = "serde_derive" diff --git a/Cargo.toml b/Cargo.toml index dc239e5..2b0e61b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,8 +14,7 @@ edition = "2018" clap = "3.0.0-beta.2" tokio = { version = "0.3.5", features = [ "full" ] } serde_json = "1.0.48" -serde_derive = "1.0.104" -serde = "1.0.104" +serde = { version = "1.0.104", features = [ "derive" ] } merge = "0.1.0" whoami = "0.9.0" log = "0.4" @@ -37,4 +36,4 @@ smol_str = "=0.1.16" [lib] name = "deploy" -path = "src/lib.rs" \ No newline at end of file +path = "src/lib.rs" diff --git a/src/bin/activate.rs b/src/bin/activate.rs index 2f13b44..947e883 100644 --- a/src/bin/activate.rs +++ b/src/bin/activate.rs @@ -20,10 +20,7 @@ use notify::{RecommendedWatcher, RecursiveMode, Watcher}; use thiserror::Error; -#[macro_use] -extern crate log; - -extern crate serde_derive; +use log::{debug, error, info, warn}; /// Remote activation utility for deploy-rs #[derive(Clap, Debug)] diff --git a/src/bin/deploy.rs b/src/bin/deploy.rs index caf3d4e..3ee2ec2 100644 --- a/src/bin/deploy.rs +++ b/src/bin/deploy.rs @@ -7,16 +7,11 @@ use std::io::{stdin, stdout, Write}; use clap::Clap; +use log::{debug, error, info, warn}; +use serde::Serialize; use std::process::Stdio; -use tokio::process::Command; - use thiserror::Error; - -#[macro_use] -extern crate log; - -#[macro_use] -extern crate serde_derive; +use tokio::process::Command; /// Simple Rust rewrite of a simple Nix Flake deployment tool #[derive(Clap, Debug)] diff --git a/src/data.rs b/src/data.rs index f557e41..6fe7f75 100644 --- a/src/data.rs +++ b/src/data.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MPL-2.0 use merge::Merge; - +use serde::Deserialize; use std::collections::HashMap; #[derive(Deserialize, Debug, Clone, Merge)] diff --git a/src/deploy.rs b/src/deploy.rs index a33721c..686c7b7 100644 --- a/src/deploy.rs +++ b/src/deploy.rs @@ -3,10 +3,10 @@ // // SPDX-License-Identifier: MPL-2.0 +use log::{debug, info}; use std::borrow::Cow; -use tokio::process::Command; - use thiserror::Error; +use tokio::process::Command; struct ActivateCommandData<'a> { sudo: &'a Option, diff --git a/src/lib.rs b/src/lib.rs index edc0507..b93b9ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,12 +11,6 @@ use thiserror::Error; use flexi_logger::*; -#[macro_use] -extern crate log; - -#[macro_use] -extern crate serde_derive; - pub fn make_lock_path(temp_path: &str, closure: &str) -> String { let lock_hash = &closure["/nix/store/".len()..closure.find('-').unwrap_or_else(|| closure.len())]; diff --git a/src/push.rs b/src/push.rs index 2f83019..0963a9a 100644 --- a/src/push.rs +++ b/src/push.rs @@ -2,11 +2,11 @@ // // SPDX-License-Identifier: MPL-2.0 +use log::{debug, info}; use std::path::Path; use std::process::Stdio; -use tokio::process::Command; - use thiserror::Error; +use tokio::process::Command; #[derive(Error, Debug)] pub enum PushProfileError { -- cgit v1.2.3 From 9c32ddeb05421a6795e9509a17d1c5f565ea0d0e Mon Sep 17 00:00:00 2001 From: Bernardo Meurer Date: Sun, 24 Jan 2021 23:39:08 -0800 Subject: changed: sort Cargo.toml --- Cargo.toml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2b0e61b..fce88bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,21 +12,21 @@ edition = "2018" [dependencies] clap = "3.0.0-beta.2" -tokio = { version = "0.3.5", features = [ "full" ] } -serde_json = "1.0.48" -serde = { version = "1.0.104", features = [ "derive" ] } -merge = "0.1.0" -whoami = "0.9.0" -log = "0.4" flexi_logger = "0.16" -notify = "5.0.0-pre.3" -futures-util = "0.3.6" fork = "0.1" +futures-util = "0.3.6" +log = "0.4" +merge = "0.1.0" +notify = "5.0.0-pre.3" +rnix = "0.8" +serde = { version = "1.0.104", features = [ "derive" ] } +serde_json = "1.0.48" +signal-hook = "0.3" thiserror = "1.0" +tokio = { version = "0.3.5", features = [ "full" ] } toml = "0.5" +whoami = "0.9.0" yn = "0.1" -rnix = "0.8" -signal-hook = "0.3" # smol_str is required by rnix, but 0.1.17 doesn't build on rustc # 1.45.2 (shipped in nixos-20.09); it requires rustc 1.46.0. See -- cgit v1.2.3 From 4ff0e5f90bb297ed73686bc13d4cfe93a5d2e7e8 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Thu, 28 Jan 2021 19:49:14 -0700 Subject: Wait for `ssh_activate` to complete and check for errors in magic_rollback activation (fixes #58 and #49) --- src/deploy.rs | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/deploy.rs b/src/deploy.rs index 686c7b7..88becc0 100644 --- a/src/deploy.rs +++ b/src/deploy.rs @@ -246,16 +246,25 @@ pub async fn deploy_profile( ssh_wait_command.arg(ssh_opt); } - let ssh_wait_exit_status = ssh_wait_command - .arg(self_wait_command) - .status() - .await - .map_err(DeployProfileError::SSHWaitError)?; + tokio::pin! { + let ssh_wait_future = ssh_wait_command.arg(self_wait_command).status(); + let ssh_activate_future = ssh_activate.wait_with_output(); + } - match ssh_wait_exit_status.code() { - Some(0) => (), - a => return Err(DeployProfileError::SSHWaitExitError(a)), - }; + tokio::select! { + x = ssh_wait_future => { + match x.map_err(DeployProfileError::SSHWaitError)?.code() { + Some(0) => (), + a => return Err(DeployProfileError::SSHWaitExitError(a)), + }; + }, + x = ssh_activate_future => { + match x.map_err(DeployProfileError::SSHActivateError)?.status.code() { + Some(0) => (), + a => return Err(DeployProfileError::SSHActivateExitError(a)), + }; + }, + } info!("Success activating, attempting to confirm activation"); @@ -279,13 +288,13 @@ pub async fn deploy_profile( confirm_command ); - let ssh_exit_status = ssh_confirm_command + let ssh_confirm_exit_status = ssh_confirm_command .arg(confirm_command) .status() .await .map_err(DeployProfileError::SSHConfirmError)?; - match ssh_exit_status.code() { + match ssh_confirm_exit_status.code() { Some(0) => (), a => return Err(DeployProfileError::SSHConfirmExitError(a)), }; -- cgit v1.2.3 From c32d25ec28adafec90c43eb19dc0ecd635f4b746 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Fri, 29 Jan 2021 04:13:00 -0700 Subject: Use oneshot signals to ensure SSH activate command has finished before deployment ends --- src/deploy.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/deploy.rs b/src/deploy.rs index 88becc0..00c97f4 100644 --- a/src/deploy.rs +++ b/src/deploy.rs @@ -246,20 +246,25 @@ pub async fn deploy_profile( ssh_wait_command.arg(ssh_opt); } - tokio::pin! { - let ssh_wait_future = ssh_wait_command.arg(self_wait_command).status(); - let ssh_activate_future = ssh_activate.wait_with_output(); - } + let (send_activate, recv_activate) = tokio::sync::oneshot::channel(); + let (send_activated, recv_activated) = tokio::sync::oneshot::channel(); + + tokio::spawn(async move { + send_activate + .send(ssh_activate.wait_with_output().await) + .unwrap(); + send_activated.send(()).unwrap(); + }); tokio::select! { - x = ssh_wait_future => { + x = ssh_wait_command.arg(self_wait_command).status() => { match x.map_err(DeployProfileError::SSHWaitError)?.code() { Some(0) => (), a => return Err(DeployProfileError::SSHWaitExitError(a)), }; }, - x = ssh_activate_future => { - match x.map_err(DeployProfileError::SSHActivateError)?.status.code() { + x = recv_activate => { + match x.unwrap().map_err(DeployProfileError::SSHActivateError)?.status.code() { Some(0) => (), a => return Err(DeployProfileError::SSHActivateExitError(a)), }; @@ -300,6 +305,8 @@ pub async fn deploy_profile( }; info!("Deployment confirmed."); + + recv_activated.await.unwrap(); } Ok(()) -- cgit v1.2.3 From e798bb7d834cd786a49041a61c1a222ecdc96483 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Fri, 29 Jan 2021 05:22:07 -0700 Subject: Still wait for activation command to end even in cases of errors --- src/deploy.rs | 113 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 43 deletions(-) diff --git a/src/deploy.rs b/src/deploy.rs index 00c97f4..aba41f2 100644 --- a/src/deploy.rs +++ b/src/deploy.rs @@ -137,6 +137,57 @@ fn test_wait_command_builder() { ); } +#[derive(Error, Debug)] +pub enum ConfirmProfileError { + #[error("Failed to run confirmation command over SSH (the server should roll back): {0}")] + SSHConfirmError(std::io::Error), + #[error( + "Confirming activation over SSH resulted in a bad exit code (the server should roll back): {0:?}" + )] + SSHConfirmExitError(Option), +} + +pub async fn confirm_profile( + deploy_data: &super::DeployData<'_>, + deploy_defs: &super::DeployDefs, + hostname: &str, + temp_path: Cow<'_, str>, +) -> Result<(), ConfirmProfileError> { + let mut c = Command::new("ssh"); + let mut ssh_confirm_command = c.arg(format!("ssh://{}@{}", deploy_defs.ssh_user, hostname)); + + for ssh_opt in &deploy_data.merged_settings.ssh_opts { + ssh_confirm_command = ssh_confirm_command.arg(ssh_opt); + } + + let lock_path = super::make_lock_path(&temp_path, &deploy_data.profile.profile_settings.path); + + let mut confirm_command = format!("rm {}", lock_path); + if let Some(sudo_cmd) = &deploy_defs.sudo { + confirm_command = format!("{} {}", sudo_cmd, confirm_command); + } + + debug!( + "Attempting to run command to confirm deployment: {}", + confirm_command + ); + + let ssh_confirm_exit_status = ssh_confirm_command + .arg(confirm_command) + .status() + .await + .map_err(ConfirmProfileError::SSHConfirmError)?; + + match ssh_confirm_exit_status.code() { + Some(0) => (), + a => return Err(ConfirmProfileError::SSHConfirmExitError(a)), + }; + + info!("Deployment confirmed."); + + Ok(()) +} + #[derive(Error, Debug)] pub enum DeployProfileError { #[error("Failed to spawn activation command over SSH: {0}")] @@ -152,12 +203,8 @@ pub enum DeployProfileError { #[error("Waiting over SSH resulted in a bad exit code: {0:?}")] SSHWaitExitError(Option), - #[error("Failed to run confirmation command over SSH (the server should roll back): {0}")] - SSHConfirmError(std::io::Error), - #[error( - "Confirming activation over SSH resulted in a bad exit code (the server should roll back): {0:?}" - )] - SSHConfirmExitError(Option), + #[error("Error confirming deployment: {0}")] + ConfirmError(#[from] ConfirmProfileError), } pub async fn deploy_profile( @@ -250,22 +297,33 @@ pub async fn deploy_profile( let (send_activated, recv_activated) = tokio::sync::oneshot::channel(); tokio::spawn(async move { - send_activate - .send(ssh_activate.wait_with_output().await) - .unwrap(); + let o = ssh_activate.wait_with_output().await; + + // Don't event unless somethis is bad + // TODO: maybe replace the structure with our own + match o { + Ok(ref x) => match x.status.code() { + Some(0) => (), + _ => send_activate.send(o).unwrap(), + }, + _ => send_activate.send(o).unwrap(), + }; + send_activated.send(()).unwrap(); }); tokio::select! { x = ssh_wait_command.arg(self_wait_command).status() => { + debug!("Wait command ended"); match x.map_err(DeployProfileError::SSHWaitError)?.code() { Some(0) => (), a => return Err(DeployProfileError::SSHWaitExitError(a)), }; }, x = recv_activate => { + debug!("Activate command exited with an error"); match x.unwrap().map_err(DeployProfileError::SSHActivateError)?.status.code() { - Some(0) => (), + Some(0) => unreachable!(), // We know it is an error, see a comment above a => return Err(DeployProfileError::SSHActivateExitError(a)), }; }, @@ -273,40 +331,9 @@ pub async fn deploy_profile( info!("Success activating, attempting to confirm activation"); - let mut c = Command::new("ssh"); - let mut ssh_confirm_command = c.arg(format!("ssh://{}@{}", deploy_defs.ssh_user, hostname)); - - for ssh_opt in &deploy_data.merged_settings.ssh_opts { - ssh_confirm_command = ssh_confirm_command.arg(ssh_opt); - } - - let lock_path = - super::make_lock_path(&temp_path, &deploy_data.profile.profile_settings.path); - - let mut confirm_command = format!("rm {}", lock_path); - if let Some(sudo_cmd) = &deploy_defs.sudo { - confirm_command = format!("{} {}", sudo_cmd, confirm_command); - } - - debug!( - "Attempting to run command to confirm deployment: {}", - confirm_command - ); - - let ssh_confirm_exit_status = ssh_confirm_command - .arg(confirm_command) - .status() - .await - .map_err(DeployProfileError::SSHConfirmError)?; - - match ssh_confirm_exit_status.code() { - Some(0) => (), - a => return Err(DeployProfileError::SSHConfirmExitError(a)), - }; - - info!("Deployment confirmed."); - + let c = confirm_profile(deploy_data, deploy_defs, hostname, temp_path).await; recv_activated.await.unwrap(); + c?; } Ok(()) -- cgit v1.2.3 From b74bb50a15b3b94d6c7138a8ca40aedc92de5f69 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Sat, 6 Feb 2021 18:01:43 -0700 Subject: Clean up structure used for activation command error sending --- src/deploy.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/deploy.rs b/src/deploy.rs index aba41f2..62c97d0 100644 --- a/src/deploy.rs +++ b/src/deploy.rs @@ -299,16 +299,18 @@ pub async fn deploy_profile( tokio::spawn(async move { let o = ssh_activate.wait_with_output().await; - // Don't event unless somethis is bad - // TODO: maybe replace the structure with our own - match o { + let maybe_err = match o { + Err(x) => Some(DeployProfileError::SSHActivateError(x)), Ok(ref x) => match x.status.code() { - Some(0) => (), - _ => send_activate.send(o).unwrap(), + Some(0) => None, + a => Some(DeployProfileError::SSHActivateExitError(a)), }, - _ => send_activate.send(o).unwrap(), }; + if let Some(err) = maybe_err { + send_activate.send(err).unwrap(); + } + send_activated.send(()).unwrap(); }); @@ -321,11 +323,7 @@ pub async fn deploy_profile( }; }, x = recv_activate => { - debug!("Activate command exited with an error"); - match x.unwrap().map_err(DeployProfileError::SSHActivateError)?.status.code() { - Some(0) => unreachable!(), // We know it is an error, see a comment above - a => return Err(DeployProfileError::SSHActivateExitError(a)), - }; + return Err(x.unwrap()); }, } -- cgit v1.2.3 From 7ee0f7eb4d315fdc0a44f09eef2e180ae27b91d0 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Sat, 6 Feb 2021 18:28:35 -0700 Subject: Re-add debug log for activate command erroring --- src/deploy.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/deploy.rs b/src/deploy.rs index 62c97d0..54d5ea7 100644 --- a/src/deploy.rs +++ b/src/deploy.rs @@ -323,6 +323,7 @@ pub async fn deploy_profile( }; }, x = recv_activate => { + debug!("Activate command exited with an error"); return Err(x.unwrap()); }, } -- cgit v1.2.3