mirror of
https://github.com/systemd/systemd
synced 2024-09-06 16:56:43 +00:00
core: add EnqueueMarkedJobs method to reload/restart marked units
We support two return types for methods that start jobs. EnqueueJob support the full-monty mode with affected jobs. I didn't do this here, since it seems unlikely to be used. In the common case there'd be a huge list of jobs and affected jobs. EnqueueMarkedJobs() just returns a list of jobs that we can wait upon. The name of the method is generic in case we decide to add something other than just reload/restart later on. When errors occur, resource errors are treated as fatal, but for other error types we queue up other jobs, and only return an error at the end. The assumption is that the caller will ignore the result error anyway, so it's better to try to reload/restart as much as possible.
This commit is contained in:
parent
0dd3c0907f
commit
70666e28a1
|
@ -176,6 +176,7 @@ node /org/freedesktop/systemd1 {
|
|||
UnsetEnvironment(in as names);
|
||||
UnsetAndSetEnvironment(in as names,
|
||||
in as assignments);
|
||||
EnqueueMarkedJobs(out ao jobs);
|
||||
ListUnitFiles(out a(ss) unit_files);
|
||||
ListUnitFilesByPatterns(in as states,
|
||||
in as patterns,
|
||||
|
@ -848,6 +849,8 @@ node /org/freedesktop/systemd1 {
|
|||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="UnsetAndSetEnvironment()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="EnqueueMarkedJobs()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ListUnitFiles()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ListUnitFilesByPatterns()"/>
|
||||
|
@ -1171,6 +1174,11 @@ node /org/freedesktop/systemd1 {
|
|||
the "Try" flavor is used in which case a service that isn't running is not affected by the restart. The
|
||||
"ReloadOrRestart" flavors attempt a reload if the unit supports it and use a restart otherwise.</para>
|
||||
|
||||
<para><function>EnqueueMarkedJobs()</function> creates reload/restart jobs for units which have been
|
||||
appropriately marked, see <varname>Marks</varname> property above. This is equivalent to calling
|
||||
<function>TryRestartUnit()</function> or <function>ReloadOrTryRestartUnit()</function> for the marked
|
||||
units.</para>
|
||||
|
||||
<para><function>BindMountUnit()</function> can be used to bind mount new files or directories into
|
||||
a running service mount namespace.</para>
|
||||
|
||||
|
|
|
@ -1807,6 +1807,75 @@ static int method_get_dynamic_users(sd_bus_message *message, void *userdata, sd_
|
|||
return sd_bus_send(NULL, reply, NULL);
|
||||
}
|
||||
|
||||
static int method_enqueue_marked_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Manager *m = userdata;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(m);
|
||||
|
||||
r = mac_selinux_access_check(message, "start", error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_verify_manage_units_async(m, message, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
||||
|
||||
log_info("Queuing reload/restart jobs for marked units…");
|
||||
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
r = sd_bus_message_new_method_return(message, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "o");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
Unit *u;
|
||||
char *k;
|
||||
int ret = 0;
|
||||
HASHMAP_FOREACH_KEY(u, k, m->units) {
|
||||
/* ignore aliases */
|
||||
if (u->id != k)
|
||||
continue;
|
||||
|
||||
BusUnitQueueFlags flags;
|
||||
if (FLAGS_SET(u->markers, 1u << UNIT_MARKER_NEEDS_RESTART))
|
||||
flags = 0;
|
||||
else if (FLAGS_SET(u->markers, 1u << UNIT_MARKER_NEEDS_RELOAD))
|
||||
flags = BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE;
|
||||
else
|
||||
continue;
|
||||
|
||||
r = mac_selinux_unit_access_check(u, message, "start", error);
|
||||
if (r >= 0)
|
||||
r = bus_unit_queue_job_one(message, u,
|
||||
JOB_TRY_RESTART, JOB_FAIL, flags,
|
||||
reply, error);
|
||||
if (r < 0) {
|
||||
if (ERRNO_IS_RESOURCE(r))
|
||||
return r;
|
||||
if (ret >= 0)
|
||||
ret = r;
|
||||
sd_bus_error_free(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
return sd_bus_error_set_errnof(error, ret,
|
||||
"Failed to enqueue some jobs, see logs for details: %m");
|
||||
|
||||
r = sd_bus_message_close_container(reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_send(NULL, reply, NULL);
|
||||
}
|
||||
|
||||
static int list_unit_files_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states, char **patterns) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
Manager *m = userdata;
|
||||
|
@ -3007,6 +3076,12 @@ const sd_bus_vtable bus_manager_vtable[] = {
|
|||
NULL,,
|
||||
method_unset_and_set_environment,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("EnqueueMarkedJobs",
|
||||
NULL,,
|
||||
"ao",
|
||||
SD_BUS_PARAM(jobs),
|
||||
method_enqueue_marked_jobs,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("ListUnitFiles",
|
||||
NULL,,
|
||||
"a(ss)",
|
||||
|
|
|
@ -1716,6 +1716,89 @@ void bus_unit_send_removed_signal(Unit *u) {
|
|||
log_unit_debug_errno(u, r, "Failed to send unit remove signal for %s: %m", u->id);
|
||||
}
|
||||
|
||||
int bus_unit_queue_job_one(
|
||||
sd_bus_message *message,
|
||||
Unit *u,
|
||||
JobType type,
|
||||
JobMode mode,
|
||||
BusUnitQueueFlags flags,
|
||||
sd_bus_message *reply,
|
||||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_set_free_ Set *affected = NULL;
|
||||
_cleanup_free_ char *job_path = NULL, *unit_path = NULL;
|
||||
Job *j, *a;
|
||||
int r;
|
||||
|
||||
if (FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) {
|
||||
affected = set_new(NULL);
|
||||
if (!affected)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = manager_add_job(u->manager, type, u, mode, affected, error, &j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_job_track_sender(j, message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Before we send the method reply, force out the announcement JobNew for this job */
|
||||
bus_job_send_pending_change_signal(j, true);
|
||||
|
||||
job_path = job_dbus_path(j);
|
||||
if (!job_path)
|
||||
return -ENOMEM;
|
||||
|
||||
/* The classic response is just a job object path */
|
||||
if (!FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY))
|
||||
return sd_bus_message_append(reply, "o", job_path);
|
||||
|
||||
/* In verbose mode respond with the anchor job plus everything that has been affected */
|
||||
|
||||
unit_path = unit_dbus_path(j->unit);
|
||||
if (!unit_path)
|
||||
return -ENOMEM;
|
||||
|
||||
r = sd_bus_message_append(reply, "uosos",
|
||||
j->id, job_path,
|
||||
j->unit->id, unit_path,
|
||||
job_type_to_string(j->type));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "(uosos)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
SET_FOREACH(a, affected) {
|
||||
if (a->id == j->id)
|
||||
continue;
|
||||
|
||||
/* Free paths from previous iteration */
|
||||
job_path = mfree(job_path);
|
||||
unit_path = mfree(unit_path);
|
||||
|
||||
job_path = job_dbus_path(a);
|
||||
if (!job_path)
|
||||
return -ENOMEM;
|
||||
|
||||
unit_path = unit_dbus_path(a->unit);
|
||||
if (!unit_path)
|
||||
return -ENOMEM;
|
||||
|
||||
r = sd_bus_message_append(reply, "(uosos)",
|
||||
a->id, job_path,
|
||||
a->unit->id, unit_path,
|
||||
job_type_to_string(a->type));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
int bus_unit_queue_job(
|
||||
sd_bus_message *message,
|
||||
Unit *u,
|
||||
|
@ -1725,9 +1808,6 @@ int bus_unit_queue_job(
|
|||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_free_ char *job_path = NULL, *unit_path = NULL;
|
||||
_cleanup_set_free_ Set *affected = NULL;
|
||||
Job *j, *a;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
|
@ -1760,77 +1840,11 @@ int bus_unit_queue_job(
|
|||
(type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
|
||||
return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id);
|
||||
|
||||
if (FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) {
|
||||
affected = set_new(NULL);
|
||||
if (!affected)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = manager_add_job(u->manager, type, u, mode, affected, error, &j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_job_track_sender(j, message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Before we send the method reply, force out the announcement JobNew for this job */
|
||||
bus_job_send_pending_change_signal(j, true);
|
||||
|
||||
job_path = job_dbus_path(j);
|
||||
if (!job_path)
|
||||
return -ENOMEM;
|
||||
|
||||
/* The classic response is just a job object path */
|
||||
if (!FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY))
|
||||
return sd_bus_reply_method_return(message, "o", job_path);
|
||||
|
||||
/* In verbose mode respond with the anchor job plus everything that has been affected */
|
||||
r = sd_bus_message_new_method_return(message, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
unit_path = unit_dbus_path(j->unit);
|
||||
if (!unit_path)
|
||||
return -ENOMEM;
|
||||
|
||||
r = sd_bus_message_append(reply, "uosos",
|
||||
j->id, job_path,
|
||||
j->unit->id, unit_path,
|
||||
job_type_to_string(j->type));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "(uosos)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
SET_FOREACH(a, affected) {
|
||||
|
||||
if (a->id == j->id)
|
||||
continue;
|
||||
|
||||
/* Free paths from previous iteration */
|
||||
job_path = mfree(job_path);
|
||||
unit_path = mfree(unit_path);
|
||||
|
||||
job_path = job_dbus_path(a);
|
||||
if (!job_path)
|
||||
return -ENOMEM;
|
||||
|
||||
unit_path = unit_dbus_path(a->unit);
|
||||
if (!unit_path)
|
||||
return -ENOMEM;
|
||||
|
||||
r = sd_bus_message_append(reply, "(uosos)",
|
||||
a->id, job_path,
|
||||
a->unit->id, unit_path,
|
||||
job_type_to_string(a->type));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(reply);
|
||||
r = bus_unit_queue_job_one(message, u, type, mode, flags, reply, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -33,7 +33,21 @@ typedef enum BusUnitQueueFlags {
|
|||
BUS_UNIT_QUEUE_VERBOSE_REPLY = 1 << 1,
|
||||
} BusUnitQueueFlags;
|
||||
|
||||
int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, BusUnitQueueFlags flags, sd_bus_error *error);
|
||||
int bus_unit_queue_job_one(
|
||||
sd_bus_message *message,
|
||||
Unit *u,
|
||||
JobType type,
|
||||
JobMode mode,
|
||||
BusUnitQueueFlags flags,
|
||||
sd_bus_message *reply,
|
||||
sd_bus_error *error);
|
||||
int bus_unit_queue_job(
|
||||
sd_bus_message *message,
|
||||
Unit *u,
|
||||
JobType type,
|
||||
JobMode mode,
|
||||
BusUnitQueueFlags flags,
|
||||
sd_bus_error *error);
|
||||
int bus_unit_validate_load_state(Unit *u, sd_bus_error *error);
|
||||
|
||||
int bus_unit_track_add_name(Unit *u, const char *name);
|
||||
|
|
Loading…
Reference in a new issue