summaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
authorMarkus Pettersson <markus.pettersson@mullvad.net>2024-12-13 08:49:04 +0100
committerMarkus Pettersson <markus.pettersson@mullvad.net>2024-12-17 12:00:26 +0100
commit6ea9b991279218886cc6bc9959ccfceeb13f4e1d (patch)
tree246967a66a05a60480d435ad4c96d2f583c6d021 /test
parente7b3c7a03b5b284676628b5ec2e25c31af279a02 (diff)
downloadmullvadvpn-6ea9b991279218886cc6bc9959ccfceeb13f4e1d.tar.xz
mullvadvpn-6ea9b991279218886cc6bc9959ccfceeb13f4e1d.zip
Add better APIs for making shh:ed files executable
Diffstat (limited to 'test')
-rw-r--r--test/test-manager/src/vm/provision.rs53
1 files changed, 41 insertions, 12 deletions
diff --git a/test/test-manager/src/vm/provision.rs b/test/test-manager/src/vm/provision.rs
index 7bda85f2a4..1ca962cbfb 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,27 +115,27 @@ fn blocking_ssh(
let temp_dir = Path::new(remote_temp_dir);
// Transfer a test runner
let source = local_runner_dir.join("test-runner");
- ssh_send_file(&session, &source, temp_dir)
+ ssh_send_file_with_opts(&session, &source, temp_dir, FileOpts { executable: true })
.with_context(|| format!("Failed to send '{source:?}' to remote"))?;
// Transfer connection-checker
let source = local_runner_dir.join("connection-checker");
- ssh_send_file(&session, &source, temp_dir)
+ ssh_send_file_with_opts(&session, &source, temp_dir, FileOpts { executable: true })
.with_context(|| format!("Failed to send '{source:?}' to remote"))?;
// Transfer app packages
let source = &local_app_manifest.app_package_path;
- ssh_send_file(&session, source, temp_dir)
+ ssh_send_file_with_opts(&session, source, temp_dir, FileOpts { executable: true })
.with_context(|| format!("Failed to send '{source:?}' to remote"))?;
if let Some(source) = &local_app_manifest.app_package_to_upgrade_from_path {
- ssh_send_file(&session, source, temp_dir)
+ ssh_send_file_with_opts(&session, source, temp_dir, FileOpts { executable: true })
.with_context(|| format!("Failed to send '{source:?}' to remote"))?;
} else {
log::warn!("No previous app package to upgrade from to send to remote")
}
if let Some(source) = &local_app_manifest.gui_package_path {
- ssh_send_file(&session, source, temp_dir)
+ ssh_send_file_with_opts(&session, source, temp_dir, FileOpts { executable: true })
.with_context(|| format!("Failed to send '{source:?}' to remote"))?;
} else {
log::warn!("No UI e2e test to send to remote")
@@ -182,13 +182,14 @@ fn blocking_ssh(
Ok(remote_dir.to_string())
}
-/// Copy a `source` file to `dest_dir` in the test runner.
+/// Copy a `source` file to `dest_dir` in the test runner with opts.
///
-/// Returns the aboslute path in the test runner where the file is stored.
-fn ssh_send_file<P: AsRef<Path> + Copy>(
+/// 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
@@ -206,18 +207,46 @@ 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[..])?;
+ ssh_write_with_opts(session, &dest, &source[..], opts)?;
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 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(())
}