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