From f73e393a75fcad939a240ff3b72cbc75813e90e3 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Mon, 28 Sep 2020 14:37:43 -0700 Subject: Add missing files --- src/utils/data.rs | 64 +++++++++++++++++++++++++++++++ src/utils/deploy.rs | 57 +++++++++++++++++++++++++++ src/utils/mod.rs | 71 ++++++++++++++++++++++++++++++++++ src/utils/push.rs | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 300 insertions(+) create mode 100644 src/utils/data.rs create mode 100644 src/utils/deploy.rs create mode 100644 src/utils/mod.rs create mode 100644 src/utils/push.rs (limited to 'src/utils') diff --git a/src/utils/data.rs b/src/utils/data.rs new file mode 100644 index 0000000..779d913 --- /dev/null +++ b/src/utils/data.rs @@ -0,0 +1,64 @@ +use merge::Merge; + +use std::{collections::HashMap}; + +#[derive(Deserialize, Debug, Clone, Merge)] +pub struct GenericSettings { + #[serde(rename(deserialize = "sshUser"))] + pub ssh_user: Option, + pub user: Option, + #[serde( + skip_serializing_if = "Vec::is_empty", + default, + rename(deserialize = "sshOpts") + )] + #[merge(strategy = merge::vec::append)] + pub ssh_opts: Vec, + #[serde(rename(deserialize = "fastConnection"))] + pub fast_connection: Option, + #[serde(rename(deserialize = "autoRollback"))] + pub auto_rollback: Option, +} + +#[derive(Deserialize, Debug, Clone)] +pub struct NodeSettings { + pub hostname: String, +} + +#[derive(Deserialize, Debug, Clone)] +pub struct ProfileSettings { + pub path: String, + pub activate: Option, + pub bootstrap: Option, +} + +#[derive(Deserialize, Debug, Clone)] +pub struct Profile { + #[serde(flatten)] + pub profile_settings: ProfileSettings, + #[serde(flatten)] + pub generic_settings: GenericSettings, +} + +#[derive(Deserialize, Debug, Clone)] +pub struct Node { + #[serde(flatten)] + pub generic_settings: GenericSettings, + #[serde(flatten)] + pub node_settings: NodeSettings, + + pub profiles: HashMap, + #[serde( + skip_serializing_if = "Vec::is_empty", + default, + rename(deserialize = "profilesOrder") + )] + pub profiles_order: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +pub struct Data { + #[serde(flatten)] + pub generic_settings: GenericSettings, + pub nodes: HashMap, +} diff --git a/src/utils/deploy.rs b/src/utils/deploy.rs new file mode 100644 index 0000000..7260e55 --- /dev/null +++ b/src/utils/deploy.rs @@ -0,0 +1,57 @@ +use super::data; + + +use tokio::process::Command; + +pub async fn deploy_profile( + profile: &data::Profile, + profile_name: &str, + node: &data::Node, + node_name: &str, + merged_settings: &data::GenericSettings, + deploy_data: &super::DeployData<'_>, +) -> Result<(), Box> { + info!( + "Activating profile `{}` for node `{}`", + profile_name, node_name + ); + + let mut self_activate_command = format!( + "{} activate '{}' '{}'", + deploy_data.current_exe.as_path().to_str().unwrap(), + deploy_data.profile_path, + profile.profile_settings.path, + ); + + if let Some(sudo_cmd) = &deploy_data.sudo { + self_activate_command = format!("{} {}", sudo_cmd, self_activate_command); + } + + if let Some(ref bootstrap_cmd) = profile.profile_settings.bootstrap { + self_activate_command = format!( + "{} --bootstrap-cmd '{}'", + self_activate_command, bootstrap_cmd + ); + } + + if let Some(ref activate_cmd) = profile.profile_settings.activate { + self_activate_command = format!( + "{} --activate-cmd '{}'", + self_activate_command, activate_cmd + ); + } + + let mut c = Command::new("ssh"); + let mut ssh_command = c.arg(format!( + "ssh://{}@{}", + deploy_data.ssh_user, node.node_settings.hostname + )); + + for ssh_opt in &merged_settings.ssh_opts { + ssh_command = ssh_command.arg(ssh_opt); + } + + ssh_command.arg(self_activate_command).spawn()?.await?; + + Ok(()) +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 0000000..764e2e9 --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1,71 @@ +use std::borrow::Cow; +use std::path::PathBuf; + +pub mod data; +pub mod deploy; +pub mod push; + +macro_rules! good_panic { + ($($tts:tt)*) => {{ + error!($($tts)*); + std::process::exit(1); + }} +} + +pub struct DeployData<'a> { + pub sudo: Option, + pub ssh_user: Cow<'a, str>, + pub profile_user: Cow<'a, str>, + pub profile_path: String, + pub current_exe: PathBuf, +} + +pub async fn make_deploy_data<'a>( + profile_name: &str, + node_name: &str, + merged_settings: &'a data::GenericSettings, +) -> Result, Box> { + let ssh_user: Cow = match &merged_settings.ssh_user { + Some(u) => u.into(), + None => whoami::username().into(), + }; + + let profile_user: Cow = match &merged_settings.user { + Some(x) => x.into(), + None => match &merged_settings.ssh_user { + Some(x) => x.into(), + None => good_panic!( + "Neither user nor sshUser set for profile `{}` of node `{}`", + profile_name, + node_name + ), + }, + }; + + let profile_path = match &profile_user[..] { + "root" => format!("/nix/var/nix/profiles/{}", profile_name), + _ => format!( + "/nix/var/nix/profiles/per-user/{}/{}", + profile_user, profile_name + ), + }; + + let sudo: Option = match merged_settings.user { + Some(ref user) if user != &ssh_user => Some(format!("sudo -u {}", user)), + _ => None, + }; + + let current_exe = std::env::current_exe().expect("Expected to find current executable path"); + + if !current_exe.starts_with("/nix/store/") { + good_panic!("The deploy binary must be in the Nix store"); + } + + Ok(DeployData { + sudo, + ssh_user, + profile_user, + profile_path, + current_exe, + }) +} diff --git a/src/utils/push.rs b/src/utils/push.rs new file mode 100644 index 0000000..54ae013 --- /dev/null +++ b/src/utils/push.rs @@ -0,0 +1,108 @@ +use super::data; + +use std::process::Stdio; +use tokio::process::Command; + +pub async fn push_profile( + profile: &data::Profile, + profile_name: &str, + node: &data::Node, + node_name: &str, + supports_flakes: bool, + check_sigs: bool, + repo: &str, + merged_settings: &data::GenericSettings, + deploy_data: &super::DeployData<'_>, +) -> Result<(), Box> { + info!( + "Pushing profile `{}` for node `{}`", + profile_name, node_name + ); + + debug!( + "Building profile `{} for node `{}`", + profile_name, node_name + ); + + if supports_flakes { + Command::new("nix") + .arg("build") + .arg("--no-link") + .arg(format!( + "{}#deploy.nodes.{}.profiles.{}.path", + repo, node_name, profile_name + )) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn()? + .await?; + } else { + Command::new("nix-build") + .arg(&repo) + .arg("-A") + .arg(format!( + "deploy.nodes.{}.profiles.{}.path", + node_name, profile_name + )) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn()? + .await?; + } + + if let Ok(local_key) = std::env::var("LOCAL_KEY") { + info!( + "Signing key present! Signing profile `{}` for node `{}`", + profile_name, node_name + ); + + Command::new("nix") + .arg("sign-paths") + .arg("-r") + .arg("-k") + .arg(local_key) + .arg(&profile.profile_settings.path) + .arg(&deploy_data.current_exe) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn()? + .await?; + } + + debug!("Copying profile `{} for node `{}`", profile_name, node_name); + + let mut copy_command_ = Command::new("nix"); + let mut copy_command = copy_command_.arg("copy"); + + if let Some(true) = merged_settings.fast_connection { + copy_command = copy_command.arg("--substitute-on-destination"); + } + + if !check_sigs { + copy_command = copy_command.arg("--no-check-sigs"); + } + + let ssh_opts_str = merged_settings + .ssh_opts + // This should provide some extra safety, but it also breaks for some reason, oh well + // .iter() + // .map(|x| format!("'{}'", x)) + // .collect::>() + .join(" "); + + copy_command + .arg("--to") + .arg(format!( + "ssh://{}@{}", + deploy_data.ssh_user, node.node_settings.hostname + )) + .arg(&profile.profile_settings.path) + .arg(&deploy_data.current_exe) + .env("NIX_SSHOPTS", ssh_opts_str) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn()? + .await?; + + Ok(()) +} -- cgit v1.2.3 From 889fb0d3f9eee9085883fe1f31e05b07be0939ec Mon Sep 17 00:00:00 2001 From: notgne2 Date: Mon, 28 Sep 2020 15:00:16 -0700 Subject: separate out activation logic --- src/utils/activate.rs | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/utils/mod.rs | 72 +++++++++++++++++++++++++++++++-- 2 files changed, 176 insertions(+), 4 deletions(-) create mode 100644 src/utils/activate.rs (limited to 'src/utils') diff --git a/src/utils/activate.rs b/src/utils/activate.rs new file mode 100644 index 0000000..33774fd --- /dev/null +++ b/src/utils/activate.rs @@ -0,0 +1,108 @@ +use std::process::Stdio; +use tokio::process::Command; + +use std::path::Path; + +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(()) +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 764e2e9..935f470 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,10 +1,7 @@ use std::borrow::Cow; use std::path::PathBuf; -pub mod data; -pub mod deploy; -pub mod push; - +#[macro_export] macro_rules! good_panic { ($($tts:tt)*) => {{ error!($($tts)*); @@ -12,6 +9,73 @@ macro_rules! good_panic { }} } +pub mod activate; +pub mod data; +pub mod deploy; +pub mod push; + +#[derive(PartialEq, Debug)] +pub struct DeployFlake<'a> { + pub repo: &'a str, + pub node: Option<&'a str>, + pub profile: Option<&'a str>, +} + +pub fn parse_flake(flake: &str) -> DeployFlake { + let flake_fragment_start = flake.find('#'); + let (repo, maybe_fragment) = match flake_fragment_start { + Some(s) => (&flake[..s], Some(&flake[s + 1..])), + None => (flake, None), + }; + + let (node, profile) = match maybe_fragment { + Some(fragment) => { + let fragment_profile_start = fragment.find('.'); + match fragment_profile_start { + Some(s) => (Some(&fragment[..s]), Some(&fragment[s + 1..])), + None => (Some(fragment), None), + } + } + None => (None, None), + }; + + DeployFlake { + repo, + node, + profile, + } +} + +#[test] +fn test_parse_flake() { + assert_eq!( + parse_flake("../deploy/examples/system#example"), + DeployFlake { + repo: "../deploy/examples/system", + node: Some("example"), + profile: None + } + ); + + assert_eq!( + parse_flake("../deploy/examples/system#example.system"), + DeployFlake { + repo: "../deploy/examples/system", + node: Some("example"), + profile: Some("system") + } + ); + + assert_eq!( + parse_flake("../deploy/examples/system"), + DeployFlake { + repo: "../deploy/examples/system", + node: None, + profile: None, + } + ); +} + pub struct DeployData<'a> { pub sudo: Option, pub ssh_user: Cow<'a, str>, -- cgit v1.2.3 From a22063343e54da9f589c7235f2f64b57fe5c257b Mon Sep 17 00:00:00 2001 From: notgne2 Date: Mon, 28 Sep 2020 15:12:42 -0700 Subject: More functions --- src/utils/data.rs | 2 +- src/utils/deploy.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'src/utils') diff --git a/src/utils/data.rs b/src/utils/data.rs index 779d913..b28b6cd 100644 --- a/src/utils/data.rs +++ b/src/utils/data.rs @@ -1,6 +1,6 @@ use merge::Merge; -use std::{collections::HashMap}; +use std::collections::HashMap; #[derive(Deserialize, Debug, Clone, Merge)] pub struct GenericSettings { diff --git a/src/utils/deploy.rs b/src/utils/deploy.rs index 7260e55..900743c 100644 --- a/src/utils/deploy.rs +++ b/src/utils/deploy.rs @@ -1,6 +1,5 @@ use super::data; - use tokio::process::Command; pub async fn deploy_profile( -- cgit v1.2.3 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/utils/data.rs | 10 ++++++---- src/utils/deploy.rs | 17 +++++++++++++++-- src/utils/push.rs | 2 +- 3 files changed, 22 insertions(+), 7 deletions(-) (limited to 'src/utils') diff --git a/src/utils/data.rs b/src/utils/data.rs index b28b6cd..0753508 100644 --- a/src/utils/data.rs +++ b/src/utils/data.rs @@ -14,10 +14,12 @@ pub struct GenericSettings { )] #[merge(strategy = merge::vec::append)] pub ssh_opts: Vec, - #[serde(rename(deserialize = "fastConnection"))] - pub fast_connection: Option, - #[serde(rename(deserialize = "autoRollback"))] - pub auto_rollback: Option, + #[serde(rename(deserialize = "fastConnection"), default)] + #[merge(strategy = merge::bool::overwrite_false)] + pub fast_connection: bool, + #[serde(rename(deserialize = "autoRollback"), default)] + #[merge(strategy = merge::bool::overwrite_false)] + pub auto_rollback: bool, } #[derive(Deserialize, Debug, Clone)] diff --git a/src/utils/deploy.rs b/src/utils/deploy.rs index 900743c..42bd0b4 100644 --- a/src/utils/deploy.rs +++ b/src/utils/deploy.rs @@ -9,6 +9,7 @@ pub async fn deploy_profile( node_name: &str, merged_settings: &data::GenericSettings, deploy_data: &super::DeployData<'_>, + auto_rollback: bool, ) -> Result<(), Box> { info!( "Activating profile `{}` for node `{}`", @@ -16,8 +17,16 @@ pub async fn deploy_profile( ); let mut self_activate_command = format!( - "{} activate '{}' '{}'", - deploy_data.current_exe.as_path().to_str().unwrap(), + "{} '{}' '{}'", + deploy_data + .current_exe + .as_path() + .parent() + .unwrap() + .to_str() + .unwrap() + .to_owned() + + "/activate", deploy_data.profile_path, profile.profile_settings.path, ); @@ -40,6 +49,10 @@ pub async fn deploy_profile( ); } + if auto_rollback { + self_activate_command = format!("{} --auto-rollback", self_activate_command); + } + let mut c = Command::new("ssh"); let mut ssh_command = c.arg(format!( "ssh://{}@{}", diff --git a/src/utils/push.rs b/src/utils/push.rs index 54ae013..0e1b9ba 100644 --- a/src/utils/push.rs +++ b/src/utils/push.rs @@ -74,7 +74,7 @@ pub async fn push_profile( let mut copy_command_ = Command::new("nix"); let mut copy_command = copy_command_.arg("copy"); - if let Some(true) = merged_settings.fast_connection { + if merged_settings.fast_connection { copy_command = copy_command.arg("--substitute-on-destination"); } -- 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/utils/activate.rs | 108 -------------------------------------------------- src/utils/mod.rs | 1 - 2 files changed, 109 deletions(-) delete mode 100644 src/utils/activate.rs (limited to 'src/utils') diff --git a/src/utils/activate.rs b/src/utils/activate.rs deleted file mode 100644 index 33774fd..0000000 --- a/src/utils/activate.rs +++ /dev/null @@ -1,108 +0,0 @@ -use std::process::Stdio; -use tokio::process::Command; - -use std::path::Path; - -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(()) -} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 935f470..8861692 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -9,7 +9,6 @@ macro_rules! good_panic { }} } -pub mod activate; pub mod data; pub mod deploy; pub mod push; -- 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/utils/data.rs | 4 ++++ src/utils/deploy.rs | 4 ++++ src/utils/mod.rs | 4 ++++ src/utils/push.rs | 4 ++++ 4 files changed, 16 insertions(+) (limited to 'src/utils') diff --git a/src/utils/data.rs b/src/utils/data.rs index 0753508..d1dae5b 100644 --- a/src/utils/data.rs +++ b/src/utils/data.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2020 Serokell +// +// SPDX-License-Identifier: MPL-2.0 + use merge::Merge; use std::collections::HashMap; diff --git a/src/utils/deploy.rs b/src/utils/deploy.rs index 42bd0b4..247d5e5 100644 --- a/src/utils/deploy.rs +++ b/src/utils/deploy.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2020 Serokell +// +// SPDX-License-Identifier: MPL-2.0 + use super::data; use tokio::process::Command; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 8861692..5802627 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2020 Serokell +// +// SPDX-License-Identifier: MPL-2.0 + use std::borrow::Cow; use std::path::PathBuf; diff --git a/src/utils/push.rs b/src/utils/push.rs index 0e1b9ba..c87c32b 100644 --- a/src/utils/push.rs +++ b/src/utils/push.rs @@ -1,3 +1,7 @@ +// SPDX-FileCopyrightText: 2020 Serokell +// +// SPDX-License-Identifier: MPL-2.0 + use super::data; use std::process::Stdio; -- cgit v1.2.3 From a0328dbcf76b7c551e92fd25060cfc7d7e4d9ebe Mon Sep 17 00:00:00 2001 From: notgne2 Date: Tue, 29 Sep 2020 21:27:49 -0700 Subject: More separation and component testing --- src/utils/deploy.rs | 116 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 28 deletions(-) (limited to 'src/utils') diff --git a/src/utils/deploy.rs b/src/utils/deploy.rs index 42bd0b4..c44c0d3 100644 --- a/src/utils/deploy.rs +++ b/src/utils/deploy.rs @@ -2,47 +2,54 @@ use super::data; use tokio::process::Command; -pub async fn deploy_profile( - profile: &data::Profile, - profile_name: &str, - node: &data::Node, - node_name: &str, - merged_settings: &data::GenericSettings, - deploy_data: &super::DeployData<'_>, - auto_rollback: bool, -) -> Result<(), Box> { - info!( - "Activating profile `{}` for node `{}`", - profile_name, node_name - ); - - let mut self_activate_command = format!( - "{} '{}' '{}'", - deploy_data - .current_exe - .as_path() +fn deploy_path_to_activate_path_str( + deploy_path: &std::path::Path, +) -> Result> { + Ok(format!( + "{}/activate", + deploy_path .parent() - .unwrap() + .ok_or("Deploy path too short")? .to_str() - .unwrap() + .ok_or("Deploy path is not valid utf8")? .to_owned() - + "/activate", - deploy_data.profile_path, - profile.profile_settings.path, - ); + )) +} - if let Some(sudo_cmd) = &deploy_data.sudo { +#[test] +fn test_activate_path_generation() { + match deploy_path_to_activate_path_str(&std::path::PathBuf::from( + "/blah/blah/deploy-rs/bin/deploy", + )) { + Err(_) => panic!(""), + Ok(x) => assert_eq!(x, "/blah/blah/deploy-rs/bin/activate".to_string()), + } +} + +fn build_activate_command( + activate_path_str: String, + sudo: &Option, + profile_path: &str, + closure: &str, + activate_cmd: &Option, + bootstrap_cmd: &Option, + auto_rollback: bool, +) -> Result> { + let mut self_activate_command = + format!("{} '{}' '{}'", activate_path_str, profile_path, closure); + + if let Some(sudo_cmd) = &sudo { self_activate_command = format!("{} {}", sudo_cmd, self_activate_command); } - if let Some(ref bootstrap_cmd) = profile.profile_settings.bootstrap { + if let Some(ref bootstrap_cmd) = bootstrap_cmd { self_activate_command = format!( "{} --bootstrap-cmd '{}'", self_activate_command, bootstrap_cmd ); } - if let Some(ref activate_cmd) = profile.profile_settings.activate { + if let Some(ref activate_cmd) = activate_cmd { self_activate_command = format!( "{} --activate-cmd '{}'", self_activate_command, activate_cmd @@ -53,6 +60,59 @@ pub async fn deploy_profile( self_activate_command = format!("{} --auto-rollback", self_activate_command); } + Ok(self_activate_command) +} + +#[test] +fn test_activation_command_builder() { + let activate_path_str = "/blah/bin/activate".to_string(); + let sudo = Some("sudo -u test".to_string()); + let profile_path = "/blah/profiles/test"; + let closure = "/blah/etc"; + let activate_cmd = Some("$THING/bin/aaaaaaa".to_string()); + let bootstrap_cmd = None; + let auto_rollback = true; + + match build_activate_command( + activate_path_str, + &sudo, + profile_path, + closure, + &activate_cmd, + &bootstrap_cmd, + auto_rollback, + ) { + Err(_) => panic!(""), + Ok(x) => assert_eq!(x, "sudo -u test /blah/bin/activate '/blah/profiles/test' '/blah/etc' --activate-cmd '$THING/bin/aaaaaaa' --auto-rollback".to_string()), + } +} + +pub async fn deploy_profile( + profile: &data::Profile, + profile_name: &str, + node: &data::Node, + node_name: &str, + merged_settings: &data::GenericSettings, + deploy_data: &super::DeployData<'_>, + auto_rollback: bool, +) -> Result<(), Box> { + info!( + "Activating profile `{}` for node `{}`", + profile_name, node_name + ); + + let activate_path_str = deploy_path_to_activate_path_str(&deploy_data.current_exe)?; + + let self_activate_command = build_activate_command( + activate_path_str, + &deploy_data.sudo, + &deploy_data.profile_path, + &profile.profile_settings.path, + &profile.profile_settings.activate, + &profile.profile_settings.bootstrap, + auto_rollback, + )?; + let mut c = Command::new("ssh"); let mut ssh_command = c.arg(format!( "ssh://{}@{}", -- cgit v1.2.3 From ea5aab76849ba3ce9ff2b7eba2a391d4ea33fa3a Mon Sep 17 00:00:00 2001 From: notgne2 Date: Thu, 1 Oct 2020 12:43:33 -0700 Subject: Improve nix copy stuff --- src/utils/deploy.rs | 26 +------------------------- src/utils/mod.rs | 24 ++++++++++++++++++++++++ src/utils/push.rs | 10 ++++++---- 3 files changed, 31 insertions(+), 29 deletions(-) (limited to 'src/utils') diff --git a/src/utils/deploy.rs b/src/utils/deploy.rs index 9c258fd..1abae64 100644 --- a/src/utils/deploy.rs +++ b/src/utils/deploy.rs @@ -6,30 +6,6 @@ use super::data; use tokio::process::Command; -fn deploy_path_to_activate_path_str( - deploy_path: &std::path::Path, -) -> Result> { - Ok(format!( - "{}/activate", - deploy_path - .parent() - .ok_or("Deploy path too short")? - .to_str() - .ok_or("Deploy path is not valid utf8")? - .to_owned() - )) -} - -#[test] -fn test_activate_path_generation() { - match deploy_path_to_activate_path_str(&std::path::PathBuf::from( - "/blah/blah/deploy-rs/bin/deploy", - )) { - Err(_) => panic!(""), - Ok(x) => assert_eq!(x, "/blah/blah/deploy-rs/bin/activate".to_string()), - } -} - fn build_activate_command( activate_path_str: String, sudo: &Option, @@ -105,7 +81,7 @@ pub async fn deploy_profile( profile_name, node_name ); - let activate_path_str = deploy_path_to_activate_path_str(&deploy_data.current_exe)?; + let activate_path_str = super::deploy_path_to_activate_path_str(&deploy_data.current_exe)?; let self_activate_command = build_activate_command( activate_path_str, diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 5802627..30201c3 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -136,3 +136,27 @@ pub async fn make_deploy_data<'a>( current_exe, }) } + +pub fn deploy_path_to_activate_path_str( + deploy_path: &std::path::Path, +) -> Result> { + Ok(format!( + "{}/activate", + deploy_path + .parent() + .ok_or("Deploy path too short")? + .to_str() + .ok_or("Deploy path is not valid utf8")? + .to_owned() + )) +} + +#[test] +fn test_activate_path_generation() { + match deploy_path_to_activate_path_str(&std::path::PathBuf::from( + "/blah/blah/deploy-rs/bin/deploy", + )) { + Err(_) => panic!(""), + Ok(x) => assert_eq!(x, "/blah/blah/deploy-rs/bin/activate".to_string()), + } +} diff --git a/src/utils/push.rs b/src/utils/push.rs index c87c32b..38a576f 100644 --- a/src/utils/push.rs +++ b/src/utils/push.rs @@ -66,7 +66,9 @@ pub async fn push_profile( .arg("-k") .arg(local_key) .arg(&profile.profile_settings.path) - .arg(&deploy_data.current_exe) + .arg(&super::deploy_path_to_activate_path_str( + &deploy_data.current_exe, + )?) .stdout(Stdio::null()) .stderr(Stdio::null()) .spawn()? @@ -101,10 +103,10 @@ pub async fn push_profile( deploy_data.ssh_user, node.node_settings.hostname )) .arg(&profile.profile_settings.path) - .arg(&deploy_data.current_exe) + .arg(&super::deploy_path_to_activate_path_str( + &deploy_data.current_exe, + )?) .env("NIX_SSHOPTS", ssh_opts_str) - .stdout(Stdio::null()) - .stderr(Stdio::null()) .spawn()? .await?; -- cgit v1.2.3 From e14acaf2bdc14bbdc30f3d558b62f64fe33ff5f9 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Thu, 1 Oct 2020 18:21:40 -0700 Subject: Rework system for deploy properties, add CLI override flags --- src/utils/deploy.rs | 37 +++++------- src/utils/mod.rs | 166 +++++++++++++++++++++++++++++++++++++++------------- src/utils/push.rs | 46 +++++++-------- 3 files changed, 165 insertions(+), 84 deletions(-) (limited to 'src/utils') diff --git a/src/utils/deploy.rs b/src/utils/deploy.rs index 1abae64..d46f2db 100644 --- a/src/utils/deploy.rs +++ b/src/utils/deploy.rs @@ -2,8 +2,6 @@ // // SPDX-License-Identifier: MPL-2.0 -use super::data; - use tokio::process::Command; fn build_activate_command( @@ -68,38 +66,35 @@ fn test_activation_command_builder() { } pub async fn deploy_profile( - profile: &data::Profile, - profile_name: &str, - node: &data::Node, - node_name: &str, - merged_settings: &data::GenericSettings, deploy_data: &super::DeployData<'_>, - auto_rollback: bool, + deploy_defs: &super::DeployDefs<'_>, ) -> Result<(), Box> { info!( "Activating profile `{}` for node `{}`", - profile_name, node_name + deploy_data.profile_name, deploy_data.node_name ); - let activate_path_str = super::deploy_path_to_activate_path_str(&deploy_data.current_exe)?; + let activate_path_str = super::deploy_path_to_activate_path_str(&deploy_defs.current_exe)?; let self_activate_command = build_activate_command( activate_path_str, - &deploy_data.sudo, - &deploy_data.profile_path, - &profile.profile_settings.path, - &profile.profile_settings.activate, - &profile.profile_settings.bootstrap, - auto_rollback, + &deploy_defs.sudo, + &deploy_defs.profile_path, + &deploy_data.profile.profile_settings.path, + &deploy_data.profile.profile_settings.activate, + &deploy_data.profile.profile_settings.bootstrap, + deploy_data.merged_settings.auto_rollback, )?; + let hostname = match deploy_data.cmd_overrides.hostname { + Some(ref x) => x, + None => &deploy_data.node.node_settings.hostname, + }; + let mut c = Command::new("ssh"); - let mut ssh_command = c.arg(format!( - "ssh://{}@{}", - deploy_data.ssh_user, node.node_settings.hostname - )); + let mut ssh_command = c.arg(format!("ssh://{}@{}", deploy_defs.ssh_user, hostname)); - for ssh_opt in &merged_settings.ssh_opts { + for ssh_opt in &deploy_data.merged_settings.ssh_opts { ssh_command = ssh_command.arg(ssh_opt); } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 30201c3..bfdbc5e 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -5,6 +5,8 @@ use std::borrow::Cow; use std::path::PathBuf; +use merge::Merge; + #[macro_export] macro_rules! good_panic { ($($tts:tt)*) => {{ @@ -17,6 +19,40 @@ pub mod data; pub mod deploy; pub mod push; +pub struct CmdOverrides { + pub ssh_user: Option, + pub profile_user: Option, + pub ssh_opts: Option, + pub fast_connection: Option, + pub auto_rollback: Option, + pub hostname: Option, +} + +pub enum OverridePurity { + ErrorProfile, + Error, + Warn, + Pure, +} + +impl CmdOverrides { + pub fn purity(&self) -> OverridePurity { + if self.profile_user.is_some() { + return OverridePurity::ErrorProfile; + } + + if self.hostname.is_some() || self.ssh_user.is_some() { + return OverridePurity::Error; + } + + if self.ssh_opts.is_some() || self.fast_connection.is_some() { + return OverridePurity::Warn; + } + + OverridePurity::Pure + } +} + #[derive(PartialEq, Debug)] pub struct DeployFlake<'a> { pub repo: &'a str, @@ -80,60 +116,110 @@ fn test_parse_flake() { } pub struct DeployData<'a> { - pub sudo: Option, + pub node_name: &'a str, + pub node: &'a data::Node, + pub profile_name: &'a str, + pub profile: &'a data::Profile, + + pub cmd_overrides: &'a CmdOverrides, + + pub merged_settings: data::GenericSettings, +} + +pub struct DeployDefs<'a> { pub ssh_user: Cow<'a, str>, pub profile_user: Cow<'a, str>, pub profile_path: String, pub current_exe: PathBuf, + pub sudo: Option, } -pub async fn make_deploy_data<'a>( - profile_name: &str, - node_name: &str, - merged_settings: &'a data::GenericSettings, -) -> Result, Box> { - let ssh_user: Cow = match &merged_settings.ssh_user { - Some(u) => u.into(), - None => whoami::username().into(), - }; - - let profile_user: Cow = match &merged_settings.user { - Some(x) => x.into(), - None => match &merged_settings.ssh_user { - Some(x) => x.into(), - None => good_panic!( - "Neither user nor sshUser set for profile `{}` of node `{}`", - profile_name, - node_name +impl<'a> DeployData<'a> { + pub fn defs(&'a self) -> DeployDefs<'a> { + let ssh_user: Cow = match self.merged_settings.ssh_user { + Some(ref u) => u.into(), + None => whoami::username().into(), + }; + + let profile_user: Cow = match self.merged_settings.user { + Some(ref x) => x.into(), + None => match self.merged_settings.ssh_user { + Some(ref x) => x.into(), + None => good_panic!( + "Neither user nor sshUser set for profile `{}` of node `{}`", + self.profile_name, + self.node_name + ), + }, + }; + + let profile_path = match &profile_user[..] { + "root" => format!("/nix/var/nix/profiles/{}", self.profile_name), + _ => format!( + "/nix/var/nix/profiles/per-user/{}/{}", + profile_user, self.profile_name ), - }, - }; + }; - let profile_path = match &profile_user[..] { - "root" => format!("/nix/var/nix/profiles/{}", profile_name), - _ => format!( - "/nix/var/nix/profiles/per-user/{}/{}", - profile_user, profile_name - ), - }; + let sudo: Option = match self.merged_settings.user { + Some(ref user) if user != &ssh_user => Some(format!("sudo -u {}", user)), + _ => None, + }; - let sudo: Option = match merged_settings.user { - Some(ref user) if user != &ssh_user => Some(format!("sudo -u {}", user)), - _ => None, - }; + let current_exe = + std::env::current_exe().expect("Expected to find current executable path"); + + if !current_exe.starts_with("/nix/store/") { + good_panic!("The deploy binary must be in the Nix store"); + } + + DeployDefs { + ssh_user, + profile_user, + profile_path, + current_exe, + sudo, + } + } +} - let current_exe = std::env::current_exe().expect("Expected to find current executable path"); +pub fn make_deploy_data<'a, 's>( + top_settings: &'s data::GenericSettings, + node: &'a data::Node, + node_name: &'a str, + profile: &'a data::Profile, + profile_name: &'a str, + cmd_overrides: &'a CmdOverrides, +) -> Result, Box> { + let mut merged_settings = top_settings.clone(); + merged_settings.merge(node.generic_settings.clone()); + merged_settings.merge(profile.generic_settings.clone()); - if !current_exe.starts_with("/nix/store/") { - good_panic!("The deploy binary must be in the Nix store"); + if cmd_overrides.ssh_user.is_some() { + merged_settings.ssh_user = cmd_overrides.ssh_user.clone(); + } + if cmd_overrides.profile_user.is_some() { + merged_settings.user = cmd_overrides.profile_user.clone(); + } + if let Some(ref ssh_opts) = cmd_overrides.ssh_opts { + merged_settings.ssh_opts = ssh_opts.split(' ').map(|x| x.to_owned()).collect(); + } + if let Some(fast_connection) = cmd_overrides.fast_connection { + merged_settings.fast_connection = fast_connection; + } + if let Some(auto_rollback) = cmd_overrides.auto_rollback { + merged_settings.auto_rollback = auto_rollback; } Ok(DeployData { - sudo, - ssh_user, - profile_user, - profile_path, - current_exe, + profile, + profile_name, + node, + node_name, + + cmd_overrides, + + merged_settings, }) } diff --git a/src/utils/push.rs b/src/utils/push.rs index 38a576f..9a6748e 100644 --- a/src/utils/push.rs +++ b/src/utils/push.rs @@ -2,30 +2,24 @@ // // SPDX-License-Identifier: MPL-2.0 -use super::data; - use std::process::Stdio; use tokio::process::Command; pub async fn push_profile( - profile: &data::Profile, - profile_name: &str, - node: &data::Node, - node_name: &str, supports_flakes: bool, check_sigs: bool, repo: &str, - merged_settings: &data::GenericSettings, deploy_data: &super::DeployData<'_>, + deploy_defs: &super::DeployDefs<'_>, ) -> Result<(), Box> { info!( "Pushing profile `{}` for node `{}`", - profile_name, node_name + deploy_data.profile_name, deploy_data.node_name ); debug!( "Building profile `{} for node `{}`", - profile_name, node_name + deploy_data.profile_name, deploy_data.node_name ); if supports_flakes { @@ -34,7 +28,7 @@ pub async fn push_profile( .arg("--no-link") .arg(format!( "{}#deploy.nodes.{}.profiles.{}.path", - repo, node_name, profile_name + repo, deploy_data.node_name, deploy_data.profile_name )) .stdout(Stdio::null()) .stderr(Stdio::null()) @@ -46,7 +40,7 @@ pub async fn push_profile( .arg("-A") .arg(format!( "deploy.nodes.{}.profiles.{}.path", - node_name, profile_name + deploy_data.node_name, deploy_data.profile_name )) .stdout(Stdio::null()) .stderr(Stdio::null()) @@ -57,7 +51,7 @@ pub async fn push_profile( if let Ok(local_key) = std::env::var("LOCAL_KEY") { info!( "Signing key present! Signing profile `{}` for node `{}`", - profile_name, node_name + deploy_data.profile_name, deploy_data.node_name ); Command::new("nix") @@ -65,9 +59,9 @@ pub async fn push_profile( .arg("-r") .arg("-k") .arg(local_key) - .arg(&profile.profile_settings.path) + .arg(&deploy_data.profile.profile_settings.path) .arg(&super::deploy_path_to_activate_path_str( - &deploy_data.current_exe, + &deploy_defs.current_exe, )?) .stdout(Stdio::null()) .stderr(Stdio::null()) @@ -75,12 +69,15 @@ pub async fn push_profile( .await?; } - debug!("Copying profile `{} for node `{}`", profile_name, node_name); + debug!( + "Copying profile `{} for node `{}`", + deploy_data.profile_name, deploy_data.node_name + ); let mut copy_command_ = Command::new("nix"); let mut copy_command = copy_command_.arg("copy"); - if merged_settings.fast_connection { + if deploy_data.merged_settings.fast_connection { copy_command = copy_command.arg("--substitute-on-destination"); } @@ -88,7 +85,8 @@ pub async fn push_profile( copy_command = copy_command.arg("--no-check-sigs"); } - let ssh_opts_str = merged_settings + let ssh_opts_str = deploy_data + .merged_settings .ssh_opts // This should provide some extra safety, but it also breaks for some reason, oh well // .iter() @@ -96,15 +94,17 @@ pub async fn push_profile( // .collect::>() .join(" "); + let hostname = match deploy_data.cmd_overrides.hostname { + Some(ref x) => x, + None => &deploy_data.node.node_settings.hostname, + }; + copy_command .arg("--to") - .arg(format!( - "ssh://{}@{}", - deploy_data.ssh_user, node.node_settings.hostname - )) - .arg(&profile.profile_settings.path) + .arg(format!("ssh://{}@{}", deploy_defs.ssh_user, hostname)) + .arg(&deploy_data.profile.profile_settings.path) .arg(&super::deploy_path_to_activate_path_str( - &deploy_data.current_exe, + &deploy_defs.current_exe, )?) .env("NIX_SSHOPTS", ssh_opts_str) .spawn()? -- 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/utils/deploy.rs | 6 +++++- src/utils/push.rs | 30 +++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 10 deletions(-) (limited to 'src/utils') diff --git a/src/utils/deploy.rs b/src/utils/deploy.rs index d46f2db..f1f4210 100644 --- a/src/utils/deploy.rs +++ b/src/utils/deploy.rs @@ -98,7 +98,11 @@ pub async fn deploy_profile( ssh_command = ssh_command.arg(ssh_opt); } - ssh_command.arg(self_activate_command).spawn()?.await?; + let ssh_exit_status = ssh_command.arg(self_activate_command).status().await?; + + if !ssh_exit_status.success() { + good_panic!("Activation over SSH failed"); + } Ok(()) } diff --git a/src/utils/push.rs b/src/utils/push.rs index 9a6748e..a973572 100644 --- a/src/utils/push.rs +++ b/src/utils/push.rs @@ -22,7 +22,7 @@ pub async fn push_profile( deploy_data.profile_name, deploy_data.node_name ); - if supports_flakes { + let build_exit_status = if supports_flakes { Command::new("nix") .arg("build") .arg("--no-link") @@ -32,8 +32,8 @@ pub async fn push_profile( )) .stdout(Stdio::null()) .stderr(Stdio::null()) - .spawn()? - .await?; + .status() + .await? } else { Command::new("nix-build") .arg(&repo) @@ -44,8 +44,12 @@ pub async fn push_profile( )) .stdout(Stdio::null()) .stderr(Stdio::null()) - .spawn()? - .await?; + .status() + .await? + }; + + if !build_exit_status.success() { + good_panic!("`nix build` failed"); } if let Ok(local_key) = std::env::var("LOCAL_KEY") { @@ -54,7 +58,7 @@ pub async fn push_profile( deploy_data.profile_name, deploy_data.node_name ); - Command::new("nix") + let sign_exit_status = Command::new("nix") .arg("sign-paths") .arg("-r") .arg("-k") @@ -65,8 +69,12 @@ pub async fn push_profile( )?) .stdout(Stdio::null()) .stderr(Stdio::null()) - .spawn()? + .status() .await?; + + if !sign_exit_status.success() { + good_panic!("`nix sign-paths` failed"); + } } debug!( @@ -99,7 +107,7 @@ pub async fn push_profile( None => &deploy_data.node.node_settings.hostname, }; - copy_command + let copy_exit_status = copy_command .arg("--to") .arg(format!("ssh://{}@{}", deploy_defs.ssh_user, hostname)) .arg(&deploy_data.profile.profile_settings.path) @@ -107,8 +115,12 @@ pub async fn push_profile( &deploy_defs.current_exe, )?) .env("NIX_SSHOPTS", ssh_opts_str) - .spawn()? + .status() .await?; + if !copy_exit_status.success() { + good_panic!("`nix copy` failed"); + } + Ok(()) } -- 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/utils/data.rs | 1 - src/utils/deploy.rs | 40 +++++++++++++++------------------------- src/utils/push.rs | 5 ----- 3 files changed, 15 insertions(+), 31 deletions(-) (limited to 'src/utils') diff --git a/src/utils/data.rs b/src/utils/data.rs index d1dae5b..de6adfc 100644 --- a/src/utils/data.rs +++ b/src/utils/data.rs @@ -34,7 +34,6 @@ pub struct NodeSettings { #[derive(Deserialize, Debug, Clone)] pub struct ProfileSettings { pub path: String, - pub activate: Option, pub bootstrap: Option, } diff --git a/src/utils/deploy.rs b/src/utils/deploy.rs index f1f4210..7301967 100644 --- a/src/utils/deploy.rs +++ b/src/utils/deploy.rs @@ -9,10 +9,9 @@ fn build_activate_command( sudo: &Option, profile_path: &str, closure: &str, - activate_cmd: &Option, bootstrap_cmd: &Option, auto_rollback: bool, -) -> Result> { +) -> String { let mut self_activate_command = format!("{} '{}' '{}'", activate_path_str, profile_path, closure); @@ -27,18 +26,11 @@ fn build_activate_command( ); } - if let Some(ref activate_cmd) = activate_cmd { - self_activate_command = format!( - "{} --activate-cmd '{}'", - self_activate_command, activate_cmd - ); - } - if auto_rollback { self_activate_command = format!("{} --auto-rollback", self_activate_command); } - Ok(self_activate_command) + self_activate_command } #[test] @@ -47,22 +39,21 @@ fn test_activation_command_builder() { let sudo = Some("sudo -u test".to_string()); let profile_path = "/blah/profiles/test"; let closure = "/blah/etc"; - let activate_cmd = Some("$THING/bin/aaaaaaa".to_string()); let bootstrap_cmd = None; let auto_rollback = true; - match build_activate_command( - activate_path_str, - &sudo, - profile_path, - closure, - &activate_cmd, - &bootstrap_cmd, - auto_rollback, - ) { - Err(_) => panic!(""), - Ok(x) => assert_eq!(x, "sudo -u test /blah/bin/activate '/blah/profiles/test' '/blah/etc' --activate-cmd '$THING/bin/aaaaaaa' --auto-rollback".to_string()), - } + assert_eq!( + build_activate_command( + activate_path_str, + &sudo, + profile_path, + closure, + &bootstrap_cmd, + auto_rollback, + ), + "sudo -u test /blah/bin/activate '/blah/profiles/test' '/blah/etc' --auto-rollback" + .to_string(), + ); } pub async fn deploy_profile( @@ -81,10 +72,9 @@ pub async fn deploy_profile( &deploy_defs.sudo, &deploy_defs.profile_path, &deploy_data.profile.profile_settings.path, - &deploy_data.profile.profile_settings.activate, &deploy_data.profile.profile_settings.bootstrap, deploy_data.merged_settings.auto_rollback, - )?; + ); let hostname = match deploy_data.cmd_overrides.hostname { Some(ref x) => x, diff --git a/src/utils/push.rs b/src/utils/push.rs index a973572..3f48d68 100644 --- a/src/utils/push.rs +++ b/src/utils/push.rs @@ -17,11 +17,6 @@ pub async fn push_profile( deploy_data.profile_name, deploy_data.node_name ); - debug!( - "Building profile `{} for node `{}`", - deploy_data.profile_name, deploy_data.node_name - ); - let build_exit_status = if supports_flakes { Command::new("nix") .arg("build") -- cgit v1.2.3 From aabcf6b77d4159100a49b143cbb8da4bad194f14 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Mon, 5 Oct 2020 20:10:41 -0700 Subject: Improve schema a bit, fix flake locks for examples --- src/utils/data.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src/utils') diff --git a/src/utils/data.rs b/src/utils/data.rs index de6adfc..371c82d 100644 --- a/src/utils/data.rs +++ b/src/utils/data.rs @@ -29,6 +29,13 @@ pub struct GenericSettings { #[derive(Deserialize, Debug, Clone)] pub struct NodeSettings { pub hostname: String, + pub profiles: HashMap, + #[serde( + skip_serializing_if = "Vec::is_empty", + default, + rename(deserialize = "profilesOrder") + )] + pub profiles_order: Vec, } #[derive(Deserialize, Debug, Clone)] @@ -51,14 +58,6 @@ pub struct Node { pub generic_settings: GenericSettings, #[serde(flatten)] pub node_settings: NodeSettings, - - pub profiles: HashMap, - #[serde( - skip_serializing_if = "Vec::is_empty", - default, - rename(deserialize = "profilesOrder") - )] - pub profiles_order: Vec, } #[derive(Deserialize, Debug, Clone)] -- cgit v1.2.3 From 518f7f5b4f1db83cab61941ab8887b0df76ce8d8 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Thu, 8 Oct 2020 18:13:26 -0700 Subject: Update documentation --- src/utils/mod.rs | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'src/utils') diff --git a/src/utils/mod.rs b/src/utils/mod.rs index bfdbc5e..97e4550 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -28,31 +28,6 @@ pub struct CmdOverrides { pub hostname: Option, } -pub enum OverridePurity { - ErrorProfile, - Error, - Warn, - Pure, -} - -impl CmdOverrides { - pub fn purity(&self) -> OverridePurity { - if self.profile_user.is_some() { - return OverridePurity::ErrorProfile; - } - - if self.hostname.is_some() || self.ssh_user.is_some() { - return OverridePurity::Error; - } - - if self.ssh_opts.is_some() || self.fast_connection.is_some() { - return OverridePurity::Warn; - } - - OverridePurity::Pure - } -} - #[derive(PartialEq, Debug)] pub struct DeployFlake<'a> { pub repo: &'a str, -- cgit v1.2.3 From db8301a45796cd919cbfa085f85ac6288e73a8db Mon Sep 17 00:00:00 2001 From: notgne2 Date: Sat, 10 Oct 2020 10:31:55 -0700 Subject: Add profile path option to profiles --- src/utils/data.rs | 2 ++ src/utils/mod.rs | 18 +++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'src/utils') diff --git a/src/utils/data.rs b/src/utils/data.rs index 371c82d..f72f9a7 100644 --- a/src/utils/data.rs +++ b/src/utils/data.rs @@ -42,6 +42,8 @@ pub struct NodeSettings { pub struct ProfileSettings { pub path: String, pub bootstrap: Option, + #[serde(rename(deserialize = "profilePath"))] + pub profile_path: Option, } #[derive(Deserialize, Debug, Clone)] diff --git a/src/utils/mod.rs b/src/utils/mod.rs index bfdbc5e..51f977f 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -129,7 +129,7 @@ pub struct DeployData<'a> { pub struct DeployDefs<'a> { pub ssh_user: Cow<'a, str>, pub profile_user: Cow<'a, str>, - pub profile_path: String, + pub profile_path: Cow<'a, str>, pub current_exe: PathBuf, pub sudo: Option, } @@ -153,12 +153,16 @@ impl<'a> DeployData<'a> { }, }; - let profile_path = match &profile_user[..] { - "root" => format!("/nix/var/nix/profiles/{}", self.profile_name), - _ => format!( - "/nix/var/nix/profiles/per-user/{}/{}", - profile_user, self.profile_name - ), + let profile_path: Cow = match self.profile.profile_settings.profile_path { + None => match &profile_user[..] { + "root" => format!("/nix/var/nix/profiles/{}", self.profile_name).into(), + _ => format!( + "/nix/var/nix/profiles/per-user/{}/{}", + profile_user, self.profile_name + ) + .into(), + }, + Some(ref x) => x.into(), }; let sudo: Option = match self.merged_settings.user { -- 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/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 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/utils/data.rs | 16 +++++----- src/utils/deploy.rs | 84 +++++++++++++++++++++++++++++++---------------------- src/utils/mod.rs | 10 +++++-- src/utils/push.rs | 2 +- 4 files changed, 67 insertions(+), 45 deletions(-) (limited to 'src/utils') diff --git a/src/utils/data.rs b/src/utils/data.rs index 351b9ae..5c58e3b 100644 --- a/src/utils/data.rs +++ b/src/utils/data.rs @@ -19,11 +19,15 @@ pub struct GenericSettings { #[merge(strategy = merge::vec::append)] pub ssh_opts: Vec, #[serde(rename(deserialize = "fastConnection"), default)] - #[merge(strategy = merge::bool::overwrite_false)] - pub fast_connection: bool, + pub fast_connection: Option, #[serde(rename(deserialize = "autoRollback"), default)] - #[merge(strategy = merge::bool::overwrite_false)] - pub auto_rollback: bool, + pub auto_rollback: Option, + #[serde(rename(deserialize = "confirmTimeout"))] + pub confirm_timeout: Option, + #[serde(rename(deserialize = "tempPath"))] + pub temp_path: Option, + #[serde(rename(deserialize = "magicRollback"))] + pub magic_rollback: Option, } #[derive(Deserialize, Debug, Clone)] @@ -44,10 +48,6 @@ 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 e3493ba..9b2f685 100644 --- a/src/utils/deploy.rs +++ b/src/utils/deploy.rs @@ -13,15 +13,20 @@ fn build_activate_command( bootstrap_cmd: &Option, auto_rollback: bool, temp_path: &Cow, - max_time: u16, + confirm_timeout: u16, + magic_rollback: bool, ) -> String { let mut self_activate_command = format!( - "{} '{}' '{}' {} {}", - activate_path_str, profile_path, closure, temp_path, max_time + "{} '{}' '{}' --temp-path {} --confirm-timeout {}", + activate_path_str, profile_path, closure, temp_path, confirm_timeout ); - if let Some(sudo_cmd) = &sudo { - self_activate_command = format!("{} {}", sudo_cmd, self_activate_command); + if magic_rollback { + self_activate_command = format!("{} --magic-rollback", self_activate_command); + } + + if auto_rollback { + self_activate_command = format!("{} --auto-rollback", self_activate_command); } if let Some(ref bootstrap_cmd) = bootstrap_cmd { @@ -31,8 +36,8 @@ fn build_activate_command( ); } - if auto_rollback { - self_activate_command = format!("{} --auto-rollback", self_activate_command); + if let Some(sudo_cmd) = &sudo { + self_activate_command = format!("{} {}", sudo_cmd, self_activate_command); } self_activate_command @@ -47,7 +52,8 @@ fn test_activation_command_builder() { let bootstrap_cmd = None; let auto_rollback = true; let temp_path = &"/tmp/deploy-rs".into(); - let max_time = 30; + let confirm_timeout = 30; + let magic_rollback = true; assert_eq!( build_activate_command( @@ -58,9 +64,10 @@ fn test_activation_command_builder() { &bootstrap_cmd, auto_rollback, temp_path, - max_time + confirm_timeout, + magic_rollback ), - "sudo -u test /blah/bin/activate '/blah/profiles/test' '/blah/etc' /tmp/deploy-rs 30 --auto-rollback" + "sudo -u test /blah/bin/activate '/blah/profiles/test' '/blah/etc' --temp-path /tmp/deploy-rs --confirm-timeout 30 --magic-rollback --auto-rollback" .to_string(), ); } @@ -76,12 +83,16 @@ 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 { + let temp_path: Cow = match &deploy_data.merged_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 confirm_timeout = deploy_data.merged_settings.confirm_timeout.unwrap_or(30); + + let magic_rollback = deploy_data.merged_settings.magic_rollback.unwrap_or(false); + + let auto_rollback = deploy_data.merged_settings.auto_rollback.unwrap_or(true); let self_activate_command = build_activate_command( activate_path_str, @@ -89,9 +100,10 @@ pub async fn deploy_profile( &deploy_defs.profile_path, &deploy_data.profile.profile_settings.path, &deploy_data.profile.profile_settings.bootstrap, - deploy_data.merged_settings.auto_rollback, + auto_rollback, &temp_path, - max_time, + confirm_timeout, + magic_rollback, ); let hostname = match deploy_data.cmd_overrides.hostname { @@ -112,33 +124,37 @@ pub async fn deploy_profile( good_panic!("Activation over SSH failed"); } - info!("Success, attempting to connect to the node to confirm deployment"); + info!("Success activating!"); - let mut c = Command::new("ssh"); - let mut ssh_confirm_command = c.arg(format!("ssh://{}@{}", deploy_defs.ssh_user, hostname)); + if magic_rollback { + info!("Attempting to confirm activation"); - for ssh_opt in &deploy_data.merged_settings.ssh_opts { - ssh_confirm_command = ssh_confirm_command.arg(ssh_opt); - } + let mut c = Command::new("ssh"); + let mut ssh_confirm_command = c.arg(format!("ssh://{}@{}", deploy_defs.ssh_user, hostname)); - let lock_hash = &deploy_data.profile.profile_settings.path[11 /* /nix/store/ */ ..]; - let lock_path = format!("{}/activating-{}", temp_path, lock_hash); + for ssh_opt in &deploy_data.merged_settings.ssh_opts { + ssh_confirm_command = ssh_confirm_command.arg(ssh_opt); + } - let mut confirm_command = format!("rm {}", lock_path); - if let Some(sudo_cmd) = &deploy_defs.sudo { - confirm_command = format!("{} {}", sudo_cmd, confirm_command); - } + let lock_hash = &deploy_data.profile.profile_settings.path[11 /* /nix/store/ */ ..]; + let lock_path = format!("{}/activating-{}", temp_path, lock_hash); - let ssh_exit_status = ssh_confirm_command.arg(confirm_command).status().await?; + let mut confirm_command = format!("rm {}", lock_path); + if let Some(sudo_cmd) = &deploy_defs.sudo { + confirm_command = format!("{} {}", sudo_cmd, confirm_command); + } - if !ssh_exit_status.success() { - good_panic!( - "Failed to confirm deployment, the node will roll back in <{} seconds", - max_time - ); - } + let ssh_exit_status = ssh_confirm_command.arg(confirm_command).status().await?; - info!("Deployment confirmed."); + if !ssh_exit_status.success() { + good_panic!( + "Failed to confirm deployment, the node will roll back in <{} seconds", + confirm_timeout + ); + } + + info!("Deployment confirmed."); + } Ok(()) } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 672a9ba..a0e62e1 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -26,6 +26,9 @@ pub struct CmdOverrides { pub fast_connection: Option, pub auto_rollback: Option, pub hostname: Option, + pub magic_rollback: Option, + pub temp_path: Option, + pub confirm_timeout: Option, } #[derive(PartialEq, Debug)] @@ -184,10 +187,13 @@ pub fn make_deploy_data<'a, 's>( merged_settings.ssh_opts = ssh_opts.split(' ').map(|x| x.to_owned()).collect(); } if let Some(fast_connection) = cmd_overrides.fast_connection { - merged_settings.fast_connection = fast_connection; + merged_settings.fast_connection = Some(fast_connection); } if let Some(auto_rollback) = cmd_overrides.auto_rollback { - merged_settings.auto_rollback = auto_rollback; + merged_settings.auto_rollback = Some(auto_rollback); + } + if let Some(magic_rollback) = cmd_overrides.magic_rollback { + merged_settings.magic_rollback = Some(magic_rollback); } Ok(DeployData { diff --git a/src/utils/push.rs b/src/utils/push.rs index 3f48d68..f80f9f8 100644 --- a/src/utils/push.rs +++ b/src/utils/push.rs @@ -80,7 +80,7 @@ pub async fn push_profile( let mut copy_command_ = Command::new("nix"); let mut copy_command = copy_command_.arg("copy"); - if deploy_data.merged_settings.fast_connection { + if let Some(true) = deploy_data.merged_settings.fast_connection { copy_command = copy_command.arg("--substitute-on-destination"); } -- cgit v1.2.3 From 48d1e48429d72b50c72282e47a68be130ea506ad Mon Sep 17 00:00:00 2001 From: notgne2 Date: Fri, 23 Oct 2020 15:06:14 -0700 Subject: Remove redundant default --- src/utils/data.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/utils') diff --git a/src/utils/data.rs b/src/utils/data.rs index 5c58e3b..6cf2c5a 100644 --- a/src/utils/data.rs +++ b/src/utils/data.rs @@ -18,9 +18,9 @@ pub struct GenericSettings { )] #[merge(strategy = merge::vec::append)] pub ssh_opts: Vec, - #[serde(rename(deserialize = "fastConnection"), default)] + #[serde(rename(deserialize = "fastConnection"))] pub fast_connection: Option, - #[serde(rename(deserialize = "autoRollback"), default)] + #[serde(rename(deserialize = "autoRollback"))] pub auto_rollback: Option, #[serde(rename(deserialize = "confirmTimeout"))] pub confirm_timeout: Option, -- cgit v1.2.3 From c55471f1a52fc7cb4c467a3c9718640cdb950a22 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Fri, 23 Oct 2020 22:03:15 -0700 Subject: Fix log messages, prevent non-flake builds writing to result, unmute stderr on nix builds --- src/utils/push.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/utils') diff --git a/src/utils/push.rs b/src/utils/push.rs index f80f9f8..a82c9d4 100644 --- a/src/utils/push.rs +++ b/src/utils/push.rs @@ -13,7 +13,7 @@ pub async fn push_profile( deploy_defs: &super::DeployDefs<'_>, ) -> Result<(), Box> { info!( - "Pushing profile `{}` for node `{}`", + "Building profile `{}` for node `{}`", deploy_data.profile_name, deploy_data.node_name ); @@ -26,19 +26,18 @@ pub async fn push_profile( repo, deploy_data.node_name, deploy_data.profile_name )) .stdout(Stdio::null()) - .stderr(Stdio::null()) .status() .await? } else { Command::new("nix-build") .arg(&repo) + .arg("--no-out-link") .arg("-A") .arg(format!( "deploy.nodes.{}.profiles.{}.path", deploy_data.node_name, deploy_data.profile_name )) .stdout(Stdio::null()) - .stderr(Stdio::null()) .status() .await? }; @@ -73,7 +72,7 @@ pub async fn push_profile( } debug!( - "Copying profile `{} for node `{}`", + "Copying profile `{}` to node `{}`", deploy_data.profile_name, deploy_data.node_name ); -- cgit v1.2.3 From 4084e0516d3903acd80ca465f9906e5d3bce2659 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Fri, 23 Oct 2020 22:14:14 -0700 Subject: Enable color for activation command --- src/utils/deploy.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/utils') diff --git a/src/utils/deploy.rs b/src/utils/deploy.rs index 9b2f685..1ef7f11 100644 --- a/src/utils/deploy.rs +++ b/src/utils/deploy.rs @@ -112,7 +112,9 @@ pub async fn deploy_profile( }; let mut c = Command::new("ssh"); - let mut ssh_command = c.arg(format!("ssh://{}@{}", deploy_defs.ssh_user, hostname)); + let mut ssh_command = c + .arg("-t") + .arg(format!("ssh://{}@{}", deploy_defs.ssh_user, hostname)); for ssh_opt in &deploy_data.merged_settings.ssh_opts { ssh_command = ssh_command.arg(ssh_opt); -- cgit v1.2.3 From 72b066b293befec048f6a1b2f8d7a4b103ae4edf Mon Sep 17 00:00:00 2001 From: notgne2 Date: Fri, 23 Oct 2020 22:44:52 -0700 Subject: Add an option to keep build results --- src/utils/push.rs | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) (limited to 'src/utils') diff --git a/src/utils/push.rs b/src/utils/push.rs index a82c9d4..5e87d5c 100644 --- a/src/utils/push.rs +++ b/src/utils/push.rs @@ -11,25 +11,27 @@ pub async fn push_profile( repo: &str, deploy_data: &super::DeployData<'_>, deploy_defs: &super::DeployDefs<'_>, + keep_result: bool, + result_path: Option<&str>, ) -> Result<(), Box> { info!( "Building profile `{}` for node `{}`", deploy_data.profile_name, deploy_data.node_name ); - let build_exit_status = if supports_flakes { + let mut build_c = if supports_flakes { Command::new("nix") - .arg("build") - .arg("--no-link") - .arg(format!( - "{}#deploy.nodes.{}.profiles.{}.path", - repo, deploy_data.node_name, deploy_data.profile_name - )) - .stdout(Stdio::null()) - .status() - .await? } else { Command::new("nix-build") + }; + + let mut build_command = if supports_flakes { + build_c.arg("build").arg("--no-link").arg(format!( + "{}#deploy.nodes.{}.profiles.{}.path", + repo, deploy_data.node_name, deploy_data.profile_name + )) + } else { + build_c .arg(&repo) .arg("--no-out-link") .arg("-A") @@ -37,11 +39,26 @@ pub async fn push_profile( "deploy.nodes.{}.profiles.{}.path", deploy_data.node_name, deploy_data.profile_name )) - .stdout(Stdio::null()) - .status() - .await? }; + build_command = match (keep_result, supports_flakes) { + (true, _) => { + let result_path = match result_path { + Some(x) => x, + None => "./.deploy-gc", + }; + + build_command.arg("--out-link").arg(format!( + "{}/{}/{}", + result_path, deploy_data.node_name, deploy_data.profile_name + )) + } + (false, false) => build_command.arg("--no-out-link"), + (false, true) => build_command.arg("--no-link"), + }; + + let build_exit_status = build_command.stdout(Stdio::null()).status().await?; + if !build_exit_status.success() { good_panic!("`nix build` failed"); } -- cgit v1.2.3 From df002c31a64409350a3cb8825364542c65a4d00a Mon Sep 17 00:00:00 2001 From: notgne2 Date: Mon, 26 Oct 2020 12:44:19 -0700 Subject: Add more debug logs --- src/utils/deploy.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/utils') diff --git a/src/utils/deploy.rs b/src/utils/deploy.rs index 1ef7f11..59217df 100644 --- a/src/utils/deploy.rs +++ b/src/utils/deploy.rs @@ -106,6 +106,8 @@ pub async fn deploy_profile( magic_rollback, ); + debug!("Constructed activation command: {}", self_activate_command); + let hostname = match deploy_data.cmd_overrides.hostname { Some(ref x) => x, None => &deploy_data.node.node_settings.hostname, @@ -146,6 +148,11 @@ pub async fn deploy_profile( confirm_command = format!("{} {}", sudo_cmd, confirm_command); } + debug!( + "Attempting to run command to confirm deployment: {}", + confirm_command + ); + let ssh_exit_status = ssh_confirm_command.arg(confirm_command).status().await?; if !ssh_exit_status.success() { -- cgit v1.2.3