author | Olivier Brunel
<jjk@jjacky.com> 2015-07-31 16:48:31 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2015-08-07 17:24:48 UTC |
parent | 4d8cb9348c8447f8f78b70c856c2d5272a5f7ff1 |
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; }