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/utils/data.rs | 4 ++++ src/utils/deploy.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 3 deletions(-) (limited to 'src/utils') diff --git a/src/utils/data.rs b/src/utils/data.rs index f72f9a7..351b9ae 100644 --- a/src/utils/data.rs +++ b/src/utils/data.rs @@ -44,6 +44,10 @@ pub struct ProfileSettings { pub bootstrap: Option, #[serde(rename(deserialize = "profilePath"))] pub profile_path: Option, + #[serde(rename(deserialize = "maxTime"))] + pub max_time: Option, + #[serde(rename(deserialize = "tempPath"))] + pub temp_path: Option, } #[derive(Deserialize, Debug, Clone)] diff --git a/src/utils/deploy.rs b/src/utils/deploy.rs index 7301967..e3493ba 100644 --- a/src/utils/deploy.rs +++ b/src/utils/deploy.rs @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: MPL-2.0 +use std::borrow::Cow; use tokio::process::Command; fn build_activate_command( @@ -11,9 +12,13 @@ fn build_activate_command( closure: &str, bootstrap_cmd: &Option, auto_rollback: bool, + temp_path: &Cow, + max_time: u16, ) -> String { - let mut self_activate_command = - format!("{} '{}' '{}'", activate_path_str, profile_path, closure); + let mut self_activate_command = format!( + "{} '{}' '{}' {} {}", + activate_path_str, profile_path, closure, temp_path, max_time + ); if let Some(sudo_cmd) = &sudo { self_activate_command = format!("{} {}", sudo_cmd, self_activate_command); @@ -41,6 +46,8 @@ fn test_activation_command_builder() { let closure = "/blah/etc"; let bootstrap_cmd = None; let auto_rollback = true; + let temp_path = &"/tmp/deploy-rs".into(); + let max_time = 30; assert_eq!( build_activate_command( @@ -50,8 +57,10 @@ fn test_activation_command_builder() { closure, &bootstrap_cmd, auto_rollback, + temp_path, + max_time ), - "sudo -u test /blah/bin/activate '/blah/profiles/test' '/blah/etc' --auto-rollback" + "sudo -u test /blah/bin/activate '/blah/profiles/test' '/blah/etc' /tmp/deploy-rs 30 --auto-rollback" .to_string(), ); } @@ -67,6 +76,13 @@ pub async fn deploy_profile( let activate_path_str = super::deploy_path_to_activate_path_str(&deploy_defs.current_exe)?; + let temp_path: Cow = match &deploy_data.profile.profile_settings.temp_path { + Some(x) => x.into(), + None => "/tmp/deploy-rs".into(), + }; + + let max_time = deploy_data.profile.profile_settings.max_time.unwrap_or(30); + let self_activate_command = build_activate_command( activate_path_str, &deploy_defs.sudo, @@ -74,6 +90,8 @@ pub async fn deploy_profile( &deploy_data.profile.profile_settings.path, &deploy_data.profile.profile_settings.bootstrap, deploy_data.merged_settings.auto_rollback, + &temp_path, + max_time, ); let hostname = match deploy_data.cmd_overrides.hostname { @@ -94,5 +112,33 @@ pub async fn deploy_profile( good_panic!("Activation over SSH failed"); } + info!("Success, attempting to connect to the node to confirm deployment"); + + 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_hash = &deploy_data.profile.profile_settings.path[11 /* /nix/store/ */ ..]; + let lock_path = format!("{}/activating-{}", temp_path, lock_hash); + + let mut confirm_command = format!("rm {}", lock_path); + if let Some(sudo_cmd) = &deploy_defs.sudo { + confirm_command = format!("{} {}", sudo_cmd, confirm_command); + } + + let ssh_exit_status = ssh_confirm_command.arg(confirm_command).status().await?; + + if !ssh_exit_status.success() { + good_panic!( + "Failed to confirm deployment, the node will roll back in <{} seconds", + max_time + ); + } + + info!("Deployment confirmed."); + Ok(()) } -- cgit v1.2.3