Welcome to little lamb

Code » anopa » commit 979d060

Make compatible/require s6 v2.2.0.0

author Olivier Brunel
2015-07-31 16:48:31 UTC
committer Olivier Brunel
2015-08-07 17:24:48 UTC
parent 4d8cb9348c8447f8f78b70c856c2d5272a5f7ff1

Make compatible/require s6 v2.2.0.0

Mainly s6 status file format changed, and readiness in now included
instead of being in a separate "ready" file.

Also event 'D' was added, for "Down & Ready" (after finish script ended)
and aa-setready now uses 'N' instead.

doc/aa-setready.pod +17 -27
doc/aa-start.pod +11 -9
doc/aa-status.pod +9 -12
doc/anopa.pod +14 -0
src/anopa/aa-status.c +19 -47
src/libanopa/service.c +36 -2
src/utils/aa-setready.c +15 -27

diff --git a/doc/aa-setready.pod b/doc/aa-setready.pod
index b461443..014addc 100644
--- a/doc/aa-setready.pod
+++ b/doc/aa-setready.pod
@@ -23,13 +23,12 @@ Show help screen and exit.
 
 =item B<-N, --unready>
 
-Mark the service unready, i.e. remove the I<ready> file (if exists) and emit
-event 'D' on I<event> fifodir.
+Mark the service unready and emit event 'N' on I<event> fifodir.
 
 =item B<-U, --ready>
 
-Mark the service ready, i.e. create the I<ready> file and emit event 'U' on
-I<event> fifodir. This is the default.
+Mark the service ready and emit event 'U' on I<event> fifodir. This is the
+default.
 
 =item B<-V, --version>
 
@@ -42,21 +41,17 @@ Show version information and exit.
 B<aa-setready>(1) is a simple tool to mark a long-running service ready or
 "unready".
 
-Marking a service ready means create the I<ready> file (used by B<s6>) and emit
-event U on the service's fifodir I<event>. This is similar to what
-B<s6-notifywhenup> does.
-
-Marking a service unready means remove the I<ready> file if it exists, and emit
-event D on the service's fifodir I<event>. This is meant for service that can
-stay up (running) but lose their ready state (e.g. connection dropped).
+Marking a service ready or unready means updating its s6 status file, and
+emitting the corresponding event on the service's fifodir I<event>.
+Unreadiness is meant for service that can stay up (running) but lose their ready
+state (e.g. connection dropped).
 
 Obviously you need to have the appropriate permissions to perform all the needed
 tasks.
 
-=head2 RETURN VALUE
+=head1 RETURN VALUE
 
-B<aa-setready>(1) will return 0 on success. If an error occurs one or more
-warning messages will be shown on stderr, and it will return:
+B<aa-setready>(1) will return 0 on success, or one of the following on error:
 
 =over
 
@@ -66,27 +61,22 @@ Syntax error (e.g. unknown option)
 
 =item B<2>
 
-Failed to init timestamp (needed to write the I<ready> file)
+Failed to read s6 status file
 
 =item B<3>
 
-Failed to create I<ready> file
+Service is not up
 
 =item B<4>
 
-Failed to remove the I<ready> file
+Failed to init timestamp (needed for readiness timestamp, when marking ready)
 
-=item B<10>
+=item B<5>
 
-Failed to sent the event on I<event> fifodir
+Failed to write s6 status file
 
-=back
+=item B<6>
 
-It can also return a value higher than 10 if more than one error occurs, e.g. 13
-if it couldn't create the I<ready> file nor emit the event, or 14 if it couldn't
-remove the I<ready> file nor emit the event (Note that this doesn't occur when
-the file doesn't exist, which is not treated as an error.).
+Failed to sent the event on I<event> fifodir
 
-Note that 1 and 2 will always causes immediate termination, i.e.
-B<aa-setready>(1) stops its execution right away (and therefore cannot return 11
-or 12).
+=back
diff --git a/doc/aa-start.pod b/doc/aa-start.pod
index 6d25132..af50dc3 100644
--- a/doc/aa-start.pod
+++ b/doc/aa-start.pod
@@ -133,15 +133,17 @@ not. If so, it disconnects and the service is announced as already up and
 process continues as expected.
 
 If not, B<aa-start>(1) then checks whether there's a file I<gets-ready> in the
-servicedir. It then sends the command to bring it up and removes the I<down>
-file (if present).
-
-If there was no I<gets-ready> file, it waits for event 'u' to be triggered, then
-(disconnects from the fifodir and) announce the service as started. If there was
-one, it will then wait for event 'U' to be triggered instead, announcing the
-service as ready instead. (A message will be shown on event 'u' as information
-only. Note that should event 'd' occur, a message will also be shown, but
-B<aa-start>(1) will still keep waiting for event 'U'.)
+servicedir, and if not whether there is a file I<notification-fd> containing a
+number. It then sends the command to bring it up and removes the I<down> file
+(if present).
+
+If there was no I<gets-ready>/valid I<notification-fd> file, it waits for event
+'u' to be triggered, then (disconnects from the fifodir and) announce the
+service as started. If there was one, it will then wait for event 'U' to be
+triggered instead, announcing the service as ready instead. (A message will be
+shown on event 'u' as information only. Note that should event 'd' occur, a
+message will also be shown, but B<aa-start>(1) will still keep waiting for event
+'U'.)
 
 =head1 STARTING A ONE-SHOT SERVICE
 
diff --git a/doc/aa-status.pod b/doc/aa-status.pod
index b079339..bcacff5 100644
--- a/doc/aa-status.pod
+++ b/doc/aa-status.pod
@@ -67,10 +67,6 @@ reading the I<status.anopa> file created by either B<aa-start>(1) or
 B<aa-stop>(1) as well as the I<status> file from B<s6> for long-run services,
 using whichever one has more recent information.
 
-For long-run services it will also check for the I<ready> file to determine
-whether the service is "Up" or "Ready" (using the timestamp from the I<ready>
-file in the later case).
-
 You can use B<-> as service name to read actual service names from stdin, where
 there must be one name per line.
 
@@ -187,24 +183,25 @@ that is starting will be matched via I<stopped>.
 
 This script I<start>/I<stop> succesfully ran (i.e. and returned 0).
 
-=item B<Up>
+=item B<Up> / B<Up & Ready>
 
 (I<long-run services only.>)
 
 The script I<run> is currently running; Its PID will be specified.
 
-=item B<Ready>
-
-(I<long-run services only.>)
+I<Up & Ready> means that the service indicated readiness (or it was set via e.g.
+B<aa-setready>(1)). Both times for up ('u') and readiness ('U') are shown,
+though in list mode (option B<--list>) only the later in shown.
 
-The script I<run> is currently running, and readiness was signaled; Its PID will
-be specified.
-
-=item B<Down>
+=item B<Down> / B<Down & Ready>
 
 (I<long-run services only.>)
 
 The script I<run> isn't running anymore. Its exitcode or which signal killed it
 will be specified.
 
+I<Down & Ready> means the the I<finish> script (if any) also ended its execution
+(or was killed by B<s6-supervise>). Both times for down ('d') and end-of-finish
+('D') are shown, though in list mode (option B<--list>) only the later in shown.
+
 =back
diff --git a/doc/anopa.pod b/doc/anopa.pod
index 014eaff..8d004c4 100644
--- a/doc/anopa.pod
+++ b/doc/anopa.pod
@@ -110,12 +110,26 @@ be logged; the I<log> service is called the service's logger.
 See B<aa-enable>(1) for how you can use a file instead, to automatically use the
 same logger for all services.
 
+=item An optional regular file named I<notification-fd>
+
+If such a file exists, it means that the service supports readiness
+notification. The file must only contain an unsigned integer, which is the
+number of the file descriptor that the service writes its readiness notification
+to, as per B<s6-supervise> requirements.
+
+This is used by B<aa-start>(1) to determine whether to wait for event 'U'
+instead of 'u' when starting the service.
+
 =item An optional, empty, regular file named I<gets-ready>
 
 This is B<anopa>-specific, and if present indicates to B<aa-start>(1) that the
 service supports readiness, so it will wait for event 'U' (instead of 'u') when
 starting it.
 
+This can be used for services that support readiness outside of the
+I<notification-fd> file interface (e.g. via B<aa-setready>(1) triggered on a log
+event).
+
 =item An optional regular file named I<timeout>
 
 If such a file exists, it should contain the number of seconds before the
diff --git a/src/anopa/aa-status.c b/src/anopa/aa-status.c
index 2ffcff1..74cb001 100644
--- a/src/anopa/aa-status.c
+++ b/src/anopa/aa-status.c
@@ -350,6 +350,12 @@ status_service (struct serv *serv, struct config *cfg)
         else
             put_time (&serv->stamp, 0);
 
+        if (serv->is_s6 && serv->st6.flagready)
+        {
+            aa_bs_noflush (AA_OUT, "Ready:   ");
+            put_time (&serv->st6.readystamp, 0);
+        }
+
         aa_bs_noflush (AA_OUT, "Status:  ");
     }
 
@@ -362,7 +368,11 @@ status_service (struct serv *serv, struct config *cfg)
             char buf[UINT_FMT];
 
             aa_is_noflush (AA_OUT, ANSI_HIGHLIGHT_GREEN_ON);
-            put_s ((serv->is_s6 == 2) ? "Ready" : "Up");
+            put_s ("Up");
+            if (serv->st6.flagready)
+            {
+                put_s (" & Ready");
+            }
             aa_is_noflush (AA_OUT, ANSI_HIGHLIGHT_OFF);
             put_s (" (PID ");
             buf[uint_fmt (buf, serv->st6.pid)] = '\0';
@@ -373,6 +383,10 @@ status_service (struct serv *serv, struct config *cfg)
         {
             aa_is_noflush (AA_OUT, ANSI_HIGHLIGHT_ON);
             put_s ("Down");
+            if (serv->st6.flagready)
+            {
+                put_s (" & Ready");
+            }
             aa_is_noflush (AA_OUT, ANSI_HIGHLIGHT_OFF);
             put_s (" (");
             put_wstat (serv->st6.wstat, max, 0);
@@ -561,56 +575,14 @@ load_service (const char *name, struct config *cfg)
         else if (tain_less (&s->st.stamp, &serv.st6.stamp))
         {
             serv.is_s6 = 1;
-            serv.stamp = serv.st6.stamp;
+            if (cfg->mode == MODE_LIST && serv.st6.flagready)
+                serv.stamp = serv.st6.readystamp;
+            else
+                serv.stamp = serv.st6.stamp;
         }
     }
     if (!serv.is_s6)
         serv.stamp = s->st.stamp;
-    else if (serv.st6.pid && !serv.st6.flagfinishing)
-    {
-        int l = strlen (name);
-        char buf[l + 1 + sizeof (S6_SUPERVISE_READY_FILENAME)];
-        struct stat st;
-
-        byte_copy (buf, l, name);
-        buf[l] = '/';
-        byte_copy (buf + l + 1, sizeof (S6_SUPERVISE_READY_FILENAME), S6_SUPERVISE_READY_FILENAME);
-
-        if (stat (buf, &st) < 0)
-        {
-            if (errno != ENOENT)
-            {
-                int e = errno;
-
-                aa_put_err (name, "Unable to read s6 ready file: ", 0);
-                aa_bs_noflush (AA_ERR, error_str (e));
-                aa_end_err ();
-                return;
-            }
-        }
-        else
-        {
-            char pack[TAIN_PACK];
-
-            if (openreadnclose (buf, pack, TAIN_PACK) < TAIN_PACK)
-            {
-                if (errno != ENOENT)
-                {
-                    int e = errno;
-
-                    aa_put_err (name, "Unable to read s6 ready file: ", 0);
-                    aa_bs_noflush (AA_ERR, error_str (e));
-                    aa_end_err ();
-                    return;
-                }
-            }
-            else
-            {
-                tain_unpack (pack, &serv.stamp);
-                serv.is_s6 = 2;
-            }
-        }
-    }
 
     if (filter_status != FILTER_NONE && !match_status (&serv, filter_status))
         return;
diff --git a/src/libanopa/service.c b/src/libanopa/service.c
index ea5441b..0a82095 100644
--- a/src/libanopa/service.c
+++ b/src/libanopa/service.c
@@ -38,6 +38,8 @@
 #include <anopa/output.h>
 #include "service_internal.h"
 
+#define NOTIFICATION_FILENAME       "notification-fd"
+
 static aa_close_fd_fn close_fd;
 
 static void
@@ -146,12 +148,36 @@ aa_get_service (const char *name, int *si, int new_in_main)
     }
 }
 
+static int
+contains_fd (const char *filename)
+{
+    char buf[UINT_FMT + 1];
+    int r;
+
+    r = openreadnclose_nb (filename, buf, UINT_FMT);
+    if (r < 0)
+    {
+        if (errno != ENOENT)
+            aa_strerr_warnu2sys ("open ", filename);
+        return 0;
+    }
+
+    buf[byte_chr (buf, r, '\n')] = '\0';
+    if (!uint0_scan (buf, &r))
+    {
+        aa_strerr_warn2x ("invalid ", filename);
+        return 0;
+    }
+
+    return 1;
+}
+
 int
 aa_preload_service (int si)
 {
     aa_service_status *svst = &aa_service (si)->st;
     int l_sn = strlen (aa_service_name (aa_service (si)));
-    char buf[l_sn + 1 + sizeof (AA_GETS_READY_FILENAME)];
+    char buf[l_sn + 1 + sizeof (NOTIFICATION_FILENAME)];
 
     byte_copy (buf, l_sn, aa_service_name (aa_service (si)));
     byte_copy (buf + l_sn, 5, "/run");
@@ -166,9 +192,17 @@ aa_preload_service (int si)
     else
     {
         svst->type = AA_TYPE_LONGRUN;
+        aa_service (si)->gets_ready = 0;
 
         byte_copy (buf + l_sn, 1 + sizeof (AA_GETS_READY_FILENAME), "/" AA_GETS_READY_FILENAME);
-        aa_service (si)->gets_ready = (access (buf, F_OK) == 0) ? 1 : 0;
+        if (access (buf, F_OK) == 0)
+            aa_service (si)->gets_ready = 1;
+        else
+        {
+            byte_copy (buf + l_sn, 1 + sizeof (NOTIFICATION_FILENAME), "/" NOTIFICATION_FILENAME);
+            if (access (buf, F_OK) == 0 && contains_fd (buf))
+                aa_service (si)->gets_ready = 1;
+        }
     }
 
     return 0;
diff --git a/src/utils/aa-setready.c b/src/utils/aa-setready.c
index bc985f2..e129ed3 100644
--- a/src/utils/aa-setready.c
+++ b/src/utils/aa-setready.c
@@ -47,7 +47,6 @@ main (int argc, char * const argv[])
 {
     PROG = "aa-setready";
     int ready = 1;
-    int r = 0;
 
     for (;;)
     {
@@ -97,43 +96,32 @@ main (int argc, char * const argv[])
     {
         int l = strlen (argv[0]);
         char fifodir[l + 1 + sizeof (S6_SUPERVISE_EVENTDIR)];
-        char readyfile[l + 1 + sizeof (S6_SUPERVISE_READY_FILENAME)];
+        s6_svstatus_t st6 = S6_SVSTATUS_ZERO;
 
         byte_copy (fifodir, l, argv[0]);
         fifodir[l] = '/';
         byte_copy (fifodir + l + 1, sizeof (S6_SUPERVISE_EVENTDIR), S6_SUPERVISE_EVENTDIR);
 
-        byte_copy (readyfile, l, argv[0]);
-        readyfile[l] = '/';
-        byte_copy (readyfile + l + 1, sizeof (S6_SUPERVISE_READY_FILENAME), S6_SUPERVISE_READY_FILENAME);
+        if (!s6_svstatus_read (argv[0], &st6))
+            aa_strerr_diefu1sys (2, "read s6 status");
+        if (!(st6.pid && !st6.flagfinishing))
+            aa_strerr_dief1x (3, "service is not up");
 
         if (ready)
         {
-            char data[TAIN_PACK];
-
-            if (!tain_now_g())
-                aa_strerr_diefu1sys (2, "tain_now");
-            tain_pack (data, &STAMP);
-
-            if (!openwritenclose_suffix (readyfile, data, TAIN_PACK, ".new"))
-            {
-                r = 3;
-                aa_strerr_warnu2sys ("create ", readyfile);
-            }
+            st6.flagready = 1;
+            if (!tain_now (&st6.readystamp))
+                aa_strerr_diefu1sys (4, "tain_now");
         }
         else
-            if (unlink (readyfile) < 0 && errno != ENOENT)
-            {
-                r = 4;
-                aa_strerr_warnu2sys ("remove ", readyfile);
-            }
+            st6.flagready = 0;
 
-        if (ftrigw_notify (fifodir, (ready) ? 'U' : 'D') < 0)
-        {
-            r += 10;
-            aa_strerr_warnu4sys ("send event ", (ready) ? "U": "D" , " via ", fifodir);
-        }
+        if (!s6_svstatus_write (argv[0], &st6))
+            aa_strerr_diefu1sys (5, "write s6 status");
+
+        if (ftrigw_notify (fifodir, (ready) ? 'U' : 'N') < 0)
+            aa_strerr_diefu4sys (6, "send event ", (ready) ? "U": "N" , " via ", fifodir);
     }
 
-    return r;
+    return 0;
 }