diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bin/activate.rs | 5 | ||||
-rw-r--r-- | src/bin/deploy.rs | 11 | ||||
-rw-r--r-- | src/data.rs | 2 | ||||
-rw-r--r-- | src/deploy.rs | 132 | ||||
-rw-r--r-- | src/lib.rs | 6 | ||||
-rw-r--r-- | src/push.rs | 4 |
6 files changed, 94 insertions, 66 deletions
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 30ebd25..8bd8b18 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..54d5ea7 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<String>, @@ -138,6 +138,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<i32>), +} + +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}")] SSHSpawnActivateError(std::io::Error), @@ -152,12 +203,8 @@ pub enum DeployProfileError { #[error("Waiting over SSH resulted in a bad exit code: {0:?}")] SSHWaitExitError(Option<i32>), - #[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<i32>), + #[error("Error confirming deployment: {0}")] + ConfirmError(#[from] ConfirmProfileError), } pub async fn deploy_profile( @@ -246,51 +293,46 @@ 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)?; - - match ssh_wait_exit_status.code() { - Some(0) => (), - a => return Err(DeployProfileError::SSHWaitExitError(a)), - }; + let (send_activate, recv_activate) = tokio::sync::oneshot::channel(); + let (send_activated, recv_activated) = tokio::sync::oneshot::channel(); - info!("Success activating, attempting to confirm activation"); + tokio::spawn(async move { + let o = ssh_activate.wait_with_output().await; - let mut c = Command::new("ssh"); - let mut ssh_confirm_command = c.arg(format!("ssh://{}@{}", deploy_defs.ssh_user, hostname)); + let maybe_err = match o { + Err(x) => Some(DeployProfileError::SSHActivateError(x)), + Ok(ref x) => match x.status.code() { + Some(0) => None, + a => Some(DeployProfileError::SSHActivateExitError(a)), + }, + }; - for ssh_opt in &deploy_data.merged_settings.ssh_opts { - ssh_confirm_command = ssh_confirm_command.arg(ssh_opt); - } + if let Some(err) = maybe_err { + send_activate.send(err).unwrap(); + } - let lock_path = - super::make_lock_path(&temp_path, &deploy_data.profile.profile_settings.path); + send_activated.send(()).unwrap(); + }); - let mut confirm_command = format!("rm {}", lock_path); - if let Some(sudo_cmd) = &deploy_defs.sudo { - confirm_command = format!("{} {}", sudo_cmd, confirm_command); + 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"); + return Err(x.unwrap()); + }, } - debug!( - "Attempting to run command to confirm deployment: {}", - confirm_command - ); - - let ssh_exit_status = ssh_confirm_command - .arg(confirm_command) - .status() - .await - .map_err(DeployProfileError::SSHConfirmError)?; - - match ssh_exit_status.code() { - Some(0) => (), - a => return Err(DeployProfileError::SSHConfirmExitError(a)), - }; + info!("Success activating, attempting to confirm activation"); - info!("Deployment confirmed."); + let c = confirm_profile(deploy_data, deploy_defs, hostname, temp_path).await; + recv_activated.await.unwrap(); + c?; } Ok(()) @@ -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 { |