pacemaker  3.0.0-d8340737c4
Scalable High-Availability cluster resource manager
pcmk_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 General Public License version 2
7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 #include <crm/common/output.h>
12 #include <crm/common/results.h>
13 #include <crm/common/xml.h>
14 #include <crm/stonith-ng.h>
15 #include <crm/fencing/internal.h> // stonith__*
16 #include <crm/pengine/internal.h>
17 #include <libxml/tree.h>
18 #include <pacemaker-internal.h>
19 
20 #include <inttypes.h>
21 #include <stdint.h>
22 
23 static char *
24 colocations_header(pcmk_resource_t *rsc, pcmk__colocation_t *cons,
25  bool dependents) {
26  char *retval = NULL;
27 
28  if (cons->primary_role > pcmk_role_started) {
29  retval = crm_strdup_printf("%s (score=%s, %s role=%s, id=%s)",
30  rsc->id, pcmk_readable_score(cons->score),
31  (dependents? "needs" : "with"),
33  cons->id);
34  } else {
35  retval = crm_strdup_printf("%s (score=%s, id=%s)",
36  rsc->id, pcmk_readable_score(cons->score),
37  cons->id);
38  }
39  return retval;
40 }
41 
42 static void
43 colocations_xml_node(pcmk__output_t *out, pcmk_resource_t *rsc,
44  pcmk__colocation_t *cons) {
45  const char *score = pcmk_readable_score(cons->score);
46  const char *dependent_role = NULL;
47  const char *primary_role = NULL;
48 
49  if (cons->dependent_role != pcmk_role_unknown) {
50  dependent_role = pcmk_role_text(cons->dependent_role);
51  }
52  if (cons->primary_role != pcmk_role_unknown) {
53  primary_role = pcmk_role_text(cons->primary_role);
54  }
55 
57  PCMK_XA_ID, cons->id,
58  PCMK_XA_RSC, cons->dependent->id,
59  PCMK_XA_WITH_RSC, cons->primary->id,
60  PCMK_XA_SCORE, score,
62  PCMK_XA_RSC_ROLE, dependent_role,
63  PCMK_XA_WITH_RSC_ROLE, primary_role,
64  NULL);
65 }
66 
67 static int
68 do_locations_list_xml(pcmk__output_t *out, pcmk_resource_t *rsc,
69  bool add_header)
70 {
71  GList *lpc = NULL;
72  int rc = pcmk_rc_no_output;
73 
74  for (lpc = rsc->priv->location_constraints;
75  lpc != NULL; lpc = lpc->next) {
76  pcmk__location_t *cons = lpc->data;
77 
78  GList *lpc2 = NULL;
79 
80  for (lpc2 = cons->nodes; lpc2 != NULL; lpc2 = lpc2->next) {
81  pcmk_node_t *node = (pcmk_node_t *) lpc2->data;
82 
83  if (add_header) {
84  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "locations");
85  }
86 
88  PCMK_XA_NODE, node->priv->name,
89  PCMK_XA_RSC, rsc->id,
90  PCMK_XA_ID, cons->id,
93  NULL);
94  }
95  }
96 
97  if (add_header) {
98  PCMK__OUTPUT_LIST_FOOTER(out, rc);
99  }
100 
101  return rc;
102 }
103 
104 PCMK__OUTPUT_ARGS("rsc-action-item", "const char *", "pcmk_resource_t *",
105  "pcmk_node_t *", "pcmk_node_t *", "pcmk_action_t *",
106  "pcmk_action_t *")
107 static int
108 rsc_action_item(pcmk__output_t *out, va_list args)
109 {
110  const char *change = va_arg(args, const char *);
111  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
112  pcmk_node_t *origin = va_arg(args, pcmk_node_t *);
113  pcmk_node_t *destination = va_arg(args, pcmk_node_t *);
114  pcmk_action_t *action = va_arg(args, pcmk_action_t *);
115  pcmk_action_t *source = va_arg(args, pcmk_action_t *);
116 
117  int len = 0;
118  char *reason = NULL;
119  char *details = NULL;
120  bool same_host = false;
121  bool same_role = false;
122  bool need_role = false;
123 
124  static int rsc_width = 5;
125  static int detail_width = 5;
126 
127  pcmk__assert((action != NULL)
128  && ((destination != NULL) || (origin != NULL)));
129 
130  if (source == NULL) {
131  source = action;
132  }
133 
134  len = strlen(rsc->id);
135  if (len > rsc_width) {
136  rsc_width = len + 2;
137  }
138 
139  if ((rsc->priv->orig_role > pcmk_role_started)
140  || (rsc->priv->next_role > pcmk_role_unpromoted)) {
141  need_role = true;
142  }
143 
144  if (pcmk__same_node(origin, destination)) {
145  same_host = true;
146  }
147 
148  if (rsc->priv->orig_role == rsc->priv->next_role) {
149  same_role = true;
150  }
151 
152  if (need_role && (origin == NULL)) {
153  /* Starting and promoting a promotable clone instance */
154  details = crm_strdup_printf("%s -> %s %s",
157  pcmk__node_name(destination));
158 
159  } else if (origin == NULL) {
160  /* Starting a resource */
161  details = crm_strdup_printf("%s", pcmk__node_name(destination));
162 
163  } else if (need_role && (destination == NULL)) {
164  /* Stopping a promotable clone instance */
165  details = crm_strdup_printf("%s %s",
167  pcmk__node_name(origin));
168 
169  } else if (destination == NULL) {
170  /* Stopping a resource */
171  details = crm_strdup_printf("%s", pcmk__node_name(origin));
172 
173  } else if (need_role && same_role && same_host) {
174  /* Recovering, restarting or re-promoting a promotable clone instance */
175  details = crm_strdup_printf("%s %s",
177  pcmk__node_name(origin));
178 
179  } else if (same_role && same_host) {
180  /* Recovering or Restarting a normal resource */
181  details = crm_strdup_printf("%s", pcmk__node_name(origin));
182 
183  } else if (need_role && same_role) {
184  /* Moving a promotable clone instance */
185  details = crm_strdup_printf("%s -> %s %s", pcmk__node_name(origin),
186  pcmk__node_name(destination),
187  pcmk_role_text(rsc->priv->orig_role));
188 
189  } else if (same_role) {
190  /* Moving a normal resource */
191  details = crm_strdup_printf("%s -> %s", pcmk__node_name(origin),
192  pcmk__node_name(destination));
193 
194  } else if (same_host) {
195  /* Promoting or demoting a promotable clone instance */
196  details = crm_strdup_printf("%s -> %s %s",
199  pcmk__node_name(origin));
200 
201  } else {
202  /* Moving and promoting/demoting */
203  details = crm_strdup_printf("%s %s -> %s %s",
205  pcmk__node_name(origin),
207  pcmk__node_name(destination));
208  }
209 
210  len = strlen(details);
211  if (len > detail_width) {
212  detail_width = len;
213  }
214 
215  if ((source->reason != NULL)
217  reason = crm_strdup_printf("due to %s (blocked)", source->reason);
218 
219  } else if (source->reason) {
220  reason = crm_strdup_printf("due to %s", source->reason);
221 
222  } else if (!pcmk_is_set(action->flags, pcmk__action_runnable)) {
223  reason = strdup("blocked");
224 
225  }
226 
227  out->list_item(out, NULL, "%-8s %-*s ( %*s )%s%s",
228  change, rsc_width, rsc->id, detail_width, details,
229  ((reason == NULL)? "" : " "), pcmk__s(reason, ""));
230 
231  free(details);
232  free(reason);
233  return pcmk_rc_ok;
234 }
235 
236 PCMK__OUTPUT_ARGS("rsc-action-item", "const char *", "pcmk_resource_t *",
237  "pcmk_node_t *", "pcmk_node_t *", "pcmk_action_t *",
238  "pcmk_action_t *")
239 static int
240 rsc_action_item_xml(pcmk__output_t *out, va_list args)
241 {
242  const char *change = va_arg(args, const char *);
243  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
244  pcmk_node_t *origin = va_arg(args, pcmk_node_t *);
245  pcmk_node_t *destination = va_arg(args, pcmk_node_t *);
246  pcmk_action_t *action = va_arg(args, pcmk_action_t *);
247  pcmk_action_t *source = va_arg(args, pcmk_action_t *);
248 
249  char *change_str = NULL;
250 
251  bool same_host = false;
252  bool same_role = false;
253  bool need_role = false;
254  xmlNode *xml = NULL;
255 
256  pcmk__assert((action != NULL)
257  && ((destination != NULL) || (origin != NULL)));
258 
259  if (source == NULL) {
260  source = action;
261  }
262 
263  if ((rsc->priv->orig_role > pcmk_role_started)
264  || (rsc->priv->next_role > pcmk_role_unpromoted)) {
265  need_role = true;
266  }
267 
268  if (pcmk__same_node(origin, destination)) {
269  same_host = true;
270  }
271 
272  if (rsc->priv->orig_role == rsc->priv->next_role) {
273  same_role = true;
274  }
275 
276  change_str = g_ascii_strdown(change, -1);
278  PCMK_XA_ACTION, change_str,
279  PCMK_XA_RESOURCE, rsc->id,
280  NULL);
281  g_free(change_str);
282 
283  if (need_role && (origin == NULL)) {
284  /* Starting and promoting a promotable clone instance */
285  pcmk__xe_set_props(xml,
286  PCMK_XA_ROLE,
290  PCMK_XA_DEST, destination->priv->name,
291  NULL);
292 
293  } else if (origin == NULL) {
294  /* Starting a resource */
295  crm_xml_add(xml, PCMK_XA_NODE, destination->priv->name);
296 
297  } else if (need_role && (destination == NULL)) {
298  /* Stopping a promotable clone instance */
299  pcmk__xe_set_props(xml,
300  PCMK_XA_ROLE,
302  PCMK_XA_NODE, origin->priv->name,
303  NULL);
304 
305  } else if (destination == NULL) {
306  /* Stopping a resource */
307  crm_xml_add(xml, PCMK_XA_NODE, origin->priv->name);
308 
309  } else if (need_role && same_role && same_host) {
310  /* Recovering, restarting or re-promoting a promotable clone instance */
311  pcmk__xe_set_props(xml,
312  PCMK_XA_ROLE,
314  PCMK_XA_SOURCE, origin->priv->name,
315  NULL);
316 
317  } else if (same_role && same_host) {
318  /* Recovering or Restarting a normal resource */
319  crm_xml_add(xml, PCMK_XA_SOURCE, origin->priv->name);
320 
321  } else if (need_role && same_role) {
322  /* Moving a promotable clone instance */
323  pcmk__xe_set_props(xml,
324  PCMK_XA_SOURCE, origin->priv->name,
325  PCMK_XA_DEST, destination->priv->name,
326  PCMK_XA_ROLE,
328  NULL);
329 
330  } else if (same_role) {
331  /* Moving a normal resource */
332  pcmk__xe_set_props(xml,
333  PCMK_XA_SOURCE, origin->priv->name,
334  PCMK_XA_DEST, destination->priv->name,
335  NULL);
336 
337  } else if (same_host) {
338  /* Promoting or demoting a promotable clone instance */
339  pcmk__xe_set_props(xml,
340  PCMK_XA_ROLE,
344  PCMK_XA_SOURCE, origin->priv->name,
345  NULL);
346 
347  } else {
348  /* Moving and promoting/demoting */
349  pcmk__xe_set_props(xml,
350  PCMK_XA_ROLE,
352  PCMK_XA_SOURCE, origin->priv->name,
355  PCMK_XA_DEST, destination->priv->name,
356  NULL);
357  }
358 
359  if ((source->reason != NULL)
361  pcmk__xe_set_props(xml,
362  PCMK_XA_REASON, source->reason,
364  NULL);
365 
366  } else if (source->reason != NULL) {
367  crm_xml_add(xml, PCMK_XA_REASON, source->reason);
368 
369  } else if (!pcmk_is_set(action->flags, pcmk__action_runnable)) {
371 
372  }
373 
374  return pcmk_rc_ok;
375 }
376 
377 PCMK__OUTPUT_ARGS("rsc-is-colocated-with-list", "pcmk_resource_t *", "bool")
378 static int
379 rsc_is_colocated_with_list(pcmk__output_t *out, va_list args) {
380  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
381  bool recursive = va_arg(args, int);
382 
383  int rc = pcmk_rc_no_output;
384 
386  return rc;
387  }
388 
389  /* We're listing constraints explicitly involving rsc, so use
390  * rsc->private->this_with_colocations directly rather than call
391  * rsc->private->cmds->this_with_colocations().
392  */
394  for (GList *lpc = rsc->priv->this_with_colocations;
395  lpc != NULL; lpc = lpc->next) {
396  pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
397  char *hdr = NULL;
398 
399  PCMK__OUTPUT_LIST_HEADER(out, false, rc,
400  "Resources %s is colocated with", rsc->id);
401 
403  out->list_item(out, NULL, "%s (id=%s - loop)",
404  cons->primary->id, cons->id);
405  continue;
406  }
407 
408  hdr = colocations_header(cons->primary, cons, false);
409  out->list_item(out, NULL, "%s", hdr);
410  free(hdr);
411 
412  // Empty list header for indentation of information about this resource
413  out->begin_list(out, NULL, NULL, NULL);
414 
415  out->message(out, "locations-list", cons->primary);
416  if (recursive) {
417  out->message(out, "rsc-is-colocated-with-list",
418  cons->primary, recursive);
419  }
420 
421  out->end_list(out);
422  }
423 
424  PCMK__OUTPUT_LIST_FOOTER(out, rc);
425  return rc;
426 }
427 
428 PCMK__OUTPUT_ARGS("rsc-is-colocated-with-list", "pcmk_resource_t *", "bool")
429 static int
430 rsc_is_colocated_with_list_xml(pcmk__output_t *out, va_list args) {
431  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
432  bool recursive = va_arg(args, int);
433 
434  int rc = pcmk_rc_no_output;
435 
437  return rc;
438  }
439 
440  /* We're listing constraints explicitly involving rsc, so use
441  * rsc->private->this_with_colocations directly rather than call
442  * rsc->private->cmds->this_with_colocations().
443  */
445  for (GList *lpc = rsc->priv->this_with_colocations;
446  lpc != NULL; lpc = lpc->next) {
447  pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
448 
450  colocations_xml_node(out, cons->primary, cons);
451  continue;
452  }
453 
454  colocations_xml_node(out, cons->primary, cons);
455  do_locations_list_xml(out, cons->primary, false);
456 
457  if (recursive) {
458  out->message(out, "rsc-is-colocated-with-list",
459  cons->primary, recursive);
460  }
461  }
462 
463  return rc;
464 }
465 
466 PCMK__OUTPUT_ARGS("rscs-colocated-with-list", "pcmk_resource_t *", "bool")
467 static int
468 rscs_colocated_with_list(pcmk__output_t *out, va_list args) {
469  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
470  bool recursive = va_arg(args, int);
471 
472  int rc = pcmk_rc_no_output;
473 
475  return rc;
476  }
477 
478  /* We're listing constraints explicitly involving rsc, so use
479  * rsc->private->with_this_colocations directly rather than
480  * rsc->private->cmds->with_this_colocations().
481  */
483  for (GList *lpc = rsc->priv->with_this_colocations;
484  lpc != NULL; lpc = lpc->next) {
485  pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
486  char *hdr = NULL;
487 
488  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Resources colocated with %s",
489  rsc->id);
490 
492  out->list_item(out, NULL, "%s (id=%s - loop)",
493  cons->dependent->id, cons->id);
494  continue;
495  }
496 
497  hdr = colocations_header(cons->dependent, cons, true);
498  out->list_item(out, NULL, "%s", hdr);
499  free(hdr);
500 
501  // Empty list header for indentation of information about this resource
502  out->begin_list(out, NULL, NULL, NULL);
503 
504  out->message(out, "locations-list", cons->dependent);
505  if (recursive) {
506  out->message(out, "rscs-colocated-with-list",
507  cons->dependent, recursive);
508  }
509 
510  out->end_list(out);
511  }
512 
513  PCMK__OUTPUT_LIST_FOOTER(out, rc);
514  return rc;
515 }
516 
517 PCMK__OUTPUT_ARGS("rscs-colocated-with-list", "pcmk_resource_t *", "bool")
518 static int
519 rscs_colocated_with_list_xml(pcmk__output_t *out, va_list args) {
520  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
521  bool recursive = va_arg(args, int);
522 
523  int rc = pcmk_rc_no_output;
524 
526  return rc;
527  }
528 
529  /* We're listing constraints explicitly involving rsc, so use
530  * rsc->private->with_this_colocations directly rather than
531  * rsc->private->cmds->with_this_colocations().
532  */
534  for (GList *lpc = rsc->priv->with_this_colocations;
535  lpc != NULL; lpc = lpc->next) {
536  pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
537 
539  colocations_xml_node(out, cons->dependent, cons);
540  continue;
541  }
542 
543  colocations_xml_node(out, cons->dependent, cons);
544  do_locations_list_xml(out, cons->dependent, false);
545 
546  if (recursive) {
547  out->message(out, "rscs-colocated-with-list",
548  cons->dependent, recursive);
549  }
550  }
551 
552  return rc;
553 }
554 
555 PCMK__OUTPUT_ARGS("locations-list", "pcmk_resource_t *")
556 static int
557 locations_list(pcmk__output_t *out, va_list args) {
558  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
559 
560  GList *lpc = NULL;
561  int rc = pcmk_rc_no_output;
562 
563  for (lpc = rsc->priv->location_constraints;
564  lpc != NULL; lpc = lpc->next) {
565  pcmk__location_t *cons = lpc->data;
566 
567  GList *lpc2 = NULL;
568 
569  for (lpc2 = cons->nodes; lpc2 != NULL; lpc2 = lpc2->next) {
570  pcmk_node_t *node = (pcmk_node_t *) lpc2->data;
571 
572  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Locations");
573  out->list_item(out, NULL, "Node %s (score=%s, id=%s, rsc=%s)",
574  pcmk__node_name(node),
575  pcmk_readable_score(node->assign->score), cons->id,
576  rsc->id);
577  }
578  }
579 
580  PCMK__OUTPUT_LIST_FOOTER(out, rc);
581  return rc;
582 }
583 
584 PCMK__OUTPUT_ARGS("locations-list", "pcmk_resource_t *")
585 static int
586 locations_list_xml(pcmk__output_t *out, va_list args) {
587  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
588  return do_locations_list_xml(out, rsc, true);
589 }
590 
591 PCMK__OUTPUT_ARGS("locations-and-colocations", "pcmk_resource_t *",
592  "bool", "bool")
593 static int
594 locations_and_colocations(pcmk__output_t *out, va_list args)
595 {
596  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
597  bool recursive = va_arg(args, int);
598  bool force = va_arg(args, int);
599 
601 
602  // Constraints apply to group/clone, not member/instance
603  if (!force) {
604  rsc = uber_parent(rsc);
605  }
606 
607  out->message(out, "locations-list", rsc);
608 
611  out->message(out, "rscs-colocated-with-list", rsc, recursive);
612 
615  out->message(out, "rsc-is-colocated-with-list", rsc, recursive);
616  return pcmk_rc_ok;
617 }
618 
619 PCMK__OUTPUT_ARGS("locations-and-colocations", "pcmk_resource_t *",
620  "bool", "bool")
621 static int
622 locations_and_colocations_xml(pcmk__output_t *out, va_list args)
623 {
624  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
625  bool recursive = va_arg(args, int);
626  bool force = va_arg(args, int);
627 
629 
630  // Constraints apply to group/clone, not member/instance
631  if (!force) {
632  rsc = uber_parent(rsc);
633  }
634 
636  do_locations_list_xml(out, rsc, false);
637 
640  out->message(out, "rscs-colocated-with-list", rsc, recursive);
641 
644  out->message(out, "rsc-is-colocated-with-list", rsc, recursive);
645 
647  return pcmk_rc_ok;
648 }
649 
650 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *",
651  "const char *")
652 static int
653 health(pcmk__output_t *out, va_list args)
654 {
655  const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
656  const char *host_from = va_arg(args, const char *);
657  const char *fsa_state = va_arg(args, const char *);
658  const char *result = va_arg(args, const char *);
659 
660  return out->info(out, "Controller on %s in state %s: %s",
661  pcmk__s(host_from, "unknown node"),
662  pcmk__s(fsa_state, "unknown"),
663  pcmk__s(result, "unknown result"));
664 }
665 
666 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *",
667  "const char *")
668 static int
669 health_text(pcmk__output_t *out, va_list args)
670 {
671  if (!out->is_quiet(out)) {
672  return health(out, args);
673  } else {
674  const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
675  const char *host_from G_GNUC_UNUSED = va_arg(args, const char *);
676  const char *fsa_state = va_arg(args, const char *);
677  const char *result G_GNUC_UNUSED = va_arg(args, const char *);
678 
679  if (fsa_state != NULL) {
680  pcmk__formatted_printf(out, "%s\n", fsa_state);
681  return pcmk_rc_ok;
682  }
683  }
684 
685  return pcmk_rc_no_output;
686 }
687 
688 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *",
689  "const char *")
690 static int
691 health_xml(pcmk__output_t *out, va_list args)
692 {
693  const char *sys_from = va_arg(args, const char *);
694  const char *host_from = va_arg(args, const char *);
695  const char *fsa_state = va_arg(args, const char *);
696  const char *result = va_arg(args, const char *);
697 
698  pcmk__output_create_xml_node(out, pcmk__s(sys_from, ""),
699  PCMK_XA_NODE_NAME, pcmk__s(host_from, ""),
700  PCMK_XA_STATE, pcmk__s(fsa_state, ""),
701  PCMK_XA_RESULT, pcmk__s(result, ""),
702  NULL);
703  return pcmk_rc_ok;
704 }
705 
706 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
707  "enum pcmk_pacemakerd_state", "const char *", "time_t")
708 static int
709 pacemakerd_health(pcmk__output_t *out, va_list args)
710 {
711  const char *sys_from = va_arg(args, const char *);
712  enum pcmk_pacemakerd_state state =
713  (enum pcmk_pacemakerd_state) va_arg(args, int);
714  const char *state_s = va_arg(args, const char *);
715  time_t last_updated = va_arg(args, time_t);
716 
717  char *last_updated_s = NULL;
718  int rc = pcmk_rc_ok;
719 
720  if (sys_from == NULL) {
721  if (state == pcmk_pacemakerd_state_remote) {
722  sys_from = PCMK__SERVER_REMOTED;
723  } else {
724  sys_from = CRM_SYSTEM_MCP;
725  }
726  }
727 
728  if (state_s == NULL) {
729  state_s = pcmk__pcmkd_state_enum2friendly(state);
730  }
731 
732  if (last_updated != 0) {
733  last_updated_s = pcmk__epoch2str(&last_updated,
737  }
738 
739  rc = out->info(out, "Status of %s: '%s' (last updated %s)",
740  sys_from, state_s,
741  pcmk__s(last_updated_s, "at unknown time"));
742 
743  free(last_updated_s);
744  return rc;
745 }
746 
747 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
748  "enum pcmk_pacemakerd_state", "const char *", "time_t")
749 static int
750 pacemakerd_health_html(pcmk__output_t *out, va_list args)
751 {
752  const char *sys_from = va_arg(args, const char *);
753  enum pcmk_pacemakerd_state state =
754  (enum pcmk_pacemakerd_state) va_arg(args, int);
755  const char *state_s = va_arg(args, const char *);
756  time_t last_updated = va_arg(args, time_t);
757 
758  char *last_updated_s = NULL;
759  char *msg = NULL;
760 
761  if (sys_from == NULL) {
762  if (state == pcmk_pacemakerd_state_remote) {
763  sys_from = PCMK__SERVER_REMOTED;
764  } else {
765  sys_from = CRM_SYSTEM_MCP;
766  }
767  }
768 
769  if (state_s == NULL) {
770  state_s = pcmk__pcmkd_state_enum2friendly(state);
771  }
772 
773  if (last_updated != 0) {
774  last_updated_s = pcmk__epoch2str(&last_updated,
778  }
779 
780  msg = crm_strdup_printf("Status of %s: '%s' (last updated %s)",
781  sys_from, state_s,
782  pcmk__s(last_updated_s, "at unknown time"));
783  pcmk__output_create_html_node(out, "li", NULL, NULL, msg);
784 
785  free(msg);
786  free(last_updated_s);
787  return pcmk_rc_ok;
788 }
789 
790 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
791  "enum pcmk_pacemakerd_state", "const char *", "time_t")
792 static int
793 pacemakerd_health_text(pcmk__output_t *out, va_list args)
794 {
795  if (!out->is_quiet(out)) {
796  return pacemakerd_health(out, args);
797  } else {
798  const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
799  enum pcmk_pacemakerd_state state =
800  (enum pcmk_pacemakerd_state) va_arg(args, int);
801  const char *state_s = va_arg(args, const char *);
802  time_t last_updated G_GNUC_UNUSED = va_arg(args, time_t);
803 
804  if (state_s == NULL) {
806  }
807  pcmk__formatted_printf(out, "%s\n", state_s);
808  return pcmk_rc_ok;
809  }
810 }
811 
812 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
813  "enum pcmk_pacemakerd_state", "const char *", "time_t")
814 static int
815 pacemakerd_health_xml(pcmk__output_t *out, va_list args)
816 {
817  const char *sys_from = va_arg(args, const char *);
818  enum pcmk_pacemakerd_state state =
819  (enum pcmk_pacemakerd_state) va_arg(args, int);
820  const char *state_s = va_arg(args, const char *);
821  time_t last_updated = va_arg(args, time_t);
822 
823  char *last_updated_s = NULL;
824 
825  if (sys_from == NULL) {
826  if (state == pcmk_pacemakerd_state_remote) {
827  sys_from = PCMK__SERVER_REMOTED;
828  } else {
829  sys_from = CRM_SYSTEM_MCP;
830  }
831  }
832 
833  if (state_s == NULL) {
835  }
836 
837  if (last_updated != 0) {
838  last_updated_s = pcmk__epoch2str(&last_updated,
842  }
843 
845  PCMK_XA_SYS_FROM, sys_from,
846  PCMK_XA_STATE, state_s,
847  PCMK_XA_LAST_UPDATED, last_updated_s,
848  NULL);
849  free(last_updated_s);
850  return pcmk_rc_ok;
851 }
852 
853 PCMK__OUTPUT_ARGS("profile", "const char *", "clock_t", "clock_t")
854 static int
855 profile_default(pcmk__output_t *out, va_list args) {
856  const char *xml_file = va_arg(args, const char *);
857  clock_t start = va_arg(args, clock_t);
858  clock_t end = va_arg(args, clock_t);
859 
860  out->list_item(out, NULL, "Testing %s ... %.2f secs", xml_file,
861  (end - start) / (float) CLOCKS_PER_SEC);
862 
863  return pcmk_rc_ok;
864 }
865 
866 PCMK__OUTPUT_ARGS("profile", "const char *", "clock_t", "clock_t")
867 static int
868 profile_xml(pcmk__output_t *out, va_list args) {
869  const char *xml_file = va_arg(args, const char *);
870  clock_t start = va_arg(args, clock_t);
871  clock_t end = va_arg(args, clock_t);
872 
873  char *duration = pcmk__ftoa((end - start) / (float) CLOCKS_PER_SEC);
874 
876  PCMK_XA_FILE, xml_file,
877  PCMK_XA_DURATION, duration,
878  NULL);
879 
880  free(duration);
881  return pcmk_rc_ok;
882 }
883 
884 PCMK__OUTPUT_ARGS("dc", "const char *")
885 static int
886 dc(pcmk__output_t *out, va_list args)
887 {
888  const char *dc = va_arg(args, const char *);
889 
890  return out->info(out, "Designated Controller is: %s",
891  pcmk__s(dc, "not yet elected"));
892 }
893 
894 PCMK__OUTPUT_ARGS("dc", "const char *")
895 static int
896 dc_text(pcmk__output_t *out, va_list args)
897 {
898  if (!out->is_quiet(out)) {
899  return dc(out, args);
900  } else {
901  const char *dc = va_arg(args, const char *);
902 
903  if (dc != NULL) {
904  pcmk__formatted_printf(out, "%s\n", pcmk__s(dc, ""));
905  return pcmk_rc_ok;
906  }
907  }
908 
909  return pcmk_rc_no_output;
910 }
911 
912 PCMK__OUTPUT_ARGS("dc", "const char *")
913 static int
914 dc_xml(pcmk__output_t *out, va_list args)
915 {
916  const char *dc = va_arg(args, const char *);
917 
919  PCMK_XA_NODE_NAME, pcmk__s(dc, ""),
920  NULL);
921  return pcmk_rc_ok;
922 }
923 
924 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *",
925  "const char *", "bool")
926 static int
927 crmadmin_node(pcmk__output_t *out, va_list args)
928 {
929  const char *type = va_arg(args, const char *);
930  const char *name = va_arg(args, const char *);
931  const char *id = va_arg(args, const char *);
932  bool bash_export = va_arg(args, int);
933 
934  if (bash_export) {
935  return out->info(out, "export %s=%s",
936  pcmk__s(name, "<null>"), pcmk__s(id, ""));
937  } else {
938  return out->info(out, "%s node: %s (%s)", type ? type : "cluster",
939  pcmk__s(name, "<null>"), pcmk__s(id, "<null>"));
940  }
941 }
942 
943 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *",
944  "const char *", "bool")
945 static int
946 crmadmin_node_text(pcmk__output_t *out, va_list args)
947 {
948  if (!out->is_quiet(out)) {
949  return crmadmin_node(out, args);
950  } else {
951  const char *type G_GNUC_UNUSED = va_arg(args, const char *);
952  const char *name = va_arg(args, const char *);
953  const char *id G_GNUC_UNUSED = va_arg(args, const char *);
954  bool bash_export G_GNUC_UNUSED = va_arg(args, int);
955 
956  pcmk__formatted_printf(out, "%s\n", pcmk__s(name, "<null>"));
957  return pcmk_rc_ok;
958  }
959 }
960 
961 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *",
962  "const char *", "bool")
963 static int
964 crmadmin_node_xml(pcmk__output_t *out, va_list args)
965 {
966  const char *type = va_arg(args, const char *);
967  const char *name = va_arg(args, const char *);
968  const char *id = va_arg(args, const char *);
969  bool bash_export G_GNUC_UNUSED = va_arg(args, int);
970 
972  PCMK_XA_TYPE, pcmk__s(type, "cluster"),
973  PCMK_XA_NAME, pcmk__s(name, ""),
974  PCMK_XA_ID, pcmk__s(id, ""),
975  NULL);
976  return pcmk_rc_ok;
977 }
978 
979 PCMK__OUTPUT_ARGS("digests", "const pcmk_resource_t *", "const pcmk_node_t *",
980  "const char *", "guint", "const pcmk__op_digest_t *")
981 static int
982 digests_text(pcmk__output_t *out, va_list args)
983 {
984  const pcmk_resource_t *rsc = va_arg(args, const pcmk_resource_t *);
985  const pcmk_node_t *node = va_arg(args, const pcmk_node_t *);
986  const char *task = va_arg(args, const char *);
987  guint interval_ms = va_arg(args, guint);
988  const pcmk__op_digest_t *digests = va_arg(args, const pcmk__op_digest_t *);
989 
990  char *action_desc = NULL;
991  const char *rsc_desc = "unknown resource";
992  const char *node_desc = "unknown node";
993 
994  if (interval_ms != 0) {
995  action_desc = crm_strdup_printf("%ums-interval %s action", interval_ms,
996  ((task == NULL)? "unknown" : task));
997  } else if (pcmk__str_eq(task, PCMK_ACTION_MONITOR, pcmk__str_none)) {
998  action_desc = strdup("probe action");
999  } else {
1000  action_desc = crm_strdup_printf("%s action",
1001  ((task == NULL)? "unknown" : task));
1002  }
1003  if ((rsc != NULL) && (rsc->id != NULL)) {
1004  rsc_desc = rsc->id;
1005  }
1006  if ((node != NULL) && (node->priv->name != NULL)) {
1007  node_desc = node->priv->name;
1008  }
1009  out->begin_list(out, NULL, NULL, "Digests for %s %s on %s",
1010  rsc_desc, action_desc, node_desc);
1011  free(action_desc);
1012 
1013  if (digests == NULL) {
1014  out->list_item(out, NULL, "none");
1015  out->end_list(out);
1016  return pcmk_rc_ok;
1017  }
1018  if (digests->digest_all_calc != NULL) {
1019  out->list_item(out, NULL, "%s (all parameters)",
1020  digests->digest_all_calc);
1021  }
1022  if (digests->digest_secure_calc != NULL) {
1023  out->list_item(out, NULL, "%s (non-private parameters)",
1024  digests->digest_secure_calc);
1025  }
1026  if (digests->digest_restart_calc != NULL) {
1027  out->list_item(out, NULL, "%s (non-reloadable parameters)",
1028  digests->digest_restart_calc);
1029  }
1030  out->end_list(out);
1031  return pcmk_rc_ok;
1032 }
1033 
1034 static void
1035 add_digest_xml(xmlNode *parent, const char *type, const char *digest,
1036  xmlNode *digest_source)
1037 {
1038  if (digest != NULL) {
1039  xmlNodePtr digest_xml = pcmk__xe_create(parent, PCMK_XE_DIGEST);
1040 
1041  crm_xml_add(digest_xml, PCMK_XA_TYPE, pcmk__s(type, "unspecified"));
1042  crm_xml_add(digest_xml, PCMK_XA_HASH, digest);
1043  pcmk__xml_copy(digest_xml, digest_source);
1044  }
1045 }
1046 
1047 PCMK__OUTPUT_ARGS("digests", "const pcmk_resource_t *", "const pcmk_node_t *",
1048  "const char *", "guint", "const pcmk__op_digest_t *")
1049 static int
1050 digests_xml(pcmk__output_t *out, va_list args)
1051 {
1052  const pcmk_resource_t *rsc = va_arg(args, const pcmk_resource_t *);
1053  const pcmk_node_t *node = va_arg(args, const pcmk_node_t *);
1054  const char *task = va_arg(args, const char *);
1055  guint interval_ms = va_arg(args, guint);
1056  const pcmk__op_digest_t *digests = va_arg(args, const pcmk__op_digest_t *);
1057 
1058  char *interval_s = crm_strdup_printf("%ums", interval_ms);
1059  xmlNode *xml = NULL;
1060 
1062  PCMK_XA_RESOURCE, pcmk__s(rsc->id, ""),
1063  PCMK_XA_NODE,
1064  pcmk__s(node->priv->name, ""),
1065  PCMK_XA_TASK, pcmk__s(task, ""),
1066  PCMK_XA_INTERVAL, interval_s,
1067  NULL);
1068  free(interval_s);
1069  if (digests != NULL) {
1070  add_digest_xml(xml, "all", digests->digest_all_calc,
1071  digests->params_all);
1072  add_digest_xml(xml, "nonprivate", digests->digest_secure_calc,
1073  digests->params_secure);
1074  add_digest_xml(xml, "nonreloadable", digests->digest_restart_calc,
1075  digests->params_restart);
1076  }
1077  return pcmk_rc_ok;
1078 }
1079 
1080 #define STOP_SANITY_ASSERT(lineno) do { \
1081  if ((current != NULL) && current->details->unclean) { \
1082  /* It will be a pseudo op */ \
1083  } else if (stop == NULL) { \
1084  crm_err("%s:%d: No stop action exists for %s", \
1085  __func__, lineno, rsc->id); \
1086  pcmk__assert(stop != NULL); \
1087  } else if (pcmk_is_set(stop->flags, pcmk__action_optional)) { \
1088  crm_err("%s:%d: Action %s is still optional", \
1089  __func__, lineno, stop->uuid); \
1090  pcmk__assert(!pcmk_is_set(stop->flags, pcmk__action_optional)); \
1091  } \
1092  } while (0)
1093 
1094 PCMK__OUTPUT_ARGS("rsc-action", "pcmk_resource_t *", "pcmk_node_t *",
1095  "pcmk_node_t *")
1096 static int
1097 rsc_action_default(pcmk__output_t *out, va_list args)
1098 {
1099  pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
1100  pcmk_node_t *current = va_arg(args, pcmk_node_t *);
1101  pcmk_node_t *next = va_arg(args, pcmk_node_t *);
1102 
1103  GList *possible_matches = NULL;
1104  char *key = NULL;
1105  int rc = pcmk_rc_no_output;
1106  bool moving = false;
1107 
1108  pcmk_node_t *start_node = NULL;
1109  pcmk_action_t *start = NULL;
1110  pcmk_action_t *stop = NULL;
1111  pcmk_action_t *promote = NULL;
1112  pcmk_action_t *demote = NULL;
1113  pcmk_action_t *reason_op = NULL;
1114 
1115  if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)
1116  || (current == NULL && next == NULL)) {
1117  const bool managed = pcmk_is_set(rsc->flags, pcmk__rsc_managed);
1118 
1119  pcmk__rsc_info(rsc, "Leave %s\t(%s%s)",
1120  rsc->id, pcmk_role_text(rsc->priv->orig_role),
1121  (managed? "" : " unmanaged"));
1122  return rc;
1123  }
1124 
1125  moving = (current != NULL) && (next != NULL)
1126  && !pcmk__same_node(current, next);
1127 
1128  possible_matches = pe__resource_actions(rsc, next, PCMK_ACTION_START,
1129  false);
1130  if (possible_matches) {
1131  start = possible_matches->data;
1132  g_list_free(possible_matches);
1133  }
1134 
1135  if ((start == NULL)
1136  || !pcmk_is_set(start->flags, pcmk__action_runnable)) {
1137  start_node = NULL;
1138  } else {
1139  start_node = current;
1140  }
1141  possible_matches = pe__resource_actions(rsc, start_node, PCMK_ACTION_STOP,
1142  false);
1143  if (possible_matches) {
1144  stop = possible_matches->data;
1145  g_list_free(possible_matches);
1146  } else if (pcmk_is_set(rsc->flags, pcmk__rsc_stop_unexpected)) {
1147  /* The resource is multiply active with PCMK_META_MULTIPLE_ACTIVE set to
1148  * PCMK_VALUE_STOP_UNEXPECTED, and not stopping on its current node, but
1149  * it should be stopping elsewhere.
1150  */
1151  possible_matches = pe__resource_actions(rsc, NULL, PCMK_ACTION_STOP,
1152  false);
1153  if (possible_matches != NULL) {
1154  stop = possible_matches->data;
1155  g_list_free(possible_matches);
1156  }
1157  }
1158 
1159  possible_matches = pe__resource_actions(rsc, next, PCMK_ACTION_PROMOTE,
1160  false);
1161  if (possible_matches) {
1162  promote = possible_matches->data;
1163  g_list_free(possible_matches);
1164  }
1165 
1166  possible_matches = pe__resource_actions(rsc, next, PCMK_ACTION_DEMOTE,
1167  false);
1168  if (possible_matches) {
1169  demote = possible_matches->data;
1170  g_list_free(possible_matches);
1171  }
1172 
1173  if (rsc->priv->orig_role == rsc->priv->next_role) {
1174  pcmk_action_t *migrate_op = NULL;
1175 
1176  CRM_CHECK(next != NULL, return rc);
1177 
1178  possible_matches = pe__resource_actions(rsc, next,
1180  false);
1181  if (possible_matches) {
1182  migrate_op = possible_matches->data;
1183  }
1184 
1185  if ((migrate_op != NULL) && (current != NULL)
1186  && pcmk_is_set(migrate_op->flags, pcmk__action_runnable)) {
1187  rc = out->message(out, "rsc-action-item", "Migrate", rsc, current,
1188  next, start, NULL);
1189 
1190  } else if (pcmk_is_set(rsc->flags, pcmk__rsc_reload)) {
1191  rc = out->message(out, "rsc-action-item", "Reload", rsc, current,
1192  next, start, NULL);
1193 
1194  } else if ((start == NULL)
1195  || pcmk_is_set(start->flags, pcmk__action_optional)) {
1196  if ((demote != NULL) && (promote != NULL)
1198  && !pcmk_is_set(promote->flags, pcmk__action_optional)) {
1199  rc = out->message(out, "rsc-action-item", "Re-promote", rsc,
1200  current, next, promote, demote);
1201  } else {
1202  pcmk__rsc_info(rsc, "Leave %s\t(%s %s)", rsc->id,
1203  pcmk_role_text(rsc->priv->orig_role),
1204  pcmk__node_name(next));
1205  }
1206 
1207  } else if (!pcmk_is_set(start->flags, pcmk__action_runnable)) {
1208  if ((stop == NULL) || (stop->reason == NULL)) {
1209  reason_op = start;
1210  } else {
1211  reason_op = stop;
1212  }
1213  rc = out->message(out, "rsc-action-item", "Stop", rsc, current,
1214  NULL, stop, reason_op);
1215  STOP_SANITY_ASSERT(__LINE__);
1216 
1217  } else if (moving && current) {
1218  const bool failed = pcmk_is_set(rsc->flags, pcmk__rsc_failed);
1219 
1220  rc = out->message(out, "rsc-action-item",
1221  (failed? "Recover" : "Move"), rsc, current, next,
1222  stop, NULL);
1223 
1224  } else if (pcmk_is_set(rsc->flags, pcmk__rsc_failed)) {
1225  rc = out->message(out, "rsc-action-item", "Recover", rsc, current,
1226  NULL, stop, NULL);
1227  STOP_SANITY_ASSERT(__LINE__);
1228 
1229  } else {
1230  rc = out->message(out, "rsc-action-item", "Restart", rsc, current,
1231  next, start, NULL);
1232 #if 0
1233  /* @TODO This can be reached in situations that should really be
1234  * "Start" (see for example the migrate-fail-7 regression test)
1235  */
1236  STOP_SANITY_ASSERT(__LINE__);
1237 #endif
1238  }
1239 
1240  g_list_free(possible_matches);
1241  return rc;
1242  }
1243 
1244  if ((stop != NULL)
1245  && ((rsc->priv->next_role == pcmk_role_stopped)
1246  || ((start != NULL)
1247  && !pcmk_is_set(start->flags, pcmk__action_runnable)))) {
1248 
1249  key = stop_key(rsc);
1250  for (GList *iter = rsc->priv->active_nodes;
1251  iter != NULL; iter = iter->next) {
1252 
1253  pcmk_node_t *node = iter->data;
1254  pcmk_action_t *stop_op = NULL;
1255 
1256  reason_op = start;
1257  possible_matches = find_actions(rsc->priv->actions, key, node);
1258  if (possible_matches) {
1259  stop_op = possible_matches->data;
1260  g_list_free(possible_matches);
1261  }
1262 
1263  if (stop_op != NULL) {
1264  if (pcmk_is_set(stop_op->flags, pcmk__action_runnable)) {
1265  STOP_SANITY_ASSERT(__LINE__);
1266  }
1267  if (stop_op->reason != NULL) {
1268  reason_op = stop_op;
1269  }
1270  }
1271 
1272  if (out->message(out, "rsc-action-item", "Stop", rsc, node, NULL,
1273  stop_op, reason_op) == pcmk_rc_ok) {
1274  rc = pcmk_rc_ok;
1275  }
1276  }
1277 
1278  free(key);
1279 
1280  } else if ((stop != NULL)
1281  && pcmk_all_flags_set(rsc->flags,
1284  /* 'stop' may be NULL if the failure was ignored */
1285  rc = out->message(out, "rsc-action-item", "Recover", rsc, current,
1286  next, stop, start);
1287  STOP_SANITY_ASSERT(__LINE__);
1288 
1289  } else if (moving) {
1290  rc = out->message(out, "rsc-action-item", "Move", rsc, current, next,
1291  stop, NULL);
1292  STOP_SANITY_ASSERT(__LINE__);
1293 
1294  } else if (pcmk_is_set(rsc->flags, pcmk__rsc_reload)) {
1295  rc = out->message(out, "rsc-action-item", "Reload", rsc, current, next,
1296  start, NULL);
1297 
1298  } else if ((stop != NULL)
1299  && !pcmk_is_set(stop->flags, pcmk__action_optional)) {
1300  rc = out->message(out, "rsc-action-item", "Restart", rsc, current,
1301  next, start, NULL);
1302  STOP_SANITY_ASSERT(__LINE__);
1303 
1304  } else if (rsc->priv->orig_role == pcmk_role_promoted) {
1305  CRM_LOG_ASSERT(current != NULL);
1306  rc = out->message(out, "rsc-action-item", "Demote", rsc, current,
1307  next, demote, NULL);
1308 
1309  } else if (rsc->priv->next_role == pcmk_role_promoted) {
1310  CRM_LOG_ASSERT(next);
1311  rc = out->message(out, "rsc-action-item", "Promote", rsc, current,
1312  next, promote, NULL);
1313 
1314  } else if ((rsc->priv->orig_role == pcmk_role_stopped)
1315  && (rsc->priv->next_role > pcmk_role_stopped)) {
1316  rc = out->message(out, "rsc-action-item", "Start", rsc, current, next,
1317  start, NULL);
1318  }
1319 
1320  return rc;
1321 }
1322 
1323 PCMK__OUTPUT_ARGS("node-action", "const char *", "const char *", "const char *")
1324 static int
1325 node_action(pcmk__output_t *out, va_list args)
1326 {
1327  const char *task = va_arg(args, const char *);
1328  const char *node_name = va_arg(args, const char *);
1329  const char *reason = va_arg(args, const char *);
1330 
1331  if (task == NULL) {
1332  return pcmk_rc_no_output;
1333  } else if (reason) {
1334  out->list_item(out, NULL, "%s %s '%s'", task, node_name, reason);
1335  } else {
1336  crm_notice(" * %s %s", task, node_name);
1337  }
1338 
1339  return pcmk_rc_ok;
1340 }
1341 
1342 PCMK__OUTPUT_ARGS("node-action", "const char *", "const char *", "const char *")
1343 static int
1344 node_action_xml(pcmk__output_t *out, va_list args)
1345 {
1346  const char *task = va_arg(args, const char *);
1347  const char *node_name = va_arg(args, const char *);
1348  const char *reason = va_arg(args, const char *);
1349 
1350  if (task == NULL) {
1351  return pcmk_rc_no_output;
1352  } else if (reason) {
1354  PCMK_XA_TASK, task,
1355  PCMK_XA_NODE, node_name,
1356  PCMK_XA_REASON, reason,
1357  NULL);
1358  } else {
1359  crm_notice(" * %s %s", task, node_name);
1360  }
1361 
1362  return pcmk_rc_ok;
1363 }
1364 
1365 PCMK__OUTPUT_ARGS("node-info", "uint32_t", "const char *", "const char *",
1366  "const char *", "bool", "bool")
1367 static int
1368 node_info_default(pcmk__output_t *out, va_list args)
1369 {
1370  uint32_t node_id = va_arg(args, uint32_t);
1371  const char *node_name = va_arg(args, const char *);
1372  const char *uuid = va_arg(args, const char *);
1373  const char *state = va_arg(args, const char *);
1374  bool have_quorum = (bool) va_arg(args, int);
1375  bool is_remote = (bool) va_arg(args, int);
1376 
1377  return out->info(out,
1378  "Node %" PRIu32 ": %s "
1379  "(uuid=%s, state=%s, have_quorum=%s, is_remote=%s)",
1380  node_id, pcmk__s(node_name, "unknown"),
1381  pcmk__s(uuid, "unknown"), pcmk__s(state, "unknown"),
1382  pcmk__btoa(have_quorum), pcmk__btoa(is_remote));
1383 }
1384 
1385 PCMK__OUTPUT_ARGS("node-info", "uint32_t", "const char *", "const char *",
1386  "const char *", "bool", "bool")
1387 static int
1388 node_info_xml(pcmk__output_t *out, va_list args)
1389 {
1390  uint32_t node_id = va_arg(args, uint32_t);
1391  const char *node_name = va_arg(args, const char *);
1392  const char *uuid = va_arg(args, const char *);
1393  const char *state = va_arg(args, const char *);
1394  bool have_quorum = (bool) va_arg(args, int);
1395  bool is_remote = (bool) va_arg(args, int);
1396 
1397  char *id_s = crm_strdup_printf("%" PRIu32, node_id);
1398 
1400  PCMK_XA_NODEID, id_s,
1401  PCMK_XA_UNAME, node_name,
1402  PCMK_XA_ID, uuid,
1403  PCMK_XA_CRMD, state,
1404  PCMK_XA_HAVE_QUORUM, pcmk__btoa(have_quorum),
1405  PCMK_XA_REMOTE_NODE, pcmk__btoa(is_remote),
1406  NULL);
1407  free(id_s);
1408  return pcmk_rc_ok;
1409 }
1410 
1411 PCMK__OUTPUT_ARGS("inject-cluster-action", "const char *", "const char *",
1412  "xmlNode *")
1413 static int
1414 inject_cluster_action(pcmk__output_t *out, va_list args)
1415 {
1416  const char *node = va_arg(args, const char *);
1417  const char *task = va_arg(args, const char *);
1418  xmlNodePtr rsc = va_arg(args, xmlNodePtr);
1419 
1420  if (out->is_quiet(out)) {
1421  return pcmk_rc_no_output;
1422  }
1423 
1424  if (rsc != NULL) {
1425  out->list_item(out, NULL, "Cluster action: %s for %s on %s",
1426  task, pcmk__xe_id(rsc), node);
1427  } else {
1428  out->list_item(out, NULL, "Cluster action: %s on %s", task, node);
1429  }
1430 
1431  return pcmk_rc_ok;
1432 }
1433 
1434 PCMK__OUTPUT_ARGS("inject-cluster-action", "const char *", "const char *",
1435  "xmlNode *")
1436 static int
1437 inject_cluster_action_xml(pcmk__output_t *out, va_list args)
1438 {
1439  const char *node = va_arg(args, const char *);
1440  const char *task = va_arg(args, const char *);
1441  xmlNodePtr rsc = va_arg(args, xmlNodePtr);
1442 
1443  xmlNodePtr xml_node = NULL;
1444 
1445  if (out->is_quiet(out)) {
1446  return pcmk_rc_no_output;
1447  }
1448 
1450  PCMK_XA_TASK, task,
1451  PCMK_XA_NODE, node,
1452  NULL);
1453 
1454  if (rsc) {
1455  crm_xml_add(xml_node, PCMK_XA_ID, pcmk__xe_id(rsc));
1456  }
1457 
1458  return pcmk_rc_ok;
1459 }
1460 
1461 PCMK__OUTPUT_ARGS("inject-fencing-action", "const char *", "const char *")
1462 static int
1463 inject_fencing_action(pcmk__output_t *out, va_list args)
1464 {
1465  const char *target = va_arg(args, const char *);
1466  const char *op = va_arg(args, const char *);
1467 
1468  if (out->is_quiet(out)) {
1469  return pcmk_rc_no_output;
1470  }
1471 
1472  out->list_item(out, NULL, "Fencing %s (%s)", target, op);
1473  return pcmk_rc_ok;
1474 }
1475 
1476 PCMK__OUTPUT_ARGS("inject-fencing-action", "const char *", "const char *")
1477 static int
1478 inject_fencing_action_xml(pcmk__output_t *out, va_list args)
1479 {
1480  const char *target = va_arg(args, const char *);
1481  const char *op = va_arg(args, const char *);
1482 
1483  if (out->is_quiet(out)) {
1484  return pcmk_rc_no_output;
1485  }
1486 
1489  PCMK_XA_OP, op,
1490  NULL);
1491  return pcmk_rc_ok;
1492 }
1493 
1494 PCMK__OUTPUT_ARGS("inject-attr", "const char *", "const char *", "xmlNode *")
1495 static int
1496 inject_attr(pcmk__output_t *out, va_list args)
1497 {
1498  const char *name = va_arg(args, const char *);
1499  const char *value = va_arg(args, const char *);
1500  xmlNodePtr cib_node = va_arg(args, xmlNodePtr);
1501 
1502  xmlChar *node_path = NULL;
1503 
1504  if (out->is_quiet(out)) {
1505  return pcmk_rc_no_output;
1506  }
1507 
1508  node_path = xmlGetNodePath(cib_node);
1509 
1510  out->list_item(out, NULL, "Injecting attribute %s=%s into %s '%s'",
1511  name, value, node_path, pcmk__xe_id(cib_node));
1512 
1513  free(node_path);
1514  return pcmk_rc_ok;
1515 }
1516 
1517 PCMK__OUTPUT_ARGS("inject-attr", "const char *", "const char *", "xmlNode *")
1518 static int
1519 inject_attr_xml(pcmk__output_t *out, va_list args)
1520 {
1521  const char *name = va_arg(args, const char *);
1522  const char *value = va_arg(args, const char *);
1523  xmlNodePtr cib_node = va_arg(args, xmlNodePtr);
1524 
1525  xmlChar *node_path = NULL;
1526 
1527  if (out->is_quiet(out)) {
1528  return pcmk_rc_no_output;
1529  }
1530 
1531  node_path = xmlGetNodePath(cib_node);
1532 
1534  PCMK_XA_NAME, name,
1535  PCMK_XA_VALUE, value,
1536  PCMK_XA_NODE_PATH, node_path,
1537  PCMK_XA_CIB_NODE, pcmk__xe_id(cib_node),
1538  NULL);
1539  free(node_path);
1540  return pcmk_rc_ok;
1541 }
1542 
1543 PCMK__OUTPUT_ARGS("inject-spec", "const char *")
1544 static int
1545 inject_spec(pcmk__output_t *out, va_list args)
1546 {
1547  const char *spec = va_arg(args, const char *);
1548 
1549  if (out->is_quiet(out)) {
1550  return pcmk_rc_no_output;
1551  }
1552 
1553  out->list_item(out, NULL, "Injecting %s into the configuration", spec);
1554  return pcmk_rc_ok;
1555 }
1556 
1557 PCMK__OUTPUT_ARGS("inject-spec", "const char *")
1558 static int
1559 inject_spec_xml(pcmk__output_t *out, va_list args)
1560 {
1561  const char *spec = va_arg(args, const char *);
1562 
1563  if (out->is_quiet(out)) {
1564  return pcmk_rc_no_output;
1565  }
1566 
1568  PCMK_XA_SPEC, spec,
1569  NULL);
1570  return pcmk_rc_ok;
1571 }
1572 
1573 PCMK__OUTPUT_ARGS("inject-modify-config", "const char *", "const char *")
1574 static int
1575 inject_modify_config(pcmk__output_t *out, va_list args)
1576 {
1577  const char *quorum = va_arg(args, const char *);
1578  const char *watchdog = va_arg(args, const char *);
1579 
1580  if (out->is_quiet(out)) {
1581  return pcmk_rc_no_output;
1582  }
1583 
1584  out->begin_list(out, NULL, NULL, "Performing Requested Modifications");
1585 
1586  if (quorum) {
1587  out->list_item(out, NULL, "Setting quorum: %s", quorum);
1588  }
1589 
1590  if (watchdog) {
1591  out->list_item(out, NULL, "Setting watchdog: %s", watchdog);
1592  }
1593 
1594  return pcmk_rc_ok;
1595 }
1596 
1597 PCMK__OUTPUT_ARGS("inject-modify-config", "const char *", "const char *")
1598 static int
1599 inject_modify_config_xml(pcmk__output_t *out, va_list args)
1600 {
1601  const char *quorum = va_arg(args, const char *);
1602  const char *watchdog = va_arg(args, const char *);
1603 
1604  xmlNodePtr node = NULL;
1605 
1606  if (out->is_quiet(out)) {
1607  return pcmk_rc_no_output;
1608  }
1609 
1611 
1612  if (quorum) {
1613  crm_xml_add(node, PCMK_XA_QUORUM, quorum);
1614  }
1615 
1616  if (watchdog) {
1617  crm_xml_add(node, PCMK_XA_WATCHDOG, watchdog);
1618  }
1619 
1621  return pcmk_rc_ok;
1622 }
1623 
1624 PCMK__OUTPUT_ARGS("inject-modify-node", "const char *", "const char *")
1625 static int
1626 inject_modify_node(pcmk__output_t *out, va_list args)
1627 {
1628  const char *action = va_arg(args, const char *);
1629  const char *node = va_arg(args, const char *);
1630 
1631  if (out->is_quiet(out)) {
1632  return pcmk_rc_no_output;
1633  }
1634 
1635  if (pcmk__str_eq(action, "Online", pcmk__str_none)) {
1636  out->list_item(out, NULL, "Bringing node %s online", node);
1637  return pcmk_rc_ok;
1638  } else if (pcmk__str_eq(action, "Offline", pcmk__str_none)) {
1639  out->list_item(out, NULL, "Taking node %s offline", node);
1640  return pcmk_rc_ok;
1641  } else if (pcmk__str_eq(action, "Failing", pcmk__str_none)) {
1642  out->list_item(out, NULL, "Failing node %s", node);
1643  return pcmk_rc_ok;
1644  }
1645 
1646  return pcmk_rc_no_output;
1647 }
1648 
1649 PCMK__OUTPUT_ARGS("inject-modify-node", "const char *", "const char *")
1650 static int
1651 inject_modify_node_xml(pcmk__output_t *out, va_list args)
1652 {
1653  const char *action = va_arg(args, const char *);
1654  const char *node = va_arg(args, const char *);
1655 
1656  if (out->is_quiet(out)) {
1657  return pcmk_rc_no_output;
1658  }
1659 
1662  PCMK_XA_NODE, node,
1663  NULL);
1664  return pcmk_rc_ok;
1665 }
1666 
1667 PCMK__OUTPUT_ARGS("inject-modify-ticket", "const char *", "const char *")
1668 static int
1669 inject_modify_ticket(pcmk__output_t *out, va_list args)
1670 {
1671  const char *action = va_arg(args, const char *);
1672  const char *ticket = va_arg(args, const char *);
1673 
1674  if (out->is_quiet(out)) {
1675  return pcmk_rc_no_output;
1676  }
1677 
1678  if (pcmk__str_eq(action, "Standby", pcmk__str_none)) {
1679  out->list_item(out, NULL, "Making ticket %s standby", ticket);
1680  } else {
1681  out->list_item(out, NULL, "%s ticket %s", action, ticket);
1682  }
1683 
1684  return pcmk_rc_ok;
1685 }
1686 
1687 PCMK__OUTPUT_ARGS("inject-modify-ticket", "const char *", "const char *")
1688 static int
1689 inject_modify_ticket_xml(pcmk__output_t *out, va_list args)
1690 {
1691  const char *action = va_arg(args, const char *);
1692  const char *ticket = va_arg(args, const char *);
1693 
1694  if (out->is_quiet(out)) {
1695  return pcmk_rc_no_output;
1696  }
1697 
1700  PCMK_XA_TICKET, ticket,
1701  NULL);
1702  return pcmk_rc_ok;
1703 }
1704 
1705 PCMK__OUTPUT_ARGS("inject-pseudo-action", "const char *", "const char *")
1706 static int
1707 inject_pseudo_action(pcmk__output_t *out, va_list args)
1708 {
1709  const char *node = va_arg(args, const char *);
1710  const char *task = va_arg(args, const char *);
1711 
1712  if (out->is_quiet(out)) {
1713  return pcmk_rc_no_output;
1714  }
1715 
1716  out->list_item(out, NULL, "Pseudo action: %s%s%s",
1717  task, ((node == NULL)? "" : " on "), pcmk__s(node, ""));
1718  return pcmk_rc_ok;
1719 }
1720 
1721 PCMK__OUTPUT_ARGS("inject-pseudo-action", "const char *", "const char *")
1722 static int
1723 inject_pseudo_action_xml(pcmk__output_t *out, va_list args)
1724 {
1725  const char *node = va_arg(args, const char *);
1726  const char *task = va_arg(args, const char *);
1727 
1728  xmlNodePtr xml_node = NULL;
1729 
1730  if (out->is_quiet(out)) {
1731  return pcmk_rc_no_output;
1732  }
1733 
1735  PCMK_XA_TASK, task,
1736  NULL);
1737  if (node) {
1738  crm_xml_add(xml_node, PCMK_XA_NODE, node);
1739  }
1740 
1741  return pcmk_rc_ok;
1742 }
1743 
1744 PCMK__OUTPUT_ARGS("inject-rsc-action", "const char *", "const char *",
1745  "const char *", "guint")
1746 static int
1747 inject_rsc_action(pcmk__output_t *out, va_list args)
1748 {
1749  const char *rsc = va_arg(args, const char *);
1750  const char *operation = va_arg(args, const char *);
1751  const char *node = va_arg(args, const char *);
1752  guint interval_ms = va_arg(args, guint);
1753 
1754  if (out->is_quiet(out)) {
1755  return pcmk_rc_no_output;
1756  }
1757 
1758  if (interval_ms) {
1759  out->list_item(out, NULL, "Resource action: %-15s %s=%u on %s",
1760  rsc, operation, interval_ms, node);
1761  } else {
1762  out->list_item(out, NULL, "Resource action: %-15s %s on %s",
1763  rsc, operation, node);
1764  }
1765 
1766  return pcmk_rc_ok;
1767 }
1768 
1769 PCMK__OUTPUT_ARGS("inject-rsc-action", "const char *", "const char *",
1770  "const char *", "guint")
1771 static int
1772 inject_rsc_action_xml(pcmk__output_t *out, va_list args)
1773 {
1774  const char *rsc = va_arg(args, const char *);
1775  const char *operation = va_arg(args, const char *);
1776  const char *node = va_arg(args, const char *);
1777  guint interval_ms = va_arg(args, guint);
1778 
1779  xmlNodePtr xml_node = NULL;
1780 
1781  if (out->is_quiet(out)) {
1782  return pcmk_rc_no_output;
1783  }
1784 
1786  PCMK_XA_RESOURCE, rsc,
1787  PCMK_XA_OP, operation,
1788  PCMK_XA_NODE, node,
1789  NULL);
1790 
1791  if (interval_ms) {
1792  char *interval_s = pcmk__itoa(interval_ms);
1793 
1794  crm_xml_add(xml_node, PCMK_XA_INTERVAL, interval_s);
1795  free(interval_s);
1796  }
1797 
1798  return pcmk_rc_ok;
1799 }
1800 
1801 #define CHECK_RC(retcode, retval) \
1802  if (retval == pcmk_rc_ok) { \
1803  retcode = pcmk_rc_ok; \
1804  }
1805 
1806 PCMK__OUTPUT_ARGS("cluster-status", "pcmk_scheduler_t *",
1807  "enum pcmk_pacemakerd_state", "crm_exit_t",
1808  "stonith_history_t *", "enum pcmk__fence_history", "uint32_t",
1809  "uint32_t", "const char *", "GList *", "GList *")
1810 int
1811 pcmk__cluster_status_text(pcmk__output_t *out, va_list args)
1812 {
1813  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
1814  enum pcmk_pacemakerd_state pcmkd_state =
1815  (enum pcmk_pacemakerd_state) va_arg(args, int);
1816  crm_exit_t history_rc = va_arg(args, crm_exit_t);
1817  stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
1818  enum pcmk__fence_history fence_history = va_arg(args, int);
1819  uint32_t section_opts = va_arg(args, uint32_t);
1820  uint32_t show_opts = va_arg(args, uint32_t);
1821  const char *prefix = va_arg(args, const char *);
1822  GList *unames = va_arg(args, GList *);
1823  GList *resources = va_arg(args, GList *);
1824 
1825  int rc = pcmk_rc_no_output;
1826  bool already_printed_failure = false;
1827 
1828  CHECK_RC(rc, out->message(out, "cluster-summary", scheduler, pcmkd_state,
1829  section_opts, show_opts));
1830 
1831  if (pcmk_is_set(section_opts, pcmk_section_nodes) && unames) {
1832  CHECK_RC(rc, out->message(out, "node-list", scheduler->nodes, unames,
1833  resources, show_opts, rc == pcmk_rc_ok));
1834  }
1835 
1836  /* Print resources section, if needed */
1837  if (pcmk_is_set(section_opts, pcmk_section_resources)) {
1838  CHECK_RC(rc, out->message(out, "resource-list", scheduler, show_opts,
1839  true, unames, resources, rc == pcmk_rc_ok));
1840  }
1841 
1842  /* print Node Attributes section if requested */
1843  if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
1844  CHECK_RC(rc, out->message(out, "node-attribute-list", scheduler,
1845  show_opts, (rc == pcmk_rc_ok), unames,
1846  resources));
1847  }
1848 
1849  /* If requested, print resource operations (which includes failcounts)
1850  * or just failcounts
1851  */
1852  if (pcmk_any_flags_set(section_opts,
1854  CHECK_RC(rc, out->message(out, "node-summary", scheduler, unames,
1855  resources, section_opts, show_opts,
1856  (rc == pcmk_rc_ok)));
1857  }
1858 
1859  /* If there were any failed actions, print them */
1860  if (pcmk_is_set(section_opts, pcmk_section_failures)
1861  && (scheduler->priv->failed != NULL)
1862  && (scheduler->priv->failed->children != NULL)) {
1863 
1864  CHECK_RC(rc, out->message(out, "failed-action-list", scheduler, unames,
1865  resources, show_opts, rc == pcmk_rc_ok));
1866  }
1867 
1868  /* Print failed stonith actions */
1869  if (pcmk_is_set(section_opts, pcmk_section_fence_failed) &&
1870  fence_history != pcmk__fence_history_none) {
1871  if (history_rc == 0) {
1872  stonith_history_t *hp = NULL;
1873 
1874  hp = stonith__first_matching_event(stonith_history,
1876  GINT_TO_POINTER(st_failed));
1877  if (hp) {
1878  CHECK_RC(rc, out->message(out, "failed-fencing-list",
1879  stonith_history, unames, section_opts,
1880  show_opts, rc == pcmk_rc_ok));
1881  }
1882  } else {
1883  PCMK__OUTPUT_SPACER_IF(out, rc == pcmk_rc_ok);
1884  out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
1885  out->list_item(out, NULL, "Failed to get fencing history: %s",
1886  crm_exit_str(history_rc));
1887  out->end_list(out);
1888 
1889  already_printed_failure = true;
1890  }
1891  }
1892 
1893  /* Print tickets if requested */
1894  if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
1895  CHECK_RC(rc, out->message(out, "ticket-list",
1897  (rc == pcmk_rc_ok), false, false));
1898  }
1899 
1900  /* Print negative location constraints if requested */
1901  if (pcmk_is_set(section_opts, pcmk_section_bans)) {
1902  CHECK_RC(rc, out->message(out, "ban-list", scheduler, prefix, resources,
1903  show_opts, rc == pcmk_rc_ok));
1904  }
1905 
1906  /* Print stonith history */
1907  if (pcmk_any_flags_set(section_opts, pcmk_section_fencing_all) &&
1908  fence_history != pcmk__fence_history_none) {
1909  if (history_rc != 0) {
1910  if (!already_printed_failure) {
1911  PCMK__OUTPUT_SPACER_IF(out, rc == pcmk_rc_ok);
1912  out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
1913  out->list_item(out, NULL, "Failed to get fencing history: %s",
1914  crm_exit_str(history_rc));
1915  out->end_list(out);
1916  }
1917  } else if (pcmk_is_set(section_opts, pcmk_section_fence_worked)) {
1918  stonith_history_t *hp = NULL;
1919 
1920  hp = stonith__first_matching_event(stonith_history,
1922  GINT_TO_POINTER(st_failed));
1923  if (hp) {
1924  CHECK_RC(rc, out->message(out, "fencing-list", hp, unames,
1925  section_opts, show_opts,
1926  rc == pcmk_rc_ok));
1927  }
1928  } else if (pcmk_is_set(section_opts, pcmk_section_fence_pending)) {
1929  stonith_history_t *hp = NULL;
1930 
1931  hp = stonith__first_matching_event(stonith_history,
1933  NULL);
1934  if (hp) {
1935  CHECK_RC(rc, out->message(out, "pending-fencing-list", hp,
1936  unames, section_opts, show_opts,
1937  rc == pcmk_rc_ok));
1938  }
1939  }
1940  }
1941 
1942  return rc;
1943 }
1944 
1945 PCMK__OUTPUT_ARGS("cluster-status", "pcmk_scheduler_t *",
1946  "enum pcmk_pacemakerd_state", "crm_exit_t",
1947  "stonith_history_t *", "enum pcmk__fence_history", "uint32_t",
1948  "uint32_t", "const char *", "GList *", "GList *")
1949 static int
1950 cluster_status_xml(pcmk__output_t *out, va_list args)
1951 {
1952  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
1953  enum pcmk_pacemakerd_state pcmkd_state =
1954  (enum pcmk_pacemakerd_state) va_arg(args, int);
1955  crm_exit_t history_rc = va_arg(args, crm_exit_t);
1956  stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
1957  enum pcmk__fence_history fence_history = va_arg(args, int);
1958  uint32_t section_opts = va_arg(args, uint32_t);
1959  uint32_t show_opts = va_arg(args, uint32_t);
1960  const char *prefix = va_arg(args, const char *);
1961  GList *unames = va_arg(args, GList *);
1962  GList *resources = va_arg(args, GList *);
1963 
1964  out->message(out, "cluster-summary", scheduler, pcmkd_state, section_opts,
1965  show_opts);
1966 
1967  /*** NODES ***/
1968  if (pcmk_is_set(section_opts, pcmk_section_nodes)) {
1969  out->message(out, "node-list", scheduler->nodes, unames, resources,
1970  show_opts, false);
1971  }
1972 
1973  /* Print resources section, if needed */
1974  if (pcmk_is_set(section_opts, pcmk_section_resources)) {
1975  /* XML output always displays full details. */
1976  uint32_t full_show_opts = show_opts & ~pcmk_show_brief;
1977 
1978  out->message(out, "resource-list", scheduler, full_show_opts,
1979  false, unames, resources, false);
1980  }
1981 
1982  /* print Node Attributes section if requested */
1983  if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
1984  out->message(out, "node-attribute-list", scheduler, show_opts, false,
1985  unames, resources);
1986  }
1987 
1988  /* If requested, print resource operations (which includes failcounts)
1989  * or just failcounts
1990  */
1991  if (pcmk_any_flags_set(section_opts,
1993  out->message(out, "node-summary", scheduler, unames,
1994  resources, section_opts, show_opts, false);
1995  }
1996 
1997  /* If there were any failed actions, print them */
1998  if (pcmk_is_set(section_opts, pcmk_section_failures)
1999  && (scheduler->priv->failed != NULL)
2000  && (scheduler->priv->failed->children != NULL)) {
2001 
2002  out->message(out, "failed-action-list", scheduler, unames, resources,
2003  show_opts, false);
2004  }
2005 
2006  /* Print stonith history */
2007  if (pcmk_is_set(section_opts, pcmk_section_fencing_all) &&
2008  fence_history != pcmk__fence_history_none) {
2009  out->message(out, "full-fencing-list", history_rc, stonith_history,
2010  unames, section_opts, show_opts, false);
2011  }
2012 
2013  /* Print tickets if requested */
2014  if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
2015  out->message(out, "ticket-list", scheduler->priv->ticket_constraints,
2016  false, false, false);
2017  }
2018 
2019  /* Print negative location constraints if requested */
2020  if (pcmk_is_set(section_opts, pcmk_section_bans)) {
2021  out->message(out, "ban-list", scheduler, prefix, resources, show_opts,
2022  false);
2023  }
2024 
2025  return pcmk_rc_ok;
2026 }
2027 
2028 PCMK__OUTPUT_ARGS("cluster-status", "pcmk_scheduler_t *",
2029  "enum pcmk_pacemakerd_state", "crm_exit_t",
2030  "stonith_history_t *", "enum pcmk__fence_history", "uint32_t",
2031  "uint32_t", "const char *", "GList *", "GList *")
2032 static int
2033 cluster_status_html(pcmk__output_t *out, va_list args)
2034 {
2035  pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
2036  enum pcmk_pacemakerd_state pcmkd_state =
2037  (enum pcmk_pacemakerd_state) va_arg(args, int);
2038  crm_exit_t history_rc = va_arg(args, crm_exit_t);
2039  stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
2040  enum pcmk__fence_history fence_history = va_arg(args, int);
2041  uint32_t section_opts = va_arg(args, uint32_t);
2042  uint32_t show_opts = va_arg(args, uint32_t);
2043  const char *prefix = va_arg(args, const char *);
2044  GList *unames = va_arg(args, GList *);
2045  GList *resources = va_arg(args, GList *);
2046  bool already_printed_failure = false;
2047 
2048  out->message(out, "cluster-summary", scheduler, pcmkd_state, section_opts,
2049  show_opts);
2050 
2051  /*** NODE LIST ***/
2052  if (pcmk_is_set(section_opts, pcmk_section_nodes) && unames) {
2053  out->message(out, "node-list", scheduler->nodes, unames, resources,
2054  show_opts, false);
2055  }
2056 
2057  /* Print resources section, if needed */
2058  if (pcmk_is_set(section_opts, pcmk_section_resources)) {
2059  out->message(out, "resource-list", scheduler, show_opts, true, unames,
2060  resources, false);
2061  }
2062 
2063  /* print Node Attributes section if requested */
2064  if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
2065  out->message(out, "node-attribute-list", scheduler, show_opts, false,
2066  unames, resources);
2067  }
2068 
2069  /* If requested, print resource operations (which includes failcounts)
2070  * or just failcounts
2071  */
2072  if (pcmk_any_flags_set(section_opts,
2074  out->message(out, "node-summary", scheduler, unames,
2075  resources, section_opts, show_opts, false);
2076  }
2077 
2078  /* If there were any failed actions, print them */
2079  if (pcmk_is_set(section_opts, pcmk_section_failures)
2080  && (scheduler->priv->failed != NULL)
2081  && (scheduler->priv->failed->children != NULL)) {
2082 
2083  out->message(out, "failed-action-list", scheduler, unames, resources,
2084  show_opts, false);
2085  }
2086 
2087  /* Print failed stonith actions */
2088  if (pcmk_is_set(section_opts, pcmk_section_fence_failed) &&
2089  fence_history != pcmk__fence_history_none) {
2090  if (history_rc == 0) {
2091  stonith_history_t *hp = NULL;
2092 
2093  hp = stonith__first_matching_event(stonith_history,
2095  GINT_TO_POINTER(st_failed));
2096  if (hp) {
2097  out->message(out, "failed-fencing-list", stonith_history,
2098  unames, section_opts, show_opts, false);
2099  }
2100  } else {
2101  out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
2102  out->list_item(out, NULL, "Failed to get fencing history: %s",
2103  crm_exit_str(history_rc));
2104  out->end_list(out);
2105  }
2106  }
2107 
2108  /* Print stonith history */
2109  if (pcmk_any_flags_set(section_opts, pcmk_section_fencing_all) &&
2110  fence_history != pcmk__fence_history_none) {
2111  if (history_rc != 0) {
2112  if (!already_printed_failure) {
2113  out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
2114  out->list_item(out, NULL, "Failed to get fencing history: %s",
2115  crm_exit_str(history_rc));
2116  out->end_list(out);
2117  }
2118  } else if (pcmk_is_set(section_opts, pcmk_section_fence_worked)) {
2119  stonith_history_t *hp = NULL;
2120 
2121  hp = stonith__first_matching_event(stonith_history,
2123  GINT_TO_POINTER(st_failed));
2124  if (hp) {
2125  out->message(out, "fencing-list", hp, unames, section_opts,
2126  show_opts, false);
2127  }
2128  } else if (pcmk_is_set(section_opts, pcmk_section_fence_pending)) {
2129  stonith_history_t *hp = NULL;
2130 
2131  hp = stonith__first_matching_event(stonith_history,
2133  NULL);
2134  if (hp) {
2135  out->message(out, "pending-fencing-list", hp, unames,
2136  section_opts, show_opts, false);
2137  }
2138  }
2139  }
2140 
2141  /* Print tickets if requested */
2142  if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
2143  out->message(out, "ticket-list", scheduler->priv->ticket_constraints,
2144  false, false, false);
2145  }
2146 
2147  /* Print negative location constraints if requested */
2148  if (pcmk_is_set(section_opts, pcmk_section_bans)) {
2149  out->message(out, "ban-list", scheduler, prefix, resources, show_opts,
2150  false);
2151  }
2152 
2153  return pcmk_rc_ok;
2154 }
2155 
2156 #define KV_PAIR(k, v) do { \
2157  if (legacy) { \
2158  pcmk__g_strcat(s, k "=", pcmk__s(v, ""), " ", NULL); \
2159  } else { \
2160  pcmk__g_strcat(s, k "=\"", pcmk__s(v, ""), "\" ", NULL); \
2161  } \
2162 } while (0)
2163 
2164 PCMK__OUTPUT_ARGS("attribute", "const char *", "const char *", "const char *",
2165  "const char *", "const char *", "bool", "bool")
2166 static int
2167 attribute_default(pcmk__output_t *out, va_list args)
2168 {
2169  const char *scope = va_arg(args, const char *);
2170  const char *instance = va_arg(args, const char *);
2171  const char *name = va_arg(args, const char *);
2172  const char *value = va_arg(args, const char *);
2173  const char *host = va_arg(args, const char *);
2174  bool quiet = va_arg(args, int);
2175  bool legacy = va_arg(args, int);
2176 
2177  gchar *value_esc = NULL;
2178  GString *s = NULL;
2179 
2180  if (quiet) {
2181  if (value != NULL) {
2182  /* Quiet needs to be turned off for ->info() to do anything */
2183  bool was_quiet = out->is_quiet(out);
2184 
2185  if (was_quiet) {
2186  out->quiet = false;
2187  }
2188 
2189  out->info(out, "%s", value);
2190 
2191  out->quiet = was_quiet;
2192  }
2193 
2194  return pcmk_rc_ok;
2195  }
2196 
2197  s = g_string_sized_new(50);
2198 
2200  value_esc = pcmk__xml_escape(value, pcmk__xml_escape_attr_pretty);
2201  value = value_esc;
2202  }
2203 
2204  if (!pcmk__str_empty(scope)) {
2205  KV_PAIR(PCMK_XA_SCOPE, scope);
2206  }
2207 
2208  if (!pcmk__str_empty(instance)) {
2209  KV_PAIR(PCMK_XA_ID, instance);
2210  }
2211 
2213 
2214  if (!pcmk__str_empty(host)) {
2216  }
2217 
2218  if (legacy) {
2219  pcmk__g_strcat(s, PCMK_XA_VALUE "=", pcmk__s(value, "(null)"), NULL);
2220  } else {
2221  pcmk__g_strcat(s, PCMK_XA_VALUE "=\"", pcmk__s(value, ""), "\"", NULL);
2222  }
2223 
2224  out->info(out, "%s", s->str);
2225 
2226  g_free(value_esc);
2227  g_string_free(s, TRUE);
2228  return pcmk_rc_ok;
2229 }
2230 
2231 PCMK__OUTPUT_ARGS("attribute", "const char *", "const char *", "const char *",
2232  "const char *", "const char *", "bool", "bool")
2233 static int
2234 attribute_xml(pcmk__output_t *out, va_list args)
2235 {
2236  const char *scope = va_arg(args, const char *);
2237  const char *instance = va_arg(args, const char *);
2238  const char *name = va_arg(args, const char *);
2239  const char *value = va_arg(args, const char *);
2240  const char *host = va_arg(args, const char *);
2241  bool quiet G_GNUC_UNUSED = va_arg(args, int);
2242  bool legacy G_GNUC_UNUSED = va_arg(args, int);
2243 
2244  xmlNodePtr node = NULL;
2245 
2247  PCMK_XA_NAME, name,
2248  PCMK_XA_VALUE, pcmk__s(value, ""),
2249  NULL);
2250 
2251  if (!pcmk__str_empty(scope)) {
2252  crm_xml_add(node, PCMK_XA_SCOPE, scope);
2253  }
2254 
2255  if (!pcmk__str_empty(instance)) {
2256  crm_xml_add(node, PCMK_XA_ID, instance);
2257  }
2258 
2259  if (!pcmk__str_empty(host)) {
2260  crm_xml_add(node, PCMK_XA_HOST, host);
2261  }
2262 
2263  return pcmk_rc_ok;
2264 }
2265 
2266 PCMK__OUTPUT_ARGS("rule-check", "const char *", "int", "const char *")
2267 static int
2268 rule_check_default(pcmk__output_t *out, va_list args)
2269 {
2270  const char *rule_id = va_arg(args, const char *);
2271  int result = va_arg(args, int);
2272  const char *error = va_arg(args, const char *);
2273 
2274  switch (result) {
2275  case pcmk_rc_within_range:
2276  return out->info(out, "Rule %s is still in effect", rule_id);
2277  case pcmk_rc_ok:
2278  return out->info(out, "Rule %s satisfies conditions", rule_id);
2279  case pcmk_rc_after_range:
2280  return out->info(out, "Rule %s is expired", rule_id);
2281  case pcmk_rc_before_range:
2282  return out->info(out, "Rule %s has not yet taken effect", rule_id);
2284  return out->info(out, "Rule %s does not satisfy conditions",
2285  rule_id);
2286  default:
2287  out->err(out,
2288  "Could not determine whether rule %s is in effect: %s",
2289  rule_id, ((error != NULL)? error : "unexpected error"));
2290  return pcmk_rc_ok;
2291  }
2292 }
2293 
2294 PCMK__OUTPUT_ARGS("rule-check", "const char *", "int", "const char *")
2295 static int
2296 rule_check_xml(pcmk__output_t *out, va_list args)
2297 {
2298  const char *rule_id = va_arg(args, const char *);
2299  int result = va_arg(args, int);
2300  const char *error = va_arg(args, const char *);
2301 
2302  char *rc_str = pcmk__itoa(pcmk_rc2exitc(result));
2303 
2305  PCMK_XA_RULE_ID, rule_id,
2306  PCMK_XA_RC, rc_str,
2307  NULL);
2308  free(rc_str);
2309 
2310  switch (result) {
2311  case pcmk_rc_within_range:
2312  case pcmk_rc_ok:
2313  case pcmk_rc_after_range:
2314  case pcmk_rc_before_range:
2316  return pcmk_rc_ok;
2317  default:
2318  out->err(out,
2319  "Could not determine whether rule %s is in effect: %s",
2320  rule_id, ((error != NULL)? error : "unexpected error"));
2321  return pcmk_rc_ok;
2322  }
2323 }
2324 
2325 PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
2326 static int
2327 result_code_none(pcmk__output_t *out, va_list args)
2328 {
2329  return pcmk_rc_no_output;
2330 }
2331 
2332 PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
2333 static int
2334 result_code_text(pcmk__output_t *out, va_list args)
2335 {
2336  int code = va_arg(args, int);
2337  const char *name = va_arg(args, const char *);
2338  const char *desc = va_arg(args, const char *);
2339 
2340  static int code_width = 0;
2341 
2342  if (out->is_quiet(out)) {
2343  /* If out->is_quiet(), don't print the code. Print name and/or desc in a
2344  * compact format for text output, or print nothing at all for none-type
2345  * output.
2346  */
2347  if ((name != NULL) && (desc != NULL)) {
2348  pcmk__formatted_printf(out, "%s - %s\n", name, desc);
2349 
2350  } else if ((name != NULL) || (desc != NULL)) {
2351  pcmk__formatted_printf(out, "%s\n", ((name != NULL)? name : desc));
2352  }
2353  return pcmk_rc_ok;
2354  }
2355 
2356  /* Get length of longest (most negative) standard Pacemaker return code
2357  * This should be longer than all the values of any other type of return
2358  * code.
2359  */
2360  if (code_width == 0) {
2361  long long most_negative = pcmk_rc_error - (long long) pcmk__n_rc + 1;
2362  code_width = (int) snprintf(NULL, 0, "%lld", most_negative);
2363  }
2364 
2365  if ((name != NULL) && (desc != NULL)) {
2366  static int name_width = 0;
2367 
2368  if (name_width == 0) {
2369  // Get length of longest standard Pacemaker return code name
2370  for (int lpc = 0; lpc < pcmk__n_rc; lpc++) {
2371  int len = (int) strlen(pcmk_rc_name(pcmk_rc_error - lpc));
2372  name_width = QB_MAX(name_width, len);
2373  }
2374  }
2375  return out->info(out, "% *d: %-*s %s", code_width, code, name_width,
2376  name, desc);
2377  }
2378 
2379  if ((name != NULL) || (desc != NULL)) {
2380  return out->info(out, "% *d: %s", code_width, code,
2381  ((name != NULL)? name : desc));
2382  }
2383 
2384  return out->info(out, "% *d", code_width, code);
2385 }
2386 
2387 PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
2388 static int
2389 result_code_xml(pcmk__output_t *out, va_list args)
2390 {
2391  int code = va_arg(args, int);
2392  const char *name = va_arg(args, const char *);
2393  const char *desc = va_arg(args, const char *);
2394 
2395  char *code_str = pcmk__itoa(code);
2396 
2398  PCMK_XA_CODE, code_str,
2399  PCMK_XA_NAME, name,
2400  PCMK_XA_DESCRIPTION, desc,
2401  NULL);
2402  free(code_str);
2403  return pcmk_rc_ok;
2404 }
2405 
2406 PCMK__OUTPUT_ARGS("ticket-attribute", "const char *", "const char *", "const char *")
2407 static int
2408 ticket_attribute_default(pcmk__output_t *out, va_list args)
2409 {
2410  const char *ticket_id G_GNUC_UNUSED = va_arg(args, const char *);
2411  const char *name G_GNUC_UNUSED = va_arg(args, const char *);
2412  const char *value = va_arg(args, const char *);
2413 
2414  out->info(out, "%s", value);
2415  return pcmk_rc_ok;
2416 }
2417 
2418 PCMK__OUTPUT_ARGS("ticket-attribute", "const char *", "const char *", "const char *")
2419 static int
2420 ticket_attribute_xml(pcmk__output_t *out, va_list args)
2421 {
2422  const char *ticket_id = va_arg(args, const char *);
2423  const char *name = va_arg(args, const char *);
2424  const char *value = va_arg(args, const char *);
2425 
2426  /* Create:
2427  * <tickets>
2428  * <ticket id="">
2429  * <attribute name="" value="" />
2430  * </ticket>
2431  * </tickets>
2432  */
2435  PCMK_XA_ID, ticket_id, NULL);
2437  PCMK_XA_NAME, name,
2438  PCMK_XA_VALUE, value,
2439  NULL);
2442 
2443  return pcmk_rc_ok;
2444 }
2445 
2446 PCMK__OUTPUT_ARGS("ticket-constraints", "xmlNode *")
2447 static int
2448 ticket_constraints_default(pcmk__output_t *out, va_list args)
2449 {
2450  xmlNode *constraint_xml = va_arg(args, xmlNode *);
2451 
2452  /* constraint_xml can take two forms:
2453  *
2454  * <rsc_ticket id="rsc1-req-ticketA" rsc="rsc1" ticket="ticketA" ... />
2455  *
2456  * for when there's only one ticket in the CIB, or when the user asked
2457  * for a specific ticket (crm_ticket -c -t for instance)
2458  *
2459  * <xpath-query>
2460  * <rsc_ticket id="rsc1-req-ticketA" rsc="rsc1" ticket="ticketA" ... />
2461  * <rsc_ticket id="rsc1-req-ticketB" rsc="rsc2" ticket="ticketB" ... />
2462  * </xpath-query>
2463  *
2464  * for when there's multiple tickets in the and the user did not ask for
2465  * a specific one.
2466  *
2467  * In both cases, we simply output a <rsc_ticket> element for each ticket
2468  * in the results.
2469  */
2470  out->info(out, "Constraints XML:\n");
2471 
2472  if (pcmk__xe_is(constraint_xml, PCMK__XE_XPATH_QUERY)) {
2473  xmlNode *child = pcmk__xe_first_child(constraint_xml, NULL, NULL, NULL);
2474 
2475  do {
2476  GString *buf = g_string_sized_new(1024);
2477 
2478  pcmk__xml_string(child, pcmk__xml_fmt_pretty, buf, 0);
2479  out->output_xml(out, PCMK_XE_CONSTRAINT, buf->str);
2480  g_string_free(buf, TRUE);
2481 
2482  child = pcmk__xe_next(child, NULL);
2483  } while (child != NULL);
2484  } else {
2485  GString *buf = g_string_sized_new(1024);
2486 
2487  pcmk__xml_string(constraint_xml, pcmk__xml_fmt_pretty, buf, 0);
2488  out->output_xml(out, PCMK_XE_CONSTRAINT, buf->str);
2489  g_string_free(buf, TRUE);
2490  }
2491 
2492  return pcmk_rc_ok;
2493 }
2494 
2495 static int
2496 add_ticket_element_with_constraints(xmlNode *node, void *userdata)
2497 {
2498  pcmk__output_t *out = (pcmk__output_t *) userdata;
2499  const char *ticket_id = crm_element_value(node, PCMK_XA_TICKET);
2500 
2502  PCMK_XA_ID, ticket_id, NULL);
2504  pcmk__output_xml_add_node_copy(out, node);
2505 
2506  /* Pop two parents so now we are back under the <tickets> element */
2509 
2510  return pcmk_rc_ok;
2511 }
2512 
2513 static int
2514 add_resource_element(xmlNode *node, void *userdata)
2515 {
2516  pcmk__output_t *out = (pcmk__output_t *) userdata;
2517  const char *rsc = crm_element_value(node, PCMK_XA_RSC);
2518 
2520  PCMK_XA_ID, rsc, NULL);
2521  return pcmk_rc_ok;
2522 }
2523 
2524 PCMK__OUTPUT_ARGS("ticket-constraints", "xmlNode *")
2525 static int
2526 ticket_constraints_xml(pcmk__output_t *out, va_list args)
2527 {
2528  xmlNode *constraint_xml = va_arg(args, xmlNode *);
2529 
2530  /* Create:
2531  * <tickets>
2532  * <ticket id="">
2533  * <constraints>
2534  * <rsc_ticket />
2535  * </constraints>
2536  * </ticket>
2537  * ...
2538  * </tickets>
2539  */
2541 
2542  if (pcmk__xe_is(constraint_xml, PCMK__XE_XPATH_QUERY)) {
2543  /* Iterate through the list of children once to create all the
2544  * ticket/constraint elements.
2545  */
2546  pcmk__xe_foreach_child(constraint_xml, NULL, add_ticket_element_with_constraints, out);
2547 
2548  /* Put us back at the same level as where <tickets> was created. */
2550 
2551  /* Constraints can reference a resource ID that is defined in the XML
2552  * schema as an IDREF. This requires some other element to be present
2553  * with an id= attribute that matches.
2554  *
2555  * Iterate through the list of children a second time to create the
2556  * following:
2557  *
2558  * <resources>
2559  * <resource id="" />
2560  * ...
2561  * </resources>
2562  */
2564  pcmk__xe_foreach_child(constraint_xml, NULL, add_resource_element, out);
2566 
2567  } else {
2568  /* Creating the output for a single constraint is much easier. All the
2569  * comments in the above block apply here.
2570  */
2571  add_ticket_element_with_constraints(constraint_xml, out);
2573 
2575  add_resource_element(constraint_xml, out);
2577  }
2578 
2579  return pcmk_rc_ok;
2580 }
2581 
2582 PCMK__OUTPUT_ARGS("ticket-state", "xmlNode *")
2583 static int
2584 ticket_state_default(pcmk__output_t *out, va_list args)
2585 {
2586  xmlNode *state_xml = va_arg(args, xmlNode *);
2587 
2588  GString *buf = g_string_sized_new(1024);
2589 
2590  out->info(out, "State XML:\n");
2591  pcmk__xml_string(state_xml, pcmk__xml_fmt_pretty, buf, 0);
2592  out->output_xml(out, PCMK__XE_TICKET_STATE, buf->str);
2593 
2594  g_string_free(buf, TRUE);
2595  return pcmk_rc_ok;
2596 }
2597 
2598 static int
2599 add_ticket_element(xmlNode *node, void *userdata)
2600 {
2601  pcmk__output_t *out = (pcmk__output_t *) userdata;
2602  xmlNode *ticket_node = NULL;
2603 
2604  ticket_node = pcmk__output_create_xml_node(out, PCMK_XE_TICKET, NULL);
2605  pcmk__xe_copy_attrs(ticket_node, node, pcmk__xaf_none);
2606  return pcmk_rc_ok;
2607 }
2608 
2609 PCMK__OUTPUT_ARGS("ticket-state", "xmlNode *")
2610 static int
2611 ticket_state_xml(pcmk__output_t *out, va_list args)
2612 {
2613  xmlNode *state_xml = va_arg(args, xmlNode *);
2614 
2615  /* Create:
2616  * <tickets>
2617  * <ticket />
2618  * ...
2619  * </tickets>
2620  */
2622 
2623  if (state_xml->children != NULL) {
2624  /* Iterate through the list of children once to create all the
2625  * ticket elements.
2626  */
2627  pcmk__xe_foreach_child(state_xml, PCMK__XE_TICKET_STATE, add_ticket_element, out);
2628 
2629  } else {
2630  add_ticket_element(state_xml, out);
2631  }
2632 
2634  return pcmk_rc_ok;
2635 }
2636 
2637 static pcmk__message_entry_t fmt_functions[] = {
2638  { "attribute", "default", attribute_default },
2639  { "attribute", "xml", attribute_xml },
2640  { "cluster-status", "default", pcmk__cluster_status_text },
2641  { "cluster-status", "html", cluster_status_html },
2642  { "cluster-status", "xml", cluster_status_xml },
2643  { "crmadmin-node", "default", crmadmin_node },
2644  { "crmadmin-node", "text", crmadmin_node_text },
2645  { "crmadmin-node", "xml", crmadmin_node_xml },
2646  { "dc", "default", dc },
2647  { "dc", "text", dc_text },
2648  { "dc", "xml", dc_xml },
2649  { "digests", "default", digests_text },
2650  { "digests", "xml", digests_xml },
2651  { "health", "default", health },
2652  { "health", "text", health_text },
2653  { "health", "xml", health_xml },
2654  { "inject-attr", "default", inject_attr },
2655  { "inject-attr", "xml", inject_attr_xml },
2656  { "inject-cluster-action", "default", inject_cluster_action },
2657  { "inject-cluster-action", "xml", inject_cluster_action_xml },
2658  { "inject-fencing-action", "default", inject_fencing_action },
2659  { "inject-fencing-action", "xml", inject_fencing_action_xml },
2660  { "inject-modify-config", "default", inject_modify_config },
2661  { "inject-modify-config", "xml", inject_modify_config_xml },
2662  { "inject-modify-node", "default", inject_modify_node },
2663  { "inject-modify-node", "xml", inject_modify_node_xml },
2664  { "inject-modify-ticket", "default", inject_modify_ticket },
2665  { "inject-modify-ticket", "xml", inject_modify_ticket_xml },
2666  { "inject-pseudo-action", "default", inject_pseudo_action },
2667  { "inject-pseudo-action", "xml", inject_pseudo_action_xml },
2668  { "inject-rsc-action", "default", inject_rsc_action },
2669  { "inject-rsc-action", "xml", inject_rsc_action_xml },
2670  { "inject-spec", "default", inject_spec },
2671  { "inject-spec", "xml", inject_spec_xml },
2672  { "locations-and-colocations", "default", locations_and_colocations },
2673  { "locations-and-colocations", "xml", locations_and_colocations_xml },
2674  { "locations-list", "default", locations_list },
2675  { "locations-list", "xml", locations_list_xml },
2676  { "node-action", "default", node_action },
2677  { "node-action", "xml", node_action_xml },
2678  { "node-info", "default", node_info_default },
2679  { "node-info", "xml", node_info_xml },
2680  { "pacemakerd-health", "default", pacemakerd_health },
2681  { "pacemakerd-health", "html", pacemakerd_health_html },
2682  { "pacemakerd-health", "text", pacemakerd_health_text },
2683  { "pacemakerd-health", "xml", pacemakerd_health_xml },
2684  { "profile", "default", profile_default, },
2685  { "profile", "xml", profile_xml },
2686  { "result-code", PCMK_VALUE_NONE, result_code_none },
2687  { "result-code", "text", result_code_text },
2688  { "result-code", "xml", result_code_xml },
2689  { "rsc-action", "default", rsc_action_default },
2690  { "rsc-action-item", "default", rsc_action_item },
2691  { "rsc-action-item", "xml", rsc_action_item_xml },
2692  { "rsc-is-colocated-with-list", "default", rsc_is_colocated_with_list },
2693  { "rsc-is-colocated-with-list", "xml", rsc_is_colocated_with_list_xml },
2694  { "rscs-colocated-with-list", "default", rscs_colocated_with_list },
2695  { "rscs-colocated-with-list", "xml", rscs_colocated_with_list_xml },
2696  { "rule-check", "default", rule_check_default },
2697  { "rule-check", "xml", rule_check_xml },
2698  { "ticket-attribute", "default", ticket_attribute_default },
2699  { "ticket-attribute", "xml", ticket_attribute_xml },
2700  { "ticket-constraints", "default", ticket_constraints_default },
2701  { "ticket-constraints", "xml", ticket_constraints_xml },
2702  { "ticket-state", "default", ticket_state_default },
2703  { "ticket-state", "xml", ticket_state_xml },
2704 
2705  { NULL, NULL, NULL }
2706 };
2707 
2708 void
2710  pcmk__register_messages(out, fmt_functions);
2711 }
pcmk__cpg_host_t host
Definition: cpg.c:52
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:213
#define PCMK_XE_PACEMAKERD
Definition: xml_names.h:157
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:805
#define PCMK_XE_DIGEST
Definition: xml_names.h:101
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 crm_notice(fmt, args...)
Definition: logging.h:365
#define PCMK_XA_NEXT_ROLE
Definition: xml_names.h:332
char * pcmk__xml_escape(const char *text, enum pcmk__xml_escape_type type)
Definition: xml.c:964
#define PCMK_XA_NAME
Definition: xml_names.h:330
const char * pcmk_role_text(enum rsc_role_e role)
Get readable description of a resource role.
Definition: roles.c:23
stonith_history_t * stonith__first_matching_event(stonith_history_t *history, bool(*matching_fn)(stonith_history_t *, void *), void *user_data)
Definition: st_client.c:2397
#define PCMK__XE_TICKET_STATE
#define PCMK_XA_DEST
Definition: xml_names.h:262
Control output from tools.
void pcmk__register_messages(pcmk__output_t *out, const pcmk__message_entry_t *table)
Definition: output.c:204
#define PCMK_XA_REMOTE_NODE
Definition: xml_names.h:376
#define PCMK__SERVER_REMOTED
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
Definition: xml_element.c:1480
#define crm_time_log_timeofday
Definition: iso8601.h:68
pcmk_resource_t * uber_parent(pcmk_resource_t *rsc)
Definition: complex.c:1017
Stopped.
Definition: roles.h:36
const char * name
Definition: cib.c:26
enum pcmk_ipc_server type
Definition: cpg.c:51
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition: scores.c:102
pcmk__fence_history
Control how much of the fencing history is output.
Definition: pcmki_fence.h:22
void pcmk__xml_string(const xmlNode *data, uint32_t options, GString *buffer, int depth)
Definition: xml_io.c:411
xmlNode * params_restart
#define PCMK_XE_CONSTRAINTS
Definition: xml_names.h:89
const size_t pcmk__n_rc
Definition: results.c:439
bool pcmk__xml_needs_escape(const char *text, enum pcmk__xml_escape_type type)
Definition: xml.c:882
#define PCMK_XE_RSC_COLOCATION
Definition: xml_names.h:185
#define pcmk__rsc_info(rsc, fmt, args...)
#define PCMK_XA_DURATION
Definition: xml_names.h:266
#define PCMK_XA_WITH_RSC_ROLE
Definition: xml_names.h:453
#define pcmk__set_rsc_flags(resource, flags_to_set)
#define PCMK_ACTION_MONITOR
Definition: actions.h:51
crm_exit_t pcmk_rc2exitc(int rc)
Map a function return code to the most similar exit code.
Definition: results.c:810
#define PCMK_XA_HAVE_QUORUM
Definition: xml_names.h:295
#define PCMK__XE_XPATH_QUERY
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_XA_RULE_ID
Definition: xml_names.h:391
#define PCMK_XE_PSEUDO_ACTION
Definition: xml_names.h:168
#define CHECK_RC(retcode, retval)
Definition: pcmk_output.c:1801
int pcmk__xe_foreach_child(xmlNode *xml, const char *child_element_name, int(*handler)(xmlNode *xml, void *userdata), void *userdata)
Definition: xml_element.c:979
Promoted.
Definition: roles.h:39
#define PCMK_XA_RSC
Definition: xml_names.h:388
#define PCMK_XE_RESULT_CODE
Definition: xml_names.h:181
enum crm_exit_e crm_exit_t
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:196
#define PCMK_XE_NODE_ACTION
Definition: xml_names.h:137
GList * pe__resource_actions(const pcmk_resource_t *rsc, const pcmk_node_t *node, const char *task, bool require_node)
Find all actions of given type for a resource.
Definition: pe_actions.c:1517
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
#define PCMK_XA_TYPE
Definition: xml_names.h:430
void pcmk__register_lib_messages(pcmk__output_t *out)
Definition: pcmk_output.c:2709
#define PCMK_XA_RESOURCE
Definition: xml_names.h:382
#define PCMK_XA_NODEID
Definition: xml_names.h:339
#define PCMK_XA_NODE_PATH
Definition: xml_names.h:338
#define PCMK_XE_ATTRIBUTE
Definition: xml_names.h:69
Include indentation and newlines.
Definition: xml_internal.h:149
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml_element.c:407
const char * action
Definition: pcmk_fence.c:32
bool stonith__event_state_pending(stonith_history_t *history, void *user_data)
Definition: st_client.c:2411
#define PCMK_XA_NODE
Definition: xml_names.h:335
#define PCMK_XA_HASH
Definition: xml_names.h:294
void void void pcmk__formatted_printf(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
#define CRM_SYSTEM_MCP
Definition: crm.h:88
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__OUTPUT_SPACER_IF(out_obj, cond)
#define PCMK_XE_RULE_CHECK
Definition: xml_names.h:192
pcmk__node_private_t * priv
Definition: nodes.h:85
#define PCMK_XA_OP
Definition: xml_names.h:347
void pe__clear_resource_flags_on_all(pcmk_scheduler_t *scheduler, uint64_t flag)
Definition: utils.c:585
#define PCMK_ACTION_DEMOTE
Definition: actions.h:40
#define PCMK_XA_SPEC
Definition: xml_names.h:404
const char * crm_exit_str(crm_exit_t exit_code)
Definition: results.c:748
#define PCMK_XA_SYS_FROM
Definition: xml_names.h:416
#define PCMK_XA_LAST_UPDATED
Definition: xml_names.h:317
#define PCMK_XE_RSC_ACTION
Definition: xml_names.h:184
#define PCMK_XE_RSC_LOCATION
Definition: xml_names.h:188
pcmk_scheduler_t * scheduler
#define PCMK_XA_NODE_NAME
Definition: xml_names.h:337
#define PCMK_XE_INJECT_ATTR
Definition: xml_names.h:120
#define PCMK_XA_UNAME
Definition: xml_names.h:431
void pcmk__unpack_constraints(pcmk_scheduler_t *scheduler)
#define PCMK_XE_DIGESTS
Definition: xml_names.h:102
#define stop_key(rsc)
Definition: internal.h:196
#define PCMK_XA_REASON
Definition: xml_names.h:371
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_VALUE_NONE
Definition: options.h:179
#define PCMK_XA_DESCRIPTION
Definition: xml_names.h:261
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1297
#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
#define PCMK_ACTION_START
Definition: actions.h:63
pcmk__resource_private_t * priv
Definition: resources.h:61
Unpromoted.
Definition: roles.h:38
Wrappers for and extensions to libxml2.
#define PCMK_XE_DC
Definition: xml_names.h:98
#define PCMK_XA_STATE
Definition: xml_names.h:409
xmlNodePtr pcmk__output_create_xml_node(pcmk__output_t *out, const char *name,...) G_GNUC_NULL_TERMINATED
Definition: output_xml.c:515
#define PCMK_XE_CONSTRAINT
Definition: xml_names.h:88
#define PCMK_ACTION_STOP
Definition: actions.h:66
Flag has no effect.
Definition: xml_internal.h:362
#define PCMK_XE_INJECT_SPEC
Definition: xml_names.h:121
#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
#define PCMK_XA_WATCHDOG
Definition: xml_names.h:445
#define pcmk_section_fencing_all
Definition: output.h:46
#define PCMK_XA_VALUE
Definition: xml_names.h:442
#define PCMK_XA_SCORE
Definition: xml_names.h:396
int pcmk__cluster_status_text(pcmk__output_t *out, va_list args)
#define PCMK_XE_NODE_INFO
Definition: xml_names.h:140
#define crm_time_log_with_timezone
Definition: iso8601.h:69
#define PCMK_XE_TICKETS
Definition: xml_names.h:213
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
Definition: output_xml.c:562
Function and executable result codes.
#define KV_PAIR(k, v)
Definition: pcmk_output.c:2156
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
Definition: xml_element.c:106
pcmk_resource_t * primary
#define PCMK_XA_INTERVAL
Definition: xml_names.h:309
#define pcmk__assert(expr)
#define PCMK__OUTPUT_LIST_FOOTER(out_obj, retcode)
const char * target
Definition: pcmk_fence.c:31
void pcmk__xe_set_props(xmlNodePtr node,...) G_GNUC_NULL_TERMINATED
Definition: xml_element.c:970
pcmk_pacemakerd_state
#define PCMK_XA_HOST
Definition: xml_names.h:297
#define PCMK_XE_TICKET
Definition: xml_names.h:212
#define PCMK_XA_FILE
Definition: xml_names.h:287
#define PCMK_XA_NODE_ATTRIBUTE
Definition: xml_names.h:336
#define PCMK_XE_NODE
Definition: xml_names.h:136
#define PCMK__OUTPUT_LIST_HEADER(out_obj, cond, retcode, title...)
int pcmk__xe_copy_attrs(xmlNode *target, const xmlNode *src, uint32_t flags)
Definition: xml_element.c:252
#define PCMK_XA_RC
Definition: xml_names.h:369
#define PCMK_XA_CODE
Definition: xml_names.h:248
GList * nodes
Definition: scheduler.h:97
pcmk__action_result_t result
Definition: pcmk_fence.c:37
#define PCMK_XA_CIB_NODE
Definition: xml_names.h:245
const char * pcmk_rc_name(int rc)
Get a return code constant name as a string.
Definition: results.c:449
pcmk_scheduler_t * scheduler
const char * pcmk_pacemakerd_api_daemon_state_enum2text(enum pcmk_pacemakerd_state state)
#define PCMK_XA_TICKET
Definition: xml_names.h:426
#define STOP_SANITY_ASSERT(lineno)
Definition: pcmk_output.c:1080
GList * find_actions(GList *input, const char *key, const pcmk_node_t *on_node)
Definition: pe_actions.c:1445
char * pcmk__epoch2str(const time_t *source, uint32_t flags)
Definition: iso8601.c:2147
#define PCMK_XA_CRMD
Definition: xml_names.h:256
xmlNode * params_secure
#define PCMK_ACTION_MIGRATE_FROM
Definition: actions.h:49
Fencing aka. STONITH.
Started.
Definition: roles.h:37
This structure contains everything that makes up a single output formatter.
#define PCMK_XA_ATTRIBUTE
Definition: xml_names.h:236
#define PCMK_XA_SOURCE
Definition: xml_names.h:401
#define PCMK_ACTION_PROMOTE
Definition: actions.h:57
pcmk_resource_t * dependent
#define PCMK_XA_RSC_ROLE
Definition: xml_names.h:390
const char * pcmk__pcmkd_state_enum2friendly(enum pcmk_pacemakerd_state state)
#define PCMK_XE_FENCING_ACTION
Definition: xml_names.h:116
#define PCMK_XE_MODIFICATIONS
Definition: xml_names.h:132
unsigned long long flags
Definition: resources.h:69
const char * node_attribute
#define PCMK_XE_MODIFY_TICKET
Definition: xml_names.h:134
#define PCMK_XA_WITH_RSC
Definition: xml_names.h:452
#define PCMK_XE_TIMING
Definition: xml_names.h:214
Resource role is unknown.
Definition: roles.h:35
Location constraint object.
#define PCMK_XA_QUORUM
Definition: xml_names.h:367
const char * parent
Definition: cib.c:27
#define PCMK_XE_CLUSTER_ACTION
Definition: xml_names.h:81
#define PCMK_XE_RESOURCE
Definition: xml_names.h:172
#define PCMK_XE_MODIFY_NODE
Definition: xml_names.h:133
bool stonith__event_state_eq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2417
#define PCMK_XA_TARGET
Definition: xml_names.h:418
#define PCMK_XA_RESULT
Definition: xml_names.h:386
#define PCMK_XA_ACTION
Definition: xml_names.h:229
#define PCMK_XA_ROLE
Definition: xml_names.h:387
#define PCMK_XE_RESOURCES
Definition: xml_names.h:179
#define crm_time_log_date
Definition: iso8601.h:67
#define PCMK_XA_SCOPE
Definition: xml_names.h:395
bool stonith__event_state_neq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2423
void pcmk__output_xml_add_node_copy(pcmk__output_t *out, xmlNodePtr node)
Definition: output_xml.c:496
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
struct pcmk__node_assignment * assign
Definition: nodes.h:79