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