pacemaker  2.1.9-49aab99839
Scalable High-Availability cluster resource manager
pe_output.c
Go to the documentation of this file.
1 /*
2  * Copyright 2019-2024 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 
12 #include <stdint.h>
13 
15 #include <crm/common/output.h>
17 #include <crm/cib/util.h>
18 #include <crm/common/xml.h>
19 #include <crm/pengine/internal.h>
20 
21 const char *
22 pe__resource_description(const pcmk_resource_t *rsc, uint32_t show_opts)
23 {
24  const char * desc = NULL;
25  // User-supplied description
26  if (pcmk_any_flags_set(show_opts, pcmk_show_rsc_only|pcmk_show_description)) {
28  }
29  return desc;
30 }
31 
32 /* Never display node attributes whose name starts with one of these prefixes */
33 #define FILTER_STR { PCMK__FAIL_COUNT_PREFIX, PCMK__LAST_FAILURE_PREFIX, \
34  PCMK__NODE_ATTR_SHUTDOWN, PCMK_NODE_ATTR_TERMINATE, \
35  PCMK_NODE_ATTR_STANDBY, "#", NULL }
36 
37 static int
38 compare_attribute(gconstpointer a, gconstpointer b)
39 {
40  int rc;
41 
42  rc = strcmp((const char *)a, (const char *)b);
43 
44  return rc;
45 }
46 
62 static bool
63 add_extra_info(const pcmk_node_t *node, GList *rsc_list,
64  pcmk_scheduler_t *scheduler, const char *attrname,
65  int *expected_score)
66 {
67  GList *gIter = NULL;
68 
69  for (gIter = rsc_list; gIter != NULL; gIter = gIter->next) {
70  pcmk_resource_t *rsc = (pcmk_resource_t *) gIter->data;
71  const char *type = g_hash_table_lookup(rsc->meta, PCMK_XA_TYPE);
72  const char *name = NULL;
73  GHashTable *params = NULL;
74 
75  if (rsc->children != NULL) {
76  if (add_extra_info(node, rsc->children, scheduler, attrname,
77  expected_score)) {
78  return true;
79  }
80  }
81 
82  if (!pcmk__strcase_any_of(type, "ping", "pingd", NULL)) {
83  continue;
84  }
85 
86  params = pe_rsc_params(rsc, node, scheduler);
87  name = g_hash_table_lookup(params, PCMK_XA_NAME);
88 
89  if (name == NULL) {
90  name = "pingd";
91  }
92 
93  /* To identify the resource with the attribute name. */
94  if (pcmk__str_eq(name, attrname, pcmk__str_casei)) {
95  int host_list_num = 0;
96  const char *hosts = g_hash_table_lookup(params, "host_list");
97  const char *multiplier = g_hash_table_lookup(params, "multiplier");
98  int multiplier_i;
99 
100  if (hosts) {
101  char **host_list = g_strsplit(hosts, " ", 0);
102  host_list_num = g_strv_length(host_list);
103  g_strfreev(host_list);
104  }
105 
106  if ((multiplier == NULL)
107  || (pcmk__scan_min_int(multiplier, &multiplier_i,
108  INT_MIN) != pcmk_rc_ok)) {
109  /* The ocf:pacemaker:ping resource agent defaults multiplier to
110  * 1. The agent currently does not handle invalid text, but it
111  * should, and this would be a reasonable choice ...
112  */
113  multiplier_i = 1;
114  }
115  *expected_score = host_list_num * multiplier_i;
116 
117  return true;
118  }
119  }
120  return false;
121 }
122 
123 static GList *
124 filter_attr_list(GList *attr_list, char *name)
125 {
126  int i;
127  const char *filt_str[] = FILTER_STR;
128 
129  CRM_CHECK(name != NULL, return attr_list);
130 
131  /* filtering automatic attributes */
132  for (i = 0; filt_str[i] != NULL; i++) {
133  if (g_str_has_prefix(name, filt_str[i])) {
134  return attr_list;
135  }
136  }
137 
138  return g_list_insert_sorted(attr_list, name, compare_attribute);
139 }
140 
141 static GList *
142 get_operation_list(xmlNode *rsc_entry) {
143  GList *op_list = NULL;
144  xmlNode *rsc_op = NULL;
145 
146  for (rsc_op = pcmk__xe_first_child(rsc_entry, NULL, NULL, NULL);
147  rsc_op != NULL; rsc_op = pcmk__xe_next(rsc_op)) {
148 
149  const char *task = crm_element_value(rsc_op, PCMK_XA_OPERATION);
150  const char *interval_ms_s = crm_element_value(rsc_op,
152  const char *op_rc = crm_element_value(rsc_op, PCMK__XA_RC_CODE);
153  int op_rc_i;
154 
155  pcmk__scan_min_int(op_rc, &op_rc_i, 0);
156 
157  /* Display 0-interval monitors as "probe" */
158  if (pcmk__str_eq(task, PCMK_ACTION_MONITOR, pcmk__str_casei)
159  && pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches | pcmk__str_casei)) {
160  task = "probe";
161  }
162 
163  /* Ignore notifies and some probes */
164  if (pcmk__str_eq(task, PCMK_ACTION_NOTIFY, pcmk__str_none)
165  || (pcmk__str_eq(task, "probe", pcmk__str_none)
166  && (op_rc_i == CRM_EX_NOT_RUNNING))) {
167  continue;
168  }
169 
170  if (pcmk__xe_is(rsc_op, PCMK__XE_LRM_RSC_OP)) {
171  op_list = g_list_append(op_list, rsc_op);
172  }
173  }
174 
175  op_list = g_list_sort(op_list, sort_op_by_callid);
176  return op_list;
177 }
178 
179 static void
180 add_dump_node(gpointer key, gpointer value, gpointer user_data)
181 {
182  xmlNodePtr node = user_data;
183 
184  node = pcmk__xe_create(node, (const char *) key);
185  pcmk__xe_set_content(node, "%s", (const char *) value);
186 }
187 
188 static void
189 append_dump_text(gpointer key, gpointer value, gpointer user_data)
190 {
191  char **dump_text = user_data;
192  char *new_text = crm_strdup_printf("%s %s=%s",
193  *dump_text, (char *)key, (char *)value);
194 
195  free(*dump_text);
196  *dump_text = new_text;
197 }
198 
199 #define XPATH_STACK "//" PCMK_XE_NVPAIR \
200  "[@" PCMK_XA_NAME "='" \
201  PCMK_OPT_CLUSTER_INFRASTRUCTURE "']"
202 
203 static const char *
204 get_cluster_stack(pcmk_scheduler_t *scheduler)
205 {
206  xmlNode *stack = get_xpath_object(XPATH_STACK, scheduler->input, LOG_DEBUG);
207 
208  if (stack != NULL) {
209  return crm_element_value(stack, PCMK_XA_VALUE);
210  }
211  return PCMK_VALUE_UNKNOWN;
212 }
213 
214 static char *
215 last_changed_string(const char *last_written, const char *user,
216  const char *client, const char *origin) {
217  if (last_written != NULL || user != NULL || client != NULL || origin != NULL) {
218  return crm_strdup_printf("%s%s%s%s%s%s%s",
219  last_written ? last_written : "",
220  user ? " by " : "",
221  user ? user : "",
222  client ? " via " : "",
223  client ? client : "",
224  origin ? " on " : "",
225  origin ? origin : "");
226  } else {
227  return strdup("");
228  }
229 }
230 
231 static char *
232 op_history_string(xmlNode *xml_op, const char *task, const char *interval_ms_s,
233  int rc, bool print_timing) {
234  const char *call = crm_element_value(xml_op, PCMK__XA_CALL_ID);
235  char *interval_str = NULL;
236  char *buf = NULL;
237 
238  if (interval_ms_s && !pcmk__str_eq(interval_ms_s, "0", pcmk__str_casei)) {
239  char *pair = pcmk__format_nvpair(PCMK_XA_INTERVAL, interval_ms_s, "ms");
240  interval_str = crm_strdup_printf(" %s", pair);
241  free(pair);
242  }
243 
244  if (print_timing) {
245  char *last_change_str = NULL;
246  char *exec_str = NULL;
247  char *queue_str = NULL;
248 
249  const char *value = NULL;
250 
251  time_t epoch = 0;
252 
254  &epoch) == pcmk_ok)
255  && (epoch > 0)) {
256  char *epoch_str = pcmk__epoch2str(&epoch, 0);
257 
258  last_change_str = crm_strdup_printf(" %s=\"%s\"",
260  pcmk__s(epoch_str, ""));
261  free(epoch_str);
262  }
263 
264  value = crm_element_value(xml_op, PCMK_XA_EXEC_TIME);
265  if (value) {
266  char *pair = pcmk__format_nvpair(PCMK_XA_EXEC_TIME, value, "ms");
267  exec_str = crm_strdup_printf(" %s", pair);
268  free(pair);
269  }
270 
271  value = crm_element_value(xml_op, PCMK_XA_QUEUE_TIME);
272  if (value) {
273  char *pair = pcmk__format_nvpair(PCMK_XA_QUEUE_TIME, value, "ms");
274  queue_str = crm_strdup_printf(" %s", pair);
275  free(pair);
276  }
277 
278  buf = crm_strdup_printf("(%s) %s:%s%s%s%s rc=%d (%s)", call, task,
279  interval_str ? interval_str : "",
280  last_change_str ? last_change_str : "",
281  exec_str ? exec_str : "",
282  queue_str ? queue_str : "",
283  rc, services_ocf_exitcode_str(rc));
284 
285  if (last_change_str) {
286  free(last_change_str);
287  }
288 
289  if (exec_str) {
290  free(exec_str);
291  }
292 
293  if (queue_str) {
294  free(queue_str);
295  }
296  } else {
297  buf = crm_strdup_printf("(%s) %s%s%s", call, task,
298  interval_str ? ":" : "",
299  interval_str ? interval_str : "");
300  }
301 
302  if (interval_str) {
303  free(interval_str);
304  }
305 
306  return buf;
307 }
308 
309 static char *
310 resource_history_string(pcmk_resource_t *rsc, const char *rsc_id, bool all,
311  int failcount, time_t last_failure) {
312  char *buf = NULL;
313 
314  if (rsc == NULL) {
315  buf = crm_strdup_printf("%s: orphan", rsc_id);
316  } else if (all || failcount || last_failure > 0) {
317  char *failcount_s = NULL;
318  char *lastfail_s = NULL;
319 
320  if (failcount > 0) {
321  failcount_s = crm_strdup_printf(" %s=%d",
322  PCMK_XA_FAIL_COUNT, failcount);
323  } else {
324  failcount_s = strdup("");
325  }
326  if (last_failure > 0) {
327  buf = pcmk__epoch2str(&last_failure, 0);
328  lastfail_s = crm_strdup_printf(" %s='%s'",
329  PCMK_XA_LAST_FAILURE, buf);
330  free(buf);
331  }
332 
333  buf = crm_strdup_printf("%s: " PCMK_META_MIGRATION_THRESHOLD "=%d%s%s",
334  rsc_id, rsc->migration_threshold, failcount_s,
335  lastfail_s? lastfail_s : "");
336  free(failcount_s);
337  free(lastfail_s);
338  } else {
339  buf = crm_strdup_printf("%s:", rsc_id);
340  }
341 
342  return buf;
343 }
344 
355 static const char *
356 get_node_feature_set(const pcmk_node_t *node)
357 {
358  if (node->details->online && node->details->expected_up
359  && !pcmk__is_pacemaker_remote_node(node)) {
360 
361  const char *feature_set = g_hash_table_lookup(node->details->attrs,
363 
364  /* The feature set attribute is present since 3.15.1. If it is missing,
365  * then the node must be running an earlier version.
366  */
367  return pcmk__s(feature_set, "<3.15.1");
368  }
369  return NULL;
370 }
371 
372 static bool
373 is_mixed_version(pcmk_scheduler_t *scheduler)
374 {
375  const char *feature_set = NULL;
376  for (GList *gIter = scheduler->nodes; gIter != NULL; gIter = gIter->next) {
377  pcmk_node_t *node = gIter->data;
378  const char *node_feature_set = get_node_feature_set(node);
379  if (node_feature_set != NULL) {
380  if (feature_set == NULL) {
381  feature_set = node_feature_set;
382  } else if (strcmp(feature_set, node_feature_set) != 0) {
383  return true;
384  }
385  }
386  }
387  return false;
388 }
389 
390 static void
391 formatted_xml_buf(const pcmk_resource_t *rsc, GString *xml_buf, bool raw)
392 {
393  if (raw && (rsc->orig_xml != NULL)) {
395  } else {
396  pcmk__xml_string(rsc->xml, pcmk__xml_fmt_pretty, xml_buf, 0);
397  }
398 }
399 
400 #define XPATH_DC_VERSION "//" PCMK_XE_NVPAIR \
401  "[@" PCMK_XA_NAME "='" PCMK_OPT_DC_VERSION "']"
402 
403 PCMK__OUTPUT_ARGS("cluster-summary", "pcmk_scheduler_t *",
404  "enum pcmk_pacemakerd_state", "uint32_t", "uint32_t")
405 static int
406 cluster_summary(pcmk__output_t *out, va_list args) {
407  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
408  enum pcmk_pacemakerd_state pcmkd_state =
409  (enum pcmk_pacemakerd_state) va_arg(args, int);
410  uint32_t section_opts = va_arg(args, uint32_t);
411  uint32_t show_opts = va_arg(args, uint32_t);
412 
413  int rc = pcmk_rc_no_output;
414  const char *stack_s = get_cluster_stack(scheduler);
415 
416  if (pcmk_is_set(section_opts, pcmk_section_stack)) {
417  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
418  out->message(out, "cluster-stack", stack_s, pcmkd_state);
419  }
420 
421  if (pcmk_is_set(section_opts, pcmk_section_dc)) {
422  xmlNode *dc_version = get_xpath_object(XPATH_DC_VERSION,
423  scheduler->input, LOG_DEBUG);
424  const char *dc_version_s = dc_version?
425  crm_element_value(dc_version, PCMK_XA_VALUE)
426  : NULL;
427  const char *quorum = crm_element_value(scheduler->input,
429  char *dc_name = scheduler->dc_node? pe__node_display_name(scheduler->dc_node, pcmk_is_set(show_opts, pcmk_show_node_id)) : NULL;
430  bool mixed_version = is_mixed_version(scheduler);
431 
432  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
433  out->message(out, "cluster-dc", scheduler->dc_node, quorum,
434  dc_version_s, dc_name, mixed_version);
435  free(dc_name);
436  }
437 
438  if (pcmk_is_set(section_opts, pcmk_section_times)) {
439  const char *last_written = crm_element_value(scheduler->input,
441  const char *user = crm_element_value(scheduler->input,
443  const char *client = crm_element_value(scheduler->input,
445  const char *origin = crm_element_value(scheduler->input,
447 
448  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
449  out->message(out, "cluster-times",
450  scheduler->localhost, last_written, user, client, origin);
451  }
452 
453  if (pcmk_is_set(section_opts, pcmk_section_counts)) {
454  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
455  out->message(out, "cluster-counts", g_list_length(scheduler->nodes),
458  }
459 
460  if (pcmk_is_set(section_opts, pcmk_section_options)) {
461  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
462  out->message(out, "cluster-options", scheduler);
463  }
464 
465  PCMK__OUTPUT_LIST_FOOTER(out, rc);
466 
467  if (pcmk_is_set(section_opts, pcmk_section_maint_mode)) {
468  if (out->message(out, "maint-mode", scheduler->flags) == pcmk_rc_ok) {
469  rc = pcmk_rc_ok;
470  }
471  }
472 
473  return rc;
474 }
475 
476 PCMK__OUTPUT_ARGS("cluster-summary", "pcmk_scheduler_t *",
477  "enum pcmk_pacemakerd_state", "uint32_t", "uint32_t")
478 static int
479 cluster_summary_html(pcmk__output_t *out, va_list args) {
480  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
481  enum pcmk_pacemakerd_state pcmkd_state =
482  (enum pcmk_pacemakerd_state) va_arg(args, int);
483  uint32_t section_opts = va_arg(args, uint32_t);
484  uint32_t show_opts = va_arg(args, uint32_t);
485 
486  int rc = pcmk_rc_no_output;
487  const char *stack_s = get_cluster_stack(scheduler);
488 
489  if (pcmk_is_set(section_opts, pcmk_section_stack)) {
490  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
491  out->message(out, "cluster-stack", stack_s, pcmkd_state);
492  }
493 
494  /* Always print DC if none, even if not requested */
495  if ((scheduler->dc_node == NULL)
496  || pcmk_is_set(section_opts, pcmk_section_dc)) {
497  xmlNode *dc_version = get_xpath_object(XPATH_DC_VERSION,
498  scheduler->input, LOG_DEBUG);
499  const char *dc_version_s = dc_version?
500  crm_element_value(dc_version, PCMK_XA_VALUE)
501  : NULL;
502  const char *quorum = crm_element_value(scheduler->input,
504  char *dc_name = scheduler->dc_node? pe__node_display_name(scheduler->dc_node, pcmk_is_set(show_opts, pcmk_show_node_id)) : NULL;
505  bool mixed_version = is_mixed_version(scheduler);
506 
507  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
508  out->message(out, "cluster-dc", scheduler->dc_node, quorum,
509  dc_version_s, dc_name, mixed_version);
510  free(dc_name);
511  }
512 
513  if (pcmk_is_set(section_opts, pcmk_section_times)) {
514  const char *last_written = crm_element_value(scheduler->input,
516  const char *user = crm_element_value(scheduler->input,
518  const char *client = crm_element_value(scheduler->input,
520  const char *origin = crm_element_value(scheduler->input,
522 
523  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
524  out->message(out, "cluster-times",
525  scheduler->localhost, last_written, user, client, origin);
526  }
527 
528  if (pcmk_is_set(section_opts, pcmk_section_counts)) {
529  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
530  out->message(out, "cluster-counts", g_list_length(scheduler->nodes),
533  }
534 
535  if (pcmk_is_set(section_opts, pcmk_section_options)) {
536  /* Kind of a hack - close the list we may have opened earlier in this
537  * function so we can put all the options into their own list. We
538  * only want to do this on HTML output, though.
539  */
540  PCMK__OUTPUT_LIST_FOOTER(out, rc);
541 
542  out->begin_list(out, NULL, NULL, "Config Options");
543  out->message(out, "cluster-options", scheduler);
544  }
545 
546  PCMK__OUTPUT_LIST_FOOTER(out, rc);
547 
548  if (pcmk_is_set(section_opts, pcmk_section_maint_mode)) {
549  if (out->message(out, "maint-mode", scheduler->flags) == pcmk_rc_ok) {
550  rc = pcmk_rc_ok;
551  }
552  }
553 
554  return rc;
555 }
556 
557 char *
558 pe__node_display_name(pcmk_node_t *node, bool print_detail)
559 {
560  char *node_name;
561  const char *node_host = NULL;
562  const char *node_id = NULL;
563  int name_len;
564 
565  pcmk__assert((node != NULL) && (node->details != NULL)
566  && (node->details->uname != NULL));
567 
568  /* Host is displayed only if this is a guest node and detail is requested */
569  if (print_detail && pcmk__is_guest_or_bundle_node(node)) {
570  const pcmk_resource_t *container = node->details->remote_rsc->container;
571  const pcmk_node_t *host_node = pcmk__current_node(container);
572 
573  if (host_node && host_node->details) {
574  node_host = host_node->details->uname;
575  }
576  if (node_host == NULL) {
577  node_host = ""; /* so we at least get "uname@" to indicate guest */
578  }
579  }
580 
581  /* Node ID is displayed if different from uname and detail is requested */
582  if (print_detail && !pcmk__str_eq(node->details->uname, node->details->id, pcmk__str_casei)) {
583  node_id = node->details->id;
584  }
585 
586  /* Determine name length */
587  name_len = strlen(node->details->uname) + 1;
588  if (node_host) {
589  name_len += strlen(node_host) + 1; /* "@node_host" */
590  }
591  if (node_id) {
592  name_len += strlen(node_id) + 3; /* + " (node_id)" */
593  }
594 
595  /* Allocate and populate display name */
596  node_name = pcmk__assert_alloc(name_len, sizeof(char));
597  strcpy(node_name, node->details->uname);
598  if (node_host) {
599  strcat(node_name, "@");
600  strcat(node_name, node_host);
601  }
602  if (node_id) {
603  strcat(node_name, " (");
604  strcat(node_name, node_id);
605  strcat(node_name, ")");
606  }
607  return node_name;
608 }
609 
610 int
611 pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name,
612  ...)
613 {
614  xmlNodePtr xml_node = NULL;
615  va_list pairs;
616 
617  pcmk__assert(tag_name != NULL);
618 
619  xml_node = pcmk__output_xml_peek_parent(out);
620  pcmk__assert(xml_node != NULL);
621  xml_node = pcmk__xe_create(xml_node, tag_name);
622 
623  va_start(pairs, tag_name);
624  pcmk__xe_set_propv(xml_node, pairs);
625  va_end(pairs);
626 
627  if (is_list) {
628  pcmk__output_xml_push_parent(out, xml_node);
629  }
630  return pcmk_rc_ok;
631 }
632 
633 static const char *
634 role_desc(enum rsc_role_e role)
635 {
636  if (role == pcmk_role_promoted) {
637 #ifdef PCMK__COMPAT_2_0
638  return "as " PCMK__ROLE_PROMOTED_LEGACY " ";
639 #else
640  return "in " PCMK_ROLE_PROMOTED " role ";
641 #endif
642  }
643  return "";
644 }
645 
646 PCMK__OUTPUT_ARGS("ban", "pcmk_node_t *", "pcmk__location_t *", "uint32_t")
647 static int
648 ban_html(pcmk__output_t *out, va_list args) {
649  pcmk_node_t *pe_node = va_arg(args, pcmk_node_t *);
650  pcmk__location_t *location = va_arg(args, pcmk__location_t *);
651  uint32_t show_opts = va_arg(args, uint32_t);
652 
653  char *node_name = pe__node_display_name(pe_node,
654  pcmk_is_set(show_opts, pcmk_show_node_id));
655  char *buf = crm_strdup_printf("%s\tprevents %s from running %son %s",
656  location->id, location->rsc->id,
657  role_desc(location->role_filter), node_name);
658 
659  pcmk__output_create_html_node(out, "li", NULL, NULL, buf);
660 
661  free(node_name);
662  free(buf);
663  return pcmk_rc_ok;
664 }
665 
666 PCMK__OUTPUT_ARGS("ban", "pcmk_node_t *", "pcmk__location_t *", "uint32_t")
667 static int
668 ban_text(pcmk__output_t *out, va_list args) {
669  pcmk_node_t *pe_node = va_arg(args, pcmk_node_t *);
670  pcmk__location_t *location = va_arg(args, pcmk__location_t *);
671  uint32_t show_opts = va_arg(args, uint32_t);
672 
673  char *node_name = pe__node_display_name(pe_node,
674  pcmk_is_set(show_opts, pcmk_show_node_id));
675  out->list_item(out, NULL, "%s\tprevents %s from running %son %s",
676  location->id, location->rsc->id,
677  role_desc(location->role_filter), node_name);
678 
679  free(node_name);
680  return pcmk_rc_ok;
681 }
682 
683 PCMK__OUTPUT_ARGS("ban", "pcmk_node_t *", "pcmk__location_t *", "uint32_t")
684 static int
685 ban_xml(pcmk__output_t *out, va_list args) {
686  pcmk_node_t *pe_node = va_arg(args, pcmk_node_t *);
687  pcmk__location_t *location = va_arg(args, pcmk__location_t *);
688  uint32_t show_opts G_GNUC_UNUSED = va_arg(args, uint32_t);
689 
690  const char *promoted_only = pcmk__btoa(location->role_filter == pcmk_role_promoted);
691  char *weight_s = pcmk__itoa(pe_node->weight);
692 
694  PCMK_XA_ID, location->id,
695  PCMK_XA_RESOURCE, location->rsc->id,
696  PCMK_XA_NODE, pe_node->details->uname,
697  PCMK_XA_WEIGHT, weight_s,
698  PCMK_XA_PROMOTED_ONLY, promoted_only,
699  /* This is a deprecated alias for
700  * promoted_only. Removing it will break
701  * backward compatibility of the API schema,
702  * which will require an API schema major
703  * version bump.
704  */
705  PCMK__XA_PROMOTED_ONLY_LEGACY, promoted_only,
706  NULL);
707 
708  free(weight_s);
709  return pcmk_rc_ok;
710 }
711 
712 PCMK__OUTPUT_ARGS("ban-list", "pcmk_scheduler_t *", "const char *", "GList *",
713  "uint32_t", "bool")
714 static int
715 ban_list(pcmk__output_t *out, va_list args) {
716  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
717  const char *prefix = va_arg(args, const char *);
718  GList *only_rsc = va_arg(args, GList *);
719  uint32_t show_opts = va_arg(args, uint32_t);
720  bool print_spacer = va_arg(args, int);
721 
722  GList *gIter, *gIter2;
723  int rc = pcmk_rc_no_output;
724 
725  /* Print each ban */
726  for (gIter = scheduler->placement_constraints;
727  gIter != NULL; gIter = gIter->next) {
728  pcmk__location_t *location = gIter->data;
729  const pcmk_resource_t *rsc = location->rsc;
730 
731  if (prefix != NULL && !g_str_has_prefix(location->id, prefix)) {
732  continue;
733  }
734 
735  if (!pcmk__str_in_list(rsc_printable_id(rsc), only_rsc,
738  only_rsc, pcmk__str_star_matches)) {
739  continue;
740  }
741 
742  for (gIter2 = location->nodes; gIter2 != NULL; gIter2 = gIter2->next) {
743  pcmk_node_t *node = (pcmk_node_t *) gIter2->data;
744 
745  if (node->weight < 0) {
746  PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Negative Location Constraints");
747  out->message(out, "ban", node, location, show_opts);
748  }
749  }
750  }
751 
752  PCMK__OUTPUT_LIST_FOOTER(out, rc);
753  return rc;
754 }
755 
756 PCMK__OUTPUT_ARGS("cluster-counts", "unsigned int", "int", "int", "int")
757 static int
758 cluster_counts_html(pcmk__output_t *out, va_list args) {
759  unsigned int nnodes = va_arg(args, unsigned int);
760  int nresources = va_arg(args, int);
761  int ndisabled = va_arg(args, int);
762  int nblocked = va_arg(args, int);
763 
764  xmlNodePtr nodes_node = pcmk__output_create_xml_node(out, "li", NULL);
765  xmlNodePtr resources_node = pcmk__output_create_xml_node(out, "li", NULL);
766  xmlNode *child = NULL;
767 
768  child = pcmk__html_create(nodes_node, PCMK__XE_SPAN, NULL, NULL);
769  pcmk__xe_set_content(child, "%d node%s configured",
770  nnodes, pcmk__plural_s(nnodes));
771 
772  if (ndisabled && nblocked) {
773  child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
774  pcmk__xe_set_content(child, "%d resource instance%s configured (%d ",
775  nresources, pcmk__plural_s(nresources), ndisabled);
776 
777  child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL,
779  pcmk__xe_set_content(child, "DISABLED");
780 
781  child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
782  pcmk__xe_set_content(child, ", %d ", nblocked);
783 
784  child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL,
786  pcmk__xe_set_content(child, "BLOCKED");
787 
788  child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
789  pcmk__xe_set_content(child, " from further action due to failure)");
790 
791  } else if (ndisabled && !nblocked) {
792  child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
793  pcmk__xe_set_content(child, "%d resource instance%s configured (%d ",
794  nresources, pcmk__plural_s(nresources),
795  ndisabled);
796 
797  child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL,
799  pcmk__xe_set_content(child, "DISABLED");
800 
801  child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
802  pcmk__xe_set_content(child, ")");
803 
804  } else if (!ndisabled && nblocked) {
805  child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
806  pcmk__xe_set_content(child, "%d resource instance%s configured (%d ",
807  nresources, pcmk__plural_s(nresources),
808  nblocked);
809 
810  child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL,
812  pcmk__xe_set_content(child, "BLOCKED");
813 
814  child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
815  pcmk__xe_set_content(child, " from further action due to failure)");
816 
817  } else {
818  child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
819  pcmk__xe_set_content(child, "%d resource instance%s configured",
820  nresources, pcmk__plural_s(nresources));
821  }
822 
823  return pcmk_rc_ok;
824 }
825 
826 PCMK__OUTPUT_ARGS("cluster-counts", "unsigned int", "int", "int", "int")
827 static int
828 cluster_counts_text(pcmk__output_t *out, va_list args) {
829  unsigned int nnodes = va_arg(args, unsigned int);
830  int nresources = va_arg(args, int);
831  int ndisabled = va_arg(args, int);
832  int nblocked = va_arg(args, int);
833 
834  out->list_item(out, NULL, "%d node%s configured",
835  nnodes, pcmk__plural_s(nnodes));
836 
837  if (ndisabled && nblocked) {
838  out->list_item(out, NULL, "%d resource instance%s configured "
839  "(%d DISABLED, %d BLOCKED from "
840  "further action due to failure)",
841  nresources, pcmk__plural_s(nresources), ndisabled,
842  nblocked);
843  } else if (ndisabled && !nblocked) {
844  out->list_item(out, NULL, "%d resource instance%s configured "
845  "(%d DISABLED)",
846  nresources, pcmk__plural_s(nresources), ndisabled);
847  } else if (!ndisabled && nblocked) {
848  out->list_item(out, NULL, "%d resource instance%s configured "
849  "(%d BLOCKED from further action "
850  "due to failure)",
851  nresources, pcmk__plural_s(nresources), nblocked);
852  } else {
853  out->list_item(out, NULL, "%d resource instance%s configured",
854  nresources, pcmk__plural_s(nresources));
855  }
856 
857  return pcmk_rc_ok;
858 }
859 
860 PCMK__OUTPUT_ARGS("cluster-counts", "unsigned int", "int", "int", "int")
861 static int
862 cluster_counts_xml(pcmk__output_t *out, va_list args) {
863  unsigned int nnodes = va_arg(args, unsigned int);
864  int nresources = va_arg(args, int);
865  int ndisabled = va_arg(args, int);
866  int nblocked = va_arg(args, int);
867 
868  xmlNodePtr nodes_node = NULL;
869  xmlNodePtr resources_node = NULL;
870  char *s = NULL;
871 
873  NULL);
874  resources_node = pcmk__output_create_xml_node(out,
876  NULL);
877 
878  s = pcmk__itoa(nnodes);
879  crm_xml_add(nodes_node, PCMK_XA_NUMBER, s);
880  free(s);
881 
882  s = pcmk__itoa(nresources);
883  crm_xml_add(resources_node, PCMK_XA_NUMBER, s);
884  free(s);
885 
886  s = pcmk__itoa(ndisabled);
887  crm_xml_add(resources_node, PCMK_XA_DISABLED, s);
888  free(s);
889 
890  s = pcmk__itoa(nblocked);
891  crm_xml_add(resources_node, PCMK_XA_BLOCKED, s);
892  free(s);
893 
894  return pcmk_rc_ok;
895 }
896 
897 PCMK__OUTPUT_ARGS("cluster-dc", "pcmk_node_t *", "const char *", "const char *",
898  "char *", "int")
899 static int
900 cluster_dc_html(pcmk__output_t *out, va_list args) {
901  pcmk_node_t *dc = va_arg(args, pcmk_node_t *);
902  const char *quorum = va_arg(args, const char *);
903  const char *dc_version_s = va_arg(args, const char *);
904  char *dc_name = va_arg(args, char *);
905  bool mixed_version = va_arg(args, int);
906 
907  xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
908  xmlNode *child = NULL;
909 
910  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, PCMK__VALUE_BOLD);
911  pcmk__xe_set_content(child, "Current DC: ");
912 
913  if (dc) {
914  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
915  pcmk__xe_set_content(child, "%s (version %s) -",
916  dc_name, pcmk__s(dc_version_s, "unknown"));
917 
918  if (mixed_version) {
919  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL,
921  pcmk__xe_set_content(child, " MIXED-VERSION");
922  }
923 
924  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
925  pcmk__xe_set_content(child, " partition");
926 
927  if (crm_is_true(quorum)) {
928  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
929  pcmk__xe_set_content(child, " with");
930 
931  } else {
932  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL,
934  pcmk__xe_set_content(child, " WITHOUT");
935  }
936 
937  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
938  pcmk__xe_set_content(child, " quorum");
939 
940  } else {
941  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL,
943  pcmk__xe_set_content(child, "NONE");
944  }
945 
946  return pcmk_rc_ok;
947 }
948 
949 PCMK__OUTPUT_ARGS("cluster-dc", "pcmk_node_t *", "const char *", "const char *",
950  "char *", "int")
951 static int
952 cluster_dc_text(pcmk__output_t *out, va_list args) {
953  pcmk_node_t *dc = va_arg(args, pcmk_node_t *);
954  const char *quorum = va_arg(args, const char *);
955  const char *dc_version_s = va_arg(args, const char *);
956  char *dc_name = va_arg(args, char *);
957  bool mixed_version = va_arg(args, int);
958 
959  if (dc) {
960  out->list_item(out, "Current DC",
961  "%s (version %s) - %spartition %s quorum",
962  dc_name, dc_version_s ? dc_version_s : "unknown",
963  mixed_version ? "MIXED-VERSION " : "",
964  crm_is_true(quorum) ? "with" : "WITHOUT");
965  } else {
966  out->list_item(out, "Current DC", "NONE");
967  }
968 
969  return pcmk_rc_ok;
970 }
971 
972 PCMK__OUTPUT_ARGS("cluster-dc", "pcmk_node_t *", "const char *", "const char *",
973  "char *", "int")
974 static int
975 cluster_dc_xml(pcmk__output_t *out, va_list args) {
976  pcmk_node_t *dc = va_arg(args, pcmk_node_t *);
977  const char *quorum = va_arg(args, const char *);
978  const char *dc_version_s = va_arg(args, const char *);
979  char *dc_name G_GNUC_UNUSED = va_arg(args, char *);
980  bool mixed_version = va_arg(args, int);
981 
982  if (dc) {
983  const char *with_quorum = pcmk__btoa(crm_is_true(quorum));
984  const char *mixed_version_s = pcmk__btoa(mixed_version);
985 
988  PCMK_XA_VERSION, pcmk__s(dc_version_s, ""),
989  PCMK_XA_NAME, dc->details->uname,
990  PCMK_XA_ID, dc->details->id,
991  PCMK_XA_WITH_QUORUM, with_quorum,
992  PCMK_XA_MIXED_VERSION, mixed_version_s,
993  NULL);
994  } else {
997  NULL);
998  }
999 
1000  return pcmk_rc_ok;
1001 }
1002 
1003 PCMK__OUTPUT_ARGS("maint-mode", "unsigned long long int")
1004 static int
1005 cluster_maint_mode_text(pcmk__output_t *out, va_list args) {
1006  unsigned long long flags = va_arg(args, unsigned long long);
1007 
1009  pcmk__formatted_printf(out, "\n *** Resource management is DISABLED ***\n");
1010  pcmk__formatted_printf(out, " The cluster will not attempt to start, stop or recover services\n");
1011  return pcmk_rc_ok;
1012  } else if (pcmk_is_set(flags, pcmk_sched_stop_all)) {
1013  pcmk__formatted_printf(out, "\n *** Resource management is DISABLED ***\n");
1014  pcmk__formatted_printf(out, " The cluster will keep all resources stopped\n");
1015  return pcmk_rc_ok;
1016  } else {
1017  return pcmk_rc_no_output;
1018  }
1019 }
1020 
1021 PCMK__OUTPUT_ARGS("cluster-options", "pcmk_scheduler_t *")
1022 static int
1023 cluster_options_html(pcmk__output_t *out, va_list args) {
1024  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
1025 
1027  out->list_item(out, NULL, "STONITH of failed nodes enabled");
1028  } else {
1029  out->list_item(out, NULL, "STONITH of failed nodes disabled");
1030  }
1031 
1033  out->list_item(out, NULL, "Cluster is symmetric");
1034  } else {
1035  out->list_item(out, NULL, "Cluster is asymmetric");
1036  }
1037 
1038  switch (scheduler->no_quorum_policy) {
1039  case pcmk_no_quorum_freeze:
1040  out->list_item(out, NULL, "No quorum policy: Freeze resources");
1041  break;
1042 
1043  case pcmk_no_quorum_stop:
1044  out->list_item(out, NULL, "No quorum policy: Stop ALL resources");
1045  break;
1046 
1047  case pcmk_no_quorum_demote:
1048  out->list_item(out, NULL, "No quorum policy: Demote promotable "
1049  "resources and stop all other resources");
1050  break;
1051 
1052  case pcmk_no_quorum_ignore:
1053  out->list_item(out, NULL, "No quorum policy: Ignore");
1054  break;
1055 
1056  case pcmk_no_quorum_fence:
1057  out->list_item(out, NULL, "No quorum policy: Suicide");
1058  break;
1059  }
1060 
1062  xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
1063  xmlNode *child = NULL;
1064 
1065  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1066  pcmk__xe_set_content(child, "Resource management: ");
1067 
1068  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, PCMK__VALUE_BOLD);
1069  pcmk__xe_set_content(child, "DISABLED");
1070 
1071  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1072  pcmk__xe_set_content(child,
1073  " (the cluster will not attempt to start, stop,"
1074  " or recover services)");
1075 
1077  xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
1078  xmlNode *child = NULL;
1079 
1080  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1081  pcmk__xe_set_content(child, "Resource management: ");
1082 
1083  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, PCMK__VALUE_BOLD);
1084  pcmk__xe_set_content(child, "STOPPED");
1085 
1086  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1087  pcmk__xe_set_content(child,
1088  " (the cluster will keep all resources stopped)");
1089 
1090  } else {
1091  out->list_item(out, NULL, "Resource management: enabled");
1092  }
1093 
1094  return pcmk_rc_ok;
1095 }
1096 
1097 PCMK__OUTPUT_ARGS("cluster-options", "pcmk_scheduler_t *")
1098 static int
1099 cluster_options_log(pcmk__output_t *out, va_list args) {
1100  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
1101 
1103  return out->info(out, "Resource management is DISABLED. The cluster will not attempt to start, stop or recover services.");
1105  return out->info(out, "Resource management is DISABLED. The cluster has stopped all resources.");
1106  } else {
1107  return pcmk_rc_no_output;
1108  }
1109 }
1110 
1111 PCMK__OUTPUT_ARGS("cluster-options", "pcmk_scheduler_t *")
1112 static int
1113 cluster_options_text(pcmk__output_t *out, va_list args) {
1114  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
1115 
1117  out->list_item(out, NULL, "STONITH of failed nodes enabled");
1118  } else {
1119  out->list_item(out, NULL, "STONITH of failed nodes disabled");
1120  }
1121 
1123  out->list_item(out, NULL, "Cluster is symmetric");
1124  } else {
1125  out->list_item(out, NULL, "Cluster is asymmetric");
1126  }
1127 
1128  switch (scheduler->no_quorum_policy) {
1129  case pcmk_no_quorum_freeze:
1130  out->list_item(out, NULL, "No quorum policy: Freeze resources");
1131  break;
1132 
1133  case pcmk_no_quorum_stop:
1134  out->list_item(out, NULL, "No quorum policy: Stop ALL resources");
1135  break;
1136 
1137  case pcmk_no_quorum_demote:
1138  out->list_item(out, NULL, "No quorum policy: Demote promotable "
1139  "resources and stop all other resources");
1140  break;
1141 
1142  case pcmk_no_quorum_ignore:
1143  out->list_item(out, NULL, "No quorum policy: Ignore");
1144  break;
1145 
1146  case pcmk_no_quorum_fence:
1147  out->list_item(out, NULL, "No quorum policy: Suicide");
1148  break;
1149  }
1150 
1151  return pcmk_rc_ok;
1152 }
1153 
1162 static const char *
1163 no_quorum_policy_text(enum pe_quorum_policy policy)
1164 {
1165  switch (policy) {
1166  case pcmk_no_quorum_freeze:
1167  return PCMK_VALUE_FREEZE;
1168 
1169  case pcmk_no_quorum_stop:
1170  return PCMK_VALUE_STOP;
1171 
1172  case pcmk_no_quorum_demote:
1173  return PCMK_VALUE_DEMOTE;
1174 
1175  case pcmk_no_quorum_ignore:
1176  return PCMK_VALUE_IGNORE;
1177 
1178  case pcmk_no_quorum_fence:
1179  return PCMK_VALUE_FENCE_LEGACY;
1180 
1181  default:
1182  return PCMK_VALUE_UNKNOWN;
1183  }
1184 }
1185 
1186 PCMK__OUTPUT_ARGS("cluster-options", "pcmk_scheduler_t *")
1187 static int
1188 cluster_options_xml(pcmk__output_t *out, va_list args) {
1189  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
1190 
1191  const char *stonith_enabled = pcmk__flag_text(scheduler->flags,
1193  const char *symmetric_cluster =
1194  pcmk__flag_text(scheduler->flags, pcmk_sched_symmetric_cluster);
1195  const char *no_quorum_policy =
1196  no_quorum_policy_text(scheduler->no_quorum_policy);
1197  const char *maintenance_mode = pcmk__flag_text(scheduler->flags,
1199  const char *stop_all_resources = pcmk__flag_text(scheduler->flags,
1201  char *stonith_timeout_ms_s = pcmk__itoa(scheduler->stonith_timeout);
1202  char *priority_fencing_delay_ms_s =
1203  pcmk__itoa(scheduler->priority_fencing_delay * 1000);
1204 
1206  PCMK_XA_STONITH_ENABLED, stonith_enabled,
1207  PCMK_XA_SYMMETRIC_CLUSTER, symmetric_cluster,
1208  PCMK_XA_NO_QUORUM_POLICY, no_quorum_policy,
1209  PCMK_XA_MAINTENANCE_MODE, maintenance_mode,
1210  PCMK_XA_STOP_ALL_RESOURCES, stop_all_resources,
1212  stonith_timeout_ms_s,
1214  priority_fencing_delay_ms_s,
1215  NULL);
1216  free(stonith_timeout_ms_s);
1217  free(priority_fencing_delay_ms_s);
1218 
1219  return pcmk_rc_ok;
1220 }
1221 
1222 PCMK__OUTPUT_ARGS("cluster-stack", "const char *", "enum pcmk_pacemakerd_state")
1223 static int
1224 cluster_stack_html(pcmk__output_t *out, va_list args) {
1225  const char *stack_s = va_arg(args, const char *);
1226  enum pcmk_pacemakerd_state pcmkd_state =
1227  (enum pcmk_pacemakerd_state) va_arg(args, int);
1228 
1229  xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
1230  xmlNode *child = NULL;
1231 
1232  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, PCMK__VALUE_BOLD);
1233  pcmk__xe_set_content(child, "Stack: ");
1234 
1235  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1236  pcmk__xe_set_content(child, "%s", stack_s);
1237 
1238  if (pcmkd_state != pcmk_pacemakerd_state_invalid) {
1239  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1240  pcmk__xe_set_content(child, " (");
1241 
1242  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1243  pcmk__xe_set_content(child, "%s",
1244  pcmk__pcmkd_state_enum2friendly(pcmkd_state));
1245 
1246  child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1247  pcmk__xe_set_content(child, ")");
1248  }
1249  return pcmk_rc_ok;
1250 }
1251 
1252 PCMK__OUTPUT_ARGS("cluster-stack", "const char *", "enum pcmk_pacemakerd_state")
1253 static int
1254 cluster_stack_text(pcmk__output_t *out, va_list args) {
1255  const char *stack_s = va_arg(args, const char *);
1256  enum pcmk_pacemakerd_state pcmkd_state =
1257  (enum pcmk_pacemakerd_state) va_arg(args, int);
1258 
1259  if (pcmkd_state != pcmk_pacemakerd_state_invalid) {
1260  out->list_item(out, "Stack", "%s (%s)",
1261  stack_s, pcmk__pcmkd_state_enum2friendly(pcmkd_state));
1262  } else {
1263  out->list_item(out, "Stack", "%s", stack_s);
1264  }
1265 
1266  return pcmk_rc_ok;
1267 }
1268 
1269 PCMK__OUTPUT_ARGS("cluster-stack", "const char *", "enum pcmk_pacemakerd_state")
1270 static int
1271 cluster_stack_xml(pcmk__output_t *out, va_list args) {
1272  const char *stack_s = va_arg(args, const char *);
1273  enum pcmk_pacemakerd_state pcmkd_state =
1274  (enum pcmk_pacemakerd_state) va_arg(args, int);
1275 
1276  const char *state_s = NULL;
1277 
1278  if (pcmkd_state != pcmk_pacemakerd_state_invalid) {
1279  state_s = pcmk_pacemakerd_api_daemon_state_enum2text(pcmkd_state);
1280  }
1281 
1283  PCMK_XA_TYPE, stack_s,
1284  PCMK_XA_PACEMAKERD_STATE, state_s,
1285  NULL);
1286 
1287  return pcmk_rc_ok;
1288 }
1289 
1290 PCMK__OUTPUT_ARGS("cluster-times", "const char *", "const char *",
1291  "const char *", "const char *", "const char *")
1292 static int
1293 cluster_times_html(pcmk__output_t *out, va_list args) {
1294  const char *our_nodename = va_arg(args, const char *);
1295  const char *last_written = va_arg(args, const char *);
1296  const char *user = va_arg(args, const char *);
1297  const char *client = va_arg(args, const char *);
1298  const char *origin = va_arg(args, const char *);
1299 
1300  xmlNodePtr updated_node = pcmk__output_create_xml_node(out, "li", NULL);
1301  xmlNodePtr changed_node = pcmk__output_create_xml_node(out, "li", NULL);
1302  xmlNode *child = NULL;
1303 
1304  char *time_s = NULL;
1305 
1306  child = pcmk__html_create(updated_node, PCMK__XE_SPAN, NULL,
1308  pcmk__xe_set_content(child, "Last updated: ");
1309 
1310  child = pcmk__html_create(updated_node, PCMK__XE_SPAN, NULL, NULL);
1311  time_s = pcmk__epoch2str(NULL, 0);
1312  pcmk__xe_set_content(child, "%s", time_s);
1313  free(time_s);
1314 
1315  if (our_nodename != NULL) {
1316  child = pcmk__html_create(updated_node, PCMK__XE_SPAN, NULL, NULL);
1317  pcmk__xe_set_content(child, " on ");
1318 
1319  child = pcmk__html_create(updated_node, PCMK__XE_SPAN, NULL, NULL);
1320  pcmk__xe_set_content(child, "%s", our_nodename);
1321  }
1322 
1323  child = pcmk__html_create(changed_node, PCMK__XE_SPAN, NULL,
1325  pcmk__xe_set_content(child, "Last change: ");
1326 
1327  child = pcmk__html_create(changed_node, PCMK__XE_SPAN, NULL, NULL);
1328  time_s = last_changed_string(last_written, user, client, origin);
1329  pcmk__xe_set_content(child, "%s", time_s);
1330  free(time_s);
1331 
1332  return pcmk_rc_ok;
1333 }
1334 
1335 PCMK__OUTPUT_ARGS("cluster-times", "const char *", "const char *",
1336  "const char *", "const char *", "const char *")
1337 static int
1338 cluster_times_xml(pcmk__output_t *out, va_list args) {
1339  const char *our_nodename = va_arg(args, const char *);
1340  const char *last_written = va_arg(args, const char *);
1341  const char *user = va_arg(args, const char *);
1342  const char *client = va_arg(args, const char *);
1343  const char *origin = va_arg(args, const char *);
1344 
1345  char *time_s = pcmk__epoch2str(NULL, 0);
1346 
1348  PCMK_XA_TIME, time_s,
1349  PCMK_XA_ORIGIN, our_nodename,
1350  NULL);
1351 
1353  PCMK_XA_TIME, pcmk__s(last_written, ""),
1354  PCMK_XA_USER, pcmk__s(user, ""),
1355  PCMK_XA_CLIENT, pcmk__s(client, ""),
1356  PCMK_XA_ORIGIN, pcmk__s(origin, ""),
1357  NULL);
1358 
1359  free(time_s);
1360  return pcmk_rc_ok;
1361 }
1362 
1363 PCMK__OUTPUT_ARGS("cluster-times", "const char *", "const char *",
1364  "const char *", "const char *", "const char *")
1365 static int
1366 cluster_times_text(pcmk__output_t *out, va_list args) {
1367  const char *our_nodename = va_arg(args, const char *);
1368  const char *last_written = va_arg(args, const char *);
1369  const char *user = va_arg(args, const char *);
1370  const char *client = va_arg(args, const char *);
1371  const char *origin = va_arg(args, const char *);
1372 
1373  char *time_s = pcmk__epoch2str(NULL, 0);
1374 
1375  out->list_item(out, "Last updated", "%s%s%s",
1376  time_s, (our_nodename != NULL)? " on " : "",
1377  pcmk__s(our_nodename, ""));
1378 
1379  free(time_s);
1380  time_s = last_changed_string(last_written, user, client, origin);
1381 
1382  out->list_item(out, "Last change", " %s", time_s);
1383 
1384  free(time_s);
1385  return pcmk_rc_ok;
1386 }
1387 
1401 static void
1402 failed_action_friendly(pcmk__output_t *out, const xmlNode *xml_op,
1403  const char *op_key, const char *node_name, int rc,
1404  int status, const char *exit_reason,
1405  const char *exec_time)
1406 {
1407  char *rsc_id = NULL;
1408  char *task = NULL;
1409  guint interval_ms = 0;
1410  time_t last_change_epoch = 0;
1411  GString *str = NULL;
1412 
1413  if (pcmk__str_empty(op_key)
1414  || !parse_op_key(op_key, &rsc_id, &task, &interval_ms)) {
1415 
1416  pcmk__str_update(&rsc_id, "unknown resource");
1417  pcmk__str_update(&task, "unknown action");
1418  interval_ms = 0;
1419  }
1420  pcmk__assert((rsc_id != NULL) && (task != NULL));
1421 
1422  str = g_string_sized_new(256); // Should be sufficient for most messages
1423 
1424  pcmk__g_strcat(str, rsc_id, " ", NULL);
1425 
1426  if (interval_ms != 0) {
1427  pcmk__g_strcat(str, pcmk__readable_interval(interval_ms), "-interval ",
1428  NULL);
1429  }
1430  pcmk__g_strcat(str, pcmk__readable_action(task, interval_ms), " on ",
1431  node_name, NULL);
1432 
1433  if (status == PCMK_EXEC_DONE) {
1434  pcmk__g_strcat(str, " returned '", services_ocf_exitcode_str(rc), "'",
1435  NULL);
1436  if (!pcmk__str_empty(exit_reason)) {
1437  pcmk__g_strcat(str, " (", exit_reason, ")", NULL);
1438  }
1439 
1440  } else {
1441  pcmk__g_strcat(str, " could not be executed (",
1442  pcmk_exec_status_str(status), NULL);
1443  if (!pcmk__str_empty(exit_reason)) {
1444  pcmk__g_strcat(str, ": ", exit_reason, NULL);
1445  }
1446  g_string_append_c(str, ')');
1447  }
1448 
1449 
1451  &last_change_epoch) == pcmk_ok) {
1452  char *s = pcmk__epoch2str(&last_change_epoch, 0);
1453 
1454  pcmk__g_strcat(str, " at ", s, NULL);
1455  free(s);
1456  }
1457  if (!pcmk__str_empty(exec_time)) {
1458  int exec_time_ms = 0;
1459 
1460  if ((pcmk__scan_min_int(exec_time, &exec_time_ms, 0) == pcmk_rc_ok)
1461  && (exec_time_ms > 0)) {
1462 
1463  pcmk__g_strcat(str, " after ",
1464  pcmk__readable_interval(exec_time_ms), NULL);
1465  }
1466  }
1467 
1468  out->list_item(out, NULL, "%s", str->str);
1469  g_string_free(str, TRUE);
1470  free(rsc_id);
1471  free(task);
1472 }
1473 
1487 static void
1488 failed_action_technical(pcmk__output_t *out, const xmlNode *xml_op,
1489  const char *op_key, const char *node_name, int rc,
1490  int status, const char *exit_reason,
1491  const char *exec_time)
1492 {
1493  const char *call_id = crm_element_value(xml_op, PCMK__XA_CALL_ID);
1494  const char *queue_time = crm_element_value(xml_op, PCMK_XA_QUEUE_TIME);
1495  const char *exit_status = services_ocf_exitcode_str(rc);
1496  const char *lrm_status = pcmk_exec_status_str(status);
1497  time_t last_change_epoch = 0;
1498  GString *str = NULL;
1499 
1500  if (pcmk__str_empty(op_key)) {
1501  op_key = "unknown operation";
1502  }
1503  if (pcmk__str_empty(exit_status)) {
1504  exit_status = "unknown exit status";
1505  }
1506  if (pcmk__str_empty(call_id)) {
1507  call_id = "unknown";
1508  }
1509 
1510  str = g_string_sized_new(256);
1511 
1512  g_string_append_printf(str, "%s on %s '%s' (%d): call=%s, status='%s'",
1513  op_key, node_name, exit_status, rc, call_id,
1514  lrm_status);
1515 
1516  if (!pcmk__str_empty(exit_reason)) {
1517  pcmk__g_strcat(str, ", exitreason='", exit_reason, "'", NULL);
1518  }
1519 
1521  &last_change_epoch) == pcmk_ok) {
1522  char *last_change_str = pcmk__epoch2str(&last_change_epoch, 0);
1523 
1524  pcmk__g_strcat(str,
1525  ", " PCMK_XA_LAST_RC_CHANGE "="
1526  "'", last_change_str, "'", NULL);
1527  free(last_change_str);
1528  }
1529  if (!pcmk__str_empty(queue_time)) {
1530  pcmk__g_strcat(str, ", queued=", queue_time, "ms", NULL);
1531  }
1532  if (!pcmk__str_empty(exec_time)) {
1533  pcmk__g_strcat(str, ", exec=", exec_time, "ms", NULL);
1534  }
1535 
1536  out->list_item(out, NULL, "%s", str->str);
1537  g_string_free(str, TRUE);
1538 }
1539 
1540 PCMK__OUTPUT_ARGS("failed-action", "xmlNode *", "uint32_t")
1541 static int
1542 failed_action_default(pcmk__output_t *out, va_list args)
1543 {
1544  xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1545  uint32_t show_opts = va_arg(args, uint32_t);
1546 
1547  const char *op_key = pcmk__xe_history_key(xml_op);
1548  const char *node_name = crm_element_value(xml_op, PCMK_XA_UNAME);
1549  const char *exit_reason = crm_element_value(xml_op, PCMK_XA_EXIT_REASON);
1550  const char *exec_time = crm_element_value(xml_op, PCMK_XA_EXEC_TIME);
1551 
1552  int rc;
1553  int status;
1554 
1556 
1558  0);
1559 
1560  if (pcmk__str_empty(node_name)) {
1561  node_name = "unknown node";
1562  }
1563 
1564  if (pcmk_is_set(show_opts, pcmk_show_failed_detail)) {
1565  failed_action_technical(out, xml_op, op_key, node_name, rc, status,
1566  exit_reason, exec_time);
1567  } else {
1568  failed_action_friendly(out, xml_op, op_key, node_name, rc, status,
1569  exit_reason, exec_time);
1570  }
1571  return pcmk_rc_ok;
1572 }
1573 
1574 PCMK__OUTPUT_ARGS("failed-action", "xmlNode *", "uint32_t")
1575 static int
1576 failed_action_xml(pcmk__output_t *out, va_list args) {
1577  xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1578  uint32_t show_opts G_GNUC_UNUSED = va_arg(args, uint32_t);
1579 
1580  const char *op_key = pcmk__xe_history_key(xml_op);
1581  const char *op_key_name = PCMK_XA_OP_KEY;
1582  int rc;
1583  int status;
1584  const char *uname = crm_element_value(xml_op, PCMK_XA_UNAME);
1585  const char *call_id = crm_element_value(xml_op, PCMK__XA_CALL_ID);
1586  const char *exitstatus = NULL;
1587  const char *exit_reason = pcmk__s(crm_element_value(xml_op,
1589  "none");
1590  const char *status_s = NULL;
1591 
1592  time_t epoch = 0;
1593  gchar *exit_reason_esc = NULL;
1594  char *rc_s = NULL;
1595  xmlNodePtr node = NULL;
1596 
1597  if (pcmk__xml_needs_escape(exit_reason, pcmk__xml_escape_attr)) {
1598  exit_reason_esc = pcmk__xml_escape(exit_reason, pcmk__xml_escape_attr);
1599  exit_reason = exit_reason_esc;
1600  }
1603  0);
1604 
1605  if (crm_element_value(xml_op, PCMK__XA_OPERATION_KEY) == NULL) {
1606  op_key_name = PCMK_XA_ID;
1607  }
1608  exitstatus = services_ocf_exitcode_str(rc);
1609  rc_s = pcmk__itoa(rc);
1610  status_s = pcmk_exec_status_str(status);
1612  op_key_name, op_key,
1614  PCMK_XA_EXITSTATUS, exitstatus,
1615  PCMK_XA_EXITREASON, exit_reason,
1616  PCMK_XA_EXITCODE, rc_s,
1617  PCMK_XA_CALL, call_id,
1618  PCMK_XA_STATUS, status_s,
1619  NULL);
1620  free(rc_s);
1621 
1623  &epoch) == pcmk_ok) && (epoch > 0)) {
1624 
1625  const char *queue_time = crm_element_value(xml_op, PCMK_XA_QUEUE_TIME);
1626  const char *exec = crm_element_value(xml_op, PCMK_XA_EXEC_TIME);
1627  const char *task = crm_element_value(xml_op, PCMK_XA_OPERATION);
1628  guint interval_ms = 0;
1629  char *interval_ms_s = NULL;
1630  char *rc_change = pcmk__epoch2str(&epoch,
1634 
1635  crm_element_value_ms(xml_op, PCMK_META_INTERVAL, &interval_ms);
1636  interval_ms_s = crm_strdup_printf("%u", interval_ms);
1637 
1638  pcmk__xe_set_props(node,
1639  PCMK_XA_LAST_RC_CHANGE, rc_change,
1640  PCMK_XA_QUEUED, queue_time,
1641  PCMK_XA_EXEC, exec,
1642  PCMK_XA_INTERVAL, interval_ms_s,
1643  PCMK_XA_TASK, task,
1644  NULL);
1645 
1646  free(interval_ms_s);
1647  free(rc_change);
1648  }
1649 
1650  g_free(exit_reason_esc);
1651  return pcmk_rc_ok;
1652 }
1653 
1654 PCMK__OUTPUT_ARGS("failed-action-list", "pcmk_scheduler_t *", "GList *",
1655  "GList *", "uint32_t", "bool")
1656 static int
1657 failed_action_list(pcmk__output_t *out, va_list args) {
1658  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
1659  GList *only_node = va_arg(args, GList *);
1660  GList *only_rsc = va_arg(args, GList *);
1661  uint32_t show_opts = va_arg(args, uint32_t);
1662  bool print_spacer = va_arg(args, int);
1663 
1664  xmlNode *xml_op = NULL;
1665  int rc = pcmk_rc_no_output;
1666 
1667  if (xmlChildElementCount(scheduler->failed) == 0) {
1668  return rc;
1669  }
1670 
1671  for (xml_op = pcmk__xe_first_child(scheduler->failed, NULL, NULL, NULL);
1672  xml_op != NULL; xml_op = pcmk__xe_next(xml_op)) {
1673 
1674  char *rsc = NULL;
1675 
1677  only_node,
1679  continue;
1680  }
1681 
1682  if (pcmk_xe_mask_probe_failure(xml_op)) {
1683  continue;
1684  }
1685 
1686  if (!parse_op_key(pcmk__xe_history_key(xml_op), &rsc, NULL, NULL)) {
1687  continue;
1688  }
1689 
1690  if (!pcmk__str_in_list(rsc, only_rsc, pcmk__str_star_matches)) {
1691  free(rsc);
1692  continue;
1693  }
1694 
1695  free(rsc);
1696 
1697  PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Failed Resource Actions");
1698  out->message(out, "failed-action", xml_op, show_opts);
1699  }
1700 
1701  PCMK__OUTPUT_LIST_FOOTER(out, rc);
1702  return rc;
1703 }
1704 
1705 static void
1706 status_node(pcmk_node_t *node, xmlNodePtr parent, uint32_t show_opts)
1707 {
1708  int health = pe__node_health(node);
1709  xmlNode *child = NULL;
1710 
1711  // Cluster membership
1712  if (node->details->online) {
1713  child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1715  pcmk__xe_set_content(child, " online");
1716 
1717  } else {
1718  child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1720  pcmk__xe_set_content(child, " OFFLINE");
1721  }
1722 
1723  // Standby mode
1724  if (node->details->standby_onfail && (node->details->running_rsc != NULL)) {
1725  child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1727  pcmk__xe_set_content(child,
1728  " (in standby due to " PCMK_META_ON_FAIL ","
1729  " with active resources)");
1730 
1731  } else if (node->details->standby_onfail) {
1732  child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1734  pcmk__xe_set_content(child,
1735  " (in standby due to " PCMK_META_ON_FAIL ")");
1736 
1737  } else if (node->details->standby && (node->details->running_rsc != NULL)) {
1738  child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1740  pcmk__xe_set_content(child,
1741  " (in standby, with active resources)");
1742 
1743  } else if (node->details->standby) {
1744  child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1746  pcmk__xe_set_content(child, " (in standby)");
1747  }
1748 
1749  // Maintenance mode
1750  if (node->details->maintenance) {
1751  child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1753  pcmk__xe_set_content(child, " (in maintenance mode)");
1754  }
1755 
1756  // Node health
1757  if (health < 0) {
1758  child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1760  pcmk__xe_set_content(child, " (health is RED)");
1761 
1762  } else if (health == 0) {
1763  child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1765  pcmk__xe_set_content(child, " (health is YELLOW)");
1766  }
1767 
1768  // Feature set
1769  if (pcmk_is_set(show_opts, pcmk_show_feature_set)) {
1770  const char *feature_set = get_node_feature_set(node);
1771  if (feature_set != NULL) {
1772  child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL, NULL);
1773  pcmk__xe_set_content(child, ", feature set %s", feature_set);
1774  }
1775  }
1776 }
1777 
1778 PCMK__OUTPUT_ARGS("node", "pcmk_node_t *", "uint32_t", "bool",
1779  "GList *", "GList *")
1780 static int
1781 node_html(pcmk__output_t *out, va_list args) {
1782  pcmk_node_t *node = va_arg(args, pcmk_node_t *);
1783  uint32_t show_opts = va_arg(args, uint32_t);
1784  bool full = va_arg(args, int);
1785  GList *only_node = va_arg(args, GList *);
1786  GList *only_rsc = va_arg(args, GList *);
1787 
1788  char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1789 
1790  if (full) {
1791  xmlNode *item_node = NULL;
1792  xmlNode *child = NULL;
1793 
1794  if (pcmk_all_flags_set(show_opts, pcmk_show_brief | pcmk_show_rscs_by_node)) {
1795  GList *rscs = pe__filter_rsc_list(node->details->running_rsc, only_rsc);
1796 
1797  out->begin_list(out, NULL, NULL, "%s:", node_name);
1798  item_node = pcmk__output_xml_create_parent(out, "li", NULL);
1799  child = pcmk__html_create(item_node, PCMK__XE_SPAN, NULL, NULL);
1800  pcmk__xe_set_content(child, "Status:");
1801  status_node(node, item_node, show_opts);
1802 
1803  if (rscs != NULL) {
1804  uint32_t new_show_opts = (show_opts | pcmk_show_rsc_only) & ~pcmk_show_inactive_rscs;
1805  out->begin_list(out, NULL, NULL, "Resources");
1806  pe__rscs_brief_output(out, rscs, new_show_opts);
1807  out->end_list(out);
1808  }
1809 
1811  out->end_list(out);
1812 
1813  } else if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
1814  GList *lpc2 = NULL;
1815  int rc = pcmk_rc_no_output;
1816 
1817  out->begin_list(out, NULL, NULL, "%s:", node_name);
1818  item_node = pcmk__output_xml_create_parent(out, "li", NULL);
1819  child = pcmk__html_create(item_node, PCMK__XE_SPAN, NULL, NULL);
1820  pcmk__xe_set_content(child, "Status:");
1821  status_node(node, item_node, show_opts);
1822 
1823  for (lpc2 = node->details->running_rsc; lpc2 != NULL; lpc2 = lpc2->next) {
1824  pcmk_resource_t *rsc = (pcmk_resource_t *) lpc2->data;
1825  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Resources");
1826 
1827  show_opts |= pcmk_show_rsc_only;
1828  out->message(out, pcmk__map_element_name(rsc->xml), show_opts,
1829  rsc, only_node, only_rsc);
1830  }
1831 
1832  PCMK__OUTPUT_LIST_FOOTER(out, rc);
1834  out->end_list(out);
1835 
1836  } else {
1837  item_node = pcmk__output_create_xml_node(out, "li", NULL);
1838  child = pcmk__html_create(item_node, PCMK__XE_SPAN, NULL,
1840  pcmk__xe_set_content(child, "%s:", node_name);
1841  status_node(node, item_node, show_opts);
1842  }
1843  } else {
1844  out->begin_list(out, NULL, NULL, "%s:", node_name);
1845  }
1846 
1847  free(node_name);
1848  return pcmk_rc_ok;
1849 }
1850 
1859 static const char *
1860 node_text_status(const pcmk_node_t *node)
1861 {
1862  if (node->details->unclean) {
1863  if (node->details->online) {
1864  return "UNCLEAN (online)";
1865 
1866  } else if (node->details->pending) {
1867  return "UNCLEAN (pending)";
1868 
1869  } else {
1870  return "UNCLEAN (offline)";
1871  }
1872 
1873  } else if (node->details->pending) {
1874  return "pending";
1875 
1876  } else if (node->details->standby_onfail && node->details->online) {
1877  return "standby (" PCMK_META_ON_FAIL ")";
1878 
1879  } else if (node->details->standby) {
1880  if (node->details->online) {
1881  if (node->details->running_rsc) {
1882  return "standby (with active resources)";
1883  } else {
1884  return "standby";
1885  }
1886  } else {
1887  return "OFFLINE (standby)";
1888  }
1889 
1890  } else if (node->details->maintenance) {
1891  if (node->details->online) {
1892  return "maintenance";
1893  } else {
1894  return "OFFLINE (maintenance)";
1895  }
1896 
1897  } else if (node->details->online) {
1898  return "online";
1899  }
1900 
1901  return "OFFLINE";
1902 }
1903 
1904 PCMK__OUTPUT_ARGS("node", "pcmk_node_t *", "uint32_t", "bool", "GList *",
1905  "GList *")
1906 static int
1907 node_text(pcmk__output_t *out, va_list args) {
1908  pcmk_node_t *node = va_arg(args, pcmk_node_t *);
1909  uint32_t show_opts = va_arg(args, uint32_t);
1910  bool full = va_arg(args, int);
1911  GList *only_node = va_arg(args, GList *);
1912  GList *only_rsc = va_arg(args, GList *);
1913 
1914  if (full) {
1915  char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1916  GString *str = g_string_sized_new(64);
1917  int health = pe__node_health(node);
1918 
1919  // Create a summary line with node type, name, and status
1920  if (pcmk__is_guest_or_bundle_node(node)) {
1921  g_string_append(str, "GuestNode");
1922  } else if (pcmk__is_remote_node(node)) {
1923  g_string_append(str, "RemoteNode");
1924  } else {
1925  g_string_append(str, "Node");
1926  }
1927  pcmk__g_strcat(str, " ", node_name, ": ", node_text_status(node), NULL);
1928 
1929  if (health < 0) {
1930  g_string_append(str, " (health is RED)");
1931  } else if (health == 0) {
1932  g_string_append(str, " (health is YELLOW)");
1933  }
1934  if (pcmk_is_set(show_opts, pcmk_show_feature_set)) {
1935  const char *feature_set = get_node_feature_set(node);
1936  if (feature_set != NULL) {
1937  pcmk__g_strcat(str, ", feature set ", feature_set, NULL);
1938  }
1939  }
1940 
1941  /* If we're grouping by node, print its resources */
1942  if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
1943  if (pcmk_is_set(show_opts, pcmk_show_brief)) {
1944  GList *rscs = pe__filter_rsc_list(node->details->running_rsc, only_rsc);
1945 
1946  if (rscs != NULL) {
1947  uint32_t new_show_opts = (show_opts | pcmk_show_rsc_only) & ~pcmk_show_inactive_rscs;
1948  out->begin_list(out, NULL, NULL, "%s", str->str);
1949  out->begin_list(out, NULL, NULL, "Resources");
1950 
1951  pe__rscs_brief_output(out, rscs, new_show_opts);
1952 
1953  out->end_list(out);
1954  out->end_list(out);
1955 
1956  g_list_free(rscs);
1957  }
1958 
1959  } else {
1960  GList *gIter2 = NULL;
1961 
1962  out->begin_list(out, NULL, NULL, "%s", str->str);
1963  out->begin_list(out, NULL, NULL, "Resources");
1964 
1965  for (gIter2 = node->details->running_rsc; gIter2 != NULL; gIter2 = gIter2->next) {
1966  pcmk_resource_t *rsc = (pcmk_resource_t *) gIter2->data;
1967 
1968  show_opts |= pcmk_show_rsc_only;
1969  out->message(out, pcmk__map_element_name(rsc->xml),
1970  show_opts, rsc, only_node, only_rsc);
1971  }
1972 
1973  out->end_list(out);
1974  out->end_list(out);
1975  }
1976  } else {
1977  out->list_item(out, NULL, "%s", str->str);
1978  }
1979 
1980  g_string_free(str, TRUE);
1981  free(node_name);
1982  } else {
1983  char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1984  out->begin_list(out, NULL, NULL, "Node: %s", node_name);
1985  free(node_name);
1986  }
1987 
1988  return pcmk_rc_ok;
1989 }
1990 
2001 static const char *
2002 health_text(int health)
2003 {
2004  if (health < 0) {
2005  return PCMK_VALUE_RED;
2006  } else if (health == 0) {
2007  return PCMK_VALUE_YELLOW;
2008  } else {
2009  return PCMK_VALUE_GREEN;
2010  }
2011 }
2012 
2024 static const char *
2025 node_type_str(enum node_type type)
2026 {
2027  switch (type) {
2029  return PCMK_VALUE_MEMBER;
2031  return PCMK_VALUE_REMOTE;
2032  case node_ping:
2033  return PCMK__VALUE_PING;
2034  default:
2035  return PCMK_VALUE_UNKNOWN;
2036  }
2037 }
2038 
2039 PCMK__OUTPUT_ARGS("node", "pcmk_node_t *", "uint32_t", "bool", "GList *",
2040  "GList *")
2041 static int
2042 node_xml(pcmk__output_t *out, va_list args) {
2043  pcmk_node_t *node = va_arg(args, pcmk_node_t *);
2044  uint32_t show_opts G_GNUC_UNUSED = va_arg(args, uint32_t);
2045  bool full = va_arg(args, int);
2046  GList *only_node = va_arg(args, GList *);
2047  GList *only_rsc = va_arg(args, GList *);
2048 
2049  if (full) {
2050  const char *online = pcmk__btoa(node->details->online);
2051  const char *standby = pcmk__btoa(node->details->standby);
2052  const char *standby_onfail = pcmk__btoa(node->details->standby_onfail);
2053  const char *maintenance = pcmk__btoa(node->details->maintenance);
2054  const char *pending = pcmk__btoa(node->details->pending);
2055  const char *unclean = pcmk__btoa(node->details->unclean);
2056  const char *health = health_text(pe__node_health(node));
2057  const char *feature_set = get_node_feature_set(node);
2058  const char *shutdown = pcmk__btoa(node->details->shutdown);
2059  const char *expected_up = pcmk__btoa(node->details->expected_up);
2060  const char *is_dc = pcmk__btoa(node->details->is_dc);
2061  int length = g_list_length(node->details->running_rsc);
2062  char *resources_running = pcmk__itoa(length);
2063  const char *node_type = node_type_str(node->details->type);
2064 
2065  int rc = pcmk_rc_ok;
2066 
2067  rc = pe__name_and_nvpairs_xml(out, true, PCMK_XE_NODE,
2068  PCMK_XA_NAME, node->details->uname,
2069  PCMK_XA_ID, node->details->id,
2070  PCMK_XA_ONLINE, online,
2071  PCMK_XA_STANDBY, standby,
2072  PCMK_XA_STANDBY_ONFAIL, standby_onfail,
2073  PCMK_XA_MAINTENANCE, maintenance,
2074  PCMK_XA_PENDING, pending,
2075  PCMK_XA_UNCLEAN, unclean,
2076  PCMK_XA_HEALTH, health,
2077  PCMK_XA_FEATURE_SET, feature_set,
2078  PCMK_XA_SHUTDOWN, shutdown,
2079  PCMK_XA_EXPECTED_UP, expected_up,
2080  PCMK_XA_IS_DC, is_dc,
2081  PCMK_XA_RESOURCES_RUNNING, resources_running,
2083  NULL);
2084 
2085  free(resources_running);
2086  pcmk__assert(rc == pcmk_rc_ok);
2087 
2088  if (pcmk__is_guest_or_bundle_node(node)) {
2089  xmlNodePtr xml_node = pcmk__output_xml_peek_parent(out);
2091  node->details->remote_rsc->container->id);
2092  }
2093 
2094  if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2095  GList *lpc = NULL;
2096 
2097  for (lpc = node->details->running_rsc; lpc != NULL; lpc = lpc->next) {
2098  pcmk_resource_t *rsc = (pcmk_resource_t *) lpc->data;
2099 
2100  show_opts |= pcmk_show_rsc_only;
2101  out->message(out, pcmk__map_element_name(rsc->xml), show_opts,
2102  rsc, only_node, only_rsc);
2103  }
2104  }
2105 
2106  out->end_list(out);
2107  } else {
2109  PCMK_XA_NAME, node->details->uname,
2110  NULL);
2111  }
2112 
2113  return pcmk_rc_ok;
2114 }
2115 
2116 PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "bool", "int")
2117 static int
2118 node_attribute_text(pcmk__output_t *out, va_list args) {
2119  const char *name = va_arg(args, const char *);
2120  const char *value = va_arg(args, const char *);
2121  bool add_extra = va_arg(args, int);
2122  int expected_score = va_arg(args, int);
2123 
2124  if (add_extra) {
2125  int v;
2126 
2127  if (value == NULL) {
2128  v = 0;
2129  } else {
2130  pcmk__scan_min_int(value, &v, INT_MIN);
2131  }
2132  if (v <= 0) {
2133  out->list_item(out, NULL, "%-32s\t: %-10s\t: Connectivity is lost", name, value);
2134  } else if (v < expected_score) {
2135  out->list_item(out, NULL, "%-32s\t: %-10s\t: Connectivity is degraded (Expected=%d)", name, value, expected_score);
2136  } else {
2137  out->list_item(out, NULL, "%-32s\t: %-10s", name, value);
2138  }
2139  } else {
2140  out->list_item(out, NULL, "%-32s\t: %-10s", name, value);
2141  }
2142 
2143  return pcmk_rc_ok;
2144 }
2145 
2146 PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "bool", "int")
2147 static int
2148 node_attribute_html(pcmk__output_t *out, va_list args) {
2149  const char *name = va_arg(args, const char *);
2150  const char *value = va_arg(args, const char *);
2151  bool add_extra = va_arg(args, int);
2152  int expected_score = va_arg(args, int);
2153 
2154  if (add_extra) {
2155  int v = 0;
2156  xmlNodePtr item_node = pcmk__output_create_xml_node(out, "li", NULL);
2157  xmlNode *child = NULL;
2158 
2159  if (value != NULL) {
2160  pcmk__scan_min_int(value, &v, INT_MIN);
2161  }
2162 
2163  child = pcmk__html_create(item_node, PCMK__XE_SPAN, NULL, NULL);
2164  pcmk__xe_set_content(child, "%s: %s", name, value);
2165 
2166  if (v <= 0) {
2167  child = pcmk__html_create(item_node, PCMK__XE_SPAN, NULL,
2169  pcmk__xe_set_content(child, "(connectivity is lost)");
2170 
2171  } else if (v < expected_score) {
2172  child = pcmk__html_create(item_node, PCMK__XE_SPAN, NULL,
2174  pcmk__xe_set_content(child,
2175  "(connectivity is degraded -- expected %d)",
2176  expected_score);
2177  }
2178  } else {
2179  out->list_item(out, NULL, "%s: %s", name, value);
2180  }
2181 
2182  return pcmk_rc_ok;
2183 }
2184 
2185 PCMK__OUTPUT_ARGS("node-and-op", "pcmk_scheduler_t *", "xmlNode *")
2186 static int
2187 node_and_op(pcmk__output_t *out, va_list args) {
2188  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
2189  xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
2190 
2191  pcmk_resource_t *rsc = NULL;
2192  gchar *node_str = NULL;
2193  char *last_change_str = NULL;
2194 
2195  const char *op_rsc = crm_element_value(xml_op, PCMK_XA_RESOURCE);
2196  int status;
2197  time_t last_change = 0;
2198 
2201 
2202  rsc = pe_find_resource(scheduler->resources, op_rsc);
2203 
2204  if (rsc) {
2205  const pcmk_node_t *node = pcmk__current_node(rsc);
2206  const char *target_role = g_hash_table_lookup(rsc->meta,
2208  uint32_t show_opts = pcmk_show_rsc_only | pcmk_show_pending;
2209 
2210  if (node == NULL) {
2211  node = rsc->pending_node;
2212  }
2213 
2214  node_str = pcmk__native_output_string(rsc, rsc_printable_id(rsc), node,
2215  show_opts, target_role, false);
2216  } else {
2217  node_str = crm_strdup_printf("Unknown resource %s", op_rsc);
2218  }
2219 
2221  &last_change) == pcmk_ok) {
2222  const char *exec_time = crm_element_value(xml_op, PCMK_XA_EXEC_TIME);
2223 
2224  last_change_str = crm_strdup_printf(", %s='%s', exec=%sms",
2226  pcmk__trim(ctime(&last_change)),
2227  exec_time);
2228  }
2229 
2230  out->list_item(out, NULL, "%s: %s (node=%s, call=%s, rc=%s%s): %s",
2231  node_str, pcmk__xe_history_key(xml_op),
2235  last_change_str ? last_change_str : "",
2236  pcmk_exec_status_str(status));
2237 
2238  g_free(node_str);
2239  free(last_change_str);
2240  return pcmk_rc_ok;
2241 }
2242 
2243 PCMK__OUTPUT_ARGS("node-and-op", "pcmk_scheduler_t *", "xmlNode *")
2244 static int
2245 node_and_op_xml(pcmk__output_t *out, va_list args) {
2246  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
2247  xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
2248 
2249  pcmk_resource_t *rsc = NULL;
2250  const char *uname = crm_element_value(xml_op, PCMK_XA_UNAME);
2251  const char *call_id = crm_element_value(xml_op, PCMK__XA_CALL_ID);
2252  const char *rc_s = crm_element_value(xml_op, PCMK__XA_RC_CODE);
2253  const char *status_s = NULL;
2254  const char *op_rsc = crm_element_value(xml_op, PCMK_XA_RESOURCE);
2255  int status;
2256  time_t last_change = 0;
2257  xmlNode *node = NULL;
2258 
2260  &status, PCMK_EXEC_UNKNOWN);
2261  status_s = pcmk_exec_status_str(status);
2262 
2264  PCMK_XA_OP, pcmk__xe_history_key(xml_op),
2266  PCMK_XA_CALL, call_id,
2267  PCMK_XA_RC, rc_s,
2268  PCMK_XA_STATUS, status_s,
2269  NULL);
2270 
2271  rsc = pe_find_resource(scheduler->resources, op_rsc);
2272 
2273  if (rsc) {
2274  const char *class = crm_element_value(rsc->xml, PCMK_XA_CLASS);
2275  const char *provider = crm_element_value(rsc->xml, PCMK_XA_PROVIDER);
2276  const char *kind = crm_element_value(rsc->xml, PCMK_XA_TYPE);
2277  bool has_provider = pcmk_is_set(pcmk_get_ra_caps(class),
2279 
2280  char *agent_tuple = crm_strdup_printf("%s:%s:%s",
2281  class,
2282  (has_provider? provider : ""),
2283  kind);
2284 
2285  pcmk__xe_set_props(node,
2287  PCMK_XA_AGENT, agent_tuple,
2288  NULL);
2289  free(agent_tuple);
2290  }
2291 
2293  &last_change) == pcmk_ok) {
2294  const char *last_rc_change = pcmk__trim(ctime(&last_change));
2295  const char *exec_time = crm_element_value(xml_op, PCMK_XA_EXEC_TIME);
2296 
2297  pcmk__xe_set_props(node,
2298  PCMK_XA_LAST_RC_CHANGE, last_rc_change,
2299  PCMK_XA_EXEC_TIME, exec_time,
2300  NULL);
2301  }
2302 
2303  return pcmk_rc_ok;
2304 }
2305 
2306 PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "bool", "int")
2307 static int
2308 node_attribute_xml(pcmk__output_t *out, va_list args) {
2309  const char *name = va_arg(args, const char *);
2310  const char *value = va_arg(args, const char *);
2311  bool add_extra = va_arg(args, int);
2312  int expected_score = va_arg(args, int);
2313 
2314  xmlNodePtr node = pcmk__output_create_xml_node(out, PCMK_XE_ATTRIBUTE,
2315  PCMK_XA_NAME, name,
2316  PCMK_XA_VALUE, value,
2317  NULL);
2318 
2319  if (add_extra) {
2320  char *buf = pcmk__itoa(expected_score);
2321  crm_xml_add(node, PCMK_XA_EXPECTED, buf);
2322  free(buf);
2323  }
2324 
2325  return pcmk_rc_ok;
2326 }
2327 
2328 PCMK__OUTPUT_ARGS("node-attribute-list", "pcmk_scheduler_t *", "uint32_t",
2329  "bool", "GList *", "GList *")
2330 static int
2331 node_attribute_list(pcmk__output_t *out, va_list args) {
2332  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
2333  uint32_t show_opts = va_arg(args, uint32_t);
2334  bool print_spacer = va_arg(args, int);
2335  GList *only_node = va_arg(args, GList *);
2336  GList *only_rsc = va_arg(args, GList *);
2337 
2338  int rc = pcmk_rc_no_output;
2339 
2340  /* Display each node's attributes */
2341  for (GList *gIter = scheduler->nodes; gIter != NULL; gIter = gIter->next) {
2342  pcmk_node_t *node = gIter->data;
2343 
2344  GList *attr_list = NULL;
2345  GHashTableIter iter;
2346  gpointer key;
2347 
2348  if (!node || !node->details || !node->details->online) {
2349  continue;
2350  }
2351 
2352  g_hash_table_iter_init(&iter, node->details->attrs);
2353  while (g_hash_table_iter_next (&iter, &key, NULL)) {
2354  attr_list = filter_attr_list(attr_list, key);
2355  }
2356 
2357  if (attr_list == NULL) {
2358  continue;
2359  }
2360 
2362  g_list_free(attr_list);
2363  continue;
2364  }
2365 
2366  PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Node Attributes");
2367 
2368  out->message(out, "node", node, show_opts, false, only_node, only_rsc);
2369 
2370  for (GList *aIter = attr_list; aIter != NULL; aIter = aIter->next) {
2371  const char *name = aIter->data;
2372  const char *value = NULL;
2373  int expected_score = 0;
2374  bool add_extra = false;
2375 
2376  value = pcmk__node_attr(node, name, NULL, pcmk__rsc_node_current);
2377 
2378  add_extra = add_extra_info(node, node->details->running_rsc,
2379  scheduler, name, &expected_score);
2380 
2381  /* Print attribute name and value */
2382  out->message(out, "node-attribute", name, value, add_extra,
2383  expected_score);
2384  }
2385 
2386  g_list_free(attr_list);
2387  out->end_list(out);
2388  }
2389 
2390  PCMK__OUTPUT_LIST_FOOTER(out, rc);
2391  return rc;
2392 }
2393 
2394 PCMK__OUTPUT_ARGS("node-capacity", "const pcmk_node_t *", "const char *")
2395 static int
2396 node_capacity(pcmk__output_t *out, va_list args)
2397 {
2398  const pcmk_node_t *node = va_arg(args, pcmk_node_t *);
2399  const char *comment = va_arg(args, const char *);
2400 
2401  char *dump_text = crm_strdup_printf("%s: %s capacity:",
2402  comment, pcmk__node_name(node));
2403 
2404  g_hash_table_foreach(node->details->utilization, append_dump_text, &dump_text);
2405  out->list_item(out, NULL, "%s", dump_text);
2406  free(dump_text);
2407 
2408  return pcmk_rc_ok;
2409 }
2410 
2411 PCMK__OUTPUT_ARGS("node-capacity", "const pcmk_node_t *", "const char *")
2412 static int
2413 node_capacity_xml(pcmk__output_t *out, va_list args)
2414 {
2415  const pcmk_node_t *node = va_arg(args, pcmk_node_t *);
2416  const char *uname = node->details->uname;
2417  const char *comment = va_arg(args, const char *);
2418 
2419  xmlNodePtr xml_node = pcmk__output_create_xml_node(out, PCMK_XE_CAPACITY,
2421  PCMK_XA_COMMENT, comment,
2422  NULL);
2423  g_hash_table_foreach(node->details->utilization, add_dump_node, xml_node);
2424 
2425  return pcmk_rc_ok;
2426 }
2427 
2428 PCMK__OUTPUT_ARGS("node-history-list", "pcmk_scheduler_t *", "pcmk_node_t *",
2429  "xmlNode *", "GList *", "GList *", "uint32_t", "uint32_t")
2430 static int
2431 node_history_list(pcmk__output_t *out, va_list args) {
2432  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
2433  pcmk_node_t *node = va_arg(args, pcmk_node_t *);
2434  xmlNode *node_state = va_arg(args, xmlNode *);
2435  GList *only_node = va_arg(args, GList *);
2436  GList *only_rsc = va_arg(args, GList *);
2437  uint32_t section_opts = va_arg(args, uint32_t);
2438  uint32_t show_opts = va_arg(args, uint32_t);
2439 
2440  xmlNode *lrm_rsc = NULL;
2441  xmlNode *rsc_entry = NULL;
2442  int rc = pcmk_rc_no_output;
2443 
2444  lrm_rsc = pcmk__xe_first_child(node_state, PCMK__XE_LRM, NULL, NULL);
2445  lrm_rsc = pcmk__xe_first_child(lrm_rsc, PCMK__XE_LRM_RESOURCES, NULL, NULL);
2446 
2447  /* Print history of each of the node's resources */
2448  for (rsc_entry = pcmk__xe_first_child(lrm_rsc, PCMK__XE_LRM_RESOURCE, NULL,
2449  NULL);
2450  rsc_entry != NULL; rsc_entry = pcmk__xe_next_same(rsc_entry)) {
2451 
2452  const char *rsc_id = crm_element_value(rsc_entry, PCMK_XA_ID);
2453  pcmk_resource_t *rsc = NULL;
2454  const pcmk_resource_t *parent = NULL;
2455 
2456  if (rsc_id == NULL) {
2457  continue; // Malformed entry
2458  }
2459 
2460  rsc = pe_find_resource(scheduler->resources, rsc_id);
2461  if (rsc == NULL) {
2462  continue; // Resource was removed from configuration
2463  }
2464 
2465  /* We can't use is_filtered here to filter group resources. For is_filtered,
2466  * we have to decide whether to check the parent or not. If we check the
2467  * parent, all elements of a group will always be printed because that's how
2468  * is_filtered works for groups. If we do not check the parent, sometimes
2469  * this will filter everything out.
2470  *
2471  * For other resource types, is_filtered is okay.
2472  */
2473  parent = pe__const_top_resource(rsc, false);
2474  if (pcmk__is_group(parent)) {
2475  if (!pcmk__str_in_list(rsc_printable_id(rsc), only_rsc,
2477  && !pcmk__str_in_list(rsc_printable_id(parent), only_rsc,
2479  continue;
2480  }
2481  } else {
2482  if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
2483  continue;
2484  }
2485  }
2486 
2487  if (!pcmk_is_set(section_opts, pcmk_section_operations)) {
2488  time_t last_failure = 0;
2489  int failcount = pe_get_failcount(node, rsc, &last_failure,
2490  pcmk__fc_default, NULL);
2491 
2492  if (failcount <= 0) {
2493  continue;
2494  }
2495 
2496  if (rc == pcmk_rc_no_output) {
2497  rc = pcmk_rc_ok;
2498  out->message(out, "node", node, show_opts, false, only_node,
2499  only_rsc);
2500  }
2501 
2502  out->message(out, "resource-history", rsc, rsc_id, false,
2503  failcount, last_failure, false);
2504  } else {
2505  GList *op_list = get_operation_list(rsc_entry);
2506  pcmk_resource_t *rsc = NULL;
2507 
2508  if (op_list == NULL) {
2509  continue;
2510  }
2511 
2513  crm_element_value(rsc_entry, PCMK_XA_ID));
2514 
2515  if (rc == pcmk_rc_no_output) {
2516  rc = pcmk_rc_ok;
2517  out->message(out, "node", node, show_opts, false, only_node,
2518  only_rsc);
2519  }
2520 
2521  out->message(out, "resource-operation-list", scheduler, rsc, node,
2522  op_list, show_opts);
2523  }
2524  }
2525 
2526  PCMK__OUTPUT_LIST_FOOTER(out, rc);
2527  return rc;
2528 }
2529 
2530 PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "uint32_t", "bool")
2531 static int
2532 node_list_html(pcmk__output_t *out, va_list args) {
2533  GList *nodes = va_arg(args, GList *);
2534  GList *only_node = va_arg(args, GList *);
2535  GList *only_rsc = va_arg(args, GList *);
2536  uint32_t show_opts = va_arg(args, uint32_t);
2537  bool print_spacer G_GNUC_UNUSED = va_arg(args, int);
2538 
2539  int rc = pcmk_rc_no_output;
2540 
2541  for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
2542  pcmk_node_t *node = (pcmk_node_t *) gIter->data;
2543 
2544  if (!pcmk__str_in_list(node->details->uname, only_node,
2546  continue;
2547  }
2548 
2549  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Node List");
2550 
2551  out->message(out, "node", node, show_opts, true, only_node, only_rsc);
2552  }
2553 
2554  PCMK__OUTPUT_LIST_FOOTER(out, rc);
2555  return rc;
2556 }
2557 
2558 PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "uint32_t", "bool")
2559 static int
2560 node_list_text(pcmk__output_t *out, va_list args) {
2561  GList *nodes = va_arg(args, GList *);
2562  GList *only_node = va_arg(args, GList *);
2563  GList *only_rsc = va_arg(args, GList *);
2564  uint32_t show_opts = va_arg(args, uint32_t);
2565  bool print_spacer = va_arg(args, int);
2566 
2567  /* space-separated lists of node names */
2568  GString *online_nodes = NULL;
2569  GString *online_remote_nodes = NULL;
2570  GString *online_guest_nodes = NULL;
2571  GString *offline_nodes = NULL;
2572  GString *offline_remote_nodes = NULL;
2573 
2574  int rc = pcmk_rc_no_output;
2575 
2576  for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
2577  pcmk_node_t *node = (pcmk_node_t *) gIter->data;
2578  char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
2579 
2580  if (!pcmk__str_in_list(node->details->uname, only_node,
2582  free(node_name);
2583  continue;
2584  }
2585 
2586  PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Node List");
2587 
2588  // Determine whether to display node individually or in a list
2589  if (node->details->unclean || node->details->pending
2590  || (node->details->standby_onfail && node->details->online)
2591  || node->details->standby || node->details->maintenance
2592  || pcmk_is_set(show_opts, pcmk_show_rscs_by_node)
2593  || pcmk_is_set(show_opts, pcmk_show_feature_set)
2594  || (pe__node_health(node) <= 0)) {
2595  // Display node individually
2596 
2597  } else if (node->details->online) {
2598  // Display online node in a list
2599  if (pcmk__is_guest_or_bundle_node(node)) {
2600  pcmk__add_word(&online_guest_nodes, 1024, node_name);
2601 
2602  } else if (pcmk__is_remote_node(node)) {
2603  pcmk__add_word(&online_remote_nodes, 1024, node_name);
2604 
2605  } else {
2606  pcmk__add_word(&online_nodes, 1024, node_name);
2607  }
2608  free(node_name);
2609  continue;
2610 
2611  } else {
2612  // Display offline node in a list
2613  if (pcmk__is_remote_node(node)) {
2614  pcmk__add_word(&offline_remote_nodes, 1024, node_name);
2615 
2616  } else if (pcmk__is_guest_or_bundle_node(node)) {
2617  /* ignore offline guest nodes */
2618 
2619  } else {
2620  pcmk__add_word(&offline_nodes, 1024, node_name);
2621  }
2622  free(node_name);
2623  continue;
2624  }
2625 
2626  /* If we get here, node is in bad state, or we're grouping by node */
2627  out->message(out, "node", node, show_opts, true, only_node, only_rsc);
2628  free(node_name);
2629  }
2630 
2631  /* If we're not grouping by node, summarize nodes by status */
2632  if (online_nodes != NULL) {
2633  out->list_item(out, "Online", "[ %s ]",
2634  (const char *) online_nodes->str);
2635  g_string_free(online_nodes, TRUE);
2636  }
2637  if (offline_nodes != NULL) {
2638  out->list_item(out, "OFFLINE", "[ %s ]",
2639  (const char *) offline_nodes->str);
2640  g_string_free(offline_nodes, TRUE);
2641  }
2642  if (online_remote_nodes) {
2643  out->list_item(out, "RemoteOnline", "[ %s ]",
2644  (const char *) online_remote_nodes->str);
2645  g_string_free(online_remote_nodes, TRUE);
2646  }
2647  if (offline_remote_nodes) {
2648  out->list_item(out, "RemoteOFFLINE", "[ %s ]",
2649  (const char *) offline_remote_nodes->str);
2650  g_string_free(offline_remote_nodes, TRUE);
2651  }
2652  if (online_guest_nodes != NULL) {
2653  out->list_item(out, "GuestOnline", "[ %s ]",
2654  (const char *) online_guest_nodes->str);
2655  g_string_free(online_guest_nodes, TRUE);
2656  }
2657 
2658  PCMK__OUTPUT_LIST_FOOTER(out, rc);
2659  return rc;
2660 }
2661 
2662 PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "uint32_t", "bool")
2663 static int
2664 node_list_xml(pcmk__output_t *out, va_list args) {
2665  GList *nodes = va_arg(args, GList *);
2666  GList *only_node = va_arg(args, GList *);
2667  GList *only_rsc = va_arg(args, GList *);
2668  uint32_t show_opts = va_arg(args, uint32_t);
2669  bool print_spacer G_GNUC_UNUSED = va_arg(args, int);
2670 
2671  /* PCMK_XE_NODES acts as the list's element name for CLI tools that use
2672  * pcmk__output_enable_list_element. Otherwise PCMK_XE_NODES is the
2673  * value of the list's PCMK_XA_NAME attribute.
2674  */
2675  out->begin_list(out, NULL, NULL, PCMK_XE_NODES);
2676  for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
2677  pcmk_node_t *node = (pcmk_node_t *) gIter->data;
2678 
2679  if (!pcmk__str_in_list(node->details->uname, only_node,
2681  continue;
2682  }
2683 
2684  out->message(out, "node", node, show_opts, true, only_node, only_rsc);
2685  }
2686  out->end_list(out);
2687 
2688  return pcmk_rc_ok;
2689 }
2690 
2691 PCMK__OUTPUT_ARGS("node-summary", "pcmk_scheduler_t *", "GList *", "GList *",
2692  "uint32_t", "uint32_t", "bool")
2693 static int
2694 node_summary(pcmk__output_t *out, va_list args) {
2695  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
2696  GList *only_node = va_arg(args, GList *);
2697  GList *only_rsc = va_arg(args, GList *);
2698  uint32_t section_opts = va_arg(args, uint32_t);
2699  uint32_t show_opts = va_arg(args, uint32_t);
2700  bool print_spacer = va_arg(args, int);
2701 
2702  xmlNode *node_state = NULL;
2703  xmlNode *cib_status = pcmk_find_cib_element(scheduler->input,
2704  PCMK_XE_STATUS);
2705  int rc = pcmk_rc_no_output;
2706 
2707  if (xmlChildElementCount(cib_status) == 0) {
2708  return rc;
2709  }
2710 
2711  for (node_state = pcmk__xe_first_child(cib_status, PCMK__XE_NODE_STATE,
2712  NULL, NULL);
2713  node_state != NULL; node_state = pcmk__xe_next_same(node_state)) {
2714 
2716  pcmk__xe_id(node_state));
2717 
2718  if (!node || !node->details || !node->details->online) {
2719  continue;
2720  }
2721 
2722  if (!pcmk__str_in_list(node->details->uname, only_node,
2724  continue;
2725  }
2726 
2727  PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc,
2728  pcmk_is_set(section_opts, pcmk_section_operations) ? "Operations" : "Migration Summary");
2729 
2730  out->message(out, "node-history-list", scheduler, node, node_state,
2731  only_node, only_rsc, section_opts, show_opts);
2732  }
2733 
2734  PCMK__OUTPUT_LIST_FOOTER(out, rc);
2735  return rc;
2736 }
2737 
2738 PCMK__OUTPUT_ARGS("node-weight", "const pcmk_resource_t *", "const char *",
2739  "const char *", "const char *")
2740 static int
2741 node_weight(pcmk__output_t *out, va_list args)
2742 {
2743  const pcmk_resource_t *rsc = va_arg(args, const pcmk_resource_t *);
2744  const char *prefix = va_arg(args, const char *);
2745  const char *uname = va_arg(args, const char *);
2746  const char *score = va_arg(args, const char *);
2747 
2748  if (rsc) {
2749  out->list_item(out, NULL, "%s: %s allocation score on %s: %s",
2750  prefix, rsc->id, uname, score);
2751  } else {
2752  out->list_item(out, NULL, "%s: %s = %s", prefix, uname, score);
2753  }
2754 
2755  return pcmk_rc_ok;
2756 }
2757 
2758 PCMK__OUTPUT_ARGS("node-weight", "const pcmk_resource_t *", "const char *",
2759  "const char *", "const char *")
2760 static int
2761 node_weight_xml(pcmk__output_t *out, va_list args)
2762 {
2763  const pcmk_resource_t *rsc = va_arg(args, const pcmk_resource_t *);
2764  const char *prefix = va_arg(args, const char *);
2765  const char *uname = va_arg(args, const char *);
2766  const char *score = va_arg(args, const char *);
2767 
2768  xmlNodePtr node = pcmk__output_create_xml_node(out, PCMK_XE_NODE_WEIGHT,
2769  PCMK_XA_FUNCTION, prefix,
2771  PCMK_XA_SCORE, score,
2772  NULL);
2773 
2774  if (rsc) {
2775  crm_xml_add(node, PCMK_XA_ID, rsc->id);
2776  }
2777 
2778  return pcmk_rc_ok;
2779 }
2780 
2781 PCMK__OUTPUT_ARGS("op-history", "xmlNode *", "const char *", "const char *", "int", "uint32_t")
2782 static int
2783 op_history_text(pcmk__output_t *out, va_list args) {
2784  xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
2785  const char *task = va_arg(args, const char *);
2786  const char *interval_ms_s = va_arg(args, const char *);
2787  int rc = va_arg(args, int);
2788  uint32_t show_opts = va_arg(args, uint32_t);
2789 
2790  char *buf = op_history_string(xml_op, task, interval_ms_s, rc,
2791  pcmk_is_set(show_opts, pcmk_show_timing));
2792 
2793  out->list_item(out, NULL, "%s", buf);
2794 
2795  free(buf);
2796  return pcmk_rc_ok;
2797 }
2798 
2799 PCMK__OUTPUT_ARGS("op-history", "xmlNode *", "const char *", "const char *", "int", "uint32_t")
2800 static int
2801 op_history_xml(pcmk__output_t *out, va_list args) {
2802  xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
2803  const char *task = va_arg(args, const char *);
2804  const char *interval_ms_s = va_arg(args, const char *);
2805  int rc = va_arg(args, int);
2806  uint32_t show_opts = va_arg(args, uint32_t);
2807 
2808  const char *call_id = crm_element_value(xml_op, PCMK__XA_CALL_ID);
2809  char *rc_s = pcmk__itoa(rc);
2810  const char *rc_text = services_ocf_exitcode_str(rc);
2811  xmlNodePtr node = NULL;
2812 
2814  PCMK_XA_CALL, call_id,
2815  PCMK_XA_TASK, task,
2816  PCMK_XA_RC, rc_s,
2817  PCMK_XA_RC_TEXT, rc_text,
2818  NULL);
2819  free(rc_s);
2820 
2821  if (interval_ms_s && !pcmk__str_eq(interval_ms_s, "0", pcmk__str_casei)) {
2822  char *s = crm_strdup_printf("%sms", interval_ms_s);
2823  crm_xml_add(node, PCMK_XA_INTERVAL, s);
2824  free(s);
2825  }
2826 
2827  if (pcmk_is_set(show_opts, pcmk_show_timing)) {
2828  const char *value = NULL;
2829  time_t epoch = 0;
2830 
2832  &epoch) == pcmk_ok) && (epoch > 0)) {
2833  char *s = pcmk__epoch2str(&epoch, 0);
2835  free(s);
2836  }
2837 
2838  value = crm_element_value(xml_op, PCMK_XA_EXEC_TIME);
2839  if (value) {
2840  char *s = crm_strdup_printf("%sms", value);
2841  crm_xml_add(node, PCMK_XA_EXEC_TIME, s);
2842  free(s);
2843  }
2844  value = crm_element_value(xml_op, PCMK_XA_QUEUE_TIME);
2845  if (value) {
2846  char *s = crm_strdup_printf("%sms", value);
2847  crm_xml_add(node, PCMK_XA_QUEUE_TIME, s);
2848  free(s);
2849  }
2850  }
2851 
2852  return pcmk_rc_ok;
2853 }
2854 
2855 PCMK__OUTPUT_ARGS("promotion-score", "pcmk_resource_t *", "pcmk_node_t *",
2856  "const char *")
2857 static int
2858 promotion_score(pcmk__output_t *out, va_list args)
2859 {
2860  pcmk_resource_t *child_rsc = va_arg(args, pcmk_resource_t *);
2861  pcmk_node_t *chosen = va_arg(args, pcmk_node_t *);
2862  const char *score = va_arg(args, const char *);
2863 
2864  if (chosen == NULL) {
2865  out->list_item(out, NULL, "%s promotion score (inactive): %s",
2866  child_rsc->id, score);
2867  } else {
2868  out->list_item(out, NULL, "%s promotion score on %s: %s",
2869  child_rsc->id, pcmk__node_name(chosen), score);
2870  }
2871  return pcmk_rc_ok;
2872 }
2873 
2874 PCMK__OUTPUT_ARGS("promotion-score", "pcmk_resource_t *", "pcmk_node_t *",
2875  "const char *")
2876 static int
2877 promotion_score_xml(pcmk__output_t *out, va_list args)
2878 {
2879  pcmk_resource_t *child_rsc = va_arg(args, pcmk_resource_t *);
2880  pcmk_node_t *chosen = va_arg(args, pcmk_node_t *);
2881  const char *score = va_arg(args, const char *);
2882 
2884  PCMK_XA_ID, child_rsc->id,
2885  PCMK_XA_SCORE, score,
2886  NULL);
2887 
2888  if (chosen) {
2889  crm_xml_add(node, PCMK_XA_NODE, chosen->details->uname);
2890  }
2891 
2892  return pcmk_rc_ok;
2893 }
2894 
2895 PCMK__OUTPUT_ARGS("resource-config", "const pcmk_resource_t *", "bool")
2896 static int
2897 resource_config(pcmk__output_t *out, va_list args) {
2898  const pcmk_resource_t *rsc = va_arg(args, const pcmk_resource_t *);
2899  GString *xml_buf = g_string_sized_new(1024);
2900  bool raw = va_arg(args, int);
2901 
2902  formatted_xml_buf(rsc, xml_buf, raw);
2903 
2904  out->output_xml(out, PCMK_XE_XML, xml_buf->str);
2905 
2906  g_string_free(xml_buf, TRUE);
2907  return pcmk_rc_ok;
2908 }
2909 
2910 PCMK__OUTPUT_ARGS("resource-config", "const pcmk_resource_t *", "bool")
2911 static int
2912 resource_config_text(pcmk__output_t *out, va_list args) {
2913  pcmk__formatted_printf(out, "Resource XML:\n");
2914  return resource_config(out, args);
2915 }
2916 
2917 PCMK__OUTPUT_ARGS("resource-history", "pcmk_resource_t *", "const char *",
2918  "bool", "int", "time_t", "bool")
2919 static int
2920 resource_history_text(pcmk__output_t *out, va_list args) {
2921  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
2922  const char *rsc_id = va_arg(args, const char *);
2923  bool all = va_arg(args, int);
2924  int failcount = va_arg(args, int);
2925  time_t last_failure = va_arg(args, time_t);
2926  bool as_header = va_arg(args, int);
2927 
2928  char *buf = resource_history_string(rsc, rsc_id, all, failcount, last_failure);
2929 
2930  if (as_header) {
2931  out->begin_list(out, NULL, NULL, "%s", buf);
2932  } else {
2933  out->list_item(out, NULL, "%s", buf);
2934  }
2935 
2936  free(buf);
2937  return pcmk_rc_ok;
2938 }
2939 
2940 PCMK__OUTPUT_ARGS("resource-history", "pcmk_resource_t *", "const char *",
2941  "bool", "int", "time_t", "bool")
2942 static int
2943 resource_history_xml(pcmk__output_t *out, va_list args) {
2944  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
2945  const char *rsc_id = va_arg(args, const char *);
2946  bool all = va_arg(args, int);
2947  int failcount = va_arg(args, int);
2948  time_t last_failure = va_arg(args, time_t);
2949  bool as_header = va_arg(args, int);
2950 
2951  xmlNodePtr node = pcmk__output_xml_create_parent(out,
2953  PCMK_XA_ID, rsc_id,
2954  NULL);
2955 
2956  if (rsc == NULL) {
2958  } else if (all || failcount || last_failure > 0) {
2959  char *migration_s = pcmk__itoa(rsc->migration_threshold);
2960 
2961  pcmk__xe_set_props(node,
2963  PCMK_META_MIGRATION_THRESHOLD, migration_s,
2964  NULL);
2965  free(migration_s);
2966 
2967  if (failcount > 0) {
2968  char *s = pcmk__itoa(failcount);
2969 
2970  crm_xml_add(node, PCMK_XA_FAIL_COUNT, s);
2971  free(s);
2972  }
2973 
2974  if (last_failure > 0) {
2975  char *s = pcmk__epoch2str(&last_failure, 0);
2976 
2978  free(s);
2979  }
2980  }
2981 
2982  if (!as_header) {
2984  }
2985 
2986  return pcmk_rc_ok;
2987 }
2988 
2989 static void
2990 print_resource_header(pcmk__output_t *out, uint32_t show_opts)
2991 {
2992  if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2993  /* Active resources have already been printed by node */
2994  out->begin_list(out, NULL, NULL, "Inactive Resources");
2995  } else if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
2996  out->begin_list(out, NULL, NULL, "Full List of Resources");
2997  } else {
2998  out->begin_list(out, NULL, NULL, "Active Resources");
2999  }
3000 }
3001 
3002 
3003 PCMK__OUTPUT_ARGS("resource-list", "pcmk_scheduler_t *", "uint32_t", "bool",
3004  "GList *", "GList *", "bool")
3005 static int
3006 resource_list(pcmk__output_t *out, va_list args)
3007 {
3008  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
3009  uint32_t show_opts = va_arg(args, uint32_t);
3010  bool print_summary = va_arg(args, int);
3011  GList *only_node = va_arg(args, GList *);
3012  GList *only_rsc = va_arg(args, GList *);
3013  bool print_spacer = va_arg(args, int);
3014 
3015  GList *rsc_iter;
3016  int rc = pcmk_rc_no_output;
3017  bool printed_header = false;
3018 
3019  /* If we already showed active resources by node, and
3020  * we're not showing inactive resources, we have nothing to do
3021  */
3022  if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node) &&
3023  !pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
3024  return rc;
3025  }
3026 
3027  /* If we haven't already printed resources grouped by node,
3028  * and brief output was requested, print resource summary */
3029  if (pcmk_is_set(show_opts, pcmk_show_brief)
3030  && !pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
3031  GList *rscs = pe__filter_rsc_list(scheduler->resources, only_rsc);
3032 
3033  PCMK__OUTPUT_SPACER_IF(out, print_spacer);
3034  print_resource_header(out, show_opts);
3035  printed_header = true;
3036 
3037  rc = pe__rscs_brief_output(out, rscs, show_opts);
3038  g_list_free(rscs);
3039  }
3040 
3041  /* For each resource, display it if appropriate */
3042  for (rsc_iter = scheduler->resources; rsc_iter != NULL; rsc_iter = rsc_iter->next) {
3043  pcmk_resource_t *rsc = (pcmk_resource_t *) rsc_iter->data;
3044  int x;
3045 
3046  /* Complex resources may have some sub-resources active and some inactive */
3047  gboolean is_active = rsc->fns->active(rsc, TRUE);
3048  gboolean partially_active = rsc->fns->active(rsc, FALSE);
3049 
3050  /* Skip inactive orphans (deleted but still in CIB) */
3051  if (pcmk_is_set(rsc->flags, pcmk_rsc_removed) && !is_active) {
3052  continue;
3053 
3054  /* Skip active resources if we already displayed them by node */
3055  } else if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
3056  if (is_active) {
3057  continue;
3058  }
3059 
3060  /* Skip primitives already counted in a brief summary */
3061  } else if (pcmk_is_set(show_opts, pcmk_show_brief)
3062  && pcmk__is_primitive(rsc)) {
3063  continue;
3064 
3065  /* Skip resources that aren't at least partially active,
3066  * unless we're displaying inactive resources
3067  */
3068  } else if (!partially_active && !pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
3069  continue;
3070 
3071  } else if (partially_active && !pe__rsc_running_on_any(rsc, only_node)) {
3072  continue;
3073  }
3074 
3075  if (!printed_header) {
3076  PCMK__OUTPUT_SPACER_IF(out, print_spacer);
3077  print_resource_header(out, show_opts);
3078  printed_header = true;
3079  }
3080 
3081  /* Print this resource */
3082  x = out->message(out, pcmk__map_element_name(rsc->xml), show_opts, rsc,
3083  only_node, only_rsc);
3084  if (x == pcmk_rc_ok) {
3085  rc = pcmk_rc_ok;
3086  }
3087  }
3088 
3089  if (print_summary && rc != pcmk_rc_ok) {
3090  if (!printed_header) {
3091  PCMK__OUTPUT_SPACER_IF(out, print_spacer);
3092  print_resource_header(out, show_opts);
3093  printed_header = true;
3094  }
3095 
3096  if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
3097  out->list_item(out, NULL, "No inactive resources");
3098  } else if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
3099  out->list_item(out, NULL, "No resources");
3100  } else {
3101  out->list_item(out, NULL, "No active resources");
3102  }
3103  }
3104 
3105  if (printed_header) {
3106  out->end_list(out);
3107  }
3108 
3109  return rc;
3110 }
3111 
3112 PCMK__OUTPUT_ARGS("resource-operation-list", "pcmk_scheduler_t *",
3113  "pcmk_resource_t *", "pcmk_node_t *", "GList *", "uint32_t")
3114 static int
3115 resource_operation_list(pcmk__output_t *out, va_list args)
3116 {
3117  pcmk_scheduler_t *scheduler G_GNUC_UNUSED = va_arg(args,
3118  pcmk_scheduler_t *);
3119  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
3120  pcmk_node_t *node = va_arg(args, pcmk_node_t *);
3121  GList *op_list = va_arg(args, GList *);
3122  uint32_t show_opts = va_arg(args, uint32_t);
3123 
3124  GList *gIter = NULL;
3125  int rc = pcmk_rc_no_output;
3126 
3127  /* Print each operation */
3128  for (gIter = op_list; gIter != NULL; gIter = gIter->next) {
3129  xmlNode *xml_op = (xmlNode *) gIter->data;
3130  const char *task = crm_element_value(xml_op, PCMK_XA_OPERATION);
3131  const char *interval_ms_s = crm_element_value(xml_op,
3133  const char *op_rc = crm_element_value(xml_op, PCMK__XA_RC_CODE);
3134  int op_rc_i;
3135 
3136  pcmk__scan_min_int(op_rc, &op_rc_i, 0);
3137 
3138  /* Display 0-interval monitors as "probe" */
3139  if (pcmk__str_eq(task, PCMK_ACTION_MONITOR, pcmk__str_casei)
3140  && pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches | pcmk__str_casei)) {
3141  task = "probe";
3142  }
3143 
3144  /* If this is the first printed operation, print heading for resource */
3145  if (rc == pcmk_rc_no_output) {
3146  time_t last_failure = 0;
3147  int failcount = pe_get_failcount(node, rsc, &last_failure,
3148  pcmk__fc_default, NULL);
3149 
3150  out->message(out, "resource-history", rsc, rsc_printable_id(rsc), true,
3151  failcount, last_failure, true);
3152  rc = pcmk_rc_ok;
3153  }
3154 
3155  /* Print the operation */
3156  out->message(out, "op-history", xml_op, task, interval_ms_s,
3157  op_rc_i, show_opts);
3158  }
3159 
3160  /* Free the list we created (no need to free the individual items) */
3161  g_list_free(op_list);
3162 
3163  PCMK__OUTPUT_LIST_FOOTER(out, rc);
3164  return rc;
3165 }
3166 
3167 PCMK__OUTPUT_ARGS("resource-util", "pcmk_resource_t *", "pcmk_node_t *",
3168  "const char *")
3169 static int
3170 resource_util(pcmk__output_t *out, va_list args)
3171 {
3172  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
3173  pcmk_node_t *node = va_arg(args, pcmk_node_t *);
3174  const char *fn = va_arg(args, const char *);
3175 
3176  char *dump_text = crm_strdup_printf("%s: %s utilization on %s:",
3177  fn, rsc->id, pcmk__node_name(node));
3178 
3179  g_hash_table_foreach(rsc->utilization, append_dump_text, &dump_text);
3180  out->list_item(out, NULL, "%s", dump_text);
3181  free(dump_text);
3182 
3183  return pcmk_rc_ok;
3184 }
3185 
3186 PCMK__OUTPUT_ARGS("resource-util", "pcmk_resource_t *", "pcmk_node_t *",
3187  "const char *")
3188 static int
3189 resource_util_xml(pcmk__output_t *out, va_list args)
3190 {
3191  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
3192  pcmk_node_t *node = va_arg(args, pcmk_node_t *);
3193  const char *uname = node->details->uname;
3194  const char *fn = va_arg(args, const char *);
3195 
3196  xmlNodePtr xml_node = NULL;
3197 
3199  PCMK_XA_RESOURCE, rsc->id,
3201  PCMK_XA_FUNCTION, fn,
3202  NULL);
3203  g_hash_table_foreach(rsc->utilization, add_dump_node, xml_node);
3204 
3205  return pcmk_rc_ok;
3206 }
3207 
3208 PCMK__OUTPUT_ARGS("ticket", "pcmk_ticket_t *", "bool", "bool")
3209 static int
3210 ticket_default(pcmk__output_t *out, va_list args) {
3211  pcmk_ticket_t *ticket = va_arg(args, pcmk_ticket_t *);
3212  bool raw = va_arg(args, int);
3213  bool details = va_arg(args, int);
3214 
3215  GString *detail_str = NULL;
3216 
3217  if (raw) {
3218  out->list_item(out, ticket->id, "%s", ticket->id);
3219  return pcmk_rc_ok;
3220  }
3221 
3222  if (details && g_hash_table_size(ticket->state) > 0) {
3223  GHashTableIter iter;
3224  const char *name = NULL;
3225  const char *value = NULL;
3226  bool already_added = false;
3227 
3228  detail_str = g_string_sized_new(100);
3229  pcmk__g_strcat(detail_str, "\t(", NULL);
3230 
3231  g_hash_table_iter_init(&iter, ticket->state);
3232  while (g_hash_table_iter_next(&iter, (void **) &name, (void **) &value)) {
3233  if (already_added) {
3234  g_string_append_printf(detail_str, ", %s=", name);
3235  } else {
3236  g_string_append_printf(detail_str, "%s=", name);
3237  already_added = true;
3238  }
3239 
3240  if (pcmk__str_any_of(name, PCMK_XA_LAST_GRANTED, "expires", NULL)) {
3241  char *epoch_str = NULL;
3242  long long time_ll;
3243 
3244  (void) pcmk__scan_ll(value, &time_ll, 0);
3245  epoch_str = pcmk__epoch2str((const time_t *) &time_ll, 0);
3246  pcmk__g_strcat(detail_str, epoch_str, NULL);
3247  free(epoch_str);
3248  } else {
3249  pcmk__g_strcat(detail_str, value, NULL);
3250  }
3251  }
3252 
3253  pcmk__g_strcat(detail_str, ")", NULL);
3254  }
3255 
3256  if (ticket->last_granted > -1) {
3257  /* Prior to the introduction of the details & raw arguments to this
3258  * function, last-granted would always be added in this block. We need
3259  * to preserve that behavior. At the same time, we also need to preserve
3260  * the existing behavior from crm_ticket, which would include last-granted
3261  * as part of the (...) detail string.
3262  *
3263  * Luckily we can check detail_str - if it's NULL, either there were no
3264  * details, or we are preserving the previous behavior of this function.
3265  * If it's not NULL, we are either preserving the previous behavior of
3266  * crm_ticket or we were given details=true as an argument.
3267  */
3268  if (detail_str == NULL) {
3269  char *epoch_str = pcmk__epoch2str(&(ticket->last_granted), 0);
3270 
3271  out->list_item(out, NULL, "%s\t%s%s last-granted=\"%s\"",
3272  ticket->id,
3273  (ticket->granted? "granted" : "revoked"),
3274  (ticket->standby? " [standby]" : ""),
3275  pcmk__s(epoch_str, ""));
3276  free(epoch_str);
3277  } else {
3278  out->list_item(out, NULL, "%s\t%s%s %s",
3279  ticket->id,
3280  (ticket->granted? "granted" : "revoked"),
3281  (ticket->standby? " [standby]" : ""),
3282  detail_str->str);
3283  }
3284  } else {
3285  out->list_item(out, NULL, "%s\t%s%s%s", ticket->id,
3286  ticket->granted ? "granted" : "revoked",
3287  ticket->standby ? " [standby]" : "",
3288  detail_str != NULL ? detail_str->str : "");
3289  }
3290 
3291  if (detail_str != NULL) {
3292  g_string_free(detail_str, TRUE);
3293  }
3294 
3295  return pcmk_rc_ok;
3296 }
3297 
3298 PCMK__OUTPUT_ARGS("ticket", "pcmk_ticket_t *", "bool", "bool")
3299 static int
3300 ticket_xml(pcmk__output_t *out, va_list args) {
3301  pcmk_ticket_t *ticket = va_arg(args, pcmk_ticket_t *);
3302  bool raw G_GNUC_UNUSED = va_arg(args, int);
3303  bool details G_GNUC_UNUSED = va_arg(args, int);
3304 
3305  const char *status = NULL;
3306  const char *standby = pcmk__btoa(ticket->standby);
3307 
3308  xmlNodePtr node = NULL;
3309  GHashTableIter iter;
3310  const char *name = NULL;
3311  const char *value = NULL;
3312 
3313  status = ticket->granted? PCMK_VALUE_GRANTED : PCMK_VALUE_REVOKED;
3314 
3316  PCMK_XA_ID, ticket->id,
3317  PCMK_XA_STATUS, status,
3318  PCMK_XA_STANDBY, standby,
3319  NULL);
3320 
3321  if (ticket->last_granted > -1) {
3322  char *buf = pcmk__epoch2str(&ticket->last_granted, 0);
3323 
3324  crm_xml_add(node, PCMK_XA_LAST_GRANTED, buf);
3325  free(buf);
3326  }
3327 
3328  g_hash_table_iter_init(&iter, ticket->state);
3329  while (g_hash_table_iter_next(&iter, (void **) &name, (void **) &value)) {
3330  /* PCMK_XA_LAST_GRANTED and "expires" are already added by the check
3331  * for ticket->last_granted above.
3332  */
3334  NULL)) {
3335  continue;
3336  }
3337 
3338  crm_xml_add(node, name, value);
3339  }
3340 
3341  return pcmk_rc_ok;
3342 }
3343 
3344 PCMK__OUTPUT_ARGS("ticket-list", "GHashTable *", "bool", "bool", "bool")
3345 static int
3346 ticket_list(pcmk__output_t *out, va_list args) {
3347  GHashTable *tickets = va_arg(args, GHashTable *);
3348  bool print_spacer = va_arg(args, int);
3349  bool raw = va_arg(args, int);
3350  bool details = va_arg(args, int);
3351 
3352  GHashTableIter iter;
3353  gpointer value;
3354 
3355  if (g_hash_table_size(tickets) == 0) {
3356  return pcmk_rc_no_output;
3357  }
3358 
3359  PCMK__OUTPUT_SPACER_IF(out, print_spacer);
3360 
3361  /* Print section heading */
3362  out->begin_list(out, NULL, NULL, "Tickets");
3363 
3364  /* Print each ticket */
3365  g_hash_table_iter_init(&iter, tickets);
3366  while (g_hash_table_iter_next(&iter, NULL, &value)) {
3367  pcmk_ticket_t *ticket = (pcmk_ticket_t *) value;
3368  out->message(out, "ticket", ticket, raw, details);
3369  }
3370 
3371  /* Close section */
3372  out->end_list(out);
3373  return pcmk_rc_ok;
3374 }
3375 
3376 static pcmk__message_entry_t fmt_functions[] = {
3377  { "ban", "default", ban_text },
3378  { "ban", "html", ban_html },
3379  { "ban", "xml", ban_xml },
3380  { "ban-list", "default", ban_list },
3381  { "bundle", "default", pe__bundle_text },
3382  { "bundle", "xml", pe__bundle_xml },
3383  { "bundle", "html", pe__bundle_html },
3384  { "clone", "default", pe__clone_default },
3385  { "clone", "xml", pe__clone_xml },
3386  { "cluster-counts", "default", cluster_counts_text },
3387  { "cluster-counts", "html", cluster_counts_html },
3388  { "cluster-counts", "xml", cluster_counts_xml },
3389  { "cluster-dc", "default", cluster_dc_text },
3390  { "cluster-dc", "html", cluster_dc_html },
3391  { "cluster-dc", "xml", cluster_dc_xml },
3392  { "cluster-options", "default", cluster_options_text },
3393  { "cluster-options", "html", cluster_options_html },
3394  { "cluster-options", "log", cluster_options_log },
3395  { "cluster-options", "xml", cluster_options_xml },
3396  { "cluster-summary", "default", cluster_summary },
3397  { "cluster-summary", "html", cluster_summary_html },
3398  { "cluster-stack", "default", cluster_stack_text },
3399  { "cluster-stack", "html", cluster_stack_html },
3400  { "cluster-stack", "xml", cluster_stack_xml },
3401  { "cluster-times", "default", cluster_times_text },
3402  { "cluster-times", "html", cluster_times_html },
3403  { "cluster-times", "xml", cluster_times_xml },
3404  { "failed-action", "default", failed_action_default },
3405  { "failed-action", "xml", failed_action_xml },
3406  { "failed-action-list", "default", failed_action_list },
3407  { "group", "default", pe__group_default},
3408  { "group", "xml", pe__group_xml },
3409  { "maint-mode", "text", cluster_maint_mode_text },
3410  { "node", "default", node_text },
3411  { "node", "html", node_html },
3412  { "node", "xml", node_xml },
3413  { "node-and-op", "default", node_and_op },
3414  { "node-and-op", "xml", node_and_op_xml },
3415  { "node-capacity", "default", node_capacity },
3416  { "node-capacity", "xml", node_capacity_xml },
3417  { "node-history-list", "default", node_history_list },
3418  { "node-list", "default", node_list_text },
3419  { "node-list", "html", node_list_html },
3420  { "node-list", "xml", node_list_xml },
3421  { "node-weight", "default", node_weight },
3422  { "node-weight", "xml", node_weight_xml },
3423  { "node-attribute", "default", node_attribute_text },
3424  { "node-attribute", "html", node_attribute_html },
3425  { "node-attribute", "xml", node_attribute_xml },
3426  { "node-attribute-list", "default", node_attribute_list },
3427  { "node-summary", "default", node_summary },
3428  { "op-history", "default", op_history_text },
3429  { "op-history", "xml", op_history_xml },
3430  { "primitive", "default", pe__resource_text },
3431  { "primitive", "xml", pe__resource_xml },
3432  { "primitive", "html", pe__resource_html },
3433  { "promotion-score", "default", promotion_score },
3434  { "promotion-score", "xml", promotion_score_xml },
3435  { "resource-config", "default", resource_config },
3436  { "resource-config", "text", resource_config_text },
3437  { "resource-history", "default", resource_history_text },
3438  { "resource-history", "xml", resource_history_xml },
3439  { "resource-list", "default", resource_list },
3440  { "resource-operation-list", "default", resource_operation_list },
3441  { "resource-util", "default", resource_util },
3442  { "resource-util", "xml", resource_util_xml },
3443  { "ticket", "default", ticket_default },
3444  { "ticket", "xml", ticket_xml },
3445  { "ticket-list", "default", ticket_list },
3446 
3447  { NULL, NULL, NULL }
3448 };
3449 
3450 void
3452  pcmk__register_messages(out, fmt_functions);
3453 }
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition: complex.c:1071
#define PCMK__XA_OPERATION_KEY
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:245
void pcmk__output_xml_push_parent(pcmk__output_t *out, xmlNodePtr parent)
Definition: output_xml.c:548
#define PCMK_XA_STONITH_TIMEOUT_MS
Definition: xml_names.h:412
xmlNode * orig_xml
Definition: resources.h:403
enum pe_quorum_policy no_quorum_policy
Definition: scheduler.h:217
#define PCMK_XE_NODES_CONFIGURED
Definition: xml_names.h:143
#define PCMK_XA_EXPECTED_UP
Definition: xml_names.h:279
#define PCMK__XE_LRM_RESOURCES
char * pcmk__xml_escape(const char *text, enum pcmk__xml_escape_type type)
Definition: xml.c:1199
xmlNode * failed
Definition: scheduler.h:240
#define PCMK_XA_CALL
Definition: xml_names.h:243
GHashTable * attrs
Definition: nodes.h:143
#define PCMK_XA_NAME
Definition: xml_names.h:330
#define PCMK_VALUE_GREEN
Definition: options.h:157
#define PCMK_XA_HEALTH
Definition: xml_names.h:296
node_type
Definition: nodes.h:39
#define PCMK_XA_PACEMAKERD_STATE
Definition: xml_names.h:354
Control output from tools.
void pcmk__register_messages(pcmk__output_t *out, const pcmk__message_entry_t *table)
Definition: output.c:204
#define PCMK_META_MIGRATION_THRESHOLD
Definition: options.h:95
int pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name,...)
Definition: pe_output.c:611
#define PCMK_XE_LAST_CHANGE
Definition: xml_names.h:125
#define PCMK_VALUE_FALSE
Definition: options.h:152
#define PCMK__XA_RC_CODE
GHashTable * state
Definition: tickets.h:35
#define PCMK_XA_ID_AS_RESOURCE
Definition: xml_names.h:302
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition: strings.c:126
gchar * pcmk__native_output_string(const pcmk_resource_t *rsc, const char *name, const pcmk_node_t *node, uint32_t show_opts, const char *target_role, bool show_nodes)
Definition: native.c:559
#define PCMK_XE_STATUS
Definition: xml_names.h:204
#define crm_time_log_timeofday
Definition: iso8601.h:68
#define PCMK_XA_UPDATE_ORIGIN
Definition: xml_names.h:437
const char * name
Definition: cib.c:26
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1038
#define PCMK_XA_IS_DC
Definition: xml_names.h:311
#define PCMK_XE_PROMOTION_SCORE
Definition: xml_names.h:165
#define PCMK_XA_STONITH_ENABLED
Definition: xml_names.h:411
#define FILTER_STR
Definition: pe_output.c:33
void pcmk__xml_string(const xmlNode *data, uint32_t options, GString *buffer, int depth)
Definition: xml_io.c:490
PCMK__OUTPUT_ARGS("cluster-summary", "pcmk_scheduler_t *", "enum pcmk_pacemakerd_state", "uint32_t", "uint32_t")
Definition: pe_output.c:403
GList * children
Definition: resources.h:471
gboolean standby
Definition: tickets.h:34
#define PCMK_VALUE_GRANTED
Definition: options.h:156
int priority_fencing_delay
Definition: scheduler.h:261
pcmk_resource_t * pe_find_resource(GList *rsc_list, const char *id)
Definition: status.c:435
bool pcmk__xml_needs_escape(const char *text, enum pcmk__xml_escape_type type)
Definition: xml.c:1117
xmlNode * xml
Definition: resources.h:400
#define PCMK_XA_EXITCODE
Definition: xml_names.h:275
#define PCMK_XA_OP_KEY
Definition: xml_names.h:348
#define PCMK_VALUE_STANDBY
Definition: options.h:205
int pe__group_default(pcmk__output_t *out, va_list args)
#define PCMK_ACTION_MONITOR
Definition: actions.h:60
#define PCMK_XA_EXIT_REASON
Definition: xml_names.h:274
GHashTable * meta
Definition: resources.h:467
#define PCMK_XA_HAVE_QUORUM
Definition: xml_names.h:295
#define PCMK_XA_LAST_FAILURE
Definition: xml_names.h:314
#define PCMK_XA_CLIENT
Definition: xml_names.h:247
xmlNodePtr pcmk__output_xml_create_parent(pcmk__output_t *out, const char *name,...) G_GNUC_NULL_TERMINATED
Definition: output_xml.c:478
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:313
#define PCMK_VALUE_UNKNOWN
Definition: options.h:217
int pe__clone_default(pcmk__output_t *out, va_list args)
xmlNodePtr pcmk__output_xml_peek_parent(pcmk__output_t *out)
Definition: output_xml.c:578
gboolean pending
Definition: nodes.h:88
#define PCMK_XA_CIB_LAST_WRITTEN
Definition: xml_names.h:244
#define PCMK_XA_PROVIDER
Definition: xml_names.h:364
Promoted.
Definition: roles.h:39
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
Definition: pe_actions.c:1784
#define PCMK_XA_RSC
Definition: xml_names.h:388
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
Definition: nvpair.c:987
#define PCMK_XA_EXEC
Definition: xml_names.h:269
#define PCMK_XA_QUEUE_TIME
Definition: xml_names.h:365
void pcmk__xe_set_propv(xmlNodePtr node, va_list pairs)
Definition: xml.c:2279
#define PCMK_XA_MIXED_VERSION
Definition: xml_names.h:326
#define PCMK_VALUE_REVOKED
Definition: options.h:201
enum crm_ais_msg_types type
Definition: cpg.c:51
const char * rsc_printable_id(const pcmk_resource_t *rsc)
Definition: utils.c:553
int migration_threshold
Definition: resources.h:422
#define PCMK_XE_FAILURE
Definition: xml_names.h:110
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:449
pcmk_resource_t * container
Definition: resources.h:476
int pe__resource_text(pcmk__output_t *out, va_list args)
#define PCMK_XA_TYPE
Definition: xml_names.h:430
#define PCMK_XA_RESOURCE
Definition: xml_names.h:382
#define PCMK_XA_OPERATION
Definition: xml_names.h:349
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:189
#define PCMK_XE_ATTRIBUTE
Definition: xml_names.h:69
#define PCMK__XE_SPAN
Include indentation and newlines.
Definition: xml_internal.h:140
#define PCMK_XA_STANDBY
Definition: xml_names.h:406
int pe_get_failcount(const pcmk_node_t *node, pcmk_resource_t *rsc, time_t *last_failure, uint32_t flags, const xmlNode *xml_op)
Definition: failcounts.c:373
int pe__bundle_html(pcmk__output_t *out, va_list args)
#define PCMK_XA_DISABLED
Definition: xml_names.h:265
#define PCMK_XA_NODE
Definition: xml_names.h:335
pe_quorum_policy
Possible responses to loss of quorum.
Definition: scheduler.h:40
void void void pcmk__formatted_printf(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
GList * resources
Definition: scheduler.h:231
void pcmk__xe_set_content(xmlNode *node, const char *format,...) G_GNUC_PRINTF(2
#define PCMK_XA_ORPHAN
Definition: xml_names.h:352
#define PCMK_XA_ORIGIN
Definition: xml_names.h:351
#define PCMK_XA_AGENT
Definition: xml_names.h:234
#define PCMK_XA_EXITREASON
Definition: xml_names.h:276
GList * pe__filter_rsc_list(GList *rscs, GList *filter)
Definition: utils.c:795
char * pcmk__format_nvpair(const char *name, const char *value, const char *units)
Definition: nvpair.c:282
#define PCMK__OUTPUT_SPACER_IF(out_obj, cond)
gboolean is_dc
Definition: nodes.h:101
#define PCMK_XA_STOP_ALL_RESOURCES
Definition: xml_names.h:413
#define PCMK__ROLE_PROMOTED_LEGACY
#define PCMK_XA_OP
Definition: xml_names.h:347
int weight
Definition: nodes.h:163
#define PCMK__XE_LRM_RESOURCE
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
Definition: strings.c:96
#define PCMK_XE_RESOURCE_HISTORY
Definition: xml_names.h:176
#define PCMK_VALUE_RED
Definition: options.h:197
#define CRM_ATTR_FEATURE_SET
Definition: crm.h:110
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition: nvpair.c:614
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)
#define PCMK_XE_NODE_WEIGHT
Definition: xml_names.h:141
#define PCMK_XE_XML
Definition: xml_names.h:221
#define PCMK_XA_UNAME
Definition: xml_names.h:431
#define PCMK_XA_EXPECTED
Definition: xml_names.h:278
#define PCMK_XA_FEATURE_SET
Definition: xml_names.h:285
Used only to initialize variables.
Definition: results.h:327
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:458
#define PCMK_XA_SHUTDOWN
Definition: xml_names.h:400
pcmk_node_t * pe_find_node_id(const GList *node_list, const char *id)
Find a node by ID in a list of nodes.
Definition: status.c:492
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml.c:481
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition: cib.c:172
#define PCMK_XE_UTILIZATION
Definition: xml_names.h:217
#define PCMK__VALUE_WARNING
bool pcmk_xe_mask_probe_failure(const xmlNode *xml_op)
Check whether an action history entry represents a maskable probe.
Definition: probes.c:69
#define PCMK_XA_DESCRIPTION
Definition: xml_names.h:261
#define PCMK_XE_BAN
Definition: xml_names.h:70
#define PCMK_XA_UPDATE_USER
Definition: xml_names.h:438
#define PCMK__VALUE_PING
#define PCMK_XA_PRESENT
Definition: xml_names.h:358
int pe__clone_xml(pcmk__output_t *out, va_list args)
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1308
#define PCMK_VALUE_MEMBER
Definition: options.h:169
bool pe__rsc_running_on_any(pcmk_resource_t *rsc, GList *node_list)
Definition: utils.c:775
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
int pe__node_health(pcmk_node_t *node)
Definition: pe_health.c:130
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:94
#define PCMK_XA_TASK
Definition: xml_names.h:424
struct pe_node_shared_s * details
Definition: nodes.h:168
unsigned long long flags
Definition: resources.h:428
const char * uname
Definition: nodes.h:74
#define PCMK_VALUE_IGNORE
Definition: options.h:161
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1289
Wrappers for and extensions to libxml2.
const char * pe__resource_description(const pcmk_resource_t *rsc, uint32_t show_opts)
Definition: pe_output.c:22
rsc_role_e
Definition: roles.h:34
#define PCMK_META_TARGET_ROLE
Definition: options.h:113
#define PCMK__VALUE_BOLD
Action completed, result is known.
Definition: results.h:329
xmlNodePtr pcmk__output_create_xml_node(pcmk__output_t *out, const char *name,...) G_GNUC_NULL_TERMINATED
Definition: output_xml.c:515
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:651
#define PCMK_XA_QUEUED
Definition: xml_names.h:366
time_t last_granted
Definition: tickets.h:33
GHashTable * utilization
Definition: resources.h:469
#define PCMK_VALUE_TRUE
Definition: options.h:215
#define PCMK_XA_ID
Definition: xml_names.h:301
#define PCMK_XA_BLOCKED
Definition: xml_names.h:239
pcmk_resource_t * rsc
gboolean standby
Definition: nodes.h:83
#define PCMK__XE_LRM
#define PCMK_XA_VALUE
Definition: xml_names.h:442
#define PCMK_XA_SCORE
Definition: xml_names.h:396
gboolean expected_up
Definition: nodes.h:100
#define crm_time_log_with_timezone
Definition: iso8601.h:69
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1062
xmlNode * input
Definition: scheduler.h:196
gboolean granted
Definition: tickets.h:32
#define PCMK_XE_CURRENT_DC
Definition: xml_names.h:94
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
Definition: output_xml.c:562
xmlNode * pcmk__html_create(xmlNode *parent, const char *name, const char *id, const char *class)
Definition: output_html.c:483
#define PCMK__XA_PROMOTED_ONLY_LEGACY
#define PCMK_XA_STATUS
Definition: xml_names.h:410
#define PCMK_XA_ONLINE
Definition: xml_names.h:346
Service safely stopped.
Definition: results.h:260
#define PCMK_VALUE_FENCE_LEGACY
Definition: options.h:224
const char * id
Definition: nodes.h:73
char * id
Definition: tickets.h:31
void pcmk__xe_set_props(xmlNodePtr node,...) G_GNUC_NULL_TERMINATED
Definition: xml.c:2297
#define PCMK_XA_MAINTENANCE
Definition: xml_names.h:321
int pe__resource_xml(pcmk__output_t *out, va_list args)
#define XPATH_STACK
Definition: pe_output.c:199
#define PCMK_XA_INTERVAL
Definition: xml_names.h:309
#define PCMK__VALUE_HEALTH_RED
#define pcmk__assert(expr)
#define PCMK__OUTPUT_LIST_FOOTER(out_obj, retcode)
GList * running_rsc
Definition: nodes.h:140
pcmk_pacemakerd_state
#define PCMK_XE_TICKET
Definition: xml_names.h:212
#define PCMK_XA_FUNCTION
Definition: xml_names.h:292
#define PCMK_VALUE_ONLINE
Definition: options.h:184
#define PCMK_XA_FAIL_COUNT
Definition: xml_names.h:282
#define PCMK_XA_EXEC_TIME
Definition: xml_names.h:270
gboolean(* active)(pcmk_resource_t *rsc, gboolean all)
Definition: resources.h:306
const char * localhost
Definition: scheduler.h:251
int pe__bundle_xml(pcmk__output_t *out, va_list args)
#define PCMK_XE_CAPACITY
Definition: xml_names.h:73
#define PCMK_XA_CLASS
Definition: xml_names.h:246
#define PCMK_XE_NODE
Definition: xml_names.h:136
#define PCMK__OUTPUT_LIST_HEADER(out_obj, cond, retcode, title...)
#define PCMK_XA_MAINTENANCE_MODE
Definition: xml_names.h:322
#define PCMK_XA_RC
Definition: xml_names.h:369
#define PCMK_XA_SYMMETRIC_CLUSTER
Definition: xml_names.h:414
#define PCMK_META_INTERVAL
Definition: options.h:91
#define PCMK_XA_LAST_RC_CHANGE
Definition: xml_names.h:316
#define PCMK_XE_RESOURCES_CONFIGURED
Definition: xml_names.h:180
pcmk_rsc_methods_t * fns
Definition: resources.h:412
#define PCMK_XA_NO_QUORUM_POLICY
Definition: xml_names.h:334
#define PCMK_ROLE_PROMOTED
Definition: roles.h:28
#define PCMK_XA_COMMENT
Definition: xml_names.h:249
pcmk_scheduler_t * scheduler
const char * pcmk_pacemakerd_api_daemon_state_enum2text(enum pcmk_pacemakerd_state state)
#define PCMK__XE_LRM_RSC_OP
char * pe__node_display_name(pcmk_node_t *node, bool print_detail)
Definition: pe_output.c:558
void(*) void(* list_item)(pcmk__output_t *out, const char *name, const char *format,...) G_GNUC_PRINTF(3
int disabled_resources
Definition: scheduler.h:255
char * pcmk__epoch2str(const time_t *source, uint32_t flags)
Definition: iso8601.c:2147
#define PCMK_XE_OPERATION
Definition: xml_names.h:149
#define PCMK_XA_PENDING
Definition: xml_names.h:356
#define PCMK_XE_STACK
Definition: xml_names.h:202
const char * pcmk__node_attr(const pcmk_node_t *node, const char *name, const char *target, enum pcmk__rsc_node node_type)
Definition: attrs.c:118
#define PCMK__XA_OP_STATUS
#define PCMK_META_ON_FAIL
Definition: options.h:98
int pe__group_xml(pcmk__output_t *out, va_list args)
This structure contains everything that makes up a single output formatter.
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: actions.c:249
#define PCMK_XA_WEIGHT
Definition: xml_names.h:449
#define PCMK_XA_USER
Definition: xml_names.h:439
enum rsc_role_e role_filter
GHashTable * utilization
Definition: nodes.h:144
#define PCMK_XA_PROMOTED_ONLY
Definition: xml_names.h:363
gboolean shutdown
Definition: nodes.h:98
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:53
int pe__resource_html(pcmk__output_t *out, va_list args)
#define PCMK_XA_EXITSTATUS
Definition: xml_names.h:277
#define PCMK__VALUE_HEALTH_YELLOW
#define PCMK__XE_NODE_STATE
const char * pcmk__pcmkd_state_enum2friendly(enum pcmk_pacemakerd_state state)
#define pcmk__plural_s(i)
#define PCMK_XA_LAST_GRANTED
Definition: xml_names.h:315
gboolean(* is_filtered)(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent)
Definition: resources.h:358
gboolean maintenance
Definition: nodes.h:105
#define pcmk_ok
Definition: results.h:65
#define PCMK__VALUE_MAINT
#define PCMK__XA_CALL_ID
GList * placement_constraints
Definition: scheduler.h:232
#define PCMK_VALUE_STOP
Definition: options.h:209
#define PCMK_XE_CLUSTER_OPTIONS
Definition: xml_names.h:83
#define PCMK_XA_RC_TEXT
Definition: xml_names.h:370
#define PCMK_XE_LAST_UPDATE
Definition: xml_names.h:127
#define PCMK_XE_NODES
Definition: xml_names.h:142
#define PCMK_XA_PRIORITY_FENCING_DELAY_MS
Definition: xml_names.h:359
const char * pcmk__readable_interval(guint interval_ms)
Definition: iso8601.c:2206
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition: agents.c:31
pcmk_node_t * pending_node
Definition: resources.h:480
gboolean crm_is_true(const char *s)
Definition: strings.c:500
char * pcmk__trim(char *str)
Definition: strings.c:540
Location constraint object.
#define PCMK_XE_OPERATION_HISTORY
Definition: xml_names.h:150
#define PCMK_XA_TIME
Definition: xml_names.h:427
GHashTable * pe_rsc_params(pcmk_resource_t *rsc, const pcmk_node_t *node, pcmk_scheduler_t *scheduler)
Get a table of resource parameters.
Definition: complex.c:484
#define PCMK_VALUE_FREEZE
Definition: options.h:155
#define PCMK_XA_NUMBER
Definition: xml_names.h:342
unsigned long long flags
Definition: scheduler.h:211
const char * parent
Definition: cib.c:27
#define PCMK_XA_UNCLEAN
Definition: xml_names.h:432
gboolean standby_onfail
Definition: nodes.h:84
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml.c:770
#define PCMK_XA_WITH_QUORUM
Definition: xml_names.h:451
#define pcmk__assert_alloc(nmemb, size)
Definition: internal.h:297
#define PCMK_XA_RESOURCES_RUNNING
Definition: xml_names.h:385
#define PCMK_VALUE_OFFLINE
Definition: options.h:183
gboolean unclean
Definition: nodes.h:92
xmlNode * pcmk__xe_next_same(const xmlNode *node)
Definition: xml.c:2130
void pe__register_messages(pcmk__output_t *out)
Definition: pe_output.c:3451
#define PCMK_XA_UPDATE_CLIENT
Definition: xml_names.h:436
#define PCMK_XA_STANDBY_ONFAIL
Definition: xml_names.h:407
#define PCMK_VALUE_YELLOW
Definition: options.h:221
enum node_type type
Definition: nodes.h:75
#define PCMK_VALUE_REMOTE
Definition: options.h:198
#define PCMK_XA_EXPIRES
Definition: xml_names.h:280
#define PCMK_VALUE_DEMOTE
Definition: options.h:145
#define crm_time_log_date
Definition: iso8601.h:67
pcmk_node_t * dc_node
Definition: scheduler.h:203
gboolean online
Definition: nodes.h:81
uint64_t flags
Definition: remote.c:215
pcmk_resource_t * remote_rsc
Definition: nodes.h:136
#define PCMK_ACTION_NOTIFY
Definition: actions.h:62
#define PCMK_XA_VERSION
Definition: xml_names.h:444
#define XPATH_DC_VERSION
Definition: pe_output.c:400
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition: strings.c:993
Where resource is running.