WIP: Generic activation program #9
7 changed files with 58 additions and 9 deletions
|
@ -28,7 +28,7 @@ use super::{
|
||||||
host::Local as LocalHost,
|
host::Local as LocalHost,
|
||||||
key::{Key, UploadAt as UploadKeyAt},
|
key::{Key, UploadAt as UploadKeyAt},
|
||||||
ColmenaError, ColmenaResult, CopyDirection, CopyOptions, Hive, Host, NodeConfig, NodeName,
|
ColmenaError, ColmenaResult, CopyDirection, CopyOptions, Hive, Host, NodeConfig, NodeName,
|
||||||
Profile, ProfileDerivation, RebootOptions,
|
Profile, ProfileDerivation, RebootOptions, StorePath,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A deployment.
|
/// 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())?;
|
job.success_with_message(arc_self.goal.success_str().to_string())?;
|
||||||
|
|
||||||
|
|
|
@ -258,6 +258,12 @@ with builtins; rec {
|
||||||
type = types.functionTo types.unspecified;
|
type = types.functionTo types.unspecified;
|
||||||
default = _: {};
|
default = _: {};
|
||||||
};
|
};
|
||||||
|
activationProgram = lib.mkOption {
|
||||||
|
description = mdDoc ''
|
||||||
|
Program to execute at activation time.
|
||||||
|
'';
|
||||||
|
type = types.path;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
registryOptions = { lib, ... }: let
|
registryOptions = { lib, ... }: let
|
||||||
|
|
|
@ -78,7 +78,12 @@ impl Host for Local {
|
||||||
Ok(())
|
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() {
|
if !goal.requires_activation() {
|
||||||
return Err(ColmenaError::Unsupported);
|
return Err(ColmenaError::Unsupported);
|
||||||
}
|
}
|
||||||
|
@ -91,7 +96,9 @@ impl Host for Local {
|
||||||
}
|
}
|
||||||
|
|
||||||
let command = {
|
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)
|
self.make_privileged_command(&activation_command)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -128,6 +128,7 @@ pub trait Host: Send + Sync + std::fmt::Debug {
|
||||||
profile: &Profile,
|
profile: &Profile,
|
||||||
goal: Goal,
|
goal: Goal,
|
||||||
copy_options: CopyOptions,
|
copy_options: CopyOptions,
|
||||||
|
activation_program: Option<&StorePath>,
|
||||||
) -> ColmenaResult<()> {
|
) -> ColmenaResult<()> {
|
||||||
self.copy_closure(
|
self.copy_closure(
|
||||||
profile.as_store_path(),
|
profile.as_store_path(),
|
||||||
|
@ -137,7 +138,12 @@ pub trait Host: Send + Sync + std::fmt::Debug {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if goal.requires_activation() {
|
if goal.requires_activation() {
|
||||||
self.activate(profile, goal).await?;
|
self.activate(
|
||||||
|
profile,
|
||||||
|
goal,
|
||||||
|
activation_program.expect("Unknown activation program"),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
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.
|
/// The profile must already exist on the host. You should probably use deploy instead.
|
||||||
#[allow(unused_variables)]
|
#[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)
|
Err(ColmenaError::Unsupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,12 @@ impl Host for Ssh {
|
||||||
Ok(())
|
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() {
|
if !goal.requires_activation() {
|
||||||
return Err(ColmenaError::Unsupported);
|
return Err(ColmenaError::Unsupported);
|
||||||
}
|
}
|
||||||
|
@ -101,7 +106,9 @@ impl Host for Ssh {
|
||||||
self.run_command(set_profile).await?;
|
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 v: Vec<&str> = activation_command.iter().map(|s| &**s).collect();
|
||||||
let command = self.ssh(&v);
|
let command = self.ssh(&v);
|
||||||
self.run_command(command).await
|
self.run_command(command).await
|
||||||
|
|
|
@ -101,6 +101,9 @@ pub struct MetaConfig {
|
||||||
pub struct SystemTypeConfig {
|
pub struct SystemTypeConfig {
|
||||||
#[serde(rename = "supportsDeployment")]
|
#[serde(rename = "supportsDeployment")]
|
||||||
pub supports_deployment: bool,
|
pub supports_deployment: bool,
|
||||||
|
|
||||||
|
#[serde(rename = "activationProgram")]
|
||||||
|
pub activation_program: StorePath,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Validate, Deserialize)]
|
#[derive(Debug, Clone, Validate, Deserialize)]
|
||||||
|
|
|
@ -26,7 +26,11 @@ impl Profile {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the command to activate this profile.
|
/// Returns the command to activate this profile.
|
||||||
pub fn activation_command(&self, goal: Goal) -> Option<Vec<String>> {
|
pub fn activation_command(
|
||||||
|
&self,
|
||||||
|
goal: Goal,
|
||||||
|
activation_program: &StorePath,
|
||||||
|
) -> Option<Vec<String>> {
|
||||||
if let Some(goal) = goal.as_str() {
|
if let Some(goal) = goal.as_str() {
|
||||||
let path = self.as_path().join("bin/switch-to-configuration");
|
let path = self.as_path().join("bin/switch-to-configuration");
|
||||||
let switch_to_configuration = path
|
let switch_to_configuration = path
|
||||||
|
|
Loading…
Reference in a new issue