pacemaker  2.1.6-802a72226b
Scalable High-Availability cluster resource manager
pcmk_output.c
Go to the documentation of this file.
1 /*
2  * Copyright 2019-2023 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/msg_xml.h>
14 #include <crm/stonith-ng.h>
15 #include <crm/fencing/internal.h>
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(pe_resource_t *rsc, pcmk__colocation_t *cons,
25  bool dependents) {
26  char *retval = NULL;
27 
28  if (cons->primary_role > RSC_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"),
32  role2text(cons->primary_role), cons->id);
33  } else {
34  retval = crm_strdup_printf("%s (score=%s, id=%s)",
35  rsc->id, pcmk_readable_score(cons->score),
36  cons->id);
37  }
38  return retval;
39 }
40 
41 static void
42 colocations_xml_node(pcmk__output_t *out, pe_resource_t *rsc,
43  pcmk__colocation_t *cons) {
44  xmlNodePtr node = NULL;
45 
47  "id", cons->id,
48  "rsc", cons->dependent->id,
49  "with-rsc", cons->primary->id,
50  "score", pcmk_readable_score(cons->score),
51  NULL);
52 
53  if (cons->node_attribute) {
54  xmlSetProp(node, (pcmkXmlStr) "node-attribute", (pcmkXmlStr) cons->node_attribute);
55  }
56 
57  if (cons->dependent_role != RSC_ROLE_UNKNOWN) {
58  xmlSetProp(node, (pcmkXmlStr) "rsc-role",
60  }
61 
62  if (cons->primary_role != RSC_ROLE_UNKNOWN) {
63  xmlSetProp(node, (pcmkXmlStr) "with-rsc-role",
65  }
66 }
67 
68 static int
69 do_locations_list_xml(pcmk__output_t *out, pe_resource_t *rsc, bool add_header)
70 {
71  GList *lpc = NULL;
72  GList *list = rsc->rsc_location;
73  int rc = pcmk_rc_no_output;
74 
75  for (lpc = list; lpc != NULL; lpc = lpc->next) {
76  pe__location_t *cons = lpc->data;
77 
78  GList *lpc2 = NULL;
79 
80  for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) {
81  pe_node_t *node = (pe_node_t *) lpc2->data;
82 
83  if (add_header) {
84  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "locations");
85  }
86 
88  "node", node->details->uname,
89  "rsc", rsc->id,
90  "id", cons->id,
91  "score", pcmk_readable_score(node->weight),
92  NULL);
93  }
94  }
95 
96  if (add_header) {
97  PCMK__OUTPUT_LIST_FOOTER(out, rc);
98  }
99 
100  return rc;
101 }
102 
103 PCMK__OUTPUT_ARGS("rsc-action-item", "const char *", "pe_resource_t *",
104  "pe_node_t *", "pe_node_t *", "pe_action_t *",
105  "pe_action_t *")
106 static int
107 rsc_action_item(pcmk__output_t *out, va_list args)
108 {
109  const char *change = va_arg(args, const char *);
110  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
111  pe_node_t *origin = va_arg(args, pe_node_t *);
112  pe_node_t *destination = va_arg(args, pe_node_t *);
113  pe_action_t *action = va_arg(args, pe_action_t *);
114  pe_action_t *source = va_arg(args, pe_action_t *);
115 
116  int len = 0;
117  char *reason = NULL;
118  char *details = NULL;
119  bool same_host = false;
120  bool same_role = false;
121  bool need_role = false;
122 
123  static int rsc_width = 5;
124  static int detail_width = 5;
125 
127  CRM_ASSERT(destination != NULL || origin != NULL);
128 
129  if(source == NULL) {
130  source = action;
131  }
132 
133  len = strlen(rsc->id);
134  if(len > rsc_width) {
135  rsc_width = len + 2;
136  }
137 
138  if ((rsc->role > RSC_ROLE_STARTED)
139  || (rsc->next_role > RSC_ROLE_UNPROMOTED)) {
140  need_role = true;
141  }
142 
143  if(origin != NULL && destination != NULL && origin->details == destination->details) {
144  same_host = true;
145  }
146 
147  if(rsc->role == rsc->next_role) {
148  same_role = true;
149  }
150 
151  if (need_role && (origin == NULL)) {
152  /* Starting and promoting a promotable clone instance */
153  details = crm_strdup_printf("%s -> %s %s", role2text(rsc->role),
154  role2text(rsc->next_role),
155  pe__node_name(destination));
156 
157  } else if (origin == NULL) {
158  /* Starting a resource */
159  details = crm_strdup_printf("%s", pe__node_name(destination));
160 
161  } else if (need_role && (destination == NULL)) {
162  /* Stopping a promotable clone instance */
163  details = crm_strdup_printf("%s %s", role2text(rsc->role),
164  pe__node_name(origin));
165 
166  } else if (destination == NULL) {
167  /* Stopping a resource */
168  details = crm_strdup_printf("%s", pe__node_name(origin));
169 
170  } else if (need_role && same_role && same_host) {
171  /* Recovering, restarting or re-promoting a promotable clone instance */
172  details = crm_strdup_printf("%s %s", role2text(rsc->role),
173  pe__node_name(origin));
174 
175  } else if (same_role && same_host) {
176  /* Recovering or Restarting a normal resource */
177  details = crm_strdup_printf("%s", pe__node_name(origin));
178 
179  } else if (need_role && same_role) {
180  /* Moving a promotable clone instance */
181  details = crm_strdup_printf("%s -> %s %s", pe__node_name(origin),
182  pe__node_name(destination),
183  role2text(rsc->role));
184 
185  } else if (same_role) {
186  /* Moving a normal resource */
187  details = crm_strdup_printf("%s -> %s", pe__node_name(origin),
188  pe__node_name(destination));
189 
190  } else if (same_host) {
191  /* Promoting or demoting a promotable clone instance */
192  details = crm_strdup_printf("%s -> %s %s", role2text(rsc->role),
193  role2text(rsc->next_role),
194  pe__node_name(origin));
195 
196  } else {
197  /* Moving and promoting/demoting */
198  details = crm_strdup_printf("%s %s -> %s %s", role2text(rsc->role),
199  pe__node_name(origin),
200  role2text(rsc->next_role),
201  pe__node_name(destination));
202  }
203 
204  len = strlen(details);
205  if(len > detail_width) {
206  detail_width = len;
207  }
208 
209  if(source->reason && !pcmk_is_set(action->flags, pe_action_runnable)) {
210  reason = crm_strdup_printf("due to %s (blocked)", source->reason);
211 
212  } else if(source->reason) {
213  reason = crm_strdup_printf("due to %s", source->reason);
214 
215  } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
216  reason = strdup("blocked");
217 
218  }
219 
220  out->list_item(out, NULL, "%-8s %-*s ( %*s )%s%s", change, rsc_width,
221  rsc->id, detail_width, details, reason ? " " : "", reason ? reason : "");
222 
223  free(details);
224  free(reason);
225  return pcmk_rc_ok;
226 }
227 
228 PCMK__OUTPUT_ARGS("rsc-action-item", "const char *", "pe_resource_t *",
229  "pe_node_t *", "pe_node_t *", "pe_action_t *",
230  "pe_action_t *")
231 static int
232 rsc_action_item_xml(pcmk__output_t *out, va_list args)
233 {
234  const char *change = va_arg(args, const char *);
235  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
236  pe_node_t *origin = va_arg(args, pe_node_t *);
237  pe_node_t *destination = va_arg(args, pe_node_t *);
238  pe_action_t *action = va_arg(args, pe_action_t *);
239  pe_action_t *source = va_arg(args, pe_action_t *);
240 
241  char *change_str = NULL;
242 
243  bool same_host = false;
244  bool same_role = false;
245  bool need_role = false;
246  xmlNode *xml = NULL;
247 
249  CRM_ASSERT(destination != NULL || origin != NULL);
250 
251  if (source == NULL) {
252  source = action;
253  }
254 
255  if ((rsc->role > RSC_ROLE_STARTED)
256  || (rsc->next_role > RSC_ROLE_UNPROMOTED)) {
257  need_role = true;
258  }
259 
260  if(origin != NULL && destination != NULL && origin->details == destination->details) {
261  same_host = true;
262  }
263 
264  if(rsc->role == rsc->next_role) {
265  same_role = true;
266  }
267 
268  change_str = g_ascii_strdown(change, -1);
269  xml = pcmk__output_create_xml_node(out, "rsc_action",
270  "action", change_str,
271  "resource", rsc->id,
272  NULL);
273  g_free(change_str);
274 
275  if (need_role && (origin == NULL)) {
276  /* Starting and promoting a promotable clone instance */
277  pcmk__xe_set_props(xml,
278  "role", role2text(rsc->role),
279  "next-role", role2text(rsc->next_role),
280  "dest", destination->details->uname,
281  NULL);
282 
283  } else if (origin == NULL) {
284  /* Starting a resource */
285  crm_xml_add(xml, "node", destination->details->uname);
286 
287  } else if (need_role && (destination == NULL)) {
288  /* Stopping a promotable clone instance */
289  pcmk__xe_set_props(xml,
290  "role", role2text(rsc->role),
291  "node", origin->details->uname,
292  NULL);
293 
294  } else if (destination == NULL) {
295  /* Stopping a resource */
296  crm_xml_add(xml, "node", origin->details->uname);
297 
298  } else if (need_role && same_role && same_host) {
299  /* Recovering, restarting or re-promoting a promotable clone instance */
300  pcmk__xe_set_props(xml,
301  "role", role2text(rsc->role),
302  "source", origin->details->uname,
303  NULL);
304 
305  } else if (same_role && same_host) {
306  /* Recovering or Restarting a normal resource */
307  crm_xml_add(xml, "source", origin->details->uname);
308 
309  } else if (need_role && same_role) {
310  /* Moving a promotable clone instance */
311  pcmk__xe_set_props(xml,
312  "source", origin->details->uname,
313  "dest", destination->details->uname,
314  "role", role2text(rsc->role),
315  NULL);
316 
317  } else if (same_role) {
318  /* Moving a normal resource */
319  pcmk__xe_set_props(xml,
320  "source", origin->details->uname,
321  "dest", destination->details->uname,
322  NULL);
323 
324  } else if (same_host) {
325  /* Promoting or demoting a promotable clone instance */
326  pcmk__xe_set_props(xml,
327  "role", role2text(rsc->role),
328  "next-role", role2text(rsc->next_role),
329  "source", origin->details->uname,
330  NULL);
331 
332  } else {
333  /* Moving and promoting/demoting */
334  pcmk__xe_set_props(xml,
335  "role", role2text(rsc->role),
336  "source", origin->details->uname,
337  "next-role", role2text(rsc->next_role),
338  "dest", destination->details->uname,
339  NULL);
340  }
341 
342  if (source->reason && !pcmk_is_set(action->flags, pe_action_runnable)) {
343  pcmk__xe_set_props(xml,
344  "reason", source->reason,
345  "blocked", "true",
346  NULL);
347 
348  } else if(source->reason) {
349  crm_xml_add(xml, "reason", source->reason);
350 
351  } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
352  pcmk__xe_set_bool_attr(xml, "blocked", true);
353 
354  }
355 
356  return pcmk_rc_ok;
357 }
358 
359 PCMK__OUTPUT_ARGS("rsc-is-colocated-with-list", "pe_resource_t *", "bool")
360 static int
361 rsc_is_colocated_with_list(pcmk__output_t *out, va_list args) {
362  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
363  bool recursive = va_arg(args, int);
364 
365  int rc = pcmk_rc_no_output;
366 
367  if (pcmk_is_set(rsc->flags, pe_rsc_detect_loop)) {
368  return rc;
369  }
370 
371  /* We're listing constraints explicitly involving rsc, so use rsc->rsc_cons
372  * directly rather than rsc->cmds->this_with_colocations().
373  */
375  for (GList *lpc = rsc->rsc_cons; lpc != NULL; lpc = lpc->next) {
376  pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
377  char *hdr = NULL;
378 
379  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Resources %s is colocated with", rsc->id);
380 
382  out->list_item(out, NULL, "%s (id=%s - loop)",
383  cons->primary->id, cons->id);
384  continue;
385  }
386 
387  hdr = colocations_header(cons->primary, cons, false);
388  out->list_item(out, NULL, "%s", hdr);
389  free(hdr);
390 
391  /* Empty list header just for indentation of information about this resource. */
392  out->begin_list(out, NULL, NULL, NULL);
393 
394  out->message(out, "locations-list", cons->primary);
395  if (recursive) {
396  out->message(out, "rsc-is-colocated-with-list",
397  cons->primary, recursive);
398  }
399 
400  out->end_list(out);
401  }
402 
403  PCMK__OUTPUT_LIST_FOOTER(out, rc);
404  return rc;
405 }
406 
407 PCMK__OUTPUT_ARGS("rsc-is-colocated-with-list", "pe_resource_t *", "bool")
408 static int
409 rsc_is_colocated_with_list_xml(pcmk__output_t *out, va_list args) {
410  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
411  bool recursive = va_arg(args, int);
412 
413  int rc = pcmk_rc_no_output;
414 
415  if (pcmk_is_set(rsc->flags, pe_rsc_detect_loop)) {
416  return rc;
417  }
418 
419  /* We're listing constraints explicitly involving rsc, so use rsc->rsc_cons
420  * directly rather than rsc->cmds->this_with_colocations().
421  */
423  for (GList *lpc = rsc->rsc_cons; lpc != NULL; lpc = lpc->next) {
424  pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
425 
427  colocations_xml_node(out, cons->primary, cons);
428  continue;
429  }
430 
431  colocations_xml_node(out, cons->primary, cons);
432  do_locations_list_xml(out, cons->primary, false);
433 
434  if (recursive) {
435  out->message(out, "rsc-is-colocated-with-list",
436  cons->primary, recursive);
437  }
438  }
439 
440  return rc;
441 }
442 
443 PCMK__OUTPUT_ARGS("rscs-colocated-with-list", "pe_resource_t *", "bool")
444 static int
445 rscs_colocated_with_list(pcmk__output_t *out, va_list args) {
446  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
447  bool recursive = va_arg(args, int);
448 
449  int rc = pcmk_rc_no_output;
450 
451  if (pcmk_is_set(rsc->flags, pe_rsc_detect_loop)) {
452  return rc;
453  }
454 
455  /* We're listing constraints explicitly involving rsc, so use
456  * rsc->rsc_cons_lhs directly rather than
457  * rsc->cmds->with_this_colocations().
458  */
460  for (GList *lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
461  pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
462  char *hdr = NULL;
463 
464  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Resources colocated with %s", rsc->id);
465 
467  out->list_item(out, NULL, "%s (id=%s - loop)",
468  cons->dependent->id, cons->id);
469  continue;
470  }
471 
472  hdr = colocations_header(cons->dependent, cons, true);
473  out->list_item(out, NULL, "%s", hdr);
474  free(hdr);
475 
476  /* Empty list header just for indentation of information about this resource. */
477  out->begin_list(out, NULL, NULL, NULL);
478 
479  out->message(out, "locations-list", cons->dependent);
480  if (recursive) {
481  out->message(out, "rscs-colocated-with-list",
482  cons->dependent, recursive);
483  }
484 
485  out->end_list(out);
486  }
487 
488  PCMK__OUTPUT_LIST_FOOTER(out, rc);
489  return rc;
490 }
491 
492 PCMK__OUTPUT_ARGS("rscs-colocated-with-list", "pe_resource_t *", "bool")
493 static int
494 rscs_colocated_with_list_xml(pcmk__output_t *out, va_list args) {
495  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
496  bool recursive = va_arg(args, int);
497 
498  int rc = pcmk_rc_no_output;
499 
500  if (pcmk_is_set(rsc->flags, pe_rsc_detect_loop)) {
501  return rc;
502  }
503 
504  /* We're listing constraints explicitly involving rsc, so use
505  * rsc->rsc_cons_lhs directly rather than
506  * rsc->cmds->with_this_colocations().
507  */
509  for (GList *lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
510  pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
511 
513  colocations_xml_node(out, cons->dependent, cons);
514  continue;
515  }
516 
517  colocations_xml_node(out, cons->dependent, cons);
518  do_locations_list_xml(out, cons->dependent, false);
519 
520  if (recursive) {
521  out->message(out, "rscs-colocated-with-list",
522  cons->dependent, recursive);
523  }
524  }
525 
526  return rc;
527 }
528 
529 PCMK__OUTPUT_ARGS("locations-list", "pe_resource_t *")
530 static int
531 locations_list(pcmk__output_t *out, va_list args) {
532  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
533 
534  GList *lpc = NULL;
535  GList *list = rsc->rsc_location;
536  int rc = pcmk_rc_no_output;
537 
538  for (lpc = list; lpc != NULL; lpc = lpc->next) {
539  pe__location_t *cons = lpc->data;
540 
541  GList *lpc2 = NULL;
542 
543  for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) {
544  pe_node_t *node = (pe_node_t *) lpc2->data;
545 
546  PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Locations");
547  out->list_item(out, NULL, "Node %s (score=%s, id=%s, rsc=%s)",
548  pe__node_name(node),
549  pcmk_readable_score(node->weight), cons->id,
550  rsc->id);
551  }
552  }
553 
554  PCMK__OUTPUT_LIST_FOOTER(out, rc);
555  return rc;
556 }
557 
558 PCMK__OUTPUT_ARGS("locations-list", "pe_resource_t *")
559 static int
560 locations_list_xml(pcmk__output_t *out, va_list args) {
561  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
562  return do_locations_list_xml(out, rsc, true);
563 }
564 
565 PCMK__OUTPUT_ARGS("locations-and-colocations", "pe_resource_t *",
566  "pe_working_set_t *", "bool", "bool")
567 static int
568 locations_and_colocations(pcmk__output_t *out, va_list args)
569 {
570  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
571  pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
572  bool recursive = va_arg(args, int);
573  bool force = va_arg(args, int);
574 
576 
577  // Constraints apply to group/clone, not member/instance
578  if (!force) {
579  rsc = uber_parent(rsc);
580  }
581 
582  out->message(out, "locations-list", rsc);
583 
585  out->message(out, "rscs-colocated-with-list", rsc, recursive);
586 
588  out->message(out, "rsc-is-colocated-with-list", rsc, recursive);
589  return pcmk_rc_ok;
590 }
591 
592 PCMK__OUTPUT_ARGS("locations-and-colocations", "pe_resource_t *",
593  "pe_working_set_t *", "bool", "bool")
594 static int
595 locations_and_colocations_xml(pcmk__output_t *out, va_list args)
596 {
597  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
598  pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
599  bool recursive = va_arg(args, int);
600  bool force = va_arg(args, int);
601 
603 
604  // Constraints apply to group/clone, not member/instance
605  if (!force) {
606  rsc = uber_parent(rsc);
607  }
608 
609  pcmk__output_xml_create_parent(out, "constraints", NULL);
610  do_locations_list_xml(out, rsc, false);
611 
613  out->message(out, "rscs-colocated-with-list", rsc, recursive);
614 
616  out->message(out, "rsc-is-colocated-with-list", rsc, recursive);
617 
619  return pcmk_rc_ok;
620 }
621 
622 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *", "const char *")
623 static int
624 health(pcmk__output_t *out, va_list args)
625 {
626  const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
627  const char *host_from = va_arg(args, const char *);
628  const char *fsa_state = va_arg(args, const char *);
629  const char *result = va_arg(args, const char *);
630 
631  return out->info(out, "Controller on %s in state %s: %s",
632  pcmk__s(host_from, "unknown node"),
633  pcmk__s(fsa_state, "unknown"),
634  pcmk__s(result, "unknown result"));
635 }
636 
637 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *", "const char *")
638 static int
639 health_text(pcmk__output_t *out, va_list args)
640 {
641  if (!out->is_quiet(out)) {
642  return health(out, args);
643  } else {
644  const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
645  const char *host_from G_GNUC_UNUSED = va_arg(args, const char *);
646  const char *fsa_state = va_arg(args, const char *);
647  const char *result G_GNUC_UNUSED = va_arg(args, const char *);
648 
649  if (fsa_state != NULL) {
650  pcmk__formatted_printf(out, "%s\n", fsa_state);
651  return pcmk_rc_ok;
652  }
653  }
654 
655  return pcmk_rc_no_output;
656 }
657 
658 PCMK__OUTPUT_ARGS("health", "const char *", "const char *", "const char *", "const char *")
659 static int
660 health_xml(pcmk__output_t *out, va_list args)
661 {
662  const char *sys_from = va_arg(args, const char *);
663  const char *host_from = va_arg(args, const char *);
664  const char *fsa_state = va_arg(args, const char *);
665  const char *result = va_arg(args, const char *);
666 
667  pcmk__output_create_xml_node(out, pcmk__s(sys_from, ""),
668  "node_name", pcmk__s(host_from, ""),
669  "state", pcmk__s(fsa_state, ""),
670  "result", pcmk__s(result, ""),
671  NULL);
672  return pcmk_rc_ok;
673 }
674 
675 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
676  "enum pcmk_pacemakerd_state", "const char *", "time_t")
677 static int
678 pacemakerd_health(pcmk__output_t *out, va_list args)
679 {
680  const char *sys_from = va_arg(args, const char *);
681  enum pcmk_pacemakerd_state state =
682  (enum pcmk_pacemakerd_state) va_arg(args, int);
683  const char *state_s = va_arg(args, const char *);
684  time_t last_updated = va_arg(args, time_t);
685 
686  char *last_updated_s = NULL;
687  int rc = pcmk_rc_ok;
688 
689  if (sys_from == NULL) {
690  if (state == pcmk_pacemakerd_state_remote) {
691  sys_from = "pacemaker-remoted";
692  } else {
693  sys_from = CRM_SYSTEM_MCP;
694  }
695  }
696 
697  if (state_s == NULL) {
698  state_s = pcmk__pcmkd_state_enum2friendly(state);
699  }
700 
701  if (last_updated != 0) {
702  last_updated_s = pcmk__epoch2str(&last_updated,
706  }
707 
708  rc = out->info(out, "Status of %s: '%s' (last updated %s)",
709  sys_from, state_s,
710  pcmk__s(last_updated_s, "at unknown time"));
711 
712  free(last_updated_s);
713  return rc;
714 }
715 
716 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
717  "enum pcmk_pacemakerd_state", "const char *", "time_t")
718 static int
719 pacemakerd_health_html(pcmk__output_t *out, va_list args)
720 {
721  const char *sys_from = va_arg(args, const char *);
722  enum pcmk_pacemakerd_state state =
723  (enum pcmk_pacemakerd_state) va_arg(args, int);
724  const char *state_s = va_arg(args, const char *);
725  time_t last_updated = va_arg(args, time_t);
726 
727  char *last_updated_s = NULL;
728  char *msg = NULL;
729 
730  if (sys_from == NULL) {
731  if (state == pcmk_pacemakerd_state_remote) {
732  sys_from = "pacemaker-remoted";
733  } else {
734  sys_from = CRM_SYSTEM_MCP;
735  }
736  }
737 
738  if (state_s == NULL) {
739  state_s = pcmk__pcmkd_state_enum2friendly(state);
740  }
741 
742  if (last_updated != 0) {
743  last_updated_s = pcmk__epoch2str(&last_updated,
747  }
748 
749  msg = crm_strdup_printf("Status of %s: '%s' (last updated %s)",
750  sys_from, state_s,
751  pcmk__s(last_updated_s, "at unknown time"));
752  pcmk__output_create_html_node(out, "li", NULL, NULL, msg);
753 
754  free(msg);
755  free(last_updated_s);
756  return pcmk_rc_ok;
757 }
758 
759 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
760  "enum pcmk_pacemakerd_state", "const char *", "time_t")
761 static int
762 pacemakerd_health_text(pcmk__output_t *out, va_list args)
763 {
764  if (!out->is_quiet(out)) {
765  return pacemakerd_health(out, args);
766  } else {
767  const char *sys_from G_GNUC_UNUSED = va_arg(args, const char *);
768  enum pcmk_pacemakerd_state state =
769  (enum pcmk_pacemakerd_state) va_arg(args, int);
770  const char *state_s = va_arg(args, const char *);
771  time_t last_updated G_GNUC_UNUSED = va_arg(args, time_t);
772 
773  if (state_s == NULL) {
775  }
776  pcmk__formatted_printf(out, "%s\n", state_s);
777  return pcmk_rc_ok;
778  }
779 }
780 
781 PCMK__OUTPUT_ARGS("pacemakerd-health", "const char *",
782  "enum pcmk_pacemakerd_state", "const char *", "time_t")
783 static int
784 pacemakerd_health_xml(pcmk__output_t *out, va_list args)
785 {
786  const char *sys_from = va_arg(args, const char *);
787  enum pcmk_pacemakerd_state state =
788  (enum pcmk_pacemakerd_state) va_arg(args, int);
789  const char *state_s = va_arg(args, const char *);
790  time_t last_updated = va_arg(args, time_t);
791 
792  char *last_updated_s = NULL;
793 
794  if (sys_from == NULL) {
795  if (state == pcmk_pacemakerd_state_remote) {
796  sys_from = "pacemaker-remoted";
797  } else {
798  sys_from = CRM_SYSTEM_MCP;
799  }
800  }
801 
802  if (state_s == NULL) {
804  }
805 
806  if (last_updated != 0) {
807  last_updated_s = pcmk__epoch2str(&last_updated,
811  }
812 
813  pcmk__output_create_xml_node(out, "pacemakerd",
814  "sys_from", sys_from,
815  "state", state_s,
816  "last_updated", last_updated_s,
817  NULL);
818  free(last_updated_s);
819  return pcmk_rc_ok;
820 }
821 
822 PCMK__OUTPUT_ARGS("profile", "const char *", "clock_t", "clock_t")
823 static int
824 profile_default(pcmk__output_t *out, va_list args) {
825  const char *xml_file = va_arg(args, const char *);
826  clock_t start = va_arg(args, clock_t);
827  clock_t end = va_arg(args, clock_t);
828 
829  out->list_item(out, NULL, "Testing %s ... %.2f secs", xml_file,
830  (end - start) / (float) CLOCKS_PER_SEC);
831 
832  return pcmk_rc_ok;
833 }
834 
835 PCMK__OUTPUT_ARGS("profile", "const char *", "clock_t", "clock_t")
836 static int
837 profile_xml(pcmk__output_t *out, va_list args) {
838  const char *xml_file = va_arg(args, const char *);
839  clock_t start = va_arg(args, clock_t);
840  clock_t end = va_arg(args, clock_t);
841 
842  char *duration = pcmk__ftoa((end - start) / (float) CLOCKS_PER_SEC);
843 
844  pcmk__output_create_xml_node(out, "timing",
845  "file", xml_file,
846  "duration", duration,
847  NULL);
848 
849  free(duration);
850  return pcmk_rc_ok;
851 }
852 
853 PCMK__OUTPUT_ARGS("dc", "const char *")
854 static int
855 dc(pcmk__output_t *out, va_list args)
856 {
857  const char *dc = va_arg(args, const char *);
858 
859  return out->info(out, "Designated Controller is: %s",
860  pcmk__s(dc, "not yet elected"));
861 }
862 
863 PCMK__OUTPUT_ARGS("dc", "const char *")
864 static int
865 dc_text(pcmk__output_t *out, va_list args)
866 {
867  if (!out->is_quiet(out)) {
868  return dc(out, args);
869  } else {
870  const char *dc = va_arg(args, const char *);
871 
872  if (dc != NULL) {
873  pcmk__formatted_printf(out, "%s\n", pcmk__s(dc, ""));
874  return pcmk_rc_ok;
875  }
876  }
877 
878  return pcmk_rc_no_output;
879 }
880 
881 PCMK__OUTPUT_ARGS("dc", "const char *")
882 static int
883 dc_xml(pcmk__output_t *out, va_list args)
884 {
885  const char *dc = va_arg(args, const char *);
886 
888  "node_name", pcmk__s(dc, ""),
889  NULL);
890  return pcmk_rc_ok;
891 }
892 
893 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *", "const char *", "bool")
894 static int
895 crmadmin_node(pcmk__output_t *out, va_list args)
896 {
897  const char *type = va_arg(args, const char *);
898  const char *name = va_arg(args, const char *);
899  const char *id = va_arg(args, const char *);
900  bool bash_export = va_arg(args, int);
901 
902  if (bash_export) {
903  return out->info(out, "export %s=%s",
904  pcmk__s(name, "<null>"), pcmk__s(id, ""));
905  } else {
906  return out->info(out, "%s node: %s (%s)", type ? type : "cluster",
907  pcmk__s(name, "<null>"), pcmk__s(id, "<null>"));
908  }
909 }
910 
911 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *", "const char *", "bool")
912 static int
913 crmadmin_node_text(pcmk__output_t *out, va_list args)
914 {
915  if (!out->is_quiet(out)) {
916  return crmadmin_node(out, args);
917  } else {
918  const char *type G_GNUC_UNUSED = va_arg(args, const char *);
919  const char *name = va_arg(args, const char *);
920  const char *id G_GNUC_UNUSED = va_arg(args, const char *);
921  bool bash_export G_GNUC_UNUSED = va_arg(args, int);
922 
923  pcmk__formatted_printf(out, "%s\n", pcmk__s(name, "<null>"));
924  return pcmk_rc_ok;
925  }
926 }
927 
928 PCMK__OUTPUT_ARGS("crmadmin-node", "const char *", "const char *", "const char *", "bool")
929 static int
930 crmadmin_node_xml(pcmk__output_t *out, va_list args)
931 {
932  const char *type = va_arg(args, const char *);
933  const char *name = va_arg(args, const char *);
934  const char *id = va_arg(args, const char *);
935  bool bash_export G_GNUC_UNUSED = va_arg(args, int);
936 
937  pcmk__output_create_xml_node(out, "node",
938  "type", type ? type : "cluster",
939  "name", pcmk__s(name, ""),
940  "id", pcmk__s(id, ""),
941  NULL);
942  return pcmk_rc_ok;
943 }
944 
945 PCMK__OUTPUT_ARGS("digests", "const pe_resource_t *", "const pe_node_t *",
946  "const char *", "guint", "const op_digest_cache_t *")
947 static int
948 digests_text(pcmk__output_t *out, va_list args)
949 {
950  const pe_resource_t *rsc = va_arg(args, const pe_resource_t *);
951  const pe_node_t *node = va_arg(args, const pe_node_t *);
952  const char *task = va_arg(args, const char *);
953  guint interval_ms = va_arg(args, guint);
954  const op_digest_cache_t *digests = va_arg(args, const op_digest_cache_t *);
955 
956  char *action_desc = NULL;
957  const char *rsc_desc = "unknown resource";
958  const char *node_desc = "unknown node";
959 
960  if (interval_ms != 0) {
961  action_desc = crm_strdup_printf("%ums-interval %s action", interval_ms,
962  ((task == NULL)? "unknown" : task));
963  } else if (pcmk__str_eq(task, "monitor", pcmk__str_none)) {
964  action_desc = strdup("probe action");
965  } else {
966  action_desc = crm_strdup_printf("%s action",
967  ((task == NULL)? "unknown" : task));
968  }
969  if ((rsc != NULL) && (rsc->id != NULL)) {
970  rsc_desc = rsc->id;
971  }
972  if ((node != NULL) && (node->details->uname != NULL)) {
973  node_desc = node->details->uname;
974  }
975  out->begin_list(out, NULL, NULL, "Digests for %s %s on %s",
976  rsc_desc, action_desc, node_desc);
977  free(action_desc);
978 
979  if (digests == NULL) {
980  out->list_item(out, NULL, "none");
981  out->end_list(out);
982  return pcmk_rc_ok;
983  }
984  if (digests->digest_all_calc != NULL) {
985  out->list_item(out, NULL, "%s (all parameters)",
986  digests->digest_all_calc);
987  }
988  if (digests->digest_secure_calc != NULL) {
989  out->list_item(out, NULL, "%s (non-private parameters)",
990  digests->digest_secure_calc);
991  }
992  if (digests->digest_restart_calc != NULL) {
993  out->list_item(out, NULL, "%s (non-reloadable parameters)",
994  digests->digest_restart_calc);
995  }
996  out->end_list(out);
997  return pcmk_rc_ok;
998 }
999 
1000 static void
1001 add_digest_xml(xmlNode *parent, const char *type, const char *digest,
1002  xmlNode *digest_source)
1003 {
1004  if (digest != NULL) {
1005  xmlNodePtr digest_xml = create_xml_node(parent, "digest");
1006 
1007  crm_xml_add(digest_xml, "type", ((type == NULL)? "unspecified" : type));
1008  crm_xml_add(digest_xml, "hash", digest);
1009  if (digest_source != NULL) {
1010  add_node_copy(digest_xml, digest_source);
1011  }
1012  }
1013 }
1014 
1015 PCMK__OUTPUT_ARGS("digests", "const pe_resource_t *", "const pe_node_t *",
1016  "const char *", "guint", "const op_digest_cache_t *")
1017 static int
1018 digests_xml(pcmk__output_t *out, va_list args)
1019 {
1020  const pe_resource_t *rsc = va_arg(args, const pe_resource_t *);
1021  const pe_node_t *node = va_arg(args, const pe_node_t *);
1022  const char *task = va_arg(args, const char *);
1023  guint interval_ms = va_arg(args, guint);
1024  const op_digest_cache_t *digests = va_arg(args, const op_digest_cache_t *);
1025 
1026  char *interval_s = crm_strdup_printf("%ums", interval_ms);
1027  xmlNode *xml = NULL;
1028 
1029  xml = pcmk__output_create_xml_node(out, "digests",
1030  "resource", pcmk__s(rsc->id, ""),
1031  "node", pcmk__s(node->details->uname, ""),
1032  "task", pcmk__s(task, ""),
1033  "interval", interval_s,
1034  NULL);
1035  free(interval_s);
1036  if (digests != NULL) {
1037  add_digest_xml(xml, "all", digests->digest_all_calc,
1038  digests->params_all);
1039  add_digest_xml(xml, "nonprivate", digests->digest_secure_calc,
1040  digests->params_secure);
1041  add_digest_xml(xml, "nonreloadable", digests->digest_restart_calc,
1042  digests->params_restart);
1043  }
1044  return pcmk_rc_ok;
1045 }
1046 
1047 #define STOP_SANITY_ASSERT(lineno) do { \
1048  if(current && current->details->unclean) { \
1049  /* It will be a pseudo op */ \
1050  } else if(stop == NULL) { \
1051  crm_err("%s:%d: No stop action exists for %s", \
1052  __func__, lineno, rsc->id); \
1053  CRM_ASSERT(stop != NULL); \
1054  } else if (pcmk_is_set(stop->flags, pe_action_optional)) { \
1055  crm_err("%s:%d: Action %s is still optional", \
1056  __func__, lineno, stop->uuid); \
1057  CRM_ASSERT(!pcmk_is_set(stop->flags, pe_action_optional)); \
1058  } \
1059  } while(0)
1060 
1061 PCMK__OUTPUT_ARGS("rsc-action", "pe_resource_t *", "pe_node_t *", "pe_node_t *")
1062 static int
1063 rsc_action_default(pcmk__output_t *out, va_list args)
1064 {
1065  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
1066  pe_node_t *current = va_arg(args, pe_node_t *);
1067  pe_node_t *next = va_arg(args, pe_node_t *);
1068 
1069  GList *possible_matches = NULL;
1070  char *key = NULL;
1071  int rc = pcmk_rc_no_output;
1072  bool moving = false;
1073 
1074  pe_node_t *start_node = NULL;
1075  pe_action_t *start = NULL;
1076  pe_action_t *stop = NULL;
1077  pe_action_t *promote = NULL;
1078  pe_action_t *demote = NULL;
1079 
1080  if (!pcmk_is_set(rsc->flags, pe_rsc_managed)
1081  || (current == NULL && next == NULL)) {
1082  pe_rsc_info(rsc, "Leave %s\t(%s%s)",
1083  rsc->id, role2text(rsc->role),
1084  !pcmk_is_set(rsc->flags, pe_rsc_managed)? " unmanaged" : "");
1085  return rc;
1086  }
1087 
1088  moving = (current != NULL) && (next != NULL)
1089  && (current->details != next->details);
1090 
1091  possible_matches = pe__resource_actions(rsc, next, RSC_START, false);
1092  if (possible_matches) {
1093  start = possible_matches->data;
1094  g_list_free(possible_matches);
1095  }
1096 
1097  if ((start == NULL) || !pcmk_is_set(start->flags, pe_action_runnable)) {
1098  start_node = NULL;
1099  } else {
1100  start_node = current;
1101  }
1102  possible_matches = pe__resource_actions(rsc, start_node, RSC_STOP, false);
1103  if (possible_matches) {
1104  stop = possible_matches->data;
1105  g_list_free(possible_matches);
1106  } else if (pcmk_is_set(rsc->flags, pe_rsc_stop_unexpected)) {
1107  /* The resource is multiply active with multiple-active set to
1108  * stop_unexpected, and not stopping on its current node, but it should
1109  * be stopping elsewhere.
1110  */
1111  possible_matches = pe__resource_actions(rsc, NULL, RSC_STOP, false);
1112  if (possible_matches != NULL) {
1113  stop = possible_matches->data;
1114  g_list_free(possible_matches);
1115  }
1116  }
1117 
1118  possible_matches = pe__resource_actions(rsc, next, RSC_PROMOTE, false);
1119  if (possible_matches) {
1120  promote = possible_matches->data;
1121  g_list_free(possible_matches);
1122  }
1123 
1124  possible_matches = pe__resource_actions(rsc, next, RSC_DEMOTE, false);
1125  if (possible_matches) {
1126  demote = possible_matches->data;
1127  g_list_free(possible_matches);
1128  }
1129 
1130  if (rsc->role == rsc->next_role) {
1131  pe_action_t *migrate_op = NULL;
1132 
1133  CRM_CHECK(next != NULL, return rc);
1134 
1135  possible_matches = pe__resource_actions(rsc, next, RSC_MIGRATED, false);
1136  if (possible_matches) {
1137  migrate_op = possible_matches->data;
1138  }
1139 
1140  if ((migrate_op != NULL) && (current != NULL)
1141  && pcmk_is_set(migrate_op->flags, pe_action_runnable)) {
1142  rc = out->message(out, "rsc-action-item", "Migrate", rsc, current,
1143  next, start, NULL);
1144 
1145  } else if (pcmk_is_set(rsc->flags, pe_rsc_reload)) {
1146  rc = out->message(out, "rsc-action-item", "Reload", rsc, current,
1147  next, start, NULL);
1148 
1149  } else if (start == NULL || pcmk_is_set(start->flags, pe_action_optional)) {
1150  if ((demote != NULL) && (promote != NULL)
1151  && !pcmk_is_set(demote->flags, pe_action_optional)
1152  && !pcmk_is_set(promote->flags, pe_action_optional)) {
1153  rc = out->message(out, "rsc-action-item", "Re-promote", rsc,
1154  current, next, promote, demote);
1155  } else {
1156  pe_rsc_info(rsc, "Leave %s\t(%s %s)", rsc->id,
1157  role2text(rsc->role), pe__node_name(next));
1158  }
1159 
1160  } else if (!pcmk_is_set(start->flags, pe_action_runnable)) {
1161  rc = out->message(out, "rsc-action-item", "Stop", rsc, current,
1162  NULL, stop, (stop && stop->reason)? stop : start);
1163  STOP_SANITY_ASSERT(__LINE__);
1164 
1165  } else if (moving && current) {
1166  rc = out->message(out, "rsc-action-item", pcmk_is_set(rsc->flags, pe_rsc_failed)? "Recover" : "Move",
1167  rsc, current, next, stop, NULL);
1168 
1169  } else if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
1170  rc = out->message(out, "rsc-action-item", "Recover", rsc, current,
1171  NULL, stop, NULL);
1172  STOP_SANITY_ASSERT(__LINE__);
1173 
1174  } else {
1175  rc = out->message(out, "rsc-action-item", "Restart", rsc, current,
1176  next, start, NULL);
1177  /* STOP_SANITY_ASSERT(__LINE__); False positive for migrate-fail-7 */
1178  }
1179 
1180  g_list_free(possible_matches);
1181  return rc;
1182  }
1183 
1184  if(stop
1185  && (rsc->next_role == RSC_ROLE_STOPPED
1186  || (start && !pcmk_is_set(start->flags, pe_action_runnable)))) {
1187 
1188  GList *gIter = NULL;
1189 
1190  key = stop_key(rsc);
1191  for (gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) {
1192  pe_node_t *node = (pe_node_t *) gIter->data;
1193  pe_action_t *stop_op = NULL;
1194 
1195  possible_matches = find_actions(rsc->actions, key, node);
1196  if (possible_matches) {
1197  stop_op = possible_matches->data;
1198  g_list_free(possible_matches);
1199  }
1200 
1201  if (stop_op && (stop_op->flags & pe_action_runnable)) {
1202  STOP_SANITY_ASSERT(__LINE__);
1203  }
1204 
1205  if (out->message(out, "rsc-action-item", "Stop", rsc, node, NULL,
1206  stop_op, (stop_op && stop_op->reason)? stop_op : start) == pcmk_rc_ok) {
1207  rc = pcmk_rc_ok;
1208  }
1209  }
1210 
1211  free(key);
1212 
1213  } else if ((stop != NULL)
1214  && pcmk_all_flags_set(rsc->flags, pe_rsc_failed|pe_rsc_stop)) {
1215  /* 'stop' may be NULL if the failure was ignored */
1216  rc = out->message(out, "rsc-action-item", "Recover", rsc, current,
1217  next, stop, start);
1218  STOP_SANITY_ASSERT(__LINE__);
1219 
1220  } else if (moving) {
1221  rc = out->message(out, "rsc-action-item", "Move", rsc, current, next,
1222  stop, NULL);
1223  STOP_SANITY_ASSERT(__LINE__);
1224 
1225  } else if (pcmk_is_set(rsc->flags, pe_rsc_reload)) {
1226  rc = out->message(out, "rsc-action-item", "Reload", rsc, current, next,
1227  start, NULL);
1228 
1229  } else if (stop != NULL && !pcmk_is_set(stop->flags, pe_action_optional)) {
1230  rc = out->message(out, "rsc-action-item", "Restart", rsc, current,
1231  next, start, NULL);
1232  STOP_SANITY_ASSERT(__LINE__);
1233 
1234  } else if (rsc->role == RSC_ROLE_PROMOTED) {
1235  CRM_LOG_ASSERT(current != NULL);
1236  rc = out->message(out, "rsc-action-item", "Demote", rsc, current,
1237  next, demote, NULL);
1238 
1239  } else if (rsc->next_role == RSC_ROLE_PROMOTED) {
1240  CRM_LOG_ASSERT(next);
1241  rc = out->message(out, "rsc-action-item", "Promote", rsc, current,
1242  next, promote, NULL);
1243 
1244  } else if (rsc->role == RSC_ROLE_STOPPED && rsc->next_role > RSC_ROLE_STOPPED) {
1245  rc = out->message(out, "rsc-action-item", "Start", rsc, current, next,
1246  start, NULL);
1247  }
1248 
1249  return rc;
1250 }
1251 
1252 PCMK__OUTPUT_ARGS("node-action", "const char *", "const char *", "const char *")
1253 static int
1254 node_action(pcmk__output_t *out, va_list args)
1255 {
1256  const char *task = va_arg(args, const char *);
1257  const char *node_name = va_arg(args, const char *);
1258  const char *reason = va_arg(args, const char *);
1259 
1260  if (task == NULL) {
1261  return pcmk_rc_no_output;
1262  } else if (reason) {
1263  out->list_item(out, NULL, "%s %s '%s'", task, node_name, reason);
1264  } else {
1265  crm_notice(" * %s %s", task, node_name);
1266  }
1267 
1268  return pcmk_rc_ok;
1269 }
1270 
1271 PCMK__OUTPUT_ARGS("node-action", "const char *", "const char *", "const char *")
1272 static int
1273 node_action_xml(pcmk__output_t *out, va_list args)
1274 {
1275  const char *task = va_arg(args, const char *);
1276  const char *node_name = va_arg(args, const char *);
1277  const char *reason = va_arg(args, const char *);
1278 
1279  if (task == NULL) {
1280  return pcmk_rc_no_output;
1281  } else if (reason) {
1282  pcmk__output_create_xml_node(out, "node_action",
1283  "task", task,
1284  "node", node_name,
1285  "reason", reason,
1286  NULL);
1287  } else {
1288  crm_notice(" * %s %s", task, node_name);
1289  }
1290 
1291  return pcmk_rc_ok;
1292 }
1293 
1294 PCMK__OUTPUT_ARGS("node-info", "int", "const char *", "const char *",
1295  "const char *", "bool", "bool")
1296 static int
1297 node_info_default(pcmk__output_t *out, va_list args)
1298 {
1299  int node_id = va_arg(args, int);
1300  const char *node_name = va_arg(args, const char *);
1301  const char *uuid = va_arg(args, const char *);
1302  const char *state = va_arg(args, const char *);
1303  bool have_quorum = (bool) va_arg(args, int);
1304  bool is_remote = (bool) va_arg(args, int);
1305 
1306  return out->info(out,
1307  "Node %d: %s "
1308  "(uuid=%s, state=%s, have_quorum=%s, is_remote=%s)",
1309  node_id, pcmk__s(node_name, "unknown"),
1310  pcmk__s(uuid, "unknown"), pcmk__s(state, "unknown"),
1311  pcmk__btoa(have_quorum), pcmk__btoa(is_remote));
1312 }
1313 
1314 PCMK__OUTPUT_ARGS("node-info", "int", "const char *", "const char *",
1315  "const char *", "bool", "bool")
1316 static int
1317 node_info_xml(pcmk__output_t *out, va_list args)
1318 {
1319  int node_id = va_arg(args, int);
1320  const char *node_name = va_arg(args, const char *);
1321  const char *uuid = va_arg(args, const char *);
1322  const char *state = va_arg(args, const char *);
1323  bool have_quorum = (bool) va_arg(args, int);
1324  bool is_remote = (bool) va_arg(args, int);
1325 
1326  char *id_s = crm_strdup_printf("%d", node_id);
1327 
1328  pcmk__output_create_xml_node(out, "node-info",
1329  "nodeid", id_s,
1330  XML_ATTR_UNAME, node_name,
1331  XML_ATTR_ID, uuid,
1332  XML_NODE_IS_PEER, state,
1333  XML_ATTR_HAVE_QUORUM, pcmk__btoa(have_quorum),
1334  XML_NODE_IS_REMOTE, pcmk__btoa(is_remote),
1335  NULL);
1336  free(id_s);
1337  return pcmk_rc_ok;
1338 }
1339 
1340 PCMK__OUTPUT_ARGS("inject-cluster-action", "const char *", "const char *", "xmlNodePtr")
1341 static int
1342 inject_cluster_action(pcmk__output_t *out, va_list args)
1343 {
1344  const char *node = va_arg(args, const char *);
1345  const char *task = va_arg(args, const char *);
1346  xmlNodePtr rsc = va_arg(args, xmlNodePtr);
1347 
1348  if (out->is_quiet(out)) {
1349  return pcmk_rc_no_output;
1350  }
1351 
1352  if(rsc) {
1353  out->list_item(out, NULL, "Cluster action: %s for %s on %s", task, ID(rsc), node);
1354  } else {
1355  out->list_item(out, NULL, "Cluster action: %s on %s", task, node);
1356  }
1357 
1358  return pcmk_rc_ok;
1359 }
1360 
1361 PCMK__OUTPUT_ARGS("inject-cluster-action", "const char *", "const char *", "xmlNodePtr")
1362 static int
1363 inject_cluster_action_xml(pcmk__output_t *out, va_list args)
1364 {
1365  const char *node = va_arg(args, const char *);
1366  const char *task = va_arg(args, const char *);
1367  xmlNodePtr rsc = va_arg(args, xmlNodePtr);
1368 
1369  xmlNodePtr xml_node = NULL;
1370 
1371  if (out->is_quiet(out)) {
1372  return pcmk_rc_no_output;
1373  }
1374 
1375  xml_node = pcmk__output_create_xml_node(out, "cluster_action",
1376  "task", task,
1377  "node", node,
1378  NULL);
1379 
1380  if (rsc) {
1381  crm_xml_add(xml_node, "id", ID(rsc));
1382  }
1383 
1384  return pcmk_rc_ok;
1385 }
1386 
1387 PCMK__OUTPUT_ARGS("inject-fencing-action", "const char *", "const char *")
1388 static int
1389 inject_fencing_action(pcmk__output_t *out, va_list args)
1390 {
1391  const char *target = va_arg(args, const char *);
1392  const char *op = va_arg(args, const char *);
1393 
1394  if (out->is_quiet(out)) {
1395  return pcmk_rc_no_output;
1396  }
1397 
1398  out->list_item(out, NULL, "Fencing %s (%s)", target, op);
1399  return pcmk_rc_ok;
1400 }
1401 
1402 PCMK__OUTPUT_ARGS("inject-fencing-action", "const char *", "const char *")
1403 static int
1404 inject_fencing_action_xml(pcmk__output_t *out, va_list args)
1405 {
1406  const char *target = va_arg(args, const char *);
1407  const char *op = va_arg(args, const char *);
1408 
1409  if (out->is_quiet(out)) {
1410  return pcmk_rc_no_output;
1411  }
1412 
1413  pcmk__output_create_xml_node(out, "fencing_action",
1414  "target", target,
1415  "op", op,
1416  NULL);
1417  return pcmk_rc_ok;
1418 }
1419 
1420 PCMK__OUTPUT_ARGS("inject-attr", "const char *", "const char *", "xmlNodePtr")
1421 static int
1422 inject_attr(pcmk__output_t *out, va_list args)
1423 {
1424  const char *name = va_arg(args, const char *);
1425  const char *value = va_arg(args, const char *);
1426  xmlNodePtr cib_node = va_arg(args, xmlNodePtr);
1427 
1428  xmlChar *node_path = NULL;
1429 
1430  if (out->is_quiet(out)) {
1431  return pcmk_rc_no_output;
1432  }
1433 
1434  node_path = xmlGetNodePath(cib_node);
1435 
1436  out->list_item(out, NULL, "Injecting attribute %s=%s into %s '%s'",
1437  name, value, node_path, ID(cib_node));
1438 
1439  free(node_path);
1440  return pcmk_rc_ok;
1441 }
1442 
1443 PCMK__OUTPUT_ARGS("inject-attr", "const char *", "const char *", "xmlNodePtr")
1444 static int
1445 inject_attr_xml(pcmk__output_t *out, va_list args)
1446 {
1447  const char *name = va_arg(args, const char *);
1448  const char *value = va_arg(args, const char *);
1449  xmlNodePtr cib_node = va_arg(args, xmlNodePtr);
1450 
1451  xmlChar *node_path = NULL;
1452 
1453  if (out->is_quiet(out)) {
1454  return pcmk_rc_no_output;
1455  }
1456 
1457  node_path = xmlGetNodePath(cib_node);
1458 
1459  pcmk__output_create_xml_node(out, "inject_attr",
1460  "name", name,
1461  "value", value,
1462  "node_path", node_path,
1463  "cib_node", ID(cib_node),
1464  NULL);
1465  free(node_path);
1466  return pcmk_rc_ok;
1467 }
1468 
1469 PCMK__OUTPUT_ARGS("inject-spec", "const char *")
1470 static int
1471 inject_spec(pcmk__output_t *out, va_list args)
1472 {
1473  const char *spec = va_arg(args, const char *);
1474 
1475  if (out->is_quiet(out)) {
1476  return pcmk_rc_no_output;
1477  }
1478 
1479  out->list_item(out, NULL, "Injecting %s into the configuration", spec);
1480  return pcmk_rc_ok;
1481 }
1482 
1483 PCMK__OUTPUT_ARGS("inject-spec", "const char *")
1484 static int
1485 inject_spec_xml(pcmk__output_t *out, va_list args)
1486 {
1487  const char *spec = va_arg(args, const char *);
1488 
1489  if (out->is_quiet(out)) {
1490  return pcmk_rc_no_output;
1491  }
1492 
1493  pcmk__output_create_xml_node(out, "inject_spec",
1494  "spec", spec,
1495  NULL);
1496  return pcmk_rc_ok;
1497 }
1498 
1499 PCMK__OUTPUT_ARGS("inject-modify-config", "const char *", "const char *")
1500 static int
1501 inject_modify_config(pcmk__output_t *out, va_list args)
1502 {
1503  const char *quorum = va_arg(args, const char *);
1504  const char *watchdog = va_arg(args, const char *);
1505 
1506  if (out->is_quiet(out)) {
1507  return pcmk_rc_no_output;
1508  }
1509 
1510  out->begin_list(out, NULL, NULL, "Performing Requested Modifications");
1511 
1512  if (quorum) {
1513  out->list_item(out, NULL, "Setting quorum: %s", quorum);
1514  }
1515 
1516  if (watchdog) {
1517  out->list_item(out, NULL, "Setting watchdog: %s", watchdog);
1518  }
1519 
1520  return pcmk_rc_ok;
1521 }
1522 
1523 PCMK__OUTPUT_ARGS("inject-modify-config", "const char *", "const char *")
1524 static int
1525 inject_modify_config_xml(pcmk__output_t *out, va_list args)
1526 {
1527  const char *quorum = va_arg(args, const char *);
1528  const char *watchdog = va_arg(args, const char *);
1529 
1530  xmlNodePtr node = NULL;
1531 
1532  if (out->is_quiet(out)) {
1533  return pcmk_rc_no_output;
1534  }
1535 
1536  node = pcmk__output_xml_create_parent(out, "modifications", NULL);
1537 
1538  if (quorum) {
1539  crm_xml_add(node, "quorum", quorum);
1540  }
1541 
1542  if (watchdog) {
1543  crm_xml_add(node, "watchdog", watchdog);
1544  }
1545 
1546  return pcmk_rc_ok;
1547 }
1548 
1549 PCMK__OUTPUT_ARGS("inject-modify-node", "const char *", "const char *")
1550 static int
1551 inject_modify_node(pcmk__output_t *out, va_list args)
1552 {
1553  const char *action = va_arg(args, const char *);
1554  const char *node = va_arg(args, const char *);
1555 
1556  if (out->is_quiet(out)) {
1557  return pcmk_rc_no_output;
1558  }
1559 
1560  if (pcmk__str_eq(action, "Online", pcmk__str_none)) {
1561  out->list_item(out, NULL, "Bringing node %s online", node);
1562  return pcmk_rc_ok;
1563  } else if (pcmk__str_eq(action, "Offline", pcmk__str_none)) {
1564  out->list_item(out, NULL, "Taking node %s offline", node);
1565  return pcmk_rc_ok;
1566  } else if (pcmk__str_eq(action, "Failing", pcmk__str_none)) {
1567  out->list_item(out, NULL, "Failing node %s", node);
1568  return pcmk_rc_ok;
1569  }
1570 
1571  return pcmk_rc_no_output;
1572 }
1573 
1574 PCMK__OUTPUT_ARGS("inject-modify-node", "const char *", "const char *")
1575 static int
1576 inject_modify_node_xml(pcmk__output_t *out, va_list args)
1577 {
1578  const char *action = va_arg(args, const char *);
1579  const char *node = va_arg(args, const char *);
1580 
1581  if (out->is_quiet(out)) {
1582  return pcmk_rc_no_output;
1583  }
1584 
1585  pcmk__output_create_xml_node(out, "modify_node",
1586  "action", action,
1587  "node", node,
1588  NULL);
1589  return pcmk_rc_ok;
1590 }
1591 
1592 PCMK__OUTPUT_ARGS("inject-modify-ticket", "const char *", "const char *")
1593 static int
1594 inject_modify_ticket(pcmk__output_t *out, va_list args)
1595 {
1596  const char *action = va_arg(args, const char *);
1597  const char *ticket = va_arg(args, const char *);
1598 
1599  if (out->is_quiet(out)) {
1600  return pcmk_rc_no_output;
1601  }
1602 
1603  if (pcmk__str_eq(action, "Standby", pcmk__str_none)) {
1604  out->list_item(out, NULL, "Making ticket %s standby", ticket);
1605  } else {
1606  out->list_item(out, NULL, "%s ticket %s", action, ticket);
1607  }
1608 
1609  return pcmk_rc_ok;
1610 }
1611 
1612 PCMK__OUTPUT_ARGS("inject-modify-ticket", "const char *", "const char *")
1613 static int
1614 inject_modify_ticket_xml(pcmk__output_t *out, va_list args)
1615 {
1616  const char *action = va_arg(args, const char *);
1617  const char *ticket = va_arg(args, const char *);
1618 
1619  if (out->is_quiet(out)) {
1620  return pcmk_rc_no_output;
1621  }
1622 
1623  pcmk__output_create_xml_node(out, "modify_ticket",
1624  "action", action,
1625  "ticket", ticket,
1626  NULL);
1627  return pcmk_rc_ok;
1628 }
1629 
1630 PCMK__OUTPUT_ARGS("inject-pseudo-action", "const char *", "const char *")
1631 static int
1632 inject_pseudo_action(pcmk__output_t *out, va_list args)
1633 {
1634  const char *node = va_arg(args, const char *);
1635  const char *task = va_arg(args, const char *);
1636 
1637  if (out->is_quiet(out)) {
1638  return pcmk_rc_no_output;
1639  }
1640 
1641  out->list_item(out, NULL, "Pseudo action: %s%s%s", task, node ? " on " : "",
1642  node ? node : "");
1643  return pcmk_rc_ok;
1644 }
1645 
1646 PCMK__OUTPUT_ARGS("inject-pseudo-action", "const char *", "const char *")
1647 static int
1648 inject_pseudo_action_xml(pcmk__output_t *out, va_list args)
1649 {
1650  const char *node = va_arg(args, const char *);
1651  const char *task = va_arg(args, const char *);
1652 
1653  xmlNodePtr xml_node = NULL;
1654 
1655  if (out->is_quiet(out)) {
1656  return pcmk_rc_no_output;
1657  }
1658 
1659  xml_node = pcmk__output_create_xml_node(out, "pseudo_action",
1660  "task", task,
1661  NULL);
1662  if (node) {
1663  crm_xml_add(xml_node, "node", node);
1664  }
1665 
1666  return pcmk_rc_ok;
1667 }
1668 
1669 PCMK__OUTPUT_ARGS("inject-rsc-action", "const char *", "const char *",
1670  "const char *", "guint")
1671 static int
1672 inject_rsc_action(pcmk__output_t *out, va_list args)
1673 {
1674  const char *rsc = va_arg(args, const char *);
1675  const char *operation = va_arg(args, const char *);
1676  const char *node = va_arg(args, const char *);
1677  guint interval_ms = va_arg(args, guint);
1678 
1679  if (out->is_quiet(out)) {
1680  return pcmk_rc_no_output;
1681  }
1682 
1683  if (interval_ms) {
1684  out->list_item(out, NULL, "Resource action: %-15s %s=%u on %s",
1685  rsc, operation, interval_ms, node);
1686  } else {
1687  out->list_item(out, NULL, "Resource action: %-15s %s on %s",
1688  rsc, operation, node);
1689  }
1690 
1691  return pcmk_rc_ok;
1692 }
1693 
1694 PCMK__OUTPUT_ARGS("inject-rsc-action", "const char *", "const char *",
1695  "const char *", "guint")
1696 static int
1697 inject_rsc_action_xml(pcmk__output_t *out, va_list args)
1698 {
1699  const char *rsc = va_arg(args, const char *);
1700  const char *operation = va_arg(args, const char *);
1701  const char *node = va_arg(args, const char *);
1702  guint interval_ms = va_arg(args, guint);
1703 
1704  xmlNodePtr xml_node = NULL;
1705 
1706  if (out->is_quiet(out)) {
1707  return pcmk_rc_no_output;
1708  }
1709 
1710  xml_node = pcmk__output_create_xml_node(out, "rsc_action",
1711  "resource", rsc,
1712  "op", operation,
1713  "node", node,
1714  NULL);
1715 
1716  if (interval_ms) {
1717  char *interval_s = pcmk__itoa(interval_ms);
1718 
1719  crm_xml_add(xml_node, "interval", interval_s);
1720  free(interval_s);
1721  }
1722 
1723  return pcmk_rc_ok;
1724 }
1725 
1726 #define CHECK_RC(retcode, retval) \
1727  if (retval == pcmk_rc_ok) { \
1728  retcode = pcmk_rc_ok; \
1729  }
1730 
1731 PCMK__OUTPUT_ARGS("cluster-status", "pe_working_set_t *",
1732  "enum pcmk_pacemakerd_state", "crm_exit_t",
1733  "stonith_history_t *", "enum pcmk__fence_history", "uint32_t",
1734  "uint32_t", "const char *", "GList *", "GList *")
1735 int
1736 pcmk__cluster_status_text(pcmk__output_t *out, va_list args)
1737 {
1738  pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1739  enum pcmk_pacemakerd_state pcmkd_state =
1740  (enum pcmk_pacemakerd_state) va_arg(args, int);
1741  crm_exit_t history_rc = va_arg(args, crm_exit_t);
1742  stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
1743  enum pcmk__fence_history fence_history = va_arg(args, int);
1744  uint32_t section_opts = va_arg(args, uint32_t);
1745  uint32_t show_opts = va_arg(args, uint32_t);
1746  const char *prefix = va_arg(args, const char *);
1747  GList *unames = va_arg(args, GList *);
1748  GList *resources = va_arg(args, GList *);
1749 
1750  int rc = pcmk_rc_no_output;
1751  bool already_printed_failure = false;
1752 
1753  CHECK_RC(rc, out->message(out, "cluster-summary", data_set, pcmkd_state,
1754  section_opts, show_opts));
1755 
1756  if (pcmk_is_set(section_opts, pcmk_section_nodes) && unames) {
1757  CHECK_RC(rc, out->message(out, "node-list", data_set->nodes, unames,
1758  resources, show_opts, rc == pcmk_rc_ok));
1759  }
1760 
1761  /* Print resources section, if needed */
1762  if (pcmk_is_set(section_opts, pcmk_section_resources)) {
1763  CHECK_RC(rc, out->message(out, "resource-list", data_set, show_opts,
1764  true, unames, resources, rc == pcmk_rc_ok));
1765  }
1766 
1767  /* print Node Attributes section if requested */
1768  if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
1769  CHECK_RC(rc, out->message(out, "node-attribute-list", data_set,
1770  show_opts, rc == pcmk_rc_ok, unames, resources));
1771  }
1772 
1773  /* If requested, print resource operations (which includes failcounts)
1774  * or just failcounts
1775  */
1776  if (pcmk_any_flags_set(section_opts, pcmk_section_operations | pcmk_section_failcounts)) {
1777  CHECK_RC(rc, out->message(out, "node-summary", data_set, unames,
1778  resources, section_opts, show_opts, rc == pcmk_rc_ok));
1779  }
1780 
1781  /* If there were any failed actions, print them */
1782  if (pcmk_is_set(section_opts, pcmk_section_failures)
1784 
1785  CHECK_RC(rc, out->message(out, "failed-action-list", data_set, unames,
1786  resources, show_opts, rc == pcmk_rc_ok));
1787  }
1788 
1789  /* Print failed stonith actions */
1790  if (pcmk_is_set(section_opts, pcmk_section_fence_failed) &&
1791  fence_history != pcmk__fence_history_none) {
1792  if (history_rc == 0) {
1794  GINT_TO_POINTER(st_failed));
1795 
1796  if (hp) {
1797  CHECK_RC(rc, out->message(out, "failed-fencing-list",
1798  stonith_history, unames, section_opts,
1799  show_opts, rc == pcmk_rc_ok));
1800  }
1801  } else {
1802  PCMK__OUTPUT_SPACER_IF(out, rc == pcmk_rc_ok);
1803  out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
1804  out->list_item(out, NULL, "Failed to get fencing history: %s",
1805  crm_exit_str(history_rc));
1806  out->end_list(out);
1807 
1808  already_printed_failure = true;
1809  }
1810  }
1811 
1812  /* Print tickets if requested */
1813  if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
1814  CHECK_RC(rc, out->message(out, "ticket-list", data_set, rc == pcmk_rc_ok));
1815  }
1816 
1817  /* Print negative location constraints if requested */
1818  if (pcmk_is_set(section_opts, pcmk_section_bans)) {
1819  CHECK_RC(rc, out->message(out, "ban-list", data_set, prefix, resources,
1820  show_opts, rc == pcmk_rc_ok));
1821  }
1822 
1823  /* Print stonith history */
1824  if (pcmk_any_flags_set(section_opts, pcmk_section_fencing_all) &&
1825  fence_history != pcmk__fence_history_none) {
1826  if (history_rc != 0) {
1827  if (!already_printed_failure) {
1828  PCMK__OUTPUT_SPACER_IF(out, rc == pcmk_rc_ok);
1829  out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
1830  out->list_item(out, NULL, "Failed to get fencing history: %s",
1831  crm_exit_str(history_rc));
1832  out->end_list(out);
1833  }
1834  } else if (pcmk_is_set(section_opts, pcmk_section_fence_worked)) {
1836  GINT_TO_POINTER(st_failed));
1837 
1838  if (hp) {
1839  CHECK_RC(rc, out->message(out, "fencing-list", hp, unames,
1840  section_opts, show_opts,
1841  rc == pcmk_rc_ok));
1842  }
1843  } else if (pcmk_is_set(section_opts, pcmk_section_fence_pending)) {
1845 
1846  if (hp) {
1847  CHECK_RC(rc, out->message(out, "pending-fencing-list", hp,
1848  unames, section_opts, show_opts,
1849  rc == pcmk_rc_ok));
1850  }
1851  }
1852  }
1853 
1854  return rc;
1855 }
1856 
1857 PCMK__OUTPUT_ARGS("cluster-status", "pe_working_set_t *",
1858  "enum pcmk_pacemakerd_state", "crm_exit_t",
1859  "stonith_history_t *", "enum pcmk__fence_history", "uint32_t",
1860  "uint32_t", "const char *", "GList *", "GList *")
1861 static int
1862 cluster_status_xml(pcmk__output_t *out, va_list args)
1863 {
1864  pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1865  enum pcmk_pacemakerd_state pcmkd_state =
1866  (enum pcmk_pacemakerd_state) va_arg(args, int);
1867  crm_exit_t history_rc = va_arg(args, crm_exit_t);
1868  stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
1869  enum pcmk__fence_history fence_history = va_arg(args, int);
1870  uint32_t section_opts = va_arg(args, uint32_t);
1871  uint32_t show_opts = va_arg(args, uint32_t);
1872  const char *prefix = va_arg(args, const char *);
1873  GList *unames = va_arg(args, GList *);
1874  GList *resources = va_arg(args, GList *);
1875 
1876  out->message(out, "cluster-summary", data_set, pcmkd_state, section_opts,
1877  show_opts);
1878 
1879  /*** NODES ***/
1880  if (pcmk_is_set(section_opts, pcmk_section_nodes)) {
1881  out->message(out, "node-list", data_set->nodes, unames, resources,
1882  show_opts, false);
1883  }
1884 
1885  /* Print resources section, if needed */
1886  if (pcmk_is_set(section_opts, pcmk_section_resources)) {
1887  /* XML output always displays full details. */
1888  uint32_t full_show_opts = show_opts & ~pcmk_show_brief;
1889 
1890  out->message(out, "resource-list", data_set, full_show_opts,
1891  false, unames, resources, false);
1892  }
1893 
1894  /* print Node Attributes section if requested */
1895  if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
1896  out->message(out, "node-attribute-list", data_set, show_opts, false,
1897  unames, resources);
1898  }
1899 
1900  /* If requested, print resource operations (which includes failcounts)
1901  * or just failcounts
1902  */
1903  if (pcmk_any_flags_set(section_opts, pcmk_section_operations | pcmk_section_failcounts)) {
1904  out->message(out, "node-summary", data_set, unames,
1905  resources, section_opts, show_opts, false);
1906  }
1907 
1908  /* If there were any failed actions, print them */
1909  if (pcmk_is_set(section_opts, pcmk_section_failures)
1911 
1912  out->message(out, "failed-action-list", data_set, unames, resources,
1913  show_opts, false);
1914  }
1915 
1916  /* Print stonith history */
1917  if (pcmk_is_set(section_opts, pcmk_section_fencing_all) &&
1918  fence_history != pcmk__fence_history_none) {
1919  out->message(out, "full-fencing-list", history_rc, stonith_history,
1920  unames, section_opts, show_opts, false);
1921  }
1922 
1923  /* Print tickets if requested */
1924  if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
1925  out->message(out, "ticket-list", data_set, false);
1926  }
1927 
1928  /* Print negative location constraints if requested */
1929  if (pcmk_is_set(section_opts, pcmk_section_bans)) {
1930  out->message(out, "ban-list", data_set, prefix, resources, show_opts,
1931  false);
1932  }
1933 
1934  return pcmk_rc_ok;
1935 }
1936 
1937 PCMK__OUTPUT_ARGS("cluster-status", "pe_working_set_t *",
1938  "enum pcmk_pacemakerd_state", "crm_exit_t",
1939  "stonith_history_t *", "enum pcmk__fence_history", "uint32_t",
1940  "uint32_t", "const char *", "GList *", "GList *")
1941 static int
1942 cluster_status_html(pcmk__output_t *out, va_list args)
1943 {
1944  pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1945  enum pcmk_pacemakerd_state pcmkd_state =
1946  (enum pcmk_pacemakerd_state) va_arg(args, int);
1947  crm_exit_t history_rc = va_arg(args, crm_exit_t);
1948  stonith_history_t *stonith_history = va_arg(args, stonith_history_t *);
1949  enum pcmk__fence_history fence_history = va_arg(args, int);
1950  uint32_t section_opts = va_arg(args, uint32_t);
1951  uint32_t show_opts = va_arg(args, uint32_t);
1952  const char *prefix = va_arg(args, const char *);
1953  GList *unames = va_arg(args, GList *);
1954  GList *resources = va_arg(args, GList *);
1955  bool already_printed_failure = false;
1956 
1957  out->message(out, "cluster-summary", data_set, pcmkd_state, section_opts,
1958  show_opts);
1959 
1960  /*** NODE LIST ***/
1961  if (pcmk_is_set(section_opts, pcmk_section_nodes) && unames) {
1962  out->message(out, "node-list", data_set->nodes, unames, resources,
1963  show_opts, false);
1964  }
1965 
1966  /* Print resources section, if needed */
1967  if (pcmk_is_set(section_opts, pcmk_section_resources)) {
1968  out->message(out, "resource-list", data_set, show_opts, true, unames,
1969  resources, false);
1970  }
1971 
1972  /* print Node Attributes section if requested */
1973  if (pcmk_is_set(section_opts, pcmk_section_attributes)) {
1974  out->message(out, "node-attribute-list", data_set, show_opts, false,
1975  unames, resources);
1976  }
1977 
1978  /* If requested, print resource operations (which includes failcounts)
1979  * or just failcounts
1980  */
1981  if (pcmk_any_flags_set(section_opts, pcmk_section_operations | pcmk_section_failcounts)) {
1982  out->message(out, "node-summary", data_set, unames,
1983  resources, section_opts, show_opts, false);
1984  }
1985 
1986  /* If there were any failed actions, print them */
1987  if (pcmk_is_set(section_opts, pcmk_section_failures)
1989 
1990  out->message(out, "failed-action-list", data_set, unames, resources,
1991  show_opts, false);
1992  }
1993 
1994  /* Print failed stonith actions */
1995  if (pcmk_is_set(section_opts, pcmk_section_fence_failed) &&
1996  fence_history != pcmk__fence_history_none) {
1997  if (history_rc == 0) {
1999  GINT_TO_POINTER(st_failed));
2000 
2001  if (hp) {
2002  out->message(out, "failed-fencing-list", stonith_history, unames,
2003  section_opts, show_opts, false);
2004  }
2005  } else {
2006  out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
2007  out->list_item(out, NULL, "Failed to get fencing history: %s",
2008  crm_exit_str(history_rc));
2009  out->end_list(out);
2010  }
2011  }
2012 
2013  /* Print stonith history */
2014  if (pcmk_any_flags_set(section_opts, pcmk_section_fencing_all) &&
2015  fence_history != pcmk__fence_history_none) {
2016  if (history_rc != 0) {
2017  if (!already_printed_failure) {
2018  out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
2019  out->list_item(out, NULL, "Failed to get fencing history: %s",
2020  crm_exit_str(history_rc));
2021  out->end_list(out);
2022  }
2023  } else if (pcmk_is_set(section_opts, pcmk_section_fence_worked)) {
2025  GINT_TO_POINTER(st_failed));
2026 
2027  if (hp) {
2028  out->message(out, "fencing-list", hp, unames, section_opts,
2029  show_opts, false);
2030  }
2031  } else if (pcmk_is_set(section_opts, pcmk_section_fence_pending)) {
2033 
2034  if (hp) {
2035  out->message(out, "pending-fencing-list", hp, unames,
2036  section_opts, show_opts, false);
2037  }
2038  }
2039  }
2040 
2041  /* Print tickets if requested */
2042  if (pcmk_is_set(section_opts, pcmk_section_tickets)) {
2043  out->message(out, "ticket-list", data_set, false);
2044  }
2045 
2046  /* Print negative location constraints if requested */
2047  if (pcmk_is_set(section_opts, pcmk_section_bans)) {
2048  out->message(out, "ban-list", data_set, prefix, resources, show_opts,
2049  false);
2050  }
2051 
2052  return pcmk_rc_ok;
2053 }
2054 
2055 PCMK__OUTPUT_ARGS("attribute", "const char *", "const char *", "const char *",
2056  "const char *", "const char *")
2057 static int
2058 attribute_default(pcmk__output_t *out, va_list args)
2059 {
2060  const char *scope = va_arg(args, const char *);
2061  const char *instance = va_arg(args, const char *);
2062  const char *name = va_arg(args, const char *);
2063  const char *value = va_arg(args, const char *);
2064  const char *host = va_arg(args, const char *);
2065 
2066  GString *s = g_string_sized_new(50);
2067 
2068  if (!pcmk__str_empty(scope)) {
2069  pcmk__g_strcat(s, "scope=\"", scope, "\" ", NULL);
2070  }
2071 
2072  if (!pcmk__str_empty(instance)) {
2073  pcmk__g_strcat(s, "id=\"", instance, "\" ", NULL);
2074  }
2075 
2076  pcmk__g_strcat(s, "name=\"", pcmk__s(name, ""), "\" ", NULL);
2077 
2078  if (!pcmk__str_empty(host)) {
2079  pcmk__g_strcat(s, "host=\"", host, "\" ", NULL);
2080  }
2081 
2082  pcmk__g_strcat(s, "value=\"", pcmk__s(value, ""), "\"", NULL);
2083 
2084  out->info(out, "%s", s->str);
2085  g_string_free(s, TRUE);
2086 
2087  return pcmk_rc_ok;
2088 }
2089 
2090 PCMK__OUTPUT_ARGS("attribute", "const char *", "const char *", "const char *",
2091  "const char *", "const char *")
2092 static int
2093 attribute_xml(pcmk__output_t *out, va_list args)
2094 {
2095  const char *scope = va_arg(args, const char *);
2096  const char *instance = va_arg(args, const char *);
2097  const char *name = va_arg(args, const char *);
2098  const char *value = va_arg(args, const char *);
2099  const char *host = va_arg(args, const char *);
2100 
2101  xmlNodePtr node = NULL;
2102 
2103  node = pcmk__output_create_xml_node(out, "attribute",
2104  "name", name,
2105  "value", value ? value : "",
2106  NULL);
2107 
2108  if (!pcmk__str_empty(scope)) {
2109  crm_xml_add(node, "scope", scope);
2110  }
2111 
2112  if (!pcmk__str_empty(instance)) {
2113  crm_xml_add(node, "id", instance);
2114  }
2115 
2116  if (!pcmk__str_empty(host)) {
2117  crm_xml_add(node, "host", host);
2118  }
2119 
2120  return pcmk_rc_ok;
2121 }
2122 
2123 PCMK__OUTPUT_ARGS("rule-check", "const char *", "int", "const char *")
2124 static int
2125 rule_check_default(pcmk__output_t *out, va_list args)
2126 {
2127  const char *rule_id = va_arg(args, const char *);
2128  int result = va_arg(args, int);
2129  const char *error = va_arg(args, const char *);
2130 
2131  switch (result) {
2132  case pcmk_rc_within_range:
2133  return out->info(out, "Rule %s is still in effect", rule_id);
2134  case pcmk_rc_ok:
2135  return out->info(out, "Rule %s satisfies conditions", rule_id);
2136  case pcmk_rc_after_range:
2137  return out->info(out, "Rule %s is expired", rule_id);
2138  case pcmk_rc_before_range:
2139  return out->info(out, "Rule %s has not yet taken effect", rule_id);
2141  return out->info(out, "Rule %s does not satisfy conditions",
2142  rule_id);
2143  default:
2144  out->err(out,
2145  "Could not determine whether rule %s is in effect: %s",
2146  rule_id, ((error != NULL)? error : "unexpected error"));
2147  return pcmk_rc_ok;
2148  }
2149 }
2150 
2151 PCMK__OUTPUT_ARGS("rule-check", "const char *", "int", "const char *")
2152 static int
2153 rule_check_xml(pcmk__output_t *out, va_list args)
2154 {
2155  const char *rule_id = va_arg(args, const char *);
2156  int result = va_arg(args, int);
2157  const char *error = va_arg(args, const char *);
2158 
2159  char *rc_str = pcmk__itoa(pcmk_rc2exitc(result));
2160 
2161  pcmk__output_create_xml_node(out, "rule-check",
2162  "rule-id", rule_id,
2163  "rc", rc_str,
2164  NULL);
2165  free(rc_str);
2166 
2167  switch (result) {
2168  case pcmk_rc_within_range:
2169  case pcmk_rc_ok:
2170  case pcmk_rc_after_range:
2171  case pcmk_rc_before_range:
2173  return pcmk_rc_ok;
2174  default:
2175  out->err(out,
2176  "Could not determine whether rule %s is in effect: %s",
2177  rule_id, ((error != NULL)? error : "unexpected error"));
2178  return pcmk_rc_ok;
2179  }
2180 }
2181 
2182 PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
2183 static int
2184 result_code_none(pcmk__output_t *out, va_list args)
2185 {
2186  return pcmk_rc_no_output;
2187 }
2188 
2189 PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
2190 static int
2191 result_code_text(pcmk__output_t *out, va_list args)
2192 {
2193  int code = va_arg(args, int);
2194  const char *name = va_arg(args, const char *);
2195  const char *desc = va_arg(args, const char *);
2196 
2197  static int code_width = 0;
2198 
2199  if (out->is_quiet(out)) {
2200  /* If out->is_quiet(), don't print the code. Print name and/or desc in a
2201  * compact format for text output, or print nothing at all for none-type
2202  * output.
2203  */
2204  if ((name != NULL) && (desc != NULL)) {
2205  pcmk__formatted_printf(out, "%s - %s\n", name, desc);
2206 
2207  } else if ((name != NULL) || (desc != NULL)) {
2208  pcmk__formatted_printf(out, "%s\n", ((name != NULL)? name : desc));
2209  }
2210  return pcmk_rc_ok;
2211  }
2212 
2213  /* Get length of longest (most negative) standard Pacemaker return code
2214  * This should be longer than all the values of any other type of return
2215  * code.
2216  */
2217  if (code_width == 0) {
2218  long long most_negative = pcmk_rc_error - (long long) pcmk__n_rc + 1;
2219  code_width = (int) snprintf(NULL, 0, "%lld", most_negative);
2220  }
2221 
2222  if ((name != NULL) && (desc != NULL)) {
2223  static int name_width = 0;
2224 
2225  if (name_width == 0) {
2226  // Get length of longest standard Pacemaker return code name
2227  for (int lpc = 0; lpc < pcmk__n_rc; lpc++) {
2228  int len = (int) strlen(pcmk_rc_name(pcmk_rc_error - lpc));
2229  name_width = QB_MAX(name_width, len);
2230  }
2231  }
2232  return out->info(out, "% *d: %-*s %s", code_width, code, name_width,
2233  name, desc);
2234  }
2235 
2236  if ((name != NULL) || (desc != NULL)) {
2237  return out->info(out, "% *d: %s", code_width, code,
2238  ((name != NULL)? name : desc));
2239  }
2240 
2241  return out->info(out, "% *d", code_width, code);
2242 }
2243 
2244 PCMK__OUTPUT_ARGS("result-code", "int", "const char *", "const char *")
2245 static int
2246 result_code_xml(pcmk__output_t *out, va_list args)
2247 {
2248  int code = va_arg(args, int);
2249  const char *name = va_arg(args, const char *);
2250  const char *desc = va_arg(args, const char *);
2251 
2252  char *code_str = pcmk__itoa(code);
2253 
2254  pcmk__output_create_xml_node(out, "result-code",
2255  "code", code_str,
2257  XML_ATTR_DESC, desc,
2258  NULL);
2259  free(code_str);
2260  return pcmk_rc_ok;
2261 }
2262 
2263 static pcmk__message_entry_t fmt_functions[] = {
2264  { "attribute", "default", attribute_default },
2265  { "attribute", "xml", attribute_xml },
2266  { "cluster-status", "default", pcmk__cluster_status_text },
2267  { "cluster-status", "html", cluster_status_html },
2268  { "cluster-status", "xml", cluster_status_xml },
2269  { "crmadmin-node", "default", crmadmin_node },
2270  { "crmadmin-node", "text", crmadmin_node_text },
2271  { "crmadmin-node", "xml", crmadmin_node_xml },
2272  { "dc", "default", dc },
2273  { "dc", "text", dc_text },
2274  { "dc", "xml", dc_xml },
2275  { "digests", "default", digests_text },
2276  { "digests", "xml", digests_xml },
2277  { "health", "default", health },
2278  { "health", "text", health_text },
2279  { "health", "xml", health_xml },
2280  { "inject-attr", "default", inject_attr },
2281  { "inject-attr", "xml", inject_attr_xml },
2282  { "inject-cluster-action", "default", inject_cluster_action },
2283  { "inject-cluster-action", "xml", inject_cluster_action_xml },
2284  { "inject-fencing-action", "default", inject_fencing_action },
2285  { "inject-fencing-action", "xml", inject_fencing_action_xml },
2286  { "inject-modify-config", "default", inject_modify_config },
2287  { "inject-modify-config", "xml", inject_modify_config_xml },
2288  { "inject-modify-node", "default", inject_modify_node },
2289  { "inject-modify-node", "xml", inject_modify_node_xml },
2290  { "inject-modify-ticket", "default", inject_modify_ticket },
2291  { "inject-modify-ticket", "xml", inject_modify_ticket_xml },
2292  { "inject-pseudo-action", "default", inject_pseudo_action },
2293  { "inject-pseudo-action", "xml", inject_pseudo_action_xml },
2294  { "inject-rsc-action", "default", inject_rsc_action },
2295  { "inject-rsc-action", "xml", inject_rsc_action_xml },
2296  { "inject-spec", "default", inject_spec },
2297  { "inject-spec", "xml", inject_spec_xml },
2298  { "locations-list", "default", locations_list },
2299  { "locations-list", "xml", locations_list_xml },
2300  { "node-action", "default", node_action },
2301  { "node-action", "xml", node_action_xml },
2302  { "node-info", "default", node_info_default },
2303  { "node-info", "xml", node_info_xml },
2304  { "pacemakerd-health", "default", pacemakerd_health },
2305  { "pacemakerd-health", "html", pacemakerd_health_html },
2306  { "pacemakerd-health", "text", pacemakerd_health_text },
2307  { "pacemakerd-health", "xml", pacemakerd_health_xml },
2308  { "profile", "default", profile_default, },
2309  { "profile", "xml", profile_xml },
2310  { "result-code", "none", result_code_none },
2311  { "result-code", "text", result_code_text },
2312  { "result-code", "xml", result_code_xml },
2313  { "rsc-action", "default", rsc_action_default },
2314  { "rsc-action-item", "default", rsc_action_item },
2315  { "rsc-action-item", "xml", rsc_action_item_xml },
2316  { "rsc-is-colocated-with-list", "default", rsc_is_colocated_with_list },
2317  { "rsc-is-colocated-with-list", "xml", rsc_is_colocated_with_list_xml },
2318  { "rscs-colocated-with-list", "default", rscs_colocated_with_list },
2319  { "rscs-colocated-with-list", "xml", rscs_colocated_with_list_xml },
2320  { "rule-check", "default", rule_check_default },
2321  { "rule-check", "xml", rule_check_xml },
2322  { "locations-and-colocations", "default", locations_and_colocations },
2323  { "locations-and-colocations", "xml", locations_and_colocations_xml },
2324 
2325  { NULL, NULL, NULL }
2326 };
2327 
2328 void
2330  pcmk__register_messages(out, fmt_functions);
2331 }
pcmk__cpg_host_t host
Definition: cpg.c:49
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:235
#define RSC_STOP
Definition: crm.h:202
#define crm_notice(fmt, args...)
Definition: logging.h:379
xmlNode * failed
Definition: pe_types.h:188
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:2356
GList * rsc_cons
Definition: pe_types.h:389
Control output from tools.
void pcmk__register_messages(pcmk__output_t *out, const pcmk__message_entry_t *table)
Definition: output.c:196
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition: scores.c:86
#define crm_time_log_timeofday
Definition: iso8601.h:68
const char * name
Definition: cib.c:24
pcmk__fence_history
Control how much of the fencing history is output.
Definition: pcmki_fence.h:18
enum rsc_role_e role
Definition: pe_types.h:402
GList * find_actions(GList *input, const char *key, const pe_node_t *on_node)
Definition: pe_actions.c:1327
#define pe_rsc_stop
Definition: pe_types.h:287
const size_t pcmk__n_rc
Definition: results.c:318
enum rsc_role_e next_role
Definition: pe_types.h:403
crm_exit_t pcmk_rc2exitc(int rc)
Map a function return code to the most similar exit code.
Definition: results.c:689
xmlNodePtr pcmk__output_xml_create_parent(pcmk__output_t *out, const char *name,...) G_GNUC_NULL_TERMINATED
Definition: output_xml.c:438
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:302
#define CHECK_RC(retcode, retval)
Definition: pcmk_output.c:1726
pe_resource_t * dependent
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
Definition: nvpair.c:921
#define XML_CONS_TAG_RSC_DEPEND
Definition: msg_xml.h:363
enum crm_exit_e crm_exit_t
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:219
xmlNode * params_restart
Definition: internal.h:511
GList * rsc_cons_lhs
Definition: pe_types.h:388
enum crm_ais_msg_types type
Definition: cpg.c:48
#define RSC_START
Definition: crm.h:199
#define pe_rsc_stop_unexpected
Definition: pe_types.h:303
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:434
void pcmk__register_lib_messages(pcmk__output_t *out)
Definition: pcmk_output.c:2329
char * reason
Definition: pe_types.h:440
const char * action
Definition: pcmk_fence.c:30
bool stonith__event_state_pending(stonith_history_t *history, void *user_data)
Definition: st_client.c:2370
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:77
void void void pcmk__formatted_printf(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
#define CRM_SYSTEM_MCP
Definition: crm.h:110
GList * nodes
Definition: pe_types.h:180
#define PCMK__OUTPUT_SPACER_IF(out_obj, cond)
const char * role2text(enum rsc_role_e role)
Definition: common.c:450
int weight
Definition: pe_types.h:265
const char * crm_exit_str(crm_exit_t exit_code)
Definition: results.c:627
#define pe_rsc_failed
Definition: pe_types.h:292
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:922
#define XML_ATTR_ID
Definition: msg_xml.h:147
char * digest_all_calc
Definition: internal.h:512
pe_resource_t * primary
#define stop_key(rsc)
Definition: internal.h:405
#define XML_CONS_TAG_RSC_LOCATION
Definition: msg_xml.h:365
#define XML_NODE_IS_PEER
Definition: msg_xml.h:296
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1217
char * digest_secure_calc
Definition: internal.h:513
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:121
xmlNode * add_node_copy(xmlNode *new_parent, xmlNode *xml_node)
Definition: xml.c:663
struct pe_node_shared_s * details
Definition: pe_types.h:268
#define XML_ATTR_NAME
Definition: msg_xml.h:148
#define XML_ATTR_HAVE_QUORUM
Definition: msg_xml.h:136
unsigned long long flags
Definition: pe_types.h:373
const char * uname
Definition: pe_types.h:232
pe_working_set_t * data_set
void pcmk__unpack_constraints(pe_working_set_t *data_set)
#define XML_ATTR_UNAME
Definition: msg_xml.h:170
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:677
xmlNodePtr pcmk__output_create_xml_node(pcmk__output_t *out, const char *name,...) G_GNUC_NULL_TERMINATED
Definition: output_xml.c:474
#define XML_ATTR_DESC
Definition: msg_xml.h:146
#define pe_rsc_detect_loop
Definition: pe_types.h:293
GList * actions
Definition: pe_types.h:391
#define XML_NODE_IS_REMOTE
Definition: msg_xml.h:297
#define pcmk_section_fencing_all
Definition: output.h:46
int pcmk__cluster_status_text(pcmk__output_t *out, va_list args)
#define crm_time_log_with_timezone
Definition: iso8601.h:69
gboolean xml_has_children(const xmlNode *root)
Definition: xml.c:1726
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
Definition: output_xml.c:518
Function and executable result codes.
xmlNode * params_all
Definition: internal.h:509
void pcmk__xe_set_props(xmlNodePtr node,...) G_GNUC_NULL_TERMINATED
Definition: xml.c:2695
const xmlChar * pcmkXmlStr
Definition: xml.h:50
#define PCMK__OUTPUT_LIST_FOOTER(out_obj, retcode)
const char * target
Definition: pcmk_fence.c:29
pcmk_pacemakerd_state
#define PCMK__OUTPUT_LIST_HEADER(out_obj, cond, retcode, title...)
pcmk__action_result_t result
Definition: pcmk_fence.c:35
const char * pcmk_rc_name(int rc)
Get a return code constant name as a string.
Definition: results.c:328
const char * pcmk_pacemakerd_api_daemon_state_enum2text(enum pcmk_pacemakerd_state state)
#define STOP_SANITY_ASSERT(lineno)
Definition: pcmk_output.c:1047
#define CRM_ASSERT(expr)
Definition: results.h:42
char * pcmk__epoch2str(const time_t *source, uint32_t flags)
Definition: iso8601.c:1858
#define pe_rsc_reload
Definition: pe_types.h:288
#define RSC_PROMOTE
Definition: crm.h:205
Fencing aka. STONITH.
This structure contains everything that makes up a single output formatter.
xmlNode * params_secure
Definition: internal.h:510
void pe__clear_resource_flags_on_all(pe_working_set_t *data_set, uint64_t flag)
Definition: utils.c:598
GList * rsc_location
Definition: pe_types.h:390
const char * pcmk__pcmkd_state_enum2friendly(enum pcmk_pacemakerd_state state)
GList * running_on
Definition: pe_types.h:398
enum pe_action_flags flags
Definition: pe_types.h:442
const char * node_attribute
#define ID(x)
Definition: msg_xml.h:480
const char * parent
Definition: cib.c:25
GList * pe__resource_actions(const pe_resource_t *rsc, const pe_node_t *node, const char *task, bool require_node)
Find all actions of given type for a resource.
Definition: pe_actions.c:1400
bool stonith__event_state_eq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2376
PCMK__OUTPUT_ARGS("rsc-action-item", "const char *", "pe_resource_t *", "pe_node_t *", "pe_node_t *", "pe_action_t *", "pe_action_t *")
Definition: pcmk_output.c:103
char * digest_restart_calc
Definition: internal.h:514
#define pe_rsc_managed
Definition: pe_types.h:273
#define crm_time_log_date
Definition: iso8601.h:67
bool stonith__event_state_neq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2382
#define RSC_DEMOTE
Definition: crm.h:207
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:48
char * id
Definition: pe_types.h:347
#define RSC_MIGRATED
Definition: crm.h:197