pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pe_output.c
Go to the documentation of this file.
1/*
2 * Copyright 2019-2025 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
12#include <stdint.h>
13
14#include <libxml/tree.h> // xmlNode
15
17#include <crm/common/output.h>
19#include <crm/cib/util.h>
20#include <crm/common/xml.h>
22
23const char *
24pe__resource_description(const pcmk_resource_t *rsc, uint32_t show_opts)
25{
26 const char * desc = NULL;
27
28 // User-supplied description
29 if (pcmk_any_flags_set(show_opts, pcmk_show_rsc_only|pcmk_show_description)) {
31 }
32 return desc;
33}
34
35/* Never display node attributes whose name starts with one of these prefixes */
36#define FILTER_STR { PCMK__FAIL_COUNT_PREFIX, PCMK__LAST_FAILURE_PREFIX, \
37 PCMK__NODE_ATTR_SHUTDOWN, PCMK_NODE_ATTR_TERMINATE, \
38 PCMK_NODE_ATTR_STANDBY, "#", NULL }
39
40static int
41compare_attribute(gconstpointer a, gconstpointer b)
42{
43 int rc;
44
45 rc = strcmp((const char *)a, (const char *)b);
46
47 return rc;
48}
49
65static bool
66add_extra_info(const pcmk_node_t *node, GList *rsc_list,
67 pcmk_scheduler_t *scheduler, const char *attrname,
68 int *expected_score)
69{
70 GList *gIter = NULL;
71
72 for (gIter = rsc_list; gIter != NULL; gIter = gIter->next) {
73 pcmk_resource_t *rsc = (pcmk_resource_t *) gIter->data;
74 const char *type = g_hash_table_lookup(rsc->priv->meta,
76 const char *name = NULL;
77 GHashTable *params = NULL;
78
79 if (rsc->priv->children != NULL) {
80 if (add_extra_info(node, rsc->priv->children, scheduler,
81 attrname, expected_score)) {
82 return true;
83 }
84 }
85
86 if (!pcmk__strcase_any_of(type, "ping", "pingd", NULL)) {
87 continue;
88 }
89
90 params = pe_rsc_params(rsc, node, scheduler);
91 name = g_hash_table_lookup(params, PCMK_XA_NAME);
92
93 if (name == NULL) {
94 name = "pingd";
95 }
96
97 /* To identify the resource with the attribute name. */
98 if (pcmk__str_eq(name, attrname, pcmk__str_casei)) {
99 int host_list_num = 0;
100 const char *hosts = g_hash_table_lookup(params, "host_list");
101 const char *multiplier = g_hash_table_lookup(params, "multiplier");
102 int multiplier_i;
103
104 if (hosts) {
105 char **host_list = g_strsplit(hosts, " ", 0);
106 host_list_num = g_strv_length(host_list);
107 g_strfreev(host_list);
108 }
109
110 if ((multiplier == NULL)
111 || (pcmk__scan_min_int(multiplier, &multiplier_i,
112 INT_MIN) != pcmk_rc_ok)) {
113 /* The ocf:pacemaker:ping resource agent defaults multiplier to
114 * 1. The agent currently does not handle invalid text, but it
115 * should, and this would be a reasonable choice ...
116 */
117 multiplier_i = 1;
118 }
119 *expected_score = host_list_num * multiplier_i;
120
121 return true;
122 }
123 }
124 return false;
125}
126
127static GList *
128filter_attr_list(GList *attr_list, char *name)
129{
130 int i;
131 const char *filt_str[] = FILTER_STR;
132
133 CRM_CHECK(name != NULL, return attr_list);
134
135 /* filtering automatic attributes */
136 for (i = 0; filt_str[i] != NULL; i++) {
137 if (g_str_has_prefix(name, filt_str[i])) {
138 return attr_list;
139 }
140 }
141
142 return g_list_insert_sorted(attr_list, name, compare_attribute);
143}
144
145static GList *
146get_operation_list(xmlNode *rsc_entry) {
147 GList *op_list = NULL;
148 xmlNode *rsc_op = NULL;
149
150 for (rsc_op = pcmk__xe_first_child(rsc_entry, PCMK__XE_LRM_RSC_OP, NULL,
151 NULL);
152 rsc_op != NULL; rsc_op = pcmk__xe_next(rsc_op, PCMK__XE_LRM_RSC_OP)) {
153
154 const char *task = crm_element_value(rsc_op, PCMK_XA_OPERATION);
155
156 if (pcmk__str_eq(task, PCMK_ACTION_NOTIFY, pcmk__str_none)) {
157 continue; // Ignore notify actions
158 } else {
159 int exit_status;
160
162 &exit_status, 0);
163 if ((exit_status == CRM_EX_NOT_RUNNING)
164 && pcmk__str_eq(task, PCMK_ACTION_MONITOR, pcmk__str_none)
165 && pcmk__str_eq(crm_element_value(rsc_op, PCMK_META_INTERVAL),
167 continue; // Ignore probes that found the resource not running
168 }
169 }
170
171 op_list = g_list_append(op_list, rsc_op);
172 }
173
174 op_list = g_list_sort(op_list, sort_op_by_callid);
175 return op_list;
176}
177
178static void
179add_dump_node(gpointer key, gpointer value, gpointer user_data)
180{
181 xmlNodePtr node = user_data;
182
183 node = pcmk__xe_create(node, (const char *) key);
184 pcmk__xe_set_content(node, "%s", (const char *) value);
185}
186
187static void
188append_dump_text(gpointer key, gpointer value, gpointer user_data)
189{
190 char **dump_text = user_data;
191 char *new_text = crm_strdup_printf("%s %s=%s",
192 *dump_text, (char *)key, (char *)value);
193
194 free(*dump_text);
195 *dump_text = new_text;
196}
197
198#define XPATH_STACK "//" PCMK_XE_NVPAIR \
199 "[@" PCMK_XA_NAME "='" \
200 PCMK_OPT_CLUSTER_INFRASTRUCTURE "']"
201
202static const char *
203get_cluster_stack(pcmk_scheduler_t *scheduler)
204{
205 xmlNode *stack = pcmk__xpath_find_one(scheduler->input->doc, XPATH_STACK,
206 LOG_DEBUG);
207
208 if (stack != NULL) {
209 return crm_element_value(stack, PCMK_XA_VALUE);
210 }
211 return PCMK_VALUE_UNKNOWN;
212}
213
214static char *
215last_changed_string(const char *last_written, const char *user,
216 const char *client, const char *origin) {
217 if (last_written != NULL || user != NULL || client != NULL || origin != NULL) {
218 return crm_strdup_printf("%s%s%s%s%s%s%s",
219 last_written ? last_written : "",
220 user ? " by " : "",
221 user ? user : "",
222 client ? " via " : "",
223 client ? client : "",
224 origin ? " on " : "",
225 origin ? origin : "");
226 } else {
227 return strdup("");
228 }
229}
230
231static char *
232op_history_string(xmlNode *xml_op, const char *task, const char *interval_ms_s,
233 int rc, bool print_timing) {
234 const char *call = crm_element_value(xml_op, PCMK__XA_CALL_ID);
235 char *interval_str = NULL;
236 char *buf = NULL;
237
238 if (interval_ms_s && !pcmk__str_eq(interval_ms_s, "0", pcmk__str_casei)) {
239 char *pair = pcmk__format_nvpair(PCMK_XA_INTERVAL, interval_ms_s, "ms");
240 interval_str = crm_strdup_printf(" %s", pair);
241 free(pair);
242 }
243
244 if (print_timing) {
245 char *last_change_str = NULL;
246 char *exec_str = NULL;
247 char *queue_str = NULL;
248
249 const char *value = NULL;
250
251 time_t epoch = 0;
252
254 &epoch) == pcmk_ok)
255 && (epoch > 0)) {
256 char *epoch_str = pcmk__epoch2str(&epoch, 0);
257
258 last_change_str = crm_strdup_printf(" %s=\"%s\"",
260 pcmk__s(epoch_str, ""));
261 free(epoch_str);
262 }
263
264 value = crm_element_value(xml_op, PCMK_XA_EXEC_TIME);
265 if (value) {
266 char *pair = pcmk__format_nvpair(PCMK_XA_EXEC_TIME, value, "ms");
267 exec_str = crm_strdup_printf(" %s", pair);
268 free(pair);
269 }
270
271 value = crm_element_value(xml_op, PCMK_XA_QUEUE_TIME);
272 if (value) {
273 char *pair = pcmk__format_nvpair(PCMK_XA_QUEUE_TIME, value, "ms");
274 queue_str = crm_strdup_printf(" %s", pair);
275 free(pair);
276 }
277
278 buf = crm_strdup_printf("(%s) %s:%s%s%s%s rc=%d (%s)", call, task,
279 interval_str ? interval_str : "",
280 last_change_str ? last_change_str : "",
281 exec_str ? exec_str : "",
282 queue_str ? queue_str : "",
283 rc, crm_exit_str(rc));
284
285 if (last_change_str) {
286 free(last_change_str);
287 }
288
289 if (exec_str) {
290 free(exec_str);
291 }
292
293 if (queue_str) {
294 free(queue_str);
295 }
296 } else {
297 buf = crm_strdup_printf("(%s) %s%s%s", call, task,
298 interval_str ? ":" : "",
299 interval_str ? interval_str : "");
300 }
301
302 if (interval_str) {
303 free(interval_str);
304 }
305
306 return buf;
307}
308
309static char *
310resource_history_string(pcmk_resource_t *rsc, const char *rsc_id, bool all,
311 int failcount, time_t last_failure) {
312 char *buf = NULL;
313
314 if (rsc == NULL) {
315 buf = crm_strdup_printf("%s: orphan", rsc_id);
316 } else if (all || failcount || last_failure > 0) {
317 char *failcount_s = NULL;
318 char *lastfail_s = NULL;
319
320 if (failcount > 0) {
321 failcount_s = crm_strdup_printf(" %s=%d",
322 PCMK_XA_FAIL_COUNT, failcount);
323 } else {
324 failcount_s = strdup("");
325 }
326 if (last_failure > 0) {
327 buf = pcmk__epoch2str(&last_failure, 0);
328 lastfail_s = crm_strdup_printf(" %s='%s'",
330 free(buf);
331 }
332
334 rsc_id, rsc->priv->ban_after_failures,
335 failcount_s, pcmk__s(lastfail_s, ""));
336 free(failcount_s);
337 free(lastfail_s);
338 } else {
339 buf = crm_strdup_printf("%s:", rsc_id);
340 }
341
342 return buf;
343}
344
355static const char *
356get_node_feature_set(const pcmk_node_t *node)
357{
358 if (node->details->online
360 && !pcmk__is_pacemaker_remote_node(node)) {
361
362 const char *feature_set = g_hash_table_lookup(node->priv->attrs,
364
365 /* The feature set attribute is present since 3.15.1. If it is missing,
366 * then the node must be running an earlier version.
367 */
368 return pcmk__s(feature_set, "<3.15.1");
369 }
370 return NULL;
371}
372
373static bool
374is_mixed_version(pcmk_scheduler_t *scheduler)
375{
376 const char *feature_set = NULL;
377 for (GList *gIter = scheduler->nodes; gIter != NULL; gIter = gIter->next) {
378 pcmk_node_t *node = gIter->data;
379 const char *node_feature_set = get_node_feature_set(node);
380 if (node_feature_set != NULL) {
381 if (feature_set == NULL) {
382 feature_set = node_feature_set;
383 } else if (strcmp(feature_set, node_feature_set) != 0) {
384 return true;
385 }
386 }
387 }
388 return false;
389}
390
391static void
392formatted_xml_buf(const pcmk_resource_t *rsc, GString *xml_buf, bool raw)
393{
394 if (raw && (rsc->priv->orig_xml != NULL)) {
396 0);
397 } else {
398 pcmk__xml_string(rsc->priv->xml, pcmk__xml_fmt_pretty, xml_buf, 0);
399 }
400}
401
402#define XPATH_DC_VERSION "//" PCMK_XE_NVPAIR \
403 "[@" PCMK_XA_NAME "='" PCMK_OPT_DC_VERSION "']"
404
405PCMK__OUTPUT_ARGS("cluster-summary", "pcmk_scheduler_t *",
406 "enum pcmk_pacemakerd_state", "uint32_t", "uint32_t")
407static int
408cluster_summary(pcmk__output_t *out, va_list args) {
410 enum pcmk_pacemakerd_state pcmkd_state =
411 (enum pcmk_pacemakerd_state) va_arg(args, int);
412 uint32_t section_opts = va_arg(args, uint32_t);
413 uint32_t show_opts = va_arg(args, uint32_t);
414
415 int rc = pcmk_rc_no_output;
416 const char *stack_s = get_cluster_stack(scheduler);
417
418 if (pcmk_is_set(section_opts, pcmk_section_stack)) {
419 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
420 out->message(out, "cluster-stack", stack_s, pcmkd_state);
421 }
422
423 if (pcmk_is_set(section_opts, pcmk_section_dc)) {
424 xmlNode *dc_version = pcmk__xpath_find_one(scheduler->input->doc,
425 XPATH_DC_VERSION, LOG_DEBUG);
426 const char *dc_version_s = dc_version?
428 : NULL;
429 const char *quorum = crm_element_value(scheduler->input,
432 bool mixed_version = is_mixed_version(scheduler);
433
434 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
435 out->message(out, "cluster-dc", scheduler->dc_node, quorum,
436 dc_version_s, dc_name, mixed_version);
437 free(dc_name);
438 }
439
440 if (pcmk_is_set(section_opts, pcmk_section_times)) {
441 const char *last_written = crm_element_value(scheduler->input,
443 const char *user = crm_element_value(scheduler->input,
445 const char *client = crm_element_value(scheduler->input,
447 const char *origin = crm_element_value(scheduler->input,
449
450 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
451 out->message(out, "cluster-times", scheduler->priv->local_node_name,
452 last_written, user, client, origin);
453 }
454
455 if (pcmk_is_set(section_opts, pcmk_section_counts)) {
456 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
457 out->message(out, "cluster-counts", g_list_length(scheduler->nodes),
461 }
462
463 if (pcmk_is_set(section_opts, pcmk_section_options)) {
464 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
465 out->message(out, "cluster-options", scheduler);
466 }
467
469
470 if (pcmk_is_set(section_opts, pcmk_section_maint_mode)) {
471 if (out->message(out, "maint-mode", scheduler->flags) == pcmk_rc_ok) {
472 rc = pcmk_rc_ok;
473 }
474 }
475
476 return rc;
477}
478
479PCMK__OUTPUT_ARGS("cluster-summary", "pcmk_scheduler_t *",
480 "enum pcmk_pacemakerd_state", "uint32_t", "uint32_t")
481static int
482cluster_summary_html(pcmk__output_t *out, va_list args) {
484 enum pcmk_pacemakerd_state pcmkd_state =
485 (enum pcmk_pacemakerd_state) va_arg(args, int);
486 uint32_t section_opts = va_arg(args, uint32_t);
487 uint32_t show_opts = va_arg(args, uint32_t);
488
489 int rc = pcmk_rc_no_output;
490 const char *stack_s = get_cluster_stack(scheduler);
491
492 if (pcmk_is_set(section_opts, pcmk_section_stack)) {
493 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
494 out->message(out, "cluster-stack", stack_s, pcmkd_state);
495 }
496
497 /* Always print DC if none, even if not requested */
498 if ((scheduler->dc_node == NULL)
499 || pcmk_is_set(section_opts, pcmk_section_dc)) {
500 xmlNode *dc_version = pcmk__xpath_find_one(scheduler->input->doc,
501 XPATH_DC_VERSION, LOG_DEBUG);
502 const char *dc_version_s = dc_version?
504 : NULL;
505 const char *quorum = crm_element_value(scheduler->input,
508 bool mixed_version = is_mixed_version(scheduler);
509
510 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
511 out->message(out, "cluster-dc", scheduler->dc_node, quorum,
512 dc_version_s, dc_name, mixed_version);
513 free(dc_name);
514 }
515
516 if (pcmk_is_set(section_opts, pcmk_section_times)) {
517 const char *last_written = crm_element_value(scheduler->input,
519 const char *user = crm_element_value(scheduler->input,
521 const char *client = crm_element_value(scheduler->input,
523 const char *origin = crm_element_value(scheduler->input,
525
526 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
527 out->message(out, "cluster-times", scheduler->priv->local_node_name,
528 last_written, user, client, origin);
529 }
530
531 if (pcmk_is_set(section_opts, pcmk_section_counts)) {
532 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Cluster Summary");
533 out->message(out, "cluster-counts", g_list_length(scheduler->nodes),
537 }
538
539 if (pcmk_is_set(section_opts, pcmk_section_options)) {
540 /* Kind of a hack - close the list we may have opened earlier in this
541 * function so we can put all the options into their own list. We
542 * only want to do this on HTML output, though.
543 */
545
546 out->begin_list(out, NULL, NULL, "Config Options");
547 out->message(out, "cluster-options", scheduler);
548 }
549
551
552 if (pcmk_is_set(section_opts, pcmk_section_maint_mode)) {
553 if (out->message(out, "maint-mode", scheduler->flags) == pcmk_rc_ok) {
554 rc = pcmk_rc_ok;
555 }
556 }
557
558 return rc;
559}
560
561char *
562pe__node_display_name(pcmk_node_t *node, bool print_detail)
563{
564 char *node_name;
565 const char *node_host = NULL;
566 const char *node_id = NULL;
567 int name_len;
568
569 pcmk__assert((node != NULL) && (node->priv->name != NULL));
570
571 /* Host is displayed only if this is a guest node and detail is requested */
572 if (print_detail && pcmk__is_guest_or_bundle_node(node)) {
573 const pcmk_resource_t *launcher = NULL;
574 const pcmk_node_t *host_node = NULL;
575
576 launcher = node->priv->remote->priv->launcher;
577 host_node = pcmk__current_node(launcher);
578
579 if (host_node && host_node->details) {
580 node_host = host_node->priv->name;
581 }
582 if (node_host == NULL) {
583 node_host = ""; /* so we at least get "uname@" to indicate guest */
584 }
585 }
586
587 /* Node ID is displayed if different from uname and detail is requested */
588 if (print_detail
589 && !pcmk__str_eq(node->priv->name, node->priv->id,
591 node_id = node->priv->id;
592 }
593
594 /* Determine name length */
595 name_len = strlen(node->priv->name) + 1;
596 if (node_host) {
597 name_len += strlen(node_host) + 1; /* "@node_host" */
598 }
599 if (node_id) {
600 name_len += strlen(node_id) + 3; /* + " (node_id)" */
601 }
602
603 /* Allocate and populate display name */
604 node_name = pcmk__assert_alloc(name_len, sizeof(char));
605 strcpy(node_name, node->priv->name);
606 if (node_host) {
607 strcat(node_name, "@");
608 strcat(node_name, node_host);
609 }
610 if (node_id) {
611 strcat(node_name, " (");
612 strcat(node_name, node_id);
613 strcat(node_name, ")");
614 }
615 return node_name;
616}
617
618int
619pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name,
620 ...)
621{
622 xmlNodePtr xml_node = NULL;
623 va_list pairs;
624
625 pcmk__assert(tag_name != NULL);
626
627 xml_node = pcmk__output_xml_peek_parent(out);
628 pcmk__assert(xml_node != NULL);
629 xml_node = pcmk__xe_create(xml_node, tag_name);
630
631 va_start(pairs, tag_name);
632 pcmk__xe_set_propv(xml_node, pairs);
633 va_end(pairs);
634
635 if (is_list) {
636 pcmk__output_xml_push_parent(out, xml_node);
637 }
638 return pcmk_rc_ok;
639}
640
641static const char *
642role_desc(enum rsc_role_e role)
643{
644 if (role == pcmk_role_promoted) {
645 return "in " PCMK_ROLE_PROMOTED " role ";
646 }
647 return "";
648}
649
650PCMK__OUTPUT_ARGS("ban", "pcmk_node_t *", "pcmk__location_t *", "uint32_t")
651static int
652ban_html(pcmk__output_t *out, va_list args) {
653 pcmk_node_t *pe_node = va_arg(args, pcmk_node_t *);
654 pcmk__location_t *location = va_arg(args, pcmk__location_t *);
655 uint32_t show_opts = va_arg(args, uint32_t);
656
657 char *node_name = pe__node_display_name(pe_node,
658 pcmk_is_set(show_opts, pcmk_show_node_id));
659 char *buf = crm_strdup_printf("%s\tprevents %s from running %son %s",
660 location->id, location->rsc->id,
661 role_desc(location->role_filter), node_name);
662
663 pcmk__output_create_html_node(out, "li", NULL, NULL, buf);
664
665 free(node_name);
666 free(buf);
667 return pcmk_rc_ok;
668}
669
670PCMK__OUTPUT_ARGS("ban", "pcmk_node_t *", "pcmk__location_t *", "uint32_t")
671static int
672ban_text(pcmk__output_t *out, va_list args) {
673 pcmk_node_t *pe_node = va_arg(args, pcmk_node_t *);
674 pcmk__location_t *location = va_arg(args, pcmk__location_t *);
675 uint32_t show_opts = va_arg(args, uint32_t);
676
677 char *node_name = pe__node_display_name(pe_node,
678 pcmk_is_set(show_opts, pcmk_show_node_id));
679 out->list_item(out, NULL, "%s\tprevents %s from running %son %s",
680 location->id, location->rsc->id,
681 role_desc(location->role_filter), node_name);
682
683 free(node_name);
684 return pcmk_rc_ok;
685}
686
687PCMK__OUTPUT_ARGS("ban", "pcmk_node_t *", "pcmk__location_t *", "uint32_t")
688static int
689ban_xml(pcmk__output_t *out, va_list args) {
690 pcmk_node_t *pe_node = va_arg(args, pcmk_node_t *);
691 pcmk__location_t *location = va_arg(args, pcmk__location_t *);
692 uint32_t show_opts G_GNUC_UNUSED = va_arg(args, uint32_t);
693
694 const char *promoted_only = pcmk__btoa(location->role_filter == pcmk_role_promoted);
695 char *weight_s = pcmk__itoa(pe_node->assign->score);
696
698 PCMK_XA_ID, location->id,
699 PCMK_XA_RESOURCE, location->rsc->id,
700 PCMK_XA_NODE, pe_node->priv->name,
701 PCMK_XA_WEIGHT, weight_s,
702 PCMK_XA_PROMOTED_ONLY, promoted_only,
703 /* This is a deprecated alias for
704 * promoted_only. Removing it will break
705 * backward compatibility of the API schema,
706 * which will require an API schema major
707 * version bump.
708 */
709 PCMK__XA_PROMOTED_ONLY_LEGACY, promoted_only,
710 NULL);
711
712 free(weight_s);
713 return pcmk_rc_ok;
714}
715
716PCMK__OUTPUT_ARGS("ban-list", "pcmk_scheduler_t *", "const char *", "GList *",
717 "uint32_t", "bool")
718static int
719ban_list(pcmk__output_t *out, va_list args) {
721 const char *prefix = va_arg(args, const char *);
722 GList *only_rsc = va_arg(args, GList *);
723 uint32_t show_opts = va_arg(args, uint32_t);
724 bool print_spacer = va_arg(args, int);
725
726 GList *gIter, *gIter2;
727 int rc = pcmk_rc_no_output;
728
729 /* Print each ban */
730 for (gIter = scheduler->priv->location_constraints;
731 gIter != NULL; gIter = gIter->next) {
732 pcmk__location_t *location = gIter->data;
733 const pcmk_resource_t *rsc = location->rsc;
734
735 if (prefix != NULL && !g_str_has_prefix(location->id, prefix)) {
736 continue;
737 }
738
739 if (!pcmk__str_in_list(rsc_printable_id(rsc), only_rsc,
742 only_rsc, pcmk__str_star_matches)) {
743 continue;
744 }
745
746 for (gIter2 = location->nodes; gIter2 != NULL; gIter2 = gIter2->next) {
747 pcmk_node_t *node = (pcmk_node_t *) gIter2->data;
748
749 if (node->assign->score < 0) {
750 PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Negative Location Constraints");
751 out->message(out, "ban", node, location, show_opts);
752 }
753 }
754 }
755
757 return rc;
758}
759
760PCMK__OUTPUT_ARGS("cluster-counts", "unsigned int", "int", "int", "int")
761static int
762cluster_counts_html(pcmk__output_t *out, va_list args) {
763 unsigned int nnodes = va_arg(args, unsigned int);
764 int nresources = va_arg(args, int);
765 int ndisabled = va_arg(args, int);
766 int nblocked = va_arg(args, int);
767
768 xmlNodePtr nodes_node = pcmk__output_create_xml_node(out, "li", NULL);
769 xmlNodePtr resources_node = pcmk__output_create_xml_node(out, "li", NULL);
770 xmlNode *child = NULL;
771
772 child = pcmk__html_create(nodes_node, PCMK__XE_SPAN, NULL, NULL);
773 pcmk__xe_set_content(child, "%d node%s configured",
774 nnodes, pcmk__plural_s(nnodes));
775
776 if (ndisabled && nblocked) {
777 child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
778 pcmk__xe_set_content(child, "%d resource instance%s configured (%d ",
779 nresources, pcmk__plural_s(nresources), ndisabled);
780
781 child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL,
783 pcmk__xe_set_content(child, "DISABLED");
784
785 child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
786 pcmk__xe_set_content(child, ", %d ", nblocked);
787
788 child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL,
790 pcmk__xe_set_content(child, "BLOCKED");
791
792 child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
793 pcmk__xe_set_content(child, " from further action due to failure)");
794
795 } else if (ndisabled && !nblocked) {
796 child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
797 pcmk__xe_set_content(child, "%d resource instance%s configured (%d ",
798 nresources, pcmk__plural_s(nresources),
799 ndisabled);
800
801 child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL,
803 pcmk__xe_set_content(child, "DISABLED");
804
805 child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
806 pcmk__xe_set_content(child, ")");
807
808 } else if (!ndisabled && nblocked) {
809 child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
810 pcmk__xe_set_content(child, "%d resource instance%s configured (%d ",
811 nresources, pcmk__plural_s(nresources),
812 nblocked);
813
814 child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL,
816 pcmk__xe_set_content(child, "BLOCKED");
817
818 child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
819 pcmk__xe_set_content(child, " from further action due to failure)");
820
821 } else {
822 child = pcmk__html_create(resources_node, PCMK__XE_SPAN, NULL, NULL);
823 pcmk__xe_set_content(child, "%d resource instance%s configured",
824 nresources, pcmk__plural_s(nresources));
825 }
826
827 return pcmk_rc_ok;
828}
829
830PCMK__OUTPUT_ARGS("cluster-counts", "unsigned int", "int", "int", "int")
831static int
832cluster_counts_text(pcmk__output_t *out, va_list args) {
833 unsigned int nnodes = va_arg(args, unsigned int);
834 int nresources = va_arg(args, int);
835 int ndisabled = va_arg(args, int);
836 int nblocked = va_arg(args, int);
837
838 out->list_item(out, NULL, "%d node%s configured",
839 nnodes, pcmk__plural_s(nnodes));
840
841 if (ndisabled && nblocked) {
842 out->list_item(out, NULL, "%d resource instance%s configured "
843 "(%d DISABLED, %d BLOCKED from "
844 "further action due to failure)",
845 nresources, pcmk__plural_s(nresources), ndisabled,
846 nblocked);
847 } else if (ndisabled && !nblocked) {
848 out->list_item(out, NULL, "%d resource instance%s configured "
849 "(%d DISABLED)",
850 nresources, pcmk__plural_s(nresources), ndisabled);
851 } else if (!ndisabled && nblocked) {
852 out->list_item(out, NULL, "%d resource instance%s configured "
853 "(%d BLOCKED from further action "
854 "due to failure)",
855 nresources, pcmk__plural_s(nresources), nblocked);
856 } else {
857 out->list_item(out, NULL, "%d resource instance%s configured",
858 nresources, pcmk__plural_s(nresources));
859 }
860
861 return pcmk_rc_ok;
862}
863
864PCMK__OUTPUT_ARGS("cluster-counts", "unsigned int", "int", "int", "int")
865static int
866cluster_counts_xml(pcmk__output_t *out, va_list args) {
867 unsigned int nnodes = va_arg(args, unsigned int);
868 int nresources = va_arg(args, int);
869 int ndisabled = va_arg(args, int);
870 int nblocked = va_arg(args, int);
871
872 xmlNodePtr nodes_node = NULL;
873 xmlNodePtr resources_node = NULL;
874 char *s = NULL;
875
877 NULL);
878 resources_node = pcmk__output_create_xml_node(out,
880 NULL);
881
882 s = pcmk__itoa(nnodes);
883 crm_xml_add(nodes_node, PCMK_XA_NUMBER, s);
884 free(s);
885
886 s = pcmk__itoa(nresources);
887 crm_xml_add(resources_node, PCMK_XA_NUMBER, s);
888 free(s);
889
890 s = pcmk__itoa(ndisabled);
891 crm_xml_add(resources_node, PCMK_XA_DISABLED, s);
892 free(s);
893
894 s = pcmk__itoa(nblocked);
895 crm_xml_add(resources_node, PCMK_XA_BLOCKED, s);
896 free(s);
897
898 return pcmk_rc_ok;
899}
900
901PCMK__OUTPUT_ARGS("cluster-dc", "pcmk_node_t *", "const char *", "const char *",
902 "char *", "int")
903static int
904cluster_dc_html(pcmk__output_t *out, va_list args) {
905 pcmk_node_t *dc = va_arg(args, pcmk_node_t *);
906 const char *quorum = va_arg(args, const char *);
907 const char *dc_version_s = va_arg(args, const char *);
908 char *dc_name = va_arg(args, char *);
909 bool mixed_version = va_arg(args, int);
910
911 xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
912 xmlNode *child = NULL;
913
915 pcmk__xe_set_content(child, "Current DC: ");
916
917 if (dc) {
918 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
919 pcmk__xe_set_content(child, "%s (version %s) -",
920 dc_name, pcmk__s(dc_version_s, "unknown"));
921
922 if (mixed_version) {
923 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL,
925 pcmk__xe_set_content(child, " MIXED-VERSION");
926 }
927
928 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
929 pcmk__xe_set_content(child, " partition");
930
931 if (crm_is_true(quorum)) {
932 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
933 pcmk__xe_set_content(child, " with");
934
935 } else {
936 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL,
938 pcmk__xe_set_content(child, " WITHOUT");
939 }
940
941 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
942 pcmk__xe_set_content(child, " quorum");
943
944 } else {
945 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL,
947 pcmk__xe_set_content(child, "NONE");
948 }
949
950 return pcmk_rc_ok;
951}
952
953PCMK__OUTPUT_ARGS("cluster-dc", "pcmk_node_t *", "const char *", "const char *",
954 "char *", "int")
955static int
956cluster_dc_text(pcmk__output_t *out, va_list args) {
957 pcmk_node_t *dc = va_arg(args, pcmk_node_t *);
958 const char *quorum = va_arg(args, const char *);
959 const char *dc_version_s = va_arg(args, const char *);
960 char *dc_name = va_arg(args, char *);
961 bool mixed_version = va_arg(args, int);
962
963 if (dc) {
964 out->list_item(out, "Current DC",
965 "%s (version %s) - %spartition %s quorum",
966 dc_name, dc_version_s ? dc_version_s : "unknown",
967 mixed_version ? "MIXED-VERSION " : "",
968 crm_is_true(quorum) ? "with" : "WITHOUT");
969 } else {
970 out->list_item(out, "Current DC", "NONE");
971 }
972
973 return pcmk_rc_ok;
974}
975
976PCMK__OUTPUT_ARGS("cluster-dc", "pcmk_node_t *", "const char *", "const char *",
977 "char *", "int")
978static int
979cluster_dc_xml(pcmk__output_t *out, va_list args) {
980 pcmk_node_t *dc = va_arg(args, pcmk_node_t *);
981 const char *quorum = va_arg(args, const char *);
982 const char *dc_version_s = va_arg(args, const char *);
983 char *dc_name G_GNUC_UNUSED = va_arg(args, char *);
984 bool mixed_version = va_arg(args, int);
985
986 if (dc) {
987 const char *with_quorum = pcmk__btoa(crm_is_true(quorum));
988 const char *mixed_version_s = pcmk__btoa(mixed_version);
989
992 PCMK_XA_VERSION, pcmk__s(dc_version_s, ""),
993 PCMK_XA_NAME, dc->priv->name,
994 PCMK_XA_ID, dc->priv->id,
995 PCMK_XA_WITH_QUORUM, with_quorum,
996 PCMK_XA_MIXED_VERSION, mixed_version_s,
997 NULL);
998 } else {
1001 NULL);
1002 }
1003
1004 return pcmk_rc_ok;
1005}
1006
1007PCMK__OUTPUT_ARGS("maint-mode", "uint64_t")
1008static int
1009cluster_maint_mode_text(pcmk__output_t *out, va_list args) {
1010 uint64_t flags = va_arg(args, uint64_t);
1011
1013 pcmk__formatted_printf(out, "\n *** Resource management is DISABLED ***\n");
1014 pcmk__formatted_printf(out, " The cluster will not attempt to start, stop or recover services\n");
1015 return pcmk_rc_ok;
1016 } else if (pcmk_is_set(flags, pcmk__sched_stop_all)) {
1017 pcmk__formatted_printf(out, "\n *** Resource management is DISABLED ***\n");
1018 pcmk__formatted_printf(out, " The cluster will keep all resources stopped\n");
1019 return pcmk_rc_ok;
1020 } else {
1021 return pcmk_rc_no_output;
1022 }
1023}
1024
1025PCMK__OUTPUT_ARGS("cluster-options", "pcmk_scheduler_t *")
1026static int
1027cluster_options_html(pcmk__output_t *out, va_list args) {
1028 pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
1029
1031 out->list_item(out, NULL, "STONITH of failed nodes enabled");
1032 } else {
1033 out->list_item(out, NULL, "STONITH of failed nodes disabled");
1034 }
1035
1037 out->list_item(out, NULL, "Cluster is symmetric");
1038 } else {
1039 out->list_item(out, NULL, "Cluster is asymmetric");
1040 }
1041
1042 switch (scheduler->no_quorum_policy) {
1043 /* @COMPAT These should say something like "resources that require
1044 * quorum" since resources with requires="nothing" are unaffected, but
1045 * it would be a good idea to investigate whether any major projects
1046 * search for this text first
1047 */
1049 out->list_item(out, NULL, "No quorum policy: Freeze resources");
1050 break;
1051
1053 out->list_item(out, NULL, "No quorum policy: Stop ALL resources");
1054 break;
1055
1057 out->list_item(out, NULL, "No quorum policy: Demote promotable "
1058 "resources and stop all other resources");
1059 break;
1060
1062 out->list_item(out, NULL, "No quorum policy: Ignore");
1063 break;
1064
1066 out->list_item(out, NULL,
1067 "No quorum policy: Fence nodes in partition");
1068 break;
1069 }
1070
1072 xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
1073 xmlNode *child = NULL;
1074
1075 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1076 pcmk__xe_set_content(child, "Resource management: ");
1077
1078 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, PCMK__VALUE_BOLD);
1079 pcmk__xe_set_content(child, "DISABLED");
1080
1081 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1083 " (the cluster will not attempt to start, stop,"
1084 " or recover services)");
1085
1087 xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
1088 xmlNode *child = NULL;
1089
1090 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1091 pcmk__xe_set_content(child, "Resource management: ");
1092
1093 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, PCMK__VALUE_BOLD);
1094 pcmk__xe_set_content(child, "STOPPED");
1095
1096 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1098 " (the cluster will keep all resources stopped)");
1099
1100 } else {
1101 out->list_item(out, NULL, "Resource management: enabled");
1102 }
1103
1104 return pcmk_rc_ok;
1105}
1106
1107PCMK__OUTPUT_ARGS("cluster-options", "pcmk_scheduler_t *")
1108static int
1109cluster_options_log(pcmk__output_t *out, va_list args) {
1110 pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
1111
1113 return out->info(out, "Resource management is DISABLED. The cluster will not attempt to start, stop or recover services.");
1115 return out->info(out, "Resource management is DISABLED. The cluster has stopped all resources.");
1116 } else {
1117 return pcmk_rc_no_output;
1118 }
1119}
1120
1121PCMK__OUTPUT_ARGS("cluster-options", "pcmk_scheduler_t *")
1122static int
1123cluster_options_text(pcmk__output_t *out, va_list args) {
1124 pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
1125
1127 out->list_item(out, NULL, "STONITH of failed nodes enabled");
1128 } else {
1129 out->list_item(out, NULL, "STONITH of failed nodes disabled");
1130 }
1131
1133 out->list_item(out, NULL, "Cluster is symmetric");
1134 } else {
1135 out->list_item(out, NULL, "Cluster is asymmetric");
1136 }
1137
1138 switch (scheduler->no_quorum_policy) {
1140 out->list_item(out, NULL, "No quorum policy: Freeze resources");
1141 break;
1142
1144 out->list_item(out, NULL, "No quorum policy: Stop ALL resources");
1145 break;
1146
1148 out->list_item(out, NULL, "No quorum policy: Demote promotable "
1149 "resources and stop all other resources");
1150 break;
1151
1153 out->list_item(out, NULL, "No quorum policy: Ignore");
1154 break;
1155
1157 out->list_item(out, NULL,
1158 "No quorum policy: Fence nodes in partition");
1159 break;
1160 }
1161
1162 return pcmk_rc_ok;
1163}
1164
1173static const char *
1174no_quorum_policy_text(enum pe_quorum_policy policy)
1175{
1176 switch (policy) {
1178 return PCMK_VALUE_FREEZE;
1179
1181 return PCMK_VALUE_STOP;
1182
1184 return PCMK_VALUE_DEMOTE;
1185
1187 return PCMK_VALUE_IGNORE;
1188
1190 return PCMK_VALUE_FENCE;
1191
1192 default:
1193 return PCMK_VALUE_UNKNOWN;
1194 }
1195}
1196
1197PCMK__OUTPUT_ARGS("cluster-options", "pcmk_scheduler_t *")
1198static int
1199cluster_options_xml(pcmk__output_t *out, va_list args) {
1200 pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
1201
1202 const char *stonith_enabled = pcmk__flag_text(scheduler->flags,
1204 const char *symmetric_cluster =
1206 const char *no_quorum_policy =
1207 no_quorum_policy_text(scheduler->no_quorum_policy);
1208 const char *maintenance_mode = pcmk__flag_text(scheduler->flags,
1210 const char *stop_all_resources = pcmk__flag_text(scheduler->flags,
1212 char *stonith_timeout_ms_s =
1214
1215 char *priority_fencing_delay_ms_s =
1217
1219 PCMK_XA_STONITH_ENABLED, stonith_enabled,
1220 PCMK_XA_SYMMETRIC_CLUSTER, symmetric_cluster,
1221 PCMK_XA_NO_QUORUM_POLICY, no_quorum_policy,
1222 PCMK_XA_MAINTENANCE_MODE, maintenance_mode,
1223 PCMK_XA_STOP_ALL_RESOURCES, stop_all_resources,
1225 stonith_timeout_ms_s,
1227 priority_fencing_delay_ms_s,
1228 NULL);
1229 free(stonith_timeout_ms_s);
1230 free(priority_fencing_delay_ms_s);
1231
1232 return pcmk_rc_ok;
1233}
1234
1235PCMK__OUTPUT_ARGS("cluster-stack", "const char *", "enum pcmk_pacemakerd_state")
1236static int
1237cluster_stack_html(pcmk__output_t *out, va_list args) {
1238 const char *stack_s = va_arg(args, const char *);
1239 enum pcmk_pacemakerd_state pcmkd_state =
1240 (enum pcmk_pacemakerd_state) va_arg(args, int);
1241
1242 xmlNodePtr node = pcmk__output_create_xml_node(out, "li", NULL);
1243 xmlNode *child = NULL;
1244
1245 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, PCMK__VALUE_BOLD);
1246 pcmk__xe_set_content(child, "Stack: ");
1247
1248 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1249 pcmk__xe_set_content(child, "%s", stack_s);
1250
1251 if (pcmkd_state != pcmk_pacemakerd_state_invalid) {
1252 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1253 pcmk__xe_set_content(child, " (");
1254
1255 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1256 pcmk__xe_set_content(child, "%s",
1257 pcmk__pcmkd_state_enum2friendly(pcmkd_state));
1258
1259 child = pcmk__html_create(node, PCMK__XE_SPAN, NULL, NULL);
1260 pcmk__xe_set_content(child, ")");
1261 }
1262 return pcmk_rc_ok;
1263}
1264
1265PCMK__OUTPUT_ARGS("cluster-stack", "const char *", "enum pcmk_pacemakerd_state")
1266static int
1267cluster_stack_text(pcmk__output_t *out, va_list args) {
1268 const char *stack_s = va_arg(args, const char *);
1269 enum pcmk_pacemakerd_state pcmkd_state =
1270 (enum pcmk_pacemakerd_state) va_arg(args, int);
1271
1272 if (pcmkd_state != pcmk_pacemakerd_state_invalid) {
1273 out->list_item(out, "Stack", "%s (%s)",
1274 stack_s, pcmk__pcmkd_state_enum2friendly(pcmkd_state));
1275 } else {
1276 out->list_item(out, "Stack", "%s", stack_s);
1277 }
1278
1279 return pcmk_rc_ok;
1280}
1281
1282PCMK__OUTPUT_ARGS("cluster-stack", "const char *", "enum pcmk_pacemakerd_state")
1283static int
1284cluster_stack_xml(pcmk__output_t *out, va_list args) {
1285 const char *stack_s = va_arg(args, const char *);
1286 enum pcmk_pacemakerd_state pcmkd_state =
1287 (enum pcmk_pacemakerd_state) va_arg(args, int);
1288
1289 const char *state_s = NULL;
1290
1291 if (pcmkd_state != pcmk_pacemakerd_state_invalid) {
1292 state_s = pcmk_pacemakerd_api_daemon_state_enum2text(pcmkd_state);
1293 }
1294
1296 PCMK_XA_TYPE, stack_s,
1297 PCMK_XA_PACEMAKERD_STATE, state_s,
1298 NULL);
1299
1300 return pcmk_rc_ok;
1301}
1302
1303PCMK__OUTPUT_ARGS("cluster-times", "const char *", "const char *",
1304 "const char *", "const char *", "const char *")
1305static int
1306cluster_times_html(pcmk__output_t *out, va_list args) {
1307 const char *our_nodename = va_arg(args, const char *);
1308 const char *last_written = va_arg(args, const char *);
1309 const char *user = va_arg(args, const char *);
1310 const char *client = va_arg(args, const char *);
1311 const char *origin = va_arg(args, const char *);
1312
1313 xmlNodePtr updated_node = pcmk__output_create_xml_node(out, "li", NULL);
1314 xmlNodePtr changed_node = pcmk__output_create_xml_node(out, "li", NULL);
1315 xmlNode *child = NULL;
1316
1317 char *time_s = NULL;
1318
1319 child = pcmk__html_create(updated_node, PCMK__XE_SPAN, NULL,
1321 pcmk__xe_set_content(child, "Last updated: ");
1322
1323 child = pcmk__html_create(updated_node, PCMK__XE_SPAN, NULL, NULL);
1324 time_s = pcmk__epoch2str(NULL, 0);
1325 pcmk__xe_set_content(child, "%s", time_s);
1326 free(time_s);
1327
1328 if (our_nodename != NULL) {
1329 child = pcmk__html_create(updated_node, PCMK__XE_SPAN, NULL, NULL);
1330 pcmk__xe_set_content(child, " on ");
1331
1332 child = pcmk__html_create(updated_node, PCMK__XE_SPAN, NULL, NULL);
1333 pcmk__xe_set_content(child, "%s", our_nodename);
1334 }
1335
1336 child = pcmk__html_create(changed_node, PCMK__XE_SPAN, NULL,
1338 pcmk__xe_set_content(child, "Last change: ");
1339
1340 child = pcmk__html_create(changed_node, PCMK__XE_SPAN, NULL, NULL);
1341 time_s = last_changed_string(last_written, user, client, origin);
1342 pcmk__xe_set_content(child, "%s", time_s);
1343 free(time_s);
1344
1345 return pcmk_rc_ok;
1346}
1347
1348PCMK__OUTPUT_ARGS("cluster-times", "const char *", "const char *",
1349 "const char *", "const char *", "const char *")
1350static int
1351cluster_times_xml(pcmk__output_t *out, va_list args) {
1352 const char *our_nodename = va_arg(args, const char *);
1353 const char *last_written = va_arg(args, const char *);
1354 const char *user = va_arg(args, const char *);
1355 const char *client = va_arg(args, const char *);
1356 const char *origin = va_arg(args, const char *);
1357
1358 char *time_s = pcmk__epoch2str(NULL, 0);
1359
1361 PCMK_XA_TIME, time_s,
1362 PCMK_XA_ORIGIN, our_nodename,
1363 NULL);
1364
1366 PCMK_XA_TIME, pcmk__s(last_written, ""),
1367 PCMK_XA_USER, pcmk__s(user, ""),
1368 PCMK_XA_CLIENT, pcmk__s(client, ""),
1369 PCMK_XA_ORIGIN, pcmk__s(origin, ""),
1370 NULL);
1371
1372 free(time_s);
1373 return pcmk_rc_ok;
1374}
1375
1376PCMK__OUTPUT_ARGS("cluster-times", "const char *", "const char *",
1377 "const char *", "const char *", "const char *")
1378static int
1379cluster_times_text(pcmk__output_t *out, va_list args) {
1380 const char *our_nodename = va_arg(args, const char *);
1381 const char *last_written = va_arg(args, const char *);
1382 const char *user = va_arg(args, const char *);
1383 const char *client = va_arg(args, const char *);
1384 const char *origin = va_arg(args, const char *);
1385
1386 char *time_s = pcmk__epoch2str(NULL, 0);
1387
1388 out->list_item(out, "Last updated", "%s%s%s",
1389 time_s, (our_nodename != NULL)? " on " : "",
1390 pcmk__s(our_nodename, ""));
1391
1392 free(time_s);
1393 time_s = last_changed_string(last_written, user, client, origin);
1394
1395 out->list_item(out, "Last change", " %s", time_s);
1396
1397 free(time_s);
1398 return pcmk_rc_ok;
1399}
1400
1414static void
1415failed_action_friendly(pcmk__output_t *out, const xmlNode *xml_op,
1416 const char *op_key, const char *node_name, int rc,
1417 int status, const char *exit_reason,
1418 const char *exec_time)
1419{
1420 char *rsc_id = NULL;
1421 char *task = NULL;
1422 guint interval_ms = 0;
1423 time_t last_change_epoch = 0;
1424 GString *str = NULL;
1425
1426 if (pcmk__str_empty(op_key)
1427 || !parse_op_key(op_key, &rsc_id, &task, &interval_ms)) {
1428
1429 pcmk__str_update(&rsc_id, "unknown resource");
1430 pcmk__str_update(&task, "unknown action");
1431 interval_ms = 0;
1432 }
1433 pcmk__assert((rsc_id != NULL) && (task != NULL));
1434
1435 str = g_string_sized_new(256); // Should be sufficient for most messages
1436
1437 pcmk__g_strcat(str, rsc_id, " ", NULL);
1438
1439 if (interval_ms != 0) {
1440 pcmk__g_strcat(str, pcmk__readable_interval(interval_ms), "-interval ",
1441 NULL);
1442 }
1443 pcmk__g_strcat(str, pcmk__readable_action(task, interval_ms), " on ",
1444 node_name, NULL);
1445
1446 if (status == PCMK_EXEC_DONE) {
1447 pcmk__g_strcat(str, " returned '", crm_exit_str(rc), "'", NULL);
1448 if (!pcmk__str_empty(exit_reason)) {
1449 pcmk__g_strcat(str, " (", exit_reason, ")", NULL);
1450 }
1451
1452 } else {
1453 pcmk__g_strcat(str, " could not be executed (",
1454 pcmk_exec_status_str(status), NULL);
1455 if (!pcmk__str_empty(exit_reason)) {
1456 pcmk__g_strcat(str, ": ", exit_reason, NULL);
1457 }
1458 g_string_append_c(str, ')');
1459 }
1460
1461
1463 &last_change_epoch) == pcmk_ok) {
1464 char *s = pcmk__epoch2str(&last_change_epoch, 0);
1465
1466 pcmk__g_strcat(str, " at ", s, NULL);
1467 free(s);
1468 }
1469 if (!pcmk__str_empty(exec_time)) {
1470 int exec_time_ms = 0;
1471
1472 if ((pcmk__scan_min_int(exec_time, &exec_time_ms, 0) == pcmk_rc_ok)
1473 && (exec_time_ms > 0)) {
1474
1475 pcmk__g_strcat(str, " after ",
1476 pcmk__readable_interval(exec_time_ms), NULL);
1477 }
1478 }
1479
1480 out->list_item(out, NULL, "%s", str->str);
1481 g_string_free(str, TRUE);
1482 free(rsc_id);
1483 free(task);
1484}
1485
1499static void
1500failed_action_technical(pcmk__output_t *out, const xmlNode *xml_op,
1501 const char *op_key, const char *node_name, int rc,
1502 int status, const char *exit_reason,
1503 const char *exec_time)
1504{
1505 const char *call_id = crm_element_value(xml_op, PCMK__XA_CALL_ID);
1506 const char *queue_time = crm_element_value(xml_op, PCMK_XA_QUEUE_TIME);
1507 const char *exit_status = crm_exit_str(rc);
1508 const char *lrm_status = pcmk_exec_status_str(status);
1509 time_t last_change_epoch = 0;
1510 GString *str = NULL;
1511
1512 if (pcmk__str_empty(op_key)) {
1513 op_key = "unknown operation";
1514 }
1515 if (pcmk__str_empty(exit_status)) {
1516 exit_status = "unknown exit status";
1517 }
1518 if (pcmk__str_empty(call_id)) {
1519 call_id = "unknown";
1520 }
1521
1522 str = g_string_sized_new(256);
1523
1524 g_string_append_printf(str, "%s on %s '%s' (%d): call=%s, status='%s'",
1525 op_key, node_name, exit_status, rc, call_id,
1526 lrm_status);
1527
1528 if (!pcmk__str_empty(exit_reason)) {
1529 pcmk__g_strcat(str, ", exitreason='", exit_reason, "'", NULL);
1530 }
1531
1533 &last_change_epoch) == pcmk_ok) {
1534 char *last_change_str = pcmk__epoch2str(&last_change_epoch, 0);
1535
1536 pcmk__g_strcat(str,
1537 ", " PCMK_XA_LAST_RC_CHANGE "="
1538 "'", last_change_str, "'", NULL);
1539 free(last_change_str);
1540 }
1541 if (!pcmk__str_empty(queue_time)) {
1542 pcmk__g_strcat(str, ", queued=", queue_time, "ms", NULL);
1543 }
1544 if (!pcmk__str_empty(exec_time)) {
1545 pcmk__g_strcat(str, ", exec=", exec_time, "ms", NULL);
1546 }
1547
1548 out->list_item(out, NULL, "%s", str->str);
1549 g_string_free(str, TRUE);
1550}
1551
1552PCMK__OUTPUT_ARGS("failed-action", "xmlNode *", "uint32_t")
1553static int
1554failed_action_default(pcmk__output_t *out, va_list args)
1555{
1556 xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1557 uint32_t show_opts = va_arg(args, uint32_t);
1558
1559 const char *op_key = pcmk__xe_history_key(xml_op);
1560 const char *node_name = crm_element_value(xml_op, PCMK_XA_UNAME);
1561 const char *exit_reason = crm_element_value(xml_op, PCMK_XA_EXIT_REASON);
1562 const char *exec_time = crm_element_value(xml_op, PCMK_XA_EXEC_TIME);
1563
1564 int rc;
1565 int status;
1566
1568
1570 0);
1571
1572 if (pcmk__str_empty(node_name)) {
1573 node_name = "unknown node";
1574 }
1575
1576 if (pcmk_is_set(show_opts, pcmk_show_failed_detail)) {
1577 failed_action_technical(out, xml_op, op_key, node_name, rc, status,
1578 exit_reason, exec_time);
1579 } else {
1580 failed_action_friendly(out, xml_op, op_key, node_name, rc, status,
1581 exit_reason, exec_time);
1582 }
1583 return pcmk_rc_ok;
1584}
1585
1586PCMK__OUTPUT_ARGS("failed-action", "xmlNode *", "uint32_t")
1587static int
1588failed_action_xml(pcmk__output_t *out, va_list args) {
1589 xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
1590 uint32_t show_opts G_GNUC_UNUSED = va_arg(args, uint32_t);
1591
1592 const char *op_key = pcmk__xe_history_key(xml_op);
1593 const char *op_key_name = PCMK_XA_OP_KEY;
1594 int rc;
1595 int status;
1596 const char *uname = crm_element_value(xml_op, PCMK_XA_UNAME);
1597 const char *call_id = crm_element_value(xml_op, PCMK__XA_CALL_ID);
1598 const char *exitstatus = NULL;
1599 const char *exit_reason = pcmk__s(crm_element_value(xml_op,
1601 "none");
1602 const char *status_s = NULL;
1603
1604 time_t epoch = 0;
1605 gchar *exit_reason_esc = NULL;
1606 char *rc_s = NULL;
1607 xmlNodePtr node = NULL;
1608
1610 exit_reason_esc = pcmk__xml_escape(exit_reason, pcmk__xml_escape_attr);
1611 exit_reason = exit_reason_esc;
1612 }
1615 0);
1616
1617 if (crm_element_value(xml_op, PCMK__XA_OPERATION_KEY) == NULL) {
1618 op_key_name = PCMK_XA_ID;
1619 }
1620 exitstatus = crm_exit_str(rc);
1621 rc_s = pcmk__itoa(rc);
1622 status_s = pcmk_exec_status_str(status);
1624 op_key_name, op_key,
1626 PCMK_XA_EXITSTATUS, exitstatus,
1627 PCMK_XA_EXITREASON, exit_reason,
1628 PCMK_XA_EXITCODE, rc_s,
1629 PCMK_XA_CALL, call_id,
1630 PCMK_XA_STATUS, status_s,
1631 NULL);
1632 free(rc_s);
1633
1635 &epoch) == pcmk_ok) && (epoch > 0)) {
1636
1637 const char *queue_time = crm_element_value(xml_op, PCMK_XA_QUEUE_TIME);
1638 const char *exec = crm_element_value(xml_op, PCMK_XA_EXEC_TIME);
1639 const char *task = crm_element_value(xml_op, PCMK_XA_OPERATION);
1640 guint interval_ms = 0;
1641 char *interval_ms_s = NULL;
1642 char *rc_change = pcmk__epoch2str(&epoch,
1646
1647 crm_element_value_ms(xml_op, PCMK_META_INTERVAL, &interval_ms);
1648 interval_ms_s = crm_strdup_printf("%u", interval_ms);
1649
1650 pcmk__xe_set_props(node,
1651 PCMK_XA_LAST_RC_CHANGE, rc_change,
1652 PCMK_XA_QUEUED, queue_time,
1653 PCMK_XA_EXEC, exec,
1654 PCMK_XA_INTERVAL, interval_ms_s,
1655 PCMK_XA_TASK, task,
1656 NULL);
1657
1658 free(interval_ms_s);
1659 free(rc_change);
1660 }
1661
1662 g_free(exit_reason_esc);
1663 return pcmk_rc_ok;
1664}
1665
1666PCMK__OUTPUT_ARGS("failed-action-list", "pcmk_scheduler_t *", "GList *",
1667 "GList *", "uint32_t", "bool")
1668static int
1669failed_action_list(pcmk__output_t *out, va_list args) {
1670 pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
1671 GList *only_node = va_arg(args, GList *);
1672 GList *only_rsc = va_arg(args, GList *);
1673 uint32_t show_opts = va_arg(args, uint32_t);
1674 bool print_spacer = va_arg(args, int);
1675
1676 xmlNode *xml_op = NULL;
1677 int rc = pcmk_rc_no_output;
1678
1679 if (xmlChildElementCount(scheduler->priv->failed) == 0) {
1680 return rc;
1681 }
1682
1683 for (xml_op = pcmk__xe_first_child(scheduler->priv->failed, NULL, NULL,
1684 NULL);
1685 xml_op != NULL; xml_op = pcmk__xe_next(xml_op, NULL)) {
1686
1687 char *rsc = NULL;
1688
1690 only_node,
1692 continue;
1693 }
1694
1695 if (pcmk_xe_mask_probe_failure(xml_op)) {
1696 continue;
1697 }
1698
1699 if (!parse_op_key(pcmk__xe_history_key(xml_op), &rsc, NULL, NULL)) {
1700 continue;
1701 }
1702
1703 if (!pcmk__str_in_list(rsc, only_rsc, pcmk__str_star_matches)) {
1704 free(rsc);
1705 continue;
1706 }
1707
1708 free(rsc);
1709
1710 PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Failed Resource Actions");
1711 out->message(out, "failed-action", xml_op, show_opts);
1712 }
1713
1714 PCMK__OUTPUT_LIST_FOOTER(out, rc);
1715 return rc;
1716}
1717
1718static void
1719status_node(pcmk_node_t *node, xmlNodePtr parent, uint32_t show_opts)
1720{
1721 int health = pe__node_health(node);
1722 xmlNode *child = NULL;
1723
1724 // Cluster membership
1725 if (node->details->online) {
1726 child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1728 pcmk__xe_set_content(child, " online");
1729
1730 } else {
1731 child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1733 pcmk__xe_set_content(child, " OFFLINE");
1734 }
1735
1736 // Standby mode
1738 child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1740 if (node->details->running_rsc == NULL) {
1742 " (in standby due to " PCMK_META_ON_FAIL ")");
1743 } else {
1745 " (in standby due to " PCMK_META_ON_FAIL ","
1746 " with active resources)");
1747 }
1748
1749 } else if (pcmk_is_set(node->priv->flags, pcmk__node_standby)) {
1750 child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1752 if (node->details->running_rsc == NULL) {
1753 pcmk__xe_set_content(child, " (in standby)");
1754 } else {
1755 pcmk__xe_set_content(child, " (in standby, with active resources)");
1756 }
1757 }
1758
1759 // Maintenance mode
1760 if (node->details->maintenance) {
1761 child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1763 pcmk__xe_set_content(child, " (in maintenance mode)");
1764 }
1765
1766 // Node health
1767 if (health < 0) {
1768 child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1770 pcmk__xe_set_content(child, " (health is RED)");
1771
1772 } else if (health == 0) {
1773 child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL,
1775 pcmk__xe_set_content(child, " (health is YELLOW)");
1776 }
1777
1778 // Feature set
1779 if (pcmk_is_set(show_opts, pcmk_show_feature_set)) {
1780 const char *feature_set = get_node_feature_set(node);
1781 if (feature_set != NULL) {
1782 child = pcmk__html_create(parent, PCMK__XE_SPAN, NULL, NULL);
1783 pcmk__xe_set_content(child, ", feature set %s", feature_set);
1784 }
1785 }
1786}
1787
1788PCMK__OUTPUT_ARGS("node", "pcmk_node_t *", "uint32_t", "bool",
1789 "GList *", "GList *")
1790static int
1791node_html(pcmk__output_t *out, va_list args) {
1792 pcmk_node_t *node = va_arg(args, pcmk_node_t *);
1793 uint32_t show_opts = va_arg(args, uint32_t);
1794 bool full = va_arg(args, int);
1795 GList *only_node = va_arg(args, GList *);
1796 GList *only_rsc = va_arg(args, GList *);
1797
1798 char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1799
1800 if (full) {
1801 xmlNode *item_node = NULL;
1802 xmlNode *child = NULL;
1803
1804 if (pcmk_all_flags_set(show_opts, pcmk_show_brief | pcmk_show_rscs_by_node)) {
1805 GList *rscs = pe__filter_rsc_list(node->details->running_rsc, only_rsc);
1806
1807 out->begin_list(out, NULL, NULL, "%s:", node_name);
1808 item_node = pcmk__output_xml_create_parent(out, "li", NULL);
1809 child = pcmk__html_create(item_node, PCMK__XE_SPAN, NULL, NULL);
1810 pcmk__xe_set_content(child, "Status:");
1811 status_node(node, item_node, show_opts);
1812
1813 if (rscs != NULL) {
1814 uint32_t new_show_opts = (show_opts | pcmk_show_rsc_only) & ~pcmk_show_inactive_rscs;
1815 out->begin_list(out, NULL, NULL, "Resources");
1816 pe__rscs_brief_output(out, rscs, new_show_opts);
1817 out->end_list(out);
1818 }
1819
1821 out->end_list(out);
1822
1823 } else if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
1824 GList *lpc2 = NULL;
1825 int rc = pcmk_rc_no_output;
1826
1827 out->begin_list(out, NULL, NULL, "%s:", node_name);
1828 item_node = pcmk__output_xml_create_parent(out, "li", NULL);
1829 child = pcmk__html_create(item_node, PCMK__XE_SPAN, NULL, NULL);
1830 pcmk__xe_set_content(child, "Status:");
1831 status_node(node, item_node, show_opts);
1832
1833 for (lpc2 = node->details->running_rsc; lpc2 != NULL; lpc2 = lpc2->next) {
1834 pcmk_resource_t *rsc = (pcmk_resource_t *) lpc2->data;
1835
1836 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Resources");
1837
1838 show_opts |= pcmk_show_rsc_only;
1839 out->message(out, (const char *) rsc->priv->xml->name,
1840 show_opts, rsc, only_node, only_rsc);
1841 }
1842
1843 PCMK__OUTPUT_LIST_FOOTER(out, rc);
1845 out->end_list(out);
1846
1847 } else {
1848 item_node = pcmk__output_create_xml_node(out, "li", NULL);
1849 child = pcmk__html_create(item_node, PCMK__XE_SPAN, NULL,
1851 pcmk__xe_set_content(child, "%s:", node_name);
1852 status_node(node, item_node, show_opts);
1853 }
1854 } else {
1855 out->begin_list(out, NULL, NULL, "%s:", node_name);
1856 }
1857
1858 free(node_name);
1859 return pcmk_rc_ok;
1860}
1861
1870static const char *
1871node_text_status(const pcmk_node_t *node)
1872{
1873 if (node->details->unclean) {
1874 if (node->details->online) {
1875 return "UNCLEAN (online)";
1876
1877 } else if (node->details->pending) {
1878 return "UNCLEAN (pending)";
1879
1880 } else {
1881 return "UNCLEAN (offline)";
1882 }
1883
1884 } else if (node->details->pending) {
1885 return "pending";
1886
1887 } else if (pcmk_is_set(node->priv->flags, pcmk__node_fail_standby)
1888 && node->details->online) {
1889 return "standby (" PCMK_META_ON_FAIL ")";
1890
1891 } else if (pcmk_is_set(node->priv->flags, pcmk__node_standby)) {
1892 if (!node->details->online) {
1893 return "OFFLINE (standby)";
1894 } else if (node->details->running_rsc == NULL) {
1895 return "standby";
1896 } else {
1897 return "standby (with active resources)";
1898 }
1899
1900 } else if (node->details->maintenance) {
1901 if (node->details->online) {
1902 return "maintenance";
1903 } else {
1904 return "OFFLINE (maintenance)";
1905 }
1906
1907 } else if (node->details->online) {
1908 return "online";
1909 }
1910
1911 return "OFFLINE";
1912}
1913
1914PCMK__OUTPUT_ARGS("node", "pcmk_node_t *", "uint32_t", "bool", "GList *",
1915 "GList *")
1916static int
1917node_text(pcmk__output_t *out, va_list args) {
1918 pcmk_node_t *node = va_arg(args, pcmk_node_t *);
1919 uint32_t show_opts = va_arg(args, uint32_t);
1920 bool full = va_arg(args, int);
1921 GList *only_node = va_arg(args, GList *);
1922 GList *only_rsc = va_arg(args, GList *);
1923
1924 if (full) {
1925 char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1926 GString *str = g_string_sized_new(64);
1927 int health = pe__node_health(node);
1928
1929 // Create a summary line with node type, name, and status
1930 if (pcmk__is_guest_or_bundle_node(node)) {
1931 g_string_append(str, "GuestNode");
1932 } else if (pcmk__is_remote_node(node)) {
1933 g_string_append(str, "RemoteNode");
1934 } else {
1935 g_string_append(str, "Node");
1936 }
1937 pcmk__g_strcat(str, " ", node_name, ": ", node_text_status(node), NULL);
1938
1939 if (health < 0) {
1940 g_string_append(str, " (health is RED)");
1941 } else if (health == 0) {
1942 g_string_append(str, " (health is YELLOW)");
1943 }
1944 if (pcmk_is_set(show_opts, pcmk_show_feature_set)) {
1945 const char *feature_set = get_node_feature_set(node);
1946 if (feature_set != NULL) {
1947 pcmk__g_strcat(str, ", feature set ", feature_set, NULL);
1948 }
1949 }
1950
1951 /* If we're grouping by node, print its resources */
1952 if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
1953 if (pcmk_is_set(show_opts, pcmk_show_brief)) {
1954 GList *rscs = pe__filter_rsc_list(node->details->running_rsc, only_rsc);
1955
1956 if (rscs != NULL) {
1957 uint32_t new_show_opts = (show_opts | pcmk_show_rsc_only) & ~pcmk_show_inactive_rscs;
1958 out->begin_list(out, NULL, NULL, "%s", str->str);
1959 out->begin_list(out, NULL, NULL, "Resources");
1960
1961 pe__rscs_brief_output(out, rscs, new_show_opts);
1962
1963 out->end_list(out);
1964 out->end_list(out);
1965
1966 g_list_free(rscs);
1967 }
1968
1969 } else {
1970 GList *gIter2 = NULL;
1971
1972 out->begin_list(out, NULL, NULL, "%s", str->str);
1973 out->begin_list(out, NULL, NULL, "Resources");
1974
1975 for (gIter2 = node->details->running_rsc; gIter2 != NULL; gIter2 = gIter2->next) {
1976 pcmk_resource_t *rsc = (pcmk_resource_t *) gIter2->data;
1977
1978 show_opts |= pcmk_show_rsc_only;
1979 out->message(out, (const char *) rsc->priv->xml->name,
1980 show_opts, rsc, only_node, only_rsc);
1981 }
1982
1983 out->end_list(out);
1984 out->end_list(out);
1985 }
1986 } else {
1987 out->list_item(out, NULL, "%s", str->str);
1988 }
1989
1990 g_string_free(str, TRUE);
1991 free(node_name);
1992 } else {
1993 char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
1994 out->begin_list(out, NULL, NULL, "Node: %s", node_name);
1995 free(node_name);
1996 }
1997
1998 return pcmk_rc_ok;
1999}
2000
2011static const char *
2012health_text(int health)
2013{
2014 if (health < 0) {
2015 return PCMK_VALUE_RED;
2016 } else if (health == 0) {
2017 return PCMK_VALUE_YELLOW;
2018 } else {
2019 return PCMK_VALUE_GREEN;
2020 }
2021}
2022
2033static const char *
2034node_variant_text(enum pcmk__node_variant variant)
2035{
2036 switch (variant) {
2038 return PCMK_VALUE_MEMBER;
2040 return PCMK_VALUE_REMOTE;
2041 default:
2042 return PCMK_VALUE_UNKNOWN;
2043 }
2044}
2045
2046PCMK__OUTPUT_ARGS("node", "pcmk_node_t *", "uint32_t", "bool", "GList *",
2047 "GList *")
2048static int
2049node_xml(pcmk__output_t *out, va_list args) {
2050 pcmk_node_t *node = va_arg(args, pcmk_node_t *);
2051 uint32_t show_opts G_GNUC_UNUSED = va_arg(args, uint32_t);
2052 bool full = va_arg(args, int);
2053 GList *only_node = va_arg(args, GList *);
2054 GList *only_rsc = va_arg(args, GList *);
2055
2056 if (full) {
2057 const char *online = pcmk__btoa(node->details->online);
2058 const char *standby = pcmk__flag_text(node->priv->flags,
2060 const char *standby_onfail = pcmk__flag_text(node->priv->flags,
2062 const char *maintenance = pcmk__btoa(node->details->maintenance);
2063 const char *pending = pcmk__btoa(node->details->pending);
2064 const char *unclean = pcmk__btoa(node->details->unclean);
2065 const char *health = health_text(pe__node_health(node));
2066 const char *feature_set = get_node_feature_set(node);
2067 const char *shutdown = pcmk__btoa(node->details->shutdown);
2068 const char *expected_up = pcmk__flag_text(node->priv->flags,
2070 const bool is_dc = pcmk__same_node(node,
2071 node->priv->scheduler->dc_node);
2072 int length = g_list_length(node->details->running_rsc);
2073 char *resources_running = pcmk__itoa(length);
2074 const char *node_type = node_variant_text(node->priv->variant);
2075
2076 int rc = pcmk_rc_ok;
2077
2078 rc = pe__name_and_nvpairs_xml(out, true, PCMK_XE_NODE,
2079 PCMK_XA_NAME, node->priv->name,
2080 PCMK_XA_ID, node->priv->id,
2081 PCMK_XA_ONLINE, online,
2082 PCMK_XA_STANDBY, standby,
2083 PCMK_XA_STANDBY_ONFAIL, standby_onfail,
2084 PCMK_XA_MAINTENANCE, maintenance,
2085 PCMK_XA_PENDING, pending,
2086 PCMK_XA_UNCLEAN, unclean,
2087 PCMK_XA_HEALTH, health,
2088 PCMK_XA_FEATURE_SET, feature_set,
2089 PCMK_XA_SHUTDOWN, shutdown,
2090 PCMK_XA_EXPECTED_UP, expected_up,
2091 PCMK_XA_IS_DC, pcmk__btoa(is_dc),
2092 PCMK_XA_RESOURCES_RUNNING, resources_running,
2093 PCMK_XA_TYPE, node_type,
2094 NULL);
2095
2096 free(resources_running);
2097 pcmk__assert(rc == pcmk_rc_ok);
2098
2099 if (pcmk__is_guest_or_bundle_node(node)) {
2100 xmlNodePtr xml_node = pcmk__output_xml_peek_parent(out);
2102 node->priv->remote->priv->launcher->id);
2103 }
2104
2105 if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
2106 GList *lpc = NULL;
2107
2108 for (lpc = node->details->running_rsc; lpc != NULL; lpc = lpc->next) {
2109 pcmk_resource_t *rsc = (pcmk_resource_t *) lpc->data;
2110
2111 show_opts |= pcmk_show_rsc_only;
2112 out->message(out, (const char *) rsc->priv->xml->name,
2113 show_opts, rsc, only_node, only_rsc);
2114 }
2115 }
2116
2117 out->end_list(out);
2118 } else {
2120 PCMK_XA_NAME, node->priv->name,
2121 NULL);
2122 }
2123
2124 return pcmk_rc_ok;
2125}
2126
2127PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "bool", "int")
2128static int
2129node_attribute_text(pcmk__output_t *out, va_list args) {
2130 const char *name = va_arg(args, const char *);
2131 const char *value = va_arg(args, const char *);
2132 bool add_extra = va_arg(args, int);
2133 int expected_score = va_arg(args, int);
2134
2135 if (add_extra) {
2136 int v;
2137
2138 if (value == NULL) {
2139 v = 0;
2140 } else {
2141 pcmk__scan_min_int(value, &v, INT_MIN);
2142 }
2143 if (v <= 0) {
2144 out->list_item(out, NULL, "%-32s\t: %-10s\t: Connectivity is lost", name, value);
2145 } else if (v < expected_score) {
2146 out->list_item(out, NULL, "%-32s\t: %-10s\t: Connectivity is degraded (Expected=%d)", name, value, expected_score);
2147 } else {
2148 out->list_item(out, NULL, "%-32s\t: %-10s", name, value);
2149 }
2150 } else {
2151 out->list_item(out, NULL, "%-32s\t: %-10s", name, value);
2152 }
2153
2154 return pcmk_rc_ok;
2155}
2156
2157PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "bool", "int")
2158static int
2159node_attribute_html(pcmk__output_t *out, va_list args) {
2160 const char *name = va_arg(args, const char *);
2161 const char *value = va_arg(args, const char *);
2162 bool add_extra = va_arg(args, int);
2163 int expected_score = va_arg(args, int);
2164
2165 if (add_extra) {
2166 int v = 0;
2167 xmlNodePtr item_node = pcmk__output_create_xml_node(out, "li", NULL);
2168 xmlNode *child = NULL;
2169
2170 if (value != NULL) {
2171 pcmk__scan_min_int(value, &v, INT_MIN);
2172 }
2173
2174 child = pcmk__html_create(item_node, PCMK__XE_SPAN, NULL, NULL);
2175 pcmk__xe_set_content(child, "%s: %s", name, value);
2176
2177 if (v <= 0) {
2178 child = pcmk__html_create(item_node, PCMK__XE_SPAN, NULL,
2180 pcmk__xe_set_content(child, "(connectivity is lost)");
2181
2182 } else if (v < expected_score) {
2183 child = pcmk__html_create(item_node, PCMK__XE_SPAN, NULL,
2186 "(connectivity is degraded -- expected %d)",
2187 expected_score);
2188 }
2189 } else {
2190 out->list_item(out, NULL, "%s: %s", name, value);
2191 }
2192
2193 return pcmk_rc_ok;
2194}
2195
2196PCMK__OUTPUT_ARGS("node-and-op", "pcmk_scheduler_t *", "xmlNode *")
2197static int
2198node_and_op(pcmk__output_t *out, va_list args) {
2199 pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
2200 xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
2201
2202 pcmk_resource_t *rsc = NULL;
2203 gchar *node_str = NULL;
2204 char *last_change_str = NULL;
2205
2206 const char *op_rsc = crm_element_value(xml_op, PCMK_XA_RESOURCE);
2207 int status;
2208 time_t last_change = 0;
2209
2212
2213 rsc = pe_find_resource(scheduler->priv->resources, op_rsc);
2214
2215 if (rsc) {
2216 const pcmk_node_t *node = pcmk__current_node(rsc);
2217 const char *target_role = g_hash_table_lookup(rsc->priv->meta,
2219 uint32_t show_opts = pcmk_show_rsc_only | pcmk_show_pending;
2220
2221 if (node == NULL) {
2222 node = rsc->priv->pending_node;
2223 }
2224
2225 node_str = pcmk__native_output_string(rsc, rsc_printable_id(rsc), node,
2226 show_opts, target_role, false);
2227 } else {
2228 node_str = crm_strdup_printf("Unknown resource %s", op_rsc);
2229 }
2230
2232 &last_change) == pcmk_ok) {
2233 const char *exec_time = crm_element_value(xml_op, PCMK_XA_EXEC_TIME);
2234
2235 last_change_str = crm_strdup_printf(", %s='%s', exec=%sms",
2237 pcmk__trim(ctime(&last_change)),
2238 exec_time);
2239 }
2240
2241 out->list_item(out, NULL, "%s: %s (node=%s, call=%s, rc=%s%s): %s",
2242 node_str, pcmk__xe_history_key(xml_op),
2246 last_change_str ? last_change_str : "",
2247 pcmk_exec_status_str(status));
2248
2249 g_free(node_str);
2250 free(last_change_str);
2251 return pcmk_rc_ok;
2252}
2253
2254PCMK__OUTPUT_ARGS("node-and-op", "pcmk_scheduler_t *", "xmlNode *")
2255static int
2256node_and_op_xml(pcmk__output_t *out, va_list args) {
2257 pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
2258 xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
2259
2260 pcmk_resource_t *rsc = NULL;
2261 const char *uname = crm_element_value(xml_op, PCMK_XA_UNAME);
2262 const char *call_id = crm_element_value(xml_op, PCMK__XA_CALL_ID);
2263 const char *rc_s = crm_element_value(xml_op, PCMK__XA_RC_CODE);
2264 const char *status_s = NULL;
2265 const char *op_rsc = crm_element_value(xml_op, PCMK_XA_RESOURCE);
2266 int status;
2267 time_t last_change = 0;
2268 xmlNode *node = NULL;
2269
2271 &status, PCMK_EXEC_UNKNOWN);
2272 status_s = pcmk_exec_status_str(status);
2273
2275 PCMK_XA_OP, pcmk__xe_history_key(xml_op),
2277 PCMK_XA_CALL, call_id,
2278 PCMK_XA_RC, rc_s,
2279 PCMK_XA_STATUS, status_s,
2280 NULL);
2281
2282 rsc = pe_find_resource(scheduler->priv->resources, op_rsc);
2283
2284 if (rsc) {
2285 const char *class = crm_element_value(rsc->priv->xml, PCMK_XA_CLASS);
2286 const char *provider = crm_element_value(rsc->priv->xml,
2288 const char *kind = crm_element_value(rsc->priv->xml, PCMK_XA_TYPE);
2289 bool has_provider = pcmk_is_set(pcmk_get_ra_caps(class),
2291
2292 char *agent_tuple = crm_strdup_printf("%s:%s:%s",
2293 class,
2294 (has_provider? provider : ""),
2295 kind);
2296
2297 pcmk__xe_set_props(node,
2299 PCMK_XA_AGENT, agent_tuple,
2300 NULL);
2301 free(agent_tuple);
2302 }
2303
2305 &last_change) == pcmk_ok) {
2306 const char *last_rc_change = pcmk__trim(ctime(&last_change));
2307 const char *exec_time = crm_element_value(xml_op, PCMK_XA_EXEC_TIME);
2308
2309 pcmk__xe_set_props(node,
2310 PCMK_XA_LAST_RC_CHANGE, last_rc_change,
2311 PCMK_XA_EXEC_TIME, exec_time,
2312 NULL);
2313 }
2314
2315 return pcmk_rc_ok;
2316}
2317
2318PCMK__OUTPUT_ARGS("node-attribute", "const char *", "const char *", "bool", "int")
2319static int
2320node_attribute_xml(pcmk__output_t *out, va_list args) {
2321 const char *name = va_arg(args, const char *);
2322 const char *value = va_arg(args, const char *);
2323 bool add_extra = va_arg(args, int);
2324 int expected_score = va_arg(args, int);
2325
2326 xmlNodePtr node = pcmk__output_create_xml_node(out, PCMK_XE_ATTRIBUTE,
2328 PCMK_XA_VALUE, value,
2329 NULL);
2330
2331 if (add_extra) {
2332 char *buf = pcmk__itoa(expected_score);
2333 crm_xml_add(node, PCMK_XA_EXPECTED, buf);
2334 free(buf);
2335 }
2336
2337 return pcmk_rc_ok;
2338}
2339
2340PCMK__OUTPUT_ARGS("node-attribute-list", "pcmk_scheduler_t *", "uint32_t",
2341 "bool", "GList *", "GList *")
2342static int
2343node_attribute_list(pcmk__output_t *out, va_list args) {
2344 pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
2345 uint32_t show_opts = va_arg(args, uint32_t);
2346 bool print_spacer = va_arg(args, int);
2347 GList *only_node = va_arg(args, GList *);
2348 GList *only_rsc = va_arg(args, GList *);
2349
2350 int rc = pcmk_rc_no_output;
2351
2352 /* Display each node's attributes */
2353 for (GList *gIter = scheduler->nodes; gIter != NULL; gIter = gIter->next) {
2354 pcmk_node_t *node = gIter->data;
2355
2356 GList *attr_list = NULL;
2357 GHashTableIter iter;
2358 gpointer key;
2359
2360 if (!node || !node->details || !node->details->online) {
2361 continue;
2362 }
2363
2364 // @TODO Maybe skip filtering for XML output
2365 g_hash_table_iter_init(&iter, node->priv->attrs);
2366 while (g_hash_table_iter_next (&iter, &key, NULL)) {
2367 attr_list = filter_attr_list(attr_list, key);
2368 }
2369
2370 if (attr_list == NULL) {
2371 continue;
2372 }
2373
2374 if (!pcmk__str_in_list(node->priv->name, only_node,
2376 g_list_free(attr_list);
2377 continue;
2378 }
2379
2380 PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Node Attributes");
2381
2382 out->message(out, "node", node, show_opts, false, only_node, only_rsc);
2383
2384 for (GList *aIter = attr_list; aIter != NULL; aIter = aIter->next) {
2385 const char *name = aIter->data;
2386 const char *value = NULL;
2387 int expected_score = 0;
2388 bool add_extra = false;
2389
2390 value = pcmk__node_attr(node, name, NULL, pcmk__rsc_node_current);
2391
2392 add_extra = add_extra_info(node, node->details->running_rsc,
2393 scheduler, name, &expected_score);
2394
2395 /* Print attribute name and value */
2396 out->message(out, "node-attribute", name, value, add_extra,
2397 expected_score);
2398 }
2399
2400 g_list_free(attr_list);
2401 out->end_list(out);
2402 }
2403
2404 PCMK__OUTPUT_LIST_FOOTER(out, rc);
2405 return rc;
2406}
2407
2408PCMK__OUTPUT_ARGS("node-capacity", "const pcmk_node_t *", "const char *")
2409static int
2410node_capacity(pcmk__output_t *out, va_list args)
2411{
2412 const pcmk_node_t *node = va_arg(args, pcmk_node_t *);
2413 const char *comment = va_arg(args, const char *);
2414
2415 char *dump_text = crm_strdup_printf("%s: %s capacity:",
2416 comment, pcmk__node_name(node));
2417
2418 g_hash_table_foreach(node->priv->utilization, append_dump_text,
2419 &dump_text);
2420 out->list_item(out, NULL, "%s", dump_text);
2421 free(dump_text);
2422
2423 return pcmk_rc_ok;
2424}
2425
2426PCMK__OUTPUT_ARGS("node-capacity", "const pcmk_node_t *", "const char *")
2427static int
2428node_capacity_xml(pcmk__output_t *out, va_list args)
2429{
2430 const pcmk_node_t *node = va_arg(args, pcmk_node_t *);
2431 const char *uname = node->priv->name;
2432 const char *comment = va_arg(args, const char *);
2433
2434 xmlNodePtr xml_node = pcmk__output_create_xml_node(out, PCMK_XE_CAPACITY,
2436 PCMK_XA_COMMENT, comment,
2437 NULL);
2438 g_hash_table_foreach(node->priv->utilization, add_dump_node, xml_node);
2439
2440 return pcmk_rc_ok;
2441}
2442
2443PCMK__OUTPUT_ARGS("node-history-list", "pcmk_scheduler_t *", "pcmk_node_t *",
2444 "xmlNode *", "GList *", "GList *", "uint32_t", "uint32_t")
2445static int
2446node_history_list(pcmk__output_t *out, va_list args) {
2447 pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
2448 pcmk_node_t *node = va_arg(args, pcmk_node_t *);
2449 xmlNode *node_state = va_arg(args, xmlNode *);
2450 GList *only_node = va_arg(args, GList *);
2451 GList *only_rsc = va_arg(args, GList *);
2452 uint32_t section_opts = va_arg(args, uint32_t);
2453 uint32_t show_opts = va_arg(args, uint32_t);
2454
2455 xmlNode *lrm_rsc = NULL;
2456 xmlNode *rsc_entry = NULL;
2457 int rc = pcmk_rc_no_output;
2458
2459 lrm_rsc = pcmk__xe_first_child(node_state, PCMK__XE_LRM, NULL, NULL);
2460 lrm_rsc = pcmk__xe_first_child(lrm_rsc, PCMK__XE_LRM_RESOURCES, NULL, NULL);
2461
2462 /* Print history of each of the node's resources */
2463 for (rsc_entry = pcmk__xe_first_child(lrm_rsc, PCMK__XE_LRM_RESOURCE, NULL,
2464 NULL);
2465 rsc_entry != NULL;
2466 rsc_entry = pcmk__xe_next(rsc_entry, PCMK__XE_LRM_RESOURCE)) {
2467
2468 const char *rsc_id = crm_element_value(rsc_entry, PCMK_XA_ID);
2469 pcmk_resource_t *rsc = NULL;
2470 const pcmk_resource_t *parent = NULL;
2471
2472 if (rsc_id == NULL) {
2473 continue; // Malformed entry
2474 }
2475
2476 rsc = pe_find_resource(scheduler->priv->resources, rsc_id);
2477 if (rsc == NULL) {
2478 continue; // Resource was removed from configuration
2479 }
2480
2481 /* We can't use is_filtered here to filter group resources. For is_filtered,
2482 * we have to decide whether to check the parent or not. If we check the
2483 * parent, all elements of a group will always be printed because that's how
2484 * is_filtered works for groups. If we do not check the parent, sometimes
2485 * this will filter everything out.
2486 *
2487 * For other resource types, is_filtered is okay.
2488 */
2489 parent = pe__const_top_resource(rsc, false);
2490 if (pcmk__is_group(parent)) {
2491 if (!pcmk__str_in_list(rsc_printable_id(rsc), only_rsc,
2495 continue;
2496 }
2497 } else if (rsc->priv->fns->is_filtered(rsc, only_rsc, true)) {
2498 continue;
2499 }
2500
2501 if (!pcmk_is_set(section_opts, pcmk_section_operations)) {
2502 time_t last_failure = 0;
2503 int failcount = pe_get_failcount(node, rsc, &last_failure,
2504 pcmk__fc_default, NULL);
2505
2506 if (failcount <= 0) {
2507 continue;
2508 }
2509
2510 if (rc == pcmk_rc_no_output) {
2511 rc = pcmk_rc_ok;
2512 out->message(out, "node", node, show_opts, false, only_node,
2513 only_rsc);
2514 }
2515
2516 out->message(out, "resource-history", rsc, rsc_id, false,
2517 failcount, last_failure, false);
2518 } else {
2519 GList *op_list = get_operation_list(rsc_entry);
2520 pcmk_resource_t *rsc = NULL;
2521
2522 if (op_list == NULL) {
2523 continue;
2524 }
2525
2527 crm_element_value(rsc_entry, PCMK_XA_ID));
2528
2529 if (rc == pcmk_rc_no_output) {
2530 rc = pcmk_rc_ok;
2531 out->message(out, "node", node, show_opts, false, only_node,
2532 only_rsc);
2533 }
2534
2535 out->message(out, "resource-operation-list", scheduler, rsc, node,
2536 op_list, show_opts);
2537 }
2538 }
2539
2540 PCMK__OUTPUT_LIST_FOOTER(out, rc);
2541 return rc;
2542}
2543
2544PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "uint32_t", "bool")
2545static int
2546node_list_html(pcmk__output_t *out, va_list args) {
2547 GList *nodes = va_arg(args, GList *);
2548 GList *only_node = va_arg(args, GList *);
2549 GList *only_rsc = va_arg(args, GList *);
2550 uint32_t show_opts = va_arg(args, uint32_t);
2551 bool print_spacer G_GNUC_UNUSED = va_arg(args, int);
2552
2553 int rc = pcmk_rc_no_output;
2554
2555 for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
2556 pcmk_node_t *node = (pcmk_node_t *) gIter->data;
2557
2558 if (!pcmk__str_in_list(node->priv->name, only_node,
2560 continue;
2561 }
2562
2563 PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Node List");
2564
2565 out->message(out, "node", node, show_opts, true, only_node, only_rsc);
2566 }
2567
2568 PCMK__OUTPUT_LIST_FOOTER(out, rc);
2569 return rc;
2570}
2571
2572PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "uint32_t", "bool")
2573static int
2574node_list_text(pcmk__output_t *out, va_list args) {
2575 GList *nodes = va_arg(args, GList *);
2576 GList *only_node = va_arg(args, GList *);
2577 GList *only_rsc = va_arg(args, GList *);
2578 uint32_t show_opts = va_arg(args, uint32_t);
2579 bool print_spacer = va_arg(args, int);
2580
2581 /* space-separated lists of node names */
2582 GString *online_nodes = NULL;
2583 GString *online_remote_nodes = NULL;
2584 GString *online_guest_nodes = NULL;
2585 GString *offline_nodes = NULL;
2586 GString *offline_remote_nodes = NULL;
2587
2588 int rc = pcmk_rc_no_output;
2589
2590 for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
2591 pcmk_node_t *node = (pcmk_node_t *) gIter->data;
2592 char *node_name = pe__node_display_name(node, pcmk_is_set(show_opts, pcmk_show_node_id));
2593
2594 if (!pcmk__str_in_list(node->priv->name, only_node,
2596 free(node_name);
2597 continue;
2598 }
2599
2600 PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Node List");
2601
2602 // Determine whether to display node individually or in a list
2603 if (node->details->unclean || node->details->pending
2605 && node->details->online)
2607 || node->details->maintenance
2608 || pcmk_is_set(show_opts, pcmk_show_rscs_by_node)
2609 || pcmk_is_set(show_opts, pcmk_show_feature_set)
2610 || (pe__node_health(node) <= 0)) {
2611 // Display node individually
2612
2613 } else if (node->details->online) {
2614 // Display online node in a list
2615 if (pcmk__is_guest_or_bundle_node(node)) {
2616 pcmk__add_word(&online_guest_nodes, 1024, node_name);
2617
2618 } else if (pcmk__is_remote_node(node)) {
2619 pcmk__add_word(&online_remote_nodes, 1024, node_name);
2620
2621 } else {
2622 pcmk__add_word(&online_nodes, 1024, node_name);
2623 }
2624 free(node_name);
2625 continue;
2626
2627 } else {
2628 // Display offline node in a list
2629 if (pcmk__is_remote_node(node)) {
2630 pcmk__add_word(&offline_remote_nodes, 1024, node_name);
2631
2632 } else if (pcmk__is_guest_or_bundle_node(node)) {
2633 /* ignore offline guest nodes */
2634
2635 } else {
2636 pcmk__add_word(&offline_nodes, 1024, node_name);
2637 }
2638 free(node_name);
2639 continue;
2640 }
2641
2642 /* If we get here, node is in bad state, or we're grouping by node */
2643 out->message(out, "node", node, show_opts, true, only_node, only_rsc);
2644 free(node_name);
2645 }
2646
2647 /* If we're not grouping by node, summarize nodes by status */
2648 if (online_nodes != NULL) {
2649 out->list_item(out, "Online", "[ %s ]",
2650 (const char *) online_nodes->str);
2651 g_string_free(online_nodes, TRUE);
2652 }
2653 if (offline_nodes != NULL) {
2654 out->list_item(out, "OFFLINE", "[ %s ]",
2655 (const char *) offline_nodes->str);
2656 g_string_free(offline_nodes, TRUE);
2657 }
2658 if (online_remote_nodes) {
2659 out->list_item(out, "RemoteOnline", "[ %s ]",
2660 (const char *) online_remote_nodes->str);
2661 g_string_free(online_remote_nodes, TRUE);
2662 }
2663 if (offline_remote_nodes) {
2664 out->list_item(out, "RemoteOFFLINE", "[ %s ]",
2665 (const char *) offline_remote_nodes->str);
2666 g_string_free(offline_remote_nodes, TRUE);
2667 }
2668 if (online_guest_nodes != NULL) {
2669 out->list_item(out, "GuestOnline", "[ %s ]",
2670 (const char *) online_guest_nodes->str);
2671 g_string_free(online_guest_nodes, TRUE);
2672 }
2673
2674 PCMK__OUTPUT_LIST_FOOTER(out, rc);
2675 return rc;
2676}
2677
2678PCMK__OUTPUT_ARGS("node-list", "GList *", "GList *", "GList *", "uint32_t", "bool")
2679static int
2680node_list_xml(pcmk__output_t *out, va_list args) {
2681 GList *nodes = va_arg(args, GList *);
2682 GList *only_node = va_arg(args, GList *);
2683 GList *only_rsc = va_arg(args, GList *);
2684 uint32_t show_opts = va_arg(args, uint32_t);
2685 bool print_spacer G_GNUC_UNUSED = va_arg(args, int);
2686
2687 /* PCMK_XE_NODES acts as the list's element name for CLI tools that use
2688 * pcmk__output_enable_list_element. Otherwise PCMK_XE_NODES is the
2689 * value of the list's PCMK_XA_NAME attribute.
2690 */
2691 out->begin_list(out, NULL, NULL, PCMK_XE_NODES);
2692 for (GList *gIter = nodes; gIter != NULL; gIter = gIter->next) {
2693 pcmk_node_t *node = (pcmk_node_t *) gIter->data;
2694
2695 if (!pcmk__str_in_list(node->priv->name, only_node,
2697 continue;
2698 }
2699
2700 out->message(out, "node", node, show_opts, true, only_node, only_rsc);
2701 }
2702 out->end_list(out);
2703
2704 return pcmk_rc_ok;
2705}
2706
2707PCMK__OUTPUT_ARGS("node-summary", "pcmk_scheduler_t *", "GList *", "GList *",
2708 "uint32_t", "uint32_t", "bool")
2709static int
2710node_summary(pcmk__output_t *out, va_list args) {
2711 pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
2712 GList *only_node = va_arg(args, GList *);
2713 GList *only_rsc = va_arg(args, GList *);
2714 uint32_t section_opts = va_arg(args, uint32_t);
2715 uint32_t show_opts = va_arg(args, uint32_t);
2716 bool print_spacer = va_arg(args, int);
2717
2718 xmlNode *node_state = NULL;
2719 xmlNode *cib_status = pcmk_find_cib_element(scheduler->input,
2721 int rc = pcmk_rc_no_output;
2722
2723 if (xmlChildElementCount(cib_status) == 0) {
2724 return rc;
2725 }
2726
2727 for (node_state = pcmk__xe_first_child(cib_status, PCMK__XE_NODE_STATE,
2728 NULL, NULL);
2729 node_state != NULL;
2730 node_state = pcmk__xe_next(node_state, PCMK__XE_NODE_STATE)) {
2731
2733 pcmk__xe_id(node_state));
2734
2735 if (!node || !node->details || !node->details->online) {
2736 continue;
2737 }
2738
2739 if (!pcmk__str_in_list(node->priv->name, only_node,
2741 continue;
2742 }
2743
2744 PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc,
2745 pcmk_is_set(section_opts, pcmk_section_operations) ? "Operations" : "Migration Summary");
2746
2747 out->message(out, "node-history-list", scheduler, node, node_state,
2748 only_node, only_rsc, section_opts, show_opts);
2749 }
2750
2751 PCMK__OUTPUT_LIST_FOOTER(out, rc);
2752 return rc;
2753}
2754
2755PCMK__OUTPUT_ARGS("node-weight", "const pcmk_resource_t *", "const char *",
2756 "const char *", "const char *")
2757static int
2758node_weight(pcmk__output_t *out, va_list args)
2759{
2760 const pcmk_resource_t *rsc = va_arg(args, const pcmk_resource_t *);
2761 const char *prefix = va_arg(args, const char *);
2762 const char *uname = va_arg(args, const char *);
2763 const char *score = va_arg(args, const char *);
2764
2765 if (rsc) {
2766 out->list_item(out, NULL, "%s: %s allocation score on %s: %s",
2767 prefix, rsc->id, uname, score);
2768 } else {
2769 out->list_item(out, NULL, "%s: %s = %s", prefix, uname, score);
2770 }
2771
2772 return pcmk_rc_ok;
2773}
2774
2775PCMK__OUTPUT_ARGS("node-weight", "const pcmk_resource_t *", "const char *",
2776 "const char *", "const char *")
2777static int
2778node_weight_xml(pcmk__output_t *out, va_list args)
2779{
2780 const pcmk_resource_t *rsc = va_arg(args, const pcmk_resource_t *);
2781 const char *prefix = va_arg(args, const char *);
2782 const char *uname = va_arg(args, const char *);
2783 const char *score = va_arg(args, const char *);
2784
2786 PCMK_XA_FUNCTION, prefix,
2788 PCMK_XA_SCORE, score,
2789 NULL);
2790
2791 if (rsc) {
2792 crm_xml_add(node, PCMK_XA_ID, rsc->id);
2793 }
2794
2795 return pcmk_rc_ok;
2796}
2797
2798PCMK__OUTPUT_ARGS("op-history", "xmlNode *", "const char *", "const char *", "int", "uint32_t")
2799static int
2800op_history_text(pcmk__output_t *out, va_list args) {
2801 xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
2802 const char *task = va_arg(args, const char *);
2803 const char *interval_ms_s = va_arg(args, const char *);
2804 int rc = va_arg(args, int);
2805 uint32_t show_opts = va_arg(args, uint32_t);
2806
2807 char *buf = op_history_string(xml_op, task, interval_ms_s, rc,
2808 pcmk_is_set(show_opts, pcmk_show_timing));
2809
2810 out->list_item(out, NULL, "%s", buf);
2811
2812 free(buf);
2813 return pcmk_rc_ok;
2814}
2815
2816PCMK__OUTPUT_ARGS("op-history", "xmlNode *", "const char *", "const char *", "int", "uint32_t")
2817static int
2818op_history_xml(pcmk__output_t *out, va_list args) {
2819 xmlNodePtr xml_op = va_arg(args, xmlNodePtr);
2820 const char *task = va_arg(args, const char *);
2821 const char *interval_ms_s = va_arg(args, const char *);
2822 int rc = va_arg(args, int);
2823 uint32_t show_opts = va_arg(args, uint32_t);
2824
2825 const char *call_id = crm_element_value(xml_op, PCMK__XA_CALL_ID);
2826 char *rc_s = pcmk__itoa(rc);
2827 const char *rc_text = crm_exit_str(rc);
2828 xmlNodePtr node = NULL;
2829
2831 PCMK_XA_CALL, call_id,
2832 PCMK_XA_TASK, task,
2833 PCMK_XA_RC, rc_s,
2834 PCMK_XA_RC_TEXT, rc_text,
2835 NULL);
2836 free(rc_s);
2837
2838 if (interval_ms_s && !pcmk__str_eq(interval_ms_s, "0", pcmk__str_casei)) {
2839 char *s = crm_strdup_printf("%sms", interval_ms_s);
2840 crm_xml_add(node, PCMK_XA_INTERVAL, s);
2841 free(s);
2842 }
2843
2844 if (pcmk_is_set(show_opts, pcmk_show_timing)) {
2845 const char *value = NULL;
2846 time_t epoch = 0;
2847
2849 &epoch) == pcmk_ok) && (epoch > 0)) {
2850 char *s = pcmk__epoch2str(&epoch, 0);
2852 free(s);
2853 }
2854
2855 value = crm_element_value(xml_op, PCMK_XA_EXEC_TIME);
2856 if (value) {
2857 char *s = crm_strdup_printf("%sms", value);
2859 free(s);
2860 }
2861 value = crm_element_value(xml_op, PCMK_XA_QUEUE_TIME);
2862 if (value) {
2863 char *s = crm_strdup_printf("%sms", value);
2865 free(s);
2866 }
2867 }
2868
2869 return pcmk_rc_ok;
2870}
2871
2872PCMK__OUTPUT_ARGS("promotion-score", "pcmk_resource_t *", "pcmk_node_t *",
2873 "const char *")
2874static int
2875promotion_score(pcmk__output_t *out, va_list args)
2876{
2877 pcmk_resource_t *child_rsc = va_arg(args, pcmk_resource_t *);
2878 pcmk_node_t *chosen = va_arg(args, pcmk_node_t *);
2879 const char *score = va_arg(args, const char *);
2880
2881 if (chosen == NULL) {
2882 out->list_item(out, NULL, "%s promotion score (inactive): %s",
2883 child_rsc->id, score);
2884 } else {
2885 out->list_item(out, NULL, "%s promotion score on %s: %s",
2886 child_rsc->id, pcmk__node_name(chosen), score);
2887 }
2888 return pcmk_rc_ok;
2889}
2890
2891PCMK__OUTPUT_ARGS("promotion-score", "pcmk_resource_t *", "pcmk_node_t *",
2892 "const char *")
2893static int
2894promotion_score_xml(pcmk__output_t *out, va_list args)
2895{
2896 pcmk_resource_t *child_rsc = va_arg(args, pcmk_resource_t *);
2897 pcmk_node_t *chosen = va_arg(args, pcmk_node_t *);
2898 const char *score = va_arg(args, const char *);
2899
2901 PCMK_XA_ID, child_rsc->id,
2902 PCMK_XA_SCORE, score,
2903 NULL);
2904
2905 if (chosen) {
2906 crm_xml_add(node, PCMK_XA_NODE, chosen->priv->name);
2907 }
2908
2909 return pcmk_rc_ok;
2910}
2911
2912PCMK__OUTPUT_ARGS("resource-config", "const pcmk_resource_t *", "bool")
2913static int
2914resource_config(pcmk__output_t *out, va_list args) {
2915 const pcmk_resource_t *rsc = va_arg(args, const pcmk_resource_t *);
2916 GString *xml_buf = g_string_sized_new(1024);
2917 bool raw = va_arg(args, int);
2918
2919 formatted_xml_buf(rsc, xml_buf, raw);
2920
2921 out->output_xml(out, PCMK_XE_XML, xml_buf->str);
2922
2923 g_string_free(xml_buf, TRUE);
2924 return pcmk_rc_ok;
2925}
2926
2927PCMK__OUTPUT_ARGS("resource-config", "const pcmk_resource_t *", "bool")
2928static int
2929resource_config_text(pcmk__output_t *out, va_list args) {
2930 pcmk__formatted_printf(out, "Resource XML:\n");
2931 return resource_config(out, args);
2932}
2933
2934PCMK__OUTPUT_ARGS("resource-history", "pcmk_resource_t *", "const char *",
2935 "bool", "int", "time_t", "bool")
2936static int
2937resource_history_text(pcmk__output_t *out, va_list args) {
2938 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
2939 const char *rsc_id = va_arg(args, const char *);
2940 bool all = va_arg(args, int);
2941 int failcount = va_arg(args, int);
2942 time_t last_failure = va_arg(args, time_t);
2943 bool as_header = va_arg(args, int);
2944
2945 char *buf = resource_history_string(rsc, rsc_id, all, failcount, last_failure);
2946
2947 if (as_header) {
2948 out->begin_list(out, NULL, NULL, "%s", buf);
2949 } else {
2950 out->list_item(out, NULL, "%s", buf);
2951 }
2952
2953 free(buf);
2954 return pcmk_rc_ok;
2955}
2956
2957PCMK__OUTPUT_ARGS("resource-history", "pcmk_resource_t *", "const char *",
2958 "bool", "int", "time_t", "bool")
2959static int
2960resource_history_xml(pcmk__output_t *out, va_list args) {
2961 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
2962 const char *rsc_id = va_arg(args, const char *);
2963 bool all = va_arg(args, int);
2964 int failcount = va_arg(args, int);
2965 time_t last_failure = va_arg(args, time_t);
2966 bool as_header = va_arg(args, int);
2967
2968 xmlNodePtr node = pcmk__output_xml_create_parent(out,
2970 PCMK_XA_ID, rsc_id,
2971 NULL);
2972
2973 if (rsc == NULL) {
2975 } else if (all || failcount || last_failure > 0) {
2976 char *migration_s = pcmk__itoa(rsc->priv->ban_after_failures);
2977
2978 pcmk__xe_set_props(node,
2980 PCMK_META_MIGRATION_THRESHOLD, migration_s,
2981 NULL);
2982 free(migration_s);
2983
2984 if (failcount > 0) {
2985 char *s = pcmk__itoa(failcount);
2986
2988 free(s);
2989 }
2990
2991 if (last_failure > 0) {
2992 char *s = pcmk__epoch2str(&last_failure, 0);
2993
2995 free(s);
2996 }
2997 }
2998
2999 if (!as_header) {
3001 }
3002
3003 return pcmk_rc_ok;
3004}
3005
3006static void
3007print_resource_header(pcmk__output_t *out, uint32_t show_opts)
3008{
3009 if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
3010 /* Active resources have already been printed by node */
3011 out->begin_list(out, NULL, NULL, "Inactive Resources");
3012 } else if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
3013 out->begin_list(out, NULL, NULL, "Full List of Resources");
3014 } else {
3015 out->begin_list(out, NULL, NULL, "Active Resources");
3016 }
3017}
3018
3019
3020PCMK__OUTPUT_ARGS("resource-list", "pcmk_scheduler_t *", "uint32_t", "bool",
3021 "GList *", "GList *", "bool")
3022static int
3023resource_list(pcmk__output_t *out, va_list args)
3024{
3025 pcmk_scheduler_t *scheduler = va_arg(args, pcmk_scheduler_t *);
3026 uint32_t show_opts = va_arg(args, uint32_t);
3027 bool print_summary = va_arg(args, int);
3028 GList *only_node = va_arg(args, GList *);
3029 GList *only_rsc = va_arg(args, GList *);
3030 bool print_spacer = va_arg(args, int);
3031
3032 GList *rsc_iter;
3033 int rc = pcmk_rc_no_output;
3034 bool printed_header = false;
3035
3036 /* If we already showed active resources by node, and
3037 * we're not showing inactive resources, we have nothing to do
3038 */
3039 if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node) &&
3040 !pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
3041 return rc;
3042 }
3043
3044 /* If we haven't already printed resources grouped by node,
3045 * and brief output was requested, print resource summary */
3046 if (pcmk_is_set(show_opts, pcmk_show_brief)
3047 && !pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
3048 GList *rscs = pe__filter_rsc_list(scheduler->priv->resources, only_rsc);
3049
3050 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
3051 print_resource_header(out, show_opts);
3052 printed_header = true;
3053
3054 rc = pe__rscs_brief_output(out, rscs, show_opts);
3055 g_list_free(rscs);
3056 }
3057
3058 /* For each resource, display it if appropriate */
3059 for (rsc_iter = scheduler->priv->resources;
3060 rsc_iter != NULL; rsc_iter = rsc_iter->next) {
3061
3062 pcmk_resource_t *rsc = (pcmk_resource_t *) rsc_iter->data;
3063 int x;
3064
3065 /* Complex resources may have some sub-resources active and some inactive */
3066 bool is_active = rsc->priv->fns->active(rsc, true);
3067 bool partially_active = rsc->priv->fns->active(rsc, false);
3068
3069 /* Skip inactive orphans (deleted but still in CIB) */
3070 if (pcmk_is_set(rsc->flags, pcmk__rsc_removed) && !is_active) {
3071 continue;
3072
3073 /* Skip active resources if we already displayed them by node */
3074 } else if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
3075 if (is_active) {
3076 continue;
3077 }
3078
3079 /* Skip primitives already counted in a brief summary */
3080 } else if (pcmk_is_set(show_opts, pcmk_show_brief)
3081 && pcmk__is_primitive(rsc)) {
3082 continue;
3083
3084 /* Skip resources that aren't at least partially active,
3085 * unless we're displaying inactive resources
3086 */
3087 } else if (!partially_active && !pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
3088 continue;
3089
3090 } else if (partially_active && !pe__rsc_running_on_any(rsc, only_node)) {
3091 continue;
3092 }
3093
3094 if (!printed_header) {
3095 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
3096 print_resource_header(out, show_opts);
3097 printed_header = true;
3098 }
3099
3100 /* Print this resource */
3101 x = out->message(out, (const char *) rsc->priv->xml->name,
3102 show_opts, rsc, only_node, only_rsc);
3103 if (x == pcmk_rc_ok) {
3104 rc = pcmk_rc_ok;
3105 }
3106 }
3107
3108 if (print_summary && rc != pcmk_rc_ok) {
3109 if (!printed_header) {
3110 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
3111 print_resource_header(out, show_opts);
3112 printed_header = true;
3113 }
3114
3115 /* @FIXME It looks as if we can return pcmk_rc_no_output even after
3116 * writing output here.
3117 */
3118 if (pcmk_is_set(show_opts, pcmk_show_rscs_by_node)) {
3119 out->list_item(out, NULL, "No inactive resources");
3120 } else if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
3121 out->list_item(out, NULL, "No resources");
3122 } else {
3123 out->list_item(out, NULL, "No active resources");
3124 }
3125 }
3126
3127 if (printed_header) {
3128 out->end_list(out);
3129 }
3130
3131 return rc;
3132}
3133
3134PCMK__OUTPUT_ARGS("resource-operation-list", "pcmk_scheduler_t *",
3135 "pcmk_resource_t *", "pcmk_node_t *", "GList *", "uint32_t")
3136static int
3137resource_operation_list(pcmk__output_t *out, va_list args)
3138{
3139 pcmk_scheduler_t *scheduler G_GNUC_UNUSED = va_arg(args,
3141 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
3142 pcmk_node_t *node = va_arg(args, pcmk_node_t *);
3143 GList *op_list = va_arg(args, GList *);
3144 uint32_t show_opts = va_arg(args, uint32_t);
3145
3146 GList *gIter = NULL;
3147 int rc = pcmk_rc_no_output;
3148
3149 /* Print each operation */
3150 for (gIter = op_list; gIter != NULL; gIter = gIter->next) {
3151 xmlNode *xml_op = (xmlNode *) gIter->data;
3152 const char *task = crm_element_value(xml_op, PCMK_XA_OPERATION);
3153 const char *interval_ms_s = crm_element_value(xml_op,
3155 const char *op_rc = crm_element_value(xml_op, PCMK__XA_RC_CODE);
3156 int op_rc_i;
3157
3158 pcmk__scan_min_int(op_rc, &op_rc_i, 0);
3159
3160 /* Display 0-interval monitors as "probe" */
3161 if (pcmk__str_eq(task, PCMK_ACTION_MONITOR, pcmk__str_casei)
3162 && pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches | pcmk__str_casei)) {
3163 task = "probe";
3164 }
3165
3166 /* If this is the first printed operation, print heading for resource */
3167 if (rc == pcmk_rc_no_output) {
3168 time_t last_failure = 0;
3169 int failcount = pe_get_failcount(node, rsc, &last_failure,
3170 pcmk__fc_default, NULL);
3171
3172 out->message(out, "resource-history", rsc, rsc_printable_id(rsc), true,
3173 failcount, last_failure, true);
3174 rc = pcmk_rc_ok;
3175 }
3176
3177 /* Print the operation */
3178 out->message(out, "op-history", xml_op, task, interval_ms_s,
3179 op_rc_i, show_opts);
3180 }
3181
3182 /* Free the list we created (no need to free the individual items) */
3183 g_list_free(op_list);
3184
3185 PCMK__OUTPUT_LIST_FOOTER(out, rc);
3186 return rc;
3187}
3188
3189PCMK__OUTPUT_ARGS("resource-util", "pcmk_resource_t *", "pcmk_node_t *",
3190 "const char *")
3191static int
3192resource_util(pcmk__output_t *out, va_list args)
3193{
3194 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
3195 pcmk_node_t *node = va_arg(args, pcmk_node_t *);
3196 const char *fn = va_arg(args, const char *);
3197
3198 char *dump_text = crm_strdup_printf("%s: %s utilization on %s:",
3199 fn, rsc->id, pcmk__node_name(node));
3200
3201 g_hash_table_foreach(rsc->priv->utilization, append_dump_text,
3202 &dump_text);
3203 out->list_item(out, NULL, "%s", dump_text);
3204 free(dump_text);
3205
3206 return pcmk_rc_ok;
3207}
3208
3209PCMK__OUTPUT_ARGS("resource-util", "pcmk_resource_t *", "pcmk_node_t *",
3210 "const char *")
3211static int
3212resource_util_xml(pcmk__output_t *out, va_list args)
3213{
3214 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
3215 pcmk_node_t *node = va_arg(args, pcmk_node_t *);
3216 const char *uname = node->priv->name;
3217 const char *fn = va_arg(args, const char *);
3218
3219 xmlNodePtr xml_node = NULL;
3220
3222 PCMK_XA_RESOURCE, rsc->id,
3224 PCMK_XA_FUNCTION, fn,
3225 NULL);
3226 g_hash_table_foreach(rsc->priv->utilization, add_dump_node, xml_node);
3227
3228 return pcmk_rc_ok;
3229}
3230
3231static inline const char *
3232ticket_status(pcmk__ticket_t *ticket)
3233{
3234 if (pcmk_is_set(ticket->flags, pcmk__ticket_granted)) {
3235 return PCMK_VALUE_GRANTED;
3236 }
3237 return PCMK_VALUE_REVOKED;
3238}
3239
3240static inline const char *
3241ticket_standby_text(pcmk__ticket_t *ticket)
3242{
3243 return pcmk_is_set(ticket->flags, pcmk__ticket_standby)? " [standby]" : "";
3244}
3245
3246PCMK__OUTPUT_ARGS("ticket", "pcmk__ticket_t *", "bool", "bool")
3247static int
3248ticket_default(pcmk__output_t *out, va_list args) {
3249 pcmk__ticket_t *ticket = va_arg(args, pcmk__ticket_t *);
3250 bool raw = va_arg(args, int);
3251 bool details = va_arg(args, int);
3252
3253 GString *detail_str = NULL;
3254
3255 if (raw) {
3256 out->list_item(out, ticket->id, "%s", ticket->id);
3257 return pcmk_rc_ok;
3258 }
3259
3260 if (details && g_hash_table_size(ticket->state) > 0) {
3261 GHashTableIter iter;
3262 const char *name = NULL;
3263 const char *value = NULL;
3264 bool already_added = false;
3265
3266 detail_str = g_string_sized_new(100);
3267 pcmk__g_strcat(detail_str, "\t(", NULL);
3268
3269 g_hash_table_iter_init(&iter, ticket->state);
3270 while (g_hash_table_iter_next(&iter, (void **) &name, (void **) &value)) {
3271 if (already_added) {
3272 g_string_append_printf(detail_str, ", %s=", name);
3273 } else {
3274 g_string_append_printf(detail_str, "%s=", name);
3275 already_added = true;
3276 }
3277
3278 if (pcmk__str_any_of(name, PCMK_XA_LAST_GRANTED, "expires", NULL)) {
3279 char *epoch_str = NULL;
3280 long long time_ll;
3281
3282 (void) pcmk__scan_ll(value, &time_ll, 0);
3283 epoch_str = pcmk__epoch2str((const time_t *) &time_ll, 0);
3284 pcmk__g_strcat(detail_str, epoch_str, NULL);
3285 free(epoch_str);
3286 } else {
3287 pcmk__g_strcat(detail_str, value, NULL);
3288 }
3289 }
3290
3291 pcmk__g_strcat(detail_str, ")", NULL);
3292 }
3293
3294 if (ticket->last_granted > -1) {
3295 /* Prior to the introduction of the details & raw arguments to this
3296 * function, last-granted would always be added in this block. We need
3297 * to preserve that behavior. At the same time, we also need to preserve
3298 * the existing behavior from crm_ticket, which would include last-granted
3299 * as part of the (...) detail string.
3300 *
3301 * Luckily we can check detail_str - if it's NULL, either there were no
3302 * details, or we are preserving the previous behavior of this function.
3303 * If it's not NULL, we are either preserving the previous behavior of
3304 * crm_ticket or we were given details=true as an argument.
3305 */
3306 if (detail_str == NULL) {
3307 char *epoch_str = pcmk__epoch2str(&(ticket->last_granted), 0);
3308
3309 out->list_item(out, NULL, "%s\t%s%s last-granted=\"%s\"",
3310 ticket->id, ticket_status(ticket),
3311 ticket_standby_text(ticket), pcmk__s(epoch_str, ""));
3312 free(epoch_str);
3313 } else {
3314 out->list_item(out, NULL, "%s\t%s%s %s",
3315 ticket->id, ticket_status(ticket),
3316 ticket_standby_text(ticket), detail_str->str);
3317 }
3318 } else {
3319 out->list_item(out, NULL, "%s\t%s%s%s", ticket->id,
3320 ticket_status(ticket),
3321 ticket_standby_text(ticket),
3322 detail_str != NULL ? detail_str->str : "");
3323 }
3324
3325 if (detail_str != NULL) {
3326 g_string_free(detail_str, TRUE);
3327 }
3328
3329 return pcmk_rc_ok;
3330}
3331
3332PCMK__OUTPUT_ARGS("ticket", "pcmk__ticket_t *", "bool", "bool")
3333static int
3334ticket_xml(pcmk__output_t *out, va_list args) {
3335 pcmk__ticket_t *ticket = va_arg(args, pcmk__ticket_t *);
3336 bool raw G_GNUC_UNUSED = va_arg(args, int);
3337 bool details G_GNUC_UNUSED = va_arg(args, int);
3338
3339 const char *standby = pcmk__flag_text(ticket->flags, pcmk__ticket_standby);
3340
3341 xmlNodePtr node = NULL;
3342 GHashTableIter iter;
3343 const char *name = NULL;
3344 const char *value = NULL;
3345
3347 PCMK_XA_ID, ticket->id,
3348 PCMK_XA_STATUS, ticket_status(ticket),
3349 PCMK_XA_STANDBY, standby,
3350 NULL);
3351
3352 if (ticket->last_granted > -1) {
3353 char *buf = pcmk__epoch2str(&ticket->last_granted, 0);
3354
3356 free(buf);
3357 }
3358
3359 g_hash_table_iter_init(&iter, ticket->state);
3360 while (g_hash_table_iter_next(&iter, (void **) &name, (void **) &value)) {
3361 /* PCMK_XA_LAST_GRANTED and "expires" are already added by the check
3362 * for ticket->last_granted above.
3363 */
3365 NULL)) {
3366 continue;
3367 }
3368
3369 crm_xml_add(node, name, value);
3370 }
3371
3372 return pcmk_rc_ok;
3373}
3374
3375PCMK__OUTPUT_ARGS("ticket-list", "GHashTable *", "bool", "bool", "bool")
3376static int
3377ticket_list(pcmk__output_t *out, va_list args) {
3378 GHashTable *tickets = va_arg(args, GHashTable *);
3379 bool print_spacer = va_arg(args, int);
3380 bool raw = va_arg(args, int);
3381 bool details = va_arg(args, int);
3382
3383 GHashTableIter iter;
3384 gpointer value;
3385
3386 if (g_hash_table_size(tickets) == 0) {
3387 return pcmk_rc_no_output;
3388 }
3389
3390 PCMK__OUTPUT_SPACER_IF(out, print_spacer);
3391
3392 /* Print section heading */
3393 out->begin_list(out, NULL, NULL, "Tickets");
3394
3395 /* Print each ticket */
3396 g_hash_table_iter_init(&iter, tickets);
3397 while (g_hash_table_iter_next(&iter, NULL, &value)) {
3398 pcmk__ticket_t *ticket = (pcmk__ticket_t *) value;
3399 out->message(out, "ticket", ticket, raw, details);
3400 }
3401
3402 /* Close section */
3403 out->end_list(out);
3404 return pcmk_rc_ok;
3405}
3406
3407static pcmk__message_entry_t fmt_functions[] = {
3408 { "ban", "default", ban_text },
3409 { "ban", "html", ban_html },
3410 { "ban", "xml", ban_xml },
3411 { "ban-list", "default", ban_list },
3412 { "bundle", "default", pe__bundle_text },
3413 { "bundle", "xml", pe__bundle_xml },
3414 { "bundle", "html", pe__bundle_html },
3415 { "clone", "default", pe__clone_default },
3416 { "clone", "xml", pe__clone_xml },
3417 { "cluster-counts", "default", cluster_counts_text },
3418 { "cluster-counts", "html", cluster_counts_html },
3419 { "cluster-counts", "xml", cluster_counts_xml },
3420 { "cluster-dc", "default", cluster_dc_text },
3421 { "cluster-dc", "html", cluster_dc_html },
3422 { "cluster-dc", "xml", cluster_dc_xml },
3423 { "cluster-options", "default", cluster_options_text },
3424 { "cluster-options", "html", cluster_options_html },
3425 { "cluster-options", "log", cluster_options_log },
3426 { "cluster-options", "xml", cluster_options_xml },
3427 { "cluster-summary", "default", cluster_summary },
3428 { "cluster-summary", "html", cluster_summary_html },
3429 { "cluster-stack", "default", cluster_stack_text },
3430 { "cluster-stack", "html", cluster_stack_html },
3431 { "cluster-stack", "xml", cluster_stack_xml },
3432 { "cluster-times", "default", cluster_times_text },
3433 { "cluster-times", "html", cluster_times_html },
3434 { "cluster-times", "xml", cluster_times_xml },
3435 { "failed-action", "default", failed_action_default },
3436 { "failed-action", "xml", failed_action_xml },
3437 { "failed-action-list", "default", failed_action_list },
3438 { "group", "default", pe__group_default},
3439 { "group", "xml", pe__group_xml },
3440 { "maint-mode", "text", cluster_maint_mode_text },
3441 { "node", "default", node_text },
3442 { "node", "html", node_html },
3443 { "node", "xml", node_xml },
3444 { "node-and-op", "default", node_and_op },
3445 { "node-and-op", "xml", node_and_op_xml },
3446 { "node-capacity", "default", node_capacity },
3447 { "node-capacity", "xml", node_capacity_xml },
3448 { "node-history-list", "default", node_history_list },
3449 { "node-list", "default", node_list_text },
3450 { "node-list", "html", node_list_html },
3451 { "node-list", "xml", node_list_xml },
3452 { "node-weight", "default", node_weight },
3453 { "node-weight", "xml", node_weight_xml },
3454 { "node-attribute", "default", node_attribute_text },
3455 { "node-attribute", "html", node_attribute_html },
3456 { "node-attribute", "xml", node_attribute_xml },
3457 { "node-attribute-list", "default", node_attribute_list },
3458 { "node-summary", "default", node_summary },
3459 { "op-history", "default", op_history_text },
3460 { "op-history", "xml", op_history_xml },
3461 { "primitive", "default", pe__resource_text },
3462 { "primitive", "xml", pe__resource_xml },
3463 { "primitive", "html", pe__resource_html },
3464 { "promotion-score", "default", promotion_score },
3465 { "promotion-score", "xml", promotion_score_xml },
3466 { "resource-config", "default", resource_config },
3467 { "resource-config", "text", resource_config_text },
3468 { "resource-history", "default", resource_history_text },
3469 { "resource-history", "xml", resource_history_xml },
3470 { "resource-list", "default", resource_list },
3471 { "resource-operation-list", "default", resource_operation_list },
3472 { "resource-util", "default", resource_util },
3473 { "resource-util", "xml", resource_util_xml },
3474 { "ticket", "default", ticket_default },
3475 { "ticket", "xml", ticket_xml },
3476 { "ticket-list", "default", ticket_list },
3477
3478 { NULL, NULL, NULL }
3479};
3480
3481void
3483 pcmk__register_messages(out, fmt_functions);
3484}
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition actions.c:278
#define PCMK_ACTION_MONITOR
Definition actions.h:51
#define PCMK_ACTION_NOTIFY
Definition actions.h:53
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition agents.c:27
@ pcmk_ra_cap_provider
Definition agents.h:55
const char * pcmk__node_attr(const pcmk_node_t *node, const char *name, const char *target, enum pcmk__rsc_node node_type)
Definition attrs.c:114
const char * parent
Definition cib.c:27
const char * name
Definition cib.c:26
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition cib.c:172
char * pcmk__format_nvpair(const char *name, const char *value, const char *units)
Definition nvpair.c:176
#define pcmk__assert_alloc(nmemb, size)
Definition internal.h:246
uint64_t flags
Definition remote.c:3
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:80
GHashTable * pe_rsc_params(pcmk_resource_t *rsc, const pcmk_node_t *node, pcmk_scheduler_t *scheduler)
Get a table of resource parameters.
Definition complex.c:462
char uname[MAX_NAME]
Definition cpg.c:5
enum pcmk_ipc_server type
Definition cpg.c:3
#define CRM_ATTR_FEATURE_SET
Definition crm.h:103
@ pcmk__fc_default
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:2151
const char * pcmk__readable_interval(guint interval_ms)
Definition iso8601.c:2210
#define CRM_CHECK(expr, failure_action)
Definition logging.h:213
pcmk_scheduler_t * scheduler
@ pcmk__node_fail_standby
@ pcmk__node_standby
@ pcmk__node_expected_up
pcmk__node_variant
@ pcmk__node_variant_remote
@ pcmk__node_variant_cluster
#define PCMK_META_INTERVAL
Definition options.h:92
#define PCMK_META_MIGRATION_THRESHOLD
Definition options.h:96
#define PCMK_VALUE_UNKNOWN
Definition options.h:221
#define PCMK_META_ON_FAIL
Definition options.h:99
#define PCMK_VALUE_REVOKED
Definition options.h:205
#define PCMK_VALUE_GRANTED
Definition options.h:158
#define PCMK_VALUE_OFFLINE
Definition options.h:186
#define PCMK_VALUE_TRUE
Definition options.h:219
#define PCMK_VALUE_YELLOW
Definition options.h:225
#define PCMK_VALUE_STANDBY
Definition options.h:209
#define PCMK_VALUE_DEMOTE
Definition options.h:147
#define PCMK_VALUE_FREEZE
Definition options.h:157
#define PCMK_VALUE_REMOTE
Definition options.h:202
#define PCMK_META_TARGET_ROLE
Definition options.h:114
#define PCMK_VALUE_IGNORE
Definition options.h:163
#define PCMK_VALUE_GREEN
Definition options.h:159
#define PCMK_VALUE_FENCE
Definition options.h:155
#define PCMK_VALUE_MEMBER
Definition options.h:171
#define PCMK_VALUE_FALSE
Definition options.h:154
#define PCMK_VALUE_RED
Definition options.h:201
#define PCMK_VALUE_STOP
Definition options.h:213
#define PCMK_VALUE_ONLINE
Definition options.h:187
#define PCMK__VALUE_MAINT
#define PCMK__VALUE_HEALTH_YELLOW
#define PCMK__VALUE_WARNING
#define PCMK__VALUE_HEALTH_RED
#define PCMK__VALUE_BOLD
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:566
xmlNodePtr pcmk__output_xml_create_parent(pcmk__output_t *out, const char *name,...) G_GNUC_NULL_TERMINATED
Definition output_xml.c:482
void pcmk__output_xml_push_parent(pcmk__output_t *out, xmlNodePtr parent)
Definition output_xml.c:552
xmlNodePtr pcmk__output_xml_peek_parent(pcmk__output_t *out)
Definition output_xml.c:582
void pcmk__register_messages(pcmk__output_t *out, const pcmk__message_entry_t *table)
Definition output.c:206
xmlNode * pcmk__html_create(xmlNode *parent, const char *name, const char *id, const char *class_name)
#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:519
void void void pcmk__formatted_printf(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
#define PCMK__OUTPUT_LIST_FOOTER(out_obj, retcode)
const char * pe__resource_description(const pcmk_resource_t *rsc, uint32_t show_opts)
Definition pe_output.c:24
#define FILTER_STR
Definition pe_output.c:36
#define XPATH_STACK
Definition pe_output.c:198
#define XPATH_DC_VERSION
Definition pe_output.c:402
void pe__register_messages(pcmk__output_t *out)
Definition pe_output.c:3482
int pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name,...)
Definition pe_output.c:619
char * pe__node_display_name(pcmk_node_t *node, bool print_detail)
Definition pe_output.c:562
int pe__clone_xml(pcmk__output_t *out, va_list args)
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition complex.c:1025
bool pe__rsc_running_on_any(pcmk_resource_t *rsc, GList *node_list)
Definition utils.c:767
int pe__bundle_xml(pcmk__output_t *out, va_list args)
int pe__group_xml(pcmk__output_t *out, va_list args)
int pe__node_health(pcmk_node_t *node)
Definition pe_health.c:130
int pe__bundle_html(pcmk__output_t *out, va_list args)
int pe__clone_default(pcmk__output_t *out, va_list args)
GList * pe__filter_rsc_list(GList *rscs, GList *filter)
Definition utils.c:789
int pe_get_failcount(const pcmk_node_t *node, pcmk_resource_t *rsc, time_t *last_failure, uint32_t flags, const xmlNode *xml_op)
Definition failcounts.c:367
int pe__bundle_text(pcmk__output_t *out, va_list args)
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
int pe__rscs_brief_output(pcmk__output_t *out, GList *rsc_list, unsigned int options)
gchar * pcmk__native_output_string(const pcmk_resource_t *rsc, const char *name, const pcmk_node_t *node, uint32_t show_opts, const char *target_role, bool show_nodes)
Definition native.c:473
int pe__resource_xml(pcmk__output_t *out, va_list args)
int pe__group_default(pcmk__output_t *out, va_list args)
int pe__resource_text(pcmk__output_t *out, va_list args)
int pe__resource_html(pcmk__output_t *out, va_list args)
bool pcmk_xe_mask_probe_failure(const xmlNode *xml_op)
Check whether an action history entry represents a maskable probe.
Definition probes.c:70
@ pcmk__rsc_removed
@ pcmk__rsc_node_current
@ CRM_EX_NOT_RUNNING
Service safely stopped.
Definition results.h:242
@ pcmk_rc_no_output
Definition results.h:128
@ pcmk_rc_ok
Definition results.h:159
#define pcmk_ok
Definition results.h:65
const char * crm_exit_str(crm_exit_t exit_code)
Definition results.c:757
@ PCMK_EXEC_DONE
Action completed, result is known.
Definition results.h:311
@ PCMK_EXEC_UNKNOWN
Used only to initialize variables.
Definition results.h:309
#define pcmk__assert(expr)
#define PCMK_ROLE_PROMOTED
Definition roles.h:28
rsc_role_e
Definition roles.h:34
@ pcmk_role_promoted
Promoted.
Definition roles.h:39
pe_quorum_policy
Possible responses to loss of quorum.
Definition scheduler.h:38
@ pcmk_no_quorum_freeze
Do not recover resources from outside partition.
Definition scheduler.h:39
@ pcmk_no_quorum_stop
Stop all resources in partition.
Definition scheduler.h:40
@ pcmk_no_quorum_ignore
Act as if partition still holds quorum.
Definition scheduler.h:41
@ pcmk_no_quorum_demote
Demote promotable resources and stop all others.
Definition scheduler.h:43
@ pcmk_no_quorum_fence
Fence all nodes in partition.
Definition scheduler.h:42
@ pcmk__sched_in_maintenance
@ pcmk__sched_fencing_enabled
@ pcmk__sched_symmetric_cluster
@ pcmk__sched_stop_all
pcmk_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:248
pcmk_resource_t * pe_find_resource(GList *rsc_list, const char *id)
Definition status.c:191
const char * rsc_printable_id(const pcmk_resource_t *rsc)
Definition utils.c:581
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
gboolean crm_is_true(const char *s)
Definition strings.c:490
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition strings.c:116
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition strings.c:984
#define pcmk__plural_s(i)
char * pcmk__trim(char *str)
Definition strings.c:530
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
Definition strings.c:92
void pcmk__str_update(char **str, const char *value)
Definition strings.c:1280
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1029
@ pcmk__str_none
@ pcmk__str_null_matches
@ pcmk__str_star_matches
@ pcmk__str_casei
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1053
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1299
Location constraint object.
enum rsc_role_e role_filter
pcmk_resource_t * rsc
gboolean shutdown
Definition nodes.h:62
gboolean online
Definition nodes.h:50
gboolean pending
Definition nodes.h:54
GList * running_rsc
Definition nodes.h:70
gboolean maintenance
Definition nodes.h:66
gboolean unclean
Definition nodes.h:58
enum pcmk__node_variant variant
GHashTable * utilization
pcmk_resource_t * remote
pcmk_scheduler_t * scheduler
This structure contains everything that makes up a single output formatter.
void(* begin_list)(pcmk__output_t *out, const char *singular_noun, const char *plural_noun, const char *format,...) G_GNUC_PRINTF(4
void void(* list_item)(pcmk__output_t *out, const char *name, const char *format,...) G_GNUC_PRINTF(3
const pcmk_node_t * pending_node
const pcmk__rsc_methods_t * fns
unsigned long long flags
Definition resources.h:69
pcmk__resource_private_t * priv
Definition resources.h:61
bool(* is_filtered)(const pcmk_resource_t *rsc, const GList *only_rsc, bool check_parent)
bool(* active)(const pcmk_resource_t *rsc, bool all)
pcmk_node_t * dc_node
Definition scheduler.h:85
pcmk__scheduler_private_t * priv
Definition scheduler.h:99
enum pe_quorum_policy no_quorum_policy
Definition scheduler.h:93
GList * nodes
Definition scheduler.h:97
xmlNode * input
Definition scheduler.h:81
uint64_t flags
Definition scheduler.h:89
pcmk__node_private_t * priv
Definition nodes.h:85
struct pcmk__node_details * details
Definition nodes.h:82
struct pcmk__node_assignment * assign
Definition nodes.h:79
GHashTable * state
@ pcmk__ticket_granted
@ pcmk__ticket_standby
Wrappers for and extensions to libxml2.
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
int crm_element_value_epoch(const xmlNode *xml, const char *name, time_t *dest)
Retrieve the seconds-since-epoch value of an XML attribute.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml_element.c:43
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
void void pcmk__xe_set_propv(xmlNodePtr node, va_list pairs)
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
void pcmk__xe_set_content(xmlNode *node, const char *format,...) G_GNUC_PRINTF(2
void pcmk__xe_set_props(xmlNodePtr node,...) G_GNUC_NULL_TERMINATED
@ pcmk__xml_fmt_pretty
Include indentation and newlines.
bool pcmk__xml_needs_escape(const char *text, enum pcmk__xml_escape_type type)
Definition xml.c:909
@ pcmk__xml_escape_attr
char * pcmk__xml_escape(const char *text, enum pcmk__xml_escape_type type)
Definition xml.c:991
void pcmk__xml_string(const xmlNode *data, uint32_t options, GString *buffer, int depth)
Definition xml_io.c:370
#define PCMK_XA_RC
Definition xml_names.h:369
#define PCMK_XA_PROMOTED_ONLY
Definition xml_names.h:363
#define PCMK_XE_UTILIZATION
Definition xml_names.h:217
#define PCMK_XA_MAINTENANCE_MODE
Definition xml_names.h:322
#define PCMK_XA_OP_KEY
Definition xml_names.h:348
#define PCMK_XE_STATUS
Definition xml_names.h:204
#define PCMK_XA_SCORE
Definition xml_names.h:396
#define PCMK_XA_EXEC
Definition xml_names.h:269
#define PCMK_XA_COMMENT
Definition xml_names.h:249
#define PCMK_XE_TICKET
Definition xml_names.h:212
#define PCMK_XA_LAST_FAILURE
Definition xml_names.h:314
#define PCMK_XA_SHUTDOWN
Definition xml_names.h:400
#define PCMK_XA_ID_AS_RESOURCE
Definition xml_names.h:302
#define PCMK_XA_DESCRIPTION
Definition xml_names.h:261
#define PCMK_XA_RC_TEXT
Definition xml_names.h:370
#define PCMK_XA_CLASS
Definition xml_names.h:246
#define PCMK_XE_NODE
Definition xml_names.h:136
#define PCMK_XA_STONITH_TIMEOUT_MS
Definition xml_names.h:412
#define PCMK_XA_QUEUED
Definition xml_names.h:366
#define PCMK_XE_LAST_UPDATE
Definition xml_names.h:127
#define PCMK_XA_IS_DC
Definition xml_names.h:311
#define PCMK_XA_QUEUE_TIME
Definition xml_names.h:365
#define PCMK_XA_MIXED_VERSION
Definition xml_names.h:326
#define PCMK_XA_FUNCTION
Definition xml_names.h:292
#define PCMK_XA_UNCLEAN
Definition xml_names.h:432
#define PCMK_XA_UPDATE_ORIGIN
Definition xml_names.h:437
#define PCMK_XA_EXITCODE
Definition xml_names.h:275
#define PCMK_XA_TIME
Definition xml_names.h:427
#define PCMK_XA_WEIGHT
Definition xml_names.h:449
#define PCMK_XE_PROMOTION_SCORE
Definition xml_names.h:165
#define PCMK_XE_RESOURCES_CONFIGURED
Definition xml_names.h:180
#define PCMK_XA_EXITSTATUS
Definition xml_names.h:277
#define PCMK_XA_CIB_LAST_WRITTEN
Definition xml_names.h:244
#define PCMK_XA_AGENT
Definition xml_names.h:234
#define PCMK_XA_USER
Definition xml_names.h:439
#define PCMK_XA_STOP_ALL_RESOURCES
Definition xml_names.h:413
#define PCMK_XA_CLIENT
Definition xml_names.h:247
#define PCMK_XA_TASK
Definition xml_names.h:424
#define PCMK_XA_OPERATION
Definition xml_names.h:349
#define PCMK_XA_HEALTH
Definition xml_names.h:296
#define PCMK_XE_XML
Definition xml_names.h:221
#define PCMK_XE_FAILURE
Definition xml_names.h:110
#define PCMK_XA_NO_QUORUM_POLICY
Definition xml_names.h:334
#define PCMK_XA_OP
Definition xml_names.h:347
#define PCMK_XA_STATUS
Definition xml_names.h:410
#define PCMK_XA_ID
Definition xml_names.h:301
#define PCMK_XE_RESOURCE_HISTORY
Definition xml_names.h:176
#define PCMK_XA_RESOURCES_RUNNING
Definition xml_names.h:385
#define PCMK_XA_EXITREASON
Definition xml_names.h:276
#define PCMK_XE_ATTRIBUTE
Definition xml_names.h:69
#define PCMK_XE_CURRENT_DC
Definition xml_names.h:94
#define PCMK_XA_PROVIDER
Definition xml_names.h:364
#define PCMK_XA_LAST_RC_CHANGE
Definition xml_names.h:316
#define PCMK_XA_ORIGIN
Definition xml_names.h:351
#define PCMK_XA_EXPECTED_UP
Definition xml_names.h:279
#define PCMK_XA_FAIL_COUNT
Definition xml_names.h:282
#define PCMK_XA_EXEC_TIME
Definition xml_names.h:270
#define PCMK_XA_MAINTENANCE
Definition xml_names.h:321
#define PCMK_XA_HAVE_QUORUM
Definition xml_names.h:295
#define PCMK_XA_VALUE
Definition xml_names.h:442
#define PCMK_XE_NODE_WEIGHT
Definition xml_names.h:141
#define PCMK_XA_NODE
Definition xml_names.h:335
#define PCMK_XA_ONLINE
Definition xml_names.h:346
#define PCMK_XA_VERSION
Definition xml_names.h:444
#define PCMK_XA_INTERVAL
Definition xml_names.h:309
#define PCMK_XA_ORPHAN
Definition xml_names.h:352
#define PCMK_XE_CLUSTER_OPTIONS
Definition xml_names.h:83
#define PCMK_XA_LAST_GRANTED
Definition xml_names.h:315
#define PCMK_XA_EXIT_REASON
Definition xml_names.h:274
#define PCMK_XA_PRIORITY_FENCING_DELAY_MS
Definition xml_names.h:359
#define PCMK_XA_PENDING
Definition xml_names.h:356
#define PCMK_XA_TYPE
Definition xml_names.h:430
#define PCMK_XA_WITH_QUORUM
Definition xml_names.h:451
#define PCMK_XA_BLOCKED
Definition xml_names.h:239
#define PCMK_XA_UPDATE_USER
Definition xml_names.h:438
#define PCMK_XA_STANDBY_ONFAIL
Definition xml_names.h:407
#define PCMK_XE_OPERATION
Definition xml_names.h:149
#define PCMK_XE_STACK
Definition xml_names.h:202
#define PCMK_XA_STANDBY
Definition xml_names.h:406
#define PCMK_XA_SYMMETRIC_CLUSTER
Definition xml_names.h:414
#define PCMK_XA_EXPECTED
Definition xml_names.h:278
#define PCMK_XA_FEATURE_SET
Definition xml_names.h:285
#define PCMK_XA_PRESENT
Definition xml_names.h:358
#define PCMK_XE_NODES
Definition xml_names.h:142
#define PCMK_XE_LAST_CHANGE
Definition xml_names.h:125
#define PCMK_XA_NUMBER
Definition xml_names.h:342
#define PCMK_XA_UNAME
Definition xml_names.h:431
#define PCMK_XA_NAME
Definition xml_names.h:330
#define PCMK_XA_EXPIRES
Definition xml_names.h:280
#define PCMK_XE_BAN
Definition xml_names.h:70
#define PCMK_XE_OPERATION_HISTORY
Definition xml_names.h:150
#define PCMK_XA_RESOURCE
Definition xml_names.h:382
#define PCMK_XA_RSC
Definition xml_names.h:388
#define PCMK_XE_NODES_CONFIGURED
Definition xml_names.h:143
#define PCMK_XA_PACEMAKERD_STATE
Definition xml_names.h:354
#define PCMK_XA_UPDATE_CLIENT
Definition xml_names.h:436
#define PCMK_XE_CAPACITY
Definition xml_names.h:73
#define PCMK_XA_STONITH_ENABLED
Definition xml_names.h:411
#define PCMK_XA_CALL
Definition xml_names.h:243
#define PCMK_XA_DISABLED
Definition xml_names.h:265
#define PCMK__XA_PROMOTED_ONLY_LEGACY
#define PCMK__XE_SPAN
#define PCMK__XE_LRM_RSC_OP
#define PCMK__XE_LRM_RESOURCE
#define PCMK__XE_LRM_RESOURCES
#define PCMK__XA_CALL_ID
#define PCMK__XA_OPERATION_KEY
#define PCMK__XA_OP_STATUS
#define PCMK__XE_NODE_STATE
#define PCMK__XE_LRM
#define PCMK__XA_RC_CODE
xmlNode * pcmk__xpath_find_one(xmlDoc *doc, const char *path, uint8_t level)
Definition xpath.c:206