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