From ea43a8d4597db7b07bb4f34815f7646b32902f63 Mon Sep 17 00:00:00 2001 From: Markus Pettersson Date: Wed, 11 Dec 2024 12:56:09 +0100 Subject: [PATCH] WIP Squash into sftp commit / make uploaded files executable --- test/test-manager/src/vm/provision.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/test/test-manager/src/vm/provision.rs b/test/test-manager/src/vm/provision.rs index 6fd14ed4d87d..b2ef9d68ddea 100644 --- a/test/test-manager/src/vm/provision.rs +++ b/test/test-manager/src/vm/provision.rs @@ -4,7 +4,7 @@ use crate::{ tests::config::BOOTSTRAP_SCRIPT, }; use anyhow::{bail, Context, Result}; -use ssh2::Session; +use ssh2::{File, Session}; use std::{ io::{self, Read}, net::{IpAddr, SocketAddr, TcpStream}, @@ -115,6 +115,7 @@ fn blocking_ssh( let temp_dir = Path::new(remote_temp_dir); // Transfer a test runner let source = local_runner_dir.join("test-runner"); + // TODO: Create good API for making these files executable if necessary ssh_send_file(&session, &source, temp_dir) .with_context(|| format!("Failed to send '{source:?}' to remote"))?; @@ -145,8 +146,10 @@ fn blocking_ssh( // TODO: Move this name to a constant somewhere? if matches!(os_type, OsType::Linux | OsType::Macos) { let bootstrap_script_dest = temp_dir.join("ssh-setup.sh"); - ssh_write(&session, &bootstrap_script_dest, BOOTSTRAP_SCRIPT) + let bootstrap_script = ssh_write(&session, &bootstrap_script_dest, BOOTSTRAP_SCRIPT) .context("failed to send bootstrap script to remote")?; + // Make sure that the script is executable! + make_executable(bootstrap_script)?; // Run setup script let app_package_path = local_app_manifest @@ -201,19 +204,31 @@ fn ssh_send_file + Copy>( let source = std::fs::read(source) .with_context(|| format!("Failed to open file at {}", source.as_ref().display()))?; - ssh_write(session, &dest, &source[..])?; + let remote_file = ssh_write(session, &dest, &source[..])?; + make_executable(remote_file)?; Ok(dest) } -/// Analogues to [`std::fs::write`], but over ssh! -fn ssh_write>(session: &Session, dest: P, mut source: impl Read) -> Result<()> { +/// Create a new file at location `dest` and write the content of `source` into it. +/// Returns a handle to the newly created file. +fn ssh_write>(session: &Session, dest: P, mut source: impl Read) -> Result { let sftp = session.sftp()?; let mut remote_file = sftp.create(dest.as_ref())?; io::copy(&mut source, &mut remote_file).context("failed to write file")?; - Ok(()) + Ok(remote_file) +} + +fn make_executable(mut file: File) -> Result { + // Make sure that the script is executable! + let mut file_stat = file.stat()?; + // 0x111 is the executable bit for Owner/Group/Public + let perm = file_stat.perm.map(|perm| perm | 0x111).unwrap_or(0x111); + file_stat.perm = Some(perm); + file.setstat(file_stat)?; + Ok(file) } /// Execute an arbitrary string of commands via ssh.