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