diff options
author | notgne2 | 2020-10-29 19:33:53 -0700 |
---|---|---|
committer | notgne2 | 2020-10-29 19:33:53 -0700 |
commit | ca86bab9e9e8a0e60cec6793147abaec44a0ea8f (patch) | |
tree | 30a834cf9b22fdffbbf52e1d778b9712357222e0 /src/utils | |
parent | d7f0006df0e3c14a9387f5bd3e3e3acd0b39fda8 (diff) |
Make all the errors work correctly (I am so so sorry)
Diffstat (limited to '')
-rw-r--r-- | src/utils/deploy.rs | 49 | ||||
-rw-r--r-- | src/utils/mod.rs | 53 | ||||
-rw-r--r-- | src/utils/push.rs | 55 |
3 files changed, 116 insertions, 41 deletions
diff --git a/src/utils/deploy.rs b/src/utils/deploy.rs index 8ed7d8c..f395a3a 100644 --- a/src/utils/deploy.rs +++ b/src/utils/deploy.rs @@ -5,6 +5,8 @@ use std::borrow::Cow; use tokio::process::Command; +use thiserror::Error; + fn build_activate_command( activate_path_str: String, sudo: &Option<String>, @@ -72,10 +74,26 @@ fn test_activation_command_builder() { ); } +#[derive(Error, Debug)] +pub enum DeployProfileError { + #[error("Failed to calculate activate bin path from deploy bin path: {0}")] + DeployPathToActivatePathError(#[from] super::DeployPathToActivatePathError), + #[error("Failed to run activation command over SSH: {0}")] + SSHActivateError(std::io::Error), + #[error("Activation over SSH resulted in a bad exit code: {0:?}")] + SSHActivateExitError(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>), +} + pub async fn deploy_profile( deploy_data: &super::DeployData<'_>, deploy_defs: &super::DeployDefs<'_>, -) -> Result<(), Box<dyn std::error::Error>> { +) -> Result<(), DeployProfileError> { info!( "Activating profile `{}` for node `{}`", deploy_data.profile_name, deploy_data.node_name @@ -122,11 +140,16 @@ pub async fn deploy_profile( ssh_command = ssh_command.arg(ssh_opt); } - let ssh_exit_status = ssh_command.arg(self_activate_command).status().await?; + let ssh_exit_status = ssh_command + .arg(self_activate_command) + .status() + .await + .map_err(DeployProfileError::SSHActivateError)?; - if !ssh_exit_status.success() { - good_panic!("Activation over SSH failed"); - } + match ssh_exit_status.code() { + Some(0) => (), + a => return Err(DeployProfileError::SSHActivateExitError(a)), + }; info!("Success activating!"); @@ -153,14 +176,16 @@ pub async fn deploy_profile( confirm_command ); - let ssh_exit_status = ssh_confirm_command.arg(confirm_command).status().await?; + let ssh_exit_status = ssh_confirm_command + .arg(confirm_command) + .status() + .await + .map_err(DeployProfileError::SSHConfirmError)?; - if !ssh_exit_status.success() { - good_panic!( - "Failed to confirm deployment, the node will roll back in <{} seconds", - confirm_timeout - ); - } + match ssh_exit_status.code() { + Some(0) => (), + a => return Err(DeployProfileError::SSHConfirmExitError(a)), + }; info!("Deployment confirmed."); } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index a0e62e1..19d0948 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -7,6 +7,8 @@ use std::path::PathBuf; use merge::Merge; +use thiserror::Error; + #[macro_export] macro_rules! good_panic { ($($tts:tt)*) => {{ @@ -112,8 +114,18 @@ pub struct DeployDefs<'a> { pub sudo: Option<String>, } +#[derive(Error, Debug)] +pub enum DeployDataDefsError { + #[error("Neither `user` nor `sshUser` are set for profile {0} of node {1}")] + NoProfileUser(String, String), + #[error("Error reading current executable path: {0}")] + ExecutablePathNotFound(std::io::Error), + #[error("Executable was not in the Nix store")] + NotNixStored, +} + impl<'a> DeployData<'a> { - pub fn defs(&'a self) -> DeployDefs<'a> { + pub fn defs(&'a self) -> Result<DeployDefs<'a>, DeployDataDefsError> { let ssh_user: Cow<str> = match self.merged_settings.ssh_user { Some(ref u) => u.into(), None => whoami::username().into(), @@ -123,11 +135,12 @@ impl<'a> DeployData<'a> { 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 - ), + None => { + return Err(DeployDataDefsError::NoProfileUser( + self.profile_name.to_owned(), + self.node_name.to_owned(), + )) + } }, }; @@ -149,19 +162,19 @@ impl<'a> DeployData<'a> { }; let current_exe = - std::env::current_exe().expect("Expected to find current executable path"); + std::env::current_exe().map_err(DeployDataDefsError::ExecutablePathNotFound)?; if !current_exe.starts_with("/nix/store/") { - good_panic!("The deploy binary must be in the Nix store"); + return Err(DeployDataDefsError::NotNixStored); } - DeployDefs { + Ok(DeployDefs { ssh_user, profile_user, profile_path, current_exe, sudo, - } + }) } } @@ -172,7 +185,7 @@ pub fn make_deploy_data<'a, 's>( profile: &'a data::Profile, profile_name: &'a str, cmd_overrides: &'a CmdOverrides, -) -> Result<DeployData<'a>, Box<dyn std::error::Error>> { +) -> DeployData<'a> { let mut merged_settings = top_settings.clone(); merged_settings.merge(node.generic_settings.clone()); merged_settings.merge(profile.generic_settings.clone()); @@ -196,7 +209,7 @@ pub fn make_deploy_data<'a, 's>( merged_settings.magic_rollback = Some(magic_rollback); } - Ok(DeployData { + DeployData { profile, profile_name, node, @@ -205,19 +218,27 @@ pub fn make_deploy_data<'a, 's>( cmd_overrides, merged_settings, - }) + } +} + +#[derive(Error, Debug)] +pub enum DeployPathToActivatePathError { + #[error("Deploy path did not have a parent directory")] + PathTooShort, + #[error("Deploy path was not valid utf8")] + InvalidUtf8, } pub fn deploy_path_to_activate_path_str( deploy_path: &std::path::Path, -) -> Result<String, Box<dyn std::error::Error>> { +) -> Result<String, DeployPathToActivatePathError> { Ok(format!( "{}/activate", deploy_path .parent() - .ok_or("Deploy path too short")? + .ok_or(DeployPathToActivatePathError::PathTooShort)? .to_str() - .ok_or("Deploy path is not valid utf8")? + .ok_or(DeployPathToActivatePathError::InvalidUtf8)? .to_owned() )) } diff --git a/src/utils/push.rs b/src/utils/push.rs index 5e87d5c..c79a004 100644 --- a/src/utils/push.rs +++ b/src/utils/push.rs @@ -5,6 +5,26 @@ use std::process::Stdio; use tokio::process::Command; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum PushProfileError { + #[error("Failed to calculate activate bin path from deploy bin path: {0}")] + DeployPathToActivatePathError(#[from] super::DeployPathToActivatePathError), + #[error("Failed to run Nix build command: {0}")] + BuildError(std::io::Error), + #[error("Nix build command resulted in a bad exit code: {0:?}")] + BuildExitError(Option<i32>), + #[error("Failed to run Nix sign command: {0}")] + SignError(std::io::Error), + #[error("Nix sign command resulted in a bad exit code: {0:?}")] + SignExitError(Option<i32>), + #[error("Failed to run Nix copy command: {0}")] + CopyError(std::io::Error), + #[error("Nix copy command resulted in a bad exit code: {0:?}")] + CopyExitError(Option<i32>), +} + pub async fn push_profile( supports_flakes: bool, check_sigs: bool, @@ -13,7 +33,7 @@ pub async fn push_profile( deploy_defs: &super::DeployDefs<'_>, keep_result: bool, result_path: Option<&str>, -) -> Result<(), Box<dyn std::error::Error>> { +) -> Result<(), PushProfileError> { info!( "Building profile `{}` for node `{}`", deploy_data.profile_name, deploy_data.node_name @@ -57,11 +77,16 @@ pub async fn push_profile( (false, true) => build_command.arg("--no-link"), }; - let build_exit_status = build_command.stdout(Stdio::null()).status().await?; + let build_exit_status = build_command + .stdout(Stdio::null()) + .status() + .await + .map_err(PushProfileError::BuildError)?; - if !build_exit_status.success() { - good_panic!("`nix build` failed"); - } + match build_exit_status.code() { + Some(0) => (), + a => return Err(PushProfileError::BuildExitError(a)), + }; if let Ok(local_key) = std::env::var("LOCAL_KEY") { info!( @@ -81,11 +106,13 @@ pub async fn push_profile( .stdout(Stdio::null()) .stderr(Stdio::null()) .status() - .await?; + .await + .map_err(PushProfileError::SignError)?; - if !sign_exit_status.success() { - good_panic!("`nix sign-paths` failed"); - } + match sign_exit_status.code() { + Some(0) => (), + a => return Err(PushProfileError::SignExitError(a)), + }; } debug!( @@ -127,11 +154,13 @@ pub async fn push_profile( )?) .env("NIX_SSHOPTS", ssh_opts_str) .status() - .await?; + .await + .map_err(PushProfileError::CopyError)?; - if !copy_exit_status.success() { - good_panic!("`nix copy` failed"); - } + match copy_exit_status.code() { + Some(0) => (), + a => return Err(PushProfileError::CopyExitError(a)), + }; Ok(()) } |