LCOV - code coverage report
Current view: top level - pacemaker - pcmk_output.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 1179 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 74 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 General Public License version 2
       7             :  * or later (GPLv2+) WITHOUT ANY WARRANTY.
       8             :  */
       9             : 
      10             : #include <crm_internal.h>
      11             : #include <crm/common/output.h>
      12             : #include <crm/common/results.h>
      13             : #include <crm/common/xml.h>
      14             : #include <crm/stonith-ng.h>
      15             : #include <crm/fencing/internal.h>   // stonith__*
      16             : #include <crm/pengine/internal.h>
      17             : #include <libxml/tree.h>
      18             : #include <pacemaker-internal.h>
      19             : 
      20             : #include <inttypes.h>
      21             : #include <stdint.h>
      22             : 
      23             : static char *
      24           0 : colocations_header(pcmk_resource_t *rsc, pcmk__colocation_t *cons,
      25             :                    bool dependents) {
      26           0 :     char *retval = NULL;
      27             : 
      28           0 :     if (cons->primary_role > pcmk_role_started) {
      29           0 :         retval = crm_strdup_printf("%s (score=%s, %s role=%s, id=%s)",
      30             :                                    rsc->id, pcmk_readable_score(cons->score),
      31             :                                    (dependents? "needs" : "with"),
      32           0 :                                    pcmk_role_text(cons->primary_role),
      33             :                                    cons->id);
      34             :     } else {
      35           0 :         retval = crm_strdup_printf("%s (score=%s, id=%s)",
      36             :                                    rsc->id, pcmk_readable_score(cons->score),
      37             :                                    cons->id);
      38             :     }
      39           0 :     return retval;
      40             : }
      41             : 
      42             : static void
      43           0 : colocations_xml_node(pcmk__output_t *out, pcmk_resource_t *rsc,
      44             :                      pcmk__colocation_t *cons) {
      45           0 :     xmlNodePtr node = NULL;
      46             : 
      47           0 :     node = pcmk__output_create_xml_node(out, PCMK_XE_RSC_COLOCATION,
      48             :                                         PCMK_XA_ID, cons->id,
      49           0 :                                         PCMK_XA_RSC, cons->dependent->id,
      50           0 :                                         PCMK_XA_WITH_RSC, cons->primary->id,
      51             :                                         PCMK_XA_SCORE,
      52             :                                         pcmk_readable_score(cons->score),
      53             :                                         NULL);
      54             : 
      55           0 :     if (cons->node_attribute) {
      56           0 :         xmlSetProp(node, (pcmkXmlStr) PCMK_XA_NODE_ATTRIBUTE,
      57           0 :                    (pcmkXmlStr) cons->node_attribute);
      58             :     }
      59             : 
      60           0 :     if (cons->dependent_role != pcmk_role_unknown) {
      61           0 :         xmlSetProp(node, (pcmkXmlStr) PCMK_XA_RSC_ROLE,
      62           0 :                    (pcmkXmlStr) pcmk_role_text(cons->dependent_role));
      63             :     }
      64             : 
      65           0 :     if (cons->primary_role != pcmk_role_unknown) {
      66           0 :         xmlSetProp(node, (pcmkXmlStr) PCMK_XA_WITH_RSC_ROLE,
      67           0 :                    (pcmkXmlStr) pcmk_role_text(cons->primary_role));
      68             :     }
      69           0 : }
      70             : 
      71             : static int
      72           0 : do_locations_list_xml(pcmk__output_t *out, pcmk_resource_t *rsc,
      73             :                       bool add_header)
      74             : {
      75           0 :     GList *lpc = NULL;
      76           0 :     GList *list = rsc->rsc_location;
      77           0 :     int rc = pcmk_rc_no_output;
      78             : 
      79           0 :     for (lpc = list; lpc != NULL; lpc = lpc->next) {
      80           0 :         pcmk__location_t *cons = lpc->data;
      81             : 
      82           0 :         GList *lpc2 = NULL;
      83             : 
      84           0 :         for (lpc2 = cons->nodes; lpc2 != NULL; lpc2 = lpc2->next) {
      85           0 :             pcmk_node_t *node = (pcmk_node_t *) lpc2->data;
      86             : 
      87           0 :             if (add_header) {
      88           0 :                 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "locations");
      89             :             }
      90             : 
      91           0 :             pcmk__output_create_xml_node(out, PCMK_XE_RSC_LOCATION,
      92           0 :                                          PCMK_XA_NODE, node->details->uname,
      93             :                                          PCMK_XA_RSC, rsc->id,
      94             :                                          PCMK_XA_ID, cons->id,
      95             :                                          PCMK_XA_SCORE,
      96             :                                          pcmk_readable_score(node->weight),
      97             :                                          NULL);
      98             :         }
      99             :     }
     100             : 
     101           0 :     if (add_header) {
     102           0 :         PCMK__OUTPUT_LIST_FOOTER(out, rc);
     103             :     }
     104             : 
     105           0 :     return rc;
     106             : }
     107             : 
     108             : PCMK__OUTPUT_ARGS("rsc-action-item", "const char *", "pcmk_resource_t *",
     109             :                   "pcmk_node_t *", "pcmk_node_t *", "pcmk_action_t *",
     110             :                   "pcmk_action_t *")
     111             : static int
     112           0 : rsc_action_item(pcmk__output_t *out, va_list args)
     113             : {
     114           0 :     const char *change = va_arg(args, const char *);
     115           0 :     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
     116           0 :     pcmk_node_t *origin = va_arg(args, pcmk_node_t *);
     117           0 :     pcmk_node_t *destination = va_arg(args, pcmk_node_t *);
     118           0 :     pcmk_action_t *action = va_arg(args, pcmk_action_t *);
     119           0 :     pcmk_action_t *source = va_arg(args, pcmk_action_t *);
     120             : 
     121           0 :     int len = 0;
     122           0 :     char *reason = NULL;
     123           0 :     char *details = NULL;
     124           0 :     bool same_host = false;
     125           0 :     bool same_role = false;
     126           0 :     bool need_role = false;
     127             : 
     128             :     static int rsc_width = 5;
     129             :     static int detail_width = 5;
     130             : 
     131           0 :     CRM_ASSERT(action);
     132           0 :     CRM_ASSERT(destination != NULL || origin != NULL);
     133             : 
     134           0 :     if (source == NULL) {
     135           0 :         source = action;
     136             :     }
     137             : 
     138           0 :     len = strlen(rsc->id);
     139           0 :     if (len > rsc_width) {
     140           0 :         rsc_width = len + 2;
     141             :     }
     142             : 
     143           0 :     if ((rsc->role > pcmk_role_started)
     144           0 :         || (rsc->next_role > pcmk_role_unpromoted)) {
     145           0 :         need_role = true;
     146             :     }
     147             : 
     148           0 :     if (pcmk__same_node(origin, destination)) {
     149           0 :         same_host = true;
     150             :     }
     151             : 
     152           0 :     if (rsc->role == rsc->next_role) {
     153           0 :         same_role = true;
     154             :     }
     155             : 
     156           0 :     if (need_role && (origin == NULL)) {
     157             :         /* Starting and promoting a promotable clone instance */
     158           0 :         details = crm_strdup_printf("%s -> %s %s", pcmk_role_text(rsc->role),
     159             :                                     pcmk_role_text(rsc->next_role),
     160             :                                     pcmk__node_name(destination));
     161             : 
     162           0 :     } else if (origin == NULL) {
     163             :         /* Starting a resource */
     164           0 :         details = crm_strdup_printf("%s", pcmk__node_name(destination));
     165             : 
     166           0 :     } else if (need_role && (destination == NULL)) {
     167             :         /* Stopping a promotable clone instance */
     168           0 :         details = crm_strdup_printf("%s %s", pcmk_role_text(rsc->role),
     169             :                                     pcmk__node_name(origin));
     170             : 
     171           0 :     } else if (destination == NULL) {
     172             :         /* Stopping a resource */
     173           0 :         details = crm_strdup_printf("%s", pcmk__node_name(origin));
     174             : 
     175           0 :     } else if (need_role && same_role && same_host) {
     176             :         /* Recovering, restarting or re-promoting a promotable clone instance */
     177           0 :         details = crm_strdup_printf("%s %s", pcmk_role_text(rsc->role),
     178             :                                     pcmk__node_name(origin));
     179             : 
     180           0 :     } else if (same_role && same_host) {
     181             :         /* Recovering or Restarting a normal resource */
     182           0 :         details = crm_strdup_printf("%s", pcmk__node_name(origin));
     183             : 
     184           0 :     } else if (need_role && same_role) {
     185             :         /* Moving a promotable clone instance */
     186           0 :         details = crm_strdup_printf("%s -> %s %s", pcmk__node_name(origin),
     187             :                                     pcmk__node_name(destination),
     188             :                                     pcmk_role_text(rsc->role));
     189             : 
     190           0 :     } else if (same_role) {
     191             :         /* Moving a normal resource */
     192           0 :         details = crm_strdup_printf("%s -> %s", pcmk__node_name(origin),
     193             :                                     pcmk__node_name(destination));
     194             : 
     195           0 :     } else if (same_host) {
     196             :         /* Promoting or demoting a promotable clone instance */
     197           0 :         details = crm_strdup_printf("%s -> %s %s", pcmk_role_text(rsc->role),
     198             :                                     pcmk_role_text(rsc->next_role),
     199             :                                     pcmk__node_name(origin));
     200             : 
     201             :     } else {
     202             :         /* Moving and promoting/demoting */
     203           0 :         details = crm_strdup_printf("%s %s -> %s %s",
     204             :                                     pcmk_role_text(rsc->role),
     205             :                                     pcmk__node_name(origin),
     206             :                                     pcmk_role_text(rsc->next_role),
     207             :                                     pcmk__node_name(destination));
     208             :     }
     209             : 
     210           0 :     len = strlen(details);
     211           0 :     if (len > detail_width) {
     212           0 :         detail_width = len;
     213             :     }
     214             : 
     215           0 :     if ((source->reason != NULL)
     216           0 :         && !pcmk_is_set(action->flags, pcmk_action_runnable)) {
     217           0 :         reason = crm_strdup_printf("due to %s (blocked)", source->reason);
     218             : 
     219           0 :     } else if (source->reason) {
     220           0 :         reason = crm_strdup_printf("due to %s", source->reason);
     221             : 
     222           0 :     } else if (!pcmk_is_set(action->flags, pcmk_action_runnable)) {
     223           0 :         reason = strdup("blocked");
     224             : 
     225             :     }
     226             : 
     227           0 :     out->list_item(out, NULL, "%-8s   %-*s   ( %*s )%s%s",
     228             :                    change, rsc_width, rsc->id, detail_width, details,
     229             :                    ((reason == NULL)? "" : "  "), pcmk__s(reason, ""));
     230             : 
     231           0 :     free(details);
     232           0 :     free(reason);
     233           0 :     return pcmk_rc_ok;
     234             : }
     235             : 
     236             : PCMK__OUTPUT_ARGS("rsc-action-item", "const char *", "pcmk_resource_t *",
     237             :                   "pcmk_node_t *", "pcmk_node_t *", "pcmk_action_t *",
     238             :                   "pcmk_action_t *")
     239             : static int
     240           0 : rsc_action_item_xml(pcmk__output_t *out, va_list args)
     241             : {
     242           0 :     const char *change = va_arg(args, const char *);
     243           0 :     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
     244           0 :     pcmk_node_t *origin = va_arg(args, pcmk_node_t *);
     245           0 :     pcmk_node_t *destination = va_arg(args, pcmk_node_t *);
     246           0 :     pcmk_action_t *action = va_arg(args, pcmk_action_t *);
     247           0 :     pcmk_action_t *source = va_arg(args, pcmk_action_t *);
     248             : 
     249           0 :     char *change_str = NULL;
     250             : 
     251           0 :     bool same_host = false;
     252           0 :     bool same_role = false;
     253           0 :     bool need_role = false;
     254           0 :     xmlNode *xml = NULL;
     255             : 
     256           0 :     CRM_ASSERT(action);
     257           0 :     CRM_ASSERT(destination != NULL || origin != NULL);
     258             : 
     259           0 :     if (source == NULL) {
     260           0 :         source = action;
     261             :     }
     262             : 
     263           0 :     if ((rsc->role > pcmk_role_started)
     264           0 :         || (rsc->next_role > pcmk_role_unpromoted)) {
     265           0 :         need_role = true;
     266             :     }
     267             : 
     268           0 :     if (pcmk__same_node(origin, destination)) {
     269           0 :         same_host = true;
     270             :     }
     271             : 
     272           0 :     if (rsc->role == rsc->next_role) {
     273           0 :         same_role = true;
     274             :     }
     275             : 
     276           0 :     change_str = g_ascii_strdown(change, -1);
     277           0 :     xml = pcmk__output_create_xml_node(out, PCMK_XE_RSC_ACTION,
     278             :                                        PCMK_XA_ACTION, change_str,
     279             :                                        PCMK_XA_RESOURCE, rsc->id,
     280             :                                        NULL);
     281           0 :     g_free(change_str);
     282             : 
     283           0 :     if (need_role && (origin == NULL)) {
     284             :         /* Starting and promoting a promotable clone instance */
     285           0 :         pcmk__xe_set_props(xml,
     286             :                            PCMK_XA_ROLE, pcmk_role_text(rsc->role),
     287             :                            PCMK_XA_NEXT_ROLE, pcmk_role_text(rsc->next_role),
     288           0 :                            PCMK_XA_DEST, destination->details->uname,
     289             :                            NULL);
     290             : 
     291           0 :     } else if (origin == NULL) {
     292             :         /* Starting a resource */
     293           0 :         crm_xml_add(xml, PCMK_XA_NODE, destination->details->uname);
     294             : 
     295           0 :     } else if (need_role && (destination == NULL)) {
     296             :         /* Stopping a promotable clone instance */
     297           0 :         pcmk__xe_set_props(xml,
     298             :                            PCMK_XA_ROLE, pcmk_role_text(rsc->role),
     299           0 :                            PCMK_XA_NODE, origin->details->uname,
     300             :                            NULL);
     301             : 
     302           0 :     } else if (destination == NULL) {
     303             :         /* Stopping a resource */
     304           0 :         crm_xml_add(xml, PCMK_XA_NODE, origin->details->uname);
     305             : 
     306           0 :     } else if (need_role && same_role && same_host) {
     307             :         /* Recovering, restarting or re-promoting a promotable clone instance */
     308           0 :         pcmk__xe_set_props(xml,
     309             :                            PCMK_XA_ROLE, pcmk_role_text(rsc->role),
     310           0 :                            PCMK_XA_SOURCE, origin->details->uname,
     311             :                            NULL);
     312             : 
     313           0 :     } else if (same_role && same_host) {
     314             :         /* Recovering or Restarting a normal resource */
     315           0 :         crm_xml_add(xml, PCMK_XA_SOURCE, origin->details->uname);
     316             : 
     317           0 :     } else if (need_role && same_role) {
     318             :         /* Moving a promotable clone instance */
     319           0 :         pcmk__xe_set_props(xml,
     320           0 :                            PCMK_XA_SOURCE, origin->details->uname,
     321           0 :                            PCMK_XA_DEST, destination->details->uname,
     322             :                            PCMK_XA_ROLE, pcmk_role_text(rsc->role),
     323             :                            NULL);
     324             : 
     325           0 :     } else if (same_role) {
     326             :         /* Moving a normal resource */
     327           0 :         pcmk__xe_set_props(xml,
     328           0 :                            PCMK_XA_SOURCE, origin->details->uname,
     329           0 :                            PCMK_XA_DEST, destination->details->uname,
     330             :                            NULL);
     331             : 
     332           0 :     } else if (same_host) {
     333             :         /* Promoting or demoting a promotable clone instance */
     334           0 :         pcmk__xe_set_props(xml,
     335             :                            PCMK_XA_ROLE, pcmk_role_text(rsc->role),
     336             :                            PCMK_XA_NEXT_ROLE, pcmk_role_text(rsc->next_role),
     337           0 :                            PCMK_XA_SOURCE, origin->details->uname,
     338             :                            NULL);
     339             : 
     340             :     } else {
     341             :         /* Moving and promoting/demoting */
     342           0 :         pcmk__xe_set_props(xml,
     343             :                            PCMK_XA_ROLE, pcmk_role_text(rsc->role),
     344           0 :                            PCMK_XA_SOURCE, origin->details->uname,
     345             :                            PCMK_XA_NEXT_ROLE, pcmk_role_text(rsc->next_role),
     346           0 :                            PCMK_XA_DEST, destination->details->uname,
     347             :                            NULL);
     348             :     }
     349             : 
     350           0 :     if ((source->reason != NULL)
     351           0 :         && !pcmk_is_set(action->flags, pcmk_action_runnable)) {
     352           0 :         pcmk__xe_set_props(xml,
     353             :                            PCMK_XA_REASON, source->reason,
     354             :                            PCMK_XA_BLOCKED, PCMK_VALUE_TRUE,
     355             :                            NULL);
     356             : 
     357           0 :     } else if (source->reason != NULL) {
     358           0 :         crm_xml_add(xml, PCMK_XA_REASON, source->reason);
     359             : 
     360           0 :     } else if (!pcmk_is_set(action->flags, pcmk_action_runnable)) {
     361           0 :         pcmk__xe_set_bool_attr(xml, PCMK_XA_BLOCKED, true);
     362             : 
     363             :     }
     364             : 
     365           0 :     return pcmk_rc_ok;
     366             : }
     367             : 
     368             : PCMK__OUTPUT_ARGS("rsc-is-colocated-with-list", "pcmk_resource_t *", "bool")
     369             : static int
     370           0 : rsc_is_colocated_with_list(pcmk__output_t *out, va_list args) {
     371           0 :     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
     372           0 :     bool recursive = va_arg(args, int);
     373             : 
     374           0 :     int rc = pcmk_rc_no_output;
     375             : 
     376           0 :     if (pcmk_is_set(rsc->flags, pcmk_rsc_detect_loop)) {
     377           0 :         return rc;
     378             :     }
     379             : 
     380             :     /* We're listing constraints explicitly involving rsc, so use rsc->rsc_cons
     381             :      * directly rather than rsc->cmds->this_with_colocations().
     382             :      */
     383           0 :     pcmk__set_rsc_flags(rsc, pcmk_rsc_detect_loop);
     384           0 :     for (GList *lpc = rsc->rsc_cons; lpc != NULL; lpc = lpc->next) {
     385           0 :         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
     386           0 :         char *hdr = NULL;
     387             : 
     388           0 :         PCMK__OUTPUT_LIST_HEADER(out, false, rc,
     389             :                                  "Resources %s is colocated with", rsc->id);
     390             : 
     391           0 :         if (pcmk_is_set(cons->primary->flags, pcmk_rsc_detect_loop)) {
     392           0 :             out->list_item(out, NULL, "%s (id=%s - loop)",
     393           0 :                            cons->primary->id, cons->id);
     394           0 :             continue;
     395             :         }
     396             : 
     397           0 :         hdr = colocations_header(cons->primary, cons, false);
     398           0 :         out->list_item(out, NULL, "%s", hdr);
     399           0 :         free(hdr);
     400             : 
     401             :         // Empty list header for indentation of information about this resource
     402           0 :         out->begin_list(out, NULL, NULL, NULL);
     403             : 
     404           0 :         out->message(out, "locations-list", cons->primary);
     405           0 :         if (recursive) {
     406           0 :             out->message(out, "rsc-is-colocated-with-list",
     407             :                          cons->primary, recursive);
     408             :         }
     409             : 
     410           0 :         out->end_list(out);
     411             :     }
     412             : 
     413           0 :     PCMK__OUTPUT_LIST_FOOTER(out, rc);
     414           0 :     return rc;
     415             : }
     416             : 
     417             : PCMK__OUTPUT_ARGS("rsc-is-colocated-with-list", "pcmk_resource_t *", "bool")
     418             : static int
     419           0 : rsc_is_colocated_with_list_xml(pcmk__output_t *out, va_list args) {
     420           0 :     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
     421           0 :     bool recursive = va_arg(args, int);
     422             : 
     423           0 :     int rc = pcmk_rc_no_output;
     424             : 
     425           0 :     if (pcmk_is_set(rsc->flags, pcmk_rsc_detect_loop)) {
     426           0 :         return rc;
     427             :     }
     428             : 
     429             :     /* We're listing constraints explicitly involving rsc, so use rsc->rsc_cons
     430             :      * directly rather than rsc->cmds->this_with_colocations().
     431             :      */
     432           0 :     pcmk__set_rsc_flags(rsc, pcmk_rsc_detect_loop);
     433           0 :     for (GList *lpc = rsc->rsc_cons; lpc != NULL; lpc = lpc->next) {
     434           0 :         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
     435             : 
     436           0 :         if (pcmk_is_set(cons->primary->flags, pcmk_rsc_detect_loop)) {
     437           0 :             colocations_xml_node(out, cons->primary, cons);
     438           0 :             continue;
     439             :         }
     440             : 
     441           0 :         colocations_xml_node(out, cons->primary, cons);
     442           0 :         do_locations_list_xml(out, cons->primary, false);
     443             : 
     444           0 :         if (recursive) {
     445           0 :             out->message(out, "rsc-is-colocated-with-list",
     446             :                          cons->primary, recursive);
     447             :         }
     448             :     }
     449             : 
     450           0 :     return rc;
     451             : }
     452             : 
     453             : PCMK__OUTPUT_ARGS("rscs-colocated-with-list", "pcmk_resource_t *", "bool")
     454             : static int
     455           0 : rscs_colocated_with_list(pcmk__output_t *out, va_list args) {
     456           0 :     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
     457           0 :     bool recursive = va_arg(args, int);
     458             : 
     459           0 :     int rc = pcmk_rc_no_output;
     460             : 
     461           0 :     if (pcmk_is_set(rsc->flags, pcmk_rsc_detect_loop)) {
     462           0 :         return rc;
     463             :     }
     464             : 
     465             :     /* We're listing constraints explicitly involving rsc, so use
     466             :      * rsc->rsc_cons_lhs directly rather than
     467             :      * rsc->cmds->with_this_colocations().
     468             :      */
     469           0 :     pcmk__set_rsc_flags(rsc, pcmk_rsc_detect_loop);
     470           0 :     for (GList *lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
     471           0 :         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
     472           0 :         char *hdr = NULL;
     473             : 
     474           0 :         PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Resources colocated with %s",
     475             :                                  rsc->id);
     476             : 
     477           0 :         if (pcmk_is_set(cons->dependent->flags, pcmk_rsc_detect_loop)) {
     478           0 :             out->list_item(out, NULL, "%s (id=%s - loop)",
     479           0 :                            cons->dependent->id, cons->id);
     480           0 :             continue;
     481             :         }
     482             : 
     483           0 :         hdr = colocations_header(cons->dependent, cons, true);
     484           0 :         out->list_item(out, NULL, "%s", hdr);
     485           0 :         free(hdr);
     486             : 
     487             :         // Empty list header for indentation of information about this resource
     488           0 :         out->begin_list(out, NULL, NULL, NULL);
     489             : 
     490           0 :         out->message(out, "locations-list", cons->dependent);
     491           0 :         if (recursive) {
     492           0 :             out->message(out, "rscs-colocated-with-list",
     493             :                          cons->dependent, recursive);
     494             :         }
     495             : 
     496           0 :         out->end_list(out);
     497             :     }
     498             : 
     499           0 :     PCMK__OUTPUT_LIST_FOOTER(out, rc);
     500           0 :     return rc;
     501             : }
     502             : 
     503             : PCMK__OUTPUT_ARGS("rscs-colocated-with-list", "pcmk_resource_t *", "bool")
     504             : static int
     505           0 : rscs_colocated_with_list_xml(pcmk__output_t *out, va_list args) {
     506           0 :     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
     507           0 :     bool recursive = va_arg(args, int);
     508             : 
     509           0 :     int rc = pcmk_rc_no_output;
     510             : 
     511           0 :     if (pcmk_is_set(rsc->flags, pcmk_rsc_detect_loop)) {
     512           0 :         return rc;
     513             :     }
     514             : 
     515             :     /* We're listing constraints explicitly involving rsc, so use
     516             :      * rsc->rsc_cons_lhs directly rather than
     517             :      * rsc->cmds->with_this_colocations().
     518             :      */
     519           0 :     pcmk__set_rsc_flags(rsc, pcmk_rsc_detect_loop);
     520           0 :     for (GList *lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
     521           0 :         pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
     522             : 
     523           0 :         if (pcmk_is_set(cons->dependent->flags, pcmk_rsc_detect_loop)) {
     524           0 :             colocations_xml_node(out, cons->dependent, cons);
     525           0 :             continue;
     526             :         }
     527             : 
     528           0 :         colocations_xml_node(out, cons->dependent, cons);
     529           0 :         do_locations_list_xml(out, cons->dependent, false);
     530             : 
     531           0 :         if (recursive) {
     532           0 :             out->message(out, "rscs-colocated-with-list",
     533             :                          cons->dependent, recursive);
     534             :         }
     535             :     }
     536             : 
     537           0 :     return rc;
     538             : }
     539             : 
     540             : PCMK__OUTPUT_ARGS("locations-list", "pcmk_resource_t *")
     541             : static int
     542           0 : locations_list(pcmk__output_t *out, va_list args) {
     543           0 :     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
     544             : 
     545           0 :     GList *lpc = NULL;
     546           0 :     GList *list = rsc->rsc_location;
     547           0 :     int rc = pcmk_rc_no_output;
     548             : 
     549           0 :     for (lpc = list; lpc != NULL; lpc = lpc->next) {
     550           0 :         pcmk__location_t *cons = lpc->data;
     551             : 
     552           0 :         GList *lpc2 = NULL;
     553             : 
     554           0 :         for (lpc2 = cons->nodes; lpc2 != NULL; lpc2 = lpc2->next) {
     555           0 :             pcmk_node_t *node = (pcmk_node_t *) lpc2->data;
     556             : 
     557           0 :             PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Locations");
     558           0 :             out->list_item(out, NULL, "Node %s (score=%s, id=%s, rsc=%s)",
     559             :                            pcmk__node_name(node),
     560             :                            pcmk_readable_score(node->weight), cons->id,
     561             :                            rsc->id);
     562             :         }
     563             :     }
     564             : 
     565           0 :     PCMK__OUTPUT_LIST_FOOTER(out, rc);
     566           0 :     return rc;
     567             : }
     568             : 
     569             : PCMK__OUTPUT_ARGS("locations-list", "pcmk_resource_t *")
     570             : static int
     571           0 : locations_list_xml(pcmk__output_t *out, va_list args) {
     572           0 :     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
     573           0 :     return do_locations_list_xml(out, rsc, true);
     574             : }
     575             : 
     576             : PCMK__OUTPUT_ARGS("locations-and-colocations", "pcmk_resource_t *",
     577             :                   "bool", "bool")
     578             : static int
     579           0 : locations_and_colocations(pcmk__output_t *out, va_list args)
     580             : {
     581           0 :     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
     582           0 :     bool recursive = va_arg(args, int);
     583           0 :     bool force = va_arg(args, int);
     584             : 
     585           0 :     pcmk__unpack_constraints(rsc->cluster);
     586             : 
     587             :     // Constraints apply to group/clone, not member/instance
     588           0 :     if (!force) {
     589           0 :         rsc = uber_parent(rsc);
     590             :     }
     591             : 
     592           0 :     out->message(out, "locations-list", rsc);
     593             : 
     594           0 :     pe__clear_resource_flags_on_all(rsc->cluster, pcmk_rsc_detect_loop);
     595           0 :     out->message(out, "rscs-colocated-with-list", rsc, recursive);
     596             : 
     597           0 :     pe__clear_resource_flags_on_all(rsc->cluster, pcmk_rsc_detect_loop);
     598           0 :     out->message(out, "rsc-is-colocated-with-list", rsc, recursive);
     599           0 :     return pcmk_rc_ok;
     600             : }
     601             : 
     602             : PCMK__OUTPUT_ARGS("locations-and-colocations", "pcmk_resource_t *",
     603             :                   "bool", "bool")
     604             : static int
     605           0 : locations_and_colocations_xml(pcmk__output_t *out, va_list args)
     606             : {
     607           0 :     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
     608           0 :     bool recursive = va_arg(args, int);
     609           0 :     bool force = va_arg(args, int);
     610             : 
     611           0 :     pcmk__unpack_constraints(rsc->cluster);
     612             : 
     613             :     // Constraints apply to group/clone, not member/instance
     614           0 :     if (!force) {
     615           0 :         rsc = uber_parent(rsc);
     616             :     }
     617             : 
     618           0 :     pcmk__output_xml_create_parent(out, PCMK_XE_CONSTRAINTS, NULL);
     619           0 :     do_locations_list_xml(out, rsc, false);
     620             : 
     621           0 :     pe__clear_resource_flags_on_all(rsc->cluster, pcmk_rsc_detect_loop);
     622           0 :     out->message(out, "rscs-colocated-with-list", rsc, recursive);
     623             : 
     624           0 :     pe__clear_resource_flags_on_all(rsc->cluster, pcmk_rsc_detect_loop);
     625           0 :     out->message(out, "rsc-is-colocated-with-list", rsc, recursive);
     626             : 
     627           0 :     pcmk__output_xml_pop_parent(out);
     628           0 :     return pcmk_rc_ok;
     629             : }
     630             : 
     631             : PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *",
     632             :                   "const char *")
     633             : static int
     634           0 : health(pcmk__output_t *out, va_list args)
     635             : {
     636           0 :     const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
     637           0 :     const char *host_from = va_arg(args, const char *);
     638           0 :     const char *fsa_state = va_arg(args, const char *);
     639           0 :     const char *result = va_arg(args, const char *);
     640             : 
     641           0 :     return out->info(out, "Controller on %s in state %s: %s",
     642             :                      pcmk__s(host_from, "unknown node"),
     643             :                      pcmk__s(fsa_state, "unknown"),
     644             :                      pcmk__s(result, "unknown result"));
     645             : }
     646             : 
     647             : PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *",
     648             :                   "const char *")
     649             : static int
     650           0 : health_text(pcmk__output_t *out, va_list args)
     651             : {
     652           0 :     if (!out->is_quiet(out)) {
     653           0 :         return health(out, args);
     654             :     } else {
     655           0 :         const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
     656           0 :         const char *host_from G_GNUC_UNUSED = va_arg(args, const char *);
     657           0 :         const char *fsa_state = va_arg(args, const char *);
     658           0 :         const char *result G_GNUC_UNUSED = va_arg(args, const char *);
     659             : 
     660           0 :         if (fsa_state != NULL) {
     661           0 :             pcmk__formatted_printf(out, "%s\n", fsa_state);
     662           0 :             return pcmk_rc_ok;
     663             :         }
     664             :     }
     665             : 
     666           0 :     return pcmk_rc_no_output;
     667             : }
     668             : 
     669             : PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *",
     670             :                   "const char *")
     671             : static int
     672           0 : health_xml(pcmk__output_t *out, va_list args)
     673             : {
     674           0 :     const char *sys_from = va_arg(args, const char *);
     675           0 :     const char *host_from = va_arg(args, const char *);
     676           0 :     const char *fsa_state = va_arg(args, const char *);
     677           0 :     const char *result = va_arg(args, const char *);
     678             : 
     679           0 :     pcmk__output_create_xml_node(out, pcmk__s(sys_from, ""),
     680             :                                  PCMK_XA_NODE_NAME, pcmk__s(host_from, ""),
     681             :                                  PCMK_XA_STATE, pcmk__s(fsa_state, ""),
     682             :                                  PCMK_XA_RESULT, pcmk__s(result, ""),
     683             :                                  NULL);
     684           0 :     return pcmk_rc_ok;
     685             : }
     686             : 
     687             : PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
     688             :                   "enum pcmk_pacemakerd_state", "const char *", "time_t")
     689             : static int
     690           0 : pacemakerd_health(pcmk__output_t *out, va_list args)
     691             : {
     692           0 :     const char *sys_from = va_arg(args, const char *);
     693           0 :     enum pcmk_pacemakerd_state state =
     694             :         (enum pcmk_pacemakerd_state) va_arg(args, int);
     695           0 :     const char *state_s = va_arg(args, const char *);
     696           0 :     time_t last_updated = va_arg(args, time_t);
     697             : 
     698           0 :     char *last_updated_s = NULL;
     699           0 :     int rc = pcmk_rc_ok;
     700             : 
     701           0 :     if (sys_from == NULL) {
     702           0 :         if (state == pcmk_pacemakerd_state_remote) {
     703           0 :             sys_from = "pacemaker-remoted";
     704             :         } else {
     705           0 :             sys_from = CRM_SYSTEM_MCP;
     706             :         }
     707             :     }
     708             : 
     709           0 :     if (state_s == NULL) {
     710           0 :         state_s = pcmk__pcmkd_state_enum2friendly(state);
     711             :     }
     712             : 
     713           0 :     if (last_updated != 0) {
     714           0 :         last_updated_s = pcmk__epoch2str(&last_updated,
     715             :                                          crm_time_log_date
     716             :                                          |crm_time_log_timeofday
     717             :                                          |crm_time_log_with_timezone);
     718             :     }
     719             : 
     720           0 :     rc = out->info(out, "Status of %s: '%s' (last updated %s)",
     721             :                    sys_from, state_s,
     722             :                    pcmk__s(last_updated_s, "at unknown time"));
     723             : 
     724           0 :     free(last_updated_s);
     725           0 :     return rc;
     726             : }
     727             : 
     728             : PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
     729             :                   "enum pcmk_pacemakerd_state", "const char *", "time_t")
     730             : static int
     731           0 : pacemakerd_health_html(pcmk__output_t *out, va_list args)
     732             : {
     733           0 :     const char *sys_from = va_arg(args, const char *);
     734           0 :     enum pcmk_pacemakerd_state state =
     735             :         (enum pcmk_pacemakerd_state) va_arg(args, int);
     736           0 :     const char *state_s = va_arg(args, const char *);
     737           0 :     time_t last_updated = va_arg(args, time_t);
     738             : 
     739           0 :     char *last_updated_s = NULL;
     740           0 :     char *msg = NULL;
     741             : 
     742           0 :     if (sys_from == NULL) {
     743           0 :         if (state == pcmk_pacemakerd_state_remote) {
     744           0 :             sys_from = "pacemaker-remoted";
     745             :         } else {
     746           0 :             sys_from = CRM_SYSTEM_MCP;
     747             :         }
     748             :     }
     749             : 
     750           0 :     if (state_s == NULL) {
     751           0 :         state_s = pcmk__pcmkd_state_enum2friendly(state);
     752             :     }
     753             : 
     754           0 :     if (last_updated != 0) {
     755           0 :         last_updated_s = pcmk__epoch2str(&last_updated,
     756             :                                          crm_time_log_date
     757             :                                          |crm_time_log_timeofday
     758             :                                          |crm_time_log_with_timezone);
     759             :     }
     760             : 
     761           0 :     msg = crm_strdup_printf("Status of %s: '%s' (last updated %s)",
     762             :                             sys_from, state_s,
     763             :                             pcmk__s(last_updated_s, "at unknown time"));
     764           0 :     pcmk__output_create_html_node(out, "li", NULL, NULL, msg);
     765             : 
     766           0 :     free(msg);
     767           0 :     free(last_updated_s);
     768           0 :     return pcmk_rc_ok;
     769             : }
     770             : 
     771             : PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
     772             :                   "enum pcmk_pacemakerd_state", "const char *", "time_t")
     773             : static int
     774           0 : pacemakerd_health_text(pcmk__output_t *out, va_list args)
     775             : {
     776           0 :     if (!out->is_quiet(out)) {
     777           0 :         return pacemakerd_health(out, args);
     778             :     } else {
     779           0 :         const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
     780           0 :         enum pcmk_pacemakerd_state state =
     781             :             (enum pcmk_pacemakerd_state) va_arg(args, int);
     782           0 :         const char *state_s = va_arg(args, const char *);
     783           0 :         time_t last_updated G_GNUC_UNUSED = va_arg(args, time_t);
     784             : 
     785           0 :         if (state_s == NULL) {
     786           0 :             state_s = pcmk_pacemakerd_api_daemon_state_enum2text(state);
     787             :         }
     788           0 :         pcmk__formatted_printf(out, "%s\n", state_s);
     789           0 :         return pcmk_rc_ok;
     790             :     }
     791             : }
     792             : 
     793             : PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
     794             :                   "enum pcmk_pacemakerd_state", "const char *", "time_t")
     795             : static int
     796           0 : pacemakerd_health_xml(pcmk__output_t *out, va_list args)
     797             : {
     798           0 :     const char *sys_from = va_arg(args, const char *);
     799           0 :     enum pcmk_pacemakerd_state state =
     800             :         (enum pcmk_pacemakerd_state) va_arg(args, int);
     801           0 :     const char *state_s = va_arg(args, const char *);
     802           0 :     time_t last_updated = va_arg(args, time_t);
     803             : 
     804           0 :     char *last_updated_s = NULL;
     805             : 
     806           0 :     if (sys_from == NULL) {
     807           0 :         if (state == pcmk_pacemakerd_state_remote) {
     808           0 :             sys_from = "pacemaker-remoted";
     809             :         } else {
     810           0 :             sys_from = CRM_SYSTEM_MCP;
     811             :         }
     812             :     }
     813             : 
     814           0 :     if (state_s == NULL) {
     815           0 :         state_s = pcmk_pacemakerd_api_daemon_state_enum2text(state);
     816             :     }
     817             : 
     818           0 :     if (last_updated != 0) {
     819           0 :         last_updated_s = pcmk__epoch2str(&last_updated,
     820             :                                          crm_time_log_date
     821             :                                          |crm_time_log_timeofday
     822             :                                          |crm_time_log_with_timezone);
     823             :     }
     824             : 
     825           0 :     pcmk__output_create_xml_node(out, PCMK_XE_PACEMAKERD,
     826             :                                  PCMK_XA_SYS_FROM, sys_from,
     827             :                                  PCMK_XA_STATE, state_s,
     828             :                                  PCMK_XA_LAST_UPDATED, last_updated_s,
     829             :                                  NULL);
     830           0 :     free(last_updated_s);
     831           0 :     return pcmk_rc_ok;
     832             : }
     833             : 
     834             : PCMK__OUTPUT_ARGS("profile", "const char *", "clock_t", "clock_t")
     835             : static int
     836           0 : profile_default(pcmk__output_t *out, va_list args) {
     837           0 :     const char *xml_file = va_arg(args, const char *);
     838           0 :     clock_t start = va_arg(args, clock_t);
     839           0 :     clock_t end = va_arg(args, clock_t);
     840             : 
     841           0 :     out->list_item(out, NULL, "Testing %s ... %.2f secs", xml_file,
     842           0 :                    (end - start) / (float) CLOCKS_PER_SEC);
     843             : 
     844           0 :     return pcmk_rc_ok;
     845             : }
     846             : 
     847             : PCMK__OUTPUT_ARGS("profile", "const char *", "clock_t", "clock_t")
     848             : static int
     849           0 : profile_xml(pcmk__output_t *out, va_list args) {
     850           0 :     const char *xml_file = va_arg(args, const char *);
     851           0 :     clock_t start = va_arg(args, clock_t);
     852           0 :     clock_t end = va_arg(args, clock_t);
     853             : 
     854           0 :     char *duration = pcmk__ftoa((end - start) / (float) CLOCKS_PER_SEC);
     855             : 
     856           0 :     pcmk__output_create_xml_node(out, PCMK_XE_TIMING,
     857             :                                  PCMK_XA_FILE, xml_file,
     858             :                                  PCMK_XA_DURATION, duration,
     859             :                                  NULL);
     860             : 
     861           0 :     free(duration);
     862           0 :     return pcmk_rc_ok;
     863             : }
     864             : 
     865             : PCMK__OUTPUT_ARGS("dc", "const char *")
     866             : static int
     867           0 : dc(pcmk__output_t *out, va_list args)
     868             : {
     869           0 :     const char *dc = va_arg(args, const char *);
     870             : 
     871           0 :     return out->info(out, "Designated Controller is: %s",
     872             :                      pcmk__s(dc, "not yet elected"));
     873             : }
     874             : 
     875             : PCMK__OUTPUT_ARGS("dc", "const char *")
     876             : static int
     877           0 : dc_text(pcmk__output_t *out, va_list args)
     878             : {
     879           0 :     if (!out->is_quiet(out)) {
     880           0 :         return dc(out, args);
     881             :     } else {
     882           0 :         const char *dc = va_arg(args, const char *);
     883             : 
     884           0 :         if (dc != NULL) {
     885           0 :             pcmk__formatted_printf(out, "%s\n", pcmk__s(dc, ""));
     886           0 :             return pcmk_rc_ok;
     887             :         }
     888             :     }
     889             : 
     890           0 :     return pcmk_rc_no_output;
     891             : }
     892             : 
     893             : PCMK__OUTPUT_ARGS("dc", "const char *")
     894             : static int
     895           0 : dc_xml(pcmk__output_t *out, va_list args)
     896             : {
     897           0 :     const char *dc = va_arg(args, const char *);
     898             : 
     899           0 :     pcmk__output_create_xml_node(out, PCMK_XE_DC,
     900             :                                  PCMK_XA_NODE_NAME, pcmk__s(dc, ""),
     901             :                                  NULL);
     902           0 :     return pcmk_rc_ok;
     903             : }
     904             : 
     905             : PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *",
     906             :                   "const char *", "bool")
     907             : static int
     908           0 : crmadmin_node(pcmk__output_t *out, va_list args)
     909             : {
     910           0 :     const char *type = va_arg(args, const char *);
     911           0 :     const char *name = va_arg(args, const char *);
     912           0 :     const char *id = va_arg(args, const char *);
     913           0 :     bool bash_export = va_arg(args, int);
     914             : 
     915           0 :     if (bash_export) {
     916           0 :         return out->info(out, "export %s=%s",
     917             :                          pcmk__s(name, "<null>"), pcmk__s(id, ""));
     918             :     } else {
     919           0 :         return out->info(out, "%s node: %s (%s)", type ? type : "cluster",
     920             :                          pcmk__s(name, "<null>"), pcmk__s(id, "<null>"));
     921             :     }
     922             : }
     923             : 
     924             : PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *",
     925             :                   "const char *", "bool")
     926             : static int
     927           0 : crmadmin_node_text(pcmk__output_t *out, va_list args)
     928             : {
     929           0 :     if (!out->is_quiet(out)) {
     930           0 :         return crmadmin_node(out, args);
     931             :     } else {
     932           0 :         const char *type G_GNUC_UNUSED = va_arg(args, const char *);
     933           0 :         const char *name = va_arg(args, const char *);
     934           0 :         const char *id G_GNUC_UNUSED = va_arg(args, const char *);
     935           0 :         bool bash_export G_GNUC_UNUSED = va_arg(args, int);
     936             : 
     937           0 :         pcmk__formatted_printf(out, "%s\n", pcmk__s(name, "<null>"));
     938           0 :         return pcmk_rc_ok;
     939             :     }
     940             : }
     941             : 
     942             : PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *",
     943             :                   "const char *", "bool")
     944             : static int
     945           0 : crmadmin_node_xml(pcmk__output_t *out, va_list args)
     946             : {
     947           0 :     const char *type = va_arg(args, const char *);
     948           0 :     const char *name = va_arg(args, const char *);
     949           0 :     const char *id = va_arg(args, const char *);
     950           0 :     bool bash_export G_GNUC_UNUSED = va_arg(args, int);
     951             : 
     952           0 :     pcmk__output_create_xml_node(out, PCMK_XE_NODE,
     953             :                                  PCMK_XA_TYPE, pcmk__s(type, "cluster"),
     954             :                                  PCMK_XA_NAME, pcmk__s(name, ""),
     955             :                                  PCMK_XA_ID, pcmk__s(id, ""),
     956             :                                  NULL);
     957           0 :     return pcmk_rc_ok;
     958             : }
     959             : 
     960             : PCMK__OUTPUT_ARGS("digests", "const pcmk_resource_t *", "const pcmk_node_t *",
     961             :                   "const char *", "guint", "const pcmk__op_digest_t *")
     962             : static int
     963           0 : digests_text(pcmk__output_t *out, va_list args)
     964             : {
     965           0 :     const pcmk_resource_t *rsc = va_arg(args, const pcmk_resource_t *);
     966           0 :     const pcmk_node_t *node = va_arg(args, const pcmk_node_t *);
     967           0 :     const char *task = va_arg(args, const char *);
     968           0 :     guint interval_ms = va_arg(args, guint);
     969           0 :     const pcmk__op_digest_t *digests = va_arg(args, const pcmk__op_digest_t *);
     970             : 
     971           0 :     char *action_desc = NULL;
     972           0 :     const char *rsc_desc = "unknown resource";
     973           0 :     const char *node_desc = "unknown node";
     974             : 
     975           0 :     if (interval_ms != 0) {
     976           0 :         action_desc = crm_strdup_printf("%ums-interval %s action", interval_ms,
     977             :                                         ((task == NULL)? "unknown" : task));
     978           0 :     } else if (pcmk__str_eq(task, PCMK_ACTION_MONITOR, pcmk__str_none)) {
     979           0 :         action_desc = strdup("probe action");
     980             :     } else {
     981           0 :         action_desc = crm_strdup_printf("%s action",
     982             :                                         ((task == NULL)? "unknown" : task));
     983             :     }
     984           0 :     if ((rsc != NULL) && (rsc->id != NULL)) {
     985           0 :         rsc_desc = rsc->id;
     986             :     }
     987           0 :     if ((node != NULL) && (node->details->uname != NULL)) {
     988           0 :         node_desc = node->details->uname;
     989             :     }
     990           0 :     out->begin_list(out, NULL, NULL, "Digests for %s %s on %s",
     991             :                     rsc_desc, action_desc, node_desc);
     992           0 :     free(action_desc);
     993             : 
     994           0 :     if (digests == NULL) {
     995           0 :         out->list_item(out, NULL, "none");
     996           0 :         out->end_list(out);
     997           0 :         return pcmk_rc_ok;
     998             :     }
     999           0 :     if (digests->digest_all_calc != NULL) {
    1000           0 :         out->list_item(out, NULL, "%s (all parameters)",
    1001           0 :                        digests->digest_all_calc);
    1002             :     }
    1003           0 :     if (digests->digest_secure_calc != NULL) {
    1004           0 :         out->list_item(out, NULL, "%s (non-private parameters)",
    1005           0 :                        digests->digest_secure_calc);
    1006             :     }
    1007           0 :     if (digests->digest_restart_calc != NULL) {
    1008           0 :         out->list_item(out, NULL, "%s (non-reloadable parameters)",
    1009           0 :                        digests->digest_restart_calc);
    1010             :     }
    1011           0 :     out->end_list(out);
    1012           0 :     return pcmk_rc_ok;
    1013             : }
    1014             : 
    1015             : static void
    1016           0 : add_digest_xml(xmlNode *parent, const char *type, const char *digest,
    1017             :                xmlNode *digest_source)
    1018             : {
    1019           0 :     if (digest != NULL) {
    1020           0 :         xmlNodePtr digest_xml = pcmk__xe_create(parent, PCMK_XE_DIGEST);
    1021             : 
    1022           0 :         crm_xml_add(digest_xml, PCMK_XA_TYPE, pcmk__s(type, "unspecified"));
    1023           0 :         crm_xml_add(digest_xml, PCMK_XA_HASH, digest);
    1024           0 :         pcmk__xml_copy(digest_xml, digest_source);
    1025             :     }
    1026           0 : }
    1027             : 
    1028             : PCMK__OUTPUT_ARGS("digests", "const pcmk_resource_t *", "const pcmk_node_t *",
    1029             :                   "const char *", "guint", "const pcmk__op_digest_t *")
    1030             : static int
    1031           0 : digests_xml(pcmk__output_t *out, va_list args)
    1032             : {
    1033           0 :     const pcmk_resource_t *rsc = va_arg(args, const pcmk_resource_t *);
    1034           0 :     const pcmk_node_t *node = va_arg(args, const pcmk_node_t *);
    1035           0 :     const char *task = va_arg(args, const char *);
    1036           0 :     guint interval_ms = va_arg(args, guint);
    1037           0 :     const pcmk__op_digest_t *digests = va_arg(args, const pcmk__op_digest_t *);
    1038             : 
    1039           0 :     char *interval_s = crm_strdup_printf("%ums", interval_ms);
    1040           0 :     xmlNode *xml = NULL;
    1041             : 
    1042           0 :     xml = pcmk__output_create_xml_node(out, PCMK_XE_DIGESTS,
    1043           0 :                                        PCMK_XA_RESOURCE, pcmk__s(rsc->id, ""),
    1044             :                                        PCMK_XA_NODE,
    1045           0 :                                        pcmk__s(node->details->uname, ""),
    1046             :                                        PCMK_XA_TASK, pcmk__s(task, ""),
    1047             :                                        PCMK_XA_INTERVAL, interval_s,
    1048             :                                        NULL);
    1049           0 :     free(interval_s);
    1050           0 :     if (digests != NULL) {
    1051           0 :         add_digest_xml(xml, "all", digests->digest_all_calc,
    1052           0 :                        digests->params_all);
    1053           0 :         add_digest_xml(xml, "nonprivate", digests->digest_secure_calc,
    1054           0 :                        digests->params_secure);
    1055           0 :         add_digest_xml(xml, "nonreloadable", digests->digest_restart_calc,
    1056           0 :                        digests->params_restart);
    1057             :     }
    1058           0 :     return pcmk_rc_ok;
    1059             : }
    1060             : 
    1061             : #define STOP_SANITY_ASSERT(lineno) do {                                 \
    1062             :         if ((current != NULL) && current->details->unclean) {           \
    1063             :             /* It will be a pseudo op */                                \
    1064             :         } else if (stop == NULL) {                                      \
    1065             :             crm_err("%s:%d: No stop action exists for %s",              \
    1066             :                     __func__, lineno, rsc->id);                         \
    1067             :             CRM_ASSERT(stop != NULL);                                   \
    1068             :         } else if (pcmk_is_set(stop->flags, pcmk_action_optional)) {    \
    1069             :             crm_err("%s:%d: Action %s is still optional",               \
    1070             :                     __func__, lineno, stop->uuid);                      \
    1071             :             CRM_ASSERT(!pcmk_is_set(stop->flags, pcmk_action_optional));\
    1072             :         }                                                               \
    1073             :     } while (0)
    1074             : 
    1075             : PCMK__OUTPUT_ARGS("rsc-action", "pcmk_resource_t *", "pcmk_node_t *",
    1076             :                   "pcmk_node_t *")
    1077             : static int
    1078           0 : rsc_action_default(pcmk__output_t *out, va_list args)
    1079             : {
    1080           0 :     pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
    1081           0 :     pcmk_node_t *current = va_arg(args, pcmk_node_t *);
    1082           0 :     pcmk_node_t *next = va_arg(args, pcmk_node_t *);
    1083             : 
    1084           0 :     GList *possible_matches = NULL;
    1085           0 :     char *key = NULL;
    1086           0 :     int rc = pcmk_rc_no_output;
    1087           0 :     bool moving = false;
    1088             : 
    1089           0 :     pcmk_node_t *start_node = NULL;
    1090           0 :     pcmk_action_t *start = NULL;
    1091           0 :     pcmk_action_t *stop = NULL;
    1092           0 :     pcmk_action_t *promote = NULL;
    1093           0 :     pcmk_action_t *demote = NULL;
    1094           0 :     pcmk_action_t *reason_op = NULL;
    1095             : 
    1096           0 :     if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)
    1097           0 :         || (current == NULL && next == NULL)) {
    1098           0 :         const bool managed = pcmk_is_set(rsc->flags, pcmk_rsc_managed);
    1099             : 
    1100           0 :         pcmk__rsc_info(rsc, "Leave   %s\t(%s%s)",
    1101             :                        rsc->id, pcmk_role_text(rsc->role),
    1102             :                        (managed? "" : " unmanaged"));
    1103           0 :         return rc;
    1104             :     }
    1105             : 
    1106           0 :     moving = (current != NULL) && (next != NULL)
    1107           0 :              && !pcmk__same_node(current, next);
    1108             : 
    1109           0 :     possible_matches = pe__resource_actions(rsc, next, PCMK_ACTION_START,
    1110             :                                             false);
    1111           0 :     if (possible_matches) {
    1112           0 :         start = possible_matches->data;
    1113           0 :         g_list_free(possible_matches);
    1114             :     }
    1115             : 
    1116           0 :     if ((start == NULL)
    1117           0 :         || !pcmk_is_set(start->flags, pcmk_action_runnable)) {
    1118           0 :         start_node = NULL;
    1119             :     } else {
    1120           0 :         start_node = current;
    1121             :     }
    1122           0 :     possible_matches = pe__resource_actions(rsc, start_node, PCMK_ACTION_STOP,
    1123             :                                             false);
    1124           0 :     if (possible_matches) {
    1125           0 :         stop = possible_matches->data;
    1126           0 :         g_list_free(possible_matches);
    1127           0 :     } else if (pcmk_is_set(rsc->flags, pcmk_rsc_stop_unexpected)) {
    1128             :         /* The resource is multiply active with PCMK_META_MULTIPLE_ACTIVE set to
    1129             :          * PCMK_VALUE_STOP_UNEXPECTED, and not stopping on its current node, but
    1130             :          * it should be stopping elsewhere.
    1131             :          */
    1132           0 :         possible_matches = pe__resource_actions(rsc, NULL, PCMK_ACTION_STOP,
    1133             :                                                 false);
    1134           0 :         if (possible_matches != NULL) {
    1135           0 :             stop = possible_matches->data;
    1136           0 :             g_list_free(possible_matches);
    1137             :         }
    1138             :     }
    1139             : 
    1140           0 :     possible_matches = pe__resource_actions(rsc, next, PCMK_ACTION_PROMOTE,
    1141             :                                             false);
    1142           0 :     if (possible_matches) {
    1143           0 :         promote = possible_matches->data;
    1144           0 :         g_list_free(possible_matches);
    1145             :     }
    1146             : 
    1147           0 :     possible_matches = pe__resource_actions(rsc, next, PCMK_ACTION_DEMOTE,
    1148             :                                             false);
    1149           0 :     if (possible_matches) {
    1150           0 :         demote = possible_matches->data;
    1151           0 :         g_list_free(possible_matches);
    1152             :     }
    1153             : 
    1154           0 :     if (rsc->role == rsc->next_role) {
    1155           0 :         pcmk_action_t *migrate_op = NULL;
    1156             : 
    1157           0 :         CRM_CHECK(next != NULL, return rc);
    1158             : 
    1159           0 :         possible_matches = pe__resource_actions(rsc, next,
    1160             :                                                 PCMK_ACTION_MIGRATE_FROM,
    1161             :                                                 false);
    1162           0 :         if (possible_matches) {
    1163           0 :             migrate_op = possible_matches->data;
    1164             :         }
    1165             : 
    1166           0 :         if ((migrate_op != NULL) && (current != NULL)
    1167           0 :             && pcmk_is_set(migrate_op->flags, pcmk_action_runnable)) {
    1168           0 :             rc = out->message(out, "rsc-action-item", "Migrate", rsc, current,
    1169             :                               next, start, NULL);
    1170             : 
    1171           0 :         } else if (pcmk_is_set(rsc->flags, pcmk_rsc_reload)) {
    1172           0 :             rc = out->message(out, "rsc-action-item", "Reload", rsc, current,
    1173             :                               next, start, NULL);
    1174             : 
    1175           0 :         } else if ((start == NULL)
    1176           0 :                    || pcmk_is_set(start->flags, pcmk_action_optional)) {
    1177           0 :             if ((demote != NULL) && (promote != NULL)
    1178           0 :                 && !pcmk_is_set(demote->flags, pcmk_action_optional)
    1179           0 :                 && !pcmk_is_set(promote->flags, pcmk_action_optional)) {
    1180           0 :                 rc = out->message(out, "rsc-action-item", "Re-promote", rsc,
    1181             :                                   current, next, promote, demote);
    1182             :             } else {
    1183           0 :                 pcmk__rsc_info(rsc, "Leave   %s\t(%s %s)", rsc->id,
    1184             :                                pcmk_role_text(rsc->role),
    1185             :                                pcmk__node_name(next));
    1186             :             }
    1187             : 
    1188           0 :         } else if (!pcmk_is_set(start->flags, pcmk_action_runnable)) {
    1189           0 :             if ((stop == NULL) || (stop->reason == NULL)) {
    1190           0 :                 reason_op = start;
    1191             :             } else {
    1192           0 :                 reason_op = stop;
    1193             :             }
    1194           0 :             rc = out->message(out, "rsc-action-item", "Stop", rsc, current,
    1195             :                               NULL, stop, reason_op);
    1196           0 :             STOP_SANITY_ASSERT(__LINE__);
    1197             : 
    1198           0 :         } else if (moving && current) {
    1199           0 :             const bool failed = pcmk_is_set(rsc->flags, pcmk_rsc_failed);
    1200             : 
    1201           0 :             rc = out->message(out, "rsc-action-item",
    1202             :                               (failed? "Recover" : "Move"), rsc, current, next,
    1203             :                               stop, NULL);
    1204             : 
    1205           0 :         } else if (pcmk_is_set(rsc->flags, pcmk_rsc_failed)) {
    1206           0 :             rc = out->message(out, "rsc-action-item", "Recover", rsc, current,
    1207             :                               NULL, stop, NULL);
    1208           0 :             STOP_SANITY_ASSERT(__LINE__);
    1209             : 
    1210             :         } else {
    1211           0 :             rc = out->message(out, "rsc-action-item", "Restart", rsc, current,
    1212             :                               next, start, NULL);
    1213             : #if 0
    1214             :             /* @TODO This can be reached in situations that should really be
    1215             :              * "Start" (see for example the migrate-fail-7 regression test)
    1216             :              */
    1217             :             STOP_SANITY_ASSERT(__LINE__);
    1218             : #endif
    1219             :         }
    1220             : 
    1221           0 :         g_list_free(possible_matches);
    1222           0 :         return rc;
    1223             :     }
    1224             : 
    1225           0 :     if ((stop != NULL)
    1226           0 :         && ((rsc->next_role == pcmk_role_stopped)
    1227           0 :             || ((start != NULL)
    1228           0 :                 && !pcmk_is_set(start->flags, pcmk_action_runnable)))) {
    1229             : 
    1230           0 :         key = stop_key(rsc);
    1231           0 :         for (GList *iter = rsc->running_on; iter != NULL; iter = iter->next) {
    1232           0 :             pcmk_node_t *node = iter->data;
    1233           0 :             pcmk_action_t *stop_op = NULL;
    1234             : 
    1235           0 :             reason_op = start;
    1236           0 :             possible_matches = find_actions(rsc->actions, key, node);
    1237           0 :             if (possible_matches) {
    1238           0 :                 stop_op = possible_matches->data;
    1239           0 :                 g_list_free(possible_matches);
    1240             :             }
    1241             : 
    1242           0 :             if (stop_op != NULL) {
    1243           0 :                 if (pcmk_is_set(stop_op->flags, pcmk_action_runnable)) {
    1244           0 :                     STOP_SANITY_ASSERT(__LINE__);
    1245             :                 }
    1246           0 :                 if (stop_op->reason != NULL) {
    1247           0 :                     reason_op = stop_op;
    1248             :                 }
    1249             :             }
    1250             : 
    1251           0 :             if (out->message(out, "rsc-action-item", "Stop", rsc, node, NULL,
    1252             :                              stop_op, reason_op) == pcmk_rc_ok) {
    1253           0 :                 rc = pcmk_rc_ok;
    1254             :             }
    1255             :         }
    1256             : 
    1257           0 :         free(key);
    1258             : 
    1259           0 :     } else if ((stop != NULL)
    1260           0 :                && pcmk_all_flags_set(rsc->flags,
    1261             :                                      pcmk_rsc_failed|pcmk_rsc_stop_if_failed)) {
    1262             :         /* 'stop' may be NULL if the failure was ignored */
    1263           0 :         rc = out->message(out, "rsc-action-item", "Recover", rsc, current,
    1264             :                           next, stop, start);
    1265           0 :         STOP_SANITY_ASSERT(__LINE__);
    1266             : 
    1267           0 :     } else if (moving) {
    1268           0 :         rc = out->message(out, "rsc-action-item", "Move", rsc, current, next,
    1269             :                           stop, NULL);
    1270           0 :         STOP_SANITY_ASSERT(__LINE__);
    1271             : 
    1272           0 :     } else if (pcmk_is_set(rsc->flags, pcmk_rsc_reload)) {
    1273           0 :         rc = out->message(out, "rsc-action-item", "Reload", rsc, current, next,
    1274             :                           start, NULL);
    1275             : 
    1276           0 :     } else if ((stop != NULL)
    1277           0 :                && !pcmk_is_set(stop->flags, pcmk_action_optional)) {
    1278           0 :         rc = out->message(out, "rsc-action-item", "Restart", rsc, current,
    1279             :                           next, start, NULL);
    1280           0 :         STOP_SANITY_ASSERT(__LINE__);
    1281             : 
    1282           0 :     } else if (rsc->role == pcmk_role_promoted) {
    1283           0 :         CRM_LOG_ASSERT(current != NULL);
    1284           0 :         rc = out->message(out, "rsc-action-item", "Demote", rsc, current,
    1285             :                           next, demote, NULL);
    1286             : 
    1287           0 :     } else if (rsc->next_role == pcmk_role_promoted) {
    1288           0 :         CRM_LOG_ASSERT(next);
    1289           0 :         rc = out->message(out, "rsc-action-item", "Promote", rsc, current,
    1290             :                           next, promote, NULL);
    1291             : 
    1292           0 :     } else if ((rsc->role == pcmk_role_stopped)
    1293           0 :                && (rsc->next_role > pcmk_role_stopped)) {
    1294           0 :         rc = out->message(out, "rsc-action-item", "Start", rsc, current, next,
    1295             :                           start, NULL);
    1296             :     }
    1297             : 
    1298           0 :     return rc;
    1299             : }
    1300             : 
    1301             : PCMK__OUTPUT_ARGS("node-action", "const char *", "const char *", "const char *")
    1302             : static int
    1303           0 : node_action(pcmk__output_t *out, va_list args)
    1304             : {
    1305           0 :     const char *task = va_arg(args, const char *);
    1306           0 :     const char *node_name = va_arg(args, const char *);
    1307           0 :     const char *reason = va_arg(args, const char *);
    1308             : 
    1309           0 :     if (task == NULL) {
    1310           0 :         return pcmk_rc_no_output;
    1311           0 :     } else if (reason) {
    1312           0 :         out->list_item(out, NULL, "%s %s '%s'", task, node_name, reason);
    1313             :     } else {
    1314           0 :         crm_notice(" * %s %s", task, node_name);
    1315             :     }
    1316             : 
    1317           0 :     return pcmk_rc_ok;
    1318             : }
    1319             : 
    1320             : PCMK__OUTPUT_ARGS("node-action", "const char *", "const char *", "const char *")
    1321             : static int
    1322           0 : node_action_xml(pcmk__output_t *out, va_list args)
    1323             : {
    1324           0 :     const char *task = va_arg(args, const char *);
    1325           0 :     const char *node_name = va_arg(args, const char *);
    1326           0 :     const char *reason = va_arg(args, const char *);
    1327             : 
    1328           0 :     if (task == NULL) {
    1329           0 :         return pcmk_rc_no_output;
    1330           0 :     } else if (reason) {
    1331           0 :         pcmk__output_create_xml_node(out, PCMK_XE_NODE_ACTION,
    1332             :                                      PCMK_XA_TASK, task,
    1333             :                                      PCMK_XA_NODE, node_name,
    1334             :                                      PCMK_XA_REASON, reason,
    1335             :                                      NULL);
    1336             :     } else {
    1337           0 :         crm_notice(" * %s %s", task, node_name);
    1338             :     }
    1339             : 
    1340           0 :     return pcmk_rc_ok;
    1341             : }
    1342             : 
    1343             : PCMK__OUTPUT_ARGS("node-info", "uint32_t", "const char *", "const char *",
    1344             :                   "const char *", "bool", "bool")
    1345             : static int
    1346           0 : node_info_default(pcmk__output_t *out, va_list args)
    1347             : {
    1348           0 :     uint32_t node_id = va_arg(args, uint32_t);
    1349           0 :     const char *node_name = va_arg(args, const char *);
    1350           0 :     const char *uuid = va_arg(args, const char *);
    1351           0 :     const char *state = va_arg(args, const char *);
    1352           0 :     bool have_quorum = (bool) va_arg(args, int);
    1353           0 :     bool is_remote = (bool) va_arg(args, int);
    1354             : 
    1355           0 :     return out->info(out,
    1356             :                      "Node %" PRIu32 ": %s "
    1357             :                      "(uuid=%s, state=%s, have_quorum=%s, is_remote=%s)",
    1358             :                      node_id, pcmk__s(node_name, "unknown"),
    1359             :                      pcmk__s(uuid, "unknown"), pcmk__s(state, "unknown"),
    1360             :                      pcmk__btoa(have_quorum), pcmk__btoa(is_remote));
    1361             : }
    1362             : 
    1363             : PCMK__OUTPUT_ARGS("node-info", "uint32_t", "const char *", "const char *",
    1364             :                   "const char *", "bool", "bool")
    1365             : static int
    1366           0 : node_info_xml(pcmk__output_t *out, va_list args)
    1367             : {
    1368           0 :     uint32_t node_id = va_arg(args, uint32_t);
    1369           0 :     const char *node_name = va_arg(args, const char *);
    1370           0 :     const char *uuid = va_arg(args, const char *);
    1371           0 :     const char *state = va_arg(args, const char *);
    1372           0 :     bool have_quorum = (bool) va_arg(args, int);
    1373           0 :     bool is_remote = (bool) va_arg(args, int);
    1374             : 
    1375           0 :     char *id_s = crm_strdup_printf("%" PRIu32, node_id);
    1376             : 
    1377           0 :     pcmk__output_create_xml_node(out, PCMK_XE_NODE_INFO,
    1378             :                                  PCMK_XA_NODEID, id_s,
    1379             :                                  PCMK_XA_UNAME, node_name,
    1380             :                                  PCMK_XA_ID, uuid,
    1381             :                                  PCMK_XA_CRMD, state,
    1382             :                                  PCMK_XA_HAVE_QUORUM, pcmk__btoa(have_quorum),
    1383             :                                  PCMK_XA_REMOTE_NODE, pcmk__btoa(is_remote),
    1384             :                                  NULL);
    1385           0 :     free(id_s);
    1386           0 :     return pcmk_rc_ok;
    1387             : }
    1388             : 
    1389             : PCMK__OUTPUT_ARGS("inject-cluster-action", "const char *", "const char *",
    1390             :                   "xmlNode *")
    1391             : static int
    1392           0 : inject_cluster_action(pcmk__output_t *out, va_list args)
    1393             : {
    1394           0 :     const char *node = va_arg(args, const char *);
    1395           0 :     const char *task = va_arg(args, const char *);
    1396           0 :     xmlNodePtr rsc = va_arg(args, xmlNodePtr);
    1397             : 
    1398           0 :     if (out->is_quiet(out)) {
    1399           0 :         return pcmk_rc_no_output;
    1400             :     }
    1401             : 
    1402           0 :     if (rsc != NULL) {
    1403           0 :         out->list_item(out, NULL, "Cluster action:  %s for %s on %s",
    1404             :                        task, pcmk__xe_id(rsc), node);
    1405             :     } else {
    1406           0 :         out->list_item(out, NULL, "Cluster action:  %s on %s", task, node);
    1407             :     }
    1408             : 
    1409           0 :     return pcmk_rc_ok;
    1410             : }
    1411             : 
    1412             : PCMK__OUTPUT_ARGS("inject-cluster-action", "const char *", "const char *",
    1413             :                   "xmlNode *")
    1414             : static int
    1415           0 : inject_cluster_action_xml(pcmk__output_t *out, va_list args)
    1416             : {
    1417           0 :     const char *node = va_arg(args, const char *);
    1418           0 :     const char *task = va_arg(args, const char *);
    1419           0 :     xmlNodePtr rsc = va_arg(args, xmlNodePtr);
    1420             : 
    1421           0 :     xmlNodePtr xml_node = NULL;
    1422             : 
    1423           0 :     if (out->is_quiet(out)) {
    1424           0 :         return pcmk_rc_no_output;
    1425             :     }
    1426             : 
    1427           0 :     xml_node = pcmk__output_create_xml_node(out, PCMK_XE_CLUSTER_ACTION,
    1428             :                                             PCMK_XA_TASK, task,
    1429             :                                             PCMK_XA_NODE, node,
    1430             :                                             NULL);
    1431             : 
    1432           0 :     if (rsc) {
    1433           0 :         crm_xml_add(xml_node, PCMK_XA_ID, pcmk__xe_id(rsc));
    1434             :     }
    1435             : 
    1436           0 :     return pcmk_rc_ok;
    1437             : }
    1438             : 
    1439             : PCMK__OUTPUT_ARGS("inject-fencing-action", "const char *", "const char *")
    1440             : static int
    1441           0 : inject_fencing_action(pcmk__output_t *out, va_list args)
    1442             : {
    1443           0 :     const char *target = va_arg(args, const char *);
    1444           0 :     const char *op = va_arg(args, const char *);
    1445             : 
    1446           0 :     if (out->is_quiet(out)) {
    1447           0 :         return pcmk_rc_no_output;
    1448             :     }
    1449             : 
    1450           0 :     out->list_item(out, NULL, "Fencing %s (%s)", target, op);
    1451           0 :     return pcmk_rc_ok;
    1452             : }
    1453             : 
    1454             : PCMK__OUTPUT_ARGS("inject-fencing-action", "const char *", "const char *")
    1455             : static int
    1456           0 : inject_fencing_action_xml(pcmk__output_t *out, va_list args)
    1457             : {
    1458           0 :     const char *target = va_arg(args, const char *);
    1459           0 :     const char *op = va_arg(args, const char *);
    1460             : 
    1461           0 :     if (out->is_quiet(out)) {
    1462           0 :         return pcmk_rc_no_output;
    1463             :     }
    1464             : 
    1465           0 :     pcmk__output_create_xml_node(out, PCMK_XE_FENCING_ACTION,
    1466             :                                  PCMK_XA_TARGET, target,
    1467             :                                  PCMK_XA_OP, op,
    1468             :                                  NULL);
    1469           0 :     return pcmk_rc_ok;
    1470             : }
    1471             : 
    1472             : PCMK__OUTPUT_ARGS("inject-attr", "const char *", "const char *", "xmlNode *")
    1473             : static int
    1474           0 : inject_attr(pcmk__output_t *out, va_list args)
    1475             : {
    1476           0 :     const char *name = va_arg(args, const char *);
    1477           0 :     const char *value = va_arg(args, const char *);
    1478           0 :     xmlNodePtr cib_node = va_arg(args, xmlNodePtr);
    1479             : 
    1480           0 :     xmlChar *node_path = NULL;
    1481             : 
    1482           0 :     if (out->is_quiet(out)) {
    1483           0 :         return pcmk_rc_no_output;
    1484             :     }
    1485             : 
    1486           0 :     node_path = xmlGetNodePath(cib_node);
    1487             : 
    1488           0 :     out->list_item(out, NULL, "Injecting attribute %s=%s into %s '%s'",
    1489             :                    name, value, node_path, pcmk__xe_id(cib_node));
    1490             : 
    1491           0 :     free(node_path);
    1492           0 :     return pcmk_rc_ok;
    1493             : }
    1494             : 
    1495             : PCMK__OUTPUT_ARGS("inject-attr", "const char *", "const char *", "xmlNode *")
    1496             : static int
    1497           0 : inject_attr_xml(pcmk__output_t *out, va_list args)
    1498             : {
    1499           0 :     const char *name = va_arg(args, const char *);
    1500           0 :     const char *value = va_arg(args, const char *);
    1501           0 :     xmlNodePtr cib_node = va_arg(args, xmlNodePtr);
    1502             : 
    1503           0 :     xmlChar *node_path = NULL;
    1504             : 
    1505           0 :     if (out->is_quiet(out)) {
    1506           0 :         return pcmk_rc_no_output;
    1507             :     }
    1508             : 
    1509           0 :     node_path = xmlGetNodePath(cib_node);
    1510             : 
    1511           0 :     pcmk__output_create_xml_node(out, PCMK_XE_INJECT_ATTR,
    1512             :                                  PCMK_XA_NAME, name,
    1513             :                                  PCMK_XA_VALUE, value,
    1514             :                                  PCMK_XA_NODE_PATH, node_path,
    1515             :                                  PCMK_XA_CIB_NODE, pcmk__xe_id(cib_node),
    1516             :                                  NULL);
    1517           0 :     free(node_path);
    1518           0 :     return pcmk_rc_ok;
    1519             : }
    1520             : 
    1521             : PCMK__OUTPUT_ARGS("inject-spec", "const char *")
    1522             : static int
    1523           0 : inject_spec(pcmk__output_t *out, va_list args)
    1524             : {
    1525           0 :     const char *spec = va_arg(args, const char *);
    1526             : 
    1527           0 :     if (out->is_quiet(out)) {
    1528           0 :         return pcmk_rc_no_output;
    1529             :     }
    1530             : 
    1531           0 :     out->list_item(out, NULL, "Injecting %s into the configuration", spec);
    1532           0 :     return pcmk_rc_ok;
    1533             : }
    1534             : 
    1535             : PCMK__OUTPUT_ARGS("inject-spec", "const char *")
    1536             : static int
    1537           0 : inject_spec_xml(pcmk__output_t *out, va_list args)
    1538             : {
    1539           0 :     const char *spec = va_arg(args, const char *);
    1540             : 
    1541           0 :     if (out->is_quiet(out)) {
    1542           0 :         return pcmk_rc_no_output;
    1543             :     }
    1544             : 
    1545           0 :     pcmk__output_create_xml_node(out, PCMK_XE_INJECT_SPEC,
    1546             :                                  PCMK_XA_SPEC, spec,
    1547             :                                  NULL);
    1548           0 :     return pcmk_rc_ok;
    1549             : }
    1550             : 
    1551             : PCMK__OUTPUT_ARGS("inject-modify-config", "const char *", "const char *")
    1552             : static int
    1553           0 : inject_modify_config(pcmk__output_t *out, va_list args)
    1554             : {
    1555           0 :     const char *quorum = va_arg(args, const char *);
    1556           0 :     const char *watchdog = va_arg(args, const char *);
    1557             : 
    1558           0 :     if (out->is_quiet(out)) {
    1559           0 :         return pcmk_rc_no_output;
    1560             :     }
    1561             : 
    1562           0 :     out->begin_list(out, NULL, NULL, "Performing Requested Modifications");
    1563             : 
    1564           0 :     if (quorum) {
    1565           0 :         out->list_item(out, NULL, "Setting quorum: %s", quorum);
    1566             :     }
    1567             : 
    1568           0 :     if (watchdog) {
    1569           0 :         out->list_item(out, NULL, "Setting watchdog: %s", watchdog);
    1570             :     }
    1571             : 
    1572           0 :     return pcmk_rc_ok;
    1573             : }
    1574             : 
    1575             : PCMK__OUTPUT_ARGS("inject-modify-config", "const char *", "const char *")
    1576             : static int
    1577           0 : inject_modify_config_xml(pcmk__output_t *out, va_list args)
    1578             : {
    1579           0 :     const char *quorum = va_arg(args, const char *);
    1580           0 :     const char *watchdog = va_arg(args, const char *);
    1581             : 
    1582           0 :     xmlNodePtr node = NULL;
    1583             : 
    1584           0 :     if (out->is_quiet(out)) {
    1585           0 :         return pcmk_rc_no_output;
    1586             :     }
    1587             : 
    1588           0 :     node = pcmk__output_xml_create_parent(out, PCMK_XE_MODIFICATIONS, NULL);
    1589             : 
    1590           0 :     if (quorum) {
    1591           0 :         crm_xml_add(node, PCMK_XA_QUORUM, quorum);
    1592             :     }
    1593             : 
    1594           0 :     if (watchdog) {
    1595           0 :         crm_xml_add(node, PCMK_XA_WATCHDOG, watchdog);
    1596             :     }
    1597             : 
    1598           0 :     pcmk__output_xml_pop_parent(out);
    1599           0 :     return pcmk_rc_ok;
    1600             : }
    1601             : 
    1602             : PCMK__OUTPUT_ARGS("inject-modify-node", "const char *", "const char *")
    1603             : static int
    1604           0 : inject_modify_node(pcmk__output_t *out, va_list args)
    1605             : {
    1606           0 :     const char *action = va_arg(args, const char *);
    1607           0 :     const char *node = va_arg(args, const char *);
    1608             : 
    1609           0 :     if (out->is_quiet(out)) {
    1610           0 :         return pcmk_rc_no_output;
    1611             :     }
    1612             : 
    1613           0 :     if (pcmk__str_eq(action, "Online", pcmk__str_none)) {
    1614           0 :         out->list_item(out, NULL, "Bringing node %s online", node);
    1615           0 :         return pcmk_rc_ok;
    1616           0 :     } else if (pcmk__str_eq(action, "Offline", pcmk__str_none)) {
    1617           0 :         out->list_item(out, NULL, "Taking node %s offline", node);
    1618           0 :         return pcmk_rc_ok;
    1619           0 :     } else if (pcmk__str_eq(action, "Failing", pcmk__str_none)) {
    1620           0 :         out->list_item(out, NULL, "Failing node %s", node);
    1621           0 :         return pcmk_rc_ok;
    1622             :     }
    1623             : 
    1624           0 :     return pcmk_rc_no_output;
    1625             : }
    1626             : 
    1627             : PCMK__OUTPUT_ARGS("inject-modify-node", "const char *", "const char *")
    1628             : static int
    1629           0 : inject_modify_node_xml(pcmk__output_t *out, va_list args)
    1630             : {
    1631           0 :     const char *action = va_arg(args, const char *);
    1632           0 :     const char *node = va_arg(args, const char *);
    1633             : 
    1634           0 :     if (out->is_quiet(out)) {
    1635           0 :         return pcmk_rc_no_output;
    1636             :     }
    1637             : 
    1638           0 :     pcmk__output_create_xml_node(out, PCMK_XE_MODIFY_NODE,
    1639             :                                  PCMK_XA_ACTION, action,
    1640             :                                  PCMK_XA_NODE, node,
    1641             :                                  NULL);
    1642           0 :     return pcmk_rc_ok;
    1643             : }
    1644             : 
    1645             : PCMK__OUTPUT_ARGS("inject-modify-ticket", "const char *", "const char *")
    1646             : static int
    1647           0 : inject_modify_ticket(pcmk__output_t *out, va_list args)
    1648             : {
    1649           0 :     const char *action = va_arg(args, const char *);
    1650           0 :     const char *ticket = va_arg(args, const char *);
    1651             : 
    1652           0 :     if (out->is_quiet(out)) {
    1653           0 :         return pcmk_rc_no_output;
    1654             :     }
    1655             : 
    1656           0 :     if (pcmk__str_eq(action, "Standby", pcmk__str_none)) {
    1657           0 :         out->list_item(out, NULL, "Making ticket %s standby", ticket);
    1658             :     } else {
    1659           0 :         out->list_item(out, NULL, "%s ticket %s", action, ticket);
    1660             :     }
    1661             : 
    1662           0 :     return pcmk_rc_ok;
    1663             : }
    1664             : 
    1665             : PCMK__OUTPUT_ARGS("inject-modify-ticket", "const char *", "const char *")
    1666             : static int
    1667           0 : inject_modify_ticket_xml(pcmk__output_t *out, va_list args)
    1668             : {
    1669           0 :     const char *action = va_arg(args, const char *);
    1670           0 :     const char *ticket = va_arg(args, const char *);
    1671             : 
    1672           0 :     if (out->is_quiet(out)) {
    1673           0 :         return pcmk_rc_no_output;
    1674             :     }
    1675             : 
    1676           0 :     pcmk__output_create_xml_node(out, PCMK_XE_MODIFY_TICKET,
    1677             :                                  PCMK_XA_ACTION, action,
    1678             :                                  PCMK_XA_TICKET, ticket,
    1679             :                                  NULL);
    1680           0 :     return pcmk_rc_ok;
    1681             : }
    1682             : 
    1683             : PCMK__OUTPUT_ARGS("inject-pseudo-action", "const char *", "const char *")
    1684             : static int
    1685           0 : inject_pseudo_action(pcmk__output_t *out, va_list args)
    1686             : {
    1687           0 :     const char *node = va_arg(args, const char *);
    1688           0 :     const char *task = va_arg(args, const char *);
    1689             : 
    1690           0 :     if (out->is_quiet(out)) {
    1691           0 :         return pcmk_rc_no_output;
    1692             :     }
    1693             : 
    1694           0 :     out->list_item(out, NULL, "Pseudo action:   %s%s%s",
    1695             :                    task, ((node == NULL)? "" : " on "), pcmk__s(node, ""));
    1696           0 :     return pcmk_rc_ok;
    1697             : }
    1698             : 
    1699             : PCMK__OUTPUT_ARGS("inject-pseudo-action", "const char *", "const char *")
    1700             : static int
    1701           0 : inject_pseudo_action_xml(pcmk__output_t *out, va_list args)
    1702             : {
    1703           0 :     const char *node = va_arg(args, const char *);
    1704           0 :     const char *task = va_arg(args, const char *);
    1705             : 
    1706           0 :     xmlNodePtr xml_node = NULL;
    1707             : 
    1708           0 :     if (out->is_quiet(out)) {
    1709           0 :         return pcmk_rc_no_output;
    1710             :     }
    1711             : 
    1712           0 :     xml_node = pcmk__output_create_xml_node(out, PCMK_XE_PSEUDO_ACTION,
    1713             :                                             PCMK_XA_TASK, task,
    1714             :                                             NULL);
    1715           0 :     if (node) {
    1716           0 :         crm_xml_add(xml_node, PCMK_XA_NODE, node);
    1717             :     }
    1718             : 
    1719           0 :     return pcmk_rc_ok;
    1720             : }
    1721             : 
    1722             : PCMK__OUTPUT_ARGS("inject-rsc-action", "const char *", "const char *",
    1723             :                   "const char *", "guint")
    1724             : static int
    1725           0 : inject_rsc_action(pcmk__output_t *out, va_list args)
    1726             : {
    1727           0 :     const char *rsc = va_arg(args, const char *);
    1728           0 :     const char *operation = va_arg(args, const char *);
    1729           0 :     const char *node = va_arg(args, const char *);
    1730           0 :     guint interval_ms = va_arg(args, guint);
    1731             : 
    1732           0 :     if (out->is_quiet(out)) {
    1733           0 :         return pcmk_rc_no_output;
    1734             :     }
    1735             : 
    1736           0 :     if (interval_ms) {
    1737           0 :         out->list_item(out, NULL, "Resource action: %-15s %s=%u on %s",
    1738             :                        rsc, operation, interval_ms, node);
    1739             :     } else {
    1740           0 :         out->list_item(out, NULL, "Resource action: %-15s %s on %s",
    1741             :                        rsc, operation, node);
    1742             :     }
    1743             : 
    1744           0 :     return pcmk_rc_ok;
    1745             : }
    1746             : 
    1747             : PCMK__OUTPUT_ARGS("inject-rsc-action", "const char *", "const char *",
    1748             :                   "const char *", "guint")
    1749             : static int
    1750           0 : inject_rsc_action_xml(pcmk__output_t *out, va_list args)
    1751             : {
    1752           0 :     const char *rsc = va_arg(args, const char *);
    1753           0 :     const char *operation = va_arg(args, const char *);
    1754           0 :     const char *node = va_arg(args, const char *);
    1755           0 :     guint interval_ms = va_arg(args, guint);
    1756             : 
    1757           0 :     xmlNodePtr xml_node = NULL;
    1758             : 
    1759           0 :     if (out->is_quiet(out)) {
    1760           0 :         return pcmk_rc_no_output;
    1761             :     }
    1762             : 
    1763           0 :     xml_node = pcmk__output_create_xml_node(out, PCMK_XE_RSC_ACTION,
    1764             :                                             PCMK_XA_RESOURCE, rsc,
    1765             :                                             PCMK_XA_OP, operation,
    1766             :                                             PCMK_XA_NODE, node,
    1767             :                                             NULL);
    1768             : 
    1769           0 :     if (interval_ms) {
    1770           0 :         char *interval_s = pcmk__itoa(interval_ms);
    1771             : 
    1772           0 :         crm_xml_add(xml_node, PCMK_XA_INTERVAL, interval_s);
    1773           0 :         free(interval_s);
    1774             :     }
    1775             : 
    1776           0 :     return pcmk_rc_ok;
    1777             : }
    1778             : 
    1779             : #define CHECK_RC(retcode, retval)   \
    1780             :     if (retval == pcmk_rc_ok) {     \
    1781             :         retcode = pcmk_rc_ok;       \
    1782             :     }
    1783             : 
    1784             : PCMK__OUTPUT_ARGS("cluster-status", "pcmk_scheduler_t *",
    1785             :                   "enum pcmk_pacemakerd_state", "crm_exit_t",
    1786             :                   "stonith_history_t *", "enum pcmk__fence_history", "uint32_t",
    1787             :                   "uint32_t", "const char *", "GList *", "GList *")
    1788             : int
    1789           0 : pcmk__cluster_status_text(pcmk__output_t *out, va_list args)
    1790             : {
    1791           0 :     pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
    1792           0 :     enum pcmk_pacemakerd_state pcmkd_state =
    1793             :         (enum pcmk_pacemakerd_state) va_arg(args, int);
    1794           0 :     crm_exit_t history_rc = va_arg(args, crm_exit_t);
    1795           0 :     stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
    1796           0 :     enum pcmk__fence_history fence_history = va_arg(args, int);
    1797           0 :     uint32_t section_opts = va_arg(args, uint32_t);
    1798           0 :     uint32_t show_opts = va_arg(args, uint32_t);
    1799           0 :     const char *prefix = va_arg(args, const char *);
    1800           0 :     GList *unames = va_arg(args, GList *);
    1801           0 :     GList *resources = va_arg(args, GList *);
    1802             : 
    1803           0 :     int rc = pcmk_rc_no_output;
    1804           0 :     bool already_printed_failure = false;
    1805             : 
    1806           0 :     CHECK_RC(rc, out->message(out, "cluster-summary", scheduler, pcmkd_state,
    1807             :                               section_opts, show_opts));
    1808             : 
    1809           0 :     if (pcmk_is_set(section_opts, pcmk_section_nodes) && unames) {
    1810           0 :         CHECK_RC(rc, out->message(out, "node-list", scheduler->nodes, unames,
    1811             :                                   resources, show_opts, rc == pcmk_rc_ok));
    1812             :     }
    1813             : 
    1814             :     /* Print resources section, if needed */
    1815           0 :     if (pcmk_is_set(section_opts, pcmk_section_resources)) {
    1816           0 :         CHECK_RC(rc, out->message(out, "resource-list", scheduler, show_opts,
    1817             :                                   true, unames, resources, rc == pcmk_rc_ok));
    1818             :     }
    1819             : 
    1820             :     /* print Node Attributes section if requested */
    1821           0 :     if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
    1822           0 :         CHECK_RC(rc, out->message(out, "node-attribute-list", scheduler,
    1823             :                                   show_opts, (rc == pcmk_rc_ok), unames,
    1824             :                                   resources));
    1825             :     }
    1826             : 
    1827             :     /* If requested, print resource operations (which includes failcounts)
    1828             :      * or just failcounts
    1829             :      */
    1830           0 :     if (pcmk_any_flags_set(section_opts,
    1831             :                            pcmk_section_operations|pcmk_section_failcounts)) {
    1832           0 :         CHECK_RC(rc, out->message(out, "node-summary", scheduler, unames,
    1833             :                                   resources, section_opts, show_opts,
    1834             :                                   (rc == pcmk_rc_ok)));
    1835             :     }
    1836             : 
    1837             :     /* If there were any failed actions, print them */
    1838           0 :     if (pcmk_is_set(section_opts, pcmk_section_failures)
    1839           0 :         && (scheduler->failed != NULL)
    1840           0 :         && (scheduler->failed->children != NULL)) {
    1841             : 
    1842           0 :         CHECK_RC(rc, out->message(out, "failed-action-list", scheduler, unames,
    1843             :                                   resources, show_opts, rc == pcmk_rc_ok));
    1844             :     }
    1845             : 
    1846             :     /* Print failed stonith actions */
    1847           0 :     if (pcmk_is_set(section_opts, pcmk_section_fence_failed) &&
    1848             :         fence_history != pcmk__fence_history_none) {
    1849           0 :         if (history_rc == 0) {
    1850           0 :             stonith_history_t *hp = NULL;
    1851             : 
    1852           0 :             hp = stonith__first_matching_event(stonith_history,
    1853             :                                                stonith__event_state_eq,
    1854             :                                                GINT_TO_POINTER(st_failed));
    1855           0 :             if (hp) {
    1856           0 :                 CHECK_RC(rc, out->message(out, "failed-fencing-list",
    1857             :                                           stonith_history, unames, section_opts,
    1858             :                                           show_opts, rc == pcmk_rc_ok));
    1859             :             }
    1860             :         } else {
    1861           0 :             PCMK__OUTPUT_SPACER_IF(out, rc == pcmk_rc_ok);
    1862           0 :             out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
    1863           0 :             out->list_item(out, NULL, "Failed to get fencing history: %s",
    1864             :                            crm_exit_str(history_rc));
    1865           0 :             out->end_list(out);
    1866             : 
    1867           0 :             already_printed_failure = true;
    1868             :         }
    1869             :     }
    1870             : 
    1871             :     /* Print tickets if requested */
    1872           0 :     if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
    1873           0 :         CHECK_RC(rc, out->message(out, "ticket-list", scheduler->tickets,
    1874             :                                   (rc == pcmk_rc_ok), false, false));
    1875             :     }
    1876             : 
    1877             :     /* Print negative location constraints if requested */
    1878           0 :     if (pcmk_is_set(section_opts, pcmk_section_bans)) {
    1879           0 :         CHECK_RC(rc, out->message(out, "ban-list", scheduler, prefix, resources,
    1880             :                                   show_opts, rc == pcmk_rc_ok));
    1881             :     }
    1882             : 
    1883             :     /* Print stonith history */
    1884           0 :     if (pcmk_any_flags_set(section_opts, pcmk_section_fencing_all) &&
    1885             :         fence_history != pcmk__fence_history_none) {
    1886           0 :         if (history_rc != 0) {
    1887           0 :             if (!already_printed_failure) {
    1888           0 :                 PCMK__OUTPUT_SPACER_IF(out, rc == pcmk_rc_ok);
    1889           0 :                 out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
    1890           0 :                 out->list_item(out, NULL, "Failed to get fencing history: %s",
    1891             :                                crm_exit_str(history_rc));
    1892           0 :                 out->end_list(out);
    1893             :             }
    1894           0 :         } else if (pcmk_is_set(section_opts, pcmk_section_fence_worked)) {
    1895           0 :             stonith_history_t *hp = NULL;
    1896             : 
    1897           0 :             hp = stonith__first_matching_event(stonith_history,
    1898             :                                                stonith__event_state_neq,
    1899             :                                                GINT_TO_POINTER(st_failed));
    1900           0 :             if (hp) {
    1901           0 :                 CHECK_RC(rc, out->message(out, "fencing-list", hp, unames,
    1902             :                                           section_opts, show_opts,
    1903             :                                           rc == pcmk_rc_ok));
    1904             :             }
    1905           0 :         } else if (pcmk_is_set(section_opts, pcmk_section_fence_pending)) {
    1906           0 :             stonith_history_t *hp = NULL;
    1907             : 
    1908           0 :             hp = stonith__first_matching_event(stonith_history,
    1909             :                                                stonith__event_state_pending,
    1910             :                                                NULL);
    1911           0 :             if (hp) {
    1912           0 :                 CHECK_RC(rc, out->message(out, "pending-fencing-list", hp,
    1913             :                                           unames, section_opts, show_opts,
    1914             :                                           rc == pcmk_rc_ok));
    1915             :             }
    1916             :         }
    1917             :     }
    1918             : 
    1919           0 :     return rc;
    1920             : }
    1921             : 
    1922             : PCMK__OUTPUT_ARGS("cluster-status", "pcmk_scheduler_t *",
    1923             :                   "enum pcmk_pacemakerd_state", "crm_exit_t",
    1924             :                   "stonith_history_t *", "enum pcmk__fence_history", "uint32_t",
    1925             :                   "uint32_t", "const char *", "GList *", "GList *")
    1926             : static int
    1927           0 : cluster_status_xml(pcmk__output_t *out, va_list args)
    1928             : {
    1929           0 :     pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
    1930           0 :     enum pcmk_pacemakerd_state pcmkd_state =
    1931             :         (enum pcmk_pacemakerd_state) va_arg(args, int);
    1932           0 :     crm_exit_t history_rc = va_arg(args, crm_exit_t);
    1933           0 :     stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
    1934           0 :     enum pcmk__fence_history fence_history = va_arg(args, int);
    1935           0 :     uint32_t section_opts = va_arg(args, uint32_t);
    1936           0 :     uint32_t show_opts = va_arg(args, uint32_t);
    1937           0 :     const char *prefix = va_arg(args, const char *);
    1938           0 :     GList *unames = va_arg(args, GList *);
    1939           0 :     GList *resources = va_arg(args, GList *);
    1940             : 
    1941           0 :     out->message(out, "cluster-summary", scheduler, pcmkd_state, section_opts,
    1942             :                  show_opts);
    1943             : 
    1944             :     /*** NODES ***/
    1945           0 :     if (pcmk_is_set(section_opts, pcmk_section_nodes)) {
    1946           0 :         out->message(out, "node-list", scheduler->nodes, unames, resources,
    1947             :                      show_opts, false);
    1948             :     }
    1949             : 
    1950             :     /* Print resources section, if needed */
    1951           0 :     if (pcmk_is_set(section_opts, pcmk_section_resources)) {
    1952             :         /* XML output always displays full details. */
    1953           0 :         uint32_t full_show_opts = show_opts & ~pcmk_show_brief;
    1954             : 
    1955           0 :         out->message(out, "resource-list", scheduler, full_show_opts,
    1956             :                      false, unames, resources, false);
    1957             :     }
    1958             : 
    1959             :     /* print Node Attributes section if requested */
    1960           0 :     if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
    1961           0 :         out->message(out, "node-attribute-list", scheduler, show_opts, false,
    1962             :                      unames, resources);
    1963             :     }
    1964             : 
    1965             :     /* If requested, print resource operations (which includes failcounts)
    1966             :      * or just failcounts
    1967             :      */
    1968           0 :     if (pcmk_any_flags_set(section_opts,
    1969             :                            pcmk_section_operations|pcmk_section_failcounts)) {
    1970           0 :         out->message(out, "node-summary", scheduler, unames,
    1971             :                      resources, section_opts, show_opts, false);
    1972             :     }
    1973             : 
    1974             :     /* If there were any failed actions, print them */
    1975           0 :     if (pcmk_is_set(section_opts, pcmk_section_failures)
    1976           0 :         && (scheduler->failed != NULL)
    1977           0 :         && (scheduler->failed->children != NULL)) {
    1978             : 
    1979           0 :         out->message(out, "failed-action-list", scheduler, unames, resources,
    1980             :                      show_opts, false);
    1981             :     }
    1982             : 
    1983             :     /* Print stonith history */
    1984           0 :     if (pcmk_is_set(section_opts, pcmk_section_fencing_all) &&
    1985             :         fence_history != pcmk__fence_history_none) {
    1986           0 :         out->message(out, "full-fencing-list", history_rc, stonith_history,
    1987             :                      unames, section_opts, show_opts, false);
    1988             :     }
    1989             : 
    1990             :     /* Print tickets if requested */
    1991           0 :     if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
    1992           0 :         out->message(out, "ticket-list", scheduler->tickets, false, false, false);
    1993             :     }
    1994             : 
    1995             :     /* Print negative location constraints if requested */
    1996           0 :     if (pcmk_is_set(section_opts, pcmk_section_bans)) {
    1997           0 :         out->message(out, "ban-list", scheduler, prefix, resources, show_opts,
    1998             :                      false);
    1999             :     }
    2000             : 
    2001           0 :     return pcmk_rc_ok;
    2002             : }
    2003             : 
    2004             : PCMK__OUTPUT_ARGS("cluster-status", "pcmk_scheduler_t *",
    2005             :                   "enum pcmk_pacemakerd_state", "crm_exit_t",
    2006             :                   "stonith_history_t *", "enum pcmk__fence_history", "uint32_t",
    2007             :                   "uint32_t", "const char *", "GList *", "GList *")
    2008             : static int
    2009           0 : cluster_status_html(pcmk__output_t *out, va_list args)
    2010             : {
    2011           0 :     pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
    2012           0 :     enum pcmk_pacemakerd_state pcmkd_state =
    2013             :         (enum pcmk_pacemakerd_state) va_arg(args, int);
    2014           0 :     crm_exit_t history_rc = va_arg(args, crm_exit_t);
    2015           0 :     stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
    2016           0 :     enum pcmk__fence_history fence_history = va_arg(args, int);
    2017           0 :     uint32_t section_opts = va_arg(args, uint32_t);
    2018           0 :     uint32_t show_opts = va_arg(args, uint32_t);
    2019           0 :     const char *prefix = va_arg(args, const char *);
    2020           0 :     GList *unames = va_arg(args, GList *);
    2021           0 :     GList *resources = va_arg(args, GList *);
    2022           0 :     bool already_printed_failure = false;
    2023             : 
    2024           0 :     out->message(out, "cluster-summary", scheduler, pcmkd_state, section_opts,
    2025             :                  show_opts);
    2026             : 
    2027             :     /*** NODE LIST ***/
    2028           0 :     if (pcmk_is_set(section_opts, pcmk_section_nodes) && unames) {
    2029           0 :         out->message(out, "node-list", scheduler->nodes, unames, resources,
    2030             :                      show_opts, false);
    2031             :     }
    2032             : 
    2033             :     /* Print resources section, if needed */
    2034           0 :     if (pcmk_is_set(section_opts, pcmk_section_resources)) {
    2035           0 :         out->message(out, "resource-list", scheduler, show_opts, true, unames,
    2036             :                      resources, false);
    2037             :     }
    2038             : 
    2039             :     /* print Node Attributes section if requested */
    2040           0 :     if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
    2041           0 :         out->message(out, "node-attribute-list", scheduler, show_opts, false,
    2042             :                      unames, resources);
    2043             :     }
    2044             : 
    2045             :     /* If requested, print resource operations (which includes failcounts)
    2046             :      * or just failcounts
    2047             :      */
    2048           0 :     if (pcmk_any_flags_set(section_opts,
    2049             :                            pcmk_section_operations|pcmk_section_failcounts)) {
    2050           0 :         out->message(out, "node-summary", scheduler, unames,
    2051             :                      resources, section_opts, show_opts, false);
    2052             :     }
    2053             : 
    2054             :     /* If there were any failed actions, print them */
    2055           0 :     if (pcmk_is_set(section_opts, pcmk_section_failures)
    2056           0 :         && (scheduler->failed != NULL)
    2057           0 :         && (scheduler->failed->children != NULL)) {
    2058             : 
    2059           0 :         out->message(out, "failed-action-list", scheduler, unames, resources,
    2060             :                      show_opts, false);
    2061             :     }
    2062             : 
    2063             :     /* Print failed stonith actions */
    2064           0 :     if (pcmk_is_set(section_opts, pcmk_section_fence_failed) &&
    2065             :         fence_history != pcmk__fence_history_none) {
    2066           0 :         if (history_rc == 0) {
    2067           0 :             stonith_history_t *hp = NULL;
    2068             : 
    2069           0 :             hp = stonith__first_matching_event(stonith_history,
    2070             :                                                stonith__event_state_eq,
    2071             :                                                GINT_TO_POINTER(st_failed));
    2072           0 :             if (hp) {
    2073           0 :                 out->message(out, "failed-fencing-list", stonith_history,
    2074             :                              unames, section_opts, show_opts, false);
    2075             :             }
    2076             :         } else {
    2077           0 :             out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
    2078           0 :             out->list_item(out, NULL, "Failed to get fencing history: %s",
    2079             :                            crm_exit_str(history_rc));
    2080           0 :             out->end_list(out);
    2081             :         }
    2082             :     }
    2083             : 
    2084             :     /* Print stonith history */
    2085           0 :     if (pcmk_any_flags_set(section_opts, pcmk_section_fencing_all) &&
    2086             :         fence_history != pcmk__fence_history_none) {
    2087           0 :         if (history_rc != 0) {
    2088           0 :             if (!already_printed_failure) {
    2089           0 :                 out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
    2090           0 :                 out->list_item(out, NULL, "Failed to get fencing history: %s",
    2091             :                                crm_exit_str(history_rc));
    2092           0 :                 out->end_list(out);
    2093             :             }
    2094           0 :         } else if (pcmk_is_set(section_opts, pcmk_section_fence_worked)) {
    2095           0 :             stonith_history_t *hp = NULL;
    2096             : 
    2097           0 :             hp = stonith__first_matching_event(stonith_history,
    2098             :                                                stonith__event_state_neq,
    2099             :                                                GINT_TO_POINTER(st_failed));
    2100           0 :             if (hp) {
    2101           0 :                 out->message(out, "fencing-list", hp, unames, section_opts,
    2102             :                              show_opts, false);
    2103             :             }
    2104           0 :         } else if (pcmk_is_set(section_opts, pcmk_section_fence_pending)) {
    2105           0 :             stonith_history_t *hp = NULL;
    2106             : 
    2107           0 :             hp = stonith__first_matching_event(stonith_history,
    2108             :                                                stonith__event_state_pending,
    2109             :                                                NULL);
    2110           0 :             if (hp) {
    2111           0 :                 out->message(out, "pending-fencing-list", hp, unames,
    2112             :                              section_opts, show_opts, false);
    2113             :             }
    2114             :         }
    2115             :     }
    2116             : 
    2117             :     /* Print tickets if requested */
    2118           0 :     if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
    2119           0 :         out->message(out, "ticket-list", scheduler->tickets, false, false, false);
    2120             :     }
    2121             : 
    2122             :     /* Print negative location constraints if requested */
    2123           0 :     if (pcmk_is_set(section_opts, pcmk_section_bans)) {
    2124           0 :         out->message(out, "ban-list", scheduler, prefix, resources, show_opts,
    2125             :                      false);
    2126             :     }
    2127             : 
    2128           0 :     return pcmk_rc_ok;
    2129             : }
    2130             : 
    2131             : #define KV_PAIR(k, v) do { \
    2132             :     if (legacy) { \
    2133             :         pcmk__g_strcat(s, k "=", pcmk__s(v, ""), " ", NULL); \
    2134             :     } else { \
    2135             :         pcmk__g_strcat(s, k "=\"", pcmk__s(v, ""), "\"", NULL); \
    2136             :     } \
    2137             : } while (0)
    2138             : 
    2139             : PCMK__OUTPUT_ARGS("attribute", "const char *", "const char *", "const char *",
    2140             :                   "const char *", "const char *", "bool", "bool")
    2141             : static int
    2142           0 : attribute_default(pcmk__output_t *out, va_list args)
    2143             : {
    2144           0 :     const char *scope = va_arg(args, const char *);
    2145           0 :     const char *instance = va_arg(args, const char *);
    2146           0 :     const char *name = va_arg(args, const char *);
    2147           0 :     const char *value = va_arg(args, const char *);
    2148           0 :     const char *host = va_arg(args, const char *);
    2149           0 :     bool quiet = va_arg(args, int);
    2150           0 :     bool legacy = va_arg(args, int);
    2151             : 
    2152           0 :     gchar *value_esc = NULL;
    2153           0 :     GString *s = NULL;
    2154             : 
    2155           0 :     if (quiet) {
    2156           0 :         if (value != NULL) {
    2157             :             /* Quiet needs to be turned off for ->info() to do anything */
    2158           0 :             bool was_quiet = out->is_quiet(out);
    2159             : 
    2160           0 :             if (was_quiet) {
    2161           0 :                 out->quiet = false;
    2162             :             }
    2163             : 
    2164           0 :             out->info(out, "%s", value);
    2165             : 
    2166           0 :             out->quiet = was_quiet;
    2167             :         }
    2168             : 
    2169           0 :         return pcmk_rc_ok;
    2170             :     }
    2171             : 
    2172           0 :     s = g_string_sized_new(50);
    2173             : 
    2174           0 :     if (pcmk__xml_needs_escape(value, pcmk__xml_escape_attr_pretty)) {
    2175           0 :         value_esc = pcmk__xml_escape(value, pcmk__xml_escape_attr_pretty);
    2176           0 :         value = value_esc;
    2177             :     }
    2178             : 
    2179           0 :     if (!pcmk__str_empty(scope)) {
    2180           0 :         KV_PAIR(PCMK_XA_SCOPE, scope);
    2181             :     }
    2182             : 
    2183           0 :     if (!pcmk__str_empty(instance)) {
    2184           0 :         KV_PAIR(PCMK_XA_ID, instance);
    2185             :     }
    2186             : 
    2187           0 :     KV_PAIR(PCMK_XA_NAME, name);
    2188             : 
    2189           0 :     if (!pcmk__str_empty(host)) {
    2190           0 :         KV_PAIR(PCMK_XA_HOST, host);
    2191             :     }
    2192             : 
    2193           0 :     if (legacy) {
    2194           0 :         pcmk__g_strcat(s, PCMK_XA_VALUE "=", pcmk__s(value, "(null)"), NULL);
    2195             :     } else {
    2196           0 :         pcmk__g_strcat(s, PCMK_XA_VALUE "=\"", pcmk__s(value, ""), "\"", NULL);
    2197             :     }
    2198             : 
    2199           0 :     out->info(out, "%s", s->str);
    2200             : 
    2201           0 :     g_free(value_esc);
    2202           0 :     g_string_free(s, TRUE);
    2203           0 :     return pcmk_rc_ok;
    2204             : }
    2205             : 
    2206             : PCMK__OUTPUT_ARGS("attribute", "const char *", "const char *", "const char *",
    2207             :                   "const char *", "const char *", "bool", "bool")
    2208             : static int
    2209           0 : attribute_xml(pcmk__output_t *out, va_list args)
    2210             : {
    2211           0 :     const char *scope = va_arg(args, const char *);
    2212           0 :     const char *instance = va_arg(args, const char *);
    2213           0 :     const char *name = va_arg(args, const char *);
    2214           0 :     const char *value = va_arg(args, const char *);
    2215           0 :     const char *host = va_arg(args, const char *);
    2216           0 :     bool quiet G_GNUC_UNUSED = va_arg(args, int);
    2217           0 :     bool legacy G_GNUC_UNUSED = va_arg(args, int);
    2218             : 
    2219           0 :     xmlNodePtr node = NULL;
    2220             : 
    2221           0 :     node = pcmk__output_create_xml_node(out, PCMK_XE_ATTRIBUTE,
    2222             :                                         PCMK_XA_NAME, name,
    2223             :                                         PCMK_XA_VALUE, pcmk__s(value, ""),
    2224             :                                         NULL);
    2225             : 
    2226           0 :     if (!pcmk__str_empty(scope)) {
    2227           0 :         crm_xml_add(node, PCMK_XA_SCOPE, scope);
    2228             :     }
    2229             : 
    2230           0 :     if (!pcmk__str_empty(instance)) {
    2231           0 :         crm_xml_add(node, PCMK_XA_ID, instance);
    2232             :     }
    2233             : 
    2234           0 :     if (!pcmk__str_empty(host)) {
    2235           0 :         crm_xml_add(node, PCMK_XA_HOST, host);
    2236             :     }
    2237             : 
    2238           0 :     return pcmk_rc_ok;
    2239             : }
    2240             : 
    2241             : PCMK__OUTPUT_ARGS("rule-check", "const char *", "int", "const char *")
    2242             : static int
    2243           0 : rule_check_default(pcmk__output_t *out, va_list args)
    2244             : {
    2245           0 :     const char *rule_id = va_arg(args, const char *);
    2246           0 :     int result = va_arg(args, int);
    2247           0 :     const char *error = va_arg(args, const char *);
    2248             : 
    2249           0 :     switch (result) {
    2250           0 :         case pcmk_rc_within_range:
    2251           0 :             return out->info(out, "Rule %s is still in effect", rule_id);
    2252           0 :         case pcmk_rc_ok:
    2253           0 :             return out->info(out, "Rule %s satisfies conditions", rule_id);
    2254           0 :         case pcmk_rc_after_range:
    2255           0 :             return out->info(out, "Rule %s is expired", rule_id);
    2256           0 :         case pcmk_rc_before_range:
    2257           0 :             return out->info(out, "Rule %s has not yet taken effect", rule_id);
    2258           0 :         case pcmk_rc_op_unsatisfied:
    2259           0 :             return out->info(out, "Rule %s does not satisfy conditions",
    2260             :                              rule_id);
    2261           0 :         default:
    2262           0 :             out->err(out,
    2263             :                      "Could not determine whether rule %s is in effect: %s",
    2264             :                      rule_id, ((error != NULL)? error : "unexpected error"));
    2265           0 :             return pcmk_rc_ok;
    2266             :     }
    2267             : }
    2268             : 
    2269             : PCMK__OUTPUT_ARGS("rule-check", "const char *", "int", "const char *")
    2270             : static int
    2271           0 : rule_check_xml(pcmk__output_t *out, va_list args)
    2272             : {
    2273           0 :     const char *rule_id = va_arg(args, const char *);
    2274           0 :     int result = va_arg(args, int);
    2275           0 :     const char *error = va_arg(args, const char *);
    2276             : 
    2277           0 :     char *rc_str = pcmk__itoa(pcmk_rc2exitc(result));
    2278             : 
    2279           0 :     pcmk__output_create_xml_node(out, PCMK_XE_RULE_CHECK,
    2280             :                                  PCMK_XA_RULE_ID, rule_id,
    2281             :                                  PCMK_XA_RC, rc_str,
    2282             :                                  NULL);
    2283           0 :     free(rc_str);
    2284             : 
    2285           0 :     switch (result) {
    2286           0 :         case pcmk_rc_within_range:
    2287             :         case pcmk_rc_ok:
    2288             :         case pcmk_rc_after_range:
    2289             :         case pcmk_rc_before_range:
    2290             :         case pcmk_rc_op_unsatisfied:
    2291           0 :             return pcmk_rc_ok;
    2292           0 :         default:
    2293           0 :             out->err(out,
    2294             :                     "Could not determine whether rule %s is in effect: %s",
    2295             :                     rule_id, ((error != NULL)? error : "unexpected error"));
    2296           0 :             return pcmk_rc_ok;
    2297             :     }
    2298             : }
    2299             : 
    2300             : PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
    2301             : static int
    2302           0 : result_code_none(pcmk__output_t *out, va_list args)
    2303             : {
    2304           0 :     return pcmk_rc_no_output;
    2305             : }
    2306             : 
    2307             : PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
    2308             : static int
    2309           0 : result_code_text(pcmk__output_t *out, va_list args)
    2310             : {
    2311           0 :     int code = va_arg(args, int);
    2312           0 :     const char *name = va_arg(args, const char *);
    2313           0 :     const char *desc = va_arg(args, const char *);
    2314             : 
    2315             :     static int code_width = 0;
    2316             : 
    2317           0 :     if (out->is_quiet(out)) {
    2318             :         /* If out->is_quiet(), don't print the code. Print name and/or desc in a
    2319             :          * compact format for text output, or print nothing at all for none-type
    2320             :          * output.
    2321             :          */
    2322           0 :         if ((name != NULL) && (desc != NULL)) {
    2323           0 :             pcmk__formatted_printf(out, "%s - %s\n", name, desc);
    2324             : 
    2325           0 :         } else if ((name != NULL) || (desc != NULL)) {
    2326           0 :             pcmk__formatted_printf(out, "%s\n", ((name != NULL)? name : desc));
    2327             :         }
    2328           0 :         return pcmk_rc_ok;
    2329             :     }
    2330             : 
    2331             :     /* Get length of longest (most negative) standard Pacemaker return code
    2332             :      * This should be longer than all the values of any other type of return
    2333             :      * code.
    2334             :      */
    2335           0 :     if (code_width == 0) {
    2336           0 :         long long most_negative = pcmk_rc_error - (long long) pcmk__n_rc + 1;
    2337           0 :         code_width = (int) snprintf(NULL, 0, "%lld", most_negative);
    2338             :     }
    2339             : 
    2340           0 :     if ((name != NULL) && (desc != NULL)) {
    2341             :         static int name_width = 0;
    2342             : 
    2343           0 :         if (name_width == 0) {
    2344             :             // Get length of longest standard Pacemaker return code name
    2345           0 :             for (int lpc = 0; lpc < pcmk__n_rc; lpc++) {
    2346           0 :                 int len = (int) strlen(pcmk_rc_name(pcmk_rc_error - lpc));
    2347           0 :                 name_width = QB_MAX(name_width, len);
    2348             :             }
    2349             :         }
    2350           0 :         return out->info(out, "% *d: %-*s  %s", code_width, code, name_width,
    2351             :                          name, desc);
    2352             :     }
    2353             : 
    2354           0 :     if ((name != NULL) || (desc != NULL)) {
    2355           0 :         return out->info(out, "% *d: %s", code_width, code,
    2356             :                          ((name != NULL)? name : desc));
    2357             :     }
    2358             : 
    2359           0 :     return out->info(out, "% *d", code_width, code);
    2360             : }
    2361             : 
    2362             : PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
    2363             : static int
    2364           0 : result_code_xml(pcmk__output_t *out, va_list args)
    2365             : {
    2366           0 :     int code = va_arg(args, int);
    2367           0 :     const char *name = va_arg(args, const char *);
    2368           0 :     const char *desc = va_arg(args, const char *);
    2369             : 
    2370           0 :     char *code_str = pcmk__itoa(code);
    2371             : 
    2372           0 :     pcmk__output_create_xml_node(out, PCMK_XE_RESULT_CODE,
    2373             :                                  PCMK_XA_CODE, code_str,
    2374             :                                  PCMK_XA_NAME, name,
    2375             :                                  PCMK_XA_DESCRIPTION, desc,
    2376             :                                  NULL);
    2377           0 :     free(code_str);
    2378           0 :     return pcmk_rc_ok;
    2379             : }
    2380             : 
    2381             : PCMK__OUTPUT_ARGS("ticket-attribute", "const char *", "const char *", "const char *")
    2382             : static int
    2383           0 : ticket_attribute_default(pcmk__output_t *out, va_list args)
    2384             : {
    2385           0 :     const char *ticket_id G_GNUC_UNUSED = va_arg(args, const char *);
    2386           0 :     const char *name G_GNUC_UNUSED = va_arg(args, const char *);
    2387           0 :     const char *value = va_arg(args, const char *);
    2388             : 
    2389           0 :     out->info(out, "%s", value);
    2390           0 :     return pcmk_rc_ok;
    2391             : }
    2392             : 
    2393             : PCMK__OUTPUT_ARGS("ticket-attribute", "const char *", "const char *", "const char *")
    2394             : static int
    2395           0 : ticket_attribute_xml(pcmk__output_t *out, va_list args)
    2396             : {
    2397           0 :     const char *ticket_id = va_arg(args, const char *);
    2398           0 :     const char *name = va_arg(args, const char *);
    2399           0 :     const char *value = va_arg(args, const char *);
    2400             : 
    2401             :     /* Create:
    2402             :      * <tickets>
    2403             :      *   <ticket id="">
    2404             :      *     <attribute name="" value="" />
    2405             :      *   </ticket>
    2406             :      * </tickets>
    2407             :      */
    2408           0 :     pcmk__output_xml_create_parent(out, PCMK_XE_TICKETS, NULL);
    2409           0 :     pcmk__output_xml_create_parent(out, PCMK_XE_TICKET,
    2410             :                                    PCMK_XA_ID, ticket_id, NULL);
    2411           0 :     pcmk__output_create_xml_node(out, PCMK_XA_ATTRIBUTE,
    2412             :                                  PCMK_XA_NAME, name,
    2413             :                                  PCMK_XA_VALUE, value,
    2414             :                                  NULL);
    2415           0 :     pcmk__output_xml_pop_parent(out);
    2416           0 :     pcmk__output_xml_pop_parent(out);
    2417             : 
    2418           0 :     return pcmk_rc_ok;
    2419             : }
    2420             : 
    2421             : PCMK__OUTPUT_ARGS("ticket-constraints", "xmlNode *")
    2422             : static int
    2423           0 : ticket_constraints_default(pcmk__output_t *out, va_list args)
    2424             : {
    2425           0 :     xmlNode *constraint_xml = va_arg(args, xmlNode *);
    2426             : 
    2427             :     /* constraint_xml can take two forms:
    2428             :      *
    2429             :      * <rsc_ticket id="rsc1-req-ticketA" rsc="rsc1" ticket="ticketA" ... />
    2430             :      *
    2431             :      * for when there's only one ticket in the CIB, or when the user asked
    2432             :      * for a specific ticket (crm_ticket -c -t for instance)
    2433             :      *
    2434             :      * <xpath-query>
    2435             :      *   <rsc_ticket id="rsc1-req-ticketA" rsc="rsc1" ticket="ticketA" ... />
    2436             :      *   <rsc_ticket id="rsc1-req-ticketB" rsc="rsc2" ticket="ticketB" ... />
    2437             :      * </xpath-query>
    2438             :      *
    2439             :      * for when there's multiple tickets in the and the user did not ask for
    2440             :      * a specific one.
    2441             :      *
    2442             :      * In both cases, we simply output a <rsc_ticket> element for each ticket
    2443             :      * in the results.
    2444             :      */
    2445           0 :     out->info(out, "Constraints XML:\n");
    2446             : 
    2447           0 :     if (pcmk__xe_is(constraint_xml, PCMK__XE_XPATH_QUERY)) {
    2448           0 :         xmlNode *child = pcmk__xe_first_child(constraint_xml, NULL, NULL, NULL);
    2449             : 
    2450             :         do {
    2451           0 :             GString *buf = g_string_sized_new(1024);
    2452             : 
    2453           0 :             pcmk__xml_string(child, pcmk__xml_fmt_pretty, buf, 0);
    2454           0 :             out->output_xml(out, PCMK_XE_CONSTRAINT, buf->str);
    2455           0 :             g_string_free(buf, TRUE);
    2456             : 
    2457           0 :             child = pcmk__xe_next(child);
    2458           0 :         } while (child != NULL);
    2459             :     } else {
    2460           0 :         GString *buf = g_string_sized_new(1024);
    2461             : 
    2462           0 :         pcmk__xml_string(constraint_xml, pcmk__xml_fmt_pretty, buf, 0);
    2463           0 :         out->output_xml(out, PCMK_XE_CONSTRAINT, buf->str);
    2464           0 :         g_string_free(buf, TRUE);
    2465             :     }
    2466             : 
    2467           0 :     return pcmk_rc_ok;
    2468             : }
    2469             : 
    2470             : static int
    2471           0 : add_ticket_element_with_constraints(xmlNode *node, void *userdata)
    2472             : {
    2473           0 :     pcmk__output_t *out = (pcmk__output_t *) userdata;
    2474           0 :     const char *ticket_id = crm_element_value(node, PCMK_XA_TICKET);
    2475             : 
    2476           0 :     pcmk__output_xml_create_parent(out, PCMK_XE_TICKET,
    2477             :                                    PCMK_XA_ID, ticket_id, NULL);
    2478           0 :     pcmk__output_xml_create_parent(out, PCMK_XE_CONSTRAINTS, NULL);
    2479           0 :     pcmk__output_xml_add_node_copy(out, node);
    2480             : 
    2481             :     /* Pop two parents so now we are back under the <tickets> element */
    2482           0 :     pcmk__output_xml_pop_parent(out);
    2483           0 :     pcmk__output_xml_pop_parent(out);
    2484             : 
    2485           0 :     return pcmk_rc_ok;
    2486             : }
    2487             : 
    2488             : static int
    2489           0 : add_resource_element(xmlNode *node, void *userdata)
    2490             : {
    2491           0 :     pcmk__output_t *out = (pcmk__output_t *) userdata;
    2492           0 :     const char *rsc = crm_element_value(node, PCMK_XA_RSC);
    2493             : 
    2494           0 :     pcmk__output_create_xml_node(out, PCMK_XE_RESOURCE,
    2495             :                                  PCMK_XA_ID, rsc, NULL);
    2496           0 :     return pcmk_rc_ok;
    2497             : }
    2498             : 
    2499             : PCMK__OUTPUT_ARGS("ticket-constraints", "xmlNode *")
    2500             : static int
    2501           0 : ticket_constraints_xml(pcmk__output_t *out, va_list args)
    2502             : {
    2503           0 :     xmlNode *constraint_xml = va_arg(args, xmlNode *);
    2504             : 
    2505             :     /* Create:
    2506             :      * <tickets>
    2507             :      *   <ticket id="">
    2508             :      *     <constraints>
    2509             :      *       <rsc_ticket />
    2510             :      *     </constraints>
    2511             :      *   </ticket>
    2512             :      *   ...
    2513             :      * </tickets>
    2514             :      */
    2515           0 :     pcmk__output_xml_create_parent(out, PCMK_XE_TICKETS, NULL);
    2516             : 
    2517           0 :     if (pcmk__xe_is(constraint_xml, PCMK__XE_XPATH_QUERY)) {
    2518             :         /* Iterate through the list of children once to create all the
    2519             :          * ticket/constraint elements.
    2520             :          */
    2521           0 :         pcmk__xe_foreach_child(constraint_xml, NULL, add_ticket_element_with_constraints, out);
    2522             : 
    2523             :         /* Put us back at the same level as where <tickets> was created. */
    2524           0 :         pcmk__output_xml_pop_parent(out);
    2525             : 
    2526             :         /* Constraints can reference a resource ID that is defined in the XML
    2527             :          * schema as an IDREF.  This requires some other element to be present
    2528             :          * with an id= attribute that matches.
    2529             :          *
    2530             :          * Iterate through the list of children a second time to create the
    2531             :          * following:
    2532             :          *
    2533             :          * <resources>
    2534             :          *   <resource id="" />
    2535             :          *   ...
    2536             :          * </resources>
    2537             :          */
    2538           0 :         pcmk__output_xml_create_parent(out, PCMK_XE_RESOURCES, NULL);
    2539           0 :         pcmk__xe_foreach_child(constraint_xml, NULL, add_resource_element, out);
    2540           0 :         pcmk__output_xml_pop_parent(out);
    2541             : 
    2542             :     } else {
    2543             :         /* Creating the output for a single constraint is much easier.  All the
    2544             :          * comments in the above block apply here.
    2545             :          */
    2546           0 :         add_ticket_element_with_constraints(constraint_xml, out);
    2547           0 :         pcmk__output_xml_pop_parent(out);
    2548             : 
    2549           0 :         pcmk__output_xml_create_parent(out, PCMK_XE_RESOURCES, NULL);
    2550           0 :         add_resource_element(constraint_xml, out);
    2551           0 :         pcmk__output_xml_pop_parent(out);
    2552             :     }
    2553             : 
    2554           0 :     return pcmk_rc_ok;
    2555             : }
    2556             : 
    2557             : PCMK__OUTPUT_ARGS("ticket-state", "xmlNode *")
    2558             : static int
    2559           0 : ticket_state_default(pcmk__output_t *out, va_list args)
    2560             : {
    2561           0 :     xmlNode *state_xml = va_arg(args, xmlNode *);
    2562             : 
    2563           0 :     GString *buf = g_string_sized_new(1024);
    2564             : 
    2565           0 :     out->info(out, "State XML:\n");
    2566           0 :     pcmk__xml_string(state_xml, pcmk__xml_fmt_pretty, buf, 0);
    2567           0 :     out->output_xml(out, PCMK__XE_TICKET_STATE, buf->str);
    2568             : 
    2569           0 :     g_string_free(buf, TRUE);
    2570           0 :     return pcmk_rc_ok;
    2571             : }
    2572             : 
    2573             : static int
    2574           0 : add_ticket_element(xmlNode *node, void *userdata)
    2575             : {
    2576           0 :     pcmk__output_t *out = (pcmk__output_t *) userdata;
    2577           0 :     xmlNode *ticket_node = NULL;
    2578             : 
    2579           0 :     ticket_node = pcmk__output_create_xml_node(out, PCMK_XE_TICKET, NULL);
    2580           0 :     pcmk__xe_copy_attrs(ticket_node, node, pcmk__xaf_none);
    2581           0 :     return pcmk_rc_ok;
    2582             : }
    2583             : 
    2584             : PCMK__OUTPUT_ARGS("ticket-state", "xmlNode *")
    2585             : static int
    2586           0 : ticket_state_xml(pcmk__output_t *out, va_list args)
    2587             : {
    2588           0 :     xmlNode *state_xml = va_arg(args, xmlNode *);
    2589             : 
    2590             :     /* Create:
    2591             :      * <tickets>
    2592             :      *   <ticket />
    2593             :      *   ...
    2594             :      * </tickets>
    2595             :      */
    2596           0 :     pcmk__output_xml_create_parent(out, PCMK_XE_TICKETS, NULL);
    2597             : 
    2598           0 :     if (state_xml->children != NULL) {
    2599             :         /* Iterate through the list of children once to create all the
    2600             :          * ticket elements.
    2601             :          */
    2602           0 :         pcmk__xe_foreach_child(state_xml, PCMK__XE_TICKET_STATE, add_ticket_element, out);
    2603             : 
    2604             :     } else {
    2605           0 :         add_ticket_element(state_xml, out);
    2606             :     }
    2607             : 
    2608           0 :     pcmk__output_xml_pop_parent(out);
    2609           0 :     return pcmk_rc_ok;
    2610             : }
    2611             : 
    2612             : static pcmk__message_entry_t fmt_functions[] = {
    2613             :     { "attribute", "default", attribute_default },
    2614             :     { "attribute", "xml", attribute_xml },
    2615             :     { "cluster-status", "default", pcmk__cluster_status_text },
    2616             :     { "cluster-status", "html", cluster_status_html },
    2617             :     { "cluster-status", "xml", cluster_status_xml },
    2618             :     { "crmadmin-node", "default", crmadmin_node },
    2619             :     { "crmadmin-node", "text", crmadmin_node_text },
    2620             :     { "crmadmin-node", "xml", crmadmin_node_xml },
    2621             :     { "dc", "default", dc },
    2622             :     { "dc", "text", dc_text },
    2623             :     { "dc", "xml", dc_xml },
    2624             :     { "digests", "default", digests_text },
    2625             :     { "digests", "xml", digests_xml },
    2626             :     { "health", "default", health },
    2627             :     { "health", "text", health_text },
    2628             :     { "health", "xml", health_xml },
    2629             :     { "inject-attr", "default", inject_attr },
    2630             :     { "inject-attr", "xml", inject_attr_xml },
    2631             :     { "inject-cluster-action", "default", inject_cluster_action },
    2632             :     { "inject-cluster-action", "xml", inject_cluster_action_xml },
    2633             :     { "inject-fencing-action", "default", inject_fencing_action },
    2634             :     { "inject-fencing-action", "xml", inject_fencing_action_xml },
    2635             :     { "inject-modify-config", "default", inject_modify_config },
    2636             :     { "inject-modify-config", "xml", inject_modify_config_xml },
    2637             :     { "inject-modify-node", "default", inject_modify_node },
    2638             :     { "inject-modify-node", "xml", inject_modify_node_xml },
    2639             :     { "inject-modify-ticket", "default", inject_modify_ticket },
    2640             :     { "inject-modify-ticket", "xml", inject_modify_ticket_xml },
    2641             :     { "inject-pseudo-action", "default", inject_pseudo_action },
    2642             :     { "inject-pseudo-action", "xml", inject_pseudo_action_xml },
    2643             :     { "inject-rsc-action", "default", inject_rsc_action },
    2644             :     { "inject-rsc-action", "xml", inject_rsc_action_xml },
    2645             :     { "inject-spec", "default", inject_spec },
    2646             :     { "inject-spec", "xml", inject_spec_xml },
    2647             :     { "locations-and-colocations", "default", locations_and_colocations },
    2648             :     { "locations-and-colocations", "xml", locations_and_colocations_xml },
    2649             :     { "locations-list", "default", locations_list },
    2650             :     { "locations-list", "xml", locations_list_xml },
    2651             :     { "node-action", "default", node_action },
    2652             :     { "node-action", "xml", node_action_xml },
    2653             :     { "node-info", "default", node_info_default },
    2654             :     { "node-info", "xml", node_info_xml },
    2655             :     { "pacemakerd-health", "default", pacemakerd_health },
    2656             :     { "pacemakerd-health", "html", pacemakerd_health_html },
    2657             :     { "pacemakerd-health", "text", pacemakerd_health_text },
    2658             :     { "pacemakerd-health", "xml", pacemakerd_health_xml },
    2659             :     { "profile", "default", profile_default, },
    2660             :     { "profile", "xml", profile_xml },
    2661             :     { "result-code", PCMK_VALUE_NONE, result_code_none },
    2662             :     { "result-code", "text", result_code_text },
    2663             :     { "result-code", "xml", result_code_xml },
    2664             :     { "rsc-action", "default", rsc_action_default },
    2665             :     { "rsc-action-item", "default", rsc_action_item },
    2666             :     { "rsc-action-item", "xml", rsc_action_item_xml },
    2667             :     { "rsc-is-colocated-with-list", "default", rsc_is_colocated_with_list },
    2668             :     { "rsc-is-colocated-with-list", "xml", rsc_is_colocated_with_list_xml },
    2669             :     { "rscs-colocated-with-list", "default", rscs_colocated_with_list },
    2670             :     { "rscs-colocated-with-list", "xml", rscs_colocated_with_list_xml },
    2671             :     { "rule-check", "default", rule_check_default },
    2672             :     { "rule-check", "xml", rule_check_xml },
    2673             :     { "ticket-attribute", "default", ticket_attribute_default },
    2674             :     { "ticket-attribute", "xml", ticket_attribute_xml },
    2675             :     { "ticket-constraints", "default", ticket_constraints_default },
    2676             :     { "ticket-constraints", "xml", ticket_constraints_xml },
    2677             :     { "ticket-state", "default", ticket_state_default },
    2678             :     { "ticket-state", "xml", ticket_state_xml },
    2679             : 
    2680             :     { NULL, NULL, NULL }
    2681             : };
    2682             : 
    2683             : void
    2684           0 : pcmk__register_lib_messages(pcmk__output_t *out) {
    2685           0 :     pcmk__register_messages(out, fmt_functions);
    2686           0 : }

Generated by: LCOV version 1.14