diff --git a/src/core/meson.build b/src/core/meson.build index 98cf02aef8..a0ff0baf8d 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -70,6 +70,7 @@ libcore_sources = files( 'varlink-common.c', 'varlink-dynamic-user.c', 'varlink-execute.c', + 'varlink-job.c', 'varlink-kill.c', 'varlink-manager.c', 'varlink-metrics.c', diff --git a/src/core/varlink-job.c b/src/core/varlink-job.c new file mode 100644 index 0000000000..46b9a4cbd9 --- /dev/null +++ b/src/core/varlink-job.c @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "sd-varlink.h" + +#include "job.h" +#include "json-util.h" +#include "strv.h" +#include "unit.h" +#include "varlink-job.h" + +static int activation_details_build_json(sd_json_variant **ret, const char *name, void *userdata) { + _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; + _cleanup_strv_free_ char **pairs = NULL; + Job *j = ASSERT_PTR(userdata); + int r; + + assert(ret); + + r = activation_details_append_pair(j->activation_details, &pairs); + if (r < 0) + return log_debug_errno(r, "Failed to get activation details: %m"); + if (r == 0) { + *ret = NULL; + return 0; + } + + STRV_FOREACH_PAIR(key, value, pairs) { + r = sd_json_variant_set_field_string(&v, *key, *value); + if (r < 0) + return r; + } + + *ret = TAKE_PTR(v); + return 0; +} + +int job_build_json(sd_json_variant **ret, const char *name, void *userdata) { + Job *j = ASSERT_PTR(userdata); + + /* "Unit" is omitted in StartTransient streaming notifications where the caller already knows the unit. */ + return sd_json_buildo( + ASSERT_PTR(ret), + SD_JSON_BUILD_PAIR_INTEGER("Id", j->id), + JSON_BUILD_PAIR_STRING_NON_EMPTY("Unit", j->unit ? j->unit->id : NULL), + JSON_BUILD_PAIR_ENUM("JobType", job_type_to_string(j->type)), + JSON_BUILD_PAIR_ENUM("State", job_state_to_string(j->state)), + JSON_BUILD_PAIR_ENUM_NON_EMPTY("Result", job_result_to_string(j->result)), + JSON_BUILD_PAIR_CALLBACK_NON_NULL("ActivationDetails", activation_details_build_json, j)); +} diff --git a/src/core/varlink-job.h b/src/core/varlink-job.h new file mode 100644 index 0000000000..cd661daca6 --- /dev/null +++ b/src/core/varlink-job.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "core-forward.h" + +int job_build_json(sd_json_variant **ret, const char *name, void *userdata); diff --git a/src/core/varlink-unit.c b/src/core/varlink-unit.c index 31f7898a8c..4bf8136fa9 100644 --- a/src/core/varlink-unit.c +++ b/src/core/varlink-unit.c @@ -27,6 +27,7 @@ #include "varlink-cgroup.h" #include "varlink-common.h" #include "varlink-execute.h" +#include "varlink-job.h" #include "varlink-kill.h" #include "varlink-mount.h" #include "varlink-path.h" @@ -617,18 +618,6 @@ void varlink_unit_send_change_signal(Unit *u) { SD_JSON_BUILD_PAIR_CALLBACK("runtime", unit_runtime_build_json, u)); } -static int job_build_json(sd_json_variant **ret, const char *name, void *userdata) { - Job *j = ASSERT_PTR(userdata); - - /* Note that "Result" is suppressed until the job reaches JOB_FINISHED. */ - return sd_json_buildo( - ASSERT_PTR(ret), - SD_JSON_BUILD_PAIR_INTEGER("Id", j->id), - JSON_BUILD_PAIR_ENUM("JobType", job_type_to_string(j->type)), - JSON_BUILD_PAIR_ENUM("State", job_state_to_string(j->state)), - JSON_BUILD_PAIR_STRING_NON_EMPTY_UNDERSCORIFY("Result", job_result_to_string(j->result))); -} - void varlink_job_send_change_signal(Job *j) { assert(j); diff --git a/src/shared/varlink-io.systemd.Job.c b/src/shared/varlink-io.systemd.Job.c index 8dfc403c7b..17b06a7de5 100644 --- a/src/shared/varlink-io.systemd.Job.c +++ b/src/shared/varlink-io.systemd.Job.c @@ -39,17 +39,24 @@ SD_VARLINK_DEFINE_ENUM_TYPE( SD_VARLINK_DEFINE_ENUM_VALUE(frozen), SD_VARLINK_DEFINE_ENUM_VALUE(concurrency)); -/* Field names match the D-Bus Job properties (Id, JobType, State) */ +/* Field names match the D-Bus Job properties (Id, Unit, JobType, State) */ +#define VARLINK_DEFINE_JOB_FIELDS(direction) \ + SD_VARLINK_FIELD_COMMENT("The numeric job ID"), \ + SD_VARLINK_DEFINE_##direction(Id, SD_VARLINK_INT, 0), \ + SD_VARLINK_FIELD_COMMENT("The unit name this job operates on"), \ + SD_VARLINK_DEFINE_##direction(Unit, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), \ + SD_VARLINK_FIELD_COMMENT("The job type"), \ + SD_VARLINK_DEFINE_##direction##_BY_TYPE(JobType, JobType, 0), \ + SD_VARLINK_FIELD_COMMENT("Current job state. 'finished' indicates the job has completed; in that case Result is also set."), \ + SD_VARLINK_DEFINE_##direction##_BY_TYPE(State, JobState, SD_VARLINK_NULLABLE), \ + SD_VARLINK_FIELD_COMMENT("Job result. Only set once the job has reached the 'finished' state."), \ + SD_VARLINK_DEFINE_##direction##_BY_TYPE(Result, JobResult, SD_VARLINK_NULLABLE), \ + SD_VARLINK_FIELD_COMMENT("Activation details describing what triggered this job, as key-value pairs"), \ + SD_VARLINK_DEFINE_##direction(ActivationDetails, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_MAP) + SD_VARLINK_DEFINE_STRUCT_TYPE( Job, - SD_VARLINK_FIELD_COMMENT("The numeric job ID"), - SD_VARLINK_DEFINE_FIELD(Id, SD_VARLINK_INT, 0), - SD_VARLINK_FIELD_COMMENT("The job type"), - SD_VARLINK_DEFINE_FIELD_BY_TYPE(JobType, JobType, 0), - SD_VARLINK_FIELD_COMMENT("Current job state. 'finished' indicates the job has completed; in that case Result is also set."), - SD_VARLINK_DEFINE_FIELD_BY_TYPE(State, JobState, SD_VARLINK_NULLABLE), - SD_VARLINK_FIELD_COMMENT("Job result. Only set once the job has reached the 'finished' state."), - SD_VARLINK_DEFINE_FIELD_BY_TYPE(Result, JobResult, SD_VARLINK_NULLABLE)); + VARLINK_DEFINE_JOB_FIELDS(FIELD)); SD_VARLINK_DEFINE_INTERFACE( io_systemd_Job,