diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2021-04-22 10:34:34 +0200 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2021-04-22 10:34:34 +0200 |
commit | d86d6ff045725bb313ca68652f76ec7f1f82714f (patch) | |
tree | 690911ed45a22d93d51bdfb5c9d16f2d43422789 | |
parent | dfeb8312ebf34479ccb82faae116ed242d372f86 (diff) | |
parent | f6229edd41292e19d8c18a81a86542741260e938 (diff) |
Merge branch 'subcommand-submit'
-rw-r--r-- | src/cli.rs | 13 | ||||
-rw-r--r-- | src/commands/db.rs | 81 | ||||
-rw-r--r-- | src/db/models/endpoint.rs | 12 | ||||
-rw-r--r-- | src/db/models/image.rs | 12 | ||||
-rw-r--r-- | src/db/models/package.rs | 12 |
5 files changed, 128 insertions, 2 deletions
@@ -152,6 +152,19 @@ pub fn cli<'a>() -> App<'a> { ) ) + .subcommand(App::new("submit") + .version(crate_version!()) + .about("Show details about one specific submit") + .arg(Arg::new("submit") + .required(true) + .multiple(false) + .index(1) + .takes_value(true) + .value_name("SUBMIT") + .about("The Submit to show details about") + ) + ) + .subcommand(App::new("submits") .version(crate_version!()) .about("List submits from the DB") diff --git a/src/commands/db.rs b/src/commands/db.rs index ba66c14..0481ab1 100644 --- a/src/commands/db.rs +++ b/src/commands/db.rs @@ -46,6 +46,7 @@ pub fn db( Some(("artifacts", matches)) => artifacts(db_connection_config, matches), Some(("envvars", matches)) => envvars(db_connection_config, matches), Some(("images", matches)) => images(db_connection_config, matches), + Some(("submit", matches)) => submit(db_connection_config, matches), Some(("submits", matches)) => submits(db_connection_config, matches), Some(("jobs", matches)) => jobs(db_connection_config, matches), Some(("job", matches)) => job(db_connection_config, config, matches), @@ -229,6 +230,76 @@ fn images(conn_cfg: DbConnectionConfig, matches: &ArgMatches) -> Result<()> { Ok(()) } +fn submit(conn_cfg: DbConnectionConfig, matches: &ArgMatches) -> Result<()> { + let conn = crate::db::establish_connection(conn_cfg)?; + let submit_id = matches.value_of("submit") + .map(uuid::Uuid::from_str) + .transpose() + .context("Parsing submit UUID")? + .unwrap(); // safe by clap + + let submit = models::Submit::with_id(&conn, &submit_id) + .with_context(|| anyhow!("Loading submit '{}' from DB", submit_id))?; + + let jobs = schema::submits::table + .inner_join(schema::jobs::table) + .filter(schema::submits::uuid.eq(&submit_id)) + .select(schema::jobs::all_columns) + .load::<models::Job>(&conn) + .with_context(|| anyhow!("Loading jobs for submit = {}", submit_id))?; + + let n_jobs = jobs.len(); + let (jobs_success, jobs_err) = { + let s = jobs.iter().map(is_job_successful).fold(Ok(0), |acc, e| acc.and_then(|a| e.map(|_| a + 1)))?; + (s, n_jobs - s) + }; + + let out = std::io::stdout(); + let mut outlock = out.lock(); + + indoc::writedoc!(outlock, r#" + Submit {submit_id} + Date: {submit_dt} + Jobs: {n_jobs} + Success: {n_jobs_success} + Errored: {n_jobs_err} + + "#, + submit_id = submit.uuid.to_string().cyan(), + submit_dt = submit.submit_time.to_string().cyan(), + n_jobs = n_jobs.to_string().cyan(), + n_jobs_success = jobs_success.to_string().green(), + n_jobs_err = jobs_err.to_string().red(), + )?; + + let header = crate::commands::util::mk_header(["Job", "Success", "Package", "Version", "Endpoint", "Container", "Image"].to_vec()); + let data = jobs.iter() + .map(|job| { + let image = models::Image::fetch_for_job(&conn, job)? + .ok_or_else(|| anyhow!("Image for job {} not found", job.uuid))?; + let package = models::Package::fetch_for_job(&conn, job)? + .ok_or_else(|| anyhow!("Package for job {} not found", job.uuid))?; + let endpoint = models::Endpoint::fetch_for_job(&conn, job)? + .ok_or_else(|| anyhow!("Endpoint for job {} not found", job.uuid))?; + + Ok(vec![ + job.uuid.to_string().cyan(), + match is_job_successful(job)? { + Some(true) => "Success".green(), + Some(false) => "Error".red(), + None => "Unknown".yellow(), + }, + package.name.cyan(), + package.version.cyan(), + job.container_hash.normal(), + endpoint.name.normal(), + image.name.normal(), + ]) + }) + .collect::<Result<Vec<Vec<colored::ColoredString>>>>()?; + crate::commands::util::display_data(header, data, false) +} + fn submits(conn_cfg: DbConnectionConfig, matches: &ArgMatches) -> Result<()> { let csv = matches.is_present("csv"); let hdrs = crate::commands::util::mk_header(vec!["id", "time", "uuid"]); @@ -355,8 +426,7 @@ fn jobs(conn_cfg: DbConnectionConfig, matches: &ArgMatches) -> Result<()> { .into_iter() .rev() // required for the --limit implementation .map(|(job, submit, ep, package)| { - let success = crate::log::ParsedLog::build_from(&job.log_text)? - .is_successfull() + let success = is_job_successful(&job)? .map(|b| if b { "yes" } else { "no" }) .map(String::from) .unwrap_or_else(|| String::from("unknown")); @@ -602,3 +672,10 @@ fn releases(conn_cfg: DbConnectionConfig, config: &Configuration, matches: &ArgM crate::commands::util::display_data(header, data, csv) } +/// Check if a job is successful +/// +/// Returns Ok(None) if cannot be decided +fn is_job_successful(job: &models::Job) -> Result<Option<bool>> { + crate::log::ParsedLog::build_from(&job.log_text).map(|pl| pl.is_successfull()) +} + diff --git a/src/db/models/endpoint.rs b/src/db/models/endpoint.rs index d7a7986..3909b2b 100644 --- a/src/db/models/endpoint.rs +++ b/src/db/models/endpoint.rs @@ -43,4 +43,16 @@ impl Endpoint { .first::<Endpoint>(database_connection) .map_err(Error::from) } + + pub fn fetch_for_job(database_connection: &PgConnection, j: &crate::db::models::Job) -> Result<Option<Endpoint>> { + Self::fetch_by_id(database_connection, j.endpoint_id) + } + + pub fn fetch_by_id(database_connection: &PgConnection, eid: i32) -> Result<Option<Endpoint>> { + match dsl::endpoints.filter(id.eq(eid)).first::<Endpoint>(database_connection) { + Err(diesel::result::Error::NotFound) => Ok(None), + Err(e) => Err(Error::from(e)), + Ok(e) => Ok(Some(e)), + } + } } diff --git a/src/db/models/image.rs b/src/db/models/image.rs index 2570dc2..600edd6 100644 --- a/src/db/models/image.rs +++ b/src/db/models/image.rs @@ -48,4 +48,16 @@ impl Image { .first::<Image>(database_connection) .map_err(Error::from) } + + pub fn fetch_for_job(database_connection: &PgConnection, j: &crate::db::models::Job) -> Result<Option<Image>> { + Self::fetch_by_id(database_connection, j.image_id) + } + + pub fn fetch_by_id(database_connection: &PgConnection, iid: i32) -> Result<Option<Image>> { + match dsl::images.filter(id.eq(iid)).first::<Image>(database_connection) { + Err(diesel::result::Error::NotFound) => Ok(None), + Err(e) => Err(Error::from(e)), + Ok(i) => Ok(Some(i)), + } + } } diff --git a/src/db/models/package.rs b/src/db/models/package.rs index 6a5b646..88839b6 100644 --- a/src/db/models/package.rs +++ b/src/db/models/package.rs @@ -57,4 +57,16 @@ impl Package { .first::<Package>(database_connection) .map_err(Error::from) } + + pub fn fetch_for_job(database_connection: &PgConnection, j: &crate::db::models::Job) -> Result<Option<Package>> { + Self::fetch_by_id(database_connection, j.package_id) + } + + pub fn fetch_by_id(database_connection: &PgConnection, pid: i32) -> Result<Option<Package>> { + match dsl::packages.filter(id.eq(pid)).first::<Package>(database_connection) { + Err(diesel::result::Error::NotFound) => Ok(None), + Err(e) => Err(Error::from(e)), + Ok(p) => Ok(Some(p)), + } + } } |