From 4fcbc6f0c677000c82104670476df58eaaf3104e Mon Sep 17 00:00:00 2001 From: "Mark A. Grondona" Date: Mon, 9 Dec 2024 16:40:03 -0800 Subject: [PATCH] jobtap: add flux_jobtap_jobspec_update_id_pack() Problem: There's no interface to update the jobspec of a job outside of a jobtap callback for that job. Add flux_jobtap_jobspec_update_id_pack(). This function just does some nominal checks on the target job, then wraps event_post_pack(). --- src/modules/job-manager/jobtap.c | 55 ++++++++++++++++++++++++++++++++ src/modules/job-manager/jobtap.h | 13 ++++++++ 2 files changed, 68 insertions(+) diff --git a/src/modules/job-manager/jobtap.c b/src/modules/job-manager/jobtap.c index 887b81e4b4cc..d690374ee427 100644 --- a/src/modules/job-manager/jobtap.c +++ b/src/modules/job-manager/jobtap.c @@ -2263,6 +2263,61 @@ int flux_jobtap_event_post_pack (flux_plugin_t *p, return rc; } +int flux_jobtap_jobspec_update_id_pack (flux_plugin_t *p, + flux_jobid_t id, + const char *fmt, + ...) +{ + int rc = -1; + va_list ap; + struct jobtap *jobtap; + struct job *job; + json_error_t error; + json_t *update = NULL; + + if (!p + || !(jobtap = flux_plugin_aux_get (p, "flux::jobtap")) + || !(job = jobtap_lookup_active_jobid (p, id)) + || job->state == FLUX_JOB_STATE_RUN + || job->state == FLUX_JOB_STATE_CLEANUP + || job->eventlog_readonly) { + errno = EINVAL; + return -1; + } + + /* This interface is only appropriate from outside a jobtap callback, + * i.e. called asynchronously to update a job. If 'job' is equivalent + * to the current job at the top of the jobtap stack, return an error. + */ + if (job == current_job (jobtap)) { + errno = EINVAL; + return -1; + } + + va_start (ap, fmt); + update = json_vpack_ex (&error, 0, fmt, ap); + va_end (ap); + if (!update) { + errno = EINVAL; + return -1; + } + if (!validate_jobspec_updates (update)) { + errno = EINVAL; + goto out; + } + /* XXX: should job.validate be called on these updates before posting? + */ + rc = event_job_post_pack (jobtap->ctx->event, + job, + "jobspec-update", + 0, + "O", + update); +out: + ERRNO_SAFE_WRAP (json_decref, update); + return rc; +} + int flux_jobtap_jobspec_update_pack (flux_plugin_t *p, const char *fmt, ...) { int rc = -1; diff --git a/src/modules/job-manager/jobtap.h b/src/modules/job-manager/jobtap.h index adfabddfa156..1baa3a07f4d2 100644 --- a/src/modules/job-manager/jobtap.h +++ b/src/modules/job-manager/jobtap.h @@ -194,6 +194,19 @@ int flux_jobtap_event_post_pack (flux_plugin_t *p, */ int flux_jobtap_jobspec_update_pack (flux_plugin_t *p, const char *fmt, ...); +/* Similar to flux_jobtap_jobspec_update_pack(), but asynchronously update + * a specific jobid. This version assumes the job is quiescent, so the event + * is applied immediately. + * + * Returns -1 with errno set to EINVAL for invalid arguments, if the job + * does not exist, if the target job is in RUN, CLEANUP or INACTIVE states, + * or if the function is called from a jobtap callback for the target job. + */ +int flux_jobtap_jobspec_update_id_pack (flux_plugin_t *p, + flux_jobid_t id, + const char *fmt, + ...); + /* Return a flux_plugin_arg_t object for a job. * * The result can then be unpacked with flux_plugin_arg_unpack(3) to get