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