diff --git a/Cargo.lock b/Cargo.lock index d8cc2dd..1f22263 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1162,7 +1162,7 @@ dependencies = [ [[package]] name = "k8s-job-dispatcher" -version = "0.3.1" +version = "0.4.0" dependencies = [ "actix-web", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index d417056..0026cb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "k8s-job-dispatcher" -version = "0.3.1" +version = "0.4.0" edition = "2021" [dependencies] diff --git a/src/jq.rs b/src/jq.rs index 3cb5da6..d345ee1 100644 --- a/src/jq.rs +++ b/src/jq.rs @@ -45,7 +45,7 @@ fn jq_extensions() -> impl Iterator { /// Compile a filter. pub fn compile(filter: &str) -> Result { - let mut defs = ParseCtx::new(vec!["ENV".to_string()]); + let mut defs = ParseCtx::new(vec!["ENV".to_string(), "PATH".to_string()]); defs.insert_natives(jaq_core::core()); defs.insert_natives(jq_extensions()); defs.insert_defs(jaq_std::std()); @@ -62,10 +62,13 @@ pub fn compile(filter: &str) -> Result { /// Execute a compiled filter against an input, and produce the first /// serde_json value. -pub fn first_result(filter: &Filter, input: Value) -> Option> { +pub fn first_result(filter: &Filter, input: Value, path: &str) -> Option> { let inputs = RcIter::new(core::iter::empty()); let mut outputs = filter - .run((Ctx::new([jq_env()], &inputs), Val::from(input))) + .run(( + Ctx::new([jq_env(), Val::str(path.to_string())], &inputs), + Val::from(input), + )) .map(|r| r.map(Value::from).map_err(|e| anyhow!(e.to_string()))); let first_result = outputs.next(); if outputs.next().is_some() { diff --git a/src/k8s_service.rs b/src/k8s_service.rs index a66b5d9..333a590 100644 --- a/src/k8s_service.rs +++ b/src/k8s_service.rs @@ -3,10 +3,10 @@ use crate::jq; use crate::state; -use actix_web::{error, get, post, web, HttpResponse, Responder, Result}; +use actix_web::{error, get, routes, web, HttpResponse, Responder, Result}; use k8s_openapi::api::batch::v1::{Job, JobStatus}; use kube::{core::params::PostParams, Error}; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use serde_json::Value; use tracing::{debug, info}; @@ -18,14 +18,25 @@ struct JobSummary { status: Option, } +/// A container for the create_job path information. +#[derive(Deserialize)] +struct PathInfo { + path: Option, +} + /// Create a K8s job by converting the request body to a job manifest. +#[routes] #[post("/job")] +#[post("/job/{path:.*}")] async fn create_job( + path: web::Path, body: web::Json, state: web::Data, ) -> Result { - debug!("Job creation request: {:?}", body); - let raw_manifest = jq::first_result(&state.filter, body.into_inner()) + let path = format!("/job/{}", path.path.clone().unwrap_or_default()); + let path = path.strip_suffix('/').map(String::from).unwrap_or(path); + debug!("Job creation request at {:?}: {:?}", path, body); + let raw_manifest = jq::first_result(&state.filter, body.into_inner(), &path) .ok_or_else(|| error::ErrorBadRequest("Filter didn't produce results"))? .map_err(|e| error::ErrorBadRequest(format!("Filter failed: {:?}", e)))?; debug!("Job raw manifest: {:?}", raw_manifest);