From 46ac71aa245549965a3d9dfdabf6421b39f62289 Mon Sep 17 00:00:00 2001 From: Oleg Pykhalov Date: Wed, 31 Mar 2021 13:14:10 +0300 Subject: Add dry activate argument. --- flake.nix | 6 +++- src/bin/activate.rs | 95 ++++++++++++++++++++++++++++++----------------------- src/bin/deploy.rs | 8 ++++- src/deploy.rs | 29 ++++++++++++---- src/lib.rs | 1 + 5 files changed, 88 insertions(+), 51 deletions(-) diff --git a/flake.nix b/flake.nix index d87702f..75ea2b7 100644 --- a/flake.nix +++ b/flake.nix @@ -90,7 +90,11 @@ # work around https://github.com/NixOS/nixpkgs/issues/73404 cd /tmp - $PROFILE/bin/switch-to-configuration switch + if [[ $DRY_ACTIVATE == "1" ]]; then + $PROFILE/bin/switch-to-configuration dry-activate + else + $PROFILE/bin/switch-to-configuration switch + fi # https://github.com/serokell/deploy-rs/issues/31 ${with base.config.boot.loader; diff --git a/src/bin/activate.rs b/src/bin/activate.rs index 947e883..73d064f 100644 --- a/src/bin/activate.rs +++ b/src/bin/activate.rs @@ -66,6 +66,10 @@ struct ActivateOpts { /// Auto rollback if failure #[clap(long)] auto_rollback: bool, + + /// Show what will be activated on the machines + #[clap(long)] + dry_activate: bool, } /// Activate a profile @@ -348,70 +352,76 @@ pub async fn activate( temp_path: String, confirm_timeout: u16, magic_rollback: bool, + dry_activate: bool, ) -> Result<(), ActivateError> { - info!("Activating profile"); - - let nix_env_set_exit_status = Command::new("nix-env") - .arg("-p") - .arg(&profile_path) - .arg("--set") - .arg(&closure) - .status() - .await - .map_err(ActivateError::SetProfileError)?; - - match nix_env_set_exit_status.code() { - Some(0) => (), - a => { - if auto_rollback { - deactivate(&profile_path).await?; + if !dry_activate { + info!("Activating profile"); + let nix_env_set_exit_status = Command::new("nix-env") + .arg("-p") + .arg(&profile_path) + .arg("--set") + .arg(&closure) + .status() + .await + .map_err(ActivateError::SetProfileError)?; + match nix_env_set_exit_status.code() { + Some(0) => (), + a => { + if auto_rollback && !dry_activate { + deactivate(&profile_path).await?; + } + return Err(ActivateError::SetProfileExitError(a)); } - return Err(ActivateError::SetProfileExitError(a)); - } - }; + }; + } debug!("Running activation script"); let activate_status = match Command::new(format!("{}/deploy-rs-activate", profile_path)) - .env("PROFILE", &profile_path) - .current_dir(&profile_path) + .env("PROFILE", &closure) + .env("DRY_ACTIVATE", if dry_activate { "1" } else { "0" }) + .current_dir(&closure) .status() .await .map_err(ActivateError::RunActivateError) { Ok(x) => x, Err(e) => { - if auto_rollback { + if auto_rollback && !dry_activate { deactivate(&profile_path).await?; } return Err(e); } }; - match activate_status.code() { - Some(0) => (), - a => { - if auto_rollback { - deactivate(&profile_path).await?; + if !dry_activate { + match activate_status.code() { + Some(0) => (), + a => { + if auto_rollback { + deactivate(&profile_path).await?; + } + return Err(ActivateError::RunActivateExitError(a)); } - return Err(ActivateError::RunActivateExitError(a)); - } - }; + }; - info!("Activation succeeded!"); + if !dry_activate { + info!("Activation succeeded!"); + } - if magic_rollback { - info!("Magic rollback is enabled, setting up confirmation hook..."); + if magic_rollback { + info!("Magic rollback is enabled, setting up confirmation hook..."); - match activation_confirmation(profile_path.clone(), temp_path, confirm_timeout, closure) - .await - { - Ok(()) => {} - Err(err) => { - deactivate(&profile_path).await?; - return Err(ActivateError::ActivationConfirmationError(err)); - } - }; + match activation_confirmation(profile_path.clone(), temp_path, confirm_timeout, closure) + .await + { + Ok(()) => {} + Err(err) => { + deactivate(&profile_path).await?; + return Err(ActivateError::ActivationConfirmationError(err)); + } + }; + } } Ok(()) @@ -446,6 +456,7 @@ async fn main() -> Result<(), Box> { opts.temp_path, activate_opts.confirm_timeout, activate_opts.magic_rollback, + activate_opts.dry_activate, ) .await .map_err(|x| Box::new(x) as Box), diff --git a/src/bin/deploy.rs b/src/bin/deploy.rs index 9c41d25..10e0552 100644 --- a/src/bin/deploy.rs +++ b/src/bin/deploy.rs @@ -74,6 +74,9 @@ struct Opts { /// Where to store temporary files (only used by magic-rollback) #[clap(long)] temp_path: Option, + /// Show what will be activated on the machines + #[clap(long)] + dry_activate: bool, } /// Returns if the available Nix installation supports flakes @@ -379,6 +382,7 @@ async fn run_deploy( extra_build_args: &[String], debug_logs: bool, log_dir: Option, + dry_activate: bool, ) -> Result<(), RunDeployError> { let to_deploy: ToDeploy = match (&deploy_flake.node, &deploy_flake.profile) { (Some(node_name), Some(profile_name)) => { @@ -499,7 +503,7 @@ async fn run_deploy( } for (deploy_data, deploy_defs) in &parts { - deploy::deploy::deploy_profile(&deploy_data, &deploy_defs).await?; + deploy::deploy::deploy_profile(&deploy_data, &deploy_defs, dry_activate).await?; } Ok(()) @@ -546,6 +550,7 @@ async fn run() -> Result<(), RunError> { magic_rollback: opts.magic_rollback, temp_path: opts.temp_path, confirm_timeout: opts.confirm_timeout, + dry_activate: opts.dry_activate, }; let supports_flakes = test_flake_support().await.map_err(RunError::FlakeTest)?; @@ -574,6 +579,7 @@ async fn run() -> Result<(), RunError> { &opts.extra_build_args, opts.debug_logs, opts.log_dir, + opts.dry_activate, ) .await?; diff --git a/src/deploy.rs b/src/deploy.rs index f6871d2..f6cd4ef 100644 --- a/src/deploy.rs +++ b/src/deploy.rs @@ -18,6 +18,7 @@ struct ActivateCommandData<'a> { magic_rollback: bool, debug_logs: bool, log_dir: Option<&'a str>, + dry_activate: bool, } fn build_activate_command(data: ActivateCommandData) -> String { @@ -49,6 +50,10 @@ fn build_activate_command(data: ActivateCommandData) -> String { self_activate_command = format!("{} --auto-rollback", self_activate_command); } + if data.dry_activate { + self_activate_command = format!("{} --dry-activate", self_activate_command); + } + if let Some(sudo_cmd) = &data.sudo { self_activate_command = format!("{} {}", sudo_cmd, self_activate_command); } @@ -62,6 +67,7 @@ fn test_activation_command_builder() { let profile_path = "/blah/profiles/test"; let closure = "/nix/store/blah/etc"; let auto_rollback = true; + let dry_activate = false; let temp_path = "/tmp"; let confirm_timeout = 30; let magic_rollback = true; @@ -78,7 +84,8 @@ fn test_activation_command_builder() { confirm_timeout, magic_rollback, debug_logs, - log_dir + log_dir, + dry_activate }), "sudo -u test /nix/store/blah/etc/activate-rs --debug-logs --log-dir /tmp/something.txt --temp-path '/tmp' activate '/nix/store/blah/etc' '/blah/profiles/test' --confirm-timeout 30 --magic-rollback --auto-rollback" .to_string(), @@ -210,11 +217,14 @@ pub enum DeployProfileError { pub async fn deploy_profile( deploy_data: &super::DeployData<'_>, deploy_defs: &super::DeployDefs, + dry_activate: bool, ) -> Result<(), DeployProfileError> { - info!( - "Activating profile `{}` for node `{}`", - deploy_data.profile_name, deploy_data.node_name - ); + if !dry_activate { + info!( + "Activating profile `{}` for node `{}`", + deploy_data.profile_name, deploy_data.node_name + ); + } let temp_path: Cow = match &deploy_data.merged_settings.temp_path { Some(x) => x.into(), @@ -227,6 +237,8 @@ pub async fn deploy_profile( let auto_rollback = deploy_data.merged_settings.auto_rollback.unwrap_or(true); + let dry_activate = dry_activate; + let self_activate_command = build_activate_command(ActivateCommandData { sudo: &deploy_defs.sudo, profile_path: &deploy_defs.profile_path, @@ -237,6 +249,7 @@ pub async fn deploy_profile( magic_rollback, debug_logs: deploy_data.debug_logs, log_dir: deploy_data.log_dir, + dry_activate, }); debug!("Constructed activation command: {}", self_activate_command); @@ -255,7 +268,7 @@ pub async fn deploy_profile( ssh_activate_command.arg(&ssh_opt); } - if !magic_rollback { + if !magic_rollback || dry_activate { let ssh_activate_exit_status = ssh_activate_command .arg(self_activate_command) .status() @@ -267,7 +280,9 @@ pub async fn deploy_profile( a => return Err(DeployProfileError::SSHActivateExitError(a)), }; - info!("Success activating, done!"); + if !dry_activate { + info!("Success activating, done!"); + } } else { let self_wait_command = build_wait_command(WaitCommandData { sudo: &deploy_defs.sudo, diff --git a/src/lib.rs b/src/lib.rs index b93b9ae..a6b57aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -140,6 +140,7 @@ pub struct CmdOverrides { pub magic_rollback: Option, pub temp_path: Option, pub confirm_timeout: Option, + pub dry_activate: bool, } #[derive(PartialEq, Debug)] -- cgit v1.2.3 From 6093dc02e98ae68f73c997c8d5d18f19074a46e1 Mon Sep 17 00:00:00 2001 From: Oleg Pykhalov Date: Wed, 7 Apr 2021 13:33:50 +0300 Subject: flake: Add optional dryActivate argument to activate.custom --- flake.nix | 80 +++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/flake.nix b/flake.nix index 75ea2b7..424718c 100644 --- a/flake.nix +++ b/flake.nix @@ -59,42 +59,56 @@ activate.custom; activate = rec { - custom = base: activate: pkgs.buildEnv { - name = ("activatable-" + base.name); - paths = [ - base - (pkgs.writeTextFile { - name = base.name + "-activate-path"; - text = '' - #!${pkgs.runtimeShell} - set -euo pipefail - - ${activate} - ''; - executable = true; - destination = "/deploy-rs-activate"; - }) - (pkgs.writeTextFile { - name = base.name + "-activate-rs"; - text = '' - #!${pkgs.runtimeShell} - exec ${self.defaultPackage."${system}"}/bin/activate "$@" - ''; - executable = true; - destination = "/activate-rs"; - }) - ]; - }; - - nixos = base: custom base.config.system.build.toplevel '' + custom = + { + __toString = customSelf: "TODO: dryActivate"; + __functor = customSelf: base: activate: + pkgs.buildEnv { + name = ("activatable-" + base.name); + paths = + let + hasDryActivate = builtins.hasAttr "dryActivate" customSelf; + in [ + base + (pkgs.writeTextFile { + name = base.name + "-activate-path"; + text = '' + #!${pkgs.runtimeShell} + set -euo pipefail + + if [[ $DRY_ACTIVATE == "1" ]] + then + if ${pkgs.lib.boolToString hasDryActivate} + then + ${if hasDryActivate then customSelf.dryActivate else ":"} + else + echo ${pkgs.writeScript "activate" activate} + fi + else + ${activate} + fi + ''; + executable = true; + destination = "/deploy-rs-activate"; + }) + (pkgs.writeTextFile { + name = base.name + "-activate-rs"; + text = '' + #!${pkgs.runtimeShell} + exec ${self.defaultPackage."${system}"}/bin/activate "$@" + ''; + executable = true; + destination = "/activate-rs"; + }) + ]; + }; + }; + + nixos = base: (custom // { dryActivate = "$PROFILE/bin/switch-to-configuration dry-activate"; }) base.config.system.build.toplevel '' # work around https://github.com/NixOS/nixpkgs/issues/73404 cd /tmp - if [[ $DRY_ACTIVATE == "1" ]]; then - $PROFILE/bin/switch-to-configuration dry-activate - else - $PROFILE/bin/switch-to-configuration switch - fi + $PROFILE/bin/switch-to-configuration switch # https://github.com/serokell/deploy-rs/issues/31 ${with base.config.boot.loader; -- cgit v1.2.3 From 920c9d2ed4034e2200c948868c7bd510e58b1371 Mon Sep 17 00:00:00 2001 From: Oleg Pykhalov Date: Fri, 16 Apr 2021 10:28:01 +0300 Subject: Apply notgne2 suggestions. --- flake.nix | 16 ++++++---------- src/bin/activate.rs | 4 ++-- src/deploy.rs | 6 +++--- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/flake.nix b/flake.nix index 424718c..d718e83 100644 --- a/flake.nix +++ b/flake.nix @@ -61,14 +61,11 @@ activate = rec { custom = { - __toString = customSelf: "TODO: dryActivate"; __functor = customSelf: base: activate: pkgs.buildEnv { name = ("activatable-" + base.name); paths = - let - hasDryActivate = builtins.hasAttr "dryActivate" customSelf; - in [ + [ base (pkgs.writeTextFile { name = base.name + "-activate-path"; @@ -78,12 +75,11 @@ if [[ $DRY_ACTIVATE == "1" ]] then - if ${pkgs.lib.boolToString hasDryActivate} - then - ${if hasDryActivate then customSelf.dryActivate else ":"} - else - echo ${pkgs.writeScript "activate" activate} - fi + ${if builtins.hasAttr "dryActivate" customSelf + then + customSelf.dryActivate + else + "echo ${pkgs.writeScript "activate" activate}"} else ${activate} fi diff --git a/src/bin/activate.rs b/src/bin/activate.rs index 73d064f..da53174 100644 --- a/src/bin/activate.rs +++ b/src/bin/activate.rs @@ -378,9 +378,9 @@ pub async fn activate( debug!("Running activation script"); let activate_status = match Command::new(format!("{}/deploy-rs-activate", profile_path)) - .env("PROFILE", &closure) + .env("PROFILE", if dry_activate { &closure } else { &profile_path }) .env("DRY_ACTIVATE", if dry_activate { "1" } else { "0" }) - .current_dir(&closure) + .current_dir(if dry_activate { &closure } else { &profile_path }) .status() .await .map_err(ActivateError::RunActivateError) diff --git a/src/deploy.rs b/src/deploy.rs index f6cd4ef..285bbbd 100644 --- a/src/deploy.rs +++ b/src/deploy.rs @@ -237,8 +237,6 @@ pub async fn deploy_profile( let auto_rollback = deploy_data.merged_settings.auto_rollback.unwrap_or(true); - let dry_activate = dry_activate; - let self_activate_command = build_activate_command(ActivateCommandData { sudo: &deploy_defs.sudo, profile_path: &deploy_defs.profile_path, @@ -280,7 +278,9 @@ pub async fn deploy_profile( a => return Err(DeployProfileError::SSHActivateExitError(a)), }; - if !dry_activate { + if dry_activate { + info!("Completed dry-activate!"); + } else { info!("Success activating, done!"); } } else { -- cgit v1.2.3 From 5d5da4898d41cefd1f79c4cf6dd451405ffb8996 Mon Sep 17 00:00:00 2001 From: notgne2 Date: Thu, 29 Apr 2021 17:34:24 -0700 Subject: Use correct path to `deploy-rs-activate` binary when using `dry_activate` Signed-off-by: Oleg Pykhalov --- src/bin/activate.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/bin/activate.rs b/src/bin/activate.rs index da53174..d17f3a8 100644 --- a/src/bin/activate.rs +++ b/src/bin/activate.rs @@ -377,10 +377,12 @@ pub async fn activate( debug!("Running activation script"); - let activate_status = match Command::new(format!("{}/deploy-rs-activate", profile_path)) - .env("PROFILE", if dry_activate { &closure } else { &profile_path }) + let activation_location = if dry_activate { &closure } else { &profile_path }; + + let activate_status = match Command::new(format!("{}/deploy-rs-activate", activation_location)) + .env("PROFILE", activation_location) .env("DRY_ACTIVATE", if dry_activate { "1" } else { "0" }) - .current_dir(if dry_activate { &closure } else { &profile_path }) + .current_dir(activation_location) .status() .await .map_err(ActivateError::RunActivateError) -- cgit v1.2.3