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