diff --git a/runtime/evaluate.nix b/runtime/evaluate.nix index 0078982..183dd26 100644 --- a/runtime/evaluate.nix +++ b/runtime/evaluate.nix @@ -84,7 +84,7 @@ rec { topLevels = builtins.mapAttrs (name: _: getTopLevel name) nodes; inspect = { - _schema = 0; + _schema = 1; nodes = builtins.mapAttrs (_: v: v.config.deployment) nodes; }; diff --git a/runtime/module/options.nix b/runtime/module/options.nix index 85ee7ca..087a7c8 100644 --- a/runtime/module/options.nix +++ b/runtime/module/options.nix @@ -73,6 +73,27 @@ in ]; }; + privilegeEscalationCommand = lib.mkOption { + type = types.listOf types.str; + description = "Command to elevate."; + default = [ + "sudo" + "--" + ]; + }; + + replaceUnknownProfiles = lib.mkOption { + type = types.bool; + description = "No-op, colmena compatability"; + default = true; + }; + + sshOptions = lib.mkOption { + type = types.listOf types.str; + description = "No-op, colmena compatability"; + default = [ ]; + }; + _keys = lib.mkOption { internal = true; readOnly = true; diff --git a/wire/lib/src/commands/interactive.rs b/wire/lib/src/commands/interactive.rs index 64f7a12..1ffbe48 100644 --- a/wire/lib/src/commands/interactive.rs +++ b/wire/lib/src/commands/interactive.rs @@ -126,7 +126,7 @@ fn create_starting_segment>( } } -#[instrument(skip_all, name = "run-int", fields(elevated = %arguments.elevated))] +#[instrument(skip_all, name = "run-int", fields(elevated = %arguments.is_elevated()))] pub(crate) fn interactive_command_with_env>( arguments: &CommandArguments, envs: std::collections::HashMap, @@ -258,7 +258,7 @@ pub(crate) fn interactive_command_with_env>( fn print_authenticate_warning>( arguments: &CommandArguments, ) -> Result<(), HiveLibError> { - if !arguments.elevated { + if !arguments.is_elevated() { return Ok(()); } @@ -330,8 +330,8 @@ fn build_command>( command }; - if arguments.elevated { - command.arg(format!("sudo -u root -- sh -c '{command_string}'")); + if let Some(escalation_command) = &arguments.privilege_escalation_command { + command.arg(format!("{escalation_command} sh -c '{command_string}'")); } else { command.arg(command_string); } diff --git a/wire/lib/src/commands/mod.rs b/wire/lib/src/commands/mod.rs index 72c88f7..08e87a8 100644 --- a/wire/lib/src/commands/mod.rs +++ b/wire/lib/src/commands/mod.rs @@ -5,6 +5,7 @@ use std::{collections::HashMap, str::from_utf8, sync::LazyLock}; use aho_corasick::AhoCorasick; use gjson::Value; +use itertools::Itertools; use nix_compat::log::{AT_NIX_PREFIX, VerbosityLevel}; use num_enum::TryFromPrimitive; use tracing::{debug, error, info, trace, warn}; @@ -16,7 +17,7 @@ use crate::{ noninteractive::{NonInteractiveChildChip, non_interactive_command_with_env}, }, errors::{CommandError, HiveLibError}, - hive::node::Target, + hive::node::{Node, Target}, }; pub(crate) mod common; @@ -44,7 +45,7 @@ pub(crate) struct CommandArguments<'t, S: AsRef> { output_mode: ChildOutputMode, command_string: S, keep_stdin_open: bool, - elevated: bool, + privilege_escalation_command: Option, log_stdout: bool, } @@ -61,7 +62,7 @@ impl<'a, S: AsRef> CommandArguments<'a, S> { Self { command_string, keep_stdin_open: false, - elevated: false, + privilege_escalation_command: None, log_stdout: false, target: None, output_mode: ChildOutputMode::Generic, @@ -84,11 +85,16 @@ impl<'a, S: AsRef> CommandArguments<'a, S> { self } - pub(crate) const fn elevated(mut self) -> Self { - self.elevated = true; + pub(crate) fn elevated(mut self, node: &Node) -> Self { + self.privilege_escalation_command = + Some(node.privilege_escalation_command.iter().join(" ")); self } + pub(crate) const fn is_elevated(&self) -> bool { + self.privilege_escalation_command.is_some() + } + pub(crate) const fn log_stdout(mut self) -> Self { self.log_stdout = true; self diff --git a/wire/lib/src/commands/noninteractive.rs b/wire/lib/src/commands/noninteractive.rs index cd56c0d..399f5d9 100644 --- a/wire/lib/src/commands/noninteractive.rs +++ b/wire/lib/src/commands/noninteractive.rs @@ -31,7 +31,7 @@ pub(crate) struct NonInteractiveChildChip { stdin: ChildStdin, } -#[instrument(skip_all, name = "run", fields(elevated = %arguments.elevated))] +#[instrument(skip_all, name = "run", fields(elevated = %arguments.is_elevated()))] pub(crate) fn non_interactive_command_with_env>( arguments: &CommandArguments, envs: HashMap, @@ -55,8 +55,8 @@ pub(crate) fn non_interactive_command_with_env>( } ); - let command_string = if arguments.elevated { - format!("sudo -u root -- sh -c '{command_string}'") + let command_string = if let Some(escalation_command) = &arguments.privilege_escalation_command { + format!("{escalation_command} sh -c '{command_string}'") } else { command_string }; diff --git a/wire/lib/src/errors.rs b/wire/lib/src/errors.rs index db0783e..cdc16cb 100644 --- a/wire/lib/src/errors.rs +++ b/wire/lib/src/errors.rs @@ -134,7 +134,7 @@ pub enum HiveInitializationError { #[diagnostic( code(wire::hive_init::Parse), - help("Please create an issue!"), + help("If you cannot resolve this problem, please create an issue."), url("{DOCS_URL}#{}", self.code().unwrap()) )] #[error("Failed to parse internal wire json.")] diff --git a/wire/lib/src/hive/mod.rs b/wire/lib/src/hive/mod.rs index a947164..ae639cc 100644 --- a/wire/lib/src/hive/mod.rs +++ b/wire/lib/src/hive/mod.rs @@ -48,7 +48,7 @@ fn check_schema_version<'de, D: Deserializer<'de>>(d: D) -> Result, + + #[serde(rename( + deserialize = "privilegeEscalationCommand", + serialize = "privilege_escalation_command" + ))] + pub privilege_escalation_command: im::Vector>, } #[cfg(test)] @@ -180,6 +186,7 @@ impl Default for Node { target: Target::default(), keys: im::Vector::new(), tags: im::HashSet::new(), + privilege_escalation_command: vec!["sudo".into(), "--".into()].into(), allow_local_deployment: true, build_remotely: false, host_platform: "x86_64-linux".into(), diff --git a/wire/lib/src/hive/steps/activate.rs b/wire/lib/src/hive/steps/activate.rs index cdddc65..298c656 100644 --- a/wire/lib/src/hive/steps/activate.rs +++ b/wire/lib/src/hive/steps/activate.rs @@ -57,7 +57,7 @@ async fn set_profile( } else { Some(&ctx.node.target) }) - .elevated(), + .elevated(ctx.node), )?; let _ = child @@ -111,7 +111,7 @@ impl ExecuteStep for SwitchToConfiguration { } else { Some(&ctx.node.target) }) - .elevated() + .elevated(ctx.node) .log_stdout(), )?; @@ -135,7 +135,7 @@ impl ExecuteStep for SwitchToConfiguration { &CommandArguments::new("reboot now", ctx.modifiers) .log_stdout() .on_target(Some(&ctx.node.target)) - .elevated(), + .elevated(ctx.node), )?; // consume result, impossible to know if the machine failed to reboot or we diff --git a/wire/lib/src/hive/steps/keys.rs b/wire/lib/src/hive/steps/keys.rs index 9748db0..7fa7263 100644 --- a/wire/lib/src/hive/steps/keys.rs +++ b/wire/lib/src/hive/steps/keys.rs @@ -258,7 +258,7 @@ impl ExecuteStep for Keys { } else { Some(&ctx.node.target) }) - .elevated() + .elevated(ctx.node) .keep_stdin_open() .log_stdout(), )?;