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