diff --git a/.gitignore b/.gitignore index 193d30e..6c972e9 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ Cargo.lock # Added by cargo /target +agent-logs/ diff --git a/.ignore b/.ignore new file mode 100644 index 0000000..fa7b49c --- /dev/null +++ b/.ignore @@ -0,0 +1 @@ +agent-logs/ diff --git a/Cargo.toml b/Cargo.toml index 9841179..bf257b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ path = "src/agent/main.rs" async-std = { version = "1", features = ["attributes"] } chrono = "0.4.15" serde = { version = "1.0", features = ["derive"] } -dotenv = "~0.15.0" +dotenv = "~0.15" driftwood = "0" handlebars = { version = "~3.4.0", features = ["dir_source"] } html-escape = "~0.2.6" @@ -25,5 +25,5 @@ pretty_env_logger = "~0.3.1" serde_json = "~1.0.0" sqlx = { version = "~0.5.1", features = ["chrono", "json", "migrate", "offline", "sqlite", "uuid", "runtime-async-std-rustls"] } tide = "0" -uuid = { version = "0", features = ["v4", "serde"]} +uuid = { version = "1", features = ["v4", "serde"]} url = "2" diff --git a/agent-api-description.yml b/agent-api-description.yml index 1f0b1e4..e76d3fc 100644 --- a/agent-api-description.yml +++ b/agent-api-description.yml @@ -88,6 +88,12 @@ components: stream: description: 'URL to streaming WebSockets logs' type: string + format: url task: description: 'URL to the task metadata' type: string + format: url + log: + description: 'URL to the raw log of the task run' + type: string + format: url diff --git a/src/agent/main.rs b/src/agent/main.rs index 68a4260..8b7bb47 100644 --- a/src/agent/main.rs +++ b/src/agent/main.rs @@ -1,9 +1,13 @@ #[macro_use] extern crate serde_json; +use std::path::PathBuf; + use dotenv::dotenv; use log::*; +const AGENT_LOGS_DIR: &str = "agent-logs"; + mod caps; mod routes { @@ -18,9 +22,14 @@ mod routes { pub mod api { use crate::caps::*; - use janky::CommandRequest; + use crate::AGENT_LOGS_DIR; + use janky::{CommandRequest, CommandResponse}; use log::*; use tide::{Body, Request}; + use url::Url; + use uuid::Uuid; + + use std::path::Path; pub fn register(app: &mut tide::Server<()>) { app.at("/api/v1/capabilities").get(get_caps); @@ -35,14 +44,23 @@ mod routes { pub async fn execute(mut req: Request<()>) -> Result { let c: CommandRequest = req.body_json().await?; debug!("Commands to exec: {:?}", c); + let uuid = Uuid::new_v4(); + // Create my log directory + let log_dir = Path::new(AGENT_LOGS_DIR).join(uuid.hyphenated().to_string()); + // TODO: Handle this error + std::fs::create_dir(log_dir.clone()); + + let log_file_path = log_dir.join("console.log"); + let log_file = std::fs::File::create(log_file_path.clone()).unwrap(); + let mut bufw = std::io::BufWriter::new(log_file); for command in c.commands.iter() { use os_pipe::pipe; - use std::io::{BufRead, BufReader}; + use std::io::{BufRead, BufReader, Write}; use std::process::Command; let mut cmd = Command::new("sh"); - cmd.args(["-c", &command.script]); - let (reader, writer) = pipe().unwrap(); + cmd.args(["-xec", &command.script]); + let (mut reader, writer) = pipe().unwrap(); let writer_clone = writer.try_clone().unwrap(); cmd.stdout(writer); cmd.stderr(writer_clone); @@ -50,18 +68,22 @@ mod routes { drop(cmd); debug!("executing: {}", &command.script); - let bufr = BufReader::new(reader); - for line in bufr.lines() { - if let Ok(buffer) = line { - debug!("output: {}", buffer); - } - } + std::io::copy(&mut reader, &mut bufw); let status = handle.wait()?; debug!("status of {}: {:?}", &command.script, status); } - Ok("{}".into()) + let response = CommandResponse { + uuid, + stream: None, + task: None, + log: req + .url() + .join(&format!("../../{}", log_file_path.display())) + .unwrap(), + }; + Ok(Body::from_json(&response)?) } /* @@ -92,8 +114,16 @@ async fn main() -> Result<(), tide::Error> { app.with(driftwood::ApacheCombinedLogger); } + /* + * Create a logs directory if it doesn't exist + */ + if !PathBuf::from(AGENT_LOGS_DIR).is_dir() { + std::fs::create_dir(AGENT_LOGS_DIR).expect("Failed to create agent logs directory"); + } + debug!("Configuring routes"); app.at("/").get(routes::index); + app.at("/agent-logs").serve_dir(AGENT_LOGS_DIR); routes::api::register(&mut app); app.listen("0.0.0.0:9000").await?; Ok(()) diff --git a/src/lib.rs b/src/lib.rs index e8d233a..0ab351e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,9 +31,10 @@ pub struct CommandRequest { #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] pub struct CommandResponse { - uuid: Uuid, - stream_url: Option, - task_url: Url, + pub uuid: Uuid, + pub stream: Option, + pub task: Option, + pub log: Url, } #[cfg(test)]