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