root/lib/pengine/pe_output.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. compare_attribute
  2. add_extra_info
  3. filter_attr_list
  4. get_operation_list
  5. add_dump_node
  6. append_dump_text
  7. failed_action_string
  8. get_cluster_stack
  9. last_changed_string
  10. op_history_string
  11. resource_history_string
  12. PCMK__OUTPUT_ARGS
  13. PCMK__OUTPUT_ARGS
  14. pe__node_display_name
  15. pe__name_and_nvpairs_xml
  16. role_desc
  17. PCMK__OUTPUT_ARGS
  18. PCMK__OUTPUT_ARGS
  19. PCMK__OUTPUT_ARGS
  20. PCMK__OUTPUT_ARGS
  21. PCMK__OUTPUT_ARGS
  22. PCMK__OUTPUT_ARGS
  23. PCMK__OUTPUT_ARGS
  24. PCMK__OUTPUT_ARGS
  25. PCMK__OUTPUT_ARGS
  26. PCMK__OUTPUT_ARGS
  27. PCMK__OUTPUT_ARGS
  28. PCMK__OUTPUT_ARGS
  29. PCMK__OUTPUT_ARGS
  30. PCMK__OUTPUT_ARGS
  31. PCMK__OUTPUT_ARGS
  32. PCMK__OUTPUT_ARGS
  33. PCMK__OUTPUT_ARGS
  34. PCMK__OUTPUT_ARGS
  35. PCMK__OUTPUT_ARGS
  36. PCMK__OUTPUT_ARGS
  37. PCMK__OUTPUT_ARGS
  38. PCMK__OUTPUT_ARGS
  39. PCMK__OUTPUT_ARGS
  40. PCMK__OUTPUT_ARGS
  41. status_node
  42. PCMK__OUTPUT_ARGS
  43. PCMK__OUTPUT_ARGS
  44. PCMK__OUTPUT_ARGS
  45. PCMK__OUTPUT_ARGS
  46. PCMK__OUTPUT_ARGS
  47. PCMK__OUTPUT_ARGS
  48. PCMK__OUTPUT_ARGS
  49. PCMK__OUTPUT_ARGS
  50. PCMK__OUTPUT_ARGS
  51. PCMK__OUTPUT_ARGS
  52. PCMK__OUTPUT_ARGS
  53. PCMK__OUTPUT_ARGS
  54. PCMK__OUTPUT_ARGS
  55. PCMK__OUTPUT_ARGS
  56. PCMK__OUTPUT_ARGS
  57. PCMK__OUTPUT_ARGS
  58. PCMK__OUTPUT_ARGS
  59. PCMK__OUTPUT_ARGS
  60. PCMK__OUTPUT_ARGS
  61. PCMK__OUTPUT_ARGS
  62. PCMK__OUTPUT_ARGS
  63. PCMK__OUTPUT_ARGS
  64. PCMK__OUTPUT_ARGS
  65. PCMK__OUTPUT_ARGS
  66. PCMK__OUTPUT_ARGS
  67. print_resource_header
  68. PCMK__OUTPUT_ARGS
  69. PCMK__OUTPUT_ARGS
  70. PCMK__OUTPUT_ARGS
  71. PCMK__OUTPUT_ARGS
  72. PCMK__OUTPUT_ARGS
  73. PCMK__OUTPUT_ARGS
  74. PCMK__OUTPUT_ARGS
  75. PCMK__OUTPUT_ARGS
  76. pe__register_messages
  77. pe__output_node

   1 /*
   2  * Copyright 2019-2021 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 #include <crm/common/iso8601_internal.h>
  12 #include <crm/common/xml_internal.h>
  13 #include <crm/common/output.h>
  14 #include <crm/cib/util.h>
  15 #include <crm/msg_xml.h>
  16 #include <crm/pengine/internal.h>
  17 
  18 /* Never display node attributes whose name starts with one of these prefixes */
  19 #define FILTER_STR { PCMK__FAIL_COUNT_PREFIX, PCMK__LAST_FAILURE_PREFIX,   \
  20                      "shutdown", "terminate", "standby", "probe_complete", \
  21                      "#", NULL }
  22 
  23 static int
  24 compare_attribute(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
  25 {
  26     int rc;
  27 
  28     rc = strcmp((const char *)a, (const char *)b);
  29 
  30     return rc;
  31 }
  32 
  33 /*!
  34  * \internal
  35  * \brief Determine whether extended information about an attribute should be added.
  36  *
  37  * \param[in]  node           Node that ran this resource.
  38  * \param[in]  rsc_list       The list of resources for this node.
  39  * \param[in]  attrname       The attribute to find.
  40  * \param[out] expected_score The expected value for this attribute.
  41  *
  42  * \return TRUE if extended information should be printed, FALSE otherwise
  43  * \note Currently, extended information is only supported for ping/pingd
  44  *       resources, for which a message will be printed if connectivity is lost
  45  *       or degraded.
  46  */
  47 static gboolean
  48 add_extra_info(pe_node_t *node, GList *rsc_list, pe_working_set_t *data_set,
     /* [previous][next][first][last][top][bottom][index][help] */
  49                const char *attrname, int *expected_score)
  50 {
  51     GList *gIter = NULL;
  52 
  53     for (gIter = rsc_list; gIter != NULL; gIter = gIter->next) {
  54         pe_resource_t *rsc = (pe_resource_t *) gIter->data;
  55         const char *type = g_hash_table_lookup(rsc->meta, "type");
  56         const char *name = NULL;
  57         GHashTable *params = NULL;
  58 
  59         if (rsc->children != NULL) {
  60             if (add_extra_info(node, rsc->children, data_set, attrname,
  61                                expected_score)) {
  62                 return TRUE;
  63             }
  64         }
  65 
  66         if (!pcmk__strcase_any_of(type, "ping", "pingd", NULL)) {
  67             continue;
  68         }
  69 
  70         params = pe_rsc_params(rsc, node, data_set);
  71         name = g_hash_table_lookup(params, "name");
  72 
  73         if (name == NULL) {
  74             name = "pingd";
  75         }
  76 
  77         /* To identify the resource with the attribute name. */
  78         if (pcmk__str_eq(name, attrname, pcmk__str_casei)) {
  79             int host_list_num = 0;
  80             const char *hosts = g_hash_table_lookup(params, "host_list");
  81             const char *multiplier = g_hash_table_lookup(params, "multiplier");
  82             int multiplier_i;
  83 
  84             if (hosts) {
  85                 char **host_list = g_strsplit(hosts, " ", 0);
  86                 host_list_num = g_strv_length(host_list);
  87                 g_strfreev(host_list);
  88             }
  89 
  90             if ((multiplier == NULL)
  91                 || (pcmk__scan_min_int(multiplier, &multiplier_i,
  92                                        INT_MIN) != pcmk_rc_ok)) {
  93                 /* The ocf:pacemaker:ping resource agent defaults multiplier to
  94                  * 1. The agent currently does not handle invalid text, but it
  95                  * should, and this would be a reasonable choice ...
  96                  */
  97                 multiplier_i = 1;
  98             }
  99             *expected_score = host_list_num * multiplier_i;
 100 
 101             return TRUE;
 102         }
 103     }
 104     return FALSE;
 105 }
 106 
 107 static GList *
 108 filter_attr_list(GList *attr_list, char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110     int i;
 111     const char *filt_str[] = FILTER_STR;
 112 
 113     CRM_CHECK(name != NULL, return attr_list);
 114 
 115     /* filtering automatic attributes */
 116     for (i = 0; filt_str[i] != NULL; i++) {
 117         if (g_str_has_prefix(name, filt_str[i])) {
 118             return attr_list;
 119         }
 120     }
 121 
 122     return g_list_insert_sorted(attr_list, name, compare_attribute);
 123 }
 124 
 125 static GList *
 126 get_operation_list(xmlNode *rsc_entry) {
     /* [previous][next][first][last][top][bottom][index][help] */
 127     GList *op_list = NULL;
 128     xmlNode *rsc_op = NULL;
 129 
 130     for (rsc_op = pcmk__xe_first_child(rsc_entry); rsc_op != NULL;
 131          rsc_op = pcmk__xe_next(rsc_op)) {
 132         const char *task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
 133         const char *interval_ms_s = crm_element_value(rsc_op,
 134                                                       XML_LRM_ATTR_INTERVAL_MS);
 135         const char *op_rc = crm_element_value(rsc_op, XML_LRM_ATTR_RC);
 136         int op_rc_i;
 137 
 138         pcmk__scan_min_int(op_rc, &op_rc_i, 0);
 139 
 140         /* Display 0-interval monitors as "probe" */
 141         if (pcmk__str_eq(task, CRMD_ACTION_STATUS, pcmk__str_casei)
 142             && pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches | pcmk__str_casei)) {
 143             task = "probe";
 144         }
 145 
 146         /* Ignore notifies and some probes */
 147         if (pcmk__str_eq(task, CRMD_ACTION_NOTIFY, pcmk__str_casei) || (pcmk__str_eq(task, "probe", pcmk__str_casei) && (op_rc_i == 7))) {
 148             continue;
 149         }
 150 
 151         if (pcmk__str_eq((const char *)rsc_op->name, XML_LRM_TAG_RSC_OP, pcmk__str_none)) {
 152             op_list = g_list_append(op_list, rsc_op);
 153         }
 154     }
 155 
 156     op_list = g_list_sort(op_list, sort_op_by_callid);
 157     return op_list;
 158 }
 159 
 160 static void
 161 add_dump_node(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 162 {
 163     xmlNodePtr node = user_data;
 164     pcmk_create_xml_text_node(node, (const char *) key, (const char *) value);
 165 }
 166 
 167 static void
 168 append_dump_text(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 169 {
 170     char **dump_text = user_data;
 171     char *new_text = crm_strdup_printf("%s %s=%s",
 172                                        *dump_text, (char *)key, (char *)value);
 173 
 174     free(*dump_text);
 175     *dump_text = new_text;
 176 }
 177 
 178 static char *
 179 failed_action_string(xmlNodePtr xml_op) {
     /* [previous][next][first][last][top][bottom][index][help] */
 180     const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
 181     int rc;
 182     int status;
 183     const char *exit_reason = crm_element_value(xml_op, XML_LRM_ATTR_EXIT_REASON);
 184 
 185     time_t last_change = 0;
 186 
 187     pcmk__scan_min_int(crm_element_value(xml_op, XML_LRM_ATTR_RC), &rc, 0);
 188     pcmk__scan_min_int(crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS),
 189                        &status, 0);
 190 
 191     if (crm_element_value_epoch(xml_op, XML_RSC_OP_LAST_CHANGE,
 192                                 &last_change) == pcmk_ok) {
 193         crm_time_t *crm_when = crm_time_new(NULL);
 194         char *time_s = NULL;
 195         char *buf = NULL;
 196 
 197         crm_time_set_timet(crm_when, &last_change);
 198         time_s = crm_time_as_string(crm_when, crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
 199 
 200         buf = crm_strdup_printf("%s on %s '%s' (%d): call=%s, status='%s', "
 201                                 "exitreason='%s', " XML_RSC_OP_LAST_CHANGE
 202                                 "='%s', queued=%sms, exec=%sms",
 203                                 op_key ? op_key : ID(xml_op),
 204                                 crm_element_value(xml_op, XML_ATTR_UNAME),
 205                                 services_ocf_exitcode_str(rc), rc,
 206                                 crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
 207                                 services_lrm_status_str(status),
 208                                 exit_reason ? exit_reason : "none",
 209                                 time_s,
 210                                 crm_element_value(xml_op, XML_RSC_OP_T_QUEUE),
 211                                 crm_element_value(xml_op, XML_RSC_OP_T_EXEC));
 212 
 213         crm_time_free(crm_when);
 214         free(time_s);
 215         return buf;
 216     } else {
 217         return crm_strdup_printf("%s on %s '%s' (%d): call=%s, status=%s, exitreason='%s'",
 218                                  op_key ? op_key : ID(xml_op),
 219                                  crm_element_value(xml_op, XML_ATTR_UNAME),
 220                                  services_ocf_exitcode_str(rc), rc,
 221                                  crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
 222                                  services_lrm_status_str(status),
 223                                  exit_reason ? exit_reason : "none");
 224     }
 225 }
 226 
 227 static const char *
 228 get_cluster_stack(pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 229 {
 230     xmlNode *stack = get_xpath_object("//nvpair[@name='cluster-infrastructure']",
 231                                       data_set->input, LOG_DEBUG);
 232     return stack? crm_element_value(stack, XML_NVPAIR_ATTR_VALUE) : "unknown";
 233 }
 234 
 235 static char *
 236 last_changed_string(const char *last_written, const char *user,
     /* [previous][next][first][last][top][bottom][index][help] */
 237                     const char *client, const char *origin) {
 238     if (last_written != NULL || user != NULL || client != NULL || origin != NULL) {
 239         return crm_strdup_printf("%s%s%s%s%s%s%s",
 240                                  last_written ? last_written : "",
 241                                  user ? " by " : "",
 242                                  user ? user : "",
 243                                  client ? " via " : "",
 244                                  client ? client : "",
 245                                  origin ? " on " : "",
 246                                  origin ? origin : "");
 247     } else {
 248         return strdup("");
 249     }
 250 }
 251 
 252 static char *
 253 op_history_string(xmlNode *xml_op, const char *task, const char *interval_ms_s,
     /* [previous][next][first][last][top][bottom][index][help] */
 254                   int rc, gboolean print_timing) {
 255     const char *call = crm_element_value(xml_op, XML_LRM_ATTR_CALLID);
 256     char *interval_str = NULL;
 257     char *buf = NULL;
 258 
 259     if (interval_ms_s && !pcmk__str_eq(interval_ms_s, "0", pcmk__str_casei)) {
 260         char *pair = pcmk__format_nvpair("interval", interval_ms_s, "ms");
 261         interval_str = crm_strdup_printf(" %s", pair);
 262         free(pair);
 263     }
 264 
 265     if (print_timing) {
 266         char *last_change_str = NULL;
 267         char *exec_str = NULL;
 268         char *queue_str = NULL;
 269 
 270         const char *value = NULL;
 271 
 272         time_t epoch = 0;
 273 
 274         if ((crm_element_value_epoch(xml_op, XML_RSC_OP_LAST_CHANGE, &epoch) == pcmk_ok)
 275             && (epoch > 0)) {
 276             char *time = pcmk__format_named_time(XML_RSC_OP_LAST_CHANGE, epoch);
 277 
 278             last_change_str = crm_strdup_printf(" %s", time);
 279             free(time);
 280         }
 281 
 282         value = crm_element_value(xml_op, XML_RSC_OP_T_EXEC);
 283         if (value) {
 284             char *pair = pcmk__format_nvpair(XML_RSC_OP_T_EXEC, value, "ms");
 285             exec_str = crm_strdup_printf(" %s", pair);
 286             free(pair);
 287         }
 288 
 289         value = crm_element_value(xml_op, XML_RSC_OP_T_QUEUE);
 290         if (value) {
 291             char *pair = pcmk__format_nvpair(XML_RSC_OP_T_QUEUE, value, "ms");
 292             queue_str = crm_strdup_printf(" %s", pair);
 293             free(pair);
 294         }
 295 
 296         buf = crm_strdup_printf("(%s) %s:%s%s%s%s rc=%d (%s)", call, task,
 297                                 interval_str ? interval_str : "",
 298                                 last_change_str ? last_change_str : "",
 299                                 exec_str ? exec_str : "",
 300                                 queue_str ? queue_str : "",
 301                                 rc, services_ocf_exitcode_str(rc));
 302 
 303         if (last_change_str) {
 304             free(last_change_str);
 305         }
 306 
 307         if (exec_str) {
 308             free(exec_str);
 309         }
 310 
 311         if (queue_str) {
 312             free(queue_str);
 313         }
 314     } else {
 315         buf = crm_strdup_printf("(%s) %s%s%s", call, task,
 316                                 interval_str ? ":" : "",
 317                                 interval_str ? interval_str : "");
 318     }
 319 
 320     if (interval_str) {
 321         free(interval_str);
 322     }
 323 
 324     return buf;
 325 }
 326 
 327 static char *
 328 resource_history_string(pe_resource_t *rsc, const char *rsc_id, gboolean all,
     /* [previous][next][first][last][top][bottom][index][help] */
 329                         int failcount, time_t last_failure) {
 330     char *buf = NULL;
 331 
 332     if (rsc == NULL) {
 333         buf = crm_strdup_printf("%s: orphan", rsc_id);
 334     } else if (all || failcount || last_failure > 0) {
 335         char *failcount_s = NULL;
 336         char *lastfail_s = NULL;
 337 
 338         if (failcount > 0) {
 339             failcount_s = crm_strdup_printf(" %s=%d", PCMK__FAIL_COUNT_PREFIX,
 340                                             failcount);
 341         } else {
 342             failcount_s = strdup("");
 343         }
 344         if (last_failure > 0) {
 345             lastfail_s = crm_strdup_printf(" %s='%s'",
 346                                            PCMK__LAST_FAILURE_PREFIX,
 347                                            pcmk__epoch2str(&last_failure));
 348         }
 349 
 350         buf = crm_strdup_printf("%s: migration-threshold=%d%s%s",
 351                                 rsc_id, rsc->migration_threshold, failcount_s,
 352                                 lastfail_s? lastfail_s : "");
 353         free(failcount_s);
 354         free(lastfail_s);
 355     } else {
 356         buf = crm_strdup_printf("%s:", rsc_id);
 357     }
 358 
 359     return buf;
 360 }
 361 
 362 PCMK__OUTPUT_ARGS("cluster-summary", "pe_working_set_t *", "unsigned int", "unsigned int")
     /* [previous][next][first][last][top][bottom][index][help] */
 363 static int
 364 cluster_summary(pcmk__output_t *out, va_list args) {
 365     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
 366     unsigned int section_opts = va_arg(args, unsigned int);
 367     unsigned int show_opts = va_arg(args, unsigned int);
 368 
 369     int rc = pcmk_rc_no_output;
 370     const char *stack_s = get_cluster_stack(data_set);
 371 
 372     if (pcmk_is_set(section_opts, pcmk_section_stack)) {
 373         PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
 374         out->message(out, "cluster-stack", stack_s);
 375     }
 376 
 377     /* Always print DC if none, even if not requested */
 378     if (data_set->dc_node == NULL || pcmk_is_set(section_opts, pcmk_section_dc)) {
 379         xmlNode *dc_version = get_xpath_object("//nvpair[@name='dc-version']",
 380                                                data_set->input, LOG_DEBUG);
 381         const char *dc_version_s = dc_version?
 382                                    crm_element_value(dc_version, XML_NVPAIR_ATTR_VALUE)
 383                                    : NULL;
 384         const char *quorum = crm_element_value(data_set->input, XML_ATTR_HAVE_QUORUM);
 385         char *dc_name = data_set->dc_node ? pe__node_display_name(data_set->dc_node, pcmk_is_set(show_opts, pcmk_show_node_id)) : NULL;
 386 
 387         PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
 388         out->message(out, "cluster-dc", data_set->dc_node, quorum, dc_version_s, dc_name);
 389         free(dc_name);
 390     }
 391 
 392     if (pcmk_is_set(section_opts, pcmk_section_times)) {
 393         const char *last_written = crm_element_value(data_set->input, XML_CIB_ATTR_WRITTEN);
 394         const char *user = crm_element_value(data_set->input, XML_ATTR_UPDATE_USER);
 395         const char *client = crm_element_value(data_set->input, XML_ATTR_UPDATE_CLIENT);
 396         const char *origin = crm_element_value(data_set->input, XML_ATTR_UPDATE_ORIG);
 397 
 398         PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
 399         out->message(out, "cluster-times", last_written, user, client, origin);
 400     }
 401 
 402     if (pcmk_is_set(section_opts, pcmk_section_counts)) {
 403         PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
 404         out->message(out, "cluster-counts", g_list_length(data_set->nodes),
 405                      data_set->ninstances, data_set->disabled_resources,
 406                      data_set->blocked_resources);
 407     }
 408 
 409     if (pcmk_is_set(section_opts, pcmk_section_options)) {
 410         PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
 411         out->message(out, "cluster-options", data_set);
 412     }
 413 
 414     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 415 
 416     if (out->message(out, "maint-mode", data_set->flags) == pcmk_rc_ok) {
 417         rc = pcmk_rc_ok;
 418     }
 419 
 420     return rc;
 421 }
 422 
 423 PCMK__OUTPUT_ARGS("cluster-summary", "pe_working_set_t *", "unsigned int", "unsigned int")
     /* [previous][next][first][last][top][bottom][index][help] */
 424 static int
 425 cluster_summary_html(pcmk__output_t *out, va_list args) {
 426     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
 427     unsigned int section_opts = va_arg(args, unsigned int);
 428     unsigned int show_opts = va_arg(args, unsigned int);
 429 
 430     int rc = pcmk_rc_no_output;
 431     const char *stack_s = get_cluster_stack(data_set);
 432 
 433     if (pcmk_is_set(section_opts, pcmk_section_stack)) {
 434         PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
 435         out->message(out, "cluster-stack", stack_s);
 436     }
 437 
 438     /* Always print DC if none, even if not requested */
 439     if (data_set->dc_node == NULL || pcmk_is_set(section_opts, pcmk_section_dc)) {
 440         xmlNode *dc_version = get_xpath_object("//nvpair[@name='dc-version']",
 441                                                data_set->input, LOG_DEBUG);
 442         const char *dc_version_s = dc_version?
 443                                    crm_element_value(dc_version, XML_NVPAIR_ATTR_VALUE)
 444                                    : NULL;
 445         const char *quorum = crm_element_value(data_set->input, XML_ATTR_HAVE_QUORUM);
 446         char *dc_name = data_set->dc_node ? pe__node_display_name(data_set->dc_node, pcmk_is_set(show_opts, pcmk_show_node_id)) : NULL;
 447 
 448         PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
 449         out->message(out, "cluster-dc", data_set->dc_node, quorum, dc_version_s, dc_name);
 450         free(dc_name);
 451     }
 452 
 453     if (pcmk_is_set(section_opts, pcmk_section_times)) {
 454         const char *last_written = crm_element_value(data_set->input, XML_CIB_ATTR_WRITTEN);
 455         const char *user = crm_element_value(data_set->input, XML_ATTR_UPDATE_USER);
 456         const char *client = crm_element_value(data_set->input, XML_ATTR_UPDATE_CLIENT);
 457         const char *origin = crm_element_value(data_set->input, XML_ATTR_UPDATE_ORIG);
 458 
 459         PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
 460         out->message(out, "cluster-times", last_written, user, client, origin);
 461     }
 462 
 463     if (pcmk_is_set(section_opts, pcmk_section_counts)) {
 464         PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Cluster Summary");
 465         out->message(out, "cluster-counts", g_list_length(data_set->nodes),
 466                      data_set->ninstances, data_set->disabled_resources,
 467                      data_set->blocked_resources);
 468     }
 469 
 470     if (pcmk_is_set(section_opts, pcmk_section_options)) {
 471         /* Kind of a hack - close the list we may have opened earlier in this
 472          * function so we can put all the options into their own list.  We
 473          * only want to do this on HTML output, though.
 474          */
 475         PCMK__OUTPUT_LIST_FOOTER(out, rc);
 476 
 477         out->begin_list(out, NULL, NULL, "Config Options");
 478         out->message(out, "cluster-options", data_set);
 479     }
 480 
 481     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 482 
 483     if (out->message(out, "maint-mode", data_set->flags) == pcmk_rc_ok) {
 484         rc = pcmk_rc_ok;
 485     }
 486 
 487     return rc;
 488 }
 489 
 490 char *
 491 pe__node_display_name(pe_node_t *node, bool print_detail)
     /* [previous][next][first][last][top][bottom][index][help] */
 492 {
 493     char *node_name;
 494     const char *node_host = NULL;
 495     const char *node_id = NULL;
 496     int name_len;
 497 
 498     CRM_ASSERT((node != NULL) && (node->details != NULL) && (node->details->uname != NULL));
 499 
 500     /* Host is displayed only if this is a guest node */
 501     if (pe__is_guest_node(node)) {
 502         pe_node_t *host_node = pe__current_node(node->details->remote_rsc);
 503 
 504         if (host_node && host_node->details) {
 505             node_host = host_node->details->uname;
 506         }
 507         if (node_host == NULL) {
 508             node_host = ""; /* so we at least get "uname@" to indicate guest */
 509         }
 510     }
 511 
 512     /* Node ID is displayed if different from uname and detail is requested */
 513     if (print_detail && !pcmk__str_eq(node->details->uname, node->details->id, pcmk__str_casei)) {
 514         node_id = node->details->id;
 515     }
 516 
 517     /* Determine name length */
 518     name_len = strlen(node->details->uname) + 1;
 519     if (node_host) {
 520         name_len += strlen(node_host) + 1; /* "@node_host" */
 521     }
 522     if (node_id) {
 523         name_len += strlen(node_id) + 3; /* + " (node_id)" */
 524     }
 525 
 526     /* Allocate and populate display name */
 527     node_name = malloc(name_len);
 528     CRM_ASSERT(node_name != NULL);
 529     strcpy(node_name, node->details->uname);
 530     if (node_host) {
 531         strcat(node_name, "@");
 532         strcat(node_name, node_host);
 533     }
 534     if (node_id) {
 535         strcat(node_name, " (");
 536         strcat(node_name, node_id);
 537         strcat(node_name, ")");
 538     }
 539     return node_name;
 540 }
 541 
 542 int
 543 pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name
     /* [previous][next][first][last][top][bottom][index][help] */
 544                          , size_t pairs_count, ...)
 545 {
 546     xmlNodePtr xml_node = NULL;
 547     va_list args;
 548 
 549     CRM_ASSERT(tag_name != NULL);
 550 
 551     xml_node = pcmk__output_xml_peek_parent(out);
 552     CRM_ASSERT(xml_node != NULL);
 553     xml_node = is_list
 554         ? create_xml_node(xml_node, tag_name)
 555         : xmlNewChild(xml_node, NULL, (pcmkXmlStr) tag_name, NULL);
 556 
 557     va_start(args, pairs_count);
 558     while(pairs_count--) {
 559         const char *param_name = va_arg(args, const char *);
 560         const char *param_value = va_arg(args, const char *);
 561         if (param_name && param_value) {
 562             crm_xml_add(xml_node, param_name, param_value);
 563         }
 564     };
 565     va_end(args);
 566 
 567     if (is_list) {
 568         pcmk__output_xml_push_parent(out, xml_node);
 569     }
 570     return pcmk_rc_ok;
 571 }
 572 
 573 static const char *
 574 role_desc(enum rsc_role_e role)
     /* [previous][next][first][last][top][bottom][index][help] */
 575 {
 576     if (role == RSC_ROLE_PROMOTED) {
 577 #ifdef PCMK__COMPAT_2_0
 578         return "as " RSC_ROLE_PROMOTED_LEGACY_S " ";
 579 #else
 580         return "in " RSC_ROLE_PROMOTED_S " role ";
 581 #endif
 582     }
 583     return "";
 584 }
 585 
 586 PCMK__OUTPUT_ARGS("ban", "pe_node_t *", "pe__location_t *", "unsigned int")
     /* [previous][next][first][last][top][bottom][index][help] */
 587 static int
 588 ban_html(pcmk__output_t *out, va_list args) {
 589     pe_node_t *pe_node = va_arg(args, pe_node_t *);
 590     pe__location_t *location = va_arg(args, pe__location_t *);
 591     unsigned int show_opts = va_arg(args, unsigned int);
 592 
 593     char *node_name = pe__node_display_name(pe_node,
 594                                             pcmk_is_set(show_opts, pcmk_show_node_id));
 595     char *buf = crm_strdup_printf("%s\tprevents %s from running %son %s",
 596                                   location->id, location->rsc_lh->id,
 597                                   role_desc(location->role_filter), node_name);
 598 
 599     pcmk__output_create_html_node(out, "li", NULL, NULL, buf);
 600 
 601     free(node_name);
 602     free(buf);
 603     return pcmk_rc_ok;
 604 }
 605 
 606 PCMK__OUTPUT_ARGS("ban", "pe_node_t *", "pe__location_t *", "unsigned int")
     /* [previous][next][first][last][top][bottom][index][help] */
 607 static int
 608 ban_text(pcmk__output_t *out, va_list args) {
 609     pe_node_t *pe_node = va_arg(args, pe_node_t *);
 610     pe__location_t *location = va_arg(args, pe__location_t *);
 611     unsigned int show_opts = va_arg(args, unsigned int);
 612 
 613     char *node_name = pe__node_display_name(pe_node,
 614                                             pcmk_is_set(show_opts, pcmk_show_node_id));
 615     out->list_item(out, NULL, "%s\tprevents %s from running %son %s",
 616                    location->id, location->rsc_lh->id,
 617                    role_desc(location->role_filter), node_name);
 618 
 619     free(node_name);
 620     return pcmk_rc_ok;
 621 }
 622 
 623 PCMK__OUTPUT_ARGS("ban", "pe_node_t *", "pe__location_t *", "unsigned int")
     /* [previous][next][first][last][top][bottom][index][help] */
 624 static int
 625 ban_xml(pcmk__output_t *out, va_list args) {
 626     pe_node_t *pe_node = va_arg(args, pe_node_t *);
 627     pe__location_t *location = va_arg(args, pe__location_t *);
 628     unsigned int show_opts G_GNUC_UNUSED = va_arg(args, unsigned int);
 629 
 630     const char *promoted_only = pcmk__btoa(location->role_filter == RSC_ROLE_PROMOTED);
 631     char *weight_s = pcmk__itoa(pe_node->weight);
 632 
 633     pcmk__output_create_xml_node(out, "ban",
 634                                  "id", location->id,
 635                                  "resource", location->rsc_lh->id,
 636                                  "node", pe_node->details->uname,
 637                                  "weight", weight_s,
 638                                  "promoted-only", promoted_only,
 639                                  /* This is a deprecated alias for
 640                                   * promoted_only. Removing it will break
 641                                   * backward compatibility of the API schema,
 642                                   * which will require an API schema major
 643                                   * version bump.
 644                                   */
 645                                  "master_only", promoted_only,
 646                                  NULL);
 647 
 648     free(weight_s);
 649     return pcmk_rc_ok;
 650 }
 651 
 652 PCMK__OUTPUT_ARGS("ban-list", "pe_working_set_t *", "const char *", "GList *",
     /* [previous][next][first][last][top][bottom][index][help] */
 653                   "unsigned int", "gboolean")
 654 static int
 655 ban_list(pcmk__output_t *out, va_list args) {
 656     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
 657     const char *prefix = va_arg(args, const char *);
 658     GList *only_rsc = va_arg(args, GList *);
 659     unsigned int show_opts = va_arg(args, unsigned int);
 660     gboolean print_spacer = va_arg(args, gboolean);
 661 
 662     GList *gIter, *gIter2;
 663     int rc = pcmk_rc_no_output;
 664 
 665     /* Print each ban */
 666     for (gIter = data_set->placement_constraints; gIter != NULL; gIter = gIter->next) {
 667         pe__location_t *location = gIter->data;
 668 
 669         if (prefix != NULL && !g_str_has_prefix(location->id, prefix)) {
 670             continue;
 671         }
 672 
 673         if (!pcmk__str_in_list(only_rsc, rsc_printable_id(location->rsc_lh), pcmk__str_none) &&
 674             !pcmk__str_in_list(only_rsc, rsc_printable_id(uber_parent(location->rsc_lh)), pcmk__str_none)) {
 675             continue;
 676         }
 677 
 678         for (gIter2 = location->node_list_rh; gIter2 != NULL; gIter2 = gIter2->next) {
 679             pe_node_t *node = (pe_node_t *) gIter2->data;
 680 
 681             if (node->weight < 0) {
 682                 PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Negative Location Constraints");
 683                 out->message(out, "ban", node, location, show_opts);
 684             }
 685         }
 686     }
 687 
 688     PCMK__OUTPUT_LIST_FOOTER(out, rc);
 689     return rc;
 690 }
 691 
 692 PCMK__OUTPUT_ARGS("cluster-counts", "unsigned int", "int", "int", "int")
     /* [previous][next][first][last][top][bottom][index][help] */
 693 static int
 694 cluster_counts_html(pcmk__output_t *out, va_list args) {
 695     unsigned int nnodes = va_arg(args, unsigned int);
 696     int nresources = va_arg(args, int);
 697     int ndisabled = va_arg(args, int);
 698     int nblocked = va_arg(args, int);
 699 
 700     xmlNodePtr nodes_node = pcmk__output_create_xml_node(out, "li", NULL);
 701     xmlNodePtr resources_node = pcmk__output_create_xml_node(out, "li", NULL);
 702 
 703     char *nnodes_str = crm_strdup_printf("%d node%s configured",
 704                                          nnodes, pcmk__plural_s(nnodes));
 705 
 706     pcmk_create_html_node(nodes_node, "span", NULL, NULL, nnodes_str);
 707     free(nnodes_str);
 708 
 709     if (ndisabled && nblocked) {
 710         char *s = crm_strdup_printf("%d resource instance%s configured (%d ",
 711                                     nresources, pcmk__plural_s(nresources),
 712                                     ndisabled);
 713         pcmk_create_html_node(resources_node, "span", NULL, NULL, s);
 714         free(s);
 715 
 716         pcmk_create_html_node(resources_node, "span", NULL, "bold", "DISABLED");
 717 
 718         s = crm_strdup_printf(", %d ", nblocked);
 719         pcmk_create_html_node(resources_node, "span", NULL, NULL, s);
 720         free(s);
 721 
 722         pcmk_create_html_node(resources_node, "span", NULL, "bold", "BLOCKED");
 723         pcmk_create_html_node(resources_node, "span", NULL, NULL,
 724                               " from further action due to failure)");
 725     } else if (ndisabled && !nblocked) {
 726         char *s = crm_strdup_printf("%d resource instance%s configured (%d ",
 727                                     nresources, pcmk__plural_s(nresources),
 728                                     ndisabled);
 729         pcmk_create_html_node(resources_node, "span", NULL, NULL, s);
 730         free(s);
 731 
 732         pcmk_create_html_node(resources_node, "span", NULL, "bold", "DISABLED");
 733         pcmk_create_html_node(resources_node, "span", NULL, NULL, ")");
 734     } else if (!ndisabled && nblocked) {
 735         char *s = crm_strdup_printf("%d resource instance%s configured (%d ",
 736                                     nresources, pcmk__plural_s(nresources),
 737                                     nblocked);
 738         pcmk_create_html_node(resources_node, "span", NULL, NULL, s);
 739         free(s);
 740 
 741         pcmk_create_html_node(resources_node, "span", NULL, "bold", "BLOCKED");
 742         pcmk_create_html_node(resources_node, "span", NULL, NULL,
 743                               " from further action due to failure)");
 744     } else {
 745         char *s = crm_strdup_printf("%d resource instance%s configured",
 746                                     nresources, pcmk__plural_s(nresources));
 747         pcmk_create_html_node(resources_node, "span", NULL, NULL, s);
 748         free(s);
 749     }
 750 
 751     return pcmk_rc_ok;
 752 }
 753 
 754 PCMK__OUTPUT_ARGS("cluster-counts", "unsigned int", "int", "int", "int")
     /* [previous][next][first][last][top][bottom][index][help] */
 755 static int
 756 cluster_counts_text(pcmk__output_t *out, va_list args) {
 757     unsigned int nnodes = va_arg(args, unsigned int);
 758     int nresources = va_arg(args, int);
 759     int ndisabled = va_arg(args, int);
 760     int nblocked = va_arg(args, int);
 761 
 762     out->list_item(out, NULL, "%d node%s configured",
 763                    nnodes, pcmk__plural_s(nnodes));
 764 
 765     if (ndisabled && nblocked) {
 766         out->list_item(out, NULL, "%d resource instance%s configured "
 767                                   "(%d DISABLED, %d BLOCKED from "
 768                                   "further action due to failure)",
 769                        nresources, pcmk__plural_s(nresources), ndisabled,
 770                        nblocked);
 771     } else if (ndisabled && !nblocked) {
 772         out->list_item(out, NULL, "%d resource instance%s configured "
 773                                   "(%d DISABLED)",
 774                        nresources, pcmk__plural_s(nresources), ndisabled);
 775     } else if (!ndisabled && nblocked) {
 776         out->list_item(out, NULL, "%d resource instance%s configured "
 777                                   "(%d BLOCKED from further action "
 778                                   "due to failure)",
 779                        nresources, pcmk__plural_s(nresources), nblocked);
 780     } else {
 781         out->list_item(out, NULL, "%d resource instance%s configured",
 782                        nresources, pcmk__plural_s(nresources));
 783     }
 784 
 785     return pcmk_rc_ok;
 786 }
 787 
 788 PCMK__OUTPUT_ARGS("cluster-counts", "unsigned int", "int", "int", "int")
     /* [previous][next][first][last][top][bottom][index][help] */
 789 static int
 790 cluster_counts_xml(pcmk__output_t *out, va_list args) {
 791     unsigned int nnodes = va_arg(args, unsigned int);
 792     int nresources = va_arg(args, int);
 793     int ndisabled = va_arg(args, int);
 794     int nblocked = va_arg(args, int);
 795 
 796     xmlNodePtr nodes_node = pcmk__output_create_xml_node(out, "nodes_configured", NULL);
 797     xmlNodePtr resources_node = pcmk__output_create_xml_node(out, "resources_configured", NULL);
 798 
 799     char *s = pcmk__itoa(nnodes);
 800     crm_xml_add(nodes_node, "number", s);
 801     free(s);
 802 
 803     s = pcmk__itoa(nresources);
 804     crm_xml_add(resources_node, "number", s);
 805     free(s);
 806 
 807     s = pcmk__itoa(ndisabled);
 808     crm_xml_add(resources_node, "disabled", s);
 809     free(s);
 810 
 811     s = pcmk__itoa(nblocked);
 812     crm_xml_add(resources_node, "blocked", s);
 813     free(s);
 814 
 815     return pcmk_rc_ok;
 816 }
 817 
 818 PCMK__OUTPUT_ARGS("cluster-dc", "pe_node_t *", "const char *", "const char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 819 static int
 820 cluster_dc_html(pcmk__output_t *out, va_list args) {
 821     pe_node_t *dc = va_arg(args, pe_node_t *);
 822     const char *quorum = va_arg(args, const char *);
 823     const char *dc_version_s = va_arg(args, const char *);
 824     char *dc_name = va_arg(args, char *);
 825 
 826     xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
 827 
 828     pcmk_create_html_node(node, "span", NULL, "bold", "Current DC: ");
 829 
 830     if (dc) {
 831         if (crm_is_true(quorum)) {
 832             char *buf = crm_strdup_printf("%s (version %s) - partition with quorum",
 833                                           dc_name, dc_version_s ? dc_version_s : "unknown");
 834             pcmk_create_html_node(node, "span", NULL, NULL, buf);
 835             free(buf);
 836         } else {
 837             char *buf = crm_strdup_printf("%s (version %s) - partition",
 838                                           dc_name, dc_version_s ? dc_version_s : "unknown");
 839             pcmk_create_html_node(node, "span", NULL, NULL, buf);
 840             free(buf);
 841 
 842             pcmk_create_html_node(node, "span", NULL, "warning", "WITHOUT");
 843             pcmk_create_html_node(node, "span", NULL, NULL, "quorum");
 844         }
 845     } else {
 846         pcmk_create_html_node(node ,"span", NULL, "warning", "NONE");
 847     }
 848 
 849     return pcmk_rc_ok;
 850 }
 851 
 852 PCMK__OUTPUT_ARGS("cluster-dc", "pe_node_t *", "const char *", "const char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 853 static int
 854 cluster_dc_text(pcmk__output_t *out, va_list args) {
 855     pe_node_t *dc = va_arg(args, pe_node_t *);
 856     const char *quorum = va_arg(args, const char *);
 857     const char *dc_version_s = va_arg(args, const char *);
 858     char *dc_name = va_arg(args, char *);
 859 
 860     if (dc) {
 861         out->list_item(out, "Current DC", "%s (version %s) - partition %s quorum",
 862                        dc_name, dc_version_s ? dc_version_s : "unknown",
 863                        crm_is_true(quorum) ? "with" : "WITHOUT");
 864     } else {
 865         out->list_item(out, "Current DC", "NONE");
 866     }
 867 
 868     return pcmk_rc_ok;
 869 }
 870 
 871 PCMK__OUTPUT_ARGS("cluster-dc", "pe_node_t *", "const char *", "const char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
 872 static int
 873 cluster_dc_xml(pcmk__output_t *out, va_list args) {
 874     pe_node_t *dc = va_arg(args, pe_node_t *);
 875     const char *quorum = va_arg(args, const char *);
 876     const char *dc_version_s = va_arg(args, const char *);
 877     char *dc_name G_GNUC_UNUSED = va_arg(args, char *);
 878 
 879     if (dc) {
 880         pcmk__output_create_xml_node(out, "current_dc",
 881                                      "present", "true",
 882                                      "version", dc_version_s ? dc_version_s : "",
 883                                      "name", dc->details->uname,
 884                                      "id", dc->details->id,
 885                                      "with_quorum", pcmk__btoa(crm_is_true(quorum)),
 886                                      NULL);
 887     } else {
 888         pcmk__output_create_xml_node(out, "current_dc",
 889                                      "present", "false",
 890                                      NULL);
 891     }
 892 
 893     return pcmk_rc_ok;
 894 }
 895 
 896 PCMK__OUTPUT_ARGS("maint-mode", "unsigned long long int")
     /* [previous][next][first][last][top][bottom][index][help] */
 897 static int
 898 cluster_maint_mode_text(pcmk__output_t *out, va_list args) {
 899     unsigned long long flags = va_arg(args, unsigned long long);
 900 
 901     if (pcmk_is_set(flags, pe_flag_maintenance_mode)) {
 902         pcmk__formatted_printf(out, "\n              *** Resource management is DISABLED ***\n");
 903         pcmk__formatted_printf(out, "  The cluster will not attempt to start, stop or recover services\n");
 904         return pcmk_rc_ok;
 905     } else if (pcmk_is_set(flags, pe_flag_stop_everything)) {
 906         pcmk__formatted_printf(out, "\n    *** Resource management is DISABLED ***\n");
 907         pcmk__formatted_printf(out, "  The cluster will keep all resources stopped\n");
 908         return pcmk_rc_ok;
 909     } else {
 910         return pcmk_rc_no_output;
 911     }
 912 }
 913 
 914 PCMK__OUTPUT_ARGS("cluster-options", "pe_working_set_t *")
     /* [previous][next][first][last][top][bottom][index][help] */
 915 static int
 916 cluster_options_html(pcmk__output_t *out, va_list args) {
 917     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
 918 
 919     out->list_item(out, NULL, "STONITH of failed nodes %s",
 920                    pcmk_is_set(data_set->flags, pe_flag_stonith_enabled) ? "enabled" : "disabled");
 921 
 922     out->list_item(out, NULL, "Cluster is %s",
 923                    pcmk_is_set(data_set->flags, pe_flag_symmetric_cluster) ? "symmetric" : "asymmetric");
 924 
 925     switch (data_set->no_quorum_policy) {
 926         case no_quorum_freeze:
 927             out->list_item(out, NULL, "No quorum policy: Freeze resources");
 928             break;
 929 
 930         case no_quorum_stop:
 931             out->list_item(out, NULL, "No quorum policy: Stop ALL resources");
 932             break;
 933 
 934         case no_quorum_demote:
 935             out->list_item(out, NULL, "No quorum policy: Demote promotable "
 936                            "resources and stop all other resources");
 937             break;
 938 
 939         case no_quorum_ignore:
 940             out->list_item(out, NULL, "No quorum policy: Ignore");
 941             break;
 942 
 943         case no_quorum_suicide:
 944             out->list_item(out, NULL, "No quorum policy: Suicide");
 945             break;
 946     }
 947 
 948     if (pcmk_is_set(data_set->flags, pe_flag_maintenance_mode)) {
 949         xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
 950 
 951         pcmk_create_html_node(node, "span", NULL, NULL, "Resource management: ");
 952         pcmk_create_html_node(node, "span", NULL, "bold", "DISABLED");
 953         pcmk_create_html_node(node, "span", NULL, NULL,
 954                               " (the cluster will not attempt to start, stop, or recover services)");
 955     } else if (pcmk_is_set(data_set->flags, pe_flag_stop_everything)) {
 956         xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
 957 
 958         pcmk_create_html_node(node, "span", NULL, NULL, "Resource management: ");
 959         pcmk_create_html_node(node, "span", NULL, "bold", "STOPPED");
 960         pcmk_create_html_node(node, "span", NULL, NULL,
 961                               " (the cluster will keep all resources stopped)");
 962     } else {
 963         out->list_item(out, NULL, "Resource management: enabled");
 964     }
 965 
 966     return pcmk_rc_ok;
 967 }
 968 
 969 PCMK__OUTPUT_ARGS("cluster-options", "pe_working_set_t *")
     /* [previous][next][first][last][top][bottom][index][help] */
 970 static int
 971 cluster_options_log(pcmk__output_t *out, va_list args) {
 972     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
 973 
 974     if (pcmk_is_set(data_set->flags, pe_flag_maintenance_mode)) {
 975         return out->info(out, "Resource management is DISABLED.  The cluster will not attempt to start, stop or recover services.");
 976     } else if (pcmk_is_set(data_set->flags, pe_flag_stop_everything)) {
 977         return out->info(out, "Resource management is DISABLED.  The cluster has stopped all resources.");
 978     } else {
 979         return pcmk_rc_no_output;
 980     }
 981 }
 982 
 983 PCMK__OUTPUT_ARGS("cluster-options", "pe_working_set_t *")
     /* [previous][next][first][last][top][bottom][index][help] */
 984 static int
 985 cluster_options_text(pcmk__output_t *out, va_list args) {
 986     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
 987 
 988     out->list_item(out, NULL, "STONITH of failed nodes %s",
 989                    pcmk_is_set(data_set->flags, pe_flag_stonith_enabled) ? "enabled" : "disabled");
 990 
 991     out->list_item(out, NULL, "Cluster is %s",
 992                    pcmk_is_set(data_set->flags, pe_flag_symmetric_cluster) ? "symmetric" : "asymmetric");
 993 
 994     switch (data_set->no_quorum_policy) {
 995         case no_quorum_freeze:
 996             out->list_item(out, NULL, "No quorum policy: Freeze resources");
 997             break;
 998 
 999         case no_quorum_stop:
1000             out->list_item(out, NULL, "No quorum policy: Stop ALL resources");
1001             break;
1002 
1003         case no_quorum_demote:
1004             out->list_item(out, NULL, "No quorum policy: Demote promotable "
1005                            "resources and stop all other resources");
1006             break;
1007 
1008         case no_quorum_ignore:
1009             out->list_item(out, NULL, "No quorum policy: Ignore");
1010             break;
1011 
1012         case no_quorum_suicide:
1013             out->list_item(out, NULL, "No quorum policy: Suicide");
1014             break;
1015     }
1016 
1017     return pcmk_rc_ok;
1018 }
1019 
1020 PCMK__OUTPUT_ARGS("cluster-options", "pe_working_set_t *")
     /* [previous][next][first][last][top][bottom][index][help] */
1021 static int
1022 cluster_options_xml(pcmk__output_t *out, va_list args) {
1023     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1024 
1025     const char *no_quorum_policy = NULL;
1026     char *stonith_timeout_str = pcmk__itoa(data_set->stonith_timeout);
1027     char *priority_fencing_delay_str = pcmk__itoa(data_set->priority_fencing_delay * 1000);
1028 
1029     switch (data_set->no_quorum_policy) {
1030         case no_quorum_freeze:
1031             no_quorum_policy = "freeze";
1032             break;
1033 
1034         case no_quorum_stop:
1035             no_quorum_policy = "stop";
1036             break;
1037 
1038         case no_quorum_demote:
1039             no_quorum_policy = "demote";
1040             break;
1041 
1042         case no_quorum_ignore:
1043             no_quorum_policy = "ignore";
1044             break;
1045 
1046         case no_quorum_suicide:
1047             no_quorum_policy = "suicide";
1048             break;
1049     }
1050 
1051     pcmk__output_create_xml_node(out, "cluster_options",
1052                                  "stonith-enabled", pcmk__btoa(pcmk_is_set(data_set->flags, pe_flag_stonith_enabled)),
1053                                  "symmetric-cluster", pcmk__btoa(pcmk_is_set(data_set->flags, pe_flag_symmetric_cluster)),
1054                                  "no-quorum-policy", no_quorum_policy,
1055                                  "maintenance-mode", pcmk__btoa(pcmk_is_set(data_set->flags, pe_flag_maintenance_mode)),
1056                                  "stop-all-resources", pcmk__btoa(pcmk_is_set(data_set->flags, pe_flag_stop_everything)),
1057                                  "stonith-timeout-ms", stonith_timeout_str,
1058                                  "priority-fencing-delay-ms", priority_fencing_delay_str,
1059                                  NULL);
1060     free(stonith_timeout_str);
1061     free(priority_fencing_delay_str);
1062 
1063     return pcmk_rc_ok;
1064 }
1065 
1066 PCMK__OUTPUT_ARGS("cluster-stack", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1067 static int
1068 cluster_stack_html(pcmk__output_t *out, va_list args) {
1069     const char *stack_s = va_arg(args, const char *);
1070 
1071     xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
1072 
1073     pcmk_create_html_node(node, "span", NULL, "bold", "Stack: ");
1074     pcmk_create_html_node(node, "span", NULL, NULL, stack_s);
1075 
1076     return pcmk_rc_ok;
1077 }
1078 
1079 PCMK__OUTPUT_ARGS("cluster-stack", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1080 static int
1081 cluster_stack_text(pcmk__output_t *out, va_list args) {
1082     const char *stack_s = va_arg(args, const char *);
1083 
1084     out->list_item(out, "Stack", "%s", stack_s);
1085     return pcmk_rc_ok;
1086 }
1087 
1088 PCMK__OUTPUT_ARGS("cluster-stack", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1089 static int
1090 cluster_stack_xml(pcmk__output_t *out, va_list args) {
1091     const char *stack_s = va_arg(args, const char *);
1092 
1093     pcmk__output_create_xml_node(out, "stack",
1094                                  "type", stack_s,
1095                                  NULL);
1096 
1097     return pcmk_rc_ok;
1098 }
1099 
1100 PCMK__OUTPUT_ARGS("cluster-times", "const char *", "const char *", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1101 static int
1102 cluster_times_html(pcmk__output_t *out, va_list args) {
1103     const char *last_written = va_arg(args, const char *);
1104     const char *user = va_arg(args, const char *);
1105     const char *client = va_arg(args, const char *);
1106     const char *origin = va_arg(args, const char *);
1107 
1108     xmlNodePtr updated_node = pcmk__output_create_xml_node(out, "li", NULL);
1109     xmlNodePtr changed_node = pcmk__output_create_xml_node(out, "li", NULL);
1110 
1111     char *buf = last_changed_string(last_written, user, client, origin);
1112 
1113     pcmk_create_html_node(updated_node, "span", NULL, "bold", "Last updated: ");
1114     pcmk_create_html_node(updated_node, "span", NULL, NULL,
1115                           pcmk__epoch2str(NULL));
1116 
1117     pcmk_create_html_node(changed_node, "span", NULL, "bold", "Last change: ");
1118     pcmk_create_html_node(changed_node, "span", NULL, NULL, buf);
1119 
1120     free(buf);
1121     return pcmk_rc_ok;
1122 }
1123 
1124 PCMK__OUTPUT_ARGS("cluster-times", "const char *", "const char *", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1125 static int
1126 cluster_times_xml(pcmk__output_t *out, va_list args) {
1127     const char *last_written = va_arg(args, const char *);
1128     const char *user = va_arg(args, const char *);
1129     const char *client = va_arg(args, const char *);
1130     const char *origin = va_arg(args, const char *);
1131 
1132     pcmk__output_create_xml_node(out, "last_update",
1133                                  "time", pcmk__epoch2str(NULL),
1134                                  NULL);
1135     pcmk__output_create_xml_node(out, "last_change",
1136                                  "time", last_written ? last_written : "",
1137                                  "user", user ? user : "",
1138                                  "client", client ? client : "",
1139                                  "origin", origin ? origin : "",
1140                                  NULL);
1141 
1142     return pcmk_rc_ok;
1143 }
1144 
1145 PCMK__OUTPUT_ARGS("cluster-times", "const char *", "const char *", "const char *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1146 static int
1147 cluster_times_text(pcmk__output_t *out, va_list args) {
1148     const char *last_written = va_arg(args, const char *);
1149     const char *user = va_arg(args, const char *);
1150     const char *client = va_arg(args, const char *);
1151     const char *origin = va_arg(args, const char *);
1152 
1153     char *buf = last_changed_string(last_written, user, client, origin);
1154 
1155     out->list_item(out, "Last updated", "%s", pcmk__epoch2str(NULL));
1156     out->list_item(out, "Last change", " %s", buf);
1157 
1158     free(buf);
1159     return pcmk_rc_ok;
1160 }
1161 
1162 PCMK__OUTPUT_ARGS("failed-action", "xmlNodePtr")
     /* [previous][next][first][last][top][bottom][index][help] */
1163 static int
1164 failed_action_text(pcmk__output_t *out, va_list args) {
1165     xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1166 
1167     char *s = failed_action_string(xml_op);
1168 
1169     out->list_item(out, NULL, "%s", s);
1170     free(s);
1171     return pcmk_rc_ok;
1172 }
1173 
1174 PCMK__OUTPUT_ARGS("failed-action", "xmlNodePtr")
     /* [previous][next][first][last][top][bottom][index][help] */
1175 static int
1176 failed_action_xml(pcmk__output_t *out, va_list args) {
1177     xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1178 
1179     const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
1180     int rc;
1181     int status;
1182     const char *exit_reason = crm_element_value(xml_op, XML_LRM_ATTR_EXIT_REASON);
1183 
1184     time_t epoch = 0;
1185     char *rc_s = NULL;
1186     char *reason_s = crm_xml_escape(exit_reason ? exit_reason : "none");
1187     xmlNodePtr node = NULL;
1188 
1189     pcmk__scan_min_int(crm_element_value(xml_op, XML_LRM_ATTR_RC), &rc, 0);
1190     pcmk__scan_min_int(crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS),
1191                        &status, 0);
1192 
1193     rc_s = pcmk__itoa(rc);
1194     node = pcmk__output_create_xml_node(out, "failure",
1195                                         (op_key == NULL)? "id" : "op_key",
1196                                         (op_key == NULL)? ID(xml_op) : op_key,
1197                                         "node", crm_element_value(xml_op, XML_ATTR_UNAME),
1198                                         "exitstatus", services_ocf_exitcode_str(rc),
1199                                         "exitreason", reason_s,
1200                                         "exitcode", rc_s,
1201                                         "call", crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
1202                                         "status", services_lrm_status_str(status),
1203                                         NULL);
1204     free(rc_s);
1205 
1206     if ((crm_element_value_epoch(xml_op, XML_RSC_OP_LAST_CHANGE,
1207                                  &epoch) == pcmk_ok) && (epoch > 0)) {
1208         guint interval_ms = 0;
1209         char *s = NULL;
1210         crm_time_t *crm_when = crm_time_new_undefined();
1211         char *rc_change = NULL;
1212 
1213         crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
1214         s = pcmk__itoa(interval_ms);
1215 
1216         crm_time_set_timet(crm_when, &epoch);
1217         rc_change = crm_time_as_string(crm_when, crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
1218 
1219         pcmk__xe_set_props(node, XML_RSC_OP_LAST_CHANGE, rc_change,
1220                            "queued", crm_element_value(xml_op, XML_RSC_OP_T_QUEUE),
1221                            "exec", crm_element_value(xml_op, XML_RSC_OP_T_EXEC),
1222                            "interval", s,
1223                            "task", crm_element_value(xml_op, XML_LRM_ATTR_TASK),
1224                            NULL);
1225 
1226         free(s);
1227         free(rc_change);
1228         crm_time_free(crm_when);
1229     }
1230 
1231     free(reason_s);
1232     return pcmk_rc_ok;
1233 }
1234 
1235 PCMK__OUTPUT_ARGS("failed-action-list", "pe_working_set_t *", "GList *",
     /* [previous][next][first][last][top][bottom][index][help] */
1236                   "GList *", "gboolean")
1237 static int
1238 failed_action_list(pcmk__output_t *out, va_list args) {
1239     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1240     GList *only_node = va_arg(args, GList *);
1241     GList *only_rsc = va_arg(args, GList *);
1242     gboolean print_spacer = va_arg(args, gboolean);
1243 
1244     xmlNode *xml_op = NULL;
1245     int rc = pcmk_rc_no_output;
1246 
1247     const char *id = NULL;
1248 
1249     if (xmlChildElementCount(data_set->failed) == 0) {
1250         return rc;
1251     }
1252 
1253     for (xml_op = pcmk__xml_first_child(data_set->failed); xml_op != NULL;
1254          xml_op = pcmk__xml_next(xml_op)) {
1255         char *rsc = NULL;
1256 
1257         if (!pcmk__str_in_list(only_node, crm_element_value(xml_op, XML_ATTR_UNAME), pcmk__str_casei)) {
1258             continue;
1259         }
1260 
1261         id = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
1262         if (parse_op_key(id ? id : ID(xml_op), &rsc, NULL, NULL) == FALSE) {
1263             continue;
1264         }
1265 
1266         if (!pcmk__str_in_list(only_rsc, rsc, pcmk__str_none)) {
1267             free(rsc);
1268             continue;
1269         }
1270 
1271         free(rsc);
1272 
1273         PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Failed Resource Actions");
1274         out->message(out, "failed-action", xml_op);
1275     }
1276 
1277     PCMK__OUTPUT_LIST_FOOTER(out, rc);
1278     return rc;
1279 }
1280 
1281 static void
1282 status_node(pe_node_t *node, xmlNodePtr parent)
     /* [previous][next][first][last][top][bottom][index][help] */
1283 {
1284     if (node->details->standby_onfail && node->details->online) {
1285         pcmk_create_html_node(parent, "span", NULL, "standby", " standby (on-fail)");
1286     } else if (node->details->standby && node->details->online) {
1287         char *s = crm_strdup_printf(" standby%s", node->details->running_rsc ? " (with active resources)" : "");
1288         pcmk_create_html_node(parent, "span", NULL, " standby", s);
1289         free(s);
1290     } else if (node->details->standby) {
1291         pcmk_create_html_node(parent, "span", NULL, "offline", " OFFLINE (standby)");
1292     } else if (node->details->maintenance && node->details->online) {
1293         pcmk_create_html_node(parent, "span", NULL, "maint", " maintenance");
1294     } else if (node->details->maintenance) {
1295         pcmk_create_html_node(parent, "span", NULL, "offline", " OFFLINE (maintenance)");
1296     } else if (node->details->online) {
1297         pcmk_create_html_node(parent, "span", NULL, "online", " online");
1298     } else {
1299         pcmk_create_html_node(parent, "span", NULL, "offline", " OFFLINE");
1300     }
1301 }
1302 
1303 PCMK__OUTPUT_ARGS("node", "pe_node_t *", "unsigned int", "gboolean", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
1304                   "GList *", "GList *")
1305 static int
1306 node_html(pcmk__output_t *out, va_list args) {
1307     pe_node_t *node = va_arg(args, pe_node_t *);
1308     unsigned int show_opts = va_arg(args, unsigned int);
1309     gboolean full = va_arg(args, gboolean);
1310     const char *node_mode G_GNUC_UNUSED = va_arg(args, const char *);
1311     GList *only_node = va_arg(args, GList *);
1312     GList *only_rsc = va_arg(args, GList *);
1313 
1314     char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1315 
1316     if (full) {
1317         xmlNodePtr item_node;
1318 
1319         if (pcmk_all_flags_set(show_opts, pcmk_show_brief | pcmk_show_rscs_by_node)) {
1320             GList *rscs = pe__filter_rsc_list(node->details->running_rsc, only_rsc);
1321 
1322             out->begin_list(out, NULL, NULL, "Node: %s", node_name);
1323             item_node = pcmk__output_xml_create_parent(out, "li", NULL);
1324             pcmk_create_html_node(item_node, "span", NULL, NULL, "Status:");
1325             status_node(node, item_node);
1326 
1327             if (rscs != NULL) {
1328                 unsigned int new_show_opts = (show_opts | pcmk_show_rsc_only) & ~pcmk_show_inactive_rscs;
1329                 out->begin_list(out, NULL, NULL, "Resources");
1330                 pe__rscs_brief_output(out, rscs, new_show_opts);
1331                 out->end_list(out);
1332             }
1333 
1334             pcmk__output_xml_pop_parent(out);
1335             out->end_list(out);
1336 
1337         } else if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
1338             GList *lpc2 = NULL;
1339             int rc = pcmk_rc_no_output;
1340 
1341             out->begin_list(out, NULL, NULL, "Node: %s", node_name);
1342             item_node = pcmk__output_xml_create_parent(out, "li", NULL);
1343             pcmk_create_html_node(item_node, "span", NULL, NULL, "Status:");
1344             status_node(node, item_node);
1345 
1346             for (lpc2 = node->details->running_rsc; lpc2 != NULL; lpc2 = lpc2->next) {
1347                 pe_resource_t *rsc = (pe_resource_t *) lpc2->data;
1348                 PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Resources");
1349 
1350                 out->message(out, crm_map_element_name(rsc->xml), show_opts | pcmk_show_rsc_only,
1351                              rsc, only_node, only_rsc);
1352             }
1353 
1354             PCMK__OUTPUT_LIST_FOOTER(out, rc);
1355             pcmk__output_xml_pop_parent(out);
1356             out->end_list(out);
1357 
1358         } else {
1359             char *buf = crm_strdup_printf("Node: %s", node_name);
1360 
1361             item_node = pcmk__output_create_xml_node(out, "li", NULL);
1362             pcmk_create_html_node(item_node, "span", NULL, NULL, buf);
1363             status_node(node, item_node);
1364 
1365             free(buf);
1366         }
1367     } else {
1368         out->begin_list(out, NULL, NULL, "Node: %s", node_name);
1369     }
1370 
1371     free(node_name);
1372     return pcmk_rc_ok;
1373 }
1374 
1375 PCMK__OUTPUT_ARGS("node", "pe_node_t *", "unsigned int", "gboolean", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
1376                   "GList *", "GList *")
1377 static int
1378 node_text(pcmk__output_t *out, va_list args) {
1379     pe_node_t *node = va_arg(args, pe_node_t *);
1380     unsigned int show_opts = va_arg(args, unsigned int);
1381     gboolean full = va_arg(args, gboolean);
1382     const char *node_mode = va_arg(args, const char *);
1383     GList *only_node = va_arg(args, GList *);
1384     GList *only_rsc = va_arg(args, GList *);
1385 
1386     if (full) {
1387         char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1388         char *buf = NULL;
1389 
1390         /* Print the node name and status */
1391         if (pe__is_guest_node(node)) {
1392             buf = crm_strdup_printf("GuestNode %s: %s", node_name, node_mode);
1393         } else if (pe__is_remote_node(node)) {
1394             buf = crm_strdup_printf("RemoteNode %s: %s", node_name, node_mode);
1395         } else {
1396             buf = crm_strdup_printf("Node %s: %s", node_name, node_mode);
1397         }
1398 
1399         /* If we're grouping by node, print its resources */
1400         if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
1401             if (pcmk_is_set(show_opts, pcmk_show_brief)) {
1402                 GList *rscs = pe__filter_rsc_list(node->details->running_rsc, only_rsc);
1403 
1404                 if (rscs != NULL) {
1405                     unsigned int new_show_opts = (show_opts | pcmk_show_rsc_only) & ~pcmk_show_inactive_rscs;
1406                     out->begin_list(out, NULL, NULL, "%s", buf);
1407                     out->begin_list(out, NULL, NULL, "Resources");
1408 
1409                     pe__rscs_brief_output(out, rscs, new_show_opts);
1410 
1411                     out->end_list(out);
1412                     out->end_list(out);
1413 
1414                     g_list_free(rscs);
1415                 }
1416 
1417             } else {
1418                 GList *gIter2 = NULL;
1419 
1420                 out->begin_list(out, NULL, NULL, "%s", buf);
1421                 out->begin_list(out, NULL, NULL, "Resources");
1422 
1423                 for (gIter2 = node->details->running_rsc; gIter2 != NULL; gIter2 = gIter2->next) {
1424                     pe_resource_t *rsc = (pe_resource_t *) gIter2->data;
1425                     out->message(out, crm_map_element_name(rsc->xml), show_opts | pcmk_show_rsc_only,
1426                                  rsc, only_node, only_rsc);
1427                 }
1428 
1429                 out->end_list(out);
1430                 out->end_list(out);
1431             }
1432         } else {
1433             out->list_item(out, NULL, "%s", buf);
1434         }
1435 
1436         free(buf);
1437         free(node_name);
1438     } else {
1439         char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1440         out->begin_list(out, NULL, NULL, "Node: %s", node_name);
1441         free(node_name);
1442     }
1443 
1444     return pcmk_rc_ok;
1445 }
1446 
1447 PCMK__OUTPUT_ARGS("node", "pe_node_t *", "unsigned int", "gboolean", "const char *",
     /* [previous][next][first][last][top][bottom][index][help] */
1448                   "GList *", "GList *")
1449 static int
1450 node_xml(pcmk__output_t *out, va_list args) {
1451     pe_node_t *node = va_arg(args, pe_node_t *);
1452     unsigned int show_opts G_GNUC_UNUSED = va_arg(args, unsigned int);
1453     gboolean full = va_arg(args, gboolean);
1454     const char *node_mode G_GNUC_UNUSED = va_arg(args, const char *);
1455     GList *only_node = va_arg(args, GList *);
1456     GList *only_rsc = va_arg(args, GList *);
1457 
1458     if (full) {
1459         const char *node_type = "unknown";
1460         char *length_s = pcmk__itoa(g_list_length(node->details->running_rsc));
1461 
1462         switch (node->details->type) {
1463             case node_member:
1464                 node_type = "member";
1465                 break;
1466             case node_remote:
1467                 node_type = "remote";
1468                 break;
1469             case node_ping:
1470                 node_type = "ping";
1471                 break;
1472         }
1473         pe__name_and_nvpairs_xml(out, true, "node", 13,
1474                                  "name", node->details->uname,
1475                                  "id", node->details->id,
1476                                  "online", pcmk__btoa(node->details->online),
1477                                  "standby", pcmk__btoa(node->details->standby),
1478                                  "standby_onfail", pcmk__btoa(node->details->standby_onfail),
1479                                  "maintenance", pcmk__btoa(node->details->maintenance),
1480                                  "pending", pcmk__btoa(node->details->pending),
1481                                  "unclean", pcmk__btoa(node->details->unclean),
1482                                  "shutdown", pcmk__btoa(node->details->shutdown),
1483                                  "expected_up", pcmk__btoa(node->details->expected_up),
1484                                  "is_dc", pcmk__btoa(node->details->is_dc),
1485                                  "resources_running", length_s,
1486                                  "type", node_type);
1487 
1488         if (pe__is_guest_node(node)) {
1489             xmlNodePtr xml_node = pcmk__output_xml_peek_parent(out);
1490             crm_xml_add(xml_node, "id_as_resource", node->details->remote_rsc->container->id);
1491         }
1492 
1493         if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
1494             GList *lpc = NULL;
1495 
1496             for (lpc = node->details->running_rsc; lpc != NULL; lpc = lpc->next) {
1497                 pe_resource_t *rsc = (pe_resource_t *) lpc->data;
1498                 out->message(out, crm_map_element_name(rsc->xml), show_opts | pcmk_show_rsc_only,
1499                              rsc, only_node, only_rsc);
1500             }
1501         }
1502 
1503         free(length_s);
1504 
1505         out->end_list(out);
1506     } else {
1507         pcmk__output_xml_create_parent(out, "node",
1508                                        "name", node->details->uname,
1509                                        NULL);
1510     }
1511 
1512     return pcmk_rc_ok;
1513 }
1514 
1515 PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "gboolean", "int")
     /* [previous][next][first][last][top][bottom][index][help] */
1516 static int
1517 node_attribute_text(pcmk__output_t *out, va_list args) {
1518     const char *name = va_arg(args, const char *);
1519     const char *value = va_arg(args, const char *);
1520     gboolean add_extra = va_arg(args, gboolean);
1521     int expected_score = va_arg(args, int);
1522 
1523     if (add_extra) {
1524         int v;
1525 
1526         if (value == NULL) {
1527             v = 0;
1528         } else {
1529             pcmk__scan_min_int(value, &v, INT_MIN);
1530         }
1531         if (v <= 0) {
1532             out->list_item(out, NULL, "%-32s\t: %-10s\t: Connectivity is lost", name, value);
1533         } else if (v < expected_score) {
1534             out->list_item(out, NULL, "%-32s\t: %-10s\t: Connectivity is degraded (Expected=%d)", name, value, expected_score);
1535         } else {
1536             out->list_item(out, NULL, "%-32s\t: %-10s", name, value);
1537         }
1538     } else {
1539         out->list_item(out, NULL, "%-32s\t: %-10s", name, value);
1540     }
1541 
1542     return pcmk_rc_ok;
1543 }
1544 
1545 PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "gboolean", "int")
     /* [previous][next][first][last][top][bottom][index][help] */
1546 static int
1547 node_attribute_html(pcmk__output_t *out, va_list args) {
1548     const char *name = va_arg(args, const char *);
1549     const char *value = va_arg(args, const char *);
1550     gboolean add_extra = va_arg(args, gboolean);
1551     int expected_score = va_arg(args, int);
1552 
1553     if (add_extra) {
1554         int v;
1555         char *s = crm_strdup_printf("%s: %s", name, value);
1556         xmlNodePtr item_node = pcmk__output_create_xml_node(out, "li", NULL);
1557 
1558         if (value == NULL) {
1559             v = 0;
1560         } else {
1561             pcmk__scan_min_int(value, &v, INT_MIN);
1562         }
1563 
1564         pcmk_create_html_node(item_node, "span", NULL, NULL, s);
1565         free(s);
1566 
1567         if (v <= 0) {
1568             pcmk_create_html_node(item_node, "span", NULL, "bold", "(connectivity is lost)");
1569         } else if (v < expected_score) {
1570             char *buf = crm_strdup_printf("(connectivity is degraded -- expected %d", expected_score);
1571             pcmk_create_html_node(item_node, "span", NULL, "bold", buf);
1572             free(buf);
1573         }
1574     } else {
1575         out->list_item(out, NULL, "%s: %s", name, value);
1576     }
1577 
1578     return pcmk_rc_ok;
1579 }
1580 
1581 PCMK__OUTPUT_ARGS("node-and-op", "pe_working_set_t *", "xmlNodePtr")
     /* [previous][next][first][last][top][bottom][index][help] */
1582 static int
1583 node_and_op(pcmk__output_t *out, va_list args) {
1584     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1585     xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1586 
1587     pe_resource_t *rsc = NULL;
1588     gchar *node_str = NULL;
1589     char *last_change_str = NULL;
1590 
1591     const char *op_rsc = crm_element_value(xml_op, "resource");
1592     const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
1593     int status;
1594     time_t last_change = 0;
1595 
1596     pcmk__scan_min_int(crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS),
1597                        &status, 0);
1598 
1599     rsc = pe_find_resource(data_set->resources, op_rsc);
1600 
1601     if (rsc) {
1602         pe_node_t *node = pe__current_node(rsc);
1603         const char *target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
1604         unsigned int show_opts = pcmk_show_rsc_only | pcmk_show_pending;
1605 
1606         if (node == NULL) {
1607             node = rsc->pending_node;
1608         }
1609 
1610         node_str = pcmk__native_output_string(rsc, rsc_printable_id(rsc), node,
1611                                               show_opts, target_role, false);
1612     } else {
1613         node_str = crm_strdup_printf("Unknown resource %s", op_rsc);
1614     }
1615 
1616     if (crm_element_value_epoch(xml_op, XML_RSC_OP_LAST_CHANGE,
1617                                 &last_change) == pcmk_ok) {
1618         last_change_str = crm_strdup_printf(", %s=%s, exec=%sms",
1619                                             XML_RSC_OP_LAST_CHANGE,
1620                                             pcmk__trim(ctime(&last_change)),
1621                                             crm_element_value(xml_op, XML_RSC_OP_T_EXEC));
1622     }
1623 
1624     out->list_item(out, NULL, "%s: %s (node=%s, call=%s, rc=%s%s): %s",
1625                    node_str, op_key ? op_key : ID(xml_op),
1626                    crm_element_value(xml_op, XML_ATTR_UNAME),
1627                    crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
1628                    crm_element_value(xml_op, XML_LRM_ATTR_RC),
1629                    last_change_str ? last_change_str : "",
1630                    services_lrm_status_str(status));
1631 
1632     g_free(node_str);
1633     free(last_change_str);
1634     return pcmk_rc_ok;
1635 }
1636 
1637 PCMK__OUTPUT_ARGS("node-and-op", "pe_working_set_t *", "xmlNodePtr")
     /* [previous][next][first][last][top][bottom][index][help] */
1638 static int
1639 node_and_op_xml(pcmk__output_t *out, va_list args) {
1640     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1641     xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1642 
1643     pe_resource_t *rsc = NULL;
1644     const char *op_rsc = crm_element_value(xml_op, "resource");
1645     const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
1646     int status;
1647     time_t last_change = 0;
1648     xmlNode *node = NULL;
1649 
1650     pcmk__scan_min_int(crm_element_value(xml_op, XML_LRM_ATTR_OPSTATUS),
1651                        &status, 0);
1652     node = pcmk__output_create_xml_node(out, "operation",
1653                                         "op", op_key ? op_key : ID(xml_op),
1654                                         "node", crm_element_value(xml_op, XML_ATTR_UNAME),
1655                                         "call", crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
1656                                         "rc", crm_element_value(xml_op, XML_LRM_ATTR_RC),
1657                                         "status", services_lrm_status_str(status),
1658                                         NULL);
1659 
1660     rsc = pe_find_resource(data_set->resources, op_rsc);
1661 
1662     if (rsc) {
1663         const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
1664         const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
1665         char *agent_tuple = NULL;
1666 
1667         agent_tuple = crm_strdup_printf("%s:%s:%s", class,
1668                                         pcmk_is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider) ? crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER) : "",
1669                                         kind);
1670 
1671         pcmk__xe_set_props(node, "rsc", rsc_printable_id(rsc),
1672                            "agent", agent_tuple,
1673                            NULL);
1674         free(agent_tuple);
1675     }
1676 
1677     if (crm_element_value_epoch(xml_op, XML_RSC_OP_LAST_CHANGE,
1678                                 &last_change) == pcmk_ok) {
1679         pcmk__xe_set_props(node, XML_RSC_OP_LAST_CHANGE,
1680                            pcmk__trim(ctime(&last_change)),
1681                            XML_RSC_OP_T_EXEC, crm_element_value(xml_op, XML_RSC_OP_T_EXEC),
1682                            NULL);
1683     }
1684 
1685     return pcmk_rc_ok;
1686 }
1687 
1688 PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "gboolean", "int")
     /* [previous][next][first][last][top][bottom][index][help] */
1689 static int
1690 node_attribute_xml(pcmk__output_t *out, va_list args) {
1691     const char *name = va_arg(args, const char *);
1692     const char *value = va_arg(args, const char *);
1693     gboolean add_extra = va_arg(args, gboolean);
1694     int expected_score = va_arg(args, int);
1695 
1696     xmlNodePtr node = pcmk__output_create_xml_node(out, "attribute",
1697                                                    "name", name,
1698                                                    "value", value,
1699                                                    NULL);
1700 
1701     if (add_extra) {
1702         char *buf = pcmk__itoa(expected_score);
1703         crm_xml_add(node, "expected", buf);
1704         free(buf);
1705     }
1706 
1707     return pcmk_rc_ok;
1708 }
1709 
1710 PCMK__OUTPUT_ARGS("node-attribute-list", "pe_working_set_t *", "unsigned int",
     /* [previous][next][first][last][top][bottom][index][help] */
1711                   "gboolean", "GList *", "GList *")
1712 static int
1713 node_attribute_list(pcmk__output_t *out, va_list args) {
1714     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1715     unsigned int show_opts = va_arg(args, unsigned int);
1716     gboolean print_spacer = va_arg(args, gboolean);
1717     GList *only_node = va_arg(args, GList *);
1718     GList *only_rsc = va_arg(args, GList *);
1719 
1720     int rc = pcmk_rc_no_output;
1721 
1722     /* Display each node's attributes */
1723     for (GList *gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
1724         pe_node_t *node = gIter->data;
1725 
1726         GList *attr_list = NULL;
1727         GHashTableIter iter;
1728         gpointer key;
1729 
1730         if (!node || !node->details || !node->details->online) {
1731             continue;
1732         }
1733 
1734         g_hash_table_iter_init(&iter, node->details->attrs);
1735         while (g_hash_table_iter_next (&iter, &key, NULL)) {
1736             attr_list = filter_attr_list(attr_list, key);
1737         }
1738 
1739         if (attr_list == NULL) {
1740             continue;
1741         }
1742 
1743         if (!pcmk__str_in_list(only_node, node->details->uname, pcmk__str_casei)) {
1744             g_list_free(attr_list);
1745             continue;
1746         }
1747 
1748         PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Node Attributes");
1749 
1750         out->message(out, "node", node, show_opts, FALSE, NULL, only_node, only_rsc);
1751 
1752         for (GList *aIter = attr_list; aIter != NULL; aIter = aIter->next) {
1753             const char *name = aIter->data;
1754             const char *value = NULL;
1755             int expected_score = 0;
1756             gboolean add_extra = FALSE;
1757 
1758             value = pe_node_attribute_raw(node, name);
1759 
1760             add_extra = add_extra_info(node, node->details->running_rsc,
1761                                        data_set, name, &expected_score);
1762 
1763             /* Print attribute name and value */
1764             out->message(out, "node-attribute", name, value, add_extra,
1765                          expected_score);
1766         }
1767 
1768         g_list_free(attr_list);
1769         out->end_list(out);
1770     }
1771 
1772     PCMK__OUTPUT_LIST_FOOTER(out, rc);
1773     return rc;
1774 }
1775 
1776 PCMK__OUTPUT_ARGS("node-capacity", "pe_node_t *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1777 static int
1778 node_capacity(pcmk__output_t *out, va_list args)
1779 {
1780     pe_node_t *node = va_arg(args, pe_node_t *);
1781     const char *comment = va_arg(args, const char *);
1782 
1783     char *dump_text = crm_strdup_printf("%s: %s capacity:",
1784                                         comment, node->details->uname);
1785 
1786     g_hash_table_foreach(node->details->utilization, append_dump_text, &dump_text);
1787     out->list_item(out, NULL, "%s", dump_text);
1788     free(dump_text);
1789 
1790     return pcmk_rc_ok;
1791 }
1792 
1793 PCMK__OUTPUT_ARGS("node-capacity", "pe_node_t *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
1794 static int
1795 node_capacity_xml(pcmk__output_t *out, va_list args)
1796 {
1797     pe_node_t *node = va_arg(args, pe_node_t *);
1798     const char *comment = va_arg(args, const char *);
1799 
1800     xmlNodePtr xml_node = pcmk__output_create_xml_node(out, "capacity",
1801                                                        "node", node->details->uname,
1802                                                        "comment", comment,
1803                                                        NULL);
1804     g_hash_table_foreach(node->details->utilization, add_dump_node, xml_node);
1805 
1806     return pcmk_rc_ok;
1807 }
1808 
1809 PCMK__OUTPUT_ARGS("node-history-list", "pe_working_set_t *", "pe_node_t *", "xmlNodePtr",
     /* [previous][next][first][last][top][bottom][index][help] */
1810                   "GList *", "GList *", "unsigned int", "unsigned int")
1811 static int
1812 node_history_list(pcmk__output_t *out, va_list args) {
1813     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1814     pe_node_t *node = va_arg(args, pe_node_t *);
1815     xmlNode *node_state = va_arg(args, xmlNode *);
1816     GList *only_node = va_arg(args, GList *);
1817     GList *only_rsc = va_arg(args, GList *);
1818     unsigned int section_opts = va_arg(args, unsigned int);
1819     unsigned int show_opts = va_arg(args, unsigned int);
1820 
1821     xmlNode *lrm_rsc = NULL;
1822     xmlNode *rsc_entry = NULL;
1823     int rc = pcmk_rc_no_output;
1824 
1825     lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE);
1826     lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE);
1827 
1828     /* Print history of each of the node's resources */
1829     for (rsc_entry = first_named_child(lrm_rsc, XML_LRM_TAG_RESOURCE);
1830          rsc_entry != NULL; rsc_entry = crm_next_same_xml(rsc_entry)) {
1831         const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID);
1832         pe_resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
1833 
1834         /* We can't use is_filtered here to filter group resources.  For is_filtered,
1835          * we have to decide whether to check the parent or not.  If we check the
1836          * parent, all elements of a group will always be printed because that's how
1837          * is_filtered works for groups.  If we do not check the parent, sometimes
1838          * this will filter everything out.
1839          *
1840          * For other resource types, is_filtered is okay.
1841          */
1842         if (uber_parent(rsc)->variant == pe_group) {
1843             if (!pcmk__str_in_list(only_rsc, rsc_printable_id(rsc), pcmk__str_none) &&
1844                 !pcmk__str_in_list(only_rsc, rsc_printable_id(uber_parent(rsc)), pcmk__str_none)) {
1845                 continue;
1846             }
1847         } else {
1848             if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
1849                 continue;
1850             }
1851         }
1852 
1853         if (!pcmk_is_set(section_opts, pcmk_section_operations)) {
1854             time_t last_failure = 0;
1855             int failcount = pe_get_failcount(node, rsc, &last_failure, pe_fc_default,
1856                                              NULL, data_set);
1857 
1858             if (failcount <= 0) {
1859                 continue;
1860             }
1861 
1862             if (rc == pcmk_rc_no_output) {
1863                 rc = pcmk_rc_ok;
1864                 out->message(out, "node", node, show_opts, FALSE, NULL, only_node, only_rsc);
1865             }
1866 
1867             out->message(out, "resource-history", rsc, rsc_id, FALSE,
1868                          failcount, last_failure, FALSE);
1869         } else {
1870             GList *op_list = get_operation_list(rsc_entry);
1871             pe_resource_t *rsc = pe_find_resource(data_set->resources,
1872                                                   crm_element_value(rsc_entry, XML_ATTR_ID));
1873 
1874             if (op_list == NULL) {
1875                 continue;
1876             }
1877 
1878             if (rc == pcmk_rc_no_output) {
1879                 rc = pcmk_rc_ok;
1880                 out->message(out, "node", node, show_opts, FALSE, NULL, only_node, only_rsc);
1881             }
1882 
1883             out->message(out, "resource-operation-list", data_set, rsc, node,
1884                          op_list, show_opts);
1885         }
1886     }
1887 
1888     PCMK__OUTPUT_LIST_FOOTER(out, rc);
1889     return rc;
1890 }
1891 
1892 PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "unsigned int")
     /* [previous][next][first][last][top][bottom][index][help] */
1893 static int
1894 node_list_html(pcmk__output_t *out, va_list args) {
1895     GList *nodes = va_arg(args, GList *);
1896     GList *only_node = va_arg(args, GList *);
1897     GList *only_rsc = va_arg(args, GList *);
1898     unsigned int show_opts = va_arg(args, unsigned int);
1899 
1900     int rc = pcmk_rc_no_output;
1901 
1902     for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
1903         pe_node_t *node = (pe_node_t *) gIter->data;
1904 
1905         if (!pcmk__str_in_list(only_node, node->details->uname, pcmk__str_casei)) {
1906             continue;
1907         }
1908 
1909         PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Node List");
1910 
1911         out->message(out, "node", node, show_opts, TRUE, NULL, only_node, only_rsc);
1912     }
1913 
1914     PCMK__OUTPUT_LIST_FOOTER(out, rc);
1915     return rc;
1916 }
1917 
1918 PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "unsigned int")
     /* [previous][next][first][last][top][bottom][index][help] */
1919 static int
1920 node_list_text(pcmk__output_t *out, va_list args) {
1921     GList *nodes = va_arg(args, GList *);
1922     GList *only_node = va_arg(args, GList *);
1923     GList *only_rsc = va_arg(args, GList *);
1924     unsigned int show_opts = va_arg(args, unsigned int);
1925 
1926     /* space-separated lists of node names */
1927     char *online_nodes = NULL;
1928     char *online_remote_nodes = NULL;
1929     char *online_guest_nodes = NULL;
1930     char *offline_nodes = NULL;
1931     char *offline_remote_nodes = NULL;
1932 
1933     size_t online_nodes_len = 0;
1934     size_t online_remote_nodes_len = 0;
1935     size_t online_guest_nodes_len = 0;
1936     size_t offline_nodes_len = 0;
1937     size_t offline_remote_nodes_len = 0;
1938 
1939     int rc = pcmk_rc_no_output;
1940 
1941     for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
1942         pe_node_t *node = (pe_node_t *) gIter->data;
1943         const char *node_mode = NULL;
1944         char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1945 
1946         if (!pcmk__str_in_list(only_node, node->details->uname, pcmk__str_casei)) {
1947             free(node_name);
1948             continue;
1949         }
1950 
1951         PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Node List");
1952 
1953         /* Get node mode */
1954         if (node->details->unclean) {
1955             if (node->details->online) {
1956                 node_mode = "UNCLEAN (online)";
1957 
1958             } else if (node->details->pending) {
1959                 node_mode = "UNCLEAN (pending)";
1960 
1961             } else {
1962                 node_mode = "UNCLEAN (offline)";
1963             }
1964 
1965         } else if (node->details->pending) {
1966             node_mode = "pending";
1967 
1968         } else if (node->details->standby_onfail && node->details->online) {
1969             node_mode = "standby (on-fail)";
1970 
1971         } else if (node->details->standby) {
1972             if (node->details->online) {
1973                 if (node->details->running_rsc) {
1974                     node_mode = "standby (with active resources)";
1975                 } else {
1976                     node_mode = "standby";
1977                 }
1978             } else {
1979                 node_mode = "OFFLINE (standby)";
1980             }
1981 
1982         } else if (node->details->maintenance) {
1983             if (node->details->online) {
1984                 node_mode = "maintenance";
1985             } else {
1986                 node_mode = "OFFLINE (maintenance)";
1987             }
1988 
1989         } else if (node->details->online) {
1990             node_mode = "online";
1991             if (!pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
1992                 if (pe__is_guest_node(node)) {
1993                     pcmk__add_word(&online_guest_nodes,
1994                                    &online_guest_nodes_len, node_name);
1995                 } else if (pe__is_remote_node(node)) {
1996                     pcmk__add_word(&online_remote_nodes,
1997                                    &online_remote_nodes_len, node_name);
1998                 } else {
1999                     pcmk__add_word(&online_nodes, &online_nodes_len, node_name);
2000                 }
2001                 free(node_name);
2002                 continue;
2003             }
2004 
2005         } else {
2006             node_mode = "OFFLINE";
2007             if (!pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2008                 if (pe__is_remote_node(node)) {
2009                     pcmk__add_word(&offline_remote_nodes,
2010                                    &offline_remote_nodes_len, node_name);
2011                 } else if (pe__is_guest_node(node)) {
2012                     /* ignore offline guest nodes */
2013                 } else {
2014                     pcmk__add_word(&offline_nodes,
2015                                    &offline_nodes_len, node_name);
2016                 }
2017                 free(node_name);
2018                 continue;
2019             }
2020         }
2021 
2022         /* If we get here, node is in bad state, or we're grouping by node */
2023         out->message(out, "node", node, show_opts, TRUE, node_mode, only_node, only_rsc);
2024         free(node_name);
2025     }
2026 
2027     /* If we're not grouping by node, summarize nodes by status */
2028     if (online_nodes) {
2029         out->list_item(out, "Online", "[ %s ]", online_nodes);
2030         free(online_nodes);
2031     }
2032     if (offline_nodes) {
2033         out->list_item(out, "OFFLINE", "[ %s ]", offline_nodes);
2034         free(offline_nodes);
2035     }
2036     if (online_remote_nodes) {
2037         out->list_item(out, "RemoteOnline", "[ %s ]", online_remote_nodes);
2038         free(online_remote_nodes);
2039     }
2040     if (offline_remote_nodes) {
2041         out->list_item(out, "RemoteOFFLINE", "[ %s ]", offline_remote_nodes);
2042         free(offline_remote_nodes);
2043     }
2044     if (online_guest_nodes) {
2045         out->list_item(out, "GuestOnline", "[ %s ]", online_guest_nodes);
2046         free(online_guest_nodes);
2047     }
2048 
2049     PCMK__OUTPUT_LIST_FOOTER(out, rc);
2050     return rc;
2051 }
2052 
2053 PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "unsigned int")
     /* [previous][next][first][last][top][bottom][index][help] */
2054 static int
2055 node_list_xml(pcmk__output_t *out, va_list args) {
2056     GList *nodes = va_arg(args, GList *);
2057     GList *only_node = va_arg(args, GList *);
2058     GList *only_rsc = va_arg(args, GList *);
2059     unsigned int show_opts = va_arg(args, unsigned int);
2060 
2061     out->begin_list(out, NULL, NULL, "nodes");
2062     for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
2063         pe_node_t *node = (pe_node_t *) gIter->data;
2064 
2065         if (!pcmk__str_in_list(only_node, node->details->uname, pcmk__str_casei)) {
2066             continue;
2067         }
2068 
2069         out->message(out, "node", node, show_opts, TRUE, NULL, only_node, only_rsc);
2070     }
2071     out->end_list(out);
2072 
2073     return pcmk_rc_ok;
2074 }
2075 
2076 PCMK__OUTPUT_ARGS("node-summary", "pe_working_set_t *", "GList *", "GList *",
     /* [previous][next][first][last][top][bottom][index][help] */
2077                   "unsigned int", "unsigned int", "gboolean")
2078 static int
2079 node_summary(pcmk__output_t *out, va_list args) {
2080     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
2081     GList *only_node = va_arg(args, GList *);
2082     GList *only_rsc = va_arg(args, GList *);
2083     unsigned int section_opts = va_arg(args, unsigned int);
2084     unsigned int show_opts = va_arg(args, unsigned int);
2085     gboolean print_spacer = va_arg(args, gboolean);
2086 
2087     xmlNode *node_state = NULL;
2088     xmlNode *cib_status = get_object_root(XML_CIB_TAG_STATUS, data_set->input);
2089     int rc = pcmk_rc_no_output;
2090 
2091     if (xmlChildElementCount(cib_status) == 0) {
2092         return rc;
2093     }
2094 
2095     for (node_state = first_named_child(cib_status, XML_CIB_TAG_STATE);
2096          node_state != NULL; node_state = crm_next_same_xml(node_state)) {
2097         pe_node_t *node = pe_find_node_id(data_set->nodes, ID(node_state));
2098 
2099         if (!node || !node->details || !node->details->online) {
2100             continue;
2101         }
2102 
2103         if (!pcmk__str_in_list(only_node, node->details->uname, pcmk__str_casei)) {
2104             continue;
2105         }
2106 
2107         PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc,
2108                                  pcmk_is_set(section_opts, pcmk_section_operations) ? "Operations" : "Migration Summary");
2109 
2110         out->message(out, "node-history-list", data_set, node, node_state,
2111                      only_node, only_rsc, section_opts, show_opts);
2112     }
2113 
2114     PCMK__OUTPUT_LIST_FOOTER(out, rc);
2115     return rc;
2116 }
2117 
2118 PCMK__OUTPUT_ARGS("node-weight", "pe_resource_t *", "const char *", "const char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
2119 static int
2120 node_weight(pcmk__output_t *out, va_list args)
2121 {
2122     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2123     const char *prefix = va_arg(args, const char *);
2124     const char *uname = va_arg(args, const char *);
2125     char *score = va_arg(args, char *);
2126 
2127     if (rsc) {
2128         out->list_item(out, NULL, "%s: %s allocation score on %s: %s",
2129                        prefix, rsc->id, uname, score);
2130     } else {
2131         out->list_item(out, NULL, "%s: %s = %s", prefix, uname, score);
2132     }
2133 
2134     return pcmk_rc_ok;
2135 }
2136 
2137 PCMK__OUTPUT_ARGS("node-weight", "pe_resource_t *", "const char *", "const char *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
2138 static int
2139 node_weight_xml(pcmk__output_t *out, va_list args)
2140 {
2141     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2142     const char *prefix = va_arg(args, const char *);
2143     const char *uname = va_arg(args, const char *);
2144     char *score = va_arg(args, char *);
2145 
2146     xmlNodePtr node = pcmk__output_create_xml_node(out, "node_weight",
2147                                                    "function", prefix,
2148                                                    "node", uname,
2149                                                    "score", score,
2150                                                    NULL);
2151 
2152     if (rsc) {
2153         crm_xml_add(node, "id", rsc->id);
2154     }
2155 
2156     return pcmk_rc_ok;
2157 }
2158 
2159 PCMK__OUTPUT_ARGS("op-history", "xmlNodePtr", "const char *", "const char *", "int",
     /* [previous][next][first][last][top][bottom][index][help] */
2160                   "unsigned int")
2161 static int
2162 op_history_text(pcmk__output_t *out, va_list args) {
2163     xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
2164     const char *task = va_arg(args, const char *);
2165     const char *interval_ms_s = va_arg(args, const char *);
2166     int rc = va_arg(args, int);
2167     unsigned int show_opts = va_arg(args, unsigned int);
2168 
2169     char *buf = op_history_string(xml_op, task, interval_ms_s, rc,
2170                                   pcmk_is_set(show_opts, pcmk_show_timing));
2171 
2172     out->list_item(out, NULL, "%s", buf);
2173 
2174     free(buf);
2175     return pcmk_rc_ok;
2176 }
2177 
2178 PCMK__OUTPUT_ARGS("op-history", "xmlNodePtr", "const char *", "const char *", "int",
     /* [previous][next][first][last][top][bottom][index][help] */
2179                   "unsigned int")
2180 static int
2181 op_history_xml(pcmk__output_t *out, va_list args) {
2182     xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
2183     const char *task = va_arg(args, const char *);
2184     const char *interval_ms_s = va_arg(args, const char *);
2185     int rc = va_arg(args, int);
2186     unsigned int show_opts = va_arg(args, unsigned int);
2187 
2188     char *rc_s = pcmk__itoa(rc);
2189     xmlNodePtr node = pcmk__output_create_xml_node(out, "operation_history",
2190                                                    "call", crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
2191                                                    "task", task,
2192                                                    "rc", rc_s,
2193                                                    "rc_text", services_ocf_exitcode_str(rc),
2194                                                    NULL);
2195     free(rc_s);
2196 
2197     if (interval_ms_s && !pcmk__str_eq(interval_ms_s, "0", pcmk__str_casei)) {
2198         char *s = crm_strdup_printf("%sms", interval_ms_s);
2199         crm_xml_add(node, "interval", s);
2200         free(s);
2201     }
2202 
2203     if (pcmk_is_set(show_opts, pcmk_show_timing)) {
2204         const char *value = NULL;
2205         time_t epoch = 0;
2206 
2207         if ((crm_element_value_epoch(xml_op, XML_RSC_OP_LAST_CHANGE,
2208                                      &epoch) == pcmk_ok) && (epoch > 0)) {
2209             crm_xml_add(node, XML_RSC_OP_LAST_CHANGE, pcmk__epoch2str(&epoch));
2210         }
2211 
2212         value = crm_element_value(xml_op, XML_RSC_OP_T_EXEC);
2213         if (value) {
2214             char *s = crm_strdup_printf("%sms", value);
2215             crm_xml_add(node, XML_RSC_OP_T_EXEC, s);
2216             free(s);
2217         }
2218         value = crm_element_value(xml_op, XML_RSC_OP_T_QUEUE);
2219         if (value) {
2220             char *s = crm_strdup_printf("%sms", value);
2221             crm_xml_add(node, XML_RSC_OP_T_QUEUE, s);
2222             free(s);
2223         }
2224     }
2225 
2226     return pcmk_rc_ok;
2227 }
2228 
2229 PCMK__OUTPUT_ARGS("promotion-score", "pe_resource_t *", "pe_node_t *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
2230 static int
2231 promotion_score(pcmk__output_t *out, va_list args)
2232 {
2233     pe_resource_t *child_rsc = va_arg(args, pe_resource_t *);
2234     pe_node_t *chosen = va_arg(args, pe_node_t *);
2235     char *score = va_arg(args, char *);
2236 
2237     out->list_item(out, NULL, "%s promotion score on %s: %s",
2238                    child_rsc->id,
2239                    chosen? chosen->details->uname : "none",
2240                    score);
2241     return pcmk_rc_ok;
2242 }
2243 
2244 PCMK__OUTPUT_ARGS("promotion-score", "pe_resource_t *", "pe_node_t *", "char *")
     /* [previous][next][first][last][top][bottom][index][help] */
2245 static int
2246 promotion_score_xml(pcmk__output_t *out, va_list args)
2247 {
2248     pe_resource_t *child_rsc = va_arg(args, pe_resource_t *);
2249     pe_node_t *chosen = va_arg(args, pe_node_t *);
2250     char *score = va_arg(args, char *);
2251 
2252     xmlNodePtr node = pcmk__output_create_xml_node(out, "promotion_score",
2253                                                    "id", child_rsc->id,
2254                                                    "score", score,
2255                                                    NULL);
2256 
2257     if (chosen) {
2258         crm_xml_add(node, "node", chosen->details->uname);
2259     }
2260 
2261     return pcmk_rc_ok;
2262 }
2263 
2264 PCMK__OUTPUT_ARGS("resource-config", "pe_resource_t *", "gboolean")
     /* [previous][next][first][last][top][bottom][index][help] */
2265 static int
2266 resource_config(pcmk__output_t *out, va_list args) {
2267     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2268     gboolean raw = va_arg(args, gboolean);
2269 
2270     char *rsc_xml = NULL;
2271 
2272     if (raw) {
2273         rsc_xml = dump_xml_formatted(rsc->orig_xml ? rsc->orig_xml : rsc->xml);
2274     } else {
2275         rsc_xml = dump_xml_formatted(rsc->xml);
2276     }
2277 
2278     pcmk__formatted_printf(out, "Resource XML:\n");
2279     out->output_xml(out, "xml", rsc_xml);
2280 
2281     free(rsc_xml);
2282     return pcmk_rc_ok;
2283 }
2284 
2285 PCMK__OUTPUT_ARGS("resource-history", "pe_resource_t *", "const char *", "gboolean", "int", "time_t", "gboolean")
     /* [previous][next][first][last][top][bottom][index][help] */
2286 static int
2287 resource_history_text(pcmk__output_t *out, va_list args) {
2288     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2289     const char *rsc_id = va_arg(args, const char *);
2290     gboolean all = va_arg(args, gboolean);
2291     int failcount = va_arg(args, int);
2292     time_t last_failure = va_arg(args, int);
2293     gboolean as_header = va_arg(args, gboolean);
2294 
2295     char *buf = resource_history_string(rsc, rsc_id, all, failcount, last_failure);
2296 
2297     if (as_header) {
2298         out->begin_list(out, NULL, NULL, "%s", buf);
2299     } else {
2300         out->list_item(out, NULL, "%s", buf);
2301     }
2302 
2303     free(buf);
2304     return pcmk_rc_ok;
2305 }
2306 
2307 PCMK__OUTPUT_ARGS("resource-history", "pe_resource_t *", "const char *", "gboolean", "int", "time_t", "gboolean")
     /* [previous][next][first][last][top][bottom][index][help] */
2308 static int
2309 resource_history_xml(pcmk__output_t *out, va_list args) {
2310     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2311     const char *rsc_id = va_arg(args, const char *);
2312     gboolean all = va_arg(args, gboolean);
2313     int failcount = va_arg(args, int);
2314     time_t last_failure = va_arg(args, int);
2315     gboolean as_header = va_arg(args, gboolean);
2316 
2317     xmlNodePtr node = pcmk__output_xml_create_parent(out, "resource_history",
2318                                                      "id", rsc_id,
2319                                                      NULL);
2320 
2321     if (rsc == NULL) {
2322         crm_xml_add(node, "orphan", "true");
2323     } else if (all || failcount || last_failure > 0) {
2324         char *migration_s = pcmk__itoa(rsc->migration_threshold);
2325 
2326         pcmk__xe_set_props(node, "orphan", "false",
2327                            "migration-threshold", migration_s,
2328                            NULL);
2329         free(migration_s);
2330 
2331         if (failcount > 0) {
2332             char *s = pcmk__itoa(failcount);
2333 
2334             crm_xml_add(node, PCMK__FAIL_COUNT_PREFIX, s);
2335             free(s);
2336         }
2337 
2338         if (last_failure > 0) {
2339             crm_xml_add(node, PCMK__LAST_FAILURE_PREFIX, pcmk__epoch2str(&last_failure));
2340         }
2341     }
2342 
2343     if (as_header == FALSE) {
2344         pcmk__output_xml_pop_parent(out);
2345     }
2346 
2347     return pcmk_rc_ok;
2348 }
2349 
2350 static void
2351 print_resource_header(pcmk__output_t *out, unsigned int show_opts)
     /* [previous][next][first][last][top][bottom][index][help] */
2352 {
2353     if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2354         /* Active resources have already been printed by node */
2355         out->begin_list(out, NULL, NULL, "Inactive Resources");
2356     } else if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
2357         out->begin_list(out, NULL, NULL, "Full List of Resources");
2358     } else {
2359         out->begin_list(out, NULL, NULL, "Active Resources");
2360     }
2361 }
2362 
2363 
2364 PCMK__OUTPUT_ARGS("resource-list", "pe_working_set_t *", "unsigned int",
     /* [previous][next][first][last][top][bottom][index][help] */
2365                   "gboolean", "GList *", "GList *", "gboolean")
2366 static int
2367 resource_list(pcmk__output_t *out, va_list args)
2368 {
2369     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
2370     unsigned int show_opts = va_arg(args, unsigned int);
2371     gboolean print_summary = va_arg(args, gboolean);
2372     GList *only_node = va_arg(args, GList *);
2373     GList *only_rsc = va_arg(args, GList *);
2374     gboolean print_spacer = va_arg(args, gboolean);
2375 
2376     GList *rsc_iter;
2377     int rc = pcmk_rc_no_output;
2378     bool printed_header = false;
2379 
2380     /* If we already showed active resources by node, and
2381      * we're not showing inactive resources, we have nothing to do
2382      */
2383     if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node) &&
2384         !pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
2385         return rc;
2386     }
2387 
2388     /* If we haven't already printed resources grouped by node,
2389      * and brief output was requested, print resource summary */
2390     if (pcmk_is_set(show_opts, pcmk_show_brief) && !pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2391         GList *rscs = pe__filter_rsc_list(data_set->resources, only_rsc);
2392 
2393         PCMK__OUTPUT_SPACER_IF(out, print_spacer);
2394         print_resource_header(out, show_opts);
2395         printed_header = true;
2396 
2397         rc = pe__rscs_brief_output(out, rscs, show_opts);
2398         g_list_free(rscs);
2399     }
2400 
2401     /* For each resource, display it if appropriate */
2402     for (rsc_iter = data_set->resources; rsc_iter != NULL; rsc_iter = rsc_iter->next) {
2403         pe_resource_t *rsc = (pe_resource_t *) rsc_iter->data;
2404         int x;
2405 
2406         /* Complex resources may have some sub-resources active and some inactive */
2407         gboolean is_active = rsc->fns->active(rsc, TRUE);
2408         gboolean partially_active = rsc->fns->active(rsc, FALSE);
2409 
2410         /* Skip inactive orphans (deleted but still in CIB) */
2411         if (pcmk_is_set(rsc->flags, pe_rsc_orphan) && !is_active) {
2412             continue;
2413 
2414         /* Skip active resources if we already displayed them by node */
2415         } else if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2416             if (is_active) {
2417                 continue;
2418             }
2419 
2420         /* Skip primitives already counted in a brief summary */
2421         } else if (pcmk_is_set(show_opts, pcmk_show_brief) && (rsc->variant == pe_native)) {
2422             continue;
2423 
2424         /* Skip resources that aren't at least partially active,
2425          * unless we're displaying inactive resources
2426          */
2427         } else if (!partially_active && !pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
2428             continue;
2429 
2430         } else if (partially_active && !pe__rsc_running_on_any(rsc, only_node)) {
2431             continue;
2432         }
2433 
2434         if (!printed_header) {
2435             PCMK__OUTPUT_SPACER_IF(out, print_spacer);
2436             print_resource_header(out, show_opts);
2437             printed_header = true;
2438         }
2439 
2440         /* Print this resource */
2441         x = out->message(out, crm_map_element_name(rsc->xml), show_opts, rsc,
2442                          only_node, only_rsc);
2443         if (x == pcmk_rc_ok) {
2444             rc = pcmk_rc_ok;
2445         }
2446     }
2447 
2448     if (print_summary && rc != pcmk_rc_ok) {
2449         if (!printed_header) {
2450             PCMK__OUTPUT_SPACER_IF(out, print_spacer);
2451             print_resource_header(out, show_opts);
2452             printed_header = true;
2453         }
2454 
2455         if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2456             out->list_item(out, NULL, "No inactive resources");
2457         } else if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
2458             out->list_item(out, NULL, "No resources");
2459         } else {
2460             out->list_item(out, NULL, "No active resources");
2461         }
2462     }
2463 
2464     if (printed_header) {
2465         out->end_list(out);
2466     }
2467 
2468     return rc;
2469 }
2470 
2471 PCMK__OUTPUT_ARGS("resource-operation-list", "pe_working_set_t *", "pe_resource_t *",
     /* [previous][next][first][last][top][bottom][index][help] */
2472                   "pe_node_t *", "GList *", "unsigned int")
2473 static int
2474 resource_operation_list(pcmk__output_t *out, va_list args)
2475 {
2476     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
2477     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2478     pe_node_t *node = va_arg(args, pe_node_t *);
2479     GList *op_list = va_arg(args, GList *);
2480     unsigned int show_opts = va_arg(args, unsigned int);
2481 
2482     GList *gIter = NULL;
2483     int rc = pcmk_rc_no_output;
2484 
2485     /* Print each operation */
2486     for (gIter = op_list; gIter != NULL; gIter = gIter->next) {
2487         xmlNode *xml_op = (xmlNode *) gIter->data;
2488         const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
2489         const char *interval_ms_s = crm_element_value(xml_op,
2490                                                       XML_LRM_ATTR_INTERVAL_MS);
2491         const char *op_rc = crm_element_value(xml_op, XML_LRM_ATTR_RC);
2492         int op_rc_i;
2493 
2494         pcmk__scan_min_int(op_rc, &op_rc_i, 0);
2495 
2496         /* Display 0-interval monitors as "probe" */
2497         if (pcmk__str_eq(task, CRMD_ACTION_STATUS, pcmk__str_casei)
2498             && pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches | pcmk__str_casei)) {
2499             task = "probe";
2500         }
2501 
2502         /* If this is the first printed operation, print heading for resource */
2503         if (rc == pcmk_rc_no_output) {
2504             time_t last_failure = 0;
2505             int failcount = pe_get_failcount(node, rsc, &last_failure, pe_fc_default,
2506                                              NULL, data_set);
2507 
2508             out->message(out, "resource-history", rsc, rsc_printable_id(rsc), TRUE,
2509                          failcount, last_failure, TRUE);
2510             rc = pcmk_rc_ok;
2511         }
2512 
2513         /* Print the operation */
2514         out->message(out, "op-history", xml_op, task, interval_ms_s,
2515                      op_rc_i, show_opts);
2516     }
2517 
2518     /* Free the list we created (no need to free the individual items) */
2519     g_list_free(op_list);
2520 
2521     PCMK__OUTPUT_LIST_FOOTER(out, rc);
2522     return rc;
2523 }
2524 
2525 PCMK__OUTPUT_ARGS("resource-util", "pe_resource_t *", "pe_node_t *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
2526 static int
2527 resource_util(pcmk__output_t *out, va_list args)
2528 {
2529     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2530     pe_node_t *node = va_arg(args, pe_node_t *);
2531     const char *fn = va_arg(args, const char *);
2532 
2533     char *dump_text = crm_strdup_printf("%s: %s utilization on %s:",
2534                                         fn, rsc->id, node->details->uname);
2535 
2536     g_hash_table_foreach(rsc->utilization, append_dump_text, &dump_text);
2537     out->list_item(out, NULL, "%s", dump_text);
2538     free(dump_text);
2539 
2540     return pcmk_rc_ok;
2541 }
2542 
2543 PCMK__OUTPUT_ARGS("resource-util", "pe_resource_t *", "pe_node_t *", "const char *")
     /* [previous][next][first][last][top][bottom][index][help] */
2544 static int
2545 resource_util_xml(pcmk__output_t *out, va_list args)
2546 {
2547     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2548     pe_node_t *node = va_arg(args, pe_node_t *);
2549     const char *fn = va_arg(args, const char *);
2550 
2551     xmlNodePtr xml_node = pcmk__output_create_xml_node(out, "utilization",
2552                                                        "resource", rsc->id,
2553                                                        "node", node->details->uname,
2554                                                        "function", fn,
2555                                                        NULL);
2556     g_hash_table_foreach(rsc->utilization, add_dump_node, xml_node);
2557 
2558     return pcmk_rc_ok;
2559 }
2560 
2561 PCMK__OUTPUT_ARGS("ticket", "pe_ticket_t *")
     /* [previous][next][first][last][top][bottom][index][help] */
2562 static int
2563 ticket_html(pcmk__output_t *out, va_list args) {
2564     pe_ticket_t *ticket = va_arg(args, pe_ticket_t *);
2565 
2566     if (ticket->last_granted > -1) {
2567         char *time = pcmk__format_named_time("last-granted",
2568                                              ticket->last_granted);
2569 
2570         out->list_item(out, NULL, "%s:\t%s%s %s", ticket->id,
2571                        ticket->granted ? "granted" : "revoked",
2572                        ticket->standby ? " [standby]" : "",
2573                        time);
2574         free(time);
2575     } else {
2576         out->list_item(out, NULL, "%s:\t%s%s", ticket->id,
2577                        ticket->granted ? "granted" : "revoked",
2578                        ticket->standby ? " [standby]" : "");
2579     }
2580 
2581     return pcmk_rc_ok;
2582 }
2583 
2584 PCMK__OUTPUT_ARGS("ticket", "pe_ticket_t *")
     /* [previous][next][first][last][top][bottom][index][help] */
2585 static int
2586 ticket_text(pcmk__output_t *out, va_list args) {
2587     pe_ticket_t *ticket = va_arg(args, pe_ticket_t *);
2588 
2589     if (ticket->last_granted > -1) {
2590         char *time = pcmk__format_named_time("last-granted",
2591                                              ticket->last_granted);
2592 
2593         out->list_item(out, ticket->id, "%s%s %s",
2594                        ticket->granted ? "granted" : "revoked",
2595                        ticket->standby ? " [standby]" : "",
2596                        time);
2597         free(time);
2598     } else {
2599         out->list_item(out, ticket->id, "%s%s",
2600                        ticket->granted ? "granted" : "revoked",
2601                        ticket->standby ? " [standby]" : "");
2602     }
2603 
2604     return pcmk_rc_ok;
2605 }
2606 
2607 PCMK__OUTPUT_ARGS("ticket", "pe_ticket_t *")
     /* [previous][next][first][last][top][bottom][index][help] */
2608 static int
2609 ticket_xml(pcmk__output_t *out, va_list args) {
2610     pe_ticket_t *ticket = va_arg(args, pe_ticket_t *);
2611 
2612     xmlNodePtr node = NULL;
2613 
2614     node = pcmk__output_create_xml_node(out, "ticket",
2615                                         "id", ticket->id,
2616                                         "status", ticket->granted ? "granted" : "revoked",
2617                                         "standby", pcmk__btoa(ticket->standby),
2618                                         NULL);
2619 
2620     if (ticket->last_granted > -1) {
2621         crm_xml_add(node, "last-granted", pcmk__epoch2str(&ticket->last_granted));
2622     }
2623 
2624     return pcmk_rc_ok;
2625 }
2626 
2627 PCMK__OUTPUT_ARGS("ticket-list", "pe_working_set_t *", "gboolean")
     /* [previous][next][first][last][top][bottom][index][help] */
2628 static int
2629 ticket_list(pcmk__output_t *out, va_list args) {
2630     pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
2631     gboolean print_spacer = va_arg(args, gboolean);
2632 
2633     GHashTableIter iter;
2634     gpointer key, value;
2635 
2636     if (g_hash_table_size(data_set->tickets) == 0) {
2637         return pcmk_rc_no_output;
2638     }
2639 
2640     PCMK__OUTPUT_SPACER_IF(out, print_spacer);
2641 
2642     /* Print section heading */
2643     out->begin_list(out, NULL, NULL, "Tickets");
2644 
2645     /* Print each ticket */
2646     g_hash_table_iter_init(&iter, data_set->tickets);
2647     while (g_hash_table_iter_next(&iter, &key, &value)) {
2648         pe_ticket_t *ticket = (pe_ticket_t *) value;
2649         out->message(out, "ticket", ticket);
2650     }
2651 
2652     /* Close section */
2653     out->end_list(out);
2654     return pcmk_rc_ok;
2655 }
2656 
2657 static pcmk__message_entry_t fmt_functions[] = {
2658     { "ban", "default", ban_text },
2659     { "ban", "html", ban_html },
2660     { "ban", "xml", ban_xml },
2661     { "ban-list", "default", ban_list },
2662     { "bundle", "default", pe__bundle_text },
2663     { "bundle", "xml",  pe__bundle_xml },
2664     { "bundle", "html",  pe__bundle_html },
2665     { "clone", "default", pe__clone_default },
2666     { "clone", "xml",  pe__clone_xml },
2667     { "cluster-counts", "default", cluster_counts_text },
2668     { "cluster-counts", "html", cluster_counts_html },
2669     { "cluster-counts", "xml", cluster_counts_xml },
2670     { "cluster-dc", "default", cluster_dc_text },
2671     { "cluster-dc", "html", cluster_dc_html },
2672     { "cluster-dc", "xml", cluster_dc_xml },
2673     { "cluster-options", "default", cluster_options_text },
2674     { "cluster-options", "html", cluster_options_html },
2675     { "cluster-options", "log", cluster_options_log },
2676     { "cluster-options", "xml", cluster_options_xml },
2677     { "cluster-summary", "default", cluster_summary },
2678     { "cluster-summary", "html", cluster_summary_html },
2679     { "cluster-stack", "default", cluster_stack_text },
2680     { "cluster-stack", "html", cluster_stack_html },
2681     { "cluster-stack", "xml", cluster_stack_xml },
2682     { "cluster-times", "default", cluster_times_text },
2683     { "cluster-times", "html", cluster_times_html },
2684     { "cluster-times", "xml", cluster_times_xml },
2685     { "failed-action", "default", failed_action_text },
2686     { "failed-action", "xml", failed_action_xml },
2687     { "failed-action-list", "default", failed_action_list },
2688     { "group", "default",  pe__group_default},
2689     { "group", "xml",  pe__group_xml },
2690     { "maint-mode", "text", cluster_maint_mode_text },
2691     { "node", "default", node_text },
2692     { "node", "html", node_html },
2693     { "node", "xml", node_xml },
2694     { "node-and-op", "default", node_and_op },
2695     { "node-and-op", "xml", node_and_op_xml },
2696     { "node-capacity", "default", node_capacity },
2697     { "node-capacity", "xml", node_capacity_xml },
2698     { "node-history-list", "default", node_history_list },
2699     { "node-list", "default", node_list_text },
2700     { "node-list", "html", node_list_html },
2701     { "node-list", "xml", node_list_xml },
2702     { "node-weight", "default", node_weight },
2703     { "node-weight", "xml", node_weight_xml },
2704     { "node-attribute", "default", node_attribute_text },
2705     { "node-attribute", "html", node_attribute_html },
2706     { "node-attribute", "xml", node_attribute_xml },
2707     { "node-attribute-list", "default", node_attribute_list },
2708     { "node-summary", "default", node_summary },
2709     { "op-history", "default", op_history_text },
2710     { "op-history", "xml", op_history_xml },
2711     { "primitive", "default",  pe__resource_text },
2712     { "primitive", "xml",  pe__resource_xml },
2713     { "primitive", "html",  pe__resource_html },
2714     { "promotion-score", "default", promotion_score },
2715     { "promotion-score", "xml", promotion_score_xml },
2716     { "resource-config", "default", resource_config },
2717     { "resource-history", "default", resource_history_text },
2718     { "resource-history", "xml", resource_history_xml },
2719     { "resource-list", "default", resource_list },
2720     { "resource-operation-list", "default", resource_operation_list },
2721     { "resource-util", "default", resource_util },
2722     { "resource-util", "xml", resource_util_xml },
2723     { "ticket", "default", ticket_text },
2724     { "ticket", "html", ticket_html },
2725     { "ticket", "xml", ticket_xml },
2726     { "ticket-list", "default", ticket_list },
2727 
2728     { NULL, NULL, NULL }
2729 };
2730 
2731 void
2732 pe__register_messages(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
2733     pcmk__register_messages(out, fmt_functions);
2734 }
2735 
2736 void
2737 pe__output_node(pe_node_t *node, gboolean details, pcmk__output_t *out)
     /* [previous][next][first][last][top][bottom][index][help] */
2738 {
2739     if (node == NULL) {
2740         crm_trace("<NULL>");
2741         return;
2742     }
2743 
2744     CRM_ASSERT(node->details);
2745     crm_trace("%sNode %s: (weight=%d, fixed=%s)",
2746               node->details->online ? "" : "Unavailable/Unclean ",
2747               node->details->uname, node->weight, node->fixed ? "True" : "False");
2748 
2749     if (details) {
2750         char *pe_mutable = strdup("\t\t");
2751         GList *gIter = node->details->running_rsc;
2752         GList *all = NULL;
2753 
2754         all = g_list_prepend(all, (gpointer) "*");
2755 
2756         crm_trace("\t\t===Node Attributes");
2757         g_hash_table_foreach(node->details->attrs, print_str_str, pe_mutable);
2758         free(pe_mutable);
2759 
2760         crm_trace("\t\t=== Resources");
2761 
2762         for (; gIter != NULL; gIter = gIter->next) {
2763             pe_resource_t *rsc = (pe_resource_t *) gIter->data;
2764 
2765             out->message(out, crm_map_element_name(rsc->xml),
2766                          pe_print_pending, rsc, all, all);
2767         }
2768 
2769         g_list_free(all);
2770     }
2771 }

/* [previous][next][first][last][top][bottom][index][help] */