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