diff --git a/src/nix/deployment/mod.rs b/src/nix/deployment/mod.rs index 7b19dca..da25324 100644 --- a/src/nix/deployment/mod.rs +++ b/src/nix/deployment/mod.rs @@ -28,7 +28,7 @@ use super::{ host::Local as LocalHost, key::{Key, UploadAt as UploadKeyAt}, ColmenaError, ColmenaResult, CopyDirection, CopyOptions, Hive, Host, NodeConfig, NodeName, - Profile, ProfileDerivation, RebootOptions, + Profile, ProfileDerivation, RebootOptions, StorePath, }; /// A deployment. @@ -637,7 +637,18 @@ impl Deployment { } } - host.activate(&profile_r, arc_self.goal).await?; + let activation_program: &StorePath = + &arc_self.hive + .get_registry_config() + .await? + .systems + .get(target.config.system_type.as_ref().unwrap_or(&"nixos".to_owned())) + .expect(&format!("System type {} does not exists", + target.config.system_type.as_ref().unwrap_or(&"nixos".to_owned()) + )) + .activation_program; + + host.activate(&profile_r, arc_self.goal, activation_program).await?; job.success_with_message(arc_self.goal.success_str().to_string())?; diff --git a/src/nix/hive/options.nix b/src/nix/hive/options.nix index a35ef81..2b65de3 100644 --- a/src/nix/hive/options.nix +++ b/src/nix/hive/options.nix @@ -258,6 +258,12 @@ with builtins; rec { type = types.functionTo types.unspecified; default = _: {}; }; + activationProgram = lib.mkOption { + description = mdDoc '' + Program to execute at activation time. + ''; + type = types.path; + }; }; }; registryOptions = { lib, ... }: let diff --git a/src/nix/host/local.rs b/src/nix/host/local.rs index a5bf0df..681394b 100644 --- a/src/nix/host/local.rs +++ b/src/nix/host/local.rs @@ -78,7 +78,12 @@ impl Host for Local { Ok(()) } - async fn activate(&mut self, profile: &Profile, goal: Goal) -> ColmenaResult<()> { + async fn activate( + &mut self, + profile: &Profile, + goal: Goal, + activation_program: &StorePath, + ) -> ColmenaResult<()> { if !goal.requires_activation() { return Err(ColmenaError::Unsupported); } @@ -91,7 +96,9 @@ impl Host for Local { } let command = { - let activation_command = profile.activation_command(goal).unwrap(); + let activation_command = profile + .activation_command(goal, activation_program) + .unwrap(); self.make_privileged_command(&activation_command) }; diff --git a/src/nix/host/mod.rs b/src/nix/host/mod.rs index 8ff44ad..531c26c 100644 --- a/src/nix/host/mod.rs +++ b/src/nix/host/mod.rs @@ -128,6 +128,7 @@ pub trait Host: Send + Sync + std::fmt::Debug { profile: &Profile, goal: Goal, copy_options: CopyOptions, + activation_program: Option<&StorePath>, ) -> ColmenaResult<()> { self.copy_closure( profile.as_store_path(), @@ -137,7 +138,12 @@ pub trait Host: Send + Sync + std::fmt::Debug { .await?; if goal.requires_activation() { - self.activate(profile, goal).await?; + self.activate( + profile, + goal, + activation_program.expect("Unknown activation program"), + ) + .await?; } Ok(()) @@ -171,7 +177,12 @@ pub trait Host: Send + Sync + std::fmt::Debug { /// /// The profile must already exist on the host. You should probably use deploy instead. #[allow(unused_variables)] - async fn activate(&mut self, profile: &Profile, goal: Goal) -> ColmenaResult<()> { + async fn activate( + &mut self, + profile: &Profile, + goal: Goal, + activation_program: &StorePath, + ) -> ColmenaResult<()> { Err(ColmenaError::Unsupported) } diff --git a/src/nix/host/ssh.rs b/src/nix/host/ssh.rs index 64ebb68..ae3952c 100644 --- a/src/nix/host/ssh.rs +++ b/src/nix/host/ssh.rs @@ -90,7 +90,12 @@ impl Host for Ssh { Ok(()) } - async fn activate(&mut self, profile: &Profile, goal: Goal) -> ColmenaResult<()> { + async fn activate( + &mut self, + profile: &Profile, + goal: Goal, + activation_program: &StorePath, + ) -> ColmenaResult<()> { if !goal.requires_activation() { return Err(ColmenaError::Unsupported); } @@ -101,7 +106,9 @@ impl Host for Ssh { self.run_command(set_profile).await?; } - let activation_command = profile.activation_command(goal).unwrap(); + let activation_command = profile + .activation_command(goal, activation_program) + .unwrap(); let v: Vec<&str> = activation_command.iter().map(|s| &**s).collect(); let command = self.ssh(&v); self.run_command(command).await diff --git a/src/nix/mod.rs b/src/nix/mod.rs index a1a0b6b..000135a 100644 --- a/src/nix/mod.rs +++ b/src/nix/mod.rs @@ -101,6 +101,9 @@ pub struct MetaConfig { pub struct SystemTypeConfig { #[serde(rename = "supportsDeployment")] pub supports_deployment: bool, + + #[serde(rename = "activationProgram")] + pub activation_program: StorePath, } #[derive(Debug, Clone, Validate, Deserialize)] diff --git a/src/nix/profile.rs b/src/nix/profile.rs index b71c637..752e3a4 100644 --- a/src/nix/profile.rs +++ b/src/nix/profile.rs @@ -26,7 +26,11 @@ impl Profile { } /// Returns the command to activate this profile. - pub fn activation_command(&self, goal: Goal) -> Option> { + pub fn activation_command( + &self, + goal: Goal, + activation_program: &StorePath, + ) -> Option> { if let Some(goal) = goal.as_str() { let path = self.as_path().join("bin/switch-to-configuration"); let switch_to_configuration = path