pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
pe_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 Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11#include <stdint.h>
13#include <crm/common/output.h>
14#include <crm/cib/util.h>
15#include <crm/msg_xml.h>
17
18/* Never display node attributes whose name starts with one of these prefixes */
19#define FILTER_STR { PCMK__FAIL_COUNT_PREFIX, PCMK__LAST_FAILURE_PREFIX, \
20 "shutdown", "terminate", "standby", "#", NULL }
21
22static int
23compare_attribute(gconstpointer a, gconstpointer b)
24{
25 int rc;
26
27 rc = strcmp((const char *)a, (const char *)b);
28
29 return rc;
30}
31
46static bool
47add_extra_info(pe_node_t *node, GList *rsc_list, pe_working_set_t *data_set,
48 const char *attrname, int *expected_score)
49{
50 GList *gIter = NULL;
51
52 for (gIter = rsc_list; gIter != NULL; gIter = gIter->next) {
53 pe_resource_t *rsc = (pe_resource_t *) gIter->data;
54 const char *type = g_hash_table_lookup(rsc->meta, "type");
55 const char *name = NULL;
56 GHashTable *params = NULL;
57
58 if (rsc->children != NULL) {
59 if (add_extra_info(node, rsc->children, data_set, attrname,
60 expected_score)) {
61 return true;
62 }
63 }
64
65 if (!pcmk__strcase_any_of(type, "ping", "pingd", NULL)) {
66 continue;
67 }
68
69 params = pe_rsc_params(rsc, node, data_set);
70 name = g_hash_table_lookup(params, "name");
71
72 if (name == NULL) {
73 name = "pingd";
74 }
75
76 /* To identify the resource with the attribute name. */
77 if (pcmk__str_eq(name, attrname, pcmk__str_casei)) {
78 int host_list_num = 0;
79 const char *hosts = g_hash_table_lookup(params, "host_list");
80 const char *multiplier = g_hash_table_lookup(params, "multiplier");
81 int multiplier_i;
82
83 if (hosts) {
84 char **host_list = g_strsplit(hosts, " ", 0);
85 host_list_num = g_strv_length(host_list);
86 g_strfreev(host_list);
87 }
88
89 if ((multiplier == NULL)
90 || (pcmk__scan_min_int(multiplier, &multiplier_i,
91 INT_MIN) != pcmk_rc_ok)) {
92 /* The ocf:pacemaker:ping resource agent defaults multiplier to
93 * 1. The agent currently does not handle invalid text, but it
94 * should, and this would be a reasonable choice ...
95 */
96 multiplier_i = 1;
97 }
98 *expected_score = host_list_num * multiplier_i;
99
100 return true;
101 }
102 }
103 return false;
104}
105
106static GList *
107filter_attr_list(GList *attr_list, char *name)
108{
109 int i;
110 const char *filt_str[] = FILTER_STR;
111
112 CRM_CHECK(name != NULL, return attr_list);
113
114 /* filtering automatic attributes */
115 for (i = 0; filt_str[i] != NULL; i++) {
116 if (g_str_has_prefix(name, filt_str[i])) {
117 return attr_list;
118 }
119 }
120
121 return g_list_insert_sorted(attr_list, name, compare_attribute);
122}
123
124static GList *
125get_operation_list(xmlNode *rsc_entry) {
126 GList *op_list = NULL;
127 xmlNode *rsc_op = NULL;
128
129 for (rsc_op = pcmk__xe_first_child(rsc_entry); rsc_op != NULL;
130 rsc_op = pcmk__xe_next(rsc_op)) {
131 const char *task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
132 const char *interval_ms_s = crm_element_value(rsc_op,
134 const char *op_rc = crm_element_value(rsc_op, XML_LRM_ATTR_RC);
135 int op_rc_i;
136
137 pcmk__scan_min_int(op_rc, &op_rc_i, 0);
138
139 /* Display 0-interval monitors as "probe" */
140 if (pcmk__str_eq(task, CRMD_ACTION_STATUS, pcmk__str_casei)
141 && pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches | pcmk__str_casei)) {
142 task = "probe";
143 }
144
145 /* Ignore notifies and some probes */
146 if (pcmk__str_eq(task, CRMD_ACTION_NOTIFY, pcmk__str_casei) || (pcmk__str_eq(task, "probe", pcmk__str_casei) && (op_rc_i == 7))) {
147 continue;
148 }
149
150 if (pcmk__str_eq((const char *)rsc_op->name, XML_LRM_TAG_RSC_OP, pcmk__str_none)) {
151 op_list = g_list_append(op_list, rsc_op);
152 }
153 }
154
155 op_list = g_list_sort(op_list, sort_op_by_callid);
156 return op_list;
157}
158
159static void
160add_dump_node(gpointer key, gpointer value, gpointer user_data)
161{
162 xmlNodePtr node = user_data;
163 pcmk_create_xml_text_node(node, (const char *) key, (const char *) value);
164}
165
166static void
167append_dump_text(gpointer key, gpointer value, gpointer user_data)
168{
169 char **dump_text = user_data;
170 char *new_text = crm_strdup_printf("%s %s=%s",
171 *dump_text, (char *)key, (char *)value);
172
173 free(*dump_text);
174 *dump_text = new_text;
175}
176
177static const char *
178get_cluster_stack(pe_working_set_t *data_set)
179{
180 xmlNode *stack = get_xpath_object("//nvpair[@name='cluster-infrastructure']",
181 data_set->input, LOG_DEBUG);
182 return stack? crm_element_value(stack, XML_NVPAIR_ATTR_VALUE) : "unknown";
183}
184
185static char *
186last_changed_string(const char *last_written, const char *user,
187 const char *client, const char *origin) {
188 if (last_written != NULL || user != NULL || client != NULL || origin != NULL) {
189 return crm_strdup_printf("%s%s%s%s%s%s%s",
190 last_written ? last_written : "",
191 user ? " by " : "",
192 user ? user : "",
193 client ? " via " : "",
194 client ? client : "",
195 origin ? " on " : "",
196 origin ? origin : "");
197 } else {
198 return strdup("");
199 }
200}
201
202static char *
203op_history_string(xmlNode *xml_op, const char *task, const char *interval_ms_s,
204 int rc, bool print_timing) {
205 const char *call = crm_element_value(xml_op, XML_LRM_ATTR_CALLID);
206 char *interval_str = NULL;
207 char *buf = NULL;
208
209 if (interval_ms_s && !pcmk__str_eq(interval_ms_s, "0", pcmk__str_casei)) {
210 char *pair = pcmk__format_nvpair("interval", interval_ms_s, "ms");
211 interval_str = crm_strdup_printf(" %s", pair);
212 free(pair);
213 }
214
215 if (print_timing) {
216 char *last_change_str = NULL;
217 char *exec_str = NULL;
218 char *queue_str = NULL;
219
220 const char *value = NULL;
221
222 time_t epoch = 0;
223
225 && (epoch > 0)) {
227
228 last_change_str = crm_strdup_printf(" %s", time);
229 free(time);
230 }
231
232 value = crm_element_value(xml_op, XML_RSC_OP_T_EXEC);
233 if (value) {
234 char *pair = pcmk__format_nvpair(XML_RSC_OP_T_EXEC, value, "ms");
235 exec_str = crm_strdup_printf(" %s", pair);
236 free(pair);
237 }
238
239 value = crm_element_value(xml_op, XML_RSC_OP_T_QUEUE);
240 if (value) {
241 char *pair = pcmk__format_nvpair(XML_RSC_OP_T_QUEUE, value, "ms");
242 queue_str = crm_strdup_printf(" %s", pair);
243 free(pair);
244 }
245
246 buf = crm_strdup_printf("(%s) %s:%s%s%s%s rc=%d (%s)", call, task,
247 interval_str ? interval_str : "",
248 last_change_str ? last_change_str : "",
249 exec_str ? exec_str : "",
250 queue_str ? queue_str : "",
251 rc, services_ocf_exitcode_str(rc));
252
253 if (last_change_str) {
254 free(last_change_str);
255 }
256
257 if (exec_str) {
258 free(exec_str);
259 }
260
261 if (queue_str) {
262 free(queue_str);
263 }
264 } else {
265 buf = crm_strdup_printf("(%s) %s%s%s", call, task,
266 interval_str ? ":" : "",
267 interval_str ? interval_str : "");
268 }
269
270 if (interval_str) {
271 free(interval_str);
272 }
273
274 return buf;
275}
276
277static char *
278resource_history_string(pe_resource_t *rsc, const char *rsc_id, bool all,
279 int failcount, time_t last_failure) {
280 char *buf = NULL;
281
282 if (rsc == NULL) {
283 buf = crm_strdup_printf("%s: orphan", rsc_id);
284 } else if (all || failcount || last_failure > 0) {
285 char *failcount_s = NULL;
286 char *lastfail_s = NULL;
287
288 if (failcount > 0) {
289 failcount_s = crm_strdup_printf(" %s=%d", PCMK__FAIL_COUNT_PREFIX,
290 failcount);
291 } else {
292 failcount_s = strdup("");
293 }
294 if (last_failure > 0) {
295 lastfail_s = crm_strdup_printf(" %s='%s'",
297 pcmk__epoch2str(&last_failure));
298 }
299
300 buf = crm_strdup_printf("%s: migration-threshold=%d%s%s",
301 rsc_id, rsc->migration_threshold, failcount_s,
302 lastfail_s? lastfail_s : "");
303 free(failcount_s);
304 free(lastfail_s);
305 } else {
306 buf = crm_strdup_printf("%s:", rsc_id);
307 }
308
309 return buf;
310}
311
312static const char *
313get_node_feature_set(pe_node_t *node) {
314 const char *feature_set = NULL;
315
316 if (node->details->online && !pe__is_guest_or_remote_node(node)) {
317 feature_set = g_hash_table_lookup(node->details->attrs,
319 /* The feature set attribute is present since 3.15.1. If it is missing
320 * then the node must be running an earlier version. */
321 if (feature_set == NULL) {
322 feature_set = "<3.15.1";
323 }
324 }
325 return feature_set;
326}
327
328static bool
329is_mixed_version(pe_working_set_t *data_set) {
330 const char *feature_set = NULL;
331 for (GList *gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
332 pe_node_t *node = gIter->data;
333 const char *node_feature_set = get_node_feature_set(node);
334 if (node_feature_set != NULL) {
335 if (feature_set == NULL) {
336 feature_set = node_feature_set;
337 } else if (strcmp(feature_set, node_feature_set) != 0) {
338 return true;
339 }
340 }
341 }
342 return false;
343}
344
345static char *
346formatted_xml_buf(pe_resource_t *rsc, bool raw)
347{
348 if (raw) {
349 return dump_xml_formatted(rsc->orig_xml ? rsc->orig_xml : rsc->xml);
350 } else {
351 return dump_xml_formatted(rsc->xml);
352 }
353}
354
355PCMK__OUTPUT_ARGS("cluster-summary", "pe_working_set_t *", "uint32_t", "uint32_t")
356static int
357cluster_summary(pcmk__output_t *out, va_list args) {
358 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
359 uint32_t section_opts = va_arg(args, uint32_t);
360 uint32_t show_opts = va_arg(args, uint32_t);
361
362 int rc = pcmk_rc_no_output;
363 const char *stack_s = get_cluster_stack(data_set);
364
365 if (pcmk_is_set(section_opts, pcmk_section_stack)) {
366 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
367 out->message(out, "cluster-stack", stack_s);
368 }
369
370 if (pcmk_is_set(section_opts, pcmk_section_dc)) {
371 xmlNode *dc_version = get_xpath_object("//nvpair[@name='dc-version']",
372 data_set->input, LOG_DEBUG);
373 const char *dc_version_s = dc_version?
375 : NULL;
377 char *dc_name = data_set->dc_node ? pe__node_display_name(data_set->dc_node, pcmk_is_set(show_opts, pcmk_show_node_id)) : NULL;
378 bool mixed_version = is_mixed_version(data_set);
379
380 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
381 out->message(out, "cluster-dc", data_set->dc_node, quorum,
382 dc_version_s, dc_name, mixed_version);
383 free(dc_name);
384 }
385
386 if (pcmk_is_set(section_opts, pcmk_section_times)) {
387 const char *last_written = crm_element_value(data_set->input, XML_CIB_ATTR_WRITTEN);
391
392 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
393 out->message(out, "cluster-times", last_written, user, client, origin);
394 }
395
396 if (pcmk_is_set(section_opts, pcmk_section_counts)) {
397 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
398 out->message(out, "cluster-counts", g_list_length(data_set->nodes),
401 }
402
403 if (pcmk_is_set(section_opts, pcmk_section_options)) {
404 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
405 out->message(out, "cluster-options", data_set);
406 }
407
409
410 if (pcmk_is_set(section_opts, pcmk_section_maint_mode)) {
411 if (out->message(out, "maint-mode", data_set->flags) == pcmk_rc_ok) {
412 rc = pcmk_rc_ok;
413 }
414 }
415
416 return rc;
417}
418
419PCMK__OUTPUT_ARGS("cluster-summary", "pe_working_set_t *", "uint32_t", "uint32_t")
420static int
421cluster_summary_html(pcmk__output_t *out, va_list args) {
422 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
423 uint32_t section_opts = va_arg(args, uint32_t);
424 uint32_t show_opts = va_arg(args, uint32_t);
425
426 int rc = pcmk_rc_no_output;
427 const char *stack_s = get_cluster_stack(data_set);
428
429 if (pcmk_is_set(section_opts, pcmk_section_stack)) {
430 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
431 out->message(out, "cluster-stack", stack_s);
432 }
433
434 /* Always print DC if none, even if not requested */
435 if (data_set->dc_node == NULL || pcmk_is_set(section_opts, pcmk_section_dc)) {
436 xmlNode *dc_version = get_xpath_object("//nvpair[@name='dc-version']",
437 data_set->input, LOG_DEBUG);
438 const char *dc_version_s = dc_version?
440 : NULL;
442 char *dc_name = data_set->dc_node ? pe__node_display_name(data_set->dc_node, pcmk_is_set(show_opts, pcmk_show_node_id)) : NULL;
443 bool mixed_version = is_mixed_version(data_set);
444
445 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
446 out->message(out, "cluster-dc", data_set->dc_node, quorum,
447 dc_version_s, dc_name, mixed_version);
448 free(dc_name);
449 }
450
451 if (pcmk_is_set(section_opts, pcmk_section_times)) {
452 const char *last_written = crm_element_value(data_set->input, XML_CIB_ATTR_WRITTEN);
456
457 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
458 out->message(out, "cluster-times", last_written, user, client, origin);
459 }
460
461 if (pcmk_is_set(section_opts, pcmk_section_counts)) {
462 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
463 out->message(out, "cluster-counts", g_list_length(data_set->nodes),
466 }
467
468 if (pcmk_is_set(section_opts, pcmk_section_options)) {
469 /* Kind of a hack - close the list we may have opened earlier in this
470 * function so we can put all the options into their own list. We
471 * only want to do this on HTML output, though.
472 */
474
475 out->begin_list(out, NULL, NULL, "Config Options");
476 out->message(out, "cluster-options", data_set);
477 }
478
480
481 if (pcmk_is_set(section_opts, pcmk_section_maint_mode)) {
482 if (out->message(out, "maint-mode", data_set->flags) == pcmk_rc_ok) {
483 rc = pcmk_rc_ok;
484 }
485 }
486
487 return rc;
488}
489
490char *
491pe__node_display_name(pe_node_t *node, bool print_detail)
492{
493 char *node_name;
494 const char *node_host = NULL;
495 const char *node_id = NULL;
496 int name_len;
497
498 CRM_ASSERT((node != NULL) && (node->details != NULL) && (node->details->uname != NULL));
499
500 /* Host is displayed only if this is a guest node and detail is requested */
501 if (print_detail && pe__is_guest_node(node)) {
502 const pe_resource_t *container = node->details->remote_rsc->container;
503 const pe_node_t *host_node = pe__current_node(container);
504
505 if (host_node && host_node->details) {
506 node_host = host_node->details->uname;
507 }
508 if (node_host == NULL) {
509 node_host = ""; /* so we at least get "uname@" to indicate guest */
510 }
511 }
512
513 /* Node ID is displayed if different from uname and detail is requested */
514 if (print_detail && !pcmk__str_eq(node->details->uname, node->details->id, pcmk__str_casei)) {
515 node_id = node->details->id;
516 }
517
518 /* Determine name length */
519 name_len = strlen(node->details->uname) + 1;
520 if (node_host) {
521 name_len += strlen(node_host) + 1; /* "@node_host" */
522 }
523 if (node_id) {
524 name_len += strlen(node_id) + 3; /* + " (node_id)" */
525 }
526
527 /* Allocate and populate display name */
528 node_name = malloc(name_len);
529 CRM_ASSERT(node_name != NULL);
530 strcpy(node_name, node->details->uname);
531 if (node_host) {
532 strcat(node_name, "@");
533 strcat(node_name, node_host);
534 }
535 if (node_id) {
536 strcat(node_name, " (");
537 strcat(node_name, node_id);
538 strcat(node_name, ")");
539 }
540 return node_name;
541}
542
543int
544pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name
545 , size_t pairs_count, ...)
546{
547 xmlNodePtr xml_node = NULL;
548 va_list args;
549
550 CRM_ASSERT(tag_name != NULL);
551
552 xml_node = pcmk__output_xml_peek_parent(out);
553 CRM_ASSERT(xml_node != NULL);
554 xml_node = is_list
555 ? create_xml_node(xml_node, tag_name)
556 : xmlNewChild(xml_node, NULL, (pcmkXmlStr) tag_name, NULL);
557
558 va_start(args, pairs_count);
559 while(pairs_count--) {
560 const char *param_name = va_arg(args, const char *);
561 const char *param_value = va_arg(args, const char *);
562 if (param_name && param_value) {
563 crm_xml_add(xml_node, param_name, param_value);
564 }
565 };
566 va_end(args);
567
568 if (is_list) {
569 pcmk__output_xml_push_parent(out, xml_node);
570 }
571 return pcmk_rc_ok;
572}
573
574static const char *
575role_desc(enum rsc_role_e role)
576{
577 if (role == RSC_ROLE_PROMOTED) {
578#ifdef PCMK__COMPAT_2_0
579 return "as " RSC_ROLE_PROMOTED_LEGACY_S " ";
580#else
581 return "in " RSC_ROLE_PROMOTED_S " role ";
582#endif
583 }
584 return "";
585}
586
587PCMK__OUTPUT_ARGS("ban", "pe_node_t *", "pe__location_t *", "uint32_t")
588static int
589ban_html(pcmk__output_t *out, va_list args) {
590 pe_node_t *pe_node = va_arg(args, pe_node_t *);
591 pe__location_t *location = va_arg(args, pe__location_t *);
592 uint32_t show_opts = va_arg(args, uint32_t);
593
594 char *node_name = pe__node_display_name(pe_node,
595 pcmk_is_set(show_opts, pcmk_show_node_id));
596 char *buf = crm_strdup_printf("%s\tprevents %s from running %son %s",
597 location->id, location->rsc_lh->id,
598 role_desc(location->role_filter), node_name);
599
600 pcmk__output_create_html_node(out, "li", NULL, NULL, buf);
601
602 free(node_name);
603 free(buf);
604 return pcmk_rc_ok;
605}
606
607PCMK__OUTPUT_ARGS("ban", "pe_node_t *", "pe__location_t *", "uint32_t")
608static int
609ban_text(pcmk__output_t *out, va_list args) {
610 pe_node_t *pe_node = va_arg(args, pe_node_t *);
611 pe__location_t *location = va_arg(args, pe__location_t *);
612 uint32_t show_opts = va_arg(args, uint32_t);
613
614 char *node_name = pe__node_display_name(pe_node,
615 pcmk_is_set(show_opts, pcmk_show_node_id));
616 out->list_item(out, NULL, "%s\tprevents %s from running %son %s",
617 location->id, location->rsc_lh->id,
618 role_desc(location->role_filter), node_name);
619
620 free(node_name);
621 return pcmk_rc_ok;
622}
623
624PCMK__OUTPUT_ARGS("ban", "pe_node_t *", "pe__location_t *", "uint32_t")
625static int
626ban_xml(pcmk__output_t *out, va_list args) {
627 pe_node_t *pe_node = va_arg(args, pe_node_t *);
628 pe__location_t *location = va_arg(args, pe__location_t *);
629 uint32_t show_opts G_GNUC_UNUSED = va_arg(args, uint32_t);
630
631 const char *promoted_only = pcmk__btoa(location->role_filter == RSC_ROLE_PROMOTED);
632 char *weight_s = pcmk__itoa(pe_node->weight);
633
635 "id", location->id,
636 "resource", location->rsc_lh->id,
637 "node", pe_node->details->uname,
638 "weight", weight_s,
639 "promoted-only", promoted_only,
640 /* This is a deprecated alias for
641 * promoted_only. Removing it will break
642 * backward compatibility of the API schema,
643 * which will require an API schema major
644 * version bump.
645 */
646 "master_only", promoted_only,
647 NULL);
648
649 free(weight_s);
650 return pcmk_rc_ok;
651}
652
653PCMK__OUTPUT_ARGS("ban-list", "pe_working_set_t *", "const char *", "GList *",
654 "uint32_t", "bool")
655static int
656ban_list(pcmk__output_t *out, va_list args) {
657 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
658 const char *prefix = va_arg(args, const char *);
659 GList *only_rsc = va_arg(args, GList *);
660 uint32_t show_opts = va_arg(args, uint32_t);
661 bool print_spacer = va_arg(args, int);
662
663 GList *gIter, *gIter2;
664 int rc = pcmk_rc_no_output;
665
666 /* Print each ban */
667 for (gIter = data_set->placement_constraints; gIter != NULL; gIter = gIter->next) {
668 pe__location_t *location = gIter->data;
669
670 if (prefix != NULL && !g_str_has_prefix(location->id, prefix)) {
671 continue;
672 }
673
676 continue;
677 }
678
679 for (gIter2 = location->node_list_rh; gIter2 != NULL; gIter2 = gIter2->next) {
680 pe_node_t *node = (pe_node_t *) gIter2->data;
681
682 if (node->weight < 0) {
683 PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Negative Location Constraints");
684 out->message(out, "ban", node, location, show_opts);
685 }
686 }
687 }
688
690 return rc;
691}
692
693PCMK__OUTPUT_ARGS("cluster-counts", "unsigned int", "int", "int", "int")
694static int
695cluster_counts_html(pcmk__output_t *out, va_list args) {
696 unsigned int nnodes = va_arg(args, unsigned int);
697 int nresources = va_arg(args, int);
698 int ndisabled = va_arg(args, int);
699 int nblocked = va_arg(args, int);
700
701 xmlNodePtr nodes_node = pcmk__output_create_xml_node(out, "li", NULL);
702 xmlNodePtr resources_node = pcmk__output_create_xml_node(out, "li", NULL);
703
704 char *nnodes_str = crm_strdup_printf("%d node%s configured",
705 nnodes, pcmk__plural_s(nnodes));
706
707 pcmk_create_html_node(nodes_node, "span", NULL, NULL, nnodes_str);
708 free(nnodes_str);
709
710 if (ndisabled && nblocked) {
711 char *s = crm_strdup_printf("%d resource instance%s configured (%d ",
712 nresources, pcmk__plural_s(nresources),
713 ndisabled);
714 pcmk_create_html_node(resources_node, "span", NULL, NULL, s);
715 free(s);
716
717 pcmk_create_html_node(resources_node, "span", NULL, "bold", "DISABLED");
718
719 s = crm_strdup_printf(", %d ", nblocked);
720 pcmk_create_html_node(resources_node, "span", NULL, NULL, s);
721 free(s);
722
723 pcmk_create_html_node(resources_node, "span", NULL, "bold", "BLOCKED");
724 pcmk_create_html_node(resources_node, "span", NULL, NULL,
725 " from further action due to failure)");
726 } else if (ndisabled && !nblocked) {
727 char *s = crm_strdup_printf("%d resource instance%s configured (%d ",
728 nresources, pcmk__plural_s(nresources),
729 ndisabled);
730 pcmk_create_html_node(resources_node, "span", NULL, NULL, s);
731 free(s);
732
733 pcmk_create_html_node(resources_node, "span", NULL, "bold", "DISABLED");
734 pcmk_create_html_node(resources_node, "span", NULL, NULL, ")");
735 } else if (!ndisabled && nblocked) {
736 char *s = crm_strdup_printf("%d resource instance%s configured (%d ",
737 nresources, pcmk__plural_s(nresources),
738 nblocked);
739 pcmk_create_html_node(resources_node, "span", NULL, NULL, s);
740 free(s);
741
742 pcmk_create_html_node(resources_node, "span", NULL, "bold", "BLOCKED");
743 pcmk_create_html_node(resources_node, "span", NULL, NULL,
744 " from further action due to failure)");
745 } else {
746 char *s = crm_strdup_printf("%d resource instance%s configured",
747 nresources, pcmk__plural_s(nresources));
748 pcmk_create_html_node(resources_node, "span", NULL, NULL, s);
749 free(s);
750 }
751
752 return pcmk_rc_ok;
753}
754
755PCMK__OUTPUT_ARGS("cluster-counts", "unsigned int", "int", "int", "int")
756static int
757cluster_counts_text(pcmk__output_t *out, va_list args) {
758 unsigned int nnodes = va_arg(args, unsigned int);
759 int nresources = va_arg(args, int);
760 int ndisabled = va_arg(args, int);
761 int nblocked = va_arg(args, int);
762
763 out->list_item(out, NULL, "%d node%s configured",
764 nnodes, pcmk__plural_s(nnodes));
765
766 if (ndisabled && nblocked) {
767 out->list_item(out, NULL, "%d resource instance%s configured "
768 "(%d DISABLED, %d BLOCKED from "
769 "further action due to failure)",
770 nresources, pcmk__plural_s(nresources), ndisabled,
771 nblocked);
772 } else if (ndisabled && !nblocked) {
773 out->list_item(out, NULL, "%d resource instance%s configured "
774 "(%d DISABLED)",
775 nresources, pcmk__plural_s(nresources), ndisabled);
776 } else if (!ndisabled && nblocked) {
777 out->list_item(out, NULL, "%d resource instance%s configured "
778 "(%d BLOCKED from further action "
779 "due to failure)",
780 nresources, pcmk__plural_s(nresources), nblocked);
781 } else {
782 out->list_item(out, NULL, "%d resource instance%s configured",
783 nresources, pcmk__plural_s(nresources));
784 }
785
786 return pcmk_rc_ok;
787}
788
789PCMK__OUTPUT_ARGS("cluster-counts", "unsigned int", "int", "int", "int")
790static int
791cluster_counts_xml(pcmk__output_t *out, va_list args) {
792 unsigned int nnodes = va_arg(args, unsigned int);
793 int nresources = va_arg(args, int);
794 int ndisabled = va_arg(args, int);
795 int nblocked = va_arg(args, int);
796
797 xmlNodePtr nodes_node = pcmk__output_create_xml_node(out, "nodes_configured", NULL);
798 xmlNodePtr resources_node = pcmk__output_create_xml_node(out, "resources_configured", NULL);
799
800 char *s = pcmk__itoa(nnodes);
801 crm_xml_add(nodes_node, "number", s);
802 free(s);
803
804 s = pcmk__itoa(nresources);
805 crm_xml_add(resources_node, "number", s);
806 free(s);
807
808 s = pcmk__itoa(ndisabled);
809 crm_xml_add(resources_node, "disabled", s);
810 free(s);
811
812 s = pcmk__itoa(nblocked);
813 crm_xml_add(resources_node, "blocked", s);
814 free(s);
815
816 return pcmk_rc_ok;
817}
818
819PCMK__OUTPUT_ARGS("cluster-dc", "pe_node_t *", "const char *", "const char *",
820 "char *", "int")
821static int
822cluster_dc_html(pcmk__output_t *out, va_list args) {
823 pe_node_t *dc = va_arg(args, pe_node_t *);
824 const char *quorum = va_arg(args, const char *);
825 const char *dc_version_s = va_arg(args, const char *);
826 char *dc_name = va_arg(args, char *);
827 bool mixed_version = va_arg(args, int);
828
829 xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
830
831 pcmk_create_html_node(node, "span", NULL, "bold", "Current DC: ");
832
833 if (dc) {
834 char *buf = crm_strdup_printf("%s (version %s) -", dc_name,
835 dc_version_s ? dc_version_s : "unknown");
836 pcmk_create_html_node(node, "span", NULL, NULL, buf);
837 free(buf);
838
839 if (mixed_version) {
840 pcmk_create_html_node(node, "span", NULL, "warning",
841 " MIXED-VERSION");
842 }
843 pcmk_create_html_node(node, "span", NULL, NULL, " partition");
844 if (crm_is_true(quorum)) {
845 pcmk_create_html_node(node, "span", NULL, NULL, " with");
846 } else {
847 pcmk_create_html_node(node, "span", NULL, "warning", " WITHOUT");
848 }
849 pcmk_create_html_node(node, "span", NULL, NULL, " quorum");
850 } else {
851 pcmk_create_html_node(node, "span", NULL, "warning", "NONE");
852 }
853
854 return pcmk_rc_ok;
855}
856
857PCMK__OUTPUT_ARGS("cluster-dc", "pe_node_t *", "const char *", "const char *",
858 "char *", "int")
859static int
860cluster_dc_text(pcmk__output_t *out, va_list args) {
861 pe_node_t *dc = va_arg(args, pe_node_t *);
862 const char *quorum = va_arg(args, const char *);
863 const char *dc_version_s = va_arg(args, const char *);
864 char *dc_name = va_arg(args, char *);
865 bool mixed_version = va_arg(args, int);
866
867 if (dc) {
868 out->list_item(out, "Current DC",
869 "%s (version %s) - %spartition %s quorum",
870 dc_name, dc_version_s ? dc_version_s : "unknown",
871 mixed_version ? "MIXED-VERSION " : "",
872 crm_is_true(quorum) ? "with" : "WITHOUT");
873 } else {
874 out->list_item(out, "Current DC", "NONE");
875 }
876
877 return pcmk_rc_ok;
878}
879
880PCMK__OUTPUT_ARGS("cluster-dc", "pe_node_t *", "const char *", "const char *",
881 "char *", "int")
882static int
883cluster_dc_xml(pcmk__output_t *out, va_list args) {
884 pe_node_t *dc = va_arg(args, pe_node_t *);
885 const char *quorum = va_arg(args, const char *);
886 const char *dc_version_s = va_arg(args, const char *);
887 char *dc_name G_GNUC_UNUSED = va_arg(args, char *);
888 bool mixed_version = va_arg(args, int);
889
890 if (dc) {
891 pcmk__output_create_xml_node(out, "current_dc",
892 "present", "true",
893 "version", dc_version_s ? dc_version_s : "",
894 "name", dc->details->uname,
895 "id", dc->details->id,
896 "with_quorum", pcmk__btoa(crm_is_true(quorum)),
897 "mixed_version", pcmk__btoa(mixed_version),
898 NULL);
899 } else {
900 pcmk__output_create_xml_node(out, "current_dc",
901 "present", "false",
902 NULL);
903 }
904
905 return pcmk_rc_ok;
906}
907
908PCMK__OUTPUT_ARGS("maint-mode", "unsigned long long int")
909static int
910cluster_maint_mode_text(pcmk__output_t *out, va_list args) {
911 unsigned long long flags = va_arg(args, unsigned long long);
912
914 pcmk__formatted_printf(out, "\n *** Resource management is DISABLED ***\n");
915 pcmk__formatted_printf(out, " The cluster will not attempt to start, stop or recover services\n");
916 return pcmk_rc_ok;
918 pcmk__formatted_printf(out, "\n *** Resource management is DISABLED ***\n");
919 pcmk__formatted_printf(out, " The cluster will keep all resources stopped\n");
920 return pcmk_rc_ok;
921 } else {
922 return pcmk_rc_no_output;
923 }
924}
925
926PCMK__OUTPUT_ARGS("cluster-options", "pe_working_set_t *")
927static int
928cluster_options_html(pcmk__output_t *out, va_list args) {
929 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
930
931 out->list_item(out, NULL, "STONITH of failed nodes %s",
932 pcmk_is_set(data_set->flags, pe_flag_stonith_enabled) ? "enabled" : "disabled");
933
934 out->list_item(out, NULL, "Cluster is %s",
935 pcmk_is_set(data_set->flags, pe_flag_symmetric_cluster) ? "symmetric" : "asymmetric");
936
937 switch (data_set->no_quorum_policy) {
938 case no_quorum_freeze:
939 out->list_item(out, NULL, "No quorum policy: Freeze resources");
940 break;
941
942 case no_quorum_stop:
943 out->list_item(out, NULL, "No quorum policy: Stop ALL resources");
944 break;
945
946 case no_quorum_demote:
947 out->list_item(out, NULL, "No quorum policy: Demote promotable "
948 "resources and stop all other resources");
949 break;
950
951 case no_quorum_ignore:
952 out->list_item(out, NULL, "No quorum policy: Ignore");
953 break;
954
956 out->list_item(out, NULL, "No quorum policy: Suicide");
957 break;
958 }
959
961 xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
962
963 pcmk_create_html_node(node, "span", NULL, NULL, "Resource management: ");
964 pcmk_create_html_node(node, "span", NULL, "bold", "DISABLED");
965 pcmk_create_html_node(node, "span", NULL, NULL,
966 " (the cluster will not attempt to start, stop, or recover services)");
968 xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
969
970 pcmk_create_html_node(node, "span", NULL, NULL, "Resource management: ");
971 pcmk_create_html_node(node, "span", NULL, "bold", "STOPPED");
972 pcmk_create_html_node(node, "span", NULL, NULL,
973 " (the cluster will keep all resources stopped)");
974 } else {
975 out->list_item(out, NULL, "Resource management: enabled");
976 }
977
978 return pcmk_rc_ok;
979}
980
981PCMK__OUTPUT_ARGS("cluster-options", "pe_working_set_t *")
982static int
983cluster_options_log(pcmk__output_t *out, va_list args) {
984 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
985
987 return out->info(out, "Resource management is DISABLED. The cluster will not attempt to start, stop or recover services.");
989 return out->info(out, "Resource management is DISABLED. The cluster has stopped all resources.");
990 } else {
991 return pcmk_rc_no_output;
992 }
993}
994
995PCMK__OUTPUT_ARGS("cluster-options", "pe_working_set_t *")
996static int
997cluster_options_text(pcmk__output_t *out, va_list args) {
998 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
999
1000 out->list_item(out, NULL, "STONITH of failed nodes %s",
1001 pcmk_is_set(data_set->flags, pe_flag_stonith_enabled) ? "enabled" : "disabled");
1002
1003 out->list_item(out, NULL, "Cluster is %s",
1004 pcmk_is_set(data_set->flags, pe_flag_symmetric_cluster) ? "symmetric" : "asymmetric");
1005
1006 switch (data_set->no_quorum_policy) {
1007 case no_quorum_freeze:
1008 out->list_item(out, NULL, "No quorum policy: Freeze resources");
1009 break;
1010
1011 case no_quorum_stop:
1012 out->list_item(out, NULL, "No quorum policy: Stop ALL resources");
1013 break;
1014
1015 case no_quorum_demote:
1016 out->list_item(out, NULL, "No quorum policy: Demote promotable "
1017 "resources and stop all other resources");
1018 break;
1019
1020 case no_quorum_ignore:
1021 out->list_item(out, NULL, "No quorum policy: Ignore");
1022 break;
1023
1024 case no_quorum_suicide:
1025 out->list_item(out, NULL, "No quorum policy: Suicide");
1026 break;
1027 }
1028
1029 return pcmk_rc_ok;
1030}
1031
1032PCMK__OUTPUT_ARGS("cluster-options", "pe_working_set_t *")
1033static int
1034cluster_options_xml(pcmk__output_t *out, va_list args) {
1035 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1036
1037 const char *no_quorum_policy = NULL;
1038 char *stonith_timeout_str = pcmk__itoa(data_set->stonith_timeout);
1039 char *priority_fencing_delay_str = pcmk__itoa(data_set->priority_fencing_delay * 1000);
1040
1041 switch (data_set->no_quorum_policy) {
1042 case no_quorum_freeze:
1043 no_quorum_policy = "freeze";
1044 break;
1045
1046 case no_quorum_stop:
1047 no_quorum_policy = "stop";
1048 break;
1049
1050 case no_quorum_demote:
1051 no_quorum_policy = "demote";
1052 break;
1053
1054 case no_quorum_ignore:
1055 no_quorum_policy = "ignore";
1056 break;
1057
1058 case no_quorum_suicide:
1059 no_quorum_policy = "suicide";
1060 break;
1061 }
1062
1063 pcmk__output_create_xml_node(out, "cluster_options",
1064 "stonith-enabled", pcmk__btoa(pcmk_is_set(data_set->flags, pe_flag_stonith_enabled)),
1065 "symmetric-cluster", pcmk__btoa(pcmk_is_set(data_set->flags, pe_flag_symmetric_cluster)),
1066 "no-quorum-policy", no_quorum_policy,
1067 "maintenance-mode", pcmk__btoa(pcmk_is_set(data_set->flags, pe_flag_maintenance_mode)),
1068 "stop-all-resources", pcmk__btoa(pcmk_is_set(data_set->flags, pe_flag_stop_everything)),
1069 "stonith-timeout-ms", stonith_timeout_str,
1070 "priority-fencing-delay-ms", priority_fencing_delay_str,
1071 NULL);
1072 free(stonith_timeout_str);
1073 free(priority_fencing_delay_str);
1074
1075 return pcmk_rc_ok;
1076}
1077
1078PCMK__OUTPUT_ARGS("cluster-stack", "const char *")
1079static int
1080cluster_stack_html(pcmk__output_t *out, va_list args) {
1081 const char *stack_s = va_arg(args, const char *);
1082
1083 xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
1084
1085 pcmk_create_html_node(node, "span", NULL, "bold", "Stack: ");
1086 pcmk_create_html_node(node, "span", NULL, NULL, stack_s);
1087
1088 return pcmk_rc_ok;
1089}
1090
1091PCMK__OUTPUT_ARGS("cluster-stack", "const char *")
1092static int
1093cluster_stack_text(pcmk__output_t *out, va_list args) {
1094 const char *stack_s = va_arg(args, const char *);
1095
1096 out->list_item(out, "Stack", "%s", stack_s);
1097 return pcmk_rc_ok;
1098}
1099
1100PCMK__OUTPUT_ARGS("cluster-stack", "const char *")
1101static int
1102cluster_stack_xml(pcmk__output_t *out, va_list args) {
1103 const char *stack_s = va_arg(args, const char *);
1104
1105 pcmk__output_create_xml_node(out, "stack",
1106 "type", stack_s,
1107 NULL);
1108
1109 return pcmk_rc_ok;
1110}
1111
1112PCMK__OUTPUT_ARGS("cluster-times", "const char *", "const char *", "const char *", "const char *")
1113static int
1114cluster_times_html(pcmk__output_t *out, va_list args) {
1115 const char *last_written = va_arg(args, const char *);
1116 const char *user = va_arg(args, const char *);
1117 const char *client = va_arg(args, const char *);
1118 const char *origin = va_arg(args, const char *);
1119
1120 xmlNodePtr updated_node = pcmk__output_create_xml_node(out, "li", NULL);
1121 xmlNodePtr changed_node = pcmk__output_create_xml_node(out, "li", NULL);
1122
1123 char *buf = last_changed_string(last_written, user, client, origin);
1124
1125 pcmk_create_html_node(updated_node, "span", NULL, "bold", "Last updated: ");
1126 pcmk_create_html_node(updated_node, "span", NULL, NULL,
1127 pcmk__epoch2str(NULL));
1128
1129 pcmk_create_html_node(changed_node, "span", NULL, "bold", "Last change: ");
1130 pcmk_create_html_node(changed_node, "span", NULL, NULL, buf);
1131
1132 free(buf);
1133 return pcmk_rc_ok;
1134}
1135
1136PCMK__OUTPUT_ARGS("cluster-times", "const char *", "const char *", "const char *", "const char *")
1137static int
1138cluster_times_xml(pcmk__output_t *out, va_list args) {
1139 const char *last_written = va_arg(args, const char *);
1140 const char *user = va_arg(args, const char *);
1141 const char *client = va_arg(args, const char *);
1142 const char *origin = va_arg(args, const char *);
1143
1144 pcmk__output_create_xml_node(out, "last_update",
1145 "time", pcmk__epoch2str(NULL),
1146 NULL);
1147 pcmk__output_create_xml_node(out, "last_change",
1148 "time", last_written ? last_written : "",
1149 "user", user ? user : "",
1150 "client", client ? client : "",
1151 "origin", origin ? origin : "",
1152 NULL);
1153
1154 return pcmk_rc_ok;
1155}
1156
1157PCMK__OUTPUT_ARGS("cluster-times", "const char *", "const char *", "const char *", "const char *")
1158static int
1159cluster_times_text(pcmk__output_t *out, va_list args) {
1160 const char *last_written = va_arg(args, const char *);
1161 const char *user = va_arg(args, const char *);
1162 const char *client = va_arg(args, const char *);
1163 const char *origin = va_arg(args, const char *);
1164
1165 char *buf = last_changed_string(last_written, user, client, origin);
1166
1167 out->list_item(out, "Last updated", "%s", pcmk__epoch2str(NULL));
1168 out->list_item(out, "Last change", " %s", buf);
1169
1170 free(buf);
1171 return pcmk_rc_ok;
1172}
1173
1178static void
1179failed_action_friendly(pcmk__output_t *out, xmlNodePtr xml_op,
1180 const char *op_key, const char *node_name, int rc,
1181 int status, const char *exit_reason,
1182 const char *exec_time)
1183{
1184 char *rsc_id = NULL;
1185 char *task = NULL;
1186 guint interval_ms = 0;
1187 const char *last_change_str = NULL;
1188 time_t last_change_epoch = 0;
1189 GString *str = NULL;
1190
1191 if (pcmk__str_empty(op_key)
1192 || !parse_op_key(op_key, &rsc_id, &task, &interval_ms)) {
1193 rsc_id = strdup("unknown resource");
1194 task = strdup("unknown action");
1195 interval_ms = 0;
1196 }
1197 CRM_ASSERT((rsc_id != NULL) && (task != NULL));
1198
1199 str = g_string_sized_new(256); // Should be sufficient for most messages
1200
1201 pcmk__g_strcat(str, rsc_id, " ", NULL);
1202
1203 if (interval_ms != 0) {
1204 pcmk__g_strcat(str, pcmk__readable_interval(interval_ms), "-interval ",
1205 NULL);
1206 }
1207 pcmk__g_strcat(str, crm_action_str(task, interval_ms), " on ", node_name,
1208 NULL);
1209
1210 if (status == PCMK_EXEC_DONE) {
1211 pcmk__g_strcat(str, " returned '", services_ocf_exitcode_str(rc), "'",
1212 NULL);
1213 if (!pcmk__str_empty(exit_reason)) {
1214 pcmk__g_strcat(str, " (", exit_reason, ")", NULL);
1215 }
1216
1217 } else {
1218 pcmk__g_strcat(str, " could not be executed (",
1219 pcmk_exec_status_str(status), NULL);
1220 if (!pcmk__str_empty(exit_reason)) {
1221 pcmk__g_strcat(str, ": ", exit_reason, NULL);
1222 }
1223 g_string_append_c(str, ')');
1224 }
1225
1226
1228 &last_change_epoch) == pcmk_ok) {
1229 last_change_str = pcmk__epoch2str(&last_change_epoch);
1230 if (last_change_str != NULL) {
1231 pcmk__g_strcat(str, " at ", last_change_str, NULL);
1232 }
1233 }
1234 if (!pcmk__str_empty(exec_time)) {
1235 int exec_time_ms = 0;
1236
1237 if ((pcmk__scan_min_int(exec_time, &exec_time_ms, 0) == pcmk_rc_ok)
1238 && (exec_time_ms > 0)) {
1239
1240 pcmk__g_strcat(str, " after ",
1241 pcmk__readable_interval(exec_time_ms), NULL);
1242 }
1243 }
1244
1245 out->list_item(out, NULL, "%s", str->str);
1246 g_string_free(str, TRUE);
1247 free(rsc_id);
1248 free(task);
1249}
1250
1255static void
1256failed_action_technical(pcmk__output_t *out, xmlNodePtr xml_op,
1257 const char *op_key, const char *node_name, int rc,
1258 int status, const char *exit_reason,
1259 const char *exec_time)
1260{
1261 const char *call_id = crm_element_value(xml_op, XML_LRM_ATTR_CALLID);
1262 const char *queue_time = crm_element_value(xml_op, XML_RSC_OP_T_QUEUE);
1263 const char *exit_status = services_ocf_exitcode_str(rc);
1264 const char *lrm_status = pcmk_exec_status_str(status);
1265 const char *last_change_str = NULL;
1266 time_t last_change_epoch = 0;
1267 GString *str = NULL;
1268
1269 if (pcmk__str_empty(op_key)) {
1270 op_key = "unknown operation";
1271 }
1272 if (pcmk__str_empty(exit_status)) {
1273 exit_status = "unknown exit status";
1274 }
1275 if (pcmk__str_empty(call_id)) {
1276 call_id = "unknown";
1277 }
1278
1279 str = g_string_sized_new(256);
1280
1281 g_string_append_printf(str, "%s on %s '%s' (%d): call=%s, status='%s'",
1282 op_key, node_name, exit_status, rc, call_id,
1283 lrm_status);
1284
1285 if (!pcmk__str_empty(exit_reason)) {
1286 pcmk__g_strcat(str, ", exitreason='", exit_reason, "'", NULL);
1287 }
1288
1290 &last_change_epoch) == pcmk_ok) {
1291 last_change_str = pcmk__epoch2str(&last_change_epoch);
1292 if (last_change_str != NULL) {
1293 pcmk__g_strcat(str,
1294 ", " XML_RSC_OP_LAST_CHANGE "="
1295 "'", last_change_str, "'", NULL);
1296 }
1297 }
1298 if (!pcmk__str_empty(queue_time)) {
1299 pcmk__g_strcat(str, ", queued=", queue_time, "ms", NULL);
1300 }
1301 if (!pcmk__str_empty(exec_time)) {
1302 pcmk__g_strcat(str, ", exec=", exec_time, "ms", NULL);
1303 }
1304
1305 out->list_item(out, NULL, "%s", str->str);
1306 g_string_free(str, TRUE);
1307}
1308
1309PCMK__OUTPUT_ARGS("failed-action", "xmlNodePtr", "uint32_t")
1310static int
1311failed_action_default(pcmk__output_t *out, va_list args)
1312{
1313 xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1314 uint32_t show_opts = va_arg(args, uint32_t);
1315
1316 const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
1317 const char *node_name = crm_element_value(xml_op, XML_ATTR_UNAME);
1318 const char *exit_reason = crm_element_value(xml_op,
1320 const char *exec_time = crm_element_value(xml_op, XML_RSC_OP_T_EXEC);
1321
1322 int rc;
1323 int status;
1324
1326
1328 &status, 0);
1329
1330 if (pcmk__str_empty(op_key)) {
1331 op_key = ID(xml_op);
1332 }
1333 if (pcmk__str_empty(node_name)) {
1334 node_name = "unknown node";
1335 }
1336
1337 if (pcmk_is_set(show_opts, pcmk_show_failed_detail)) {
1338 failed_action_technical(out, xml_op, op_key, node_name, rc, status,
1339 exit_reason, exec_time);
1340 } else {
1341 failed_action_friendly(out, xml_op, op_key, node_name, rc, status,
1342 exit_reason, exec_time);
1343 }
1344 return pcmk_rc_ok;
1345}
1346
1347PCMK__OUTPUT_ARGS("failed-action", "xmlNodePtr", "uint32_t")
1348static int
1349failed_action_xml(pcmk__output_t *out, va_list args) {
1350 xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1351 uint32_t show_opts G_GNUC_UNUSED = va_arg(args, uint32_t);
1352
1353 const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
1354 int rc;
1355 int status;
1356 const char *exit_reason = crm_element_value(xml_op, XML_LRM_ATTR_EXIT_REASON);
1357
1358 time_t epoch = 0;
1359 char *rc_s = NULL;
1360 char *reason_s = crm_xml_escape(exit_reason ? exit_reason : "none");
1361 xmlNodePtr node = NULL;
1362
1365 &status, 0);
1366
1367 rc_s = pcmk__itoa(rc);
1368 node = pcmk__output_create_xml_node(out, "failure",
1369 (op_key == NULL)? "id" : "op_key",
1370 (op_key == NULL)? ID(xml_op) : op_key,
1371 "node", crm_element_value(xml_op, XML_ATTR_UNAME),
1372 "exitstatus", services_ocf_exitcode_str(rc),
1373 "exitreason", pcmk__s(reason_s, ""),
1374 "exitcode", rc_s,
1375 "call", crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
1376 "status", pcmk_exec_status_str(status),
1377 NULL);
1378 free(rc_s);
1379
1381 &epoch) == pcmk_ok) && (epoch > 0)) {
1382 guint interval_ms = 0;
1383 char *s = NULL;
1384 crm_time_t *crm_when = crm_time_new_undefined();
1385 char *rc_change = NULL;
1386
1387 crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
1388 s = pcmk__itoa(interval_ms);
1389
1390 crm_time_set_timet(crm_when, &epoch);
1392
1394 "queued", crm_element_value(xml_op, XML_RSC_OP_T_QUEUE),
1395 "exec", crm_element_value(xml_op, XML_RSC_OP_T_EXEC),
1396 "interval", s,
1397 "task", crm_element_value(xml_op, XML_LRM_ATTR_TASK),
1398 NULL);
1399
1400 free(s);
1401 free(rc_change);
1402 crm_time_free(crm_when);
1403 }
1404
1405 free(reason_s);
1406 return pcmk_rc_ok;
1407}
1408
1409PCMK__OUTPUT_ARGS("failed-action-list", "pe_working_set_t *", "GList *",
1410 "GList *", "uint32_t", "bool")
1411static int
1412failed_action_list(pcmk__output_t *out, va_list args) {
1413 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1414 GList *only_node = va_arg(args, GList *);
1415 GList *only_rsc = va_arg(args, GList *);
1416 uint32_t show_opts = va_arg(args, uint32_t);
1417 bool print_spacer = va_arg(args, int);
1418
1419 xmlNode *xml_op = NULL;
1420 int rc = pcmk_rc_no_output;
1421
1422 const char *id = NULL;
1423
1424 if (xmlChildElementCount(data_set->failed) == 0) {
1425 return rc;
1426 }
1427
1428 for (xml_op = pcmk__xml_first_child(data_set->failed); xml_op != NULL;
1429 xml_op = pcmk__xml_next(xml_op)) {
1430 char *rsc = NULL;
1431
1432 if (!pcmk__str_in_list(crm_element_value(xml_op, XML_ATTR_UNAME), only_node,
1434 continue;
1435 }
1436
1437 if (pcmk_xe_mask_probe_failure(xml_op)) {
1438 continue;
1439 }
1440
1442 if (!parse_op_key(id ? id : ID(xml_op), &rsc, NULL, NULL)) {
1443 continue;
1444 }
1445
1446 if (!pcmk__str_in_list(rsc, only_rsc, pcmk__str_star_matches)) {
1447 free(rsc);
1448 continue;
1449 }
1450
1451 free(rsc);
1452
1453 PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Failed Resource Actions");
1454 out->message(out, "failed-action", xml_op, show_opts);
1455 }
1456
1457 PCMK__OUTPUT_LIST_FOOTER(out, rc);
1458 return rc;
1459}
1460
1461static void
1462status_node(pe_node_t *node, xmlNodePtr parent, uint32_t show_opts)
1463{
1464 int health = pe__node_health(node);
1465
1466 // Cluster membership
1467 if (node->details->online) {
1468 pcmk_create_html_node(parent, "span", NULL, "online", " online");
1469 } else {
1470 pcmk_create_html_node(parent, "span", NULL, "offline", " OFFLINE");
1471 }
1472
1473 // Standby mode
1474 if (node->details->standby_onfail && (node->details->running_rsc != NULL)) {
1475 pcmk_create_html_node(parent, "span", NULL, "standby",
1476 " (in standby due to on-fail,"
1477 " with active resources)");
1478 } else if (node->details->standby_onfail) {
1479 pcmk_create_html_node(parent, "span", NULL, "standby",
1480 " (in standby due to on-fail)");
1481 } else if (node->details->standby && (node->details->running_rsc != NULL)) {
1482 pcmk_create_html_node(parent, "span", NULL, "standby",
1483 " (in standby, with active resources)");
1484 } else if (node->details->standby) {
1485 pcmk_create_html_node(parent, "span", NULL, "standby", " (in standby)");
1486 }
1487
1488 // Maintenance mode
1489 if (node->details->maintenance) {
1490 pcmk_create_html_node(parent, "span", NULL, "maint",
1491 " (in maintenance mode)");
1492 }
1493
1494 // Node health
1495 if (health < 0) {
1496 pcmk_create_html_node(parent, "span", NULL, "health_red",
1497 " (health is RED)");
1498 } else if (health == 0) {
1499 pcmk_create_html_node(parent, "span", NULL, "health_yellow",
1500 " (health is YELLOW)");
1501 }
1502
1503 // Feature set
1504 if (pcmk_is_set(show_opts, pcmk_show_feature_set)) {
1505 const char *feature_set = get_node_feature_set(node);
1506 if (feature_set != NULL) {
1507 char *buf = crm_strdup_printf(", feature set %s", feature_set);
1508 pcmk_create_html_node(parent, "span", NULL, NULL, buf);
1509 free(buf);
1510 }
1511 }
1512}
1513
1514PCMK__OUTPUT_ARGS("node", "pe_node_t *", "uint32_t", "bool",
1515 "GList *", "GList *")
1516static int
1517node_html(pcmk__output_t *out, va_list args) {
1518 pe_node_t *node = va_arg(args, pe_node_t *);
1519 uint32_t show_opts = va_arg(args, uint32_t);
1520 bool full = va_arg(args, int);
1521 GList *only_node = va_arg(args, GList *);
1522 GList *only_rsc = va_arg(args, GList *);
1523
1524 char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1525
1526 if (full) {
1527 xmlNodePtr item_node;
1528
1529 if (pcmk_all_flags_set(show_opts, pcmk_show_brief | pcmk_show_rscs_by_node)) {
1530 GList *rscs = pe__filter_rsc_list(node->details->running_rsc, only_rsc);
1531
1532 out->begin_list(out, NULL, NULL, "%s:", node_name);
1533 item_node = pcmk__output_xml_create_parent(out, "li", NULL);
1534 pcmk_create_html_node(item_node, "span", NULL, NULL, "Status:");
1535 status_node(node, item_node, show_opts);
1536
1537 if (rscs != NULL) {
1538 uint32_t new_show_opts = (show_opts | pcmk_show_rsc_only) & ~pcmk_show_inactive_rscs;
1539 out->begin_list(out, NULL, NULL, "Resources");
1540 pe__rscs_brief_output(out, rscs, new_show_opts);
1541 out->end_list(out);
1542 }
1543
1545 out->end_list(out);
1546
1547 } else if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
1548 GList *lpc2 = NULL;
1549 int rc = pcmk_rc_no_output;
1550
1551 out->begin_list(out, NULL, NULL, "%s:", node_name);
1552 item_node = pcmk__output_xml_create_parent(out, "li", NULL);
1553 pcmk_create_html_node(item_node, "span", NULL, NULL, "Status:");
1554 status_node(node, item_node, show_opts);
1555
1556 for (lpc2 = node->details->running_rsc; lpc2 != NULL; lpc2 = lpc2->next) {
1557 pe_resource_t *rsc = (pe_resource_t *) lpc2->data;
1558 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Resources");
1559
1560 show_opts |= pcmk_show_rsc_only;
1561 out->message(out, crm_map_element_name(rsc->xml), show_opts,
1562 rsc, only_node, only_rsc);
1563 }
1564
1565 PCMK__OUTPUT_LIST_FOOTER(out, rc);
1567 out->end_list(out);
1568
1569 } else {
1570 char *buf = crm_strdup_printf("%s:", node_name);
1571
1572 item_node = pcmk__output_create_xml_node(out, "li", NULL);
1573 pcmk_create_html_node(item_node, "span", NULL, "bold", buf);
1574 status_node(node, item_node, show_opts);
1575
1576 free(buf);
1577 }
1578 } else {
1579 out->begin_list(out, NULL, NULL, "%s:", node_name);
1580 }
1581
1582 free(node_name);
1583 return pcmk_rc_ok;
1584}
1585
1594static const char *
1595node_text_status(pe_node_t *node)
1596{
1597 if (node->details->unclean) {
1598 if (node->details->online) {
1599 return "UNCLEAN (online)";
1600
1601 } else if (node->details->pending) {
1602 return "UNCLEAN (pending)";
1603
1604 } else {
1605 return "UNCLEAN (offline)";
1606 }
1607
1608 } else if (node->details->pending) {
1609 return "pending";
1610
1611 } else if (node->details->standby_onfail && node->details->online) {
1612 return "standby (on-fail)";
1613
1614 } else if (node->details->standby) {
1615 if (node->details->online) {
1616 if (node->details->running_rsc) {
1617 return "standby (with active resources)";
1618 } else {
1619 return "standby";
1620 }
1621 } else {
1622 return "OFFLINE (standby)";
1623 }
1624
1625 } else if (node->details->maintenance) {
1626 if (node->details->online) {
1627 return "maintenance";
1628 } else {
1629 return "OFFLINE (maintenance)";
1630 }
1631
1632 } else if (node->details->online) {
1633 return "online";
1634 }
1635
1636 return "OFFLINE";
1637}
1638
1639PCMK__OUTPUT_ARGS("node", "pe_node_t *", "uint32_t", "bool", "GList *", "GList *")
1640static int
1641node_text(pcmk__output_t *out, va_list args) {
1642 pe_node_t *node = va_arg(args, pe_node_t *);
1643 uint32_t show_opts = va_arg(args, uint32_t);
1644 bool full = va_arg(args, int);
1645 GList *only_node = va_arg(args, GList *);
1646 GList *only_rsc = va_arg(args, GList *);
1647
1648 if (full) {
1649 char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1650 GString *str = g_string_sized_new(64);
1651 int health = pe__node_health(node);
1652
1653 // Create a summary line with node type, name, and status
1654 if (pe__is_guest_node(node)) {
1655 g_string_append(str, "GuestNode");
1656 } else if (pe__is_remote_node(node)) {
1657 g_string_append(str, "RemoteNode");
1658 } else {
1659 g_string_append(str, "Node");
1660 }
1661 pcmk__g_strcat(str, " ", node_name, ": ", node_text_status(node), NULL);
1662
1663 if (health < 0) {
1664 g_string_append(str, " (health is RED)");
1665 } else if (health == 0) {
1666 g_string_append(str, " (health is YELLOW)");
1667 }
1668 if (pcmk_is_set(show_opts, pcmk_show_feature_set)) {
1669 const char *feature_set = get_node_feature_set(node);
1670 if (feature_set != NULL) {
1671 pcmk__g_strcat(str, ", feature set ", feature_set, NULL);
1672 }
1673 }
1674
1675 /* If we're grouping by node, print its resources */
1676 if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
1677 if (pcmk_is_set(show_opts, pcmk_show_brief)) {
1678 GList *rscs = pe__filter_rsc_list(node->details->running_rsc, only_rsc);
1679
1680 if (rscs != NULL) {
1681 uint32_t new_show_opts = (show_opts | pcmk_show_rsc_only) & ~pcmk_show_inactive_rscs;
1682 out->begin_list(out, NULL, NULL, "%s", str->str);
1683 out->begin_list(out, NULL, NULL, "Resources");
1684
1685 pe__rscs_brief_output(out, rscs, new_show_opts);
1686
1687 out->end_list(out);
1688 out->end_list(out);
1689
1690 g_list_free(rscs);
1691 }
1692
1693 } else {
1694 GList *gIter2 = NULL;
1695
1696 out->begin_list(out, NULL, NULL, "%s", str->str);
1697 out->begin_list(out, NULL, NULL, "Resources");
1698
1699 for (gIter2 = node->details->running_rsc; gIter2 != NULL; gIter2 = gIter2->next) {
1700 pe_resource_t *rsc = (pe_resource_t *) gIter2->data;
1701
1702 show_opts |= pcmk_show_rsc_only;
1703 out->message(out, crm_map_element_name(rsc->xml), show_opts,
1704 rsc, only_node, only_rsc);
1705 }
1706
1707 out->end_list(out);
1708 out->end_list(out);
1709 }
1710 } else {
1711 out->list_item(out, NULL, "%s", str->str);
1712 }
1713
1714 g_string_free(str, TRUE);
1715 free(node_name);
1716 } else {
1717 char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1718 out->begin_list(out, NULL, NULL, "Node: %s", node_name);
1719 free(node_name);
1720 }
1721
1722 return pcmk_rc_ok;
1723}
1724
1725PCMK__OUTPUT_ARGS("node", "pe_node_t *", "uint32_t", "bool", "GList *", "GList *")
1726static int
1727node_xml(pcmk__output_t *out, va_list args) {
1728 pe_node_t *node = va_arg(args, pe_node_t *);
1729 uint32_t show_opts G_GNUC_UNUSED = va_arg(args, uint32_t);
1730 bool full = va_arg(args, int);
1731 GList *only_node = va_arg(args, GList *);
1732 GList *only_rsc = va_arg(args, GList *);
1733
1734 if (full) {
1735 const char *node_type = "unknown";
1736 char *length_s = pcmk__itoa(g_list_length(node->details->running_rsc));
1737 int health = pe__node_health(node);
1738 const char *health_s = NULL;
1739 const char *feature_set;
1740
1741 switch (node->details->type) {
1742 case node_member:
1743 node_type = "member";
1744 break;
1745 case node_remote:
1746 node_type = "remote";
1747 break;
1748 case node_ping:
1749 node_type = "ping";
1750 break;
1751 }
1752
1753 if (health < 0) {
1754 health_s = "red";
1755 } else if (health == 0) {
1756 health_s = "yellow";
1757 } else {
1758 health_s = "green";
1759 }
1760
1761 feature_set = get_node_feature_set(node);
1762
1763 pe__name_and_nvpairs_xml(out, true, "node", 15,
1764 "name", node->details->uname,
1765 "id", node->details->id,
1766 "online", pcmk__btoa(node->details->online),
1767 "standby", pcmk__btoa(node->details->standby),
1768 "standby_onfail", pcmk__btoa(node->details->standby_onfail),
1769 "maintenance", pcmk__btoa(node->details->maintenance),
1770 "pending", pcmk__btoa(node->details->pending),
1771 "unclean", pcmk__btoa(node->details->unclean),
1772 "health", health_s,
1773 "feature_set", feature_set,
1774 "shutdown", pcmk__btoa(node->details->shutdown),
1775 "expected_up", pcmk__btoa(node->details->expected_up),
1776 "is_dc", pcmk__btoa(node->details->is_dc),
1777 "resources_running", length_s,
1778 "type", node_type);
1779
1780 if (pe__is_guest_node(node)) {
1781 xmlNodePtr xml_node = pcmk__output_xml_peek_parent(out);
1782 crm_xml_add(xml_node, "id_as_resource", node->details->remote_rsc->container->id);
1783 }
1784
1785 if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
1786 GList *lpc = NULL;
1787
1788 for (lpc = node->details->running_rsc; lpc != NULL; lpc = lpc->next) {
1789 pe_resource_t *rsc = (pe_resource_t *) lpc->data;
1790
1791 show_opts |= pcmk_show_rsc_only;
1792 out->message(out, crm_map_element_name(rsc->xml), show_opts,
1793 rsc, only_node, only_rsc);
1794 }
1795 }
1796
1797 free(length_s);
1798
1799 out->end_list(out);
1800 } else {
1802 "name", node->details->uname,
1803 NULL);
1804 }
1805
1806 return pcmk_rc_ok;
1807}
1808
1809PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "bool", "int")
1810static int
1811node_attribute_text(pcmk__output_t *out, va_list args) {
1812 const char *name = va_arg(args, const char *);
1813 const char *value = va_arg(args, const char *);
1814 bool add_extra = va_arg(args, int);
1815 int expected_score = va_arg(args, int);
1816
1817 if (add_extra) {
1818 int v;
1819
1820 if (value == NULL) {
1821 v = 0;
1822 } else {
1823 pcmk__scan_min_int(value, &v, INT_MIN);
1824 }
1825 if (v <= 0) {
1826 out->list_item(out, NULL, "%-32s\t: %-10s\t: Connectivity is lost", name, value);
1827 } else if (v < expected_score) {
1828 out->list_item(out, NULL, "%-32s\t: %-10s\t: Connectivity is degraded (Expected=%d)", name, value, expected_score);
1829 } else {
1830 out->list_item(out, NULL, "%-32s\t: %-10s", name, value);
1831 }
1832 } else {
1833 out->list_item(out, NULL, "%-32s\t: %-10s", name, value);
1834 }
1835
1836 return pcmk_rc_ok;
1837}
1838
1839PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "bool", "int")
1840static int
1841node_attribute_html(pcmk__output_t *out, va_list args) {
1842 const char *name = va_arg(args, const char *);
1843 const char *value = va_arg(args, const char *);
1844 bool add_extra = va_arg(args, int);
1845 int expected_score = va_arg(args, int);
1846
1847 if (add_extra) {
1848 int v;
1849 char *s = crm_strdup_printf("%s: %s", name, value);
1850 xmlNodePtr item_node = pcmk__output_create_xml_node(out, "li", NULL);
1851
1852 if (value == NULL) {
1853 v = 0;
1854 } else {
1855 pcmk__scan_min_int(value, &v, INT_MIN);
1856 }
1857
1858 pcmk_create_html_node(item_node, "span", NULL, NULL, s);
1859 free(s);
1860
1861 if (v <= 0) {
1862 pcmk_create_html_node(item_node, "span", NULL, "bold", "(connectivity is lost)");
1863 } else if (v < expected_score) {
1864 char *buf = crm_strdup_printf("(connectivity is degraded -- expected %d", expected_score);
1865 pcmk_create_html_node(item_node, "span", NULL, "bold", buf);
1866 free(buf);
1867 }
1868 } else {
1869 out->list_item(out, NULL, "%s: %s", name, value);
1870 }
1871
1872 return pcmk_rc_ok;
1873}
1874
1875PCMK__OUTPUT_ARGS("node-and-op", "pe_working_set_t *", "xmlNodePtr")
1876static int
1877node_and_op(pcmk__output_t *out, va_list args) {
1878 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1879 xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1880
1881 pe_resource_t *rsc = NULL;
1882 gchar *node_str = NULL;
1883 char *last_change_str = NULL;
1884
1885 const char *op_rsc = crm_element_value(xml_op, "resource");
1886 const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
1887 int status;
1888 time_t last_change = 0;
1889
1891 &status, PCMK_EXEC_UNKNOWN);
1892
1893 rsc = pe_find_resource(data_set->resources, op_rsc);
1894
1895 if (rsc) {
1896 pe_node_t *node = pe__current_node(rsc);
1897 const char *target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
1898 uint32_t show_opts = pcmk_show_rsc_only | pcmk_show_pending;
1899
1900 if (node == NULL) {
1901 node = rsc->pending_node;
1902 }
1903
1904 node_str = pcmk__native_output_string(rsc, rsc_printable_id(rsc), node,
1905 show_opts, target_role, false);
1906 } else {
1907 node_str = crm_strdup_printf("Unknown resource %s", op_rsc);
1908 }
1909
1911 &last_change) == pcmk_ok) {
1912 last_change_str = crm_strdup_printf(", %s='%s', exec=%sms",
1914 pcmk__trim(ctime(&last_change)),
1916 }
1917
1918 out->list_item(out, NULL, "%s: %s (node=%s, call=%s, rc=%s%s): %s",
1919 node_str, op_key ? op_key : ID(xml_op),
1923 last_change_str ? last_change_str : "",
1924 pcmk_exec_status_str(status));
1925
1926 g_free(node_str);
1927 free(last_change_str);
1928 return pcmk_rc_ok;
1929}
1930
1931PCMK__OUTPUT_ARGS("node-and-op", "pe_working_set_t *", "xmlNodePtr")
1932static int
1933node_and_op_xml(pcmk__output_t *out, va_list args) {
1934 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
1935 xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1936
1937 pe_resource_t *rsc = NULL;
1938 const char *op_rsc = crm_element_value(xml_op, "resource");
1939 const char *op_key = crm_element_value(xml_op, XML_LRM_ATTR_TASK_KEY);
1940 int status;
1941 time_t last_change = 0;
1942 xmlNode *node = NULL;
1943
1945 &status, PCMK_EXEC_UNKNOWN);
1946 node = pcmk__output_create_xml_node(out, "operation",
1947 "op", op_key ? op_key : ID(xml_op),
1948 "node", crm_element_value(xml_op, XML_ATTR_UNAME),
1949 "call", crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
1950 "rc", crm_element_value(xml_op, XML_LRM_ATTR_RC),
1951 "status", pcmk_exec_status_str(status),
1952 NULL);
1953
1954 rsc = pe_find_resource(data_set->resources, op_rsc);
1955
1956 if (rsc) {
1957 const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
1958 const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
1959 char *agent_tuple = NULL;
1960
1961 agent_tuple = crm_strdup_printf("%s:%s:%s", class,
1963 kind);
1964
1965 pcmk__xe_set_props(node, "rsc", rsc_printable_id(rsc),
1966 "agent", agent_tuple,
1967 NULL);
1968 free(agent_tuple);
1969 }
1970
1972 &last_change) == pcmk_ok) {
1974 pcmk__trim(ctime(&last_change)),
1976 NULL);
1977 }
1978
1979 return pcmk_rc_ok;
1980}
1981
1982PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "bool", "int")
1983static int
1984node_attribute_xml(pcmk__output_t *out, va_list args) {
1985 const char *name = va_arg(args, const char *);
1986 const char *value = va_arg(args, const char *);
1987 bool add_extra = va_arg(args, int);
1988 int expected_score = va_arg(args, int);
1989
1990 xmlNodePtr node = pcmk__output_create_xml_node(out, "attribute",
1991 "name", name,
1992 "value", value,
1993 NULL);
1994
1995 if (add_extra) {
1996 char *buf = pcmk__itoa(expected_score);
1997 crm_xml_add(node, "expected", buf);
1998 free(buf);
1999 }
2000
2001 return pcmk_rc_ok;
2002}
2003
2004PCMK__OUTPUT_ARGS("node-attribute-list", "pe_working_set_t *", "uint32_t",
2005 "bool", "GList *", "GList *")
2006static int
2007node_attribute_list(pcmk__output_t *out, va_list args) {
2008 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
2009 uint32_t show_opts = va_arg(args, uint32_t);
2010 bool print_spacer = va_arg(args, int);
2011 GList *only_node = va_arg(args, GList *);
2012 GList *only_rsc = va_arg(args, GList *);
2013
2014 int rc = pcmk_rc_no_output;
2015
2016 /* Display each node's attributes */
2017 for (GList *gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
2018 pe_node_t *node = gIter->data;
2019
2020 GList *attr_list = NULL;
2021 GHashTableIter iter;
2022 gpointer key;
2023
2024 if (!node || !node->details || !node->details->online) {
2025 continue;
2026 }
2027
2028 g_hash_table_iter_init(&iter, node->details->attrs);
2029 while (g_hash_table_iter_next (&iter, &key, NULL)) {
2030 attr_list = filter_attr_list(attr_list, key);
2031 }
2032
2033 if (attr_list == NULL) {
2034 continue;
2035 }
2036
2038 g_list_free(attr_list);
2039 continue;
2040 }
2041
2042 PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Node Attributes");
2043
2044 out->message(out, "node", node, show_opts, false, only_node, only_rsc);
2045
2046 for (GList *aIter = attr_list; aIter != NULL; aIter = aIter->next) {
2047 const char *name = aIter->data;
2048 const char *value = NULL;
2049 int expected_score = 0;
2050 bool add_extra = false;
2051
2052 value = pe_node_attribute_raw(node, name);
2053
2054 add_extra = add_extra_info(node, node->details->running_rsc,
2055 data_set, name, &expected_score);
2056
2057 /* Print attribute name and value */
2058 out->message(out, "node-attribute", name, value, add_extra,
2059 expected_score);
2060 }
2061
2062 g_list_free(attr_list);
2063 out->end_list(out);
2064 }
2065
2066 PCMK__OUTPUT_LIST_FOOTER(out, rc);
2067 return rc;
2068}
2069
2070PCMK__OUTPUT_ARGS("node-capacity", "pe_node_t *", "const char *")
2071static int
2072node_capacity(pcmk__output_t *out, va_list args)
2073{
2074 pe_node_t *node = va_arg(args, pe_node_t *);
2075 const char *comment = va_arg(args, const char *);
2076
2077 char *dump_text = crm_strdup_printf("%s: %s capacity:",
2078 comment, pe__node_name(node));
2079
2080 g_hash_table_foreach(node->details->utilization, append_dump_text, &dump_text);
2081 out->list_item(out, NULL, "%s", dump_text);
2082 free(dump_text);
2083
2084 return pcmk_rc_ok;
2085}
2086
2087PCMK__OUTPUT_ARGS("node-capacity", "pe_node_t *", "const char *")
2088static int
2089node_capacity_xml(pcmk__output_t *out, va_list args)
2090{
2091 pe_node_t *node = va_arg(args, pe_node_t *);
2092 const char *comment = va_arg(args, const char *);
2093
2094 xmlNodePtr xml_node = pcmk__output_create_xml_node(out, "capacity",
2095 "node", node->details->uname,
2096 "comment", comment,
2097 NULL);
2098 g_hash_table_foreach(node->details->utilization, add_dump_node, xml_node);
2099
2100 return pcmk_rc_ok;
2101}
2102
2103PCMK__OUTPUT_ARGS("node-history-list", "pe_working_set_t *", "pe_node_t *", "xmlNodePtr",
2104 "GList *", "GList *", "uint32_t", "uint32_t")
2105static int
2106node_history_list(pcmk__output_t *out, va_list args) {
2107 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
2108 pe_node_t *node = va_arg(args, pe_node_t *);
2109 xmlNode *node_state = va_arg(args, xmlNode *);
2110 GList *only_node = va_arg(args, GList *);
2111 GList *only_rsc = va_arg(args, GList *);
2112 uint32_t section_opts = va_arg(args, uint32_t);
2113 uint32_t show_opts = va_arg(args, uint32_t);
2114
2115 xmlNode *lrm_rsc = NULL;
2116 xmlNode *rsc_entry = NULL;
2117 int rc = pcmk_rc_no_output;
2118
2119 lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE);
2120 lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE);
2121
2122 /* Print history of each of the node's resources */
2123 for (rsc_entry = first_named_child(lrm_rsc, XML_LRM_TAG_RESOURCE);
2124 rsc_entry != NULL; rsc_entry = crm_next_same_xml(rsc_entry)) {
2125 const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID);
2127
2128 /* We can't use is_filtered here to filter group resources. For is_filtered,
2129 * we have to decide whether to check the parent or not. If we check the
2130 * parent, all elements of a group will always be printed because that's how
2131 * is_filtered works for groups. If we do not check the parent, sometimes
2132 * this will filter everything out.
2133 *
2134 * For other resource types, is_filtered is okay.
2135 */
2136 if (uber_parent(rsc)->variant == pe_group) {
2139 continue;
2140 }
2141 } else {
2142 if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
2143 continue;
2144 }
2145 }
2146
2147 if (!pcmk_is_set(section_opts, pcmk_section_operations)) {
2148 time_t last_failure = 0;
2149 int failcount = pe_get_failcount(node, rsc, &last_failure, pe_fc_default,
2150 NULL, data_set);
2151
2152 if (failcount <= 0) {
2153 continue;
2154 }
2155
2156 if (rc == pcmk_rc_no_output) {
2157 rc = pcmk_rc_ok;
2158 out->message(out, "node", node, show_opts, false, only_node,
2159 only_rsc);
2160 }
2161
2162 out->message(out, "resource-history", rsc, rsc_id, false,
2163 failcount, last_failure, false);
2164 } else {
2165 GList *op_list = get_operation_list(rsc_entry);
2167 crm_element_value(rsc_entry, XML_ATTR_ID));
2168
2169 if (op_list == NULL) {
2170 continue;
2171 }
2172
2173 if (rc == pcmk_rc_no_output) {
2174 rc = pcmk_rc_ok;
2175 out->message(out, "node", node, show_opts, false, only_node,
2176 only_rsc);
2177 }
2178
2179 out->message(out, "resource-operation-list", data_set, rsc, node,
2180 op_list, show_opts);
2181 }
2182 }
2183
2184 PCMK__OUTPUT_LIST_FOOTER(out, rc);
2185 return rc;
2186}
2187
2188PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "uint32_t", "bool")
2189static int
2190node_list_html(pcmk__output_t *out, va_list args) {
2191 GList *nodes = va_arg(args, GList *);
2192 GList *only_node = va_arg(args, GList *);
2193 GList *only_rsc = va_arg(args, GList *);
2194 uint32_t show_opts = va_arg(args, uint32_t);
2195 bool print_spacer G_GNUC_UNUSED = va_arg(args, int);
2196
2197 int rc = pcmk_rc_no_output;
2198
2199 for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
2200 pe_node_t *node = (pe_node_t *) gIter->data;
2201
2202 if (!pcmk__str_in_list(node->details->uname, only_node,
2204 continue;
2205 }
2206
2207 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Node List");
2208
2209 out->message(out, "node", node, show_opts, true, only_node, only_rsc);
2210 }
2211
2212 PCMK__OUTPUT_LIST_FOOTER(out, rc);
2213 return rc;
2214}
2215
2216PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "uint32_t", "bool")
2217static int
2218node_list_text(pcmk__output_t *out, va_list args) {
2219 GList *nodes = va_arg(args, GList *);
2220 GList *only_node = va_arg(args, GList *);
2221 GList *only_rsc = va_arg(args, GList *);
2222 uint32_t show_opts = va_arg(args, uint32_t);
2223 bool print_spacer = va_arg(args, int);
2224
2225 /* space-separated lists of node names */
2226 GString *online_nodes = NULL;
2227 GString *online_remote_nodes = NULL;
2228 GString *online_guest_nodes = NULL;
2229 GString *offline_nodes = NULL;
2230 GString *offline_remote_nodes = NULL;
2231
2232 int rc = pcmk_rc_no_output;
2233
2234 for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
2235 pe_node_t *node = (pe_node_t *) gIter->data;
2236 char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
2237
2238 if (!pcmk__str_in_list(node->details->uname, only_node,
2240 free(node_name);
2241 continue;
2242 }
2243
2244 PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Node List");
2245
2246 // Determine whether to display node individually or in a list
2247 if (node->details->unclean || node->details->pending
2248 || (node->details->standby_onfail && node->details->online)
2249 || node->details->standby || node->details->maintenance
2250 || pcmk_is_set(show_opts, pcmk_show_rscs_by_node)
2251 || pcmk_is_set(show_opts, pcmk_show_feature_set)
2252 || (pe__node_health(node) <= 0)) {
2253 // Display node individually
2254
2255 } else if (node->details->online) {
2256 // Display online node in a list
2257 if (pe__is_guest_node(node)) {
2258 pcmk__add_word(&online_guest_nodes, 1024, node_name);
2259
2260 } else if (pe__is_remote_node(node)) {
2261 pcmk__add_word(&online_remote_nodes, 1024, node_name);
2262
2263 } else {
2264 pcmk__add_word(&online_nodes, 1024, node_name);
2265 }
2266 free(node_name);
2267 continue;
2268
2269 } else {
2270 // Display offline node in a list
2271 if (pe__is_remote_node(node)) {
2272 pcmk__add_word(&offline_remote_nodes, 1024, node_name);
2273
2274 } else if (pe__is_guest_node(node)) {
2275 /* ignore offline guest nodes */
2276
2277 } else {
2278 pcmk__add_word(&offline_nodes, 1024, node_name);
2279 }
2280 free(node_name);
2281 continue;
2282 }
2283
2284 /* If we get here, node is in bad state, or we're grouping by node */
2285 out->message(out, "node", node, show_opts, true, only_node, only_rsc);
2286 free(node_name);
2287 }
2288
2289 /* If we're not grouping by node, summarize nodes by status */
2290 if (online_nodes != NULL) {
2291 out->list_item(out, "Online", "[ %s ]",
2292 (const char *) online_nodes->str);
2293 g_string_free(online_nodes, TRUE);
2294 }
2295 if (offline_nodes != NULL) {
2296 out->list_item(out, "OFFLINE", "[ %s ]",
2297 (const char *) offline_nodes->str);
2298 g_string_free(offline_nodes, TRUE);
2299 }
2300 if (online_remote_nodes) {
2301 out->list_item(out, "RemoteOnline", "[ %s ]",
2302 (const char *) online_remote_nodes->str);
2303 g_string_free(online_remote_nodes, TRUE);
2304 }
2305 if (offline_remote_nodes) {
2306 out->list_item(out, "RemoteOFFLINE", "[ %s ]",
2307 (const char *) offline_remote_nodes->str);
2308 g_string_free(offline_remote_nodes, TRUE);
2309 }
2310 if (online_guest_nodes != NULL) {
2311 out->list_item(out, "GuestOnline", "[ %s ]",
2312 (const char *) online_guest_nodes->str);
2313 g_string_free(online_guest_nodes, TRUE);
2314 }
2315
2316 PCMK__OUTPUT_LIST_FOOTER(out, rc);
2317 return rc;
2318}
2319
2320PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "uint32_t", "bool")
2321static int
2322node_list_xml(pcmk__output_t *out, va_list args) {
2323 GList *nodes = va_arg(args, GList *);
2324 GList *only_node = va_arg(args, GList *);
2325 GList *only_rsc = va_arg(args, GList *);
2326 uint32_t show_opts = va_arg(args, uint32_t);
2327 bool print_spacer G_GNUC_UNUSED = va_arg(args, int);
2328
2329 out->begin_list(out, NULL, NULL, "nodes");
2330 for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
2331 pe_node_t *node = (pe_node_t *) gIter->data;
2332
2333 if (!pcmk__str_in_list(node->details->uname, only_node,
2335 continue;
2336 }
2337
2338 out->message(out, "node", node, show_opts, true, only_node, only_rsc);
2339 }
2340 out->end_list(out);
2341
2342 return pcmk_rc_ok;
2343}
2344
2345PCMK__OUTPUT_ARGS("node-summary", "pe_working_set_t *", "GList *", "GList *",
2346 "uint32_t", "uint32_t", "bool")
2347static int
2348node_summary(pcmk__output_t *out, va_list args) {
2349 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
2350 GList *only_node = va_arg(args, GList *);
2351 GList *only_rsc = va_arg(args, GList *);
2352 uint32_t section_opts = va_arg(args, uint32_t);
2353 uint32_t show_opts = va_arg(args, uint32_t);
2354 bool print_spacer = va_arg(args, int);
2355
2356 xmlNode *node_state = NULL;
2357 xmlNode *cib_status = pcmk_find_cib_element(data_set->input,
2359 int rc = pcmk_rc_no_output;
2360
2361 if (xmlChildElementCount(cib_status) == 0) {
2362 return rc;
2363 }
2364
2365 for (node_state = first_named_child(cib_status, XML_CIB_TAG_STATE);
2366 node_state != NULL; node_state = crm_next_same_xml(node_state)) {
2367 pe_node_t *node = pe_find_node_id(data_set->nodes, ID(node_state));
2368
2369 if (!node || !node->details || !node->details->online) {
2370 continue;
2371 }
2372
2373 if (!pcmk__str_in_list(node->details->uname, only_node,
2375 continue;
2376 }
2377
2378 PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc,
2379 pcmk_is_set(section_opts, pcmk_section_operations) ? "Operations" : "Migration Summary");
2380
2381 out->message(out, "node-history-list", data_set, node, node_state,
2382 only_node, only_rsc, section_opts, show_opts);
2383 }
2384
2385 PCMK__OUTPUT_LIST_FOOTER(out, rc);
2386 return rc;
2387}
2388
2389PCMK__OUTPUT_ARGS("node-weight", "pe_resource_t *", "const char *", "const char *", "const char *")
2390static int
2391node_weight(pcmk__output_t *out, va_list args)
2392{
2393 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2394 const char *prefix = va_arg(args, const char *);
2395 const char *uname = va_arg(args, const char *);
2396 const char *score = va_arg(args, const char *);
2397
2398 if (rsc) {
2399 out->list_item(out, NULL, "%s: %s allocation score on %s: %s",
2400 prefix, rsc->id, uname, score);
2401 } else {
2402 out->list_item(out, NULL, "%s: %s = %s", prefix, uname, score);
2403 }
2404
2405 return pcmk_rc_ok;
2406}
2407
2408PCMK__OUTPUT_ARGS("node-weight", "pe_resource_t *", "const char *", "const char *", "const char *")
2409static int
2410node_weight_xml(pcmk__output_t *out, va_list args)
2411{
2412 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2413 const char *prefix = va_arg(args, const char *);
2414 const char *uname = va_arg(args, const char *);
2415 const char *score = va_arg(args, const char *);
2416
2417 xmlNodePtr node = pcmk__output_create_xml_node(out, "node_weight",
2418 "function", prefix,
2419 "node", uname,
2420 "score", score,
2421 NULL);
2422
2423 if (rsc) {
2424 crm_xml_add(node, "id", rsc->id);
2425 }
2426
2427 return pcmk_rc_ok;
2428}
2429
2430PCMK__OUTPUT_ARGS("op-history", "xmlNodePtr", "const char *", "const char *", "int", "uint32_t")
2431static int
2432op_history_text(pcmk__output_t *out, va_list args) {
2433 xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
2434 const char *task = va_arg(args, const char *);
2435 const char *interval_ms_s = va_arg(args, const char *);
2436 int rc = va_arg(args, int);
2437 uint32_t show_opts = va_arg(args, uint32_t);
2438
2439 char *buf = op_history_string(xml_op, task, interval_ms_s, rc,
2440 pcmk_is_set(show_opts, pcmk_show_timing));
2441
2442 out->list_item(out, NULL, "%s", buf);
2443
2444 free(buf);
2445 return pcmk_rc_ok;
2446}
2447
2448PCMK__OUTPUT_ARGS("op-history", "xmlNodePtr", "const char *", "const char *", "int", "uint32_t")
2449static int
2450op_history_xml(pcmk__output_t *out, va_list args) {
2451 xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
2452 const char *task = va_arg(args, const char *);
2453 const char *interval_ms_s = va_arg(args, const char *);
2454 int rc = va_arg(args, int);
2455 uint32_t show_opts = va_arg(args, uint32_t);
2456
2457 char *rc_s = pcmk__itoa(rc);
2458 xmlNodePtr node = pcmk__output_create_xml_node(out, "operation_history",
2459 "call", crm_element_value(xml_op, XML_LRM_ATTR_CALLID),
2460 "task", task,
2461 "rc", rc_s,
2462 "rc_text", services_ocf_exitcode_str(rc),
2463 NULL);
2464 free(rc_s);
2465
2466 if (interval_ms_s && !pcmk__str_eq(interval_ms_s, "0", pcmk__str_casei)) {
2467 char *s = crm_strdup_printf("%sms", interval_ms_s);
2468 crm_xml_add(node, "interval", s);
2469 free(s);
2470 }
2471
2472 if (pcmk_is_set(show_opts, pcmk_show_timing)) {
2473 const char *value = NULL;
2474 time_t epoch = 0;
2475
2477 &epoch) == pcmk_ok) && (epoch > 0)) {
2479 }
2480
2481 value = crm_element_value(xml_op, XML_RSC_OP_T_EXEC);
2482 if (value) {
2483 char *s = crm_strdup_printf("%sms", value);
2485 free(s);
2486 }
2487 value = crm_element_value(xml_op, XML_RSC_OP_T_QUEUE);
2488 if (value) {
2489 char *s = crm_strdup_printf("%sms", value);
2491 free(s);
2492 }
2493 }
2494
2495 return pcmk_rc_ok;
2496}
2497
2498PCMK__OUTPUT_ARGS("promotion-score", "pe_resource_t *", "pe_node_t *", "const char *")
2499static int
2500promotion_score(pcmk__output_t *out, va_list args)
2501{
2502 pe_resource_t *child_rsc = va_arg(args, pe_resource_t *);
2503 pe_node_t *chosen = va_arg(args, pe_node_t *);
2504 const char *score = va_arg(args, const char *);
2505
2506 out->list_item(out, NULL, "%s promotion score on %s: %s",
2507 child_rsc->id,
2508 chosen? chosen->details->uname : "none",
2509 score);
2510 return pcmk_rc_ok;
2511}
2512
2513PCMK__OUTPUT_ARGS("promotion-score", "pe_resource_t *", "pe_node_t *", "const char *")
2514static int
2515promotion_score_xml(pcmk__output_t *out, va_list args)
2516{
2517 pe_resource_t *child_rsc = va_arg(args, pe_resource_t *);
2518 pe_node_t *chosen = va_arg(args, pe_node_t *);
2519 const char *score = va_arg(args, const char *);
2520
2521 xmlNodePtr node = pcmk__output_create_xml_node(out, "promotion_score",
2522 "id", child_rsc->id,
2523 "score", score,
2524 NULL);
2525
2526 if (chosen) {
2527 crm_xml_add(node, "node", chosen->details->uname);
2528 }
2529
2530 return pcmk_rc_ok;
2531}
2532
2533PCMK__OUTPUT_ARGS("resource-config", "pe_resource_t *", "bool")
2534static int
2535resource_config(pcmk__output_t *out, va_list args) {
2536 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2537 bool raw = va_arg(args, int);
2538
2539 char *rsc_xml = formatted_xml_buf(rsc, raw);
2540
2541 out->output_xml(out, "xml", rsc_xml);
2542
2543 free(rsc_xml);
2544 return pcmk_rc_ok;
2545}
2546
2547PCMK__OUTPUT_ARGS("resource-config", "pe_resource_t *", "bool")
2548static int
2549resource_config_text(pcmk__output_t *out, va_list args) {
2550 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2551 bool raw = va_arg(args, int);
2552
2553 char *rsc_xml = formatted_xml_buf(rsc, raw);
2554
2555 pcmk__formatted_printf(out, "Resource XML:\n");
2556 out->output_xml(out, "xml", rsc_xml);
2557
2558 free(rsc_xml);
2559 return pcmk_rc_ok;
2560}
2561
2562PCMK__OUTPUT_ARGS("resource-history", "pe_resource_t *", "const char *", "bool", "int", "time_t", "bool")
2563static int
2564resource_history_text(pcmk__output_t *out, va_list args) {
2565 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2566 const char *rsc_id = va_arg(args, const char *);
2567 bool all = va_arg(args, int);
2568 int failcount = va_arg(args, int);
2569 time_t last_failure = va_arg(args, time_t);
2570 bool as_header = va_arg(args, int);
2571
2572 char *buf = resource_history_string(rsc, rsc_id, all, failcount, last_failure);
2573
2574 if (as_header) {
2575 out->begin_list(out, NULL, NULL, "%s", buf);
2576 } else {
2577 out->list_item(out, NULL, "%s", buf);
2578 }
2579
2580 free(buf);
2581 return pcmk_rc_ok;
2582}
2583
2584PCMK__OUTPUT_ARGS("resource-history", "pe_resource_t *", "const char *", "bool", "int", "time_t", "bool")
2585static int
2586resource_history_xml(pcmk__output_t *out, va_list args) {
2587 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2588 const char *rsc_id = va_arg(args, const char *);
2589 bool all = va_arg(args, int);
2590 int failcount = va_arg(args, int);
2591 time_t last_failure = va_arg(args, time_t);
2592 bool as_header = va_arg(args, int);
2593
2594 xmlNodePtr node = pcmk__output_xml_create_parent(out, "resource_history",
2595 "id", rsc_id,
2596 NULL);
2597
2598 if (rsc == NULL) {
2599 pcmk__xe_set_bool_attr(node, "orphan", true);
2600 } else if (all || failcount || last_failure > 0) {
2601 char *migration_s = pcmk__itoa(rsc->migration_threshold);
2602
2603 pcmk__xe_set_props(node, "orphan", "false",
2604 "migration-threshold", migration_s,
2605 NULL);
2606 free(migration_s);
2607
2608 if (failcount > 0) {
2609 char *s = pcmk__itoa(failcount);
2610
2612 free(s);
2613 }
2614
2615 if (last_failure > 0) {
2617 }
2618 }
2619
2620 if (!as_header) {
2622 }
2623
2624 return pcmk_rc_ok;
2625}
2626
2627static void
2628print_resource_header(pcmk__output_t *out, uint32_t show_opts)
2629{
2630 if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2631 /* Active resources have already been printed by node */
2632 out->begin_list(out, NULL, NULL, "Inactive Resources");
2633 } else if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
2634 out->begin_list(out, NULL, NULL, "Full List of Resources");
2635 } else {
2636 out->begin_list(out, NULL, NULL, "Active Resources");
2637 }
2638}
2639
2640
2641PCMK__OUTPUT_ARGS("resource-list", "pe_working_set_t *", "uint32_t", "bool",
2642 "GList *", "GList *", "bool")
2643static int
2644resource_list(pcmk__output_t *out, va_list args)
2645{
2646 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
2647 uint32_t show_opts = va_arg(args, uint32_t);
2648 bool print_summary = va_arg(args, int);
2649 GList *only_node = va_arg(args, GList *);
2650 GList *only_rsc = va_arg(args, GList *);
2651 bool print_spacer = va_arg(args, int);
2652
2653 GList *rsc_iter;
2654 int rc = pcmk_rc_no_output;
2655 bool printed_header = false;
2656
2657 /* If we already showed active resources by node, and
2658 * we're not showing inactive resources, we have nothing to do
2659 */
2660 if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node) &&
2661 !pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
2662 return rc;
2663 }
2664
2665 /* If we haven't already printed resources grouped by node,
2666 * and brief output was requested, print resource summary */
2667 if (pcmk_is_set(show_opts, pcmk_show_brief) && !pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2668 GList *rscs = pe__filter_rsc_list(data_set->resources, only_rsc);
2669
2670 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
2671 print_resource_header(out, show_opts);
2672 printed_header = true;
2673
2674 rc = pe__rscs_brief_output(out, rscs, show_opts);
2675 g_list_free(rscs);
2676 }
2677
2678 /* For each resource, display it if appropriate */
2679 for (rsc_iter = data_set->resources; rsc_iter != NULL; rsc_iter = rsc_iter->next) {
2680 pe_resource_t *rsc = (pe_resource_t *) rsc_iter->data;
2681 int x;
2682
2683 /* Complex resources may have some sub-resources active and some inactive */
2684 gboolean is_active = rsc->fns->active(rsc, TRUE);
2685 gboolean partially_active = rsc->fns->active(rsc, FALSE);
2686
2687 /* Skip inactive orphans (deleted but still in CIB) */
2688 if (pcmk_is_set(rsc->flags, pe_rsc_orphan) && !is_active) {
2689 continue;
2690
2691 /* Skip active resources if we already displayed them by node */
2692 } else if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2693 if (is_active) {
2694 continue;
2695 }
2696
2697 /* Skip primitives already counted in a brief summary */
2698 } else if (pcmk_is_set(show_opts, pcmk_show_brief) && (rsc->variant == pe_native)) {
2699 continue;
2700
2701 /* Skip resources that aren't at least partially active,
2702 * unless we're displaying inactive resources
2703 */
2704 } else if (!partially_active && !pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
2705 continue;
2706
2707 } else if (partially_active && !pe__rsc_running_on_any(rsc, only_node)) {
2708 continue;
2709 }
2710
2711 if (!printed_header) {
2712 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
2713 print_resource_header(out, show_opts);
2714 printed_header = true;
2715 }
2716
2717 /* Print this resource */
2718 x = out->message(out, crm_map_element_name(rsc->xml), show_opts, rsc,
2719 only_node, only_rsc);
2720 if (x == pcmk_rc_ok) {
2721 rc = pcmk_rc_ok;
2722 }
2723 }
2724
2725 if (print_summary && rc != pcmk_rc_ok) {
2726 if (!printed_header) {
2727 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
2728 print_resource_header(out, show_opts);
2729 printed_header = true;
2730 }
2731
2732 if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2733 out->list_item(out, NULL, "No inactive resources");
2734 } else if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
2735 out->list_item(out, NULL, "No resources");
2736 } else {
2737 out->list_item(out, NULL, "No active resources");
2738 }
2739 }
2740
2741 if (printed_header) {
2742 out->end_list(out);
2743 }
2744
2745 return rc;
2746}
2747
2748PCMK__OUTPUT_ARGS("resource-operation-list", "pe_working_set_t *", "pe_resource_t *",
2749 "pe_node_t *", "GList *", "uint32_t")
2750static int
2751resource_operation_list(pcmk__output_t *out, va_list args)
2752{
2753 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
2754 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2755 pe_node_t *node = va_arg(args, pe_node_t *);
2756 GList *op_list = va_arg(args, GList *);
2757 uint32_t show_opts = va_arg(args, uint32_t);
2758
2759 GList *gIter = NULL;
2760 int rc = pcmk_rc_no_output;
2761
2762 /* Print each operation */
2763 for (gIter = op_list; gIter != NULL; gIter = gIter->next) {
2764 xmlNode *xml_op = (xmlNode *) gIter->data;
2765 const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
2766 const char *interval_ms_s = crm_element_value(xml_op,
2768 const char *op_rc = crm_element_value(xml_op, XML_LRM_ATTR_RC);
2769 int op_rc_i;
2770
2771 pcmk__scan_min_int(op_rc, &op_rc_i, 0);
2772
2773 /* Display 0-interval monitors as "probe" */
2774 if (pcmk__str_eq(task, CRMD_ACTION_STATUS, pcmk__str_casei)
2775 && pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches | pcmk__str_casei)) {
2776 task = "probe";
2777 }
2778
2779 /* If this is the first printed operation, print heading for resource */
2780 if (rc == pcmk_rc_no_output) {
2781 time_t last_failure = 0;
2782 int failcount = pe_get_failcount(node, rsc, &last_failure, pe_fc_default,
2783 NULL, data_set);
2784
2785 out->message(out, "resource-history", rsc, rsc_printable_id(rsc), true,
2786 failcount, last_failure, true);
2787 rc = pcmk_rc_ok;
2788 }
2789
2790 /* Print the operation */
2791 out->message(out, "op-history", xml_op, task, interval_ms_s,
2792 op_rc_i, show_opts);
2793 }
2794
2795 /* Free the list we created (no need to free the individual items) */
2796 g_list_free(op_list);
2797
2798 PCMK__OUTPUT_LIST_FOOTER(out, rc);
2799 return rc;
2800}
2801
2802PCMK__OUTPUT_ARGS("resource-util", "pe_resource_t *", "pe_node_t *", "const char *")
2803static int
2804resource_util(pcmk__output_t *out, va_list args)
2805{
2806 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2807 pe_node_t *node = va_arg(args, pe_node_t *);
2808 const char *fn = va_arg(args, const char *);
2809
2810 char *dump_text = crm_strdup_printf("%s: %s utilization on %s:",
2811 fn, rsc->id, pe__node_name(node));
2812
2813 g_hash_table_foreach(rsc->utilization, append_dump_text, &dump_text);
2814 out->list_item(out, NULL, "%s", dump_text);
2815 free(dump_text);
2816
2817 return pcmk_rc_ok;
2818}
2819
2820PCMK__OUTPUT_ARGS("resource-util", "pe_resource_t *", "pe_node_t *", "const char *")
2821static int
2822resource_util_xml(pcmk__output_t *out, va_list args)
2823{
2824 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
2825 pe_node_t *node = va_arg(args, pe_node_t *);
2826 const char *fn = va_arg(args, const char *);
2827
2828 xmlNodePtr xml_node = pcmk__output_create_xml_node(out, "utilization",
2829 "resource", rsc->id,
2830 "node", node->details->uname,
2831 "function", fn,
2832 NULL);
2833 g_hash_table_foreach(rsc->utilization, add_dump_node, xml_node);
2834
2835 return pcmk_rc_ok;
2836}
2837
2838PCMK__OUTPUT_ARGS("ticket", "pe_ticket_t *")
2839static int
2840ticket_html(pcmk__output_t *out, va_list args) {
2841 pe_ticket_t *ticket = va_arg(args, pe_ticket_t *);
2842
2843 if (ticket->last_granted > -1) {
2844 char *time = pcmk__format_named_time("last-granted",
2845 ticket->last_granted);
2846
2847 out->list_item(out, NULL, "%s:\t%s%s %s", ticket->id,
2848 ticket->granted ? "granted" : "revoked",
2849 ticket->standby ? " [standby]" : "",
2850 time);
2851 free(time);
2852 } else {
2853 out->list_item(out, NULL, "%s:\t%s%s", ticket->id,
2854 ticket->granted ? "granted" : "revoked",
2855 ticket->standby ? " [standby]" : "");
2856 }
2857
2858 return pcmk_rc_ok;
2859}
2860
2861PCMK__OUTPUT_ARGS("ticket", "pe_ticket_t *")
2862static int
2863ticket_text(pcmk__output_t *out, va_list args) {
2864 pe_ticket_t *ticket = va_arg(args, pe_ticket_t *);
2865
2866 if (ticket->last_granted > -1) {
2867 char *time = pcmk__format_named_time("last-granted",
2868 ticket->last_granted);
2869
2870 out->list_item(out, ticket->id, "%s%s %s",
2871 ticket->granted ? "granted" : "revoked",
2872 ticket->standby ? " [standby]" : "",
2873 time);
2874 free(time);
2875 } else {
2876 out->list_item(out, ticket->id, "%s%s",
2877 ticket->granted ? "granted" : "revoked",
2878 ticket->standby ? " [standby]" : "");
2879 }
2880
2881 return pcmk_rc_ok;
2882}
2883
2884PCMK__OUTPUT_ARGS("ticket", "pe_ticket_t *")
2885static int
2886ticket_xml(pcmk__output_t *out, va_list args) {
2887 pe_ticket_t *ticket = va_arg(args, pe_ticket_t *);
2888
2889 xmlNodePtr node = NULL;
2890
2891 node = pcmk__output_create_xml_node(out, "ticket",
2892 "id", ticket->id,
2893 "status", ticket->granted ? "granted" : "revoked",
2894 "standby", pcmk__btoa(ticket->standby),
2895 NULL);
2896
2897 if (ticket->last_granted > -1) {
2898 crm_xml_add(node, "last-granted", pcmk__epoch2str(&ticket->last_granted));
2899 }
2900
2901 return pcmk_rc_ok;
2902}
2903
2904PCMK__OUTPUT_ARGS("ticket-list", "pe_working_set_t *", "bool")
2905static int
2906ticket_list(pcmk__output_t *out, va_list args) {
2907 pe_working_set_t *data_set = va_arg(args, pe_working_set_t *);
2908 bool print_spacer = va_arg(args, int);
2909
2910 GHashTableIter iter;
2911 gpointer key, value;
2912
2913 if (g_hash_table_size(data_set->tickets) == 0) {
2914 return pcmk_rc_no_output;
2915 }
2916
2917 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
2918
2919 /* Print section heading */
2920 out->begin_list(out, NULL, NULL, "Tickets");
2921
2922 /* Print each ticket */
2923 g_hash_table_iter_init(&iter, data_set->tickets);
2924 while (g_hash_table_iter_next(&iter, &key, &value)) {
2925 pe_ticket_t *ticket = (pe_ticket_t *) value;
2926 out->message(out, "ticket", ticket);
2927 }
2928
2929 /* Close section */
2930 out->end_list(out);
2931 return pcmk_rc_ok;
2932}
2933
2934static pcmk__message_entry_t fmt_functions[] = {
2935 { "ban", "default", ban_text },
2936 { "ban", "html", ban_html },
2937 { "ban", "xml", ban_xml },
2938 { "ban-list", "default", ban_list },
2939 { "bundle", "default", pe__bundle_text },
2940 { "bundle", "xml", pe__bundle_xml },
2941 { "bundle", "html", pe__bundle_html },
2942 { "clone", "default", pe__clone_default },
2943 { "clone", "xml", pe__clone_xml },
2944 { "cluster-counts", "default", cluster_counts_text },
2945 { "cluster-counts", "html", cluster_counts_html },
2946 { "cluster-counts", "xml", cluster_counts_xml },
2947 { "cluster-dc", "default", cluster_dc_text },
2948 { "cluster-dc", "html", cluster_dc_html },
2949 { "cluster-dc", "xml", cluster_dc_xml },
2950 { "cluster-options", "default", cluster_options_text },
2951 { "cluster-options", "html", cluster_options_html },
2952 { "cluster-options", "log", cluster_options_log },
2953 { "cluster-options", "xml", cluster_options_xml },
2954 { "cluster-summary", "default", cluster_summary },
2955 { "cluster-summary", "html", cluster_summary_html },
2956 { "cluster-stack", "default", cluster_stack_text },
2957 { "cluster-stack", "html", cluster_stack_html },
2958 { "cluster-stack", "xml", cluster_stack_xml },
2959 { "cluster-times", "default", cluster_times_text },
2960 { "cluster-times", "html", cluster_times_html },
2961 { "cluster-times", "xml", cluster_times_xml },
2962 { "failed-action", "default", failed_action_default },
2963 { "failed-action", "xml", failed_action_xml },
2964 { "failed-action-list", "default", failed_action_list },
2965 { "group", "default", pe__group_default},
2966 { "group", "xml", pe__group_xml },
2967 { "maint-mode", "text", cluster_maint_mode_text },
2968 { "node", "default", node_text },
2969 { "node", "html", node_html },
2970 { "node", "xml", node_xml },
2971 { "node-and-op", "default", node_and_op },
2972 { "node-and-op", "xml", node_and_op_xml },
2973 { "node-capacity", "default", node_capacity },
2974 { "node-capacity", "xml", node_capacity_xml },
2975 { "node-history-list", "default", node_history_list },
2976 { "node-list", "default", node_list_text },
2977 { "node-list", "html", node_list_html },
2978 { "node-list", "xml", node_list_xml },
2979 { "node-weight", "default", node_weight },
2980 { "node-weight", "xml", node_weight_xml },
2981 { "node-attribute", "default", node_attribute_text },
2982 { "node-attribute", "html", node_attribute_html },
2983 { "node-attribute", "xml", node_attribute_xml },
2984 { "node-attribute-list", "default", node_attribute_list },
2985 { "node-summary", "default", node_summary },
2986 { "op-history", "default", op_history_text },
2987 { "op-history", "xml", op_history_xml },
2988 { "primitive", "default", pe__resource_text },
2989 { "primitive", "xml", pe__resource_xml },
2990 { "primitive", "html", pe__resource_html },
2991 { "promotion-score", "default", promotion_score },
2992 { "promotion-score", "xml", promotion_score_xml },
2993 { "resource-config", "default", resource_config },
2994 { "resource-config", "text", resource_config_text },
2995 { "resource-history", "default", resource_history_text },
2996 { "resource-history", "xml", resource_history_xml },
2997 { "resource-list", "default", resource_list },
2998 { "resource-operation-list", "default", resource_operation_list },
2999 { "resource-util", "default", resource_util },
3000 { "resource-util", "xml", resource_util_xml },
3001 { "ticket", "default", ticket_text },
3002 { "ticket", "html", ticket_html },
3003 { "ticket", "xml", ticket_xml },
3004 { "ticket-list", "default", ticket_list },
3005
3006 { NULL, NULL, NULL }
3007};
3008
3009void
3011 pcmk__register_messages(out, fmt_functions);
3012}
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition: agents.c:31
@ pcmk_ra_cap_provider
Definition: agents.h:57
const char * parent
Definition: cib.c:25
const char * name
Definition: cib.c:24
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition: cib.c:153
#define PCMK__LAST_FAILURE_PREFIX
Definition: internal.h:312
#define PCMK__FAIL_COUNT_PREFIX
Definition: internal.h:311
char * pcmk__format_nvpair(const char *name, const char *value, const char *units)
Definition: nvpair.c:284
char * pcmk__format_named_time(const char *name, time_t epoch_time)
Definition: nvpair.c:303
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
Definition: nvpair.c:942
uint64_t flags
Definition: remote.c:3
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: operations.c:185
bool pcmk_xe_mask_probe_failure(xmlNode *xml_op)
Definition: operations.c:562
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
gboolean crm_is_true(const char *s)
Definition: strings.c:416
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
#define RSC_ROLE_PROMOTED_LEGACY_S
Definition: common.h:116
rsc_role_e
Possible roles that a resource can be in.
Definition: common.h:92
@ RSC_ROLE_PROMOTED
Definition: common.h:97
#define RSC_ROLE_PROMOTED_S
Definition: common.h:114
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:912
GHashTable * pe_rsc_params(pe_resource_t *rsc, const pe_node_t *node, pe_working_set_t *data_set)
Get a table of resource parameters.
Definition: complex.c:429
enum crm_ais_msg_types type
Definition: cpg.c:3
char uname[MAX_NAME]
Definition: cpg.c:5
#define CRMD_ACTION_NOTIFY
Definition: crm.h:185
#define CRMD_ACTION_STATUS
Definition: crm.h:188
#define CRM_ATTR_FEATURE_SET
Definition: crm.h:124
void crm_time_set_timet(crm_time_t *target, const time_t *source)
Definition: iso8601.c:1259
#define crm_time_log_timeofday
Definition: iso8601.h:68
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:140
char * crm_time_as_string(const crm_time_t *dt, int flags)
Definition: iso8601.c:500
#define crm_time_log_with_timezone
Definition: iso8601.h:69
#define crm_time_log_date
Definition: iso8601.h:67
crm_time_t * crm_time_new_undefined(void)
Allocate memory for an uninitialized time object.
Definition: iso8601.c:116
struct crm_time_s crm_time_t
Definition: iso8601.h:32
const char * pcmk__epoch2str(const time_t *when)
Definition: iso8601.c:1730
const char * pcmk__readable_interval(guint interval_ms)
Definition: iso8601.c:1765
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define XML_LRM_TAG_RSC_OP
Definition: msg_xml.h:268
#define ID(x)
Definition: msg_xml.h:468
#define XML_ATTR_UNAME
Definition: msg_xml.h:157
#define XML_RSC_ATTR_TARGET_ROLE
Definition: msg_xml.h:236
#define XML_NVPAIR_ATTR_VALUE
Definition: msg_xml.h:392
#define XML_LRM_TAG_RESOURCES
Definition: msg_xml.h:266
#define XML_LRM_ATTR_TASK_KEY
Definition: msg_xml.h:301
#define XML_CIB_TAG_STATE
Definition: msg_xml.h:204
#define XML_LRM_ATTR_OPSTATUS
Definition: msg_xml.h:310
#define XML_ATTR_ID
Definition: msg_xml.h:134
#define XML_ATTR_HAVE_QUORUM
Definition: msg_xml.h:123
#define XML_RSC_OP_T_EXEC
Definition: msg_xml.h:322
#define XML_LRM_ATTR_EXIT_REASON
Definition: msg_xml.h:318
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:270
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:269
#define XML_ATTR_UPDATE_CLIENT
Definition: msg_xml.h:143
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:300
#define XML_ATTR_TYPE
Definition: msg_xml.h:138
#define XML_CIB_ATTR_WRITTEN
Definition: msg_xml.h:131
#define XML_CIB_TAG_STATUS
Definition: msg_xml.h:185
#define XML_RSC_OP_LAST_CHANGE
Definition: msg_xml.h:320
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:312
#define XML_CIB_TAG_LRM
Definition: msg_xml.h:265
#define XML_ATTR_UPDATE_ORIG
Definition: msg_xml.h:142
#define XML_ATTR_UPDATE_USER
Definition: msg_xml.h:144
#define XML_LRM_ATTR_RC
Definition: msg_xml.h:311
#define XML_RSC_OP_T_QUEUE
Definition: msg_xml.h:323
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:298
#define XML_LRM_TAG_RESOURCE
Definition: msg_xml.h:267
pe_working_set_t * data_set
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:517
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition: nvpair.c:610
int crm_element_value_epoch(const xmlNode *xml, const char *name, time_t *dest)
Retrieve the seconds-since-epoch value of an XML attribute.
Definition: nvpair.c:638
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_show_rscs_by_node
Definition: output.h:64
@ pcmk_show_timing
Definition: output.h:62
@ pcmk_show_failed_detail
Definition: output.h:67
@ pcmk_show_pending
Definition: output.h:65
@ pcmk_show_brief
Definition: output.h:58
@ pcmk_show_rsc_only
Definition: output.h:66
@ pcmk_show_inactive_rscs
Definition: output.h:63
@ pcmk_show_node_id
Definition: output.h:60
@ pcmk_show_feature_set
Definition: output.h:68
@ pcmk_section_times
Definition: output.h:29
@ pcmk_section_operations
Definition: output.h:36
@ pcmk_section_options
Definition: output.h:31
@ pcmk_section_stack
Definition: output.h:27
@ pcmk_section_counts
Definition: output.h:30
@ pcmk_section_dc
Definition: output.h:28
@ pcmk_section_maint_mode
Definition: output.h:43
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__output_xml_push_parent(pcmk__output_t *out, xmlNodePtr parent)
Definition: output_xml.c:500
xmlNodePtr pcmk__output_xml_peek_parent(pcmk__output_t *out)
Definition: output_xml.c:526
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)
int pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name, size_t pairs_count,...)
Definition: pe_output.c:544
char * pe__node_display_name(pe_node_t *node, bool print_detail)
Definition: pe_output.c:491
#define FILTER_STR
Definition: pe_output.c:19
void pe__register_messages(pcmk__output_t *out)
Definition: pe_output.c:3010
PCMK__OUTPUT_ARGS("ban-list", "pe_working_set_t *", "const char *", "GList *", "uint32_t", "bool")
Definition: pe_output.c:653
@ no_quorum_suicide
Definition: pe_types.h:67
@ no_quorum_demote
Definition: pe_types.h:68
@ no_quorum_freeze
Definition: pe_types.h:64
@ no_quorum_ignore
Definition: pe_types.h:66
@ no_quorum_stop
Definition: pe_types.h:65
#define pe_flag_maintenance_mode
Definition: pe_types.h:97
#define pe_flag_symmetric_cluster
Definition: pe_types.h:96
#define pe_rsc_orphan
Definition: pe_types.h:256
#define pe_flag_stop_everything
Definition: pe_types.h:106
node_type
Definition: pe_types.h:71
@ node_ping
Definition: pe_types.h:72
@ node_remote
Definition: pe_types.h:74
@ node_member
Definition: pe_types.h:73
@ pe_group
Definition: pe_types.h:39
@ pe_native
Definition: pe_types.h:38
#define pe_flag_stonith_enabled
Definition: pe_types.h:99
int pe__clone_xml(pcmk__output_t *out, va_list args)
Definition: clone.c:755
gchar * pcmk__native_output_string(pe_resource_t *rsc, const char *name, pe_node_t *node, uint32_t show_opts, const char *target_role, bool show_nodes)
Definition: native.c:542
const char * pe_node_attribute_raw(const pe_node_t *node, const char *name)
Definition: common.c:562
bool pe__rsc_running_on_any(pe_resource_t *rsc, GList *node_list)
Definition: utils.c:754
int pe__bundle_xml(pcmk__output_t *out, va_list args)
Definition: bundle.c:1223
int pe__group_xml(pcmk__output_t *out, va_list args)
Definition: group.c:331
int pe__bundle_html(pcmk__output_t *out, va_list args)
Definition: bundle.c:1347
int pe_get_failcount(pe_node_t *node, pe_resource_t *rsc, time_t *last_failure, uint32_t flags, xmlNode *xml_op, pe_working_set_t *data_set)
Definition: failcounts.c:251
int pe__clone_default(pcmk__output_t *out, va_list args)
Definition: clone.c:817
GList * pe__filter_rsc_list(GList *rscs, GList *filter)
Definition: utils.c:774
int pe__bundle_text(pcmk__output_t *out, va_list args)
Definition: bundle.c:1475
int pe__node_health(pe_node_t *node)
Definition: pe_health.c:112
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
Definition: pe_actions.c:1627
int pe__rscs_brief_output(pcmk__output_t *out, GList *rsc_list, unsigned int options)
@ pe_fc_default
Definition: internal.h:344
int pe__resource_xml(pcmk__output_t *out, va_list args)
Definition: native.c:914
int pe__group_default(pcmk__output_t *out, va_list args)
Definition: group.c:381
int pe__resource_text(pcmk__output_t *out, va_list args)
Definition: native.c:1015
int pe__resource_html(pcmk__output_t *out, va_list args)
Definition: native.c:991
bool pe__is_guest_node(const pe_node_t *node)
Definition: remote.c:33
bool pe__is_guest_or_remote_node(const pe_node_t *node)
Definition: remote.c:41
bool pe__is_remote_node(const pe_node_t *node)
Definition: remote.c:25
#define CRM_ASSERT(expr)
Definition: results.h:42
@ pcmk_rc_no_output
Definition: results.h:118
@ pcmk_rc_ok
Definition: results.h:148
#define pcmk_ok
Definition: results.h:68
@ PCMK_EXEC_DONE
Action completed, result is known.
Definition: results.h:312
@ PCMK_EXEC_UNKNOWN
Used only to initialize variables.
Definition: results.h:310
pe_node_t * pe_find_node_id(GList *node_list, const char *id)
Definition: status.c:427
const char * rsc_printable_id(pe_resource_t *rsc)
Definition: utils.c:568
pe_resource_t * pe_find_resource(GList *rsc_list, const char *id_rh)
Definition: status.c:391
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition: strings.c:127
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition: strings.c:883
#define pcmk__plural_s(i)
char * pcmk__trim(char *str)
Definition: strings.c:456
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:928
@ pcmk__str_none
@ pcmk__str_null_matches
@ pcmk__str_star_matches
@ pcmk__str_casei
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1214
This structure contains everything that makes up a single output formatter.
void(*) void(* list_item)(pcmk__output_t *out, const char *name, const char *format,...) G_GNUC_PRINTF(3
void(* begin_list)(pcmk__output_t *out, const char *singular_noun, const char *plural_noun, const char *format,...) G_GNUC_PRINTF(4
pe_resource_t * rsc_lh
Definition: internal.h:188
enum rsc_role_e role_filter
Definition: internal.h:189
int weight
Definition: pe_types.h:249
struct pe_node_shared_s * details
Definition: pe_types.h:252
GHashTable * attrs
Definition: pe_types.h:241
gboolean shutdown
Definition: pe_types.h:226
gboolean expected_up
Definition: pe_types.h:227
const char * id
Definition: pe_types.h:215
gboolean online
Definition: pe_types.h:220
gboolean standby_onfail
Definition: pe_types.h:222
const char * uname
Definition: pe_types.h:216
gboolean standby
Definition: pe_types.h:221
GHashTable * utilization
Definition: pe_types.h:242
pe_resource_t * remote_rsc
Definition: pe_types.h:237
gboolean is_dc
Definition: pe_types.h:228
gboolean unclean
Definition: pe_types.h:224
gboolean maintenance
Definition: pe_types.h:229
enum node_type type
Definition: pe_types.h:217
gboolean pending
Definition: pe_types.h:223
GList * running_rsc
Definition: pe_types.h:238
enum pe_obj_types variant
Definition: pe_types.h:338
GHashTable * meta
Definition: pe_types.h:380
GList * children
Definition: pe_types.h:384
int migration_threshold
Definition: pe_types.h:351
pe_resource_t * container
Definition: pe_types.h:387
char * id
Definition: pe_types.h:329
xmlNode * xml
Definition: pe_types.h:331
GHashTable * utilization
Definition: pe_types.h:382
pe_node_t * pending_node
Definition: pe_types.h:390
unsigned long long flags
Definition: pe_types.h:355
xmlNode * orig_xml
Definition: pe_types.h:332
resource_object_functions_t * fns
Definition: pe_types.h:340
char * id
Definition: pe_types.h:453
gboolean standby
Definition: pe_types.h:456
gboolean granted
Definition: pe_types.h:454
time_t last_granted
Definition: pe_types.h:455
int blocked_resources
Definition: pe_types.h:189
xmlNode * input
Definition: pe_types.h:144
GList * resources
Definition: pe_types.h:165
pe_node_t * dc_node
Definition: pe_types.h:149
xmlNode * failed
Definition: pe_types.h:172
int disabled_resources
Definition: pe_types.h:190
unsigned long long flags
Definition: pe_types.h:153
enum pe_quorum_policy no_quorum_policy
Definition: pe_types.h:156
GHashTable * tickets
Definition: pe_types.h:159
GList * placement_constraints
Definition: pe_types.h:166
GList * nodes
Definition: pe_types.h:164
int priority_fencing_delay
Definition: pe_types.h:197
gboolean(* is_filtered)(pe_resource_t *, GList *, gboolean)
Definition: pe_types.h:58
gboolean(* active)(pe_resource_t *, gboolean)
Definition: pe_types.h:53
char * dump_xml_formatted(xmlNode *msg)
Definition: xml.c:2106
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2930
xmlNode * pcmk_create_xml_text_node(xmlNode *parent, const char *name, const char *content)
Definition: xml.c:774
const xmlChar * pcmkXmlStr
Definition: xml.h:50
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:214
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2956
char * crm_xml_escape(const char *text)
Replace special characters with their XML escape sequences.
Definition: xml.c:1406
xmlNode * pcmk_create_html_node(xmlNode *parent, const char *element_name, const char *id, const char *class_name, const char *text)
Definition: xml.c:786
xmlNode * find_xml_node(const xmlNode *root, const char *search_path, gboolean must_find)
Definition: xml.c:470
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