LCOV - code coverage report
Current view: top level - fencing - st_output.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 264 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 18 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2019-2024 the Pacemaker project contributors
       3             :  *
       4             :  * The version control history for this file may have further details.
       5             :  *
       6             :  * This source code is licensed under the GNU Lesser General Public License
       7             :  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
       8             :  */
       9             : 
      10             : #include <crm_internal.h>
      11             : #include <stdarg.h>
      12             : #include <stdint.h>
      13             : 
      14             : #include <crm/stonith-ng.h>
      15             : #include <crm/common/iso8601.h>
      16             : #include <crm/common/util.h>
      17             : #include <crm/common/xml.h>
      18             : #include <crm/common/output.h>
      19             : #include <crm/common/output_internal.h>
      20             : #include <crm/common/xml_internal.h>
      21             : #include <crm/fencing/internal.h>
      22             : #include <crm/pengine/internal.h>
      23             : 
      24             : /*!
      25             :  * \internal
      26             :  * \brief Convert seconds and nanoseconds to a date/time/time-zone string
      27             :  *
      28             :  * \param[in] sec        Seconds
      29             :  * \param[in] nsec       Nanoseconds
      30             :  * \param[in] show_usec  Whether to show time in microseconds resolution (if
      31             :  *                       false, use seconds resolution)
      32             :  *
      33             :  * \return A string representation of \p sec and \nsec
      34             :  *
      35             :  * \note The caller is responsible for freeing the return value using \p free().
      36             :  */
      37             : static char *
      38           0 : timespec_string(time_t sec, long nsec, bool show_usec) {
      39           0 :     const struct timespec ts = {
      40             :         .tv_sec = sec,
      41             :         .tv_nsec = nsec,
      42             :     };
      43             : 
      44           0 :     return pcmk__timespec2str(&ts,
      45             :                               crm_time_log_date
      46             :                               |crm_time_log_timeofday
      47             :                               |crm_time_log_with_timezone
      48             :                               |(show_usec? crm_time_usecs : 0));
      49             : }
      50             : 
      51             : /*!
      52             :  * \internal
      53             :  * \brief Return a status-friendly description of fence history entry state
      54             :  *
      55             :  * \param[in] history  Fence history entry to describe
      56             :  *
      57             :  * \return One-word description of history entry state
      58             :  * \note This is similar to stonith_op_state_str() except user-oriented (i.e.
      59             :  *       for cluster status) instead of developer-oriented (for debug logs).
      60             :  */
      61             : static const char *
      62           0 : state_str(const stonith_history_t *history)
      63             : {
      64           0 :     switch (history->state) {
      65           0 :         case st_failed: return "failed";
      66           0 :         case st_done:   return "successful";
      67           0 :         default:        return "pending";
      68             :     }
      69             : }
      70             : 
      71             : /*!
      72             :  * \internal
      73             :  * \brief Create a description of a fencing history entry for status displays
      74             :  *
      75             :  * \param[in] history          Fencing history entry to describe
      76             :  * \param[in] full_history     Whether this is for full or condensed history
      77             :  * \param[in] later_succeeded  Node that a later equivalent attempt succeeded
      78             :  *                             from, or NULL if none
      79             :  * \param[in] show_opts        Flag group of pcmk_show_opt_e
      80             :  *
      81             :  * \return Newly created string with fencing history entry description
      82             :  *
      83             :  * \note The caller is responsible for freeing the return value with g_free().
      84             :  * \note This is similar to stonith__event_description(), except this is used
      85             :  *       for history entries (stonith_history_t) in status displays rather than
      86             :  *       event notifications (stonith_event_t) in log messages.
      87             :  */
      88             : gchar *
      89           0 : stonith__history_description(const stonith_history_t *history,
      90             :                              bool full_history, const char *later_succeeded,
      91             :                              uint32_t show_opts)
      92             : {
      93           0 :     GString *str = g_string_sized_new(256); // Generous starting size
      94           0 :     char *completed_time_s = NULL;
      95             : 
      96           0 :     if ((history->state == st_failed) || (history->state == st_done)) {
      97           0 :         completed_time_s = timespec_string(history->completed,
      98           0 :                                            history->completed_nsec, true);
      99             :     }
     100             : 
     101           0 :     pcmk__g_strcat(str,
     102           0 :                    stonith_action_str(history->action), " of ", history->target,
     103             :                    NULL);
     104             : 
     105           0 :     if (!pcmk_is_set(show_opts, pcmk_show_failed_detail)) {
     106             :         // More human-friendly
     107           0 :         if (((history->state == st_failed) || (history->state == st_done))
     108           0 :             && (history->delegate != NULL)) {
     109             : 
     110           0 :             pcmk__g_strcat(str, " by ", history->delegate, NULL);
     111             :         }
     112           0 :         pcmk__g_strcat(str, " for ", history->client, "@", history->origin,
     113             :                        NULL);
     114           0 :         if (!full_history) {
     115           0 :             g_string_append(str, " last"); // For example, "last failed at ..."
     116             :         }
     117             :     }
     118             : 
     119           0 :     pcmk__add_word(&str, 0, state_str(history));
     120             : 
     121             :     // For failed actions, add exit reason if available
     122           0 :     if ((history->state == st_failed) && (history->exit_reason != NULL)) {
     123           0 :         pcmk__g_strcat(str, " (", history->exit_reason, ")", NULL);
     124             :     }
     125             : 
     126           0 :     if (pcmk_is_set(show_opts, pcmk_show_failed_detail)) {
     127             :         // More technical
     128           0 :         g_string_append(str, ": ");
     129             : 
     130             :         // For completed actions, add delegate if available
     131           0 :         if (((history->state == st_failed) || (history->state == st_done))
     132           0 :             && (history->delegate != NULL)) {
     133             : 
     134           0 :             pcmk__g_strcat(str, PCMK_XA_DELEGATE "=", history->delegate, ", ",
     135             :                            NULL);
     136             :         }
     137             : 
     138             :         // Add information about originator
     139           0 :         pcmk__g_strcat(str,
     140           0 :                        PCMK_XA_CLIENT "=", history->client, ", "
     141           0 :                        PCMK_XA_ORIGIN "=", history->origin, NULL);
     142             : 
     143             :         // For completed actions, add completion time
     144           0 :         if (completed_time_s != NULL) {
     145           0 :             if (full_history) {
     146           0 :                 g_string_append(str, ", completed");
     147           0 :             } else if (history->state == st_failed) {
     148           0 :                 g_string_append(str, ", last-failed");
     149             :             } else {
     150           0 :                 g_string_append(str, ", last-successful");
     151             :             }
     152           0 :             pcmk__g_strcat(str, "='", completed_time_s, "'", NULL);
     153             :         }
     154           0 :     } else if (completed_time_s != NULL) {
     155             :         // More human-friendly
     156           0 :         pcmk__g_strcat(str, " at ", completed_time_s, NULL);
     157             :     }
     158             : 
     159           0 :     if ((history->state == st_failed) && (later_succeeded != NULL)) {
     160           0 :         pcmk__g_strcat(str,
     161             :                        " (a later attempt from ", later_succeeded,
     162             :                        " succeeded)", NULL);
     163             :     }
     164             : 
     165           0 :     free(completed_time_s);
     166           0 :     return g_string_free(str, FALSE);
     167             : }
     168             : 
     169             : PCMK__OUTPUT_ARGS("failed-fencing-list", "stonith_history_t *", "GList *",
     170             :                   "uint32_t", "uint32_t", "bool")
     171             : static int
     172           0 : failed_history(pcmk__output_t *out, va_list args)
     173             : {
     174           0 :     stonith_history_t *history = va_arg(args, stonith_history_t *);
     175           0 :     GList *only_node = va_arg(args, GList *);
     176           0 :     uint32_t section_opts = va_arg(args, uint32_t);
     177           0 :     uint32_t show_opts = va_arg(args, uint32_t);
     178           0 :     bool print_spacer = va_arg(args, int);
     179             : 
     180           0 :     int rc = pcmk_rc_no_output;
     181             : 
     182           0 :     for (stonith_history_t *hp = history; hp; hp = hp->next) {
     183           0 :         if (hp->state != st_failed) {
     184           0 :             continue;
     185             :         }
     186             : 
     187           0 :         if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
     188           0 :             continue;
     189             :         }
     190             : 
     191           0 :         PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Failed Fencing Actions");
     192           0 :         out->message(out, "stonith-event", hp,
     193           0 :                      pcmk_all_flags_set(section_opts, pcmk_section_fencing_all),
     194             :                      false, stonith__later_succeeded(hp, history), show_opts);
     195           0 :         out->increment_list(out);
     196             :     }
     197             : 
     198           0 :     PCMK__OUTPUT_LIST_FOOTER(out, rc);
     199           0 :     return rc;
     200             : }
     201             : 
     202             : PCMK__OUTPUT_ARGS("fencing-list", "stonith_history_t *", "GList *", "uint32_t",
     203             :                   "uint32_t", "bool")
     204             : static int
     205           0 : stonith_history(pcmk__output_t *out, va_list args)
     206             : {
     207           0 :     stonith_history_t *history = va_arg(args, stonith_history_t *);
     208           0 :     GList *only_node = va_arg(args, GList *);
     209           0 :     uint32_t section_opts = va_arg(args, uint32_t);
     210           0 :     uint32_t show_opts = va_arg(args, uint32_t);
     211           0 :     bool print_spacer = va_arg(args, int);
     212             : 
     213           0 :     int rc = pcmk_rc_no_output;
     214             : 
     215           0 :     for (stonith_history_t *hp = history; hp; hp = hp->next) {
     216           0 :         if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
     217           0 :             continue;
     218             :         }
     219             : 
     220           0 :         if (hp->state != st_failed) {
     221           0 :             PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Fencing History");
     222           0 :             out->message(out, "stonith-event", hp,
     223           0 :                          pcmk_all_flags_set(section_opts,
     224             :                                             pcmk_section_fencing_all),
     225             :                          false, stonith__later_succeeded(hp, history), show_opts);
     226           0 :             out->increment_list(out);
     227             :         }
     228             :     }
     229             : 
     230           0 :     PCMK__OUTPUT_LIST_FOOTER(out, rc);
     231           0 :     return rc;
     232             : }
     233             : 
     234             : PCMK__OUTPUT_ARGS("full-fencing-list", "crm_exit_t", "stonith_history_t *",
     235             :                   "GList *", "uint32_t", "uint32_t", "bool")
     236             : static int
     237           0 : full_history(pcmk__output_t *out, va_list args)
     238             : {
     239           0 :     crm_exit_t history_rc G_GNUC_UNUSED = va_arg(args, crm_exit_t);
     240           0 :     stonith_history_t *history = va_arg(args, stonith_history_t *);
     241           0 :     GList *only_node = va_arg(args, GList *);
     242           0 :     uint32_t section_opts = va_arg(args, uint32_t);
     243           0 :     uint32_t show_opts = va_arg(args, uint32_t);
     244           0 :     bool print_spacer = va_arg(args, int);
     245             : 
     246           0 :     int rc = pcmk_rc_no_output;
     247             : 
     248           0 :     for (stonith_history_t *hp = history; hp; hp = hp->next) {
     249           0 :         if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
     250           0 :             continue;
     251             :         }
     252             : 
     253           0 :         PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Fencing History");
     254           0 :         out->message(out, "stonith-event", hp,
     255           0 :                      pcmk_all_flags_set(section_opts, pcmk_section_fencing_all),
     256             :                      false, stonith__later_succeeded(hp, history), show_opts);
     257           0 :         out->increment_list(out);
     258             :     }
     259             : 
     260           0 :     PCMK__OUTPUT_LIST_FOOTER(out, rc);
     261           0 :     return rc;
     262             : }
     263             : 
     264             : PCMK__OUTPUT_ARGS("full-fencing-list", "crm_exit_t", "stonith_history_t *",
     265             :                   "GList *", "uint32_t", "uint32_t", "bool")
     266             : static int
     267           0 : full_history_xml(pcmk__output_t *out, va_list args)
     268             : {
     269           0 :     crm_exit_t history_rc = va_arg(args, crm_exit_t);
     270           0 :     stonith_history_t *history = va_arg(args, stonith_history_t *);
     271           0 :     GList *only_node = va_arg(args, GList *);
     272           0 :     uint32_t section_opts = va_arg(args, uint32_t);
     273           0 :     uint32_t show_opts = va_arg(args, uint32_t);
     274           0 :     bool print_spacer G_GNUC_UNUSED = va_arg(args, int);
     275             : 
     276           0 :     int rc = pcmk_rc_no_output;
     277             : 
     278           0 :     if (history_rc == 0) {
     279           0 :         for (stonith_history_t *hp = history; hp; hp = hp->next) {
     280           0 :             if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
     281           0 :                 continue;
     282             :             }
     283             : 
     284           0 :             PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Fencing History");
     285           0 :             out->message(out, "stonith-event", hp,
     286           0 :                          pcmk_all_flags_set(section_opts,
     287             :                                             pcmk_section_fencing_all),
     288             :                          false, stonith__later_succeeded(hp, history), show_opts);
     289           0 :             out->increment_list(out);
     290             :         }
     291             : 
     292           0 :         PCMK__OUTPUT_LIST_FOOTER(out, rc);
     293             :     } else {
     294           0 :         char *rc_s = pcmk__itoa(history_rc);
     295             : 
     296           0 :         pcmk__output_create_xml_node(out, PCMK_XE_FENCE_HISTORY,
     297             :                                      PCMK_XA_STATUS, rc_s,
     298             :                                      NULL);
     299           0 :         free(rc_s);
     300             : 
     301           0 :         rc = pcmk_rc_ok;
     302             :     }
     303             : 
     304           0 :     return rc;
     305             : }
     306             : 
     307             : PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
     308             : static int
     309           0 : last_fenced_html(pcmk__output_t *out, va_list args) {
     310           0 :     const char *target = va_arg(args, const char *);
     311           0 :     time_t when = va_arg(args, time_t);
     312             : 
     313           0 :     if (when) {
     314           0 :         char *buf = crm_strdup_printf("Node %s last fenced at: %s", target, ctime(&when));
     315           0 :         pcmk__output_create_html_node(out, PCMK__XE_DIV, NULL, NULL, buf);
     316           0 :         free(buf);
     317           0 :         return pcmk_rc_ok;
     318             :     } else {
     319           0 :         return pcmk_rc_no_output;
     320             :     }
     321             : }
     322             : 
     323             : PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
     324             : static int
     325           0 : last_fenced_text(pcmk__output_t *out, va_list args) {
     326           0 :     const char *target = va_arg(args, const char *);
     327           0 :     time_t when = va_arg(args, time_t);
     328             : 
     329           0 :     if (when) {
     330           0 :         pcmk__indented_printf(out, "Node %s last fenced at: %s", target, ctime(&when));
     331             :     } else {
     332           0 :         pcmk__indented_printf(out, "Node %s has never been fenced\n", target);
     333             :     }
     334             : 
     335           0 :     return pcmk_rc_ok;
     336             : }
     337             : 
     338             : PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
     339             : static int
     340           0 : last_fenced_xml(pcmk__output_t *out, va_list args) {
     341           0 :     const char *target = va_arg(args, const char *);
     342           0 :     time_t when = va_arg(args, time_t);
     343             : 
     344           0 :     if (when) {
     345           0 :         char *buf = timespec_string(when, 0, false);
     346             : 
     347           0 :         pcmk__output_create_xml_node(out, PCMK_XE_LAST_FENCED,
     348             :                                      PCMK_XA_TARGET, target,
     349             :                                      PCMK_XA_WHEN, buf,
     350             :                                      NULL);
     351             : 
     352           0 :         free(buf);
     353           0 :         return pcmk_rc_ok;
     354             :     } else {
     355           0 :         return pcmk_rc_no_output;
     356             :     }
     357             : }
     358             : 
     359             : PCMK__OUTPUT_ARGS("pending-fencing-list", "stonith_history_t *", "GList *",
     360             :                   "uint32_t", "uint32_t", "bool")
     361             : static int
     362           0 : pending_actions(pcmk__output_t *out, va_list args)
     363             : {
     364           0 :     stonith_history_t *history = va_arg(args, stonith_history_t *);
     365           0 :     GList *only_node = va_arg(args, GList *);
     366           0 :     uint32_t section_opts = va_arg(args, uint32_t);
     367           0 :     uint32_t show_opts = va_arg(args, uint32_t);
     368           0 :     bool print_spacer = va_arg(args, int);
     369             : 
     370           0 :     int rc = pcmk_rc_no_output;
     371             : 
     372           0 :     for (stonith_history_t *hp = history; hp; hp = hp->next) {
     373           0 :         if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
     374           0 :             continue;
     375             :         }
     376             : 
     377             :         /* Skip the rest of the history after we see a failed/done action */
     378           0 :         if ((hp->state == st_failed) || (hp->state == st_done)) {
     379             :             break;
     380             :         }
     381             : 
     382           0 :         PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Pending Fencing Actions");
     383           0 :         out->message(out, "stonith-event", hp,
     384           0 :                      pcmk_all_flags_set(section_opts, pcmk_section_fencing_all),
     385             :                      false, stonith__later_succeeded(hp, history), show_opts);
     386           0 :         out->increment_list(out);
     387             :     }
     388             : 
     389           0 :     PCMK__OUTPUT_LIST_FOOTER(out, rc);
     390           0 :     return rc;
     391             : }
     392             : 
     393             : PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "bool", "bool",
     394             :                   "const char *", "uint32_t")
     395             : static int
     396           0 : stonith_event_html(pcmk__output_t *out, va_list args)
     397             : {
     398           0 :     stonith_history_t *event = va_arg(args, stonith_history_t *);
     399           0 :     bool full_history = va_arg(args, int);
     400           0 :     bool completed_only G_GNUC_UNUSED = va_arg(args, int);
     401           0 :     const char *succeeded = va_arg(args, const char *);
     402           0 :     uint32_t show_opts = va_arg(args, uint32_t);
     403             : 
     404           0 :     gchar *desc = stonith__history_description(event, full_history, succeeded,
     405             :                                                show_opts);
     406             : 
     407           0 :     switch(event->state) {
     408           0 :         case st_done:
     409           0 :             out->list_item(out, "successful-stonith-event", "%s", desc);
     410           0 :             break;
     411             : 
     412           0 :         case st_failed:
     413           0 :             out->list_item(out, "failed-stonith-event", "%s", desc);
     414           0 :             break;
     415             : 
     416           0 :         default:
     417           0 :             out->list_item(out, "pending-stonith-event", "%s", desc);
     418           0 :             break;
     419             :     }
     420           0 :     g_free(desc);
     421           0 :     return pcmk_rc_ok;
     422             : }
     423             : 
     424             : PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "bool", "bool",
     425             :                   "const char *", "uint32_t")
     426             : static int
     427           0 : stonith_event_text(pcmk__output_t *out, va_list args)
     428             : {
     429           0 :     stonith_history_t *event = va_arg(args, stonith_history_t *);
     430           0 :     bool full_history = va_arg(args, int);
     431           0 :     bool completed_only = va_arg(args, int);
     432           0 :     const char *succeeded = va_arg(args, const char *);
     433           0 :     uint32_t show_opts = va_arg(args, uint32_t);
     434             : 
     435           0 :     if (completed_only) {
     436           0 :         pcmk__formatted_printf(out, "%lld\n", (long long) event->completed);
     437             :     } else {
     438           0 :         gchar *desc = stonith__history_description(event, full_history, succeeded,
     439             :                                                    show_opts);
     440             : 
     441           0 :         pcmk__indented_printf(out, "%s\n", desc);
     442           0 :         g_free(desc);
     443             :     }
     444             : 
     445           0 :     return pcmk_rc_ok;
     446             : }
     447             : 
     448             : PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "bool", "bool",
     449             :                   "const char *", "uint32_t")
     450             : static int
     451           0 : stonith_event_xml(pcmk__output_t *out, va_list args)
     452             : {
     453           0 :     stonith_history_t *event = va_arg(args, stonith_history_t *);
     454           0 :     bool full_history G_GNUC_UNUSED = va_arg(args, int);
     455           0 :     bool completed_only G_GNUC_UNUSED = va_arg(args, int);
     456           0 :     const char *succeeded G_GNUC_UNUSED = va_arg(args, const char *);
     457           0 :     uint32_t show_opts G_GNUC_UNUSED = va_arg(args, uint32_t);
     458             : 
     459           0 :     xmlNodePtr node = NULL;
     460             : 
     461           0 :     node = pcmk__output_create_xml_node(out, PCMK_XE_FENCE_EVENT,
     462             :                                         PCMK_XA_ACTION, event->action,
     463             :                                         PCMK_XA_TARGET, event->target,
     464             :                                         PCMK_XA_CLIENT, event->client,
     465             :                                         PCMK_XA_ORIGIN, event->origin,
     466             :                                         NULL);
     467             : 
     468           0 :     switch (event->state) {
     469           0 :         case st_failed:
     470           0 :             pcmk__xe_set_props(node,
     471             :                                PCMK_XA_STATUS, PCMK_VALUE_FAILED,
     472             :                                PCMK_XA_EXIT_REASON, event->exit_reason,
     473             :                                NULL);
     474           0 :             break;
     475             : 
     476           0 :         case st_done:
     477           0 :             crm_xml_add(node, PCMK_XA_STATUS, PCMK_VALUE_SUCCESS);
     478           0 :             break;
     479             : 
     480           0 :         default: {
     481           0 :             char *state = pcmk__itoa(event->state);
     482           0 :             pcmk__xe_set_props(node,
     483             :                                PCMK_XA_STATUS, PCMK_VALUE_PENDING,
     484             :                                PCMK_XA_EXTENDED_STATUS, state,
     485             :                                NULL);
     486           0 :             free(state);
     487           0 :             break;
     488             :         }
     489             :     }
     490             : 
     491           0 :     if (event->delegate != NULL) {
     492           0 :         crm_xml_add(node, PCMK_XA_DELEGATE, event->delegate);
     493             :     }
     494             : 
     495           0 :     if ((event->state == st_failed) || (event->state == st_done)) {
     496           0 :         char *time_s = timespec_string(event->completed, event->completed_nsec,
     497             :                                        true);
     498             : 
     499           0 :         crm_xml_add(node, PCMK_XA_COMPLETED, time_s);
     500           0 :         free(time_s);
     501             :     }
     502             : 
     503           0 :     return pcmk_rc_ok;
     504             : }
     505             : 
     506             : PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "const char *",
     507             :                   "const char *", "int")
     508             : static int
     509           0 : validate_agent_html(pcmk__output_t *out, va_list args) {
     510           0 :     const char *agent = va_arg(args, const char *);
     511           0 :     const char *device = va_arg(args, const char *);
     512           0 :     const char *output = va_arg(args, const char *);
     513           0 :     const char *error_output = va_arg(args, const char *);
     514           0 :     int rc = va_arg(args, int);
     515             : 
     516           0 :     if (device) {
     517           0 :         char *buf = crm_strdup_printf("Validation of %s on %s %s", agent, device,
     518             :                                       rc ? "failed" : "succeeded");
     519           0 :         pcmk__output_create_html_node(out, PCMK__XE_DIV, NULL, NULL, buf);
     520           0 :         free(buf);
     521             :     } else {
     522           0 :         char *buf = crm_strdup_printf("Validation of %s %s", agent,
     523             :                                       rc ? "failed" : "succeeded");
     524           0 :         pcmk__output_create_html_node(out, PCMK__XE_DIV, NULL, NULL, buf);
     525           0 :         free(buf);
     526             :     }
     527             : 
     528           0 :     out->subprocess_output(out, rc, output, error_output);
     529           0 :     return rc;
     530             : }
     531             : 
     532             : PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "const char *",
     533             :                   "const char *", "int")
     534             : static int
     535           0 : validate_agent_text(pcmk__output_t *out, va_list args) {
     536           0 :     const char *agent = va_arg(args, const char *);
     537           0 :     const char *device = va_arg(args, const char *);
     538           0 :     const char *output = va_arg(args, const char *);
     539           0 :     const char *error_output = va_arg(args, const char *);
     540           0 :     int rc = va_arg(args, int);
     541             : 
     542           0 :     if (device) {
     543           0 :         pcmk__indented_printf(out, "Validation of %s on %s %s\n", agent, device,
     544             :                               rc ? "failed" : "succeeded");
     545             :     } else {
     546           0 :         pcmk__indented_printf(out, "Validation of %s %s\n", agent,
     547             :                               rc ? "failed" : "succeeded");
     548             :     }
     549             : 
     550           0 :     out->subprocess_output(out, rc, output, error_output);
     551           0 :     return rc;
     552             : }
     553             : 
     554             : PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "const char *",
     555             :                   "const char *", "int")
     556             : static int
     557           0 : validate_agent_xml(pcmk__output_t *out, va_list args) {
     558           0 :     const char *agent = va_arg(args, const char *);
     559           0 :     const char *device = va_arg(args, const char *);
     560           0 :     const char *output = va_arg(args, const char *);
     561           0 :     const char *error_output = va_arg(args, const char *);
     562           0 :     int rc = va_arg(args, int);
     563             : 
     564           0 :     const char *valid = pcmk__btoa(rc == pcmk_ok);
     565           0 :     xmlNodePtr node = pcmk__output_create_xml_node(out, PCMK_XE_VALIDATE,
     566             :                                                    PCMK_XA_AGENT, agent,
     567             :                                                    PCMK_XA_VALID, valid,
     568             :                                                    NULL);
     569             : 
     570           0 :     if (device != NULL) {
     571           0 :         crm_xml_add(node, PCMK_XA_DEVICE, device);
     572             :     }
     573             : 
     574           0 :     pcmk__output_xml_push_parent(out, node);
     575           0 :     out->subprocess_output(out, rc, output, error_output);
     576           0 :     pcmk__output_xml_pop_parent(out);
     577             : 
     578           0 :     return rc;
     579             : }
     580             : 
     581             : static pcmk__message_entry_t fmt_functions[] = {
     582             :     { "failed-fencing-list", "default", failed_history },
     583             :     { "fencing-list", "default", stonith_history },
     584             :     { "full-fencing-list", "default", full_history },
     585             :     { "full-fencing-list", "xml", full_history_xml },
     586             :     { "last-fenced", "html", last_fenced_html },
     587             :     { "last-fenced", "log", last_fenced_text },
     588             :     { "last-fenced", "text", last_fenced_text },
     589             :     { "last-fenced", "xml", last_fenced_xml },
     590             :     { "pending-fencing-list", "default", pending_actions },
     591             :     { "stonith-event", "html", stonith_event_html },
     592             :     { "stonith-event", "log", stonith_event_text },
     593             :     { "stonith-event", "text", stonith_event_text },
     594             :     { "stonith-event", "xml", stonith_event_xml },
     595             :     { "validate", "html", validate_agent_html },
     596             :     { "validate", "log", validate_agent_text },
     597             :     { "validate", "text", validate_agent_text },
     598             :     { "validate", "xml", validate_agent_xml },
     599             : 
     600             :     { NULL, NULL, NULL }
     601             : };
     602             : 
     603             : void
     604           0 : stonith__register_messages(pcmk__output_t *out) {
     605           0 :     pcmk__register_messages(out, fmt_functions);
     606           0 : }

Generated by: LCOV version 1.14