mirror of
https://github.com/systemd/systemd
synced 2024-07-21 18:24:38 +00:00
Merge pull request #27584 from rphibel/add-restartquick-option
service: add new RestartMode option
This commit is contained in:
commit
b2deaaf01b
|
@ -2598,6 +2598,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s Restart = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s RestartMode = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s PIDFile = '...';
|
||||
readonly s NotifyAccess = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
|
@ -3243,6 +3245,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||
|
||||
<!--property Restart is not documented!-->
|
||||
|
||||
<!--property RestartMode is not documented!-->
|
||||
|
||||
<!--property PIDFile is not documented!-->
|
||||
|
||||
<!--property NotifyAccess is not documented!-->
|
||||
|
@ -3823,6 +3827,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="Restart"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="RestartMode"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PIDFile"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="NotifyAccess"/>
|
||||
|
|
|
@ -897,6 +897,28 @@
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RestartMode=</varname></term>
|
||||
|
||||
<listitem>
|
||||
<para>Takes a string value that specifies how a service should restart:
|
||||
<itemizedlist>
|
||||
<listitem><para>If set to <option>normal</option> (the default), the service restarts by
|
||||
going through a failed/inactive state.</para></listitem>
|
||||
|
||||
<listitem><para>If set to <option>direct</option>, the service transitions to the activating
|
||||
state directly during auto-restart, skipping failed/inactive state.
|
||||
<varname>ExecStopPost=</varname> is invoked.
|
||||
<varname>OnSuccess=</varname> and <varname>OnFailure=</varname> are skipped.</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>This option is useful in cases where a dependency can fail temporarily
|
||||
but we don't want these temporary failures to make the dependent units fail.
|
||||
When this option is set to <option>direct</option>, dependent units are not notified of these temporary failures.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>SuccessExitStatus=</varname></term>
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType
|
|||
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exit_type, service_exit_type, ServiceExitType);
|
||||
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult);
|
||||
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart, service_restart, ServiceRestart);
|
||||
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart_mode, service_restart_mode, ServiceRestartMode);
|
||||
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction);
|
||||
static BUS_DEFINE_PROPERTY_GET2(property_get_notify_access, "s", Service, service_get_notify_access, notify_access_to_string);
|
||||
static BUS_DEFINE_PROPERTY_GET(property_get_restart_usec_next, "t", Service, service_restart_usec_next);
|
||||
|
@ -322,6 +323,7 @@ const sd_bus_vtable bus_service_vtable[] = {
|
|||
SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Service, type), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ExitType", "s", property_get_exit_type, offsetof(Service, exit_type), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Restart", "s", property_get_restart, offsetof(Service, restart), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RestartMode", "s", property_get_restart_mode, offsetof(Service, restart_mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("PIDFile", "s", NULL, offsetof(Service, pid_file), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("NotifyAccess", "s", property_get_notify_access, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("RestartUSec", "t", bus_property_get_usec, offsetof(Service, restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
|
@ -512,6 +514,7 @@ static BUS_DEFINE_SET_TRANSIENT_PARSE(notify_access, NotifyAccess, notify_access
|
|||
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_type, ServiceType, service_type_from_string);
|
||||
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_exit_type, ServiceExitType, service_exit_type_from_string);
|
||||
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_restart, ServiceRestart, service_restart_from_string);
|
||||
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_restart_mode, ServiceRestartMode, service_restart_mode_from_string);
|
||||
static BUS_DEFINE_SET_TRANSIENT_PARSE(oom_policy, OOMPolicy, oom_policy_from_string);
|
||||
static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(bus_name, sd_bus_service_name_is_valid);
|
||||
static BUS_DEFINE_SET_TRANSIENT_PARSE(timeout_failure_mode, ServiceTimeoutFailureMode, service_timeout_failure_mode_from_string);
|
||||
|
@ -660,6 +663,9 @@ static int bus_service_set_transient_property(
|
|||
if (streq(name, "Restart"))
|
||||
return bus_set_transient_service_restart(u, name, &s->restart, message, flags, error);
|
||||
|
||||
if (streq(name, "RestartMode"))
|
||||
return bus_set_transient_service_restart_mode(u, name, &s->restart_mode, message, flags, error);
|
||||
|
||||
if (streq(name, "RestartPreventExitStatus"))
|
||||
return bus_set_transient_exit_status(u, name, &s->restart_prevent_status, message, flags, error);
|
||||
|
||||
|
|
|
@ -217,7 +217,7 @@ static void job_merge_into_installed(Job *j, Job *other) {
|
|||
j->ignore_order = j->ignore_order || other->ignore_order;
|
||||
}
|
||||
|
||||
Job* job_install(Job *j) {
|
||||
Job* job_install(Job *j, JobMode mode) {
|
||||
Job **pj;
|
||||
Job *uj;
|
||||
|
||||
|
@ -235,7 +235,7 @@ Job* job_install(Job *j) {
|
|||
/* not conflicting, i.e. mergeable */
|
||||
|
||||
if (uj->state == JOB_WAITING ||
|
||||
(job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) {
|
||||
(job_type_allows_late_merge(j->type) && mode != JOB_RESTART_DEPENDENCIES && job_type_is_superset(uj->type, j->type))) {
|
||||
job_merge_into_installed(uj, j);
|
||||
log_unit_debug(uj->unit,
|
||||
"Merged %s/%s into installed job %s/%s as %"PRIu32,
|
||||
|
|
|
@ -169,7 +169,7 @@ Job* job_new(Unit *unit, JobType type);
|
|||
Job* job_new_raw(Unit *unit);
|
||||
void job_unlink(Job *job);
|
||||
Job* job_free(Job *job);
|
||||
Job* job_install(Job *j);
|
||||
Job* job_install(Job *j, JobMode mode);
|
||||
int job_install_deserialized(Job *j);
|
||||
void job_uninstall(Job *j);
|
||||
void job_dump(Job *j, FILE *f, const char *prefix);
|
||||
|
|
|
@ -427,6 +427,7 @@ Service.RebootArgument, config_parse_unit_string_printf,
|
|||
Service.Type, config_parse_service_type, 0, offsetof(Service, type)
|
||||
Service.ExitType, config_parse_service_exit_type, 0, offsetof(Service, exit_type)
|
||||
Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart)
|
||||
Service.RestartMode, config_parse_service_restart_mode, 0, offsetof(Service, restart_mode)
|
||||
Service.PermissionsStartOnly, config_parse_bool, 0, offsetof(Service, permissions_start_only)
|
||||
Service.RootDirectoryStartOnly, config_parse_bool, 0, offsetof(Service, root_directory_start_only)
|
||||
Service.RemainAfterExit, config_parse_bool, 0, offsetof(Service, remain_after_exit)
|
||||
|
|
|
@ -142,6 +142,7 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_preserve_mode, exec_preserve_mode, Ex
|
|||
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_exit_type, service_exit_type, ServiceExitType, "Failed to parse service exit type");
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart_mode, service_restart_mode, ServiceRestartMode, "Failed to parse service restart mode");
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_timeout_failure_mode, service_timeout_failure_mode, ServiceTimeoutFailureMode, "Failed to parse timeout failure mode");
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_socket_bind, socket_address_bind_ipv6_only_or_bool, SocketAddressBindIPv6Only, "Failed to parse bind IPv6 only value");
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_oom_policy, oom_policy, OOMPolicy, "Failed to parse OOM policy");
|
||||
|
@ -6299,6 +6300,7 @@ void unit_dump_config_items(FILE *f) {
|
|||
{ config_parse_service_type, "SERVICETYPE" },
|
||||
{ config_parse_service_exit_type, "SERVICEEXITTYPE" },
|
||||
{ config_parse_service_restart, "SERVICERESTART" },
|
||||
{ config_parse_service_restart_mode, "SERVICERESTARTMODE" },
|
||||
{ config_parse_service_timeout_failure_mode, "TIMEOUTMODE" },
|
||||
{ config_parse_kill_mode, "KILLMODE" },
|
||||
{ config_parse_signal, "SIGNAL" },
|
||||
|
|
|
@ -41,6 +41,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout_failure_mode);
|
|||
CONFIG_PARSER_PROTOTYPE(config_parse_service_type);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_service_exit_type);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_service_restart);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_service_restart_mode);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_socket_bindtodevice);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_exec_output);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_exec_input);
|
||||
|
|
|
@ -2011,7 +2011,8 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
|
|||
* are only transitionary and followed by an automatic restart. We have fine-grained
|
||||
* low-level states for this though so that software can distinguish the permanent UNIT_INACTIVE
|
||||
* state from this transitionary UNIT_INACTIVE state by looking at the low-level states. */
|
||||
service_set_state(s, restart_state);
|
||||
if (s->restart_mode != SERVICE_RESTART_MODE_DIRECT)
|
||||
service_set_state(s, restart_state);
|
||||
|
||||
r = service_arm_timer(s, /* relative= */ true, service_restart_usec_next(s));
|
||||
if (r < 0)
|
||||
|
@ -5009,6 +5010,13 @@ static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
|
|||
|
||||
DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
|
||||
|
||||
static const char* const service_restart_mode_table[_SERVICE_RESTART_MODE_MAX] = {
|
||||
[SERVICE_RESTART_MODE_NORMAL] = "normal",
|
||||
[SERVICE_RESTART_MODE_DIRECT] = "direct",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(service_restart_mode, ServiceRestartMode);
|
||||
|
||||
static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
|
||||
[SERVICE_SIMPLE] = "simple",
|
||||
[SERVICE_FORKING] = "forking",
|
||||
|
|
|
@ -91,6 +91,13 @@ typedef enum ServiceTimeoutFailureMode {
|
|||
_SERVICE_TIMEOUT_FAILURE_MODE_INVALID = -EINVAL,
|
||||
} ServiceTimeoutFailureMode;
|
||||
|
||||
typedef enum ServiceRestartMode {
|
||||
SERVICE_RESTART_MODE_NORMAL,
|
||||
SERVICE_RESTART_MODE_DIRECT,
|
||||
_SERVICE_RESTART_MODE_MAX,
|
||||
_SERVICE_RESTART_MODE_INVALID = -EINVAL,
|
||||
} ServiceRestartMode;
|
||||
|
||||
struct ServiceFDStore {
|
||||
Service *service;
|
||||
|
||||
|
@ -108,6 +115,7 @@ struct Service {
|
|||
ServiceType type;
|
||||
ServiceExitType exit_type;
|
||||
ServiceRestart restart;
|
||||
ServiceRestartMode restart_mode;
|
||||
ExitStatusSet restart_prevent_status;
|
||||
ExitStatusSet restart_force_status;
|
||||
ExitStatusSet success_status;
|
||||
|
@ -249,6 +257,9 @@ usec_t service_restart_usec_next(Service *s);
|
|||
const char* service_restart_to_string(ServiceRestart i) _const_;
|
||||
ServiceRestart service_restart_from_string(const char *s) _pure_;
|
||||
|
||||
const char* service_restart_mode_to_string(ServiceRestartMode i) _const_;
|
||||
ServiceRestartMode service_restart_mode_from_string(const char *s) _pure_;
|
||||
|
||||
const char* service_type_to_string(ServiceType i) _const_;
|
||||
ServiceType service_type_from_string(const char *s) _pure_;
|
||||
|
||||
|
|
|
@ -657,7 +657,7 @@ static int transaction_apply(
|
|||
/* Clean the job dependencies */
|
||||
transaction_unlink_job(tr, j, false);
|
||||
|
||||
installed_job = job_install(j);
|
||||
installed_job = job_install(j, mode);
|
||||
if (installed_job != j) {
|
||||
/* j has been merged into a previously installed job */
|
||||
if (tr->anchor_job == j)
|
||||
|
|
|
@ -2206,6 +2206,7 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con
|
|||
"Type",
|
||||
"ExitType",
|
||||
"Restart",
|
||||
"RestartMode",
|
||||
"BusName",
|
||||
"NotifyAccess",
|
||||
"USBFunctionDescriptors",
|
||||
|
|
|
@ -97,6 +97,7 @@ int main(int argc, char **argv) {
|
|||
test_table(scope_state, SCOPE_STATE);
|
||||
test_table(service_exec_command, SERVICE_EXEC_COMMAND);
|
||||
test_table(service_restart, SERVICE_RESTART);
|
||||
test_table(service_restart_mode, SERVICE_RESTART_MODE);
|
||||
test_table(service_result, SERVICE_RESULT);
|
||||
test_table(service_state, SERVICE_STATE);
|
||||
test_table(service_type, SERVICE_TYPE);
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[Unit]
|
||||
Description=Fail on restart
|
||||
StartLimitIntervalSec=1m
|
||||
StartLimitBurst=3
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=false
|
||||
Restart=on-failure
|
||||
RestartMode=direct
|
3
test/testsuite-03.units/fails-on-restart-restartdirect.target
Executable file
3
test/testsuite-03.units/fails-on-restart-restartdirect.target
Executable file
|
@ -0,0 +1,3 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[Unit]
|
||||
Requires=fails-on-restart-restartdirect.service
|
11
test/testsuite-03.units/fails-on-restart.service
Normal file
11
test/testsuite-03.units/fails-on-restart.service
Normal file
|
@ -0,0 +1,11 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[Unit]
|
||||
Description=Fail on restart
|
||||
StartLimitIntervalSec=1m
|
||||
StartLimitBurst=3
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=false
|
||||
Restart=on-failure
|
||||
RestartMode=normal
|
3
test/testsuite-03.units/fails-on-restart.target
Executable file
3
test/testsuite-03.units/fails-on-restart.target
Executable file
|
@ -0,0 +1,3 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[Unit]
|
||||
Requires=fails-on-restart.service
|
6
test/testsuite-03.units/succeeds-on-restart-restartdirect.service
Executable file
6
test/testsuite-03.units/succeeds-on-restart-restartdirect.service
Executable file
|
@ -0,0 +1,6 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/lib/systemd/tests/testdata/testsuite-03.units/succeeds-on-restart.sh
|
||||
Restart=on-failure
|
||||
RestartMode=direct
|
3
test/testsuite-03.units/succeeds-on-restart-restartdirect.target
Executable file
3
test/testsuite-03.units/succeeds-on-restart-restartdirect.target
Executable file
|
@ -0,0 +1,3 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[Unit]
|
||||
Requires=succeeds-on-restart-restartdirect.service
|
6
test/testsuite-03.units/succeeds-on-restart.service
Executable file
6
test/testsuite-03.units/succeeds-on-restart.service
Executable file
|
@ -0,0 +1,6 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/lib/systemd/tests/testdata/testsuite-03.units/succeeds-on-restart.sh
|
||||
Restart=on-failure
|
||||
RestartMode=normal
|
10
test/testsuite-03.units/succeeds-on-restart.sh
Executable file
10
test/testsuite-03.units/succeeds-on-restart.sh
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
if [[ ! -f "/succeeds-on-restart.ko" ]]
|
||||
then
|
||||
touch "/succeeds-on-restart.ko"
|
||||
exit 1
|
||||
else
|
||||
rm "/succeeds-on-restart.ko"
|
||||
exit 0
|
||||
fi
|
3
test/testsuite-03.units/succeeds-on-restart.target
Executable file
3
test/testsuite-03.units/succeeds-on-restart.target
Executable file
|
@ -0,0 +1,3 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[Unit]
|
||||
Requires=succeeds-on-restart.service
|
|
@ -153,4 +153,17 @@ systemctl restart propagatestopto-indirect.target
|
|||
assert_rc 3 systemctl --quiet is-active propagatestopto-and-pullin.target
|
||||
assert_rc 3 systemctl --quiet is-active sleep-infinity-simple.service
|
||||
|
||||
# Test restart mode direct
|
||||
systemctl start succeeds-on-restart-restartdirect.target
|
||||
assert_rc 0 systemctl --quiet is-active succeeds-on-restart-restartdirect.target
|
||||
|
||||
systemctl start fails-on-restart-restartdirect.target || :
|
||||
assert_rc 3 systemctl --quiet is-active fails-on-restart-restartdirect.target
|
||||
|
||||
systemctl start succeeds-on-restart.target || :
|
||||
assert_rc 3 systemctl --quiet is-active succeeds-on-restart.target
|
||||
|
||||
systemctl start fails-on-restart.target || :
|
||||
assert_rc 3 systemctl --quiet is-active fails-on-restart.target
|
||||
|
||||
touch /testok
|
||||
|
|
Loading…
Reference in a new issue