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