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