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