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