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