Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix async eldritch functions crashing golem/imix. #148

Merged
merged 21 commits into from Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 24 additions & 2 deletions implants/eldritch/src/lib.rs
Expand Up @@ -29,6 +29,7 @@ pub fn get_eldritch() -> anyhow::Result<Globals> {
}

pub fn eldritch_run(tome_filename: String, tome_contents: String, tome_parameters: Option<String>) -> anyhow::Result<String> {
// Boilder plate
let ast: AstModule;
match AstModule::parse(
&tome_filename,
Expand All @@ -41,7 +42,7 @@ pub fn eldritch_run(tome_filename: String, tome_contents: String, tome_parameter

let tome_params_str: String = match tome_parameters {
Some(param_string) => param_string,
None => "".to_string(),
None => "{}".to_string(),
};

let globals = get_eldritch()?;
Expand All @@ -50,7 +51,7 @@ pub fn eldritch_run(tome_filename: String, tome_contents: String, tome_parameter

let res: SmallMap<Value, Value> = SmallMap::new();
let mut input_params: Dict = Dict::new(res);

let parsed: serde_json::Value = serde_json::from_str(&tome_params_str)?;
let param_map: serde_json::Map<String, serde_json::Value> = match parsed.as_object() {
Some(tmp_param_map) => tmp_param_map.clone(),
Expand Down Expand Up @@ -110,10 +111,13 @@ pub fn eldritch_run(tome_filename: String, tome_contents: String, tome_parameter

#[cfg(test)]
mod tests {
use std::thread;

use super::*;
use starlark::environment::{GlobalsBuilder};
use starlark::{starlark_module};
use starlark::assert::Assert;
use tempfile::NamedTempFile;

use super::file::FileLibrary;
use super::process::ProcessLibrary;
Expand Down Expand Up @@ -191,4 +195,22 @@ input_params
Ok(())
}

#[tokio::test]
async fn test_library_async() -> anyhow::Result<()> {
// just using a temp file for its path
let tmp_file = NamedTempFile::new()?;
let path = String::from(tmp_file.path().to_str().unwrap()).clone();

let test_content = format!(r#"
file.download("https://www.google.com/", "{path}")
"#);

let test_res = thread::spawn(|| { eldritch_run("test.tome".to_string(), test_content, None) });
let _ = test_res.join();

assert!(tmp_file.as_file().metadata().unwrap().len() > 5);
let _ = tmp_file.close();
hulto marked this conversation as resolved.
Show resolved Hide resolved
Ok(())
}

}
45 changes: 18 additions & 27 deletions implants/golem/src/main.rs
Expand Up @@ -2,22 +2,14 @@ extern crate golem;
extern crate eldritch;

use clap::{Command, Arg};
use tokio::task;
use std::fs;
use std::process;
use std::thread;

use eldritch::{eldritch_run};

mod inter;


async fn run(tome_path: String) -> anyhow::Result<String> {
// Read a tome script
let tome_contents = fs::read_to_string(tome_path.clone())?;
// Execute a tome script
eldritch_run(tome_path, tome_contents, None)
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let matches = Command::new("golem")
Expand All @@ -37,31 +29,32 @@ async fn main() -> anyhow::Result<()> {
// Queue async tasks
let mut all_tome_futures: Vec<(String, _)> = vec![];
for tome in tome_files {
let tome_execution_task = run(tome.to_string());
let tmp_row = (tome.to_string(), task::spawn(tome_execution_task));
let tome_path = tome.to_string().clone();
let tome_contents = fs::read_to_string(tome_path.clone())?;
let tmp_row = (tome.to_string(), thread::spawn(|| { eldritch_run(tome_path, tome_contents, None) }));
all_tome_futures.push(tmp_row)
}


let mut error_code = 0;
// Collect results and do error handling
let mut result: Vec<String> = Vec::new();
for tome_task in all_tome_futures {
// Get the name of the file from our tuple.
let tome_name: String = tome_task.0;
match tome_task.1.await {
// Match on task results.
Ok(res) => match res {
Ok(task_res) => result.push(task_res),
Err(task_err) => {
eprintln!("[TASK ERROR] {tome_name}: {task_err}");
error_code = 1;
}
},

Err(err) => {
eprintln!("[ERROR] {tome_name}: {err}");
// Join our
let tome_result_thread_join = match tome_task.1.join() {
Ok(local_thread_join_res) => local_thread_join_res,
Err(_) => {
error_code = 1;
Err(anyhow::anyhow!("An error occured waiting for the tome thread to complete while executing {tome_name}."))
},
};

match tome_result_thread_join {
Ok(local_tome_result) => result.push(local_tome_result),
Err(task_error) => {
error_code = 1;
eprintln!("[TASK ERROR] {tome_name}: {task_error}");
}
}
}
if result.len() > 0 {
Expand All @@ -73,5 +66,3 @@ async fn main() -> anyhow::Result<()> {
}
Ok(())
}


18 changes: 16 additions & 2 deletions implants/golem/tests/cli.rs
Expand Up @@ -12,7 +12,7 @@ fn test_golem_main_file_not_found() -> anyhow::Result<()> {
cmd.arg("nonexistentdir/run.tome");
cmd.assert()
.failure()
.stderr(predicate::str::contains("[TASK ERROR] nonexistentdir/run.tome: No such file or directory (os error 2)"));
.stderr(predicate::str::contains("Error: No such file or directory"));

Ok(())
}
Expand Down Expand Up @@ -53,7 +53,21 @@ fn test_golem_main_basic_eldritch_non_interactive() -> anyhow::Result<()> {
cmd.arg("working_dir/tomes/eldritch_test.tome");
cmd.assert()
.success()
.stdout(predicate::str::contains("[\"[\\\"append\\\", \\\"copy\\\", \\\"download\\\", \\\"exists\\\", \\\"hash\\\", \\\"is_dir\\\", \\\"is_file\\\", \\\"mkdir\\\", \\\"read\\\", \\\"remove\\\", \\\"rename\\\", \\\"replace\\\", \\\"replace_all\\\", \\\"timestomp\\\", \\\"write\\\"]\"]"));
.stdout(predicate::str::contains(r#"[\"append\", \"compress\""#));

Ok(())
}


// Test running `./golem ./working_dir/tomes/eldritch_test.tome`
#[test]
fn test_golem_main_basic_async() -> anyhow::Result<()> {
let mut cmd = Command::cargo_bin("golem")?;

cmd.arg("working_dir/tomes/download_test.tome");
cmd.assert()
.success()
.stderr(predicate::str::contains(r#"OKAY!"#));

Ok(())
}
Expand Down
2 changes: 2 additions & 0 deletions implants/golem/working_dir/tomes/download_test.tome
@@ -0,0 +1,2 @@
file.download("https://github.com/KCarretto/realm/releases/download/v0.0.1/imix-linux-x64","/tmp/abc")
print("OKAY!")
7 changes: 6 additions & 1 deletion implants/imix/src/main.rs
@@ -1,3 +1,4 @@
use std::thread;
use std::{collections::HashMap, fs};
use std::fs::File;
use std::io::Write;
Expand Down Expand Up @@ -40,7 +41,11 @@ async fn handle_exec_tome(task: GraphQLTask) -> Result<(String,String)> {
let tome_contents = task_job.tome.eldritch;

// Execute a tome script
let res = eldritch_run(tome_name, tome_contents, task_job.tome.parameters);
let res = match thread::spawn(|| { eldritch_run(tome_name, tome_contents, task_job.tome.parameters) }).join() {
Ok(local_thread_res) => local_thread_res,
Err(_) => todo!(),
};

match res {
Ok(tome_output) => Ok((tome_output, "".to_string())),
Err(tome_error) => Ok(("".to_string(), tome_error.to_string())),
Expand Down