|
|
|
@ -2,7 +2,7 @@ use crate::{ |
|
|
|
|
combined_result::CombinedResult, |
|
|
|
|
executor::{ExecResult, Waiter}, |
|
|
|
|
misc::OneOrVec, |
|
|
|
|
models::{Agent, AssignedJob, AssignedJobById, FatJobMeta, JobType, Payload, ThinJobMeta}, |
|
|
|
|
models::{Agent, AssignedJob, AssignedJobById, FatJob, JobType, RawJob, ThinJob}, |
|
|
|
|
proc_output::ProcOutput, |
|
|
|
|
ufs, |
|
|
|
|
}; |
|
|
|
@ -16,11 +16,10 @@ pub struct AnonymousJobBatch { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl AnonymousJobBatch { |
|
|
|
|
pub fn from_meta_with_id(jobs: impl OneOrVec<(ThinJobMeta, AssignedJobById)>) -> Self { |
|
|
|
|
let jobs = jobs.into_vec(); |
|
|
|
|
pub fn from_meta_with_id(jobs: impl OneOrVec<(ThinJob, AssignedJobById)>) -> Self { |
|
|
|
|
let mut waiter = Waiter::new(); |
|
|
|
|
for (meta, job) in jobs { |
|
|
|
|
waiter.push(run_assigned_job(meta, job)); |
|
|
|
|
for (job, ids) in jobs.into_vec() { |
|
|
|
|
waiter.push(run_assigned_job(job, ids)); |
|
|
|
|
} |
|
|
|
|
Self { |
|
|
|
|
waiter, |
|
|
|
@ -28,14 +27,14 @@ impl AnonymousJobBatch { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn from_meta(metas: impl OneOrVec<ThinJobMeta>) -> Self { |
|
|
|
|
let jobs: Vec<_> = metas |
|
|
|
|
pub fn from_meta(jobs: impl OneOrVec<ThinJob>) -> Self { |
|
|
|
|
let jobs_ids: Vec<_> = jobs |
|
|
|
|
.into_vec() |
|
|
|
|
.into_iter() |
|
|
|
|
.map(|meta| { |
|
|
|
|
let job_id = meta.id; |
|
|
|
|
.map(|job| { |
|
|
|
|
let job_id = job.job.id; |
|
|
|
|
( |
|
|
|
|
meta, |
|
|
|
|
job, |
|
|
|
|
AssignedJobById { |
|
|
|
|
job_id, |
|
|
|
|
..Default::default() |
|
|
|
@ -43,7 +42,7 @@ impl AnonymousJobBatch { |
|
|
|
|
) |
|
|
|
|
}) |
|
|
|
|
.collect(); |
|
|
|
|
AnonymousJobBatch::from_meta_with_id(jobs) |
|
|
|
|
AnonymousJobBatch::from_meta_with_id(jobs_ids) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Spawn jobs
|
|
|
|
@ -85,18 +84,8 @@ impl NamedJobBatch { |
|
|
|
|
.into_vec() |
|
|
|
|
.into_iter() |
|
|
|
|
.filter_map(|(alias, cmd)| { |
|
|
|
|
match FatJobMeta::builder() |
|
|
|
|
.with_shell(cmd) |
|
|
|
|
.with_alias(alias) |
|
|
|
|
.build() |
|
|
|
|
{ |
|
|
|
|
Ok(fat_meta) => match fat_meta_to_thin(fat_meta) { |
|
|
|
|
Ok(thin_meta) => Some(thin_meta), |
|
|
|
|
Err(e) => { |
|
|
|
|
result.err(e); |
|
|
|
|
None |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
match RawJob::builder().with_shell(cmd).with_alias(alias).build() { |
|
|
|
|
Ok(jpm) => Some(jpm), |
|
|
|
|
Err(e) => { |
|
|
|
|
result.err(e); |
|
|
|
|
None |
|
|
|
@ -108,14 +97,14 @@ impl NamedJobBatch { |
|
|
|
|
result |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn from_meta(named_jobs: impl OneOrVec<ThinJobMeta>) -> Self { |
|
|
|
|
let (job_names, job_metas): (Vec<_>, Vec<_>) = named_jobs |
|
|
|
|
pub fn from_meta(named_jobs: impl OneOrVec<ThinJob>) -> Self { |
|
|
|
|
let (job_names, jobs): (Vec<_>, Vec<_>) = named_jobs |
|
|
|
|
.into_vec() |
|
|
|
|
.into_iter() |
|
|
|
|
.map(|meta| (meta.alias.clone().unwrap(), meta)) |
|
|
|
|
.map(|job| (job.job.alias.clone().unwrap(), job)) |
|
|
|
|
.unzip(); |
|
|
|
|
Self { |
|
|
|
|
runner: Some(AnonymousJobBatch::from_meta(job_metas)), |
|
|
|
|
runner: Some(AnonymousJobBatch::from_meta(jobs)), |
|
|
|
|
job_names, |
|
|
|
|
results: HashMap::new(), |
|
|
|
|
} |
|
|
|
@ -145,17 +134,18 @@ impl NamedJobBatch<true> { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub async fn run_assigned_job(meta: ThinJobMeta, ids: AssignedJobById) -> ExecResult { |
|
|
|
|
let mut job = AssignedJob::from((&meta, ids)); |
|
|
|
|
match meta.exec_type { |
|
|
|
|
pub async fn run_assigned_job(job: ThinJob, ids: AssignedJobById) -> ExecResult { |
|
|
|
|
let ThinJob { job, payload_meta } = job; |
|
|
|
|
let mut result = AssignedJob::from((&job, ids)); |
|
|
|
|
match job.exec_type { |
|
|
|
|
JobType::Shell => { |
|
|
|
|
let (argv, _prepared_payload) = { |
|
|
|
|
if let Some(ref payload) = meta.payload { |
|
|
|
|
let (prep_exec, prep_exec_path) = ufs::prepare_executable(payload)?; |
|
|
|
|
let argv_with_exec = meta.argv.replace("{}", &prep_exec_path); |
|
|
|
|
if let Some(meta) = payload_meta { |
|
|
|
|
let (prep_exec, prep_exec_path) = ufs::prepare_executable(meta.name)?; |
|
|
|
|
let argv_with_exec = job.argv.replace("{}", &prep_exec_path); |
|
|
|
|
(argv_with_exec, Some(prep_exec)) |
|
|
|
|
} else { |
|
|
|
|
(meta.argv, None) |
|
|
|
|
(job.argv, None) |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -175,69 +165,55 @@ pub async fn run_assigned_job(meta: ThinJobMeta, ids: AssignedJobById) -> ExecRe |
|
|
|
|
None, |
|
|
|
|
), |
|
|
|
|
}; |
|
|
|
|
job.result = Some(data); |
|
|
|
|
job.retcode = retcode; |
|
|
|
|
result.result = Some(data); |
|
|
|
|
result.retcode = retcode; |
|
|
|
|
} |
|
|
|
|
JobType::Init => { |
|
|
|
|
job.set_result(&Agent::run().await); |
|
|
|
|
job.retcode = Some(0); |
|
|
|
|
result.set_result(&Agent::run().await); |
|
|
|
|
result.retcode = Some(0); |
|
|
|
|
} |
|
|
|
|
JobType::Service => todo!(), |
|
|
|
|
JobType::Update => todo!(), |
|
|
|
|
JobType::Terminate => exit(0), |
|
|
|
|
}; |
|
|
|
|
Ok(job) |
|
|
|
|
Ok(result) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn fat_meta_to_thin(meta: FatJobMeta<true>) -> Result<ThinJobMeta, ufs::Error> { |
|
|
|
|
let payload_ident = if let Some(mut payload) = meta.payload { |
|
|
|
|
let job_name = match &meta.alias { |
|
|
|
|
Some(a) => a.to_string(), |
|
|
|
|
None => meta.id.simple().to_string(), |
|
|
|
|
}; |
|
|
|
|
payload.write_self_into(&job_name)?; |
|
|
|
|
Some(job_name) |
|
|
|
|
} else { |
|
|
|
|
None |
|
|
|
|
}; |
|
|
|
|
pub fn split_payload(job: FatJob) -> Result<ThinJob, ufs::Error> { |
|
|
|
|
let FatJob { |
|
|
|
|
job, |
|
|
|
|
payload_meta, |
|
|
|
|
payload_data, |
|
|
|
|
} = job; |
|
|
|
|
|
|
|
|
|
Ok(ThinJobMeta { |
|
|
|
|
alias: meta.alias, |
|
|
|
|
argv: meta.argv, |
|
|
|
|
id: meta.id, |
|
|
|
|
exec_type: meta.exec_type, |
|
|
|
|
platform: meta.platform, |
|
|
|
|
payload: payload_ident, |
|
|
|
|
schedule: meta.schedule, |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
if let Some(meta) = &payload_meta { |
|
|
|
|
if !ufs::in_index(&meta.name) { |
|
|
|
|
ufs::put(&meta.name, payload_data.unwrap())?; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn thin_meta_to_fat(meta: ThinJobMeta) -> Result<FatJobMeta<true>, ufs::Error> { |
|
|
|
|
let payload = if let Some(payload) = meta.payload { |
|
|
|
|
let mut fat_payload = Payload::Ident(payload); |
|
|
|
|
fat_payload.read_into_self()?; |
|
|
|
|
Some(fat_payload) |
|
|
|
|
} else { |
|
|
|
|
None |
|
|
|
|
}; |
|
|
|
|
Ok(ThinJob { job, payload_meta }) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Ok(FatJobMeta { |
|
|
|
|
alias: meta.alias, |
|
|
|
|
argv: meta.argv, |
|
|
|
|
id: meta.id, |
|
|
|
|
exec_type: meta.exec_type, |
|
|
|
|
platform: meta.platform, |
|
|
|
|
payload, |
|
|
|
|
schedule: meta.schedule, |
|
|
|
|
pub fn join_payload(job: ThinJob) -> Result<FatJob, ufs::Error> { |
|
|
|
|
let ThinJob { job, payload_meta } = job; |
|
|
|
|
let payload_data = payload_meta |
|
|
|
|
.as_ref() |
|
|
|
|
.map(|p| ufs::read(&p.name)) |
|
|
|
|
.transpose()?; |
|
|
|
|
|
|
|
|
|
Ok(FatJob { |
|
|
|
|
job, |
|
|
|
|
payload_meta, |
|
|
|
|
payload_data, |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[cfg(test)] |
|
|
|
|
mod tests { |
|
|
|
|
use super::*; |
|
|
|
|
use crate::{ |
|
|
|
|
jobs::{AnonymousJobBatch, NamedJobBatch}, |
|
|
|
|
models::{misc::JobType, FatJobMeta}, |
|
|
|
|
models::{misc::JobType, RawJob}, |
|
|
|
|
unwrap_enum, UError, |
|
|
|
|
}; |
|
|
|
|
use std::time::SystemTime; |
|
|
|
@ -247,10 +223,8 @@ mod tests { |
|
|
|
|
#[tokio::test] |
|
|
|
|
async fn test_is_really_async() { |
|
|
|
|
const SLEEP_SECS: u64 = 1; |
|
|
|
|
let job = FatJobMeta::from_shell(format!("sleep {SLEEP_SECS}")).unwrap(); |
|
|
|
|
let sleep_jobs = (0..50) |
|
|
|
|
.map(|_| fat_meta_to_thin(job.clone()).unwrap()) |
|
|
|
|
.collect::<Vec<_>>(); |
|
|
|
|
let job = RawJob::from_shell(format!("sleep {SLEEP_SECS}")).unwrap(); |
|
|
|
|
let sleep_jobs = (0..50).map(|_| job.clone()).collect::<Vec<_>>(); |
|
|
|
|
|
|
|
|
|
let now = SystemTime::now(); |
|
|
|
|
AnonymousJobBatch::from_meta(sleep_jobs).wait().await; |
|
|
|
@ -287,11 +261,11 @@ mod tests { |
|
|
|
|
#[case] payload: Option<&[u8]>, |
|
|
|
|
#[case] expected_result: &str, |
|
|
|
|
) -> TestResult { |
|
|
|
|
let mut job = FatJobMeta::builder().with_shell(cmd); |
|
|
|
|
let mut job = RawJob::builder().with_shell(cmd); |
|
|
|
|
if let Some(p) = payload { |
|
|
|
|
job = job.with_payload(p); |
|
|
|
|
} |
|
|
|
|
let job = fat_meta_to_thin(job.build().unwrap()).unwrap(); |
|
|
|
|
let job = job.build().unwrap(); |
|
|
|
|
let result = AnonymousJobBatch::from_meta(job).wait_one().await.unwrap(); |
|
|
|
|
let result = result.to_str_result(); |
|
|
|
|
assert_eq!(result.trim(), expected_result); |
|
|
|
@ -302,13 +276,9 @@ mod tests { |
|
|
|
|
async fn test_complex_load() -> TestResult { |
|
|
|
|
const SLEEP_SECS: u64 = 1; |
|
|
|
|
let now = SystemTime::now(); |
|
|
|
|
let longest_job = FatJobMeta::from_shell(format!("sleep {}", SLEEP_SECS)).unwrap(); |
|
|
|
|
let longest_job = AnonymousJobBatch::from_meta(fat_meta_to_thin(longest_job).unwrap()) |
|
|
|
|
.spawn() |
|
|
|
|
.await; |
|
|
|
|
let ls = AnonymousJobBatch::from_meta( |
|
|
|
|
fat_meta_to_thin(FatJobMeta::from_shell("ls").unwrap()).unwrap(), |
|
|
|
|
) |
|
|
|
|
let longest_job = RawJob::from_shell(format!("sleep {}", SLEEP_SECS)).unwrap(); |
|
|
|
|
let longest_job = AnonymousJobBatch::from_meta(longest_job).spawn().await; |
|
|
|
|
let ls = AnonymousJobBatch::from_meta(RawJob::from_shell("ls").unwrap()) |
|
|
|
|
.wait_one() |
|
|
|
|
.await |
|
|
|
|
.unwrap(); |
|
|
|
@ -318,7 +288,7 @@ mod tests { |
|
|
|
|
let folders = ls.to_str_result(); |
|
|
|
|
let subfolders_jobs = folders |
|
|
|
|
.lines() |
|
|
|
|
.map(|f| fat_meta_to_thin(FatJobMeta::from_shell(format!("ls {f}")).unwrap()).unwrap()) |
|
|
|
|
.map(|f| RawJob::from_shell(format!("ls {f}")).unwrap()) |
|
|
|
|
.collect::<Vec<_>>(); |
|
|
|
|
|
|
|
|
|
let ls_subfolders = AnonymousJobBatch::from_meta(subfolders_jobs).wait().await; |
|
|
|
@ -351,7 +321,7 @@ mod tests { |
|
|
|
|
*/ |
|
|
|
|
#[tokio::test] |
|
|
|
|
async fn test_failing_shell_job() -> TestResult { |
|
|
|
|
let job = fat_meta_to_thin(FatJobMeta::from_shell("lol_kek_puk").unwrap()).unwrap(); |
|
|
|
|
let job = RawJob::from_shell("lol_kek_puk").unwrap(); |
|
|
|
|
let job_result = AnonymousJobBatch::from_meta(job).wait_one().await.unwrap(); |
|
|
|
|
let output = job_result.to_str_result(); |
|
|
|
|
assert!(output.contains("No such file")); |
|
|
|
@ -368,7 +338,7 @@ mod tests { |
|
|
|
|
#[case] payload: Option<&[u8]>, |
|
|
|
|
#[case] err_str: &str, |
|
|
|
|
) -> TestResult { |
|
|
|
|
let mut job = FatJobMeta::builder().with_shell(cmd); |
|
|
|
|
let mut job = RawJob::builder().with_shell(cmd); |
|
|
|
|
if let Some(p) = payload { |
|
|
|
|
job = job.with_payload(p); |
|
|
|
|
} |
|
|
|
@ -380,23 +350,18 @@ mod tests { |
|
|
|
|
|
|
|
|
|
#[tokio::test] |
|
|
|
|
async fn test_different_job_types() -> TestResult { |
|
|
|
|
let mut jobs = NamedJobBatch::from_meta( |
|
|
|
|
[ |
|
|
|
|
FatJobMeta::builder() |
|
|
|
|
let mut jobs = NamedJobBatch::from_meta(vec![ |
|
|
|
|
RawJob::builder() |
|
|
|
|
.with_shell("sleep 3") |
|
|
|
|
.with_alias("sleeper") |
|
|
|
|
.build() |
|
|
|
|
.unwrap(), |
|
|
|
|
FatJobMeta::builder() |
|
|
|
|
RawJob::builder() |
|
|
|
|
.with_type(JobType::Init) |
|
|
|
|
.with_alias("gatherer") |
|
|
|
|
.build() |
|
|
|
|
.unwrap(), |
|
|
|
|
] |
|
|
|
|
.into_iter() |
|
|
|
|
.map(|meta| fat_meta_to_thin(meta).unwrap()) |
|
|
|
|
.collect::<Vec<_>>(), |
|
|
|
|
) |
|
|
|
|
]) |
|
|
|
|
.wait() |
|
|
|
|
.await; |
|
|
|
|
let gathered = jobs.pop("gatherer").unwrap(); |
|
|
|
|