Skip to content

Commit

Permalink
Add better APIs for making shh:ed files executable
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkusPettersson98 committed Dec 13, 2024
1 parent f00ed9a commit 2f76509
Showing 1 changed file with 54 additions and 4 deletions.
58 changes: 54 additions & 4 deletions test/test-manager/src/vm/provision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -185,6 +185,18 @@ fn ssh_send_file<P: AsRef<Path> + Copy>(
session: &Session,
source: P,
dest_dir: &Path,
) -> Result<PathBuf> {
ssh_send_file_with_opts(session, source, dest_dir, FileOpts::default())
}

/// Copy a `source` file to `dest_dir` in the test runner with opts.
///
/// Returns the absolute path in the test runner where the file is stored.
fn ssh_send_file_with_opts<P: AsRef<Path> + Copy>(
session: &Session,
source: P,
dest_dir: &Path,
opts: FileOpts,
) -> Result<PathBuf> {
let dest = dest_dir.join(
source
Expand All @@ -202,18 +214,56 @@ fn ssh_send_file<P: AsRef<Path> + 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 mut remote_file = ssh_write(session, &dest, &source[..])?;

if opts.executable {
make_executable(&mut remote_file)?;
}

Ok(dest)
}

/// Analogues to [`std::fs::write`], but over ssh!
fn ssh_write<P: AsRef<Path>>(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<P: AsRef<Path>>(session: &Session, dest: P, source: impl Read) -> Result<File> {
ssh_write_with_opts(session, dest, source, FileOpts::default())
}

/// Create a new file with opts at location `dest` and write the content of `source` into it.
/// Returns a handle to the newly created file.
fn ssh_write_with_opts<P: AsRef<Path>>(
session: &Session,
dest: P,
mut source: impl Read,
opts: FileOpts,
) -> Result<File> {
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")?;

if opts.executable {
make_executable(&mut remote_file)?;
};

Ok(remote_file)
}

/// Extra options that may be necessary to configure for files written to the test runner VM.
/// Used in conjunction with the `ssh_*_with_opts` functions.
#[derive(Clone, Copy, Debug, Default)]
struct FileOpts {
/// If file should be executable.
executable: bool,
}

fn make_executable(file: &mut 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(())
}

Expand Down

0 comments on commit 2f76509

Please sign in to comment.