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