[systemd-devel] [RFC PATCH] service: add FailureAction= option

Michael Olbrich m.olbrich at pengutronix.de
Wed Mar 26 02:02:51 PDT 2014


It has the same possible values as StartLimitAction= and is executed
immediately if a service fails.
---

Hi Lennart,

Something like this maybe? I'm not quite sure about the condition in
service_enter_dead(). I don't think the action should be executed when the
service is explicitly stopped. Maybe it should depend on !forbid_restart?

If you like, I'll add some documentation. An maybe a follow-up patch to
rename the StartLimitAction type? To what though?

Regards,
Michael

 src/core/dbus-service.c               |  1 +
 src/core/load-fragment-gperf.gperf.m4 |  1 +
 src/core/service.c                    | 31 ++++++++++++++++++++-----------
 src/core/service.h                    |  2 ++
 4 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 0451790..1e710e3 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -50,6 +50,7 @@ const sd_bus_vtable bus_service_vtable[] = {
         SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Service, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Service, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("StartLimitAction", "s", property_get_start_limit_action, offsetof(Service, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("FailureAction", "s", property_get_start_limit_action, offsetof(Service, failure_action), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("PermissionsStartOnly", "b", bus_property_get_bool, offsetof(Service, permissions_start_only), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RootDirectoryStartOnly", "b", bus_property_get_bool, offsetof(Service, root_directory_start_only), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RemainAfterExit", "b", bus_property_get_bool, offsetof(Service, remain_after_exit), SD_BUS_VTABLE_PROPERTY_CONST),
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index dbb5d13..dc83247 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -180,6 +180,7 @@ Service.WatchdogSec,             config_parse_sec,                   0,
 Service.StartLimitInterval,      config_parse_sec,                   0,                             offsetof(Service, start_limit.interval)
 Service.StartLimitBurst,         config_parse_unsigned,              0,                             offsetof(Service, start_limit.burst)
 Service.StartLimitAction,        config_parse_start_limit_action,    0,                             offsetof(Service, start_limit_action)
+Service.FailureAction,           config_parse_start_limit_action,    0,                             offsetof(Service, failure_action)
 Service.Type,                    config_parse_service_type,          0,                             offsetof(Service, type)
 Service.Restart,                 config_parse_service_restart,       0,                             offsetof(Service, restart)
 Service.PermissionsStartOnly,    config_parse_bool,                  0,                             offsetof(Service, permissions_start_only)
diff --git a/src/core/service.c b/src/core/service.c
index ae3695a..ab161a5 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1835,6 +1835,8 @@ static int cgroup_good(Service *s) {
         return !r;
 }
 
+static int service_execute_action(Service *s, StartLimitAction action, const char *reason);
+
 static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) {
         int r;
         assert(s);
@@ -1844,7 +1846,9 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
 
         service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
 
-        if (allow_restart &&
+        if (s->result != SERVICE_SUCCESS && s->failure_action != SERVICE_START_LIMIT_NONE)
+                service_execute_action(s, s->failure_action, "failed");
+        else if (allow_restart &&
             !s->forbid_restart &&
             (s->restart == SERVICE_RESTART_ALWAYS ||
              (s->restart == SERVICE_RESTART_ON_SUCCESS && s->result == SERVICE_SUCCESS) ||
@@ -2366,18 +2370,14 @@ fail:
         service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
 }
 
-static int service_start_limit_test(Service *s) {
+static int service_execute_action(Service *s, StartLimitAction action, const char *reason) {
         assert(s);
 
-        if (ratelimit_test(&s->start_limit))
-                return 0;
-
-        switch (s->start_limit_action) {
+        switch (action) {
 
         case SERVICE_START_LIMIT_NONE:
                 log_warning_unit(UNIT(s)->id,
-                                 "%s start request repeated too quickly, refusing to start.",
-                                 UNIT(s)->id);
+                                 "%s %s, refusing to start.", UNIT(s)->id, reason);
                 break;
 
         case SERVICE_START_LIMIT_REBOOT: {
@@ -2385,7 +2385,7 @@ static int service_start_limit_test(Service *s) {
                 int r;
 
                 log_warning_unit(UNIT(s)->id,
-                                 "%s start request repeated too quickly, rebooting.", UNIT(s)->id);
+                                 "%s %s, rebooting.", UNIT(s)->id, reason);
 
                 r = manager_add_job_by_name(UNIT(s)->manager, JOB_START,
                                             SPECIAL_REBOOT_TARGET, JOB_REPLACE,
@@ -2399,13 +2399,13 @@ static int service_start_limit_test(Service *s) {
 
         case SERVICE_START_LIMIT_REBOOT_FORCE:
                 log_warning_unit(UNIT(s)->id,
-                                 "%s start request repeated too quickly, forcibly rebooting.", UNIT(s)->id);
+                                 "%s %s, forcibly rebooting.", UNIT(s)->id, reason);
                 UNIT(s)->manager->exit_code = MANAGER_REBOOT;
                 break;
 
         case SERVICE_START_LIMIT_REBOOT_IMMEDIATE:
                 log_warning_unit(UNIT(s)->id,
-                                 "%s start request repeated too quickly, rebooting immediately.", UNIT(s)->id);
+                                 "%s %s, rebooting immediately.", UNIT(s)->id, reason);
                 sync();
                 reboot(RB_AUTOBOOT);
                 break;
@@ -2419,6 +2419,15 @@ static int service_start_limit_test(Service *s) {
         return -ECANCELED;
 }
 
+static int service_start_limit_test(Service *s) {
+        assert(s);
+
+        if (ratelimit_test(&s->start_limit))
+                return 0;
+
+        return service_execute_action(s, s->start_limit_action, "start request repeated too quickly");
+}
+
 static int service_start(Unit *u) {
         Service *s = SERVICE(u);
         int r;
diff --git a/src/core/service.h b/src/core/service.h
index 1992926..d76563d 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -187,6 +187,8 @@ struct Service {
 
         char *status_text;
 
+        StartLimitAction failure_action;
+
         RateLimit start_limit;
         StartLimitAction start_limit_action;
 
-- 
1.9.1



More information about the systemd-devel mailing list