pacemaker  2.1.2-ada5c3b36
Scalable High-Availability cluster resource manager
pe_output.c
Go to the documentation of this file.
1 /*
2  * Copyright 2019-2021 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
12 #include <crm/common/output.h>
13 #include <crm/cib/util.h>
14 #include <crm/msg_xml.h>
15 #include <crm/pengine/internal.h>
16 
17 /* Never display node attributes whose name starts with one of these prefixes */
18 #define FILTER_STR { PCMK__FAIL_COUNT_PREFIX, PCMK__LAST_FAILURE_PREFIX, \
19  "shutdown", "terminate", "standby", "probe_complete", \
20  "#", 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 *", "unsigned int", "unsigned int")
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  unsigned int section_opts = va_arg(args, unsigned int);
317  unsigned int show_opts = va_arg(args, unsigned int);
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);
343  const char *user = crm_element_value(data_set->input, XML_ATTR_UPDATE_USER);
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),
354  data_set->ninstances, data_set->disabled_resources,
355  data_set->blocked_resources);
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 
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 *", "unsigned int", "unsigned int")
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  unsigned int section_opts = va_arg(args, unsigned int);
379  unsigned int show_opts = va_arg(args, unsigned int);
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);
406  const char *user = crm_element_value(data_set->input, XML_ATTR_UPDATE_USER);
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),
417  data_set->ninstances, data_set->disabled_resources,
418  data_set->blocked_resources);
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  */
427 
428  out->begin_list(out, NULL, NULL, "Config Options");
429  out->message(out, "cluster-options", data_set);
430  }
431 
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 *", "unsigned int")
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  unsigned int show_opts = va_arg(args, unsigned int);
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 *", "unsigned int")
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  unsigned int show_opts = va_arg(args, unsigned int);
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 *", "unsigned int")
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  unsigned int show_opts G_GNUC_UNUSED = va_arg(args, unsigned int);
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  "unsigned int", "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  unsigned int show_opts = va_arg(args, unsigned int);
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 
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 
901  if (pcmk_is_set(data_set->flags, pe_flag_maintenance_mode)) {
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)");
908  } else if (pcmk_is_set(data_set->flags, pe_flag_stop_everything)) {
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 
927  if (pcmk_is_set(data_set->flags, pe_flag_maintenance_mode)) {
928  return out->info(out, "Resource management is DISABLED. The cluster will not attempt to start, stop or recover services.");
929  } else if (pcmk_is_set(data_set->flags, pe_flag_stop_everything)) {
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 
1139  str = g_string_sized_new(strlen(rsc_id) + strlen(task) + strlen(node_name)
1140  + 100); // reasonable starting size
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  } else {
1155  g_string_append_printf(str, " could not be executed (%s)",
1156  pcmk_exec_status_str(status));
1157  }
1158 
1159  if (!pcmk__str_empty(exit_reason)) {
1160  g_string_append_printf(str, " because '%s'", exit_reason);
1161  }
1162 
1164  &last_change_epoch) == pcmk_ok) {
1165  last_change_str = pcmk__epoch2str(&last_change_epoch);
1166  if (last_change_str != NULL) {
1167  g_string_append_printf(str, " at %s", last_change_str);
1168  }
1169  }
1170  if (!pcmk__str_empty(exec_time)) {
1171  int exec_time_ms = 0;
1172 
1173  if ((pcmk__scan_min_int(exec_time, &exec_time_ms, 0) == pcmk_rc_ok)
1174  && (exec_time_ms > 0)) {
1175  g_string_append_printf(str, " after %s",
1176  pcmk__readable_interval(exec_time_ms));
1177  }
1178  }
1179 
1180  out->list_item(out, NULL, "%s", str->str);
1181  g_string_free(str, TRUE);
1182  free(rsc_id);
1183  free(task);
1184 }
1185 
1190 static void
1191 failed_action_technical(pcmk__output_t *out, xmlNodePtr xml_op,
1192  const char *op_key, const char *node_name, int rc,
1193  int status, const char *exit_reason,
1194  const char *exec_time)
1195 {
1196  const char *call_id = crm_element_value(xml_op, XML_LRM_ATTR_CALLID);
1197  const char *queue_time = crm_element_value(xml_op, XML_RSC_OP_T_QUEUE);
1198  const char *exit_status = services_ocf_exitcode_str(rc);
1199  const char *lrm_status = pcmk_exec_status_str(status);
1200  const char *last_change_str = NULL;
1201  time_t last_change_epoch = 0;
1202  GString *str = NULL;
1203 
1204  if (pcmk__str_empty(op_key)) {
1205  op_key = "unknown operation";
1206  }
1207  if (pcmk__str_empty(exit_status)) {
1208  exit_status = "unknown exit status";
1209  }
1210  if (pcmk__str_empty(call_id)) {
1211  call_id = "unknown";
1212  }
1213 
1214  str = g_string_sized_new(strlen(op_key) + strlen(node_name)
1215  + strlen(exit_status) + strlen(call_id)
1216  + strlen(lrm_status) + 50); // rough estimate
1217 
1218  g_string_printf(str, "%s on %s '%s' (%d): call=%s, status='%s'",
1219  op_key, node_name, exit_status, rc, call_id, lrm_status);
1220 
1221  if (!pcmk__str_empty(exit_reason)) {
1222  g_string_append_printf(str, ", exitreason='%s'", exit_reason);
1223  }
1224 
1226  &last_change_epoch) == pcmk_ok) {
1227  last_change_str = pcmk__epoch2str(&last_change_epoch);
1228  if (last_change_str != NULL) {
1229  g_string_append_printf(str, ", " XML_RSC_OP_LAST_CHANGE "='%s'",
1230  last_change_str);
1231  }
1232  }
1233  if (!pcmk__str_empty(queue_time)) {
1234  g_string_append_printf(str, ", queued=%sms", queue_time);
1235  }
1236  if (!pcmk__str_empty(exec_time)) {
1237  g_string_append_printf(str, ", exec=%sms", exec_time);
1238  }
1239 
1240  out->list_item(out, NULL, "%s", str->str);
1241  g_string_free(str, TRUE);
1242 }
1243 
1244 PCMK__OUTPUT_ARGS("failed-action", "xmlNodePtr", "unsigned int")
1245 static int
1246 failed_action_default(pcmk__output_t *out, va_list args)
1247 {
1248  xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1249  unsigned int show_opts = va_arg(args, unsigned int);
1250 
1251  const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
1252  const char *node_name = crm_element_value(xml_op, XML_ATTR_UNAME);
1253  const char *exit_reason = crm_element_value(xml_op,
1255  const char *exec_time = crm_element_value(xml_op, XML_RSC_OP_T_EXEC);
1256 
1257  int rc;
1258  int status;
1259 
1261 
1263  &status, 0);
1264 
1265  if (pcmk__str_empty(op_key)) {
1266  op_key = ID(xml_op);
1267  }
1268  if (pcmk__str_empty(node_name)) {
1269  node_name = "unknown node";
1270  }
1271 
1272  if (pcmk_is_set(show_opts, pcmk_show_failed_detail)) {
1273  failed_action_technical(out, xml_op, op_key, node_name, rc, status,
1274  exit_reason, exec_time);
1275  } else {
1276  failed_action_friendly(out, xml_op, op_key, node_name, rc, status,
1277  exit_reason, exec_time);
1278  }
1279  return pcmk_rc_ok;
1280 }
1281 
1282 PCMK__OUTPUT_ARGS("failed-action", "xmlNodePtr", "unsigned int")
1283 static int
1284 failed_action_xml(pcmk__output_t *out, va_list args) {
1285  xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1286  unsigned int show_opts G_GNUC_UNUSED = va_arg(args, unsigned int);
1287 
1288  const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
1289  int rc;
1290  int status;
1291  const char *exit_reason = crm_element_value(xml_op, XML_LRM_ATTR_EXIT_REASON);
1292 
1293  time_t epoch = 0;
1294  char *rc_s = NULL;
1295  char *reason_s = crm_xml_escape(exit_reason ? exit_reason : "none");
1296  xmlNodePtr node = NULL;
1297 
1300  &status, 0);
1301 
1302  rc_s = pcmk__itoa(rc);
1303  node = pcmk__output_create_xml_node(out, "failure",
1304  (op_key == NULL)? "id" : "op_key",
1305  (op_key == NULL)? ID(xml_op) : op_key,
1306  "node", crm_element_value(xml_op, XML_ATTR_UNAME),
1307  "exitstatus", services_ocf_exitcode_str(rc),
1308  "exitreason", crm_str(reason_s),
1309  "exitcode", rc_s,
1310  "call", crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
1311  "status", pcmk_exec_status_str(status),
1312  NULL);
1313  free(rc_s);
1314 
1316  &epoch) == pcmk_ok) && (epoch > 0)) {
1317  guint interval_ms = 0;
1318  char *s = NULL;
1319  crm_time_t *crm_when = crm_time_new_undefined();
1320  char *rc_change = NULL;
1321 
1322  crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
1323  s = pcmk__itoa(interval_ms);
1324 
1325  crm_time_set_timet(crm_when, &epoch);
1327 
1328  pcmk__xe_set_props(node, XML_RSC_OP_LAST_CHANGE, rc_change,
1329  "queued", crm_element_value(xml_op, XML_RSC_OP_T_QUEUE),
1330  "exec", crm_element_value(xml_op, XML_RSC_OP_T_EXEC),
1331  "interval", s,
1332  "task", crm_element_value(xml_op, XML_LRM_ATTR_TASK),
1333  NULL);
1334 
1335  free(s);
1336  free(rc_change);
1337  crm_time_free(crm_when);
1338  }
1339 
1340  free(reason_s);
1341  return pcmk_rc_ok;
1342 }
1343 
1344 PCMK__OUTPUT_ARGS("failed-action-list", "pe_working_set_t *", "GList *",
1345  "GList *", "unsigned int", "gboolean")
1346 static int
1347 failed_action_list(pcmk__output_t *out, va_list args) {
1348  pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1349  GList *only_node = va_arg(args, GList *);
1350  GList *only_rsc = va_arg(args, GList *);
1351  unsigned int show_opts = va_arg(args, gboolean);
1352  gboolean print_spacer = va_arg(args, gboolean);
1353 
1354  xmlNode *xml_op = NULL;
1355  int rc = pcmk_rc_no_output;
1356 
1357  const char *id = NULL;
1358 
1359  if (xmlChildElementCount(data_set->failed) == 0) {
1360  return rc;
1361  }
1362 
1363  for (xml_op = pcmk__xml_first_child(data_set->failed); xml_op != NULL;
1364  xml_op = pcmk__xml_next(xml_op)) {
1365  char *rsc = NULL;
1366 
1367  if (!pcmk__str_in_list(crm_element_value(xml_op, XML_ATTR_UNAME), only_node,
1369  continue;
1370  }
1371 
1373  if (parse_op_key(id ? id : ID(xml_op), &rsc, NULL, NULL) == FALSE) {
1374  continue;
1375  }
1376 
1377  if (!pcmk__str_in_list(rsc, only_rsc, pcmk__str_star_matches)) {
1378  free(rsc);
1379  continue;
1380  }
1381 
1382  free(rsc);
1383 
1384  PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Failed Resource Actions");
1385  out->message(out, "failed-action", xml_op, show_opts);
1386  }
1387 
1389  return rc;
1390 }
1391 
1392 static void
1393 status_node(pe_node_t *node, xmlNodePtr parent)
1394 {
1395  if (node->details->standby_onfail && node->details->online) {
1396  pcmk_create_html_node(parent, "span", NULL, "standby", " standby (on-fail)");
1397  } else if (node->details->standby && node->details->online) {
1398  char *s = crm_strdup_printf(" standby%s", node->details->running_rsc ? " (with active resources)" : "");
1399  pcmk_create_html_node(parent, "span", NULL, " standby", s);
1400  free(s);
1401  } else if (node->details->standby) {
1402  pcmk_create_html_node(parent, "span", NULL, "offline", " OFFLINE (standby)");
1403  } else if (node->details->maintenance && node->details->online) {
1404  pcmk_create_html_node(parent, "span", NULL, "maint", " maintenance");
1405  } else if (node->details->maintenance) {
1406  pcmk_create_html_node(parent, "span", NULL, "offline", " OFFLINE (maintenance)");
1407  } else 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 
1414 PCMK__OUTPUT_ARGS("node", "pe_node_t *", "unsigned int", "gboolean", "const char *",
1415  "GList *", "GList *")
1416 static int
1417 node_html(pcmk__output_t *out, va_list args) {
1418  pe_node_t *node = va_arg(args, pe_node_t *);
1419  unsigned int show_opts = va_arg(args, unsigned int);
1420  gboolean full = va_arg(args, gboolean);
1421  const char *node_mode G_GNUC_UNUSED = va_arg(args, const char *);
1422  GList *only_node = va_arg(args, GList *);
1423  GList *only_rsc = va_arg(args, GList *);
1424 
1425  char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1426 
1427  if (full) {
1428  xmlNodePtr item_node;
1429 
1430  if (pcmk_all_flags_set(show_opts, pcmk_show_brief | pcmk_show_rscs_by_node)) {
1431  GList *rscs = pe__filter_rsc_list(node->details->running_rsc, only_rsc);
1432 
1433  out->begin_list(out, NULL, NULL, "Node: %s", node_name);
1434  item_node = pcmk__output_xml_create_parent(out, "li", NULL);
1435  pcmk_create_html_node(item_node, "span", NULL, NULL, "Status:");
1436  status_node(node, item_node);
1437 
1438  if (rscs != NULL) {
1439  unsigned int new_show_opts = (show_opts | pcmk_show_rsc_only) & ~pcmk_show_inactive_rscs;
1440  out->begin_list(out, NULL, NULL, "Resources");
1441  pe__rscs_brief_output(out, rscs, new_show_opts);
1442  out->end_list(out);
1443  }
1444 
1446  out->end_list(out);
1447 
1448  } else if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
1449  GList *lpc2 = NULL;
1450  int rc = pcmk_rc_no_output;
1451 
1452  out->begin_list(out, NULL, NULL, "Node: %s", node_name);
1453  item_node = pcmk__output_xml_create_parent(out, "li", NULL);
1454  pcmk_create_html_node(item_node, "span", NULL, NULL, "Status:");
1455  status_node(node, item_node);
1456 
1457  for (lpc2 = node->details->running_rsc; lpc2 != NULL; lpc2 = lpc2->next) {
1458  pe_resource_t *rsc = (pe_resource_t *) lpc2->data;
1459  PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Resources");
1460 
1461  out->message(out, crm_map_element_name(rsc->xml), show_opts | pcmk_show_rsc_only,
1462  rsc, only_node, only_rsc);
1463  }
1464 
1467  out->end_list(out);
1468 
1469  } else {
1470  char *buf = crm_strdup_printf("Node: %s", node_name);
1471 
1472  item_node = pcmk__output_create_xml_node(out, "li", NULL);
1473  pcmk_create_html_node(item_node, "span", NULL, NULL, buf);
1474  status_node(node, item_node);
1475 
1476  free(buf);
1477  }
1478  } else {
1479  out->begin_list(out, NULL, NULL, "Node: %s", node_name);
1480  }
1481 
1482  free(node_name);
1483  return pcmk_rc_ok;
1484 }
1485 
1486 PCMK__OUTPUT_ARGS("node", "pe_node_t *", "unsigned int", "gboolean", "const char *",
1487  "GList *", "GList *")
1488 static int
1489 node_text(pcmk__output_t *out, va_list args) {
1490  pe_node_t *node = va_arg(args, pe_node_t *);
1491  unsigned int show_opts = va_arg(args, unsigned int);
1492  gboolean full = va_arg(args, gboolean);
1493  const char *node_mode = va_arg(args, const char *);
1494  GList *only_node = va_arg(args, GList *);
1495  GList *only_rsc = va_arg(args, GList *);
1496 
1497  if (full) {
1498  char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1499  char *buf = NULL;
1500 
1501  /* Print the node name and status */
1502  if (pe__is_guest_node(node)) {
1503  buf = crm_strdup_printf("GuestNode %s: %s", node_name, node_mode);
1504  } else if (pe__is_remote_node(node)) {
1505  buf = crm_strdup_printf("RemoteNode %s: %s", node_name, node_mode);
1506  } else {
1507  buf = crm_strdup_printf("Node %s: %s", node_name, node_mode);
1508  }
1509 
1510  /* If we're grouping by node, print its resources */
1511  if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
1512  if (pcmk_is_set(show_opts, pcmk_show_brief)) {
1513  GList *rscs = pe__filter_rsc_list(node->details->running_rsc, only_rsc);
1514 
1515  if (rscs != NULL) {
1516  unsigned int new_show_opts = (show_opts | pcmk_show_rsc_only) & ~pcmk_show_inactive_rscs;
1517  out->begin_list(out, NULL, NULL, "%s", buf);
1518  out->begin_list(out, NULL, NULL, "Resources");
1519 
1520  pe__rscs_brief_output(out, rscs, new_show_opts);
1521 
1522  out->end_list(out);
1523  out->end_list(out);
1524 
1525  g_list_free(rscs);
1526  }
1527 
1528  } else {
1529  GList *gIter2 = NULL;
1530 
1531  out->begin_list(out, NULL, NULL, "%s", buf);
1532  out->begin_list(out, NULL, NULL, "Resources");
1533 
1534  for (gIter2 = node->details->running_rsc; gIter2 != NULL; gIter2 = gIter2->next) {
1535  pe_resource_t *rsc = (pe_resource_t *) gIter2->data;
1536  out->message(out, crm_map_element_name(rsc->xml), show_opts | pcmk_show_rsc_only,
1537  rsc, only_node, only_rsc);
1538  }
1539 
1540  out->end_list(out);
1541  out->end_list(out);
1542  }
1543  } else {
1544  out->list_item(out, NULL, "%s", buf);
1545  }
1546 
1547  free(buf);
1548  free(node_name);
1549  } else {
1550  char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1551  out->begin_list(out, NULL, NULL, "Node: %s", node_name);
1552  free(node_name);
1553  }
1554 
1555  return pcmk_rc_ok;
1556 }
1557 
1558 PCMK__OUTPUT_ARGS("node", "pe_node_t *", "unsigned int", "gboolean", "const char *",
1559  "GList *", "GList *")
1560 static int
1561 node_xml(pcmk__output_t *out, va_list args) {
1562  pe_node_t *node = va_arg(args, pe_node_t *);
1563  unsigned int show_opts G_GNUC_UNUSED = va_arg(args, unsigned int);
1564  gboolean full = va_arg(args, gboolean);
1565  const char *node_mode G_GNUC_UNUSED = va_arg(args, const char *);
1566  GList *only_node = va_arg(args, GList *);
1567  GList *only_rsc = va_arg(args, GList *);
1568 
1569  if (full) {
1570  const char *node_type = "unknown";
1571  char *length_s = pcmk__itoa(g_list_length(node->details->running_rsc));
1572 
1573  switch (node->details->type) {
1574  case node_member:
1575  node_type = "member";
1576  break;
1577  case node_remote:
1578  node_type = "remote";
1579  break;
1580  case node_ping:
1581  node_type = "ping";
1582  break;
1583  }
1584  pe__name_and_nvpairs_xml(out, true, "node", 13,
1585  "name", node->details->uname,
1586  "id", node->details->id,
1587  "online", pcmk__btoa(node->details->online),
1588  "standby", pcmk__btoa(node->details->standby),
1589  "standby_onfail", pcmk__btoa(node->details->standby_onfail),
1590  "maintenance", pcmk__btoa(node->details->maintenance),
1591  "pending", pcmk__btoa(node->details->pending),
1592  "unclean", pcmk__btoa(node->details->unclean),
1593  "shutdown", pcmk__btoa(node->details->shutdown),
1594  "expected_up", pcmk__btoa(node->details->expected_up),
1595  "is_dc", pcmk__btoa(node->details->is_dc),
1596  "resources_running", length_s,
1597  "type", node_type);
1598 
1599  if (pe__is_guest_node(node)) {
1600  xmlNodePtr xml_node = pcmk__output_xml_peek_parent(out);
1601  crm_xml_add(xml_node, "id_as_resource", node->details->remote_rsc->container->id);
1602  }
1603 
1604  if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
1605  GList *lpc = NULL;
1606 
1607  for (lpc = node->details->running_rsc; lpc != NULL; lpc = lpc->next) {
1608  pe_resource_t *rsc = (pe_resource_t *) lpc->data;
1609  out->message(out, crm_map_element_name(rsc->xml), show_opts | pcmk_show_rsc_only,
1610  rsc, only_node, only_rsc);
1611  }
1612  }
1613 
1614  free(length_s);
1615 
1616  out->end_list(out);
1617  } else {
1618  pcmk__output_xml_create_parent(out, "node",
1619  "name", node->details->uname,
1620  NULL);
1621  }
1622 
1623  return pcmk_rc_ok;
1624 }
1625 
1626 PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "gboolean", "int")
1627 static int
1628 node_attribute_text(pcmk__output_t *out, va_list args) {
1629  const char *name = va_arg(args, const char *);
1630  const char *value = va_arg(args, const char *);
1631  gboolean add_extra = va_arg(args, gboolean);
1632  int expected_score = va_arg(args, int);
1633 
1634  if (add_extra) {
1635  int v;
1636 
1637  if (value == NULL) {
1638  v = 0;
1639  } else {
1640  pcmk__scan_min_int(value, &v, INT_MIN);
1641  }
1642  if (v <= 0) {
1643  out->list_item(out, NULL, "%-32s\t: %-10s\t: Connectivity is lost", name, value);
1644  } else if (v < expected_score) {
1645  out->list_item(out, NULL, "%-32s\t: %-10s\t: Connectivity is degraded (Expected=%d)", name, value, expected_score);
1646  } else {
1647  out->list_item(out, NULL, "%-32s\t: %-10s", name, value);
1648  }
1649  } else {
1650  out->list_item(out, NULL, "%-32s\t: %-10s", name, value);
1651  }
1652 
1653  return pcmk_rc_ok;
1654 }
1655 
1656 PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "gboolean", "int")
1657 static int
1658 node_attribute_html(pcmk__output_t *out, va_list args) {
1659  const char *name = va_arg(args, const char *);
1660  const char *value = va_arg(args, const char *);
1661  gboolean add_extra = va_arg(args, gboolean);
1662  int expected_score = va_arg(args, int);
1663 
1664  if (add_extra) {
1665  int v;
1666  char *s = crm_strdup_printf("%s: %s", name, value);
1667  xmlNodePtr item_node = pcmk__output_create_xml_node(out, "li", NULL);
1668 
1669  if (value == NULL) {
1670  v = 0;
1671  } else {
1672  pcmk__scan_min_int(value, &v, INT_MIN);
1673  }
1674 
1675  pcmk_create_html_node(item_node, "span", NULL, NULL, s);
1676  free(s);
1677 
1678  if (v <= 0) {
1679  pcmk_create_html_node(item_node, "span", NULL, "bold", "(connectivity is lost)");
1680  } else if (v < expected_score) {
1681  char *buf = crm_strdup_printf("(connectivity is degraded -- expected %d", expected_score);
1682  pcmk_create_html_node(item_node, "span", NULL, "bold", buf);
1683  free(buf);
1684  }
1685  } else {
1686  out->list_item(out, NULL, "%s: %s", name, value);
1687  }
1688 
1689  return pcmk_rc_ok;
1690 }
1691 
1692 PCMK__OUTPUT_ARGS("node-and-op", "pe_working_set_t *", "xmlNodePtr")
1693 static int
1694 node_and_op(pcmk__output_t *out, va_list args) {
1695  pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1696  xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1697 
1698  pe_resource_t *rsc = NULL;
1699  gchar *node_str = NULL;
1700  char *last_change_str = NULL;
1701 
1702  const char *op_rsc = crm_element_value(xml_op, "resource");
1703  const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
1704  int status;
1705  time_t last_change = 0;
1706 
1708  &status, 0);
1709 
1710  rsc = pe_find_resource(data_set->resources, op_rsc);
1711 
1712  if (rsc) {
1713  pe_node_t *node = pe__current_node(rsc);
1714  const char *target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
1715  unsigned int show_opts = pcmk_show_rsc_only | pcmk_show_pending;
1716 
1717  if (node == NULL) {
1718  node = rsc->pending_node;
1719  }
1720 
1721  node_str = pcmk__native_output_string(rsc, rsc_printable_id(rsc), node,
1722  show_opts, target_role, false);
1723  } else {
1724  node_str = crm_strdup_printf("Unknown resource %s", op_rsc);
1725  }
1726 
1728  &last_change) == pcmk_ok) {
1729  last_change_str = crm_strdup_printf(", %s=%s, exec=%sms",
1731  pcmk__trim(ctime(&last_change)),
1733  }
1734 
1735  out->list_item(out, NULL, "%s: %s (node=%s, call=%s, rc=%s%s): %s",
1736  node_str, op_key ? op_key : ID(xml_op),
1740  last_change_str ? last_change_str : "",
1741  pcmk_exec_status_str(status));
1742 
1743  g_free(node_str);
1744  free(last_change_str);
1745  return pcmk_rc_ok;
1746 }
1747 
1748 PCMK__OUTPUT_ARGS("node-and-op", "pe_working_set_t *", "xmlNodePtr")
1749 static int
1750 node_and_op_xml(pcmk__output_t *out, va_list args) {
1751  pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1752  xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1753 
1754  pe_resource_t *rsc = NULL;
1755  const char *op_rsc = crm_element_value(xml_op, "resource");
1756  const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
1757  int status;
1758  time_t last_change = 0;
1759  xmlNode *node = NULL;
1760 
1762  &status, 0);
1763  node = pcmk__output_create_xml_node(out, "operation",
1764  "op", op_key ? op_key : ID(xml_op),
1765  "node", crm_element_value(xml_op, XML_ATTR_UNAME),
1766  "call", crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
1767  "rc", crm_element_value(xml_op, XML_LRM_ATTR_RC),
1768  "status", pcmk_exec_status_str(status),
1769  NULL);
1770 
1771  rsc = pe_find_resource(data_set->resources, op_rsc);
1772 
1773  if (rsc) {
1774  const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
1775  const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
1776  char *agent_tuple = NULL;
1777 
1778  agent_tuple = crm_strdup_printf("%s:%s:%s", class,
1780  kind);
1781 
1782  pcmk__xe_set_props(node, "rsc", rsc_printable_id(rsc),
1783  "agent", agent_tuple,
1784  NULL);
1785  free(agent_tuple);
1786  }
1787 
1789  &last_change) == pcmk_ok) {
1791  pcmk__trim(ctime(&last_change)),
1793  NULL);
1794  }
1795 
1796  return pcmk_rc_ok;
1797 }
1798 
1799 PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "gboolean", "int")
1800 static int
1801 node_attribute_xml(pcmk__output_t *out, va_list args) {
1802  const char *name = va_arg(args, const char *);
1803  const char *value = va_arg(args, const char *);
1804  gboolean add_extra = va_arg(args, gboolean);
1805  int expected_score = va_arg(args, int);
1806 
1807  xmlNodePtr node = pcmk__output_create_xml_node(out, "attribute",
1808  "name", name,
1809  "value", value,
1810  NULL);
1811 
1812  if (add_extra) {
1813  char *buf = pcmk__itoa(expected_score);
1814  crm_xml_add(node, "expected", buf);
1815  free(buf);
1816  }
1817 
1818  return pcmk_rc_ok;
1819 }
1820 
1821 PCMK__OUTPUT_ARGS("node-attribute-list", "pe_working_set_t *", "unsigned int",
1822  "gboolean", "GList *", "GList *")
1823 static int
1824 node_attribute_list(pcmk__output_t *out, va_list args) {
1825  pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1826  unsigned int show_opts = va_arg(args, unsigned int);
1827  gboolean print_spacer = va_arg(args, gboolean);
1828  GList *only_node = va_arg(args, GList *);
1829  GList *only_rsc = va_arg(args, GList *);
1830 
1831  int rc = pcmk_rc_no_output;
1832 
1833  /* Display each node's attributes */
1834  for (GList *gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
1835  pe_node_t *node = gIter->data;
1836 
1837  GList *attr_list = NULL;
1838  GHashTableIter iter;
1839  gpointer key;
1840 
1841  if (!node || !node->details || !node->details->online) {
1842  continue;
1843  }
1844 
1845  g_hash_table_iter_init(&iter, node->details->attrs);
1846  while (g_hash_table_iter_next (&iter, &key, NULL)) {
1847  attr_list = filter_attr_list(attr_list, key);
1848  }
1849 
1850  if (attr_list == NULL) {
1851  continue;
1852  }
1853 
1855  g_list_free(attr_list);
1856  continue;
1857  }
1858 
1859  PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Node Attributes");
1860 
1861  out->message(out, "node", node, show_opts, FALSE, NULL, only_node, only_rsc);
1862 
1863  for (GList *aIter = attr_list; aIter != NULL; aIter = aIter->next) {
1864  const char *name = aIter->data;
1865  const char *value = NULL;
1866  int expected_score = 0;
1867  gboolean add_extra = FALSE;
1868 
1869  value = pe_node_attribute_raw(node, name);
1870 
1871  add_extra = add_extra_info(node, node->details->running_rsc,
1872  data_set, name, &expected_score);
1873 
1874  /* Print attribute name and value */
1875  out->message(out, "node-attribute", name, value, add_extra,
1876  expected_score);
1877  }
1878 
1879  g_list_free(attr_list);
1880  out->end_list(out);
1881  }
1882 
1884  return rc;
1885 }
1886 
1887 PCMK__OUTPUT_ARGS("node-capacity", "pe_node_t *", "const char *")
1888 static int
1889 node_capacity(pcmk__output_t *out, va_list args)
1890 {
1891  pe_node_t *node = va_arg(args, pe_node_t *);
1892  const char *comment = va_arg(args, const char *);
1893 
1894  char *dump_text = crm_strdup_printf("%s: %s capacity:",
1895  comment, node->details->uname);
1896 
1897  g_hash_table_foreach(node->details->utilization, append_dump_text, &dump_text);
1898  out->list_item(out, NULL, "%s", dump_text);
1899  free(dump_text);
1900 
1901  return pcmk_rc_ok;
1902 }
1903 
1904 PCMK__OUTPUT_ARGS("node-capacity", "pe_node_t *", "const char *")
1905 static int
1906 node_capacity_xml(pcmk__output_t *out, va_list args)
1907 {
1908  pe_node_t *node = va_arg(args, pe_node_t *);
1909  const char *comment = va_arg(args, const char *);
1910 
1911  xmlNodePtr xml_node = pcmk__output_create_xml_node(out, "capacity",
1912  "node", node->details->uname,
1913  "comment", comment,
1914  NULL);
1915  g_hash_table_foreach(node->details->utilization, add_dump_node, xml_node);
1916 
1917  return pcmk_rc_ok;
1918 }
1919 
1920 PCMK__OUTPUT_ARGS("node-history-list", "pe_working_set_t *", "pe_node_t *", "xmlNodePtr",
1921  "GList *", "GList *", "unsigned int", "unsigned int")
1922 static int
1923 node_history_list(pcmk__output_t *out, va_list args) {
1924  pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1925  pe_node_t *node = va_arg(args, pe_node_t *);
1926  xmlNode *node_state = va_arg(args, xmlNode *);
1927  GList *only_node = va_arg(args, GList *);
1928  GList *only_rsc = va_arg(args, GList *);
1929  unsigned int section_opts = va_arg(args, unsigned int);
1930  unsigned int show_opts = va_arg(args, unsigned int);
1931 
1932  xmlNode *lrm_rsc = NULL;
1933  xmlNode *rsc_entry = NULL;
1934  int rc = pcmk_rc_no_output;
1935 
1936  lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE);
1937  lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE);
1938 
1939  /* Print history of each of the node's resources */
1940  for (rsc_entry = first_named_child(lrm_rsc, XML_LRM_TAG_RESOURCE);
1941  rsc_entry != NULL; rsc_entry = crm_next_same_xml(rsc_entry)) {
1942  const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID);
1943  pe_resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
1944 
1945  /* We can't use is_filtered here to filter group resources. For is_filtered,
1946  * we have to decide whether to check the parent or not. If we check the
1947  * parent, all elements of a group will always be printed because that's how
1948  * is_filtered works for groups. If we do not check the parent, sometimes
1949  * this will filter everything out.
1950  *
1951  * For other resource types, is_filtered is okay.
1952  */
1953  if (uber_parent(rsc)->variant == pe_group) {
1956  continue;
1957  }
1958  } else {
1959  if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
1960  continue;
1961  }
1962  }
1963 
1964  if (!pcmk_is_set(section_opts, pcmk_section_operations)) {
1965  time_t last_failure = 0;
1966  int failcount = pe_get_failcount(node, rsc, &last_failure, pe_fc_default,
1967  NULL, data_set);
1968 
1969  if (failcount <= 0) {
1970  continue;
1971  }
1972 
1973  if (rc == pcmk_rc_no_output) {
1974  rc = pcmk_rc_ok;
1975  out->message(out, "node", node, show_opts, FALSE, NULL, only_node, only_rsc);
1976  }
1977 
1978  out->message(out, "resource-history", rsc, rsc_id, FALSE,
1979  failcount, last_failure, FALSE);
1980  } else {
1981  GList *op_list = get_operation_list(rsc_entry);
1982  pe_resource_t *rsc = pe_find_resource(data_set->resources,
1983  crm_element_value(rsc_entry, XML_ATTR_ID));
1984 
1985  if (op_list == NULL) {
1986  continue;
1987  }
1988 
1989  if (rc == pcmk_rc_no_output) {
1990  rc = pcmk_rc_ok;
1991  out->message(out, "node", node, show_opts, FALSE, NULL, only_node, only_rsc);
1992  }
1993 
1994  out->message(out, "resource-operation-list", data_set, rsc, node,
1995  op_list, show_opts);
1996  }
1997  }
1998 
2000  return rc;
2001 }
2002 
2003 PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "unsigned int", "gboolean")
2004 static int
2005 node_list_html(pcmk__output_t *out, va_list args) {
2006  GList *nodes = va_arg(args, GList *);
2007  GList *only_node = va_arg(args, GList *);
2008  GList *only_rsc = va_arg(args, GList *);
2009  unsigned int show_opts = va_arg(args, unsigned int);
2010  gboolean print_spacer G_GNUC_UNUSED = va_arg(args, gboolean);
2011 
2012  int rc = pcmk_rc_no_output;
2013 
2014  for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
2015  pe_node_t *node = (pe_node_t *) gIter->data;
2016 
2017  if (!pcmk__str_in_list(node->details->uname, only_node,
2019  continue;
2020  }
2021 
2022  PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Node List");
2023 
2024  out->message(out, "node", node, show_opts, TRUE, NULL, only_node, only_rsc);
2025  }
2026 
2028  return rc;
2029 }
2030 
2031 PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "unsigned int", "gboolean")
2032 static int
2033 node_list_text(pcmk__output_t *out, va_list args) {
2034  GList *nodes = va_arg(args, GList *);
2035  GList *only_node = va_arg(args, GList *);
2036  GList *only_rsc = va_arg(args, GList *);
2037  unsigned int show_opts = va_arg(args, unsigned int);
2038  gboolean print_spacer = va_arg(args, gboolean);
2039 
2040  /* space-separated lists of node names */
2041  char *online_nodes = NULL;
2042  char *online_remote_nodes = NULL;
2043  char *online_guest_nodes = NULL;
2044  char *offline_nodes = NULL;
2045  char *offline_remote_nodes = NULL;
2046 
2047  size_t online_nodes_len = 0;
2048  size_t online_remote_nodes_len = 0;
2049  size_t online_guest_nodes_len = 0;
2050  size_t offline_nodes_len = 0;
2051  size_t offline_remote_nodes_len = 0;
2052 
2053  int rc = pcmk_rc_no_output;
2054 
2055  for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
2056  pe_node_t *node = (pe_node_t *) gIter->data;
2057  const char *node_mode = NULL;
2058  char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
2059 
2060  if (!pcmk__str_in_list(node->details->uname, only_node,
2062  free(node_name);
2063  continue;
2064  }
2065 
2066  PCMK__OUTPUT_LIST_HEADER(out, print_spacer == TRUE, rc, "Node List");
2067 
2068  /* Get node mode */
2069  if (node->details->unclean) {
2070  if (node->details->online) {
2071  node_mode = "UNCLEAN (online)";
2072 
2073  } else if (node->details->pending) {
2074  node_mode = "UNCLEAN (pending)";
2075 
2076  } else {
2077  node_mode = "UNCLEAN (offline)";
2078  }
2079 
2080  } else if (node->details->pending) {
2081  node_mode = "pending";
2082 
2083  } else if (node->details->standby_onfail && node->details->online) {
2084  node_mode = "standby (on-fail)";
2085 
2086  } else if (node->details->standby) {
2087  if (node->details->online) {
2088  if (node->details->running_rsc) {
2089  node_mode = "standby (with active resources)";
2090  } else {
2091  node_mode = "standby";
2092  }
2093  } else {
2094  node_mode = "OFFLINE (standby)";
2095  }
2096 
2097  } else if (node->details->maintenance) {
2098  if (node->details->online) {
2099  node_mode = "maintenance";
2100  } else {
2101  node_mode = "OFFLINE (maintenance)";
2102  }
2103 
2104  } else if (node->details->online) {
2105  node_mode = "online";
2106  if (!pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2107  if (pe__is_guest_node(node)) {
2108  pcmk__add_word(&online_guest_nodes,
2109  &online_guest_nodes_len, node_name);
2110  } else if (pe__is_remote_node(node)) {
2111  pcmk__add_word(&online_remote_nodes,
2112  &online_remote_nodes_len, node_name);
2113  } else {
2114  pcmk__add_word(&online_nodes, &online_nodes_len, node_name);
2115  }
2116  free(node_name);
2117  continue;
2118  }
2119 
2120  } else {
2121  node_mode = "OFFLINE";
2122  if (!pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2123  if (pe__is_remote_node(node)) {
2124  pcmk__add_word(&offline_remote_nodes,
2125  &offline_remote_nodes_len, node_name);
2126  } else if (pe__is_guest_node(node)) {
2127  /* ignore offline guest nodes */
2128  } else {
2129  pcmk__add_word(&offline_nodes,
2130  &offline_nodes_len, node_name);
2131  }
2132  free(node_name);
2133  continue;
2134  }
2135  }
2136 
2137  /* If we get here, node is in bad state, or we're grouping by node */
2138  out->message(out, "node", node, show_opts, TRUE, node_mode, only_node, only_rsc);
2139  free(node_name);
2140  }
2141 
2142  /* If we're not grouping by node, summarize nodes by status */
2143  if (online_nodes) {
2144  out->list_item(out, "Online", "[ %s ]", online_nodes);
2145  free(online_nodes);
2146  }
2147  if (offline_nodes) {
2148  out->list_item(out, "OFFLINE", "[ %s ]", offline_nodes);
2149  free(offline_nodes);
2150  }
2151  if (online_remote_nodes) {
2152  out->list_item(out, "RemoteOnline", "[ %s ]", online_remote_nodes);
2153  free(online_remote_nodes);
2154  }
2155  if (offline_remote_nodes) {
2156  out->list_item(out, "RemoteOFFLINE", "[ %s ]", offline_remote_nodes);
2157  free(offline_remote_nodes);
2158  }
2159  if (online_guest_nodes) {
2160  out->list_item(out, "GuestOnline", "[ %s ]", online_guest_nodes);
2161  free(online_guest_nodes);
2162  }
2163 
2165  return rc;
2166 }
2167 
2168 PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "unsigned int", "gboolean")
2169 static int
2170 node_list_xml(pcmk__output_t *out, va_list args) {
2171  GList *nodes = va_arg(args, GList *);
2172  GList *only_node = va_arg(args, GList *);
2173  GList *only_rsc = va_arg(args, GList *);
2174  unsigned int show_opts = va_arg(args, unsigned int);
2175  gboolean print_spacer G_GNUC_UNUSED = va_arg(args, gboolean);
2176 
2177  out->begin_list(out, NULL, NULL, "nodes");
2178  for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
2179  pe_node_t *node = (pe_node_t *) gIter->data;
2180 
2181  if (!pcmk__str_in_list(node->details->uname, only_node,
2183  continue;
2184  }
2185 
2186  out->message(out, "node", node, show_opts, TRUE, NULL, only_node, only_rsc);
2187  }
2188  out->end_list(out);
2189 
2190  return pcmk_rc_ok;
2191 }
2192 
2193 PCMK__OUTPUT_ARGS("node-summary", "pe_working_set_t *", "GList *", "GList *",
2194  "unsigned int", "unsigned int", "gboolean")
2195 static int
2196 node_summary(pcmk__output_t *out, va_list args) {
2197  pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
2198  GList *only_node = va_arg(args, GList *);
2199  GList *only_rsc = va_arg(args, GList *);
2200  unsigned int section_opts = va_arg(args, unsigned int);
2201  unsigned int show_opts = va_arg(args, unsigned int);
2202  gboolean print_spacer = va_arg(args, gboolean);
2203 
2204  xmlNode *node_state = NULL;
2205  xmlNode *cib_status = get_object_root(XML_CIB_TAG_STATUS, data_set->input);
2206  int rc = pcmk_rc_no_output;
2207 
2208  if (xmlChildElementCount(cib_status) == 0) {
2209  return rc;
2210  }
2211 
2212  for (node_state = first_named_child(cib_status, XML_CIB_TAG_STATE);
2213  node_state != NULL; node_state = crm_next_same_xml(node_state)) {
2214  pe_node_t *node = pe_find_node_id(data_set->nodes, ID(node_state));
2215 
2216  if (!node || !node->details || !node->details->online) {
2217  continue;
2218  }
2219 
2220  if (!pcmk__str_in_list(node->details->uname, only_node,
2222  continue;
2223  }
2224 
2225  PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc,
2226  pcmk_is_set(section_opts, pcmk_section_operations) ? "Operations" : "Migration Summary");
2227 
2228  out->message(out, "node-history-list", data_set, node, node_state,
2229  only_node, only_rsc, section_opts, show_opts);
2230  }
2231 
2233  return rc;
2234 }
2235 
2236 PCMK__OUTPUT_ARGS("node-weight", "pe_resource_t *", "const char *", "const char *", "char *")
2237 static int
2238 node_weight(pcmk__output_t *out, va_list args)
2239 {
2240  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2241  const char *prefix = va_arg(args, const char *);
2242  const char *uname = va_arg(args, const char *);
2243  char *score = va_arg(args, char *);
2244 
2245  if (rsc) {
2246  out->list_item(out, NULL, "%s: %s allocation score on %s: %s",
2247  prefix, rsc->id, uname, score);
2248  } else {
2249  out->list_item(out, NULL, "%s: %s = %s", prefix, uname, score);
2250  }
2251 
2252  return pcmk_rc_ok;
2253 }
2254 
2255 PCMK__OUTPUT_ARGS("node-weight", "pe_resource_t *", "const char *", "const char *", "char *")
2256 static int
2257 node_weight_xml(pcmk__output_t *out, va_list args)
2258 {
2259  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2260  const char *prefix = va_arg(args, const char *);
2261  const char *uname = va_arg(args, const char *);
2262  char *score = va_arg(args, char *);
2263 
2264  xmlNodePtr node = pcmk__output_create_xml_node(out, "node_weight",
2265  "function", prefix,
2266  "node", uname,
2267  "score", score,
2268  NULL);
2269 
2270  if (rsc) {
2271  crm_xml_add(node, "id", rsc->id);
2272  }
2273 
2274  return pcmk_rc_ok;
2275 }
2276 
2277 PCMK__OUTPUT_ARGS("op-history", "xmlNodePtr", "const char *", "const char *", "int",
2278  "unsigned int")
2279 static int
2280 op_history_text(pcmk__output_t *out, va_list args) {
2281  xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
2282  const char *task = va_arg(args, const char *);
2283  const char *interval_ms_s = va_arg(args, const char *);
2284  int rc = va_arg(args, int);
2285  unsigned int show_opts = va_arg(args, unsigned int);
2286 
2287  char *buf = op_history_string(xml_op, task, interval_ms_s, rc,
2288  pcmk_is_set(show_opts, pcmk_show_timing));
2289 
2290  out->list_item(out, NULL, "%s", buf);
2291 
2292  free(buf);
2293  return pcmk_rc_ok;
2294 }
2295 
2296 PCMK__OUTPUT_ARGS("op-history", "xmlNodePtr", "const char *", "const char *", "int",
2297  "unsigned int")
2298 static int
2299 op_history_xml(pcmk__output_t *out, va_list args) {
2300  xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
2301  const char *task = va_arg(args, const char *);
2302  const char *interval_ms_s = va_arg(args, const char *);
2303  int rc = va_arg(args, int);
2304  unsigned int show_opts = va_arg(args, unsigned int);
2305 
2306  char *rc_s = pcmk__itoa(rc);
2307  xmlNodePtr node = pcmk__output_create_xml_node(out, "operation_history",
2308  "call", crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
2309  "task", task,
2310  "rc", rc_s,
2311  "rc_text", services_ocf_exitcode_str(rc),
2312  NULL);
2313  free(rc_s);
2314 
2315  if (interval_ms_s && !pcmk__str_eq(interval_ms_s, "0", pcmk__str_casei)) {
2316  char *s = crm_strdup_printf("%sms", interval_ms_s);
2317  crm_xml_add(node, "interval", s);
2318  free(s);
2319  }
2320 
2321  if (pcmk_is_set(show_opts, pcmk_show_timing)) {
2322  const char *value = NULL;
2323  time_t epoch = 0;
2324 
2326  &epoch) == pcmk_ok) && (epoch > 0)) {
2328  }
2329 
2330  value = crm_element_value(xml_op, XML_RSC_OP_T_EXEC);
2331  if (value) {
2332  char *s = crm_strdup_printf("%sms", value);
2333  crm_xml_add(node, XML_RSC_OP_T_EXEC, s);
2334  free(s);
2335  }
2336  value = crm_element_value(xml_op, XML_RSC_OP_T_QUEUE);
2337  if (value) {
2338  char *s = crm_strdup_printf("%sms", value);
2339  crm_xml_add(node, XML_RSC_OP_T_QUEUE, s);
2340  free(s);
2341  }
2342  }
2343 
2344  return pcmk_rc_ok;
2345 }
2346 
2347 PCMK__OUTPUT_ARGS("promotion-score", "pe_resource_t *", "pe_node_t *", "char *")
2348 static int
2349 promotion_score(pcmk__output_t *out, va_list args)
2350 {
2351  pe_resource_t *child_rsc = va_arg(args, pe_resource_t *);
2352  pe_node_t *chosen = va_arg(args, pe_node_t *);
2353  char *score = va_arg(args, char *);
2354 
2355  out->list_item(out, NULL, "%s promotion score on %s: %s",
2356  child_rsc->id,
2357  chosen? chosen->details->uname : "none",
2358  score);
2359  return pcmk_rc_ok;
2360 }
2361 
2362 PCMK__OUTPUT_ARGS("promotion-score", "pe_resource_t *", "pe_node_t *", "char *")
2363 static int
2364 promotion_score_xml(pcmk__output_t *out, va_list args)
2365 {
2366  pe_resource_t *child_rsc = va_arg(args, pe_resource_t *);
2367  pe_node_t *chosen = va_arg(args, pe_node_t *);
2368  char *score = va_arg(args, char *);
2369 
2370  xmlNodePtr node = pcmk__output_create_xml_node(out, "promotion_score",
2371  "id", child_rsc->id,
2372  "score", score,
2373  NULL);
2374 
2375  if (chosen) {
2376  crm_xml_add(node, "node", chosen->details->uname);
2377  }
2378 
2379  return pcmk_rc_ok;
2380 }
2381 
2382 PCMK__OUTPUT_ARGS("resource-config", "pe_resource_t *", "gboolean")
2383 static int
2384 resource_config(pcmk__output_t *out, va_list args) {
2385  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2386  gboolean raw = va_arg(args, gboolean);
2387 
2388  char *rsc_xml = NULL;
2389 
2390  if (raw) {
2391  rsc_xml = dump_xml_formatted(rsc->orig_xml ? rsc->orig_xml : rsc->xml);
2392  } else {
2393  rsc_xml = dump_xml_formatted(rsc->xml);
2394  }
2395 
2396  pcmk__formatted_printf(out, "Resource XML:\n");
2397  out->output_xml(out, "xml", rsc_xml);
2398 
2399  free(rsc_xml);
2400  return pcmk_rc_ok;
2401 }
2402 
2403 PCMK__OUTPUT_ARGS("resource-history", "pe_resource_t *", "const char *", "gboolean", "int", "time_t", "gboolean")
2404 static int
2405 resource_history_text(pcmk__output_t *out, va_list args) {
2406  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2407  const char *rsc_id = va_arg(args, const char *);
2408  gboolean all = va_arg(args, gboolean);
2409  int failcount = va_arg(args, int);
2410  time_t last_failure = va_arg(args, int);
2411  gboolean as_header = va_arg(args, gboolean);
2412 
2413  char *buf = resource_history_string(rsc, rsc_id, all, failcount, last_failure);
2414 
2415  if (as_header) {
2416  out->begin_list(out, NULL, NULL, "%s", buf);
2417  } else {
2418  out->list_item(out, NULL, "%s", buf);
2419  }
2420 
2421  free(buf);
2422  return pcmk_rc_ok;
2423 }
2424 
2425 PCMK__OUTPUT_ARGS("resource-history", "pe_resource_t *", "const char *", "gboolean", "int", "time_t", "gboolean")
2426 static int
2427 resource_history_xml(pcmk__output_t *out, va_list args) {
2428  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2429  const char *rsc_id = va_arg(args, const char *);
2430  gboolean all = va_arg(args, gboolean);
2431  int failcount = va_arg(args, int);
2432  time_t last_failure = va_arg(args, int);
2433  gboolean as_header = va_arg(args, gboolean);
2434 
2435  xmlNodePtr node = pcmk__output_xml_create_parent(out, "resource_history",
2436  "id", rsc_id,
2437  NULL);
2438 
2439  if (rsc == NULL) {
2440  crm_xml_add(node, "orphan", "true");
2441  } else if (all || failcount || last_failure > 0) {
2442  char *migration_s = pcmk__itoa(rsc->migration_threshold);
2443 
2444  pcmk__xe_set_props(node, "orphan", "false",
2445  "migration-threshold", migration_s,
2446  NULL);
2447  free(migration_s);
2448 
2449  if (failcount > 0) {
2450  char *s = pcmk__itoa(failcount);
2451 
2453  free(s);
2454  }
2455 
2456  if (last_failure > 0) {
2457  crm_xml_add(node, PCMK__LAST_FAILURE_PREFIX, pcmk__epoch2str(&last_failure));
2458  }
2459  }
2460 
2461  if (as_header == FALSE) {
2463  }
2464 
2465  return pcmk_rc_ok;
2466 }
2467 
2468 static void
2469 print_resource_header(pcmk__output_t *out, unsigned int show_opts)
2470 {
2471  if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2472  /* Active resources have already been printed by node */
2473  out->begin_list(out, NULL, NULL, "Inactive Resources");
2474  } else if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
2475  out->begin_list(out, NULL, NULL, "Full List of Resources");
2476  } else {
2477  out->begin_list(out, NULL, NULL, "Active Resources");
2478  }
2479 }
2480 
2481 
2482 PCMK__OUTPUT_ARGS("resource-list", "pe_working_set_t *", "unsigned int",
2483  "gboolean", "GList *", "GList *", "gboolean")
2484 static int
2485 resource_list(pcmk__output_t *out, va_list args)
2486 {
2487  pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
2488  unsigned int show_opts = va_arg(args, unsigned int);
2489  gboolean print_summary = va_arg(args, gboolean);
2490  GList *only_node = va_arg(args, GList *);
2491  GList *only_rsc = va_arg(args, GList *);
2492  gboolean print_spacer = va_arg(args, gboolean);
2493 
2494  GList *rsc_iter;
2495  int rc = pcmk_rc_no_output;
2496  bool printed_header = false;
2497 
2498  /* If we already showed active resources by node, and
2499  * we're not showing inactive resources, we have nothing to do
2500  */
2501  if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node) &&
2502  !pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
2503  return rc;
2504  }
2505 
2506  /* If we haven't already printed resources grouped by node,
2507  * and brief output was requested, print resource summary */
2508  if (pcmk_is_set(show_opts, pcmk_show_brief) && !pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2509  GList *rscs = pe__filter_rsc_list(data_set->resources, only_rsc);
2510 
2511  PCMK__OUTPUT_SPACER_IF(out, print_spacer);
2512  print_resource_header(out, show_opts);
2513  printed_header = true;
2514 
2515  rc = pe__rscs_brief_output(out, rscs, show_opts);
2516  g_list_free(rscs);
2517  }
2518 
2519  /* For each resource, display it if appropriate */
2520  for (rsc_iter = data_set->resources; rsc_iter != NULL; rsc_iter = rsc_iter->next) {
2521  pe_resource_t *rsc = (pe_resource_t *) rsc_iter->data;
2522  int x;
2523 
2524  /* Complex resources may have some sub-resources active and some inactive */
2525  gboolean is_active = rsc->fns->active(rsc, TRUE);
2526  gboolean partially_active = rsc->fns->active(rsc, FALSE);
2527 
2528  /* Skip inactive orphans (deleted but still in CIB) */
2529  if (pcmk_is_set(rsc->flags, pe_rsc_orphan) && !is_active) {
2530  continue;
2531 
2532  /* Skip active resources if we already displayed them by node */
2533  } else if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2534  if (is_active) {
2535  continue;
2536  }
2537 
2538  /* Skip primitives already counted in a brief summary */
2539  } else if (pcmk_is_set(show_opts, pcmk_show_brief) && (rsc->variant == pe_native)) {
2540  continue;
2541 
2542  /* Skip resources that aren't at least partially active,
2543  * unless we're displaying inactive resources
2544  */
2545  } else if (!partially_active && !pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
2546  continue;
2547 
2548  } else if (partially_active && !pe__rsc_running_on_any(rsc, only_node)) {
2549  continue;
2550  }
2551 
2552  if (!printed_header) {
2553  PCMK__OUTPUT_SPACER_IF(out, print_spacer);
2554  print_resource_header(out, show_opts);
2555  printed_header = true;
2556  }
2557 
2558  /* Print this resource */
2559  x = out->message(out, crm_map_element_name(rsc->xml), show_opts, rsc,
2560  only_node, only_rsc);
2561  if (x == pcmk_rc_ok) {
2562  rc = pcmk_rc_ok;
2563  }
2564  }
2565 
2566  if (print_summary && rc != pcmk_rc_ok) {
2567  if (!printed_header) {
2568  PCMK__OUTPUT_SPACER_IF(out, print_spacer);
2569  print_resource_header(out, show_opts);
2570  printed_header = true;
2571  }
2572 
2573  if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2574  out->list_item(out, NULL, "No inactive resources");
2575  } else if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
2576  out->list_item(out, NULL, "No resources");
2577  } else {
2578  out->list_item(out, NULL, "No active resources");
2579  }
2580  }
2581 
2582  if (printed_header) {
2583  out->end_list(out);
2584  }
2585 
2586  return rc;
2587 }
2588 
2589 PCMK__OUTPUT_ARGS("resource-operation-list", "pe_working_set_t *", "pe_resource_t *",
2590  "pe_node_t *", "GList *", "unsigned int")
2591 static int
2592 resource_operation_list(pcmk__output_t *out, va_list args)
2593 {
2594  pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
2595  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2596  pe_node_t *node = va_arg(args, pe_node_t *);
2597  GList *op_list = va_arg(args, GList *);
2598  unsigned int show_opts = va_arg(args, unsigned int);
2599 
2600  GList *gIter = NULL;
2601  int rc = pcmk_rc_no_output;
2602 
2603  /* Print each operation */
2604  for (gIter = op_list; gIter != NULL; gIter = gIter->next) {
2605  xmlNode *xml_op = (xmlNode *) gIter->data;
2606  const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
2607  const char *interval_ms_s = crm_element_value(xml_op,
2609  const char *op_rc = crm_element_value(xml_op, XML_LRM_ATTR_RC);
2610  int op_rc_i;
2611 
2612  pcmk__scan_min_int(op_rc, &op_rc_i, 0);
2613 
2614  /* Display 0-interval monitors as "probe" */
2615  if (pcmk__str_eq(task, CRMD_ACTION_STATUS, pcmk__str_casei)
2616  && pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches | pcmk__str_casei)) {
2617  task = "probe";
2618  }
2619 
2620  /* If this is the first printed operation, print heading for resource */
2621  if (rc == pcmk_rc_no_output) {
2622  time_t last_failure = 0;
2623  int failcount = pe_get_failcount(node, rsc, &last_failure, pe_fc_default,
2624  NULL, data_set);
2625 
2626  out->message(out, "resource-history", rsc, rsc_printable_id(rsc), TRUE,
2627  failcount, last_failure, TRUE);
2628  rc = pcmk_rc_ok;
2629  }
2630 
2631  /* Print the operation */
2632  out->message(out, "op-history", xml_op, task, interval_ms_s,
2633  op_rc_i, show_opts);
2634  }
2635 
2636  /* Free the list we created (no need to free the individual items) */
2637  g_list_free(op_list);
2638 
2640  return rc;
2641 }
2642 
2643 PCMK__OUTPUT_ARGS("resource-util", "pe_resource_t *", "pe_node_t *", "const char *")
2644 static int
2645 resource_util(pcmk__output_t *out, va_list args)
2646 {
2647  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2648  pe_node_t *node = va_arg(args, pe_node_t *);
2649  const char *fn = va_arg(args, const char *);
2650 
2651  char *dump_text = crm_strdup_printf("%s: %s utilization on %s:",
2652  fn, rsc->id, node->details->uname);
2653 
2654  g_hash_table_foreach(rsc->utilization, append_dump_text, &dump_text);
2655  out->list_item(out, NULL, "%s", dump_text);
2656  free(dump_text);
2657 
2658  return pcmk_rc_ok;
2659 }
2660 
2661 PCMK__OUTPUT_ARGS("resource-util", "pe_resource_t *", "pe_node_t *", "const char *")
2662 static int
2663 resource_util_xml(pcmk__output_t *out, va_list args)
2664 {
2665  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2666  pe_node_t *node = va_arg(args, pe_node_t *);
2667  const char *fn = va_arg(args, const char *);
2668 
2669  xmlNodePtr xml_node = pcmk__output_create_xml_node(out, "utilization",
2670  "resource", rsc->id,
2671  "node", node->details->uname,
2672  "function", fn,
2673  NULL);
2674  g_hash_table_foreach(rsc->utilization, add_dump_node, xml_node);
2675 
2676  return pcmk_rc_ok;
2677 }
2678 
2679 PCMK__OUTPUT_ARGS("ticket", "pe_ticket_t *")
2680 static int
2681 ticket_html(pcmk__output_t *out, va_list args) {
2682  pe_ticket_t *ticket = va_arg(args, pe_ticket_t *);
2683 
2684  if (ticket->last_granted > -1) {
2685  char *time = pcmk__format_named_time("last-granted",
2686  ticket->last_granted);
2687 
2688  out->list_item(out, NULL, "%s:\t%s%s %s", ticket->id,
2689  ticket->granted ? "granted" : "revoked",
2690  ticket->standby ? " [standby]" : "",
2691  time);
2692  free(time);
2693  } else {
2694  out->list_item(out, NULL, "%s:\t%s%s", ticket->id,
2695  ticket->granted ? "granted" : "revoked",
2696  ticket->standby ? " [standby]" : "");
2697  }
2698 
2699  return pcmk_rc_ok;
2700 }
2701 
2702 PCMK__OUTPUT_ARGS("ticket", "pe_ticket_t *")
2703 static int
2704 ticket_text(pcmk__output_t *out, va_list args) {
2705  pe_ticket_t *ticket = va_arg(args, pe_ticket_t *);
2706 
2707  if (ticket->last_granted > -1) {
2708  char *time = pcmk__format_named_time("last-granted",
2709  ticket->last_granted);
2710 
2711  out->list_item(out, ticket->id, "%s%s %s",
2712  ticket->granted ? "granted" : "revoked",
2713  ticket->standby ? " [standby]" : "",
2714  time);
2715  free(time);
2716  } else {
2717  out->list_item(out, ticket->id, "%s%s",
2718  ticket->granted ? "granted" : "revoked",
2719  ticket->standby ? " [standby]" : "");
2720  }
2721 
2722  return pcmk_rc_ok;
2723 }
2724 
2725 PCMK__OUTPUT_ARGS("ticket", "pe_ticket_t *")
2726 static int
2727 ticket_xml(pcmk__output_t *out, va_list args) {
2728  pe_ticket_t *ticket = va_arg(args, pe_ticket_t *);
2729 
2730  xmlNodePtr node = NULL;
2731 
2732  node = pcmk__output_create_xml_node(out, "ticket",
2733  "id", ticket->id,
2734  "status", ticket->granted ? "granted" : "revoked",
2735  "standby", pcmk__btoa(ticket->standby),
2736  NULL);
2737 
2738  if (ticket->last_granted > -1) {
2739  crm_xml_add(node, "last-granted", pcmk__epoch2str(&ticket->last_granted));
2740  }
2741 
2742  return pcmk_rc_ok;
2743 }
2744 
2745 PCMK__OUTPUT_ARGS("ticket-list", "pe_working_set_t *", "gboolean")
2746 static int
2747 ticket_list(pcmk__output_t *out, va_list args) {
2748  pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
2749  gboolean print_spacer = va_arg(args, gboolean);
2750 
2751  GHashTableIter iter;
2752  gpointer key, value;
2753 
2754  if (g_hash_table_size(data_set->tickets) == 0) {
2755  return pcmk_rc_no_output;
2756  }
2757 
2758  PCMK__OUTPUT_SPACER_IF(out, print_spacer);
2759 
2760  /* Print section heading */
2761  out->begin_list(out, NULL, NULL, "Tickets");
2762 
2763  /* Print each ticket */
2764  g_hash_table_iter_init(&iter, data_set->tickets);
2765  while (g_hash_table_iter_next(&iter, &key, &value)) {
2766  pe_ticket_t *ticket = (pe_ticket_t *) value;
2767  out->message(out, "ticket", ticket);
2768  }
2769 
2770  /* Close section */
2771  out->end_list(out);
2772  return pcmk_rc_ok;
2773 }
2774 
2775 static pcmk__message_entry_t fmt_functions[] = {
2776  { "ban", "default", ban_text },
2777  { "ban", "html", ban_html },
2778  { "ban", "xml", ban_xml },
2779  { "ban-list", "default", ban_list },
2780  { "bundle", "default", pe__bundle_text },
2781  { "bundle", "xml", pe__bundle_xml },
2782  { "bundle", "html", pe__bundle_html },
2783  { "clone", "default", pe__clone_default },
2784  { "clone", "xml", pe__clone_xml },
2785  { "cluster-counts", "default", cluster_counts_text },
2786  { "cluster-counts", "html", cluster_counts_html },
2787  { "cluster-counts", "xml", cluster_counts_xml },
2788  { "cluster-dc", "default", cluster_dc_text },
2789  { "cluster-dc", "html", cluster_dc_html },
2790  { "cluster-dc", "xml", cluster_dc_xml },
2791  { "cluster-options", "default", cluster_options_text },
2792  { "cluster-options", "html", cluster_options_html },
2793  { "cluster-options", "log", cluster_options_log },
2794  { "cluster-options", "xml", cluster_options_xml },
2795  { "cluster-summary", "default", cluster_summary },
2796  { "cluster-summary", "html", cluster_summary_html },
2797  { "cluster-stack", "default", cluster_stack_text },
2798  { "cluster-stack", "html", cluster_stack_html },
2799  { "cluster-stack", "xml", cluster_stack_xml },
2800  { "cluster-times", "default", cluster_times_text },
2801  { "cluster-times", "html", cluster_times_html },
2802  { "cluster-times", "xml", cluster_times_xml },
2803  { "failed-action", "default", failed_action_default },
2804  { "failed-action", "xml", failed_action_xml },
2805  { "failed-action-list", "default", failed_action_list },
2806  { "group", "default", pe__group_default},
2807  { "group", "xml", pe__group_xml },
2808  { "maint-mode", "text", cluster_maint_mode_text },
2809  { "node", "default", node_text },
2810  { "node", "html", node_html },
2811  { "node", "xml", node_xml },
2812  { "node-and-op", "default", node_and_op },
2813  { "node-and-op", "xml", node_and_op_xml },
2814  { "node-capacity", "default", node_capacity },
2815  { "node-capacity", "xml", node_capacity_xml },
2816  { "node-history-list", "default", node_history_list },
2817  { "node-list", "default", node_list_text },
2818  { "node-list", "html", node_list_html },
2819  { "node-list", "xml", node_list_xml },
2820  { "node-weight", "default", node_weight },
2821  { "node-weight", "xml", node_weight_xml },
2822  { "node-attribute", "default", node_attribute_text },
2823  { "node-attribute", "html", node_attribute_html },
2824  { "node-attribute", "xml", node_attribute_xml },
2825  { "node-attribute-list", "default", node_attribute_list },
2826  { "node-summary", "default", node_summary },
2827  { "op-history", "default", op_history_text },
2828  { "op-history", "xml", op_history_xml },
2829  { "primitive", "default", pe__resource_text },
2830  { "primitive", "xml", pe__resource_xml },
2831  { "primitive", "html", pe__resource_html },
2832  { "promotion-score", "default", promotion_score },
2833  { "promotion-score", "xml", promotion_score_xml },
2834  { "resource-config", "default", resource_config },
2835  { "resource-history", "default", resource_history_text },
2836  { "resource-history", "xml", resource_history_xml },
2837  { "resource-list", "default", resource_list },
2838  { "resource-operation-list", "default", resource_operation_list },
2839  { "resource-util", "default", resource_util },
2840  { "resource-util", "xml", resource_util_xml },
2841  { "ticket", "default", ticket_text },
2842  { "ticket", "html", ticket_html },
2843  { "ticket", "xml", ticket_xml },
2844  { "ticket-list", "default", ticket_list },
2845 
2846  { NULL, NULL, NULL }
2847 };
2848 
2849 void
2851  pcmk__register_messages(out, fmt_functions);
2852 }
2853 
2854 void
2855 pe__output_node(pe_node_t *node, gboolean details, pcmk__output_t *out)
2856 {
2857  if (node == NULL) {
2858  crm_trace("<NULL>");
2859  return;
2860  }
2861 
2862  CRM_ASSERT(node->details);
2863  crm_trace("%sNode %s: (weight=%d, fixed=%s)",
2864  node->details->online ? "" : "Unavailable/Unclean ",
2865  node->details->uname, node->weight, node->fixed ? "True" : "False");
2866 
2867  if (details) {
2868  char *pe_mutable = strdup("\t\t");
2869  GList *gIter = node->details->running_rsc;
2870  GList *all = NULL;
2871 
2872  all = g_list_prepend(all, (gpointer) "*");
2873 
2874  crm_trace("\t\t===Node Attributes");
2875  g_hash_table_foreach(node->details->attrs, print_str_str, pe_mutable);
2876  free(pe_mutable);
2877 
2878  crm_trace("\t\t=== Resources");
2879 
2880  for (; gIter != NULL; gIter = gIter->next) {
2881  pe_resource_t *rsc = (pe_resource_t *) gIter->data;
2882 
2883  out->message(out, crm_map_element_name(rsc->xml),
2884  pe_print_pending, rsc, all, all);
2885  }
2886 
2887  g_list_free(all);
2888  }
2889 }
crm_time_t * crm_time_new_undefined(void)
Allocate memory for an uninitialized time object.
Definition: iso8601.c:116
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:225
#define XML_RSC_OP_LAST_CHANGE
Definition: msg_xml.h:317
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:136
enum rsc_role_e role_filter
Definition: internal.h:171
xmlNode * orig_xml
Definition: pe_types.h:325
enum pe_quorum_policy no_quorum_policy
Definition: pe_types.h:149
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:137
xmlNode * failed
Definition: pe_types.h:165
GHashTable * attrs
Definition: pe_types.h:234
gboolean fixed
Definition: pe_types.h:242
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:380
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:132
struct crm_time_s crm_time_t
Definition: iso8601.h:32
#define FILTER_STR
Definition: pe_output.c:18
GList * children
Definition: pe_types.h:377
#define pe_flag_symmetric_cluster
Definition: pe_types.h:95
gboolean standby
Definition: pe_types.h:460
int priority_fencing_delay
Definition: pe_types.h:190
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition: cib_utils.c:145
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2789
xmlNode * xml
Definition: pe_types.h:324
#define pe_flag_maintenance_mode
Definition: pe_types.h:96
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:138
int pe__group_default(pcmk__output_t *out, va_list args)
Definition: group.c:309
pe_resource_t * remote_rsc
Definition: pe_types.h:230
#define CRMD_ACTION_NOTIFY
Definition: crm.h:187
GHashTable * meta
Definition: pe_types.h:373
#define XML_RSC_OP_T_EXEC
Definition: msg_xml.h:319
resource_object_functions_t * fns
Definition: pe_types.h:333
#define XML_LRM_TAG_RESOURCE
Definition: msg_xml.h:264
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:432
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:706
xmlNodePtr pcmk__output_xml_peek_parent(pcmk__output_t *out)
Definition: output_xml.c:527
gboolean pending
Definition: pe_types.h:216
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
Definition: utils.c:1735
#define RSC_ROLE_PROMOTED_LEGACY_S
Definition: common.h:116
pe_resource_t * pe_find_resource(GList *rsc_list, const char *id_rh)
Definition: status.c:382
enum crm_ais_msg_types type
Definition: cpg.c:48
#define XML_CIB_TAG_LRM
Definition: msg_xml.h:262
pe_resource_t * rsc_lh
Definition: internal.h:170
bool pe__rsc_running_on_any(pe_resource_t *rsc, GList *node_list)
Definition: utils.c:2468
int migration_threshold
Definition: pe_types.h:344
GHashTable * tickets
Definition: pe_types.h:152
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:417
int pe__resource_text(pcmk__output_t *out, va_list args)
Definition: native.c:996
#define XML_RSC_OP_T_QUEUE
Definition: msg_xml.h:320
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:314
int pe__bundle_html(pcmk__output_t *out, va_list args)
Definition: bundle.c:1592
void void void pcmk__formatted_printf(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
GList * resources
Definition: pe_types.h:158
GList * nodes
Definition: pe_types.h:157
#define pe_flag_stop_everything
Definition: pe_types.h:105
GList * pe__filter_rsc_list(GList *rscs, GList *filter)
Definition: utils.c:2488
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:221
#define XML_LRM_ATTR_TASK_KEY
Definition: msg_xml.h:298
bool pe__is_remote_node(const pe_node_t *node)
Definition: remote.c:25
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:297
int weight
Definition: pe_types.h:241
int rc
Definition: pcmk_fence.c:35
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)
Definition: native.c:1260
int pe__bundle_text(pcmk__output_t *out, va_list args)
Definition: bundle.c:1720
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:903
void pcmk__output_xml_push_parent(pcmk__output_t *out, xmlNodePtr node)
Definition: output_xml.c:495
#define XML_ATTR_ID
Definition: msg_xml.h:129
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:198
bool pe__is_guest_node(const pe_node_t *node)
Definition: remote.c:33
char * pe__node_display_name(pe_node_t *node, bool print_detail)
Definition: pe_output.c:444
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:363
int pe__clone_xml(pcmk__output_t *out, va_list args)
Definition: clone.c:644
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:1254
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:114
int blocked_resources
Definition: pe_types.h:182
struct pe_node_shared_s * details
Definition: pe_types.h:244
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:267
#define XML_ATTR_HAVE_QUORUM
Definition: msg_xml.h:118
unsigned long long flags
Definition: pe_types.h:348
const char * uname
Definition: pe_types.h:209
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
#define XML_ATTR_UNAME
Definition: msg_xml.h:151
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:2002
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:465
#define pe_flag_stonith_enabled
Definition: pe_types.h:98
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:635
#define PCMK__FAIL_COUNT_PREFIX
Definition: internal.h:313
void pe__output_node(pe_node_t *node, gboolean details, pcmk__output_t *out)
Definition: pe_output.c:2855
time_t last_granted
Definition: pe_types.h:459
GHashTable * utilization
Definition: pe_types.h:375
#define XML_RSC_ATTR_TARGET_ROLE
Definition: msg_xml.h:233
gboolean standby
Definition: pe_types.h:214
#define XML_LRM_ATTR_EXIT_REASON
Definition: msg_xml.h:315
gboolean expected_up
Definition: pe_types.h:220
#define crm_time_log_with_timezone
Definition: iso8601.h:68
enum pe_obj_types variant
Definition: pe_types.h:331
xmlNode * input
Definition: pe_types.h:137
gboolean granted
Definition: pe_types.h:458
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
Definition: output_xml.c:511
#define RSC_ROLE_PROMOTED_S
Definition: common.h:114
const char * pcmk__epoch2str(time_t *when)
Definition: iso8601.c:1714
const char * id
Definition: pe_types.h:208
char * id
Definition: pe_types.h:457
void pcmk__xe_set_props(xmlNodePtr node,...) G_GNUC_NULL_TERMINATED
Definition: xml.c:2969
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:898
const xmlChar * pcmkXmlStr
Definition: xml.h:51
pe_node_t * pe_find_node_id(GList *node_list, const char *id)
Definition: status.c:418
#define PCMK__OUTPUT_LIST_FOOTER(out_obj, retcode)
GList * running_rsc
Definition: pe_types.h:231
pe_node_t * dc_node
Definition: pe_types.h:142
int pe__bundle_xml(pcmk__output_t *out, va_list args)
Definition: bundle.c:1468
#define PCMK__OUTPUT_LIST_HEADER(out_obj, cond, retcode, title...)
gboolean(* is_filtered)(pe_resource_t *, GList *, gboolean)
Definition: pe_types.h:57
pe_node_t * pending_node
Definition: pe_types.h:383
#define XML_LRM_TAG_RESOURCES
Definition: msg_xml.h:263
gchar * pcmk__native_output_string(pe_resource_t *rsc, const char *name, pe_node_t *node, unsigned long show_opts, const char *target_role, bool show_nodes)
Definition: native.c:542
#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:183
const char * rsc_printable_id(pe_resource_t *rsc)
Definition: utils.c:2011
#define XML_CIB_ATTR_WRITTEN
Definition: msg_xml.h:126
node_type
Definition: pe_types.h:70
int pe__group_xml(pcmk__output_t *out, va_list args)
Definition: group.c:259
This structure contains everything that makes up a single output formatter.
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:295
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:309
#define XML_NVPAIR_ATTR_VALUE
Definition: msg_xml.h:378
GHashTable * utilization
Definition: pe_types.h:235
gboolean shutdown
Definition: pe_types.h:219
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:383
#define XML_LRM_ATTR_OPSTATUS
Definition: msg_xml.h:307
int pe__resource_html(pcmk__output_t *out, va_list args)
Definition: native.c:972
#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:222
#define XML_LRM_ATTR_RC
Definition: msg_xml.h:308
#define pcmk_ok
Definition: results.h:68
GList * placement_constraints
Definition: pe_types.h:159
#define XML_CIB_TAG_STATUS
Definition: msg_xml.h:179
const char * pcmk__readable_interval(guint interval_ms)
Definition: iso8601.c:1749
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:265
#define ID(x)
Definition: msg_xml.h:456
unsigned long long flags
Definition: pe_types.h:146
char * crm_xml_escape(const char *text)
Replace special characters with their XML escape sequences.
Definition: xml.c:1344
gboolean standby_onfail
Definition: pe_types.h:215
void print_str_str(gpointer key, gpointer value, gpointer user_data)
Definition: utils.c:1448
char * name
Definition: pcmk_fence.c:31
gboolean unclean
Definition: pe_types.h:217
PCMK__OUTPUT_ARGS("ban-list", "pe_working_set_t *", "const char *", "GList *", "unsigned int", "gboolean")
Definition: pe_output.c:605
void pe__register_messages(pcmk__output_t *out)
Definition: pe_output.c:2850
enum node_type type
Definition: pe_types.h:210
#define pe_rsc_orphan
Definition: pe_types.h:248
#define crm_time_log_date
Definition: iso8601.h:66
gboolean online
Definition: pe_types.h:213
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:52
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:266
char * id
Definition: pe_types.h:322
#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:2815
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:140