ALPHA: wire is a tool to deploy nixos systems wire.althaea.zone/
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

allow interactive to be non elevated (#302)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

authored by

marshmallow
autofix-ci[bot]
and committed by
GitHub
3f02f31d 61758a17

+187 -120
+3 -3
.github/workflows/test.yml
··· 15 15 with: 16 16 concurrent_skipping: "same_content_newer" 17 17 cancel_others: "true" 18 - nextest: 18 + test: 19 19 runs-on: ubuntu-latest 20 20 needs: pre-job 21 21 permissions: ··· 33 33 ~/.cargo/git 34 34 target 35 35 key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 36 - - name: Nextest 37 - run: nix develop --print-build-logs -v --command cargo nextest run 36 + - name: Cargo Tests 37 + run: nix develop --print-build-logs -v --command cargo test
-1
flake.nix
··· 33 33 ./nix/hooks.nix # pre-commit hooks 34 34 ./nix/utils.nix # utility functions 35 35 ./nix/shells.nix 36 - ./nix/checks.nix 37 36 ./wire/cli 38 37 ./wire/key_agent 39 38 ./doc
-21
nix/checks.nix
··· 1 - { 2 - perSystem = 3 - { 4 - craneLib, 5 - commonArgs, 6 - ... 7 - }: 8 - { 9 - checks.wire-nextest = craneLib.cargoNextest ( 10 - { 11 - partitions = 2; 12 - cargoArtifacts = craneLib.buildDepsOnly commonArgs; 13 - cargoNextestPartitionsExtraArgs = builtins.concatStringsSep " " [ 14 - "--no-tests pass" 15 - ]; 16 - 17 - } 18 - // commonArgs 19 - ); 20 - }; 21 - }
-1
nix/shells.nix
··· 19 19 cfg.settings.package 20 20 21 21 pkgs.just 22 - pkgs.cargo-nextest 23 22 pkgs.pnpm 24 23 pkgs.nodejs 25 24 ];
+7 -1
tests/nix/suite/test_remote_deploy/default.nix
··· 19 19 # ran --ssh-accept-host, should succeed 20 20 deployer.succeed(f"wire apply push --on receiver --no-progress --path {TEST_DIR}/hive.nix --no-keys --ssh-accept-host -vvv >&2") 21 21 22 - with subtest("Check basic apply"): 22 + with subtest("Check basic apply: Interactive"): 23 23 deployer.succeed(f"wire apply --on receiver --no-progress --path {TEST_DIR}/hive.nix --no-keys --ssh-accept-host -vvv >&2") 24 24 25 25 identity = receiver.succeed("cat /etc/identity") 26 26 assert identity == "first", "Identity of first apply wasn't as expected" 27 + 28 + with subtest("Check basic apply: NonInteractive"): 29 + deployer.succeed(f"wire apply --on receiver-third --no-progress --path {TEST_DIR}/hive.nix --no-keys --ssh-accept-host --non-interactive -vvv >&2") 30 + 31 + identity = receiver.succeed("cat /etc/identity") 32 + assert identity == "third", "Identity of non-interactive apply wasn't as expected" 27 33 28 34 with subtest("Check boot apply"): 29 35 first_system = receiver.succeed("readlink -f /run/current-system")
+17 -12
wire/lib/src/commands/common.rs
··· 9 9 10 10 use crate::{ 11 11 EvalGoal, SubCommandModifiers, 12 - commands::{ 13 - ChildOutputMode, WireCommand, WireCommandChip, noninteractive::NonInteractiveCommand, 14 - }, 12 + commands::{ChildOutputMode, CommandArguments, WireCommand, WireCommandChip, get_command}, 15 13 errors::{HiveInitializationError, HiveLibError}, 16 14 hive::{ 17 15 find_hive, ··· 26 24 modifiers: SubCommandModifiers, 27 25 clobber_lock: Arc<Mutex<()>>, 28 26 ) -> Result<(), HiveLibError> { 29 - let mut command = 30 - NonInteractiveCommand::spawn_new(None, ChildOutputMode::Nix, modifiers).await?; 27 + let mut command = get_command(None, ChildOutputMode::Nix, modifiers).await?; 31 28 32 29 let command_string = format!( 33 30 "nix --extra-experimental-features nix-command \ ··· 41 38 ); 42 39 43 40 let child = command.run_command_with_env( 44 - command_string, 45 - false, 41 + CommandArguments { 42 + command_string, 43 + keep_stdin_open: false, 44 + elevated: false, 45 + clobber_lock, 46 + }, 46 47 HashMap::from([("NIX_SSHOPTS".into(), node.target.create_ssh_opts(modifiers))]), 47 - clobber_lock, 48 48 )?; 49 49 50 50 child ··· 72 72 HiveInitializationError::NoHiveFound(path.to_path_buf()), 73 73 ))?; 74 74 75 - let mut command = 76 - NonInteractiveCommand::spawn_new(None, ChildOutputMode::Nix, modifiers).await?; 75 + let mut command = get_command(None, ChildOutputMode::Nix, modifiers).await?; 76 + 77 77 let attribute = if canon_path.ends_with("flake.nix") { 78 78 format!( 79 79 "{}#wire --apply \"hive: {}\"", ··· 105 105 }, 106 106 ); 107 107 108 - let child = command.run_command(command_string, false, clobber_lock)?; 108 + let child = command.run_command(CommandArguments { 109 + command_string, 110 + keep_stdin_open: false, 111 + elevated: false, 112 + clobber_lock, 113 + })?; 109 114 110 115 child 111 116 .wait_till_success() 112 117 .await 113 118 .map_err(|source| HiveLibError::NixEvalError { attribute, source }) 114 - .map(|(_, stdout)| stdout) 119 + .map(|x| x.get_stdout().clone()) 115 120 }
+46 -26
wire/lib/src/commands/interactive.rs
··· 20 20 use tracing::{debug, error, info, trace}; 21 21 22 22 use crate::SubCommandModifiers; 23 + use crate::commands::CommandArguments; 23 24 use crate::commands::interactive_logbuffer::LogBuffer; 24 25 use crate::errors::CommandError; 25 26 use crate::nix_log::NixLog; ··· 48 49 cancel_stdin_pipe_w: OwnedFd, 49 50 write_stdin_pipe_w: OwnedFd, 50 51 51 - error_collection: Arc<Mutex<VecDeque<String>>>, 52 + stderr_collection: Arc<Mutex<VecDeque<String>>>, 53 + stdout_collection: Arc<Mutex<VecDeque<String>>>, 52 54 53 55 command_string: String, 54 56 ··· 71 73 failed_needle: Arc<String>, 72 74 start_needle: Arc<String>, 73 75 output_mode: Arc<ChildOutputMode>, 74 - collection: Arc<Mutex<VecDeque<String>>>, 76 + stderr_collection: Arc<Mutex<VecDeque<String>>>, 77 + stdout_collection: Arc<Mutex<VecDeque<String>>>, 75 78 completion_status: Arc<CompletionStatus>, 76 79 } 77 80 ··· 79 82 const THREAD_BEGAN_SIGNAL: &[u8; 1] = b"b"; 80 83 const THREAD_QUIT_SIGNAL: &[u8; 1] = b"q"; 81 84 85 + /// substitutes STDOUT with #$line. stdout is far less common than stderr. 86 + const IO_SUBS: &str = "1> >(while IFS= read -r line; do echo \"#$line\"; done)"; 87 + 82 88 impl<'t> WireCommand<'t> for InteractiveCommand<'t> { 83 89 type ChildChip = InteractiveChildChip; 84 90 ··· 106 112 #[allow(clippy::too_many_lines)] 107 113 fn run_command_with_env<S: AsRef<str>>( 108 114 &mut self, 109 - command_string: S, 110 - keep_stdin_open: bool, 115 + arguments: CommandArguments<S>, 111 116 envs: std::collections::HashMap<String, String>, 112 - clobber_lock: Arc<Mutex<()>>, 113 117 ) -> Result<Self::ChildChip, HiveLibError> { 114 - if let Some(target) = self.target { 115 - if target.user != "root".into() { 116 - eprintln!( 117 - "Non-root user: Please authenticate for \"sudo {}\"", 118 - command_string.as_ref(), 119 - ); 120 - } 118 + if arguments.elevated { 119 + eprintln!( 120 + "Please authenticate for \"sudo {}\"", 121 + arguments.command_string.as_ref(), 122 + ); 121 123 } 122 124 123 125 let pty_system = NativePtySystem::default(); ··· 141 143 } 142 144 143 145 let command_string = &format!( 144 - "echo '{start}' && {command} {flags} && echo '{succeed}' || echo '{failed}'", 146 + "echo '{start}' && {command} {flags} {IO_SUBS} && echo '{succeed}' || echo '{failed}'", 145 147 start = self.start_needle, 146 148 succeed = self.succeed_needle, 147 149 failed = self.failed_needle, 148 - command = command_string.as_ref(), 150 + command = arguments.command_string.as_ref(), 149 151 flags = match *self.output_mode { 150 152 ChildOutputMode::Nix => "--log-format internal-json", 151 153 ChildOutputMode::Raw => "", ··· 169 171 command 170 172 }; 171 173 172 - command.args([&format!("sudo -u root -- sh -c \"{command_string}\"")]); 174 + if arguments.elevated { 175 + command.arg(format!("sudo -u root -- sh -c '{command_string}'")); 176 + } else { 177 + command.arg(command_string); 178 + } 173 179 174 180 // give command all env vars 175 181 for (key, value) in envs { 176 182 command.env(key, value); 177 183 } 178 184 179 - let clobber_guard = clobber_lock.lock().unwrap(); 185 + let clobber_guard = arguments.clobber_lock.lock().unwrap(); 180 186 let _guard = StdinTermiosAttrGuard::new().map_err(HiveLibError::CommandError)?; 181 187 let child = pty_pair 182 188 .slave ··· 196 202 .take_writer() 197 203 .map_err(|x| HiveLibError::CommandError(CommandError::PortablePty(x)))?; 198 204 199 - let error_collection = Arc::new(Mutex::new(VecDeque::<String>::with_capacity(10))); 205 + let stderr_collection = Arc::new(Mutex::new(VecDeque::<String>::with_capacity(10))); 206 + let stdout_collection = Arc::new(Mutex::new(VecDeque::<String>::with_capacity(10))); 200 207 let (began_tx, began_rx) = mpsc::channel::<()>(); 201 208 let completion_status = Arc::new(CompletionStatus::new()); 202 209 ··· 208 215 failed_needle: self.failed_needle.clone(), 209 216 start_needle: self.start_needle.clone(), 210 217 output_mode: self.output_mode.clone(), 211 - collection: error_collection.clone(), 218 + stderr_collection: stderr_collection.clone(), 219 + stdout_collection: stdout_collection.clone(), 212 220 completion_status: completion_status.clone(), 213 221 }; 214 222 ··· 232 240 233 241 drop(clobber_guard); 234 242 235 - if keep_stdin_open { 243 + if arguments.keep_stdin_open { 236 244 trace!("Sending THREAD_BEGAN_SIGNAL"); 237 245 238 246 posix_write(&cancel_stdin_pipe_w, THREAD_BEGAN_SIGNAL) ··· 248 256 child, 249 257 cancel_stdin_pipe_w, 250 258 write_stdin_pipe_w, 251 - error_collection, 259 + stderr_collection, 260 + stdout_collection, 252 261 command_string: command_string.clone(), 253 262 completion_status, 254 263 stdout_handle, ··· 287 296 } 288 297 289 298 impl WireCommandChip for InteractiveChildChip { 290 - type ExitStatus = portable_pty::ExitStatus; 299 + type ExitStatus = (portable_pty::ExitStatus, String); 291 300 292 301 async fn wait_till_success(mut self) -> Result<Self::ExitStatus, CommandError> { 293 302 info!("trying to grab status..."); ··· 308 317 let _ = posix_write(&self.cancel_stdin_pipe_w, THREAD_QUIT_SIGNAL); 309 318 310 319 if let Some(true) = success { 311 - return Ok(exit_status); 320 + let mut collection = self.stdout_collection.lock().unwrap(); 321 + let logs = collection.make_contiguous().join("\n"); 322 + 323 + return Ok((exit_status, logs)); 312 324 } 313 325 314 326 debug!("child did not succeed"); 315 327 316 - let mut collection = self.error_collection.lock().unwrap(); 328 + let mut collection = self.stderr_collection.lock().unwrap(); 317 329 let logs = collection.make_contiguous().join("\n"); 318 330 319 331 Err(CommandError::CommandFailed { ··· 366 378 modifiers: SubCommandModifiers, 367 379 ) -> Result<portable_pty::CommandBuilder, HiveLibError> { 368 380 let mut command = portable_pty::CommandBuilder::new("ssh"); 369 - command.args(target.create_ssh_args(modifiers)?); 381 + command.args(target.create_ssh_args(modifiers, false)?); 370 382 Ok(command) 371 383 } 372 384 ··· 378 390 failed_needle, 379 391 start_needle, 380 392 output_mode, 381 - collection, 393 + stdout_collection, 394 + stderr_collection, 382 395 completion_status, 383 396 } = arguments; 384 397 ··· 417 430 } 418 431 419 432 if began { 433 + if let Some(stripped) = line.strip_prefix('#') { 434 + output_mode.trace(stripped.to_string(), false); 435 + let mut queue = stdout_collection.lock().unwrap(); 436 + queue.push_front(stripped.to_string()); 437 + continue; 438 + } 439 + 420 440 let log = output_mode.trace(line.clone(), false); 441 + let mut queue = stderr_collection.lock().unwrap(); 421 442 422 443 if let Some(NixLog::Internal(log)) = log { 423 444 if let Some(message) = log.get_errorish_message() { 424 - let mut queue = collection.lock().unwrap(); 425 445 // add at most 10 message to the front, drop the rest. 426 446 queue.push_front(message); 427 447 queue.truncate(10);
+32 -22
wire/lib/src/commands/mod.rs
··· 6 6 sync::{Arc, Mutex}, 7 7 }; 8 8 9 - use itertools::Either; 10 - 11 9 use crate::{ 12 10 SubCommandModifiers, 13 11 commands::{ ··· 30 28 Nix, 31 29 } 32 30 33 - pub(crate) async fn get_elevated_command( 31 + #[derive(Debug)] 32 + pub enum Either<L, R> { 33 + Left(L), 34 + Right(R), 35 + } 36 + 37 + pub(crate) struct CommandArguments<S: AsRef<str>> { 38 + pub(crate) command_string: S, 39 + pub(crate) keep_stdin_open: bool, 40 + pub(crate) elevated: bool, 41 + pub(crate) clobber_lock: Arc<Mutex<()>>, 42 + } 43 + 44 + pub(crate) async fn get_command( 34 45 target: Option<&'_ Target>, 35 46 output_mode: ChildOutputMode, 36 47 modifiers: SubCommandModifiers, ··· 57 68 58 69 fn run_command<S: AsRef<str>>( 59 70 &mut self, 60 - command_string: S, 61 - keep_stdin_open: bool, 62 - clobber_lock: Arc<Mutex<()>>, 71 + command_arugments: CommandArguments<S>, 63 72 ) -> Result<Self::ChildChip, HiveLibError> { 64 - self.run_command_with_env( 65 - command_string, 66 - keep_stdin_open, 67 - std::collections::HashMap::new(), 68 - clobber_lock, 69 - ) 73 + self.run_command_with_env(command_arugments, std::collections::HashMap::new()) 70 74 } 71 75 72 76 fn run_command_with_env<S: AsRef<str>>( 73 77 &mut self, 74 - command_string: S, 75 - keep_stdin_open: bool, 78 + command_arugments: CommandArguments<S>, 76 79 args: HashMap<String, String>, 77 - clobber_lock: Arc<Mutex<()>>, 78 80 ) -> Result<Self::ChildChip, HiveLibError>; 79 81 } 80 82 ··· 99 101 100 102 fn run_command_with_env<S: AsRef<str>>( 101 103 &mut self, 102 - command_string: S, 103 - keep_stdin_open: bool, 104 - args: HashMap<String, String>, 105 - clobber_lock: Arc<Mutex<()>>, 104 + command_arugments: CommandArguments<S>, 105 + envs: HashMap<String, String>, 106 106 ) -> Result<Self::ChildChip, HiveLibError> { 107 107 match self { 108 108 Self::Left(left) => left 109 - .run_command_with_env(command_string, keep_stdin_open, args, clobber_lock) 109 + .run_command_with_env(command_arugments, envs) 110 110 .map(Either::Left), 111 111 Self::Right(right) => right 112 - .run_command_with_env(command_string, keep_stdin_open, args, clobber_lock) 112 + .run_command_with_env(command_arugments, envs) 113 113 .map(Either::Right), 114 114 } 115 115 } 116 116 } 117 117 118 + type ExitStatus = Either<(portable_pty::ExitStatus, String), (std::process::ExitStatus, String)>; 119 + 118 120 impl WireCommandChip for Either<InteractiveChildChip, NonInteractiveChildChip> { 119 - type ExitStatus = Either<portable_pty::ExitStatus, (std::process::ExitStatus, String)>; 121 + type ExitStatus = ExitStatus; 120 122 121 123 async fn write_stdin(&mut self, data: Vec<u8>) -> Result<(), HiveLibError> { 122 124 match self { ··· 129 131 match self { 130 132 Self::Left(left) => left.wait_till_success().await.map(Either::Left), 131 133 Self::Right(right) => right.wait_till_success().await.map(Either::Right), 134 + } 135 + } 136 + } 137 + 138 + impl ExitStatus { 139 + fn get_stdout(&self) -> &String { 140 + match self { 141 + Self::Left((_, stdout)) | Self::Right((_, stdout)) => stdout, 132 142 } 133 143 } 134 144 }
+12 -6
wire/lib/src/commands/noninteractive.rs
··· 18 18 19 19 use crate::{ 20 20 SubCommandModifiers, 21 - commands::{ChildOutputMode, WireCommand, WireCommandChip}, 21 + commands::{ChildOutputMode, CommandArguments, WireCommand, WireCommandChip}, 22 22 errors::{CommandError, HiveLibError}, 23 23 hive::node::Target, 24 24 nix_log::NixLog, ··· 60 60 61 61 fn run_command_with_env<S: AsRef<str>>( 62 62 &mut self, 63 - command_string: S, 64 - _keep_stdin_open: bool, 63 + arguments: CommandArguments<S>, 65 64 envs: HashMap<String, String>, 66 - _clobber_lock: Arc<std::sync::Mutex<()>>, 67 65 ) -> Result<Self::ChildChip, HiveLibError> { 68 66 let mut command = if let Some(target) = self.target { 69 67 create_sync_ssh_command(target, self.modifiers)? ··· 77 75 78 76 let command_string = format!( 79 77 "{command_string}{extra}", 80 - command_string = command_string.as_ref(), 78 + command_string = arguments.command_string.as_ref(), 81 79 extra = match *self.output_mode { 82 80 ChildOutputMode::Raw => "", 83 81 ChildOutputMode::Nix => " --log-format internal-json", 84 82 } 85 83 ); 84 + 85 + let command_string = if arguments.elevated { 86 + format!("sudo -u root -- sh -c '{command_string}'") 87 + } else { 88 + command_string 89 + }; 90 + 91 + debug!("{command_string}"); 86 92 87 93 command.arg(&command_string); 88 94 command.stdin(std::process::Stdio::piped()); ··· 204 210 modifiers: SubCommandModifiers, 205 211 ) -> Result<Command, HiveLibError> { 206 212 let mut command = Command::new("ssh"); 207 - command.args(target.create_ssh_args(modifiers)?); 213 + command.args(target.create_ssh_args(modifiers, true)?); 208 214 209 215 Ok(command) 210 216 }
+3 -1
wire/lib/src/hive/mod.rs
··· 43 43 impl Hive { 44 44 pub const SCHEMA_VERSION: u32 = 0; 45 45 46 - #[instrument] 46 + #[instrument(skip_all, name = "eval_hive")] 47 47 pub async fn new_from_path( 48 48 path: &Path, 49 49 modifiers: SubCommandModifiers, ··· 53 53 54 54 let output = 55 55 evaluate_hive_attribute(path, &EvalGoal::Inspect, modifiers, clobber_lock).await?; 56 + 57 + info!("evaluate_hive_attribute ouputted {output}"); 56 58 57 59 let hive: Hive = serde_json::from_str(&output).map_err(|err| { 58 60 HiveLibError::HiveInitializationError(HiveInitializationError::ParseEvaluateError(err))
+12 -8
wire/lib/src/hive/node.rs
··· 12 12 use tracing::{error, info, instrument, trace}; 13 13 14 14 use crate::SubCommandModifiers; 15 - use crate::commands::noninteractive::NonInteractiveCommand; 16 - use crate::commands::{ChildOutputMode, WireCommand, WireCommandChip}; 15 + use crate::commands::{ 16 + ChildOutputMode, CommandArguments, WireCommand, WireCommandChip, get_command, 17 + }; 17 18 use crate::errors::NetworkError; 18 19 use crate::hive::steps::build::Build; 19 20 use crate::hive::steps::evaluate::Evaluate; ··· 59 60 pub fn create_ssh_args( 60 61 &self, 61 62 modifiers: SubCommandModifiers, 63 + non_elevated_forced: bool, 62 64 ) -> Result<Vec<String>, HiveLibError> { 63 65 let mut vector = vec![ 64 66 "-l".to_string(), ··· 81 83 .to_string(), 82 84 ]); 83 85 84 - if modifiers.non_interactive { 86 + if modifiers.non_interactive || non_elevated_forced { 85 87 vector.extend(["-o".to_string(), "PasswordAuthentication=no".to_string()]); 86 88 vector.extend([ 87 89 "-o".to_string(), ··· 205 207 self.target.user, host 206 208 ); 207 209 208 - let mut command = 209 - NonInteractiveCommand::spawn_new(None, ChildOutputMode::Nix, modifiers).await?; 210 + let mut command = get_command(None, ChildOutputMode::Nix, modifiers).await?; 210 211 let output = command.run_command_with_env( 211 - command_string, 212 - false, 212 + CommandArguments { 213 + command_string, 214 + keep_stdin_open: false, 215 + elevated: false, 216 + clobber_lock, 217 + }, 213 218 HashMap::from([("NIX_SSHOPTS".into(), self.target.create_ssh_opts(modifiers))]), 214 - clobber_lock, 215 219 )?; 216 220 217 221 output.wait_till_success().await.map_err(|source| {
+24 -12
wire/lib/src/hive/steps/activate.rs
··· 7 7 8 8 use crate::{ 9 9 HiveLibError, 10 - commands::{ChildOutputMode, WireCommand, WireCommandChip, get_elevated_command}, 10 + commands::{ChildOutputMode, CommandArguments, WireCommand, WireCommandChip, get_command}, 11 11 errors::{ActivationError, NetworkError}, 12 12 hive::node::{Context, ExecuteStep, Goal, SwitchToConfigurationGoal, should_apply_locally}, 13 13 }; ··· 47 47 ) -> Result<(), HiveLibError> { 48 48 info!("Setting profiles in anticipation for switch-to-configuration {goal}"); 49 49 50 - let mut command = get_elevated_command( 50 + let mut command = get_command( 51 51 if should_apply_locally(ctx.node.allow_local_deployment, &ctx.name.to_string()) { 52 52 None 53 53 } else { ··· 59 59 .await?; 60 60 let command_string = format!("nix-env -p /nix/var/nix/profiles/system/ --set {built_path}"); 61 61 62 - let child = command.run_command(command_string, false, ctx.clobber_lock.clone())?; 62 + let child = command.run_command(CommandArguments { 63 + command_string, 64 + keep_stdin_open: false, 65 + elevated: true, 66 + clobber_lock: ctx.clobber_lock.clone(), 67 + })?; 63 68 64 69 let _ = child 65 70 .wait_till_success() ··· 93 98 94 99 info!("Running switch-to-configuration {goal}"); 95 100 96 - let mut command = get_elevated_command( 101 + let mut command = get_command( 97 102 if should_apply_locally(ctx.node.allow_local_deployment, &ctx.name.to_string()) { 98 103 None 99 104 } else { ··· 114 119 } 115 120 ); 116 121 117 - let child = command.run_command(command_string, false, ctx.clobber_lock.clone())?; 122 + let child = command.run_command(CommandArguments { 123 + command_string, 124 + keep_stdin_open: false, 125 + elevated: true, 126 + clobber_lock: ctx.clobber_lock.clone(), 127 + })?; 118 128 119 129 let result = child.wait_till_success().await; 120 130 ··· 130 140 return Ok(()); 131 141 } 132 142 133 - let mut command = get_elevated_command( 134 - Some(&ctx.node.target), 135 - ChildOutputMode::Nix, 136 - ctx.modifiers, 137 - ) 138 - .await?; 143 + let mut command = 144 + get_command(Some(&ctx.node.target), ChildOutputMode::Nix, ctx.modifiers) 145 + .await?; 139 146 140 147 warn!("Rebooting {name}!", name = ctx.name); 141 148 142 - let reboot = command.run_command("reboot now", false, ctx.clobber_lock.clone())?; 149 + let reboot = command.run_command(CommandArguments { 150 + command_string: "reboot now", 151 + keep_stdin_open: false, 152 + elevated: true, 153 + clobber_lock: ctx.clobber_lock.clone(), 154 + })?; 143 155 144 156 // consume result, impossible to know if the machine failed to reboot or we 145 157 // simply disconnected
+8 -2
wire/lib/src/hive/steps/build.rs
··· 8 8 use crate::{ 9 9 HiveLibError, 10 10 commands::{ 11 - ChildOutputMode, WireCommand, WireCommandChip, noninteractive::NonInteractiveCommand, 11 + ChildOutputMode, CommandArguments, WireCommand, WireCommandChip, 12 + noninteractive::NonInteractiveCommand, 12 13 }, 13 14 hive::node::{Context, ExecuteStep, Goal}, 14 15 }; ··· 48 49 .await?; 49 50 50 51 let (_, stdout) = command 51 - .run_command(command_string, false, ctx.clobber_lock.clone())? 52 + .run_command(CommandArguments { 53 + command_string, 54 + keep_stdin_open: false, 55 + elevated: false, 56 + clobber_lock: ctx.clobber_lock.clone(), 57 + })? 52 58 .wait_till_success() 53 59 .await 54 60 .map_err(|source| HiveLibError::NixBuildError {
+10 -3
wire/lib/src/hive/steps/keys.rs
··· 24 24 25 25 use crate::HiveLibError; 26 26 use crate::commands::common::push; 27 - use crate::commands::{ChildOutputMode, WireCommand, WireCommandChip, get_elevated_command}; 27 + use crate::commands::{ 28 + ChildOutputMode, CommandArguments, WireCommand, WireCommandChip, get_command, 29 + }; 28 30 use crate::errors::KeyError; 29 31 use crate::hive::node::{ 30 32 Context, ExecuteStep, Goal, Push, SwitchToConfigurationGoal, should_apply_locally, ··· 230 232 return Ok(()); 231 233 } 232 234 233 - let mut command = get_elevated_command( 235 + let mut command = get_command( 234 236 if should_apply_locally(ctx.node.allow_local_deployment, &ctx.name.to_string()) { 235 237 None 236 238 } else { ··· 242 244 .await?; 243 245 let command_string = format!("{agent_directory}/bin/key_agent"); 244 246 245 - let mut child = command.run_command(command_string, true, ctx.clobber_lock.clone())?; 247 + let mut child = command.run_command(CommandArguments { 248 + command_string, 249 + keep_stdin_open: true, 250 + elevated: true, 251 + clobber_lock: ctx.clobber_lock.clone(), 252 + })?; 246 253 247 254 let mut writer = SimpleLengthDelimWriter::new(async |data| child.write_stdin(data).await); 248 255
+13 -1
wire/lib/src/lib.rs
··· 9 9 )] 10 10 #![feature(assert_matches)] 11 11 12 + use std::io::IsTerminal; 13 + 12 14 use crate::{errors::HiveLibError, hive::node::Name}; 13 15 14 16 pub mod commands; ··· 23 25 24 26 pub mod errors; 25 27 26 - #[derive(Debug, Default, Clone, Copy)] 28 + #[derive(Debug, Clone, Copy)] 27 29 pub struct SubCommandModifiers { 28 30 pub show_trace: bool, 29 31 pub non_interactive: bool, 30 32 pub ssh_accept_host: bool, 33 + } 34 + 35 + impl Default for SubCommandModifiers { 36 + fn default() -> Self { 37 + SubCommandModifiers { 38 + show_trace: false, 39 + non_interactive: !std::io::stdin().is_terminal(), 40 + ssh_accept_host: false, 41 + } 42 + } 31 43 } 32 44 33 45 pub enum EvalGoal<'a> {