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