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