Add deployment.privilegeEscalationCommand

This adds a NixOps-equivalent option for non-root deployment
on remote hosts.

Fixes #27.
This commit is contained in:
Zhaofeng Li 2021-05-24 00:15:38 -07:00
parent 2581f33dad
commit 960af8f793
3 changed files with 28 additions and 0 deletions

View file

@ -155,6 +155,16 @@ let
type = types.bool; type = types.bool;
default = true; default = true;
}; };
privilegeEscalationCommand = lib.mkOption {
description = ''
Command to use to elevate privileges when activating the new profiles on SSH hosts.
This is used on SSH hosts when `deployment.targetUser` is not `root`.
The user must be allowed to use the command non-interactively.
'';
type = types.listOf types.str;
default = [ "sudo" "-H" "--" ];
};
}; };
}; };
}; };

View file

@ -26,6 +26,9 @@ pub struct Ssh {
/// Local path to a ssh_config file. /// Local path to a ssh_config file.
ssh_config: Option<PathBuf>, ssh_config: Option<PathBuf>,
/// Command to elevate privileges with.
privilege_escalation_command: Vec<String>,
friendly_name: String, friendly_name: String,
progress_bar: TaskProgress, progress_bar: TaskProgress,
logs: String, logs: String,
@ -107,6 +110,7 @@ impl Ssh {
port: None, port: None,
ssh_config: None, ssh_config: None,
friendly_name, friendly_name,
privilege_escalation_command: Vec::new(),
progress_bar: TaskProgress::default(), progress_bar: TaskProgress::default(),
logs: String::new(), logs: String::new(),
} }
@ -120,6 +124,10 @@ impl Ssh {
self.ssh_config = Some(ssh_config); self.ssh_config = Some(ssh_config);
} }
pub fn set_privilege_escalation_command(&mut self, command: Vec<String>) {
self.privilege_escalation_command = command;
}
pub fn upcast(self) -> Box<dyn Host> { pub fn upcast(self) -> Box<dyn Host> {
Box::new(self) Box::new(self)
} }
@ -128,6 +136,11 @@ impl Ssh {
pub fn ssh(&self, command: &[&str]) -> Command { pub fn ssh(&self, command: &[&str]) -> Command {
let options = self.ssh_options(); let options = self.ssh_options();
let options_str = options.join(" "); let options_str = options.join(" ");
let privilege_escalation_command = if self.user != "root" {
self.privilege_escalation_command.as_slice()
} else {
&[]
};
let mut cmd = Command::new("ssh"); let mut cmd = Command::new("ssh");
@ -135,6 +148,7 @@ impl Ssh {
.arg(self.ssh_target()) .arg(self.ssh_target())
.args(&options) .args(&options)
.arg("--") .arg("--")
.args(privilege_escalation_command)
.args(command) .args(command)
.env("NIX_SSHOPTS", options_str); .env("NIX_SSHOPTS", options_str);

View file

@ -121,6 +121,9 @@ pub struct NodeConfig {
#[serde(rename = "replaceUnknownProfiles")] #[serde(rename = "replaceUnknownProfiles")]
replace_unknown_profiles: bool, replace_unknown_profiles: bool,
#[serde(rename = "privilegeEscalationCommand")]
privilege_escalation_command: Vec<String>,
#[validate(custom = "validate_keys")] #[validate(custom = "validate_keys")]
keys: HashMap<String, Key>, keys: HashMap<String, Key>,
} }
@ -132,6 +135,7 @@ impl NodeConfig {
pub fn to_ssh_host(&self) -> Option<Ssh> { pub fn to_ssh_host(&self) -> Option<Ssh> {
self.target_host.as_ref().map(|target_host| { self.target_host.as_ref().map(|target_host| {
let mut host = Ssh::new(self.target_user.clone(), target_host.clone()); let mut host = Ssh::new(self.target_user.clone(), target_host.clone());
host.set_privilege_escalation_command(self.privilege_escalation_command.clone());
if let Some(target_port) = self.target_port { if let Some(target_port) = self.target_port {
host.set_port(target_port); host.set_port(target_port);