use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use anyhow::Result;
use futures::future::BoxFuture;
use indexmap::IndexMap;
use crate::ContentKind;
use crate::EvaluationPath;
use crate::GuestPath;
use crate::TaskInputs;
use crate::Value;
use crate::http::Location;
use crate::http::Transferer;
use crate::v1::requirements::ContainerSource;
mod apptainer;
mod docker;
mod local;
mod lsf_apptainer;
pub(crate) mod manager;
mod slurm_apptainer;
mod tes;
pub use apptainer::*;
pub use docker::*;
pub use local::*;
pub use lsf_apptainer::*;
pub use slurm_apptainer::*;
pub use tes::*;
const GUEST_INPUTS_DIR: &str = "/mnt/task/inputs/";
pub(crate) const WORK_DIR_NAME: &str = "work";
pub(crate) const COMMAND_FILE_NAME: &str = "command";
pub(crate) const STDOUT_FILE_NAME: &str = "stdout";
pub(crate) const STDERR_FILE_NAME: &str = "stderr";
const INITIAL_EXPECTED_NAMES: usize = 1000;
#[derive(Debug, Clone)]
pub(crate) struct Input {
kind: ContentKind,
path: EvaluationPath,
guest_path: Option<GuestPath>,
location: Option<Location>,
}
impl Input {
pub fn new(kind: ContentKind, path: EvaluationPath, guest_path: Option<GuestPath>) -> Self {
Self {
kind,
path,
guest_path,
location: None,
}
}
pub fn kind(&self) -> ContentKind {
self.kind
}
pub fn path(&self) -> &EvaluationPath {
&self.path
}
pub fn guest_path(&self) -> Option<&GuestPath> {
self.guest_path.as_ref()
}
pub fn local_path(&self) -> Option<&Path> {
self.location.as_deref().or_else(|| self.path.as_local())
}
pub fn set_location(&mut self, location: Location) {
self.location = Some(location);
}
}
#[derive(Debug)]
pub struct TaskExecutionConstraints {
pub container: Option<ContainerSource>,
pub cpu: f64,
pub memory: u64,
pub gpu: Vec<String>,
pub fpga: Vec<String>,
pub disks: IndexMap<String, i64>,
}
#[derive(Debug)]
pub struct ExecuteTaskRequest<'a> {
pub id: &'a str,
pub command: &'a str,
pub inputs: &'a TaskInputs,
pub backend_inputs: &'a [Input],
pub requirements: &'a HashMap<String, Value>,
pub hints: &'a HashMap<String, Value>,
pub env: &'a IndexMap<String, String>,
pub constraints: &'a TaskExecutionConstraints,
pub attempt_dir: &'a Path,
pub temp_dir: &'a Path,
}
impl<'a> ExecuteTaskRequest<'a> {
pub fn command_path(&self) -> PathBuf {
self.attempt_dir.join(COMMAND_FILE_NAME)
}
pub fn work_dir(&self) -> PathBuf {
self.attempt_dir.join(WORK_DIR_NAME)
}
pub fn stdout_path(&self) -> PathBuf {
self.attempt_dir.join(STDOUT_FILE_NAME)
}
pub fn stderr_path(&self) -> PathBuf {
self.attempt_dir.join(STDERR_FILE_NAME)
}
}
#[derive(Debug)]
pub struct TaskExecutionResult {
pub exit_code: i32,
pub work_dir: EvaluationPath,
pub stdout: Value,
pub stderr: Value,
}
pub(crate) trait TaskExecutionBackend: Send + Sync {
fn constraints(
&self,
inputs: &TaskInputs,
requirements: &HashMap<String, Value>,
hints: &HashMap<String, Value>,
) -> Result<TaskExecutionConstraints>;
fn guest_inputs_dir(&self) -> Option<&'static str> {
Some(GUEST_INPUTS_DIR)
}
fn needs_local_inputs(&self) -> bool {
true
}
fn execute<'a>(
&'a self,
transferer: &'a Arc<dyn Transferer>,
request: ExecuteTaskRequest<'a>,
) -> BoxFuture<'a, Result<Option<TaskExecutionResult>>>;
}