Output the logs to the file and return the log URL to the server
This commit is contained in:
parent
b47b1943cd
commit
433239f47d
|
@ -19,3 +19,4 @@ Cargo.lock
|
||||||
# Added by cargo
|
# Added by cargo
|
||||||
|
|
||||||
/target
|
/target
|
||||||
|
agent-logs/
|
||||||
|
|
|
@ -15,7 +15,7 @@ path = "src/agent/main.rs"
|
||||||
async-std = { version = "1", features = ["attributes"] }
|
async-std = { version = "1", features = ["attributes"] }
|
||||||
chrono = "0.4.15"
|
chrono = "0.4.15"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
dotenv = "~0.15.0"
|
dotenv = "~0.15"
|
||||||
driftwood = "0"
|
driftwood = "0"
|
||||||
handlebars = { version = "~3.4.0", features = ["dir_source"] }
|
handlebars = { version = "~3.4.0", features = ["dir_source"] }
|
||||||
html-escape = "~0.2.6"
|
html-escape = "~0.2.6"
|
||||||
|
@ -25,5 +25,5 @@ pretty_env_logger = "~0.3.1"
|
||||||
serde_json = "~1.0.0"
|
serde_json = "~1.0.0"
|
||||||
sqlx = { version = "~0.5.1", features = ["chrono", "json", "migrate", "offline", "sqlite", "uuid", "runtime-async-std-rustls"] }
|
sqlx = { version = "~0.5.1", features = ["chrono", "json", "migrate", "offline", "sqlite", "uuid", "runtime-async-std-rustls"] }
|
||||||
tide = "0"
|
tide = "0"
|
||||||
uuid = { version = "0", features = ["v4", "serde"]}
|
uuid = { version = "1", features = ["v4", "serde"]}
|
||||||
url = "2"
|
url = "2"
|
||||||
|
|
|
@ -88,6 +88,12 @@ components:
|
||||||
stream:
|
stream:
|
||||||
description: 'URL to streaming WebSockets logs'
|
description: 'URL to streaming WebSockets logs'
|
||||||
type: string
|
type: string
|
||||||
|
format: url
|
||||||
task:
|
task:
|
||||||
description: 'URL to the task metadata'
|
description: 'URL to the task metadata'
|
||||||
type: string
|
type: string
|
||||||
|
format: url
|
||||||
|
log:
|
||||||
|
description: 'URL to the raw log of the task run'
|
||||||
|
type: string
|
||||||
|
format: url
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
|
const AGENT_LOGS_DIR: &str = "agent-logs";
|
||||||
|
|
||||||
mod caps;
|
mod caps;
|
||||||
|
|
||||||
mod routes {
|
mod routes {
|
||||||
|
@ -18,9 +22,14 @@ mod routes {
|
||||||
|
|
||||||
pub mod api {
|
pub mod api {
|
||||||
use crate::caps::*;
|
use crate::caps::*;
|
||||||
use janky::CommandRequest;
|
use crate::AGENT_LOGS_DIR;
|
||||||
|
use janky::{CommandRequest, CommandResponse};
|
||||||
use log::*;
|
use log::*;
|
||||||
use tide::{Body, Request};
|
use tide::{Body, Request};
|
||||||
|
use url::Url;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
pub fn register(app: &mut tide::Server<()>) {
|
pub fn register(app: &mut tide::Server<()>) {
|
||||||
app.at("/api/v1/capabilities").get(get_caps);
|
app.at("/api/v1/capabilities").get(get_caps);
|
||||||
|
@ -35,14 +44,23 @@ mod routes {
|
||||||
pub async fn execute(mut req: Request<()>) -> Result<Body, tide::Error> {
|
pub async fn execute(mut req: Request<()>) -> Result<Body, tide::Error> {
|
||||||
let c: CommandRequest = req.body_json().await?;
|
let c: CommandRequest = req.body_json().await?;
|
||||||
debug!("Commands to exec: {:?}", c);
|
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() {
|
for command in c.commands.iter() {
|
||||||
use os_pipe::pipe;
|
use os_pipe::pipe;
|
||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader, Write};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
let mut cmd = Command::new("sh");
|
let mut cmd = Command::new("sh");
|
||||||
cmd.args(["-c", &command.script]);
|
cmd.args(["-xec", &command.script]);
|
||||||
let (reader, writer) = pipe().unwrap();
|
let (mut reader, writer) = pipe().unwrap();
|
||||||
let writer_clone = writer.try_clone().unwrap();
|
let writer_clone = writer.try_clone().unwrap();
|
||||||
cmd.stdout(writer);
|
cmd.stdout(writer);
|
||||||
cmd.stderr(writer_clone);
|
cmd.stderr(writer_clone);
|
||||||
|
@ -50,18 +68,22 @@ mod routes {
|
||||||
drop(cmd);
|
drop(cmd);
|
||||||
|
|
||||||
debug!("executing: {}", &command.script);
|
debug!("executing: {}", &command.script);
|
||||||
let bufr = BufReader::new(reader);
|
std::io::copy(&mut reader, &mut bufw);
|
||||||
for line in bufr.lines() {
|
|
||||||
if let Ok(buffer) = line {
|
|
||||||
debug!("output: {}", buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let status = handle.wait()?;
|
let status = handle.wait()?;
|
||||||
debug!("status of {}: {:?}", &command.script, status);
|
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);
|
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");
|
debug!("Configuring routes");
|
||||||
app.at("/").get(routes::index);
|
app.at("/").get(routes::index);
|
||||||
|
app.at("/agent-logs").serve_dir(AGENT_LOGS_DIR);
|
||||||
routes::api::register(&mut app);
|
routes::api::register(&mut app);
|
||||||
app.listen("0.0.0.0:9000").await?;
|
app.listen("0.0.0.0:9000").await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -31,9 +31,10 @@ pub struct CommandRequest {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
|
||||||
pub struct CommandResponse {
|
pub struct CommandResponse {
|
||||||
uuid: Uuid,
|
pub uuid: Uuid,
|
||||||
stream_url: Option<Url>,
|
pub stream: Option<Url>,
|
||||||
task_url: Url,
|
pub task: Option<Url>,
|
||||||
|
pub log: Url,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in New Issue