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