Skip to content

Commit 7d4d63b

Browse files
authored
Merge pull request #6500 from grondo/issue#5957
jobtap: add `flux_jobtap_jobspec_update_id_pack()`
2 parents 0af65c5 + c5d9fda commit 7d4d63b

File tree

4 files changed

+118
-1
lines changed

4 files changed

+118
-1
lines changed

src/modules/job-manager/jobtap.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2263,6 +2263,61 @@ int flux_jobtap_event_post_pack (flux_plugin_t *p,
22632263
return rc;
22642264
}
22652265

2266+
int flux_jobtap_jobspec_update_id_pack (flux_plugin_t *p,
2267+
flux_jobid_t id,
2268+
const char *fmt,
2269+
...)
2270+
{
2271+
int rc = -1;
2272+
va_list ap;
2273+
struct jobtap *jobtap;
2274+
struct job *job;
2275+
json_error_t error;
2276+
json_t *update = NULL;
2277+
2278+
if (!p
2279+
|| !(jobtap = flux_plugin_aux_get (p, "flux::jobtap"))
2280+
|| !(job = jobtap_lookup_active_jobid (p, id))
2281+
|| job->state == FLUX_JOB_STATE_RUN
2282+
|| job->state == FLUX_JOB_STATE_CLEANUP
2283+
|| job->eventlog_readonly) {
2284+
errno = EINVAL;
2285+
return -1;
2286+
}
2287+
2288+
/* This interface is only appropriate from outside a jobtap callback,
2289+
* i.e. called asynchronously to update a job. If 'job' is equivalent
2290+
* to the current job at the top of the jobtap stack, return an error.
2291+
*/
2292+
if (job == current_job (jobtap)) {
2293+
errno = EINVAL;
2294+
return -1;
2295+
}
2296+
2297+
va_start (ap, fmt);
2298+
update = json_vpack_ex (&error, 0, fmt, ap);
2299+
va_end (ap);
2300+
if (!update) {
2301+
errno = EINVAL;
2302+
return -1;
2303+
}
2304+
if (!validate_jobspec_updates (update)) {
2305+
errno = EINVAL;
2306+
goto out;
2307+
}
2308+
/* XXX: should job.validate be called on these updates before posting?
2309+
*/
2310+
rc = event_job_post_pack (jobtap->ctx->event,
2311+
job,
2312+
"jobspec-update",
2313+
0,
2314+
"O",
2315+
update);
2316+
out:
2317+
ERRNO_SAFE_WRAP (json_decref, update);
2318+
return rc;
2319+
}
2320+
22662321
int flux_jobtap_jobspec_update_pack (flux_plugin_t *p, const char *fmt, ...)
22672322
{
22682323
int rc = -1;

src/modules/job-manager/jobtap.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,19 @@ int flux_jobtap_event_post_pack (flux_plugin_t *p,
194194
*/
195195
int flux_jobtap_jobspec_update_pack (flux_plugin_t *p, const char *fmt, ...);
196196

197+
/* Similar to flux_jobtap_jobspec_update_pack(), but asynchronously update
198+
* a specific jobid. This version assumes the job is quiescent, so the event
199+
* is applied immediately.
200+
*
201+
* Returns -1 with errno set to EINVAL for invalid arguments, if the job
202+
* does not exist, if the target job is in RUN, CLEANUP or INACTIVE states,
203+
* or if the function is called from a jobtap callback for the target job.
204+
*/
205+
int flux_jobtap_jobspec_update_id_pack (flux_plugin_t *p,
206+
flux_jobid_t id,
207+
const char *fmt,
208+
...);
209+
197210
/* Return a flux_plugin_arg_t object for a job.
198211
*
199212
* The result can then be unpacked with flux_plugin_arg_unpack(3) to get

t/job-manager/plugins/jobspec-update.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ static int get_and_update_jobspec_name (flux_error_t *errp,
2525
const char **cur_namep,
2626
char *name)
2727
{
28+
flux_jobid_t id;
2829
const char *current_name = NULL;
2930
char *copy = NULL;
3031
if (flux_plugin_arg_unpack (args,
3132
FLUX_PLUGIN_ARG_IN,
32-
"{s:{s:{s?{s?{s?s}}}}}",
33+
"{s:I s:{s:{s?{s?{s?s}}}}}",
34+
"id", &id,
3335
"jobspec",
3436
"attributes",
3537
"system",
@@ -41,6 +43,20 @@ static int get_and_update_jobspec_name (flux_error_t *errp,
4143
flux_plugin_arg_strerror (args));
4244
return -1;
4345
}
46+
47+
/* flux_jobtap_jobspec_update_id_pack() should fail here, since this
48+
* function is always called in the context of a jobtap callback:
49+
*/
50+
if (flux_jobtap_jobspec_update_id_pack (p,
51+
id,
52+
"{s:s}",
53+
"attributes.system.foo",
54+
"bar") == 0) {
55+
errprintf (errp,
56+
"flux_jobtap_jobspec_update_id_pack() unexpected success");
57+
return -1;
58+
}
59+
4460
if (current_name && !(copy = strdup (current_name))) {
4561
errprintf (errp, "failed to copy job name");
4662
return -1;
@@ -199,6 +215,20 @@ static int run_cb (flux_plugin_t *p,
199215
return 0;
200216
}
201217

218+
static void update_msg_cb (flux_t *h,
219+
flux_msg_handler_t *mh,
220+
const flux_msg_t *msg,
221+
void *arg)
222+
{
223+
flux_plugin_t *p = arg;
224+
flux_jobid_t id;
225+
json_t *update;
226+
227+
if (flux_msg_unpack (msg, "{s:I s:o}", "id", &id, "update", &update) < 0
228+
|| flux_jobtap_jobspec_update_id_pack (p, id, "O", update) < 0)
229+
flux_jobtap_raise_exception (p, id, "test", 0, "update failed");
230+
flux_respond (h, msg, NULL);
231+
}
202232

203233
static const struct flux_plugin_handler tab[] = {
204234
{ "job.new", new_cb, NULL },
@@ -214,6 +244,9 @@ int flux_plugin_init (flux_plugin_t *p)
214244
{
215245
if (flux_plugin_register (p, "jobspec-update", tab) < 0)
216246
return -1;
247+
if (flux_jobtap_service_register (p, "update", update_msg_cb, p) < 0)
248+
flux_log_error (flux_jobtap_get_flux (p),
249+
"flux_jobtap_service_register");
217250
return 0;
218251
}
219252

t/t2212-job-manager-plugins.t

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,22 @@ test_expect_success 'job-manager: plugins can update jobspec' '
529529
--match-context=attributes.system.job.name=new \
530530
$jobid jobspec-update
531531
'
532+
test_expect_success 'job-manager: plugin can asynchronously update jobspec' '
533+
flux dmesg -H | grep jobspec-update &&
534+
jobid=$(flux submit -n1 --urgency=hold sleep 0) &&
535+
cat <<-EOF >update-test.py &&
536+
import flux
537+
from flux.job import JobID
538+
id=JobID("$jobid")
539+
flux.Flux().rpc(
540+
"job-manager.jobspec-update.update",
541+
dict(id=id, update={"attributes.system.job.name": "test"}),
542+
).get()
543+
EOF
544+
flux python update-test.py &&
545+
flux job wait-event -Hv -t 30 $jobid jobspec-update &&
546+
flux jobs $jobid
547+
'
532548
test_expect_success 'job-manager: plugin fails to load on config.update error' '
533549
flux jobtap remove all &&
534550
test_must_fail flux jobtap load ${PLUGINPATH}/config.so 2>config.err

0 commit comments

Comments
 (0)