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