This source file includes following definitions.
- is_multiply_active
- native_priority_to_node
- native_add_running
- recursive_clear_unique
- native_unpack
- rsc_is_on_node
- native_find_rsc
- native_parameter
- native_active
- native_pending_state
- native_pending_task
- native_displayable_role
- native_displayable_state
- native_print_xml
- add_output_flag
- add_output_node
- pcmk__native_output_string
- pe__common_output_html
- pe__common_output_text
- common_print
- native_print
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- native_free
- native_resource_state
- native_location
- get_rscs_brief
- destroy_node_table
- print_rscs_brief
- pe__rscs_brief_output
- pe__native_is_filtered
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdint.h>
13
14 #include <crm/common/output.h>
15 #include <crm/pengine/rules.h>
16 #include <crm/pengine/status.h>
17 #include <crm/pengine/complex.h>
18 #include <crm/pengine/internal.h>
19 #include <crm/msg_xml.h>
20 #include <pe_status_private.h>
21
22 #define VARIANT_NATIVE 1
23 #include "./variant.h"
24
25 #ifdef PCMK__COMPAT_2_0
26 #define PROVIDER_SEP "::"
27 #else
28 #define PROVIDER_SEP ":"
29 #endif
30
31
32
33
34
35 static bool
36 is_multiply_active(pe_resource_t *rsc)
37 {
38 unsigned int count = 0;
39
40 if (rsc->variant == pe_native) {
41 pe__find_active_requires(rsc, &count);
42 }
43 return count > 1;
44 }
45
46 static void
47 native_priority_to_node(pe_resource_t * rsc, pe_node_t * node, gboolean failed)
48 {
49 int priority = 0;
50
51 if ((rsc->priority == 0) || (failed == TRUE)) {
52 return;
53 }
54
55 if (rsc->role == RSC_ROLE_PROMOTED) {
56
57 priority = rsc->priority + 1;
58
59 } else {
60 priority = rsc->priority;
61 }
62
63 node->details->priority += priority;
64 pe_rsc_trace(rsc, "Node '%s' now has priority %d with %s'%s' (priority: %d%s)",
65 node->details->uname, node->details->priority,
66 (rsc->role == RSC_ROLE_PROMOTED)? "promoted " : "",
67 rsc->id, rsc->priority,
68 (rsc->role == RSC_ROLE_PROMOTED)? " + 1" : "");
69
70
71
72 if (node->details->remote_rsc
73 && node->details->remote_rsc->container) {
74 GList *gIter = node->details->remote_rsc->container->running_on;
75
76 for (; gIter != NULL; gIter = gIter->next) {
77 pe_node_t *a_node = gIter->data;
78
79 a_node->details->priority += priority;
80 pe_rsc_trace(rsc, "Node '%s' now has priority %d with %s'%s' (priority: %d%s) "
81 "from guest node '%s'",
82 a_node->details->uname, a_node->details->priority,
83 (rsc->role == RSC_ROLE_PROMOTED)? "promoted " : "",
84 rsc->id, rsc->priority,
85 (rsc->role == RSC_ROLE_PROMOTED)? " + 1" : "",
86 node->details->uname);
87 }
88 }
89 }
90
91 void
92 native_add_running(pe_resource_t * rsc, pe_node_t * node, pe_working_set_t * data_set, gboolean failed)
93 {
94 GList *gIter = rsc->running_on;
95
96 CRM_CHECK(node != NULL, return);
97 for (; gIter != NULL; gIter = gIter->next) {
98 pe_node_t *a_node = (pe_node_t *) gIter->data;
99
100 CRM_CHECK(a_node != NULL, return);
101 if (pcmk__str_eq(a_node->details->id, node->details->id, pcmk__str_casei)) {
102 return;
103 }
104 }
105
106 pe_rsc_trace(rsc, "Adding %s to %s %s", rsc->id, node->details->uname,
107 pcmk_is_set(rsc->flags, pe_rsc_managed)? "" : "(unmanaged)");
108
109 rsc->running_on = g_list_append(rsc->running_on, node);
110 if (rsc->variant == pe_native) {
111 node->details->running_rsc = g_list_append(node->details->running_rsc, rsc);
112
113 native_priority_to_node(rsc, node, failed);
114 }
115
116 if (rsc->variant == pe_native && node->details->maintenance) {
117 pe__clear_resource_flags(rsc, pe_rsc_managed);
118 }
119
120 if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
121 pe_resource_t *p = rsc->parent;
122
123 pe_rsc_info(rsc, "resource %s isn't managed", rsc->id);
124 resource_location(rsc, node, INFINITY, "not_managed_default", data_set);
125
126 while(p && node->details->online) {
127
128 p->running_on = g_list_append(p->running_on, node);
129 p = p->parent;
130 }
131 return;
132 }
133
134 if (is_multiply_active(rsc)) {
135 switch (rsc->recovery_type) {
136 case recovery_stop_only:
137 {
138 GHashTableIter gIter;
139 pe_node_t *local_node = NULL;
140
141
142 if (rsc->allowed_nodes != NULL) {
143 g_hash_table_destroy(rsc->allowed_nodes);
144 }
145 rsc->allowed_nodes = pe__node_list2table(data_set->nodes);
146 g_hash_table_iter_init(&gIter, rsc->allowed_nodes);
147 while (g_hash_table_iter_next(&gIter, NULL, (void **)&local_node)) {
148 local_node->weight = -INFINITY;
149 }
150 }
151 break;
152 case recovery_block:
153 pe__clear_resource_flags(rsc, pe_rsc_managed);
154 pe__set_resource_flags(rsc, pe_rsc_block);
155
156
157
158
159 if (rsc->parent
160 && (rsc->parent->variant == pe_group || rsc->parent->variant == pe_container)
161 && rsc->parent->recovery_type == recovery_block) {
162 GList *gIter = rsc->parent->children;
163
164 for (; gIter != NULL; gIter = gIter->next) {
165 pe_resource_t *child = (pe_resource_t *) gIter->data;
166
167 pe__clear_resource_flags(child, pe_rsc_managed);
168 pe__set_resource_flags(child, pe_rsc_block);
169 }
170 }
171 break;
172 default:
173
174
175
176 break;
177 }
178 crm_debug("%s is active on multiple nodes including %s: %s",
179 rsc->id, node->details->uname,
180 recovery2text(rsc->recovery_type));
181
182 } else {
183 pe_rsc_trace(rsc, "Resource %s is active on: %s", rsc->id, node->details->uname);
184 }
185
186 if (rsc->parent != NULL) {
187 native_add_running(rsc->parent, node, data_set, FALSE);
188 }
189 }
190
191 static void
192 recursive_clear_unique(pe_resource_t *rsc, gpointer user_data)
193 {
194 pe__clear_resource_flags(rsc, pe_rsc_unique);
195 add_hash_param(rsc->meta, XML_RSC_ATTR_UNIQUE, XML_BOOLEAN_FALSE);
196 g_list_foreach(rsc->children, (GFunc) recursive_clear_unique, NULL);
197 }
198
199 gboolean
200 native_unpack(pe_resource_t * rsc, pe_working_set_t * data_set)
201 {
202 pe_resource_t *parent = uber_parent(rsc);
203 native_variant_data_t *native_data = NULL;
204 const char *standard = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
205 uint32_t ra_caps = pcmk_get_ra_caps(standard);
206
207 pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
208
209 native_data = calloc(1, sizeof(native_variant_data_t));
210 rsc->variant_opaque = native_data;
211
212
213 if (!pcmk_is_set(ra_caps, pcmk_ra_cap_unique)
214 && pcmk_is_set(rsc->flags, pe_rsc_unique) && pe_rsc_is_clone(parent)) {
215
216
217
218
219
220
221 pe__force_anon(standard, parent, rsc->id, data_set);
222
223
224
225
226
227
228 recursive_clear_unique(parent, NULL);
229 recursive_clear_unique(rsc, NULL);
230 }
231 if (!pcmk_is_set(ra_caps, pcmk_ra_cap_promotable)
232 && pcmk_is_set(parent->flags, pe_rsc_promotable)) {
233
234 pe_err("Resource %s is of type %s and therefore "
235 "cannot be used as a promotable clone resource",
236 rsc->id, standard);
237 return FALSE;
238 }
239 return TRUE;
240 }
241
242 static bool
243 rsc_is_on_node(pe_resource_t *rsc, const pe_node_t *node, int flags)
244 {
245 pe_rsc_trace(rsc, "Checking whether %s is on %s",
246 rsc->id, node->details->uname);
247
248 if (pcmk_is_set(flags, pe_find_current) && rsc->running_on) {
249
250 for (GList *iter = rsc->running_on; iter; iter = iter->next) {
251 pe_node_t *loc = (pe_node_t *) iter->data;
252
253 if (loc->details == node->details) {
254 return true;
255 }
256 }
257
258 } else if (pcmk_is_set(flags, pe_find_inactive)
259 && (rsc->running_on == NULL)) {
260 return true;
261
262 } else if (!pcmk_is_set(flags, pe_find_current) && rsc->allocated_to
263 && (rsc->allocated_to->details == node->details)) {
264 return true;
265 }
266 return false;
267 }
268
269 pe_resource_t *
270 native_find_rsc(pe_resource_t * rsc, const char *id, const pe_node_t *on_node,
271 int flags)
272 {
273 bool match = false;
274 pe_resource_t *result = NULL;
275
276 CRM_CHECK(id && rsc && rsc->id, return NULL);
277
278 if (flags & pe_find_clone) {
279 const char *rid = ID(rsc->xml);
280
281 if (!pe_rsc_is_clone(uber_parent(rsc))) {
282 match = false;
283
284 } else if (!strcmp(id, rsc->id) || pcmk__str_eq(id, rid, pcmk__str_none)) {
285 match = true;
286 }
287
288 } else if (!strcmp(id, rsc->id)) {
289 match = true;
290
291 } else if (pcmk_is_set(flags, pe_find_renamed)
292 && rsc->clone_name && strcmp(rsc->clone_name, id) == 0) {
293 match = true;
294
295 } else if (pcmk_is_set(flags, pe_find_any)
296 || (pcmk_is_set(flags, pe_find_anon)
297 && !pcmk_is_set(rsc->flags, pe_rsc_unique))) {
298 match = pe_base_name_eq(rsc, id);
299 }
300
301 if (match && on_node) {
302 if (!rsc_is_on_node(rsc, on_node, flags)) {
303 match = false;
304 }
305 }
306
307 if (match) {
308 return rsc;
309 }
310
311 for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
312 pe_resource_t *child = (pe_resource_t *) gIter->data;
313
314 result = rsc->fns->find_rsc(child, id, on_node, flags);
315 if (result) {
316 return result;
317 }
318 }
319 return NULL;
320 }
321
322
323 char *
324 native_parameter(pe_resource_t * rsc, pe_node_t * node, gboolean create, const char *name,
325 pe_working_set_t * data_set)
326 {
327 char *value_copy = NULL;
328 const char *value = NULL;
329 GHashTable *params = NULL;
330
331 CRM_CHECK(rsc != NULL, return NULL);
332 CRM_CHECK(name != NULL && strlen(name) != 0, return NULL);
333
334 pe_rsc_trace(rsc, "Looking up %s in %s", name, rsc->id);
335 params = pe_rsc_params(rsc, node, data_set);
336 value = g_hash_table_lookup(params, name);
337 if (value == NULL) {
338
339 value = g_hash_table_lookup(rsc->meta, name);
340 }
341 pcmk__str_update(&value_copy, value);
342 return value_copy;
343 }
344
345 gboolean
346 native_active(pe_resource_t * rsc, gboolean all)
347 {
348 for (GList *gIter = rsc->running_on; gIter != NULL; gIter = gIter->next) {
349 pe_node_t *a_node = (pe_node_t *) gIter->data;
350
351 if (a_node->details->unclean) {
352 pe_rsc_trace(rsc, "Resource %s: node %s is unclean",
353 rsc->id, a_node->details->uname);
354 return TRUE;
355 } else if (a_node->details->online == FALSE && pcmk_is_set(rsc->flags, pe_rsc_managed)) {
356 pe_rsc_trace(rsc, "Resource %s: node %s is offline",
357 rsc->id, a_node->details->uname);
358 } else {
359 pe_rsc_trace(rsc, "Resource %s active on %s",
360 rsc->id, a_node->details->uname);
361 return TRUE;
362 }
363 }
364 return FALSE;
365 }
366
367 struct print_data_s {
368 long options;
369 void *print_data;
370 };
371
372 static const char *
373 native_pending_state(pe_resource_t * rsc)
374 {
375 const char *pending_state = NULL;
376
377 if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_START, pcmk__str_casei)) {
378 pending_state = "Starting";
379
380 } else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_STOP, pcmk__str_casei)) {
381 pending_state = "Stopping";
382
383 } else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_MIGRATE, pcmk__str_casei)) {
384 pending_state = "Migrating";
385
386 } else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_MIGRATED, pcmk__str_casei)) {
387
388 pending_state = "Migrating";
389
390 } else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_PROMOTE, pcmk__str_casei)) {
391 pending_state = "Promoting";
392
393 } else if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_DEMOTE, pcmk__str_casei)) {
394 pending_state = "Demoting";
395 }
396
397 return pending_state;
398 }
399
400 static const char *
401 native_pending_task(pe_resource_t * rsc)
402 {
403 const char *pending_task = NULL;
404
405 if (pcmk__str_eq(rsc->pending_task, CRMD_ACTION_STATUS, pcmk__str_casei)) {
406 pending_task = "Monitoring";
407
408
409
410
411
412
413
414
415
416
417 }
418
419 return pending_task;
420 }
421
422 static enum rsc_role_e
423 native_displayable_role(pe_resource_t *rsc)
424 {
425 enum rsc_role_e role = rsc->role;
426
427 if ((role == RSC_ROLE_STARTED)
428 && pcmk_is_set(uber_parent(rsc)->flags, pe_rsc_promotable)) {
429
430 role = RSC_ROLE_UNPROMOTED;
431 }
432 return role;
433 }
434
435 static const char *
436 native_displayable_state(pe_resource_t *rsc, bool print_pending)
437 {
438 const char *rsc_state = NULL;
439
440 if (print_pending) {
441 rsc_state = native_pending_state(rsc);
442 }
443 if (rsc_state == NULL) {
444 rsc_state = role2text(native_displayable_role(rsc));
445 }
446 return rsc_state;
447 }
448
449 static void
450 native_print_xml(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
451 {
452 const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
453 const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
454 const char *rsc_state = native_displayable_state(rsc, pcmk_is_set(options, pe_print_pending));
455 const char *target_role = NULL;
456
457
458 status_print("%s<resource ", pre_text);
459 status_print("id=\"%s\" ", rsc_printable_id(rsc));
460 status_print("resource_agent=\"%s%s%s:%s\" ", class,
461 ((prov == NULL)? "" : PROVIDER_SEP),
462 ((prov == NULL)? "" : prov),
463 crm_element_value(rsc->xml, XML_ATTR_TYPE));
464
465 status_print("role=\"%s\" ", rsc_state);
466 if (rsc->meta) {
467 target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
468 }
469 if (target_role) {
470 status_print("target_role=\"%s\" ", target_role);
471 }
472 status_print("active=\"%s\" ", pcmk__btoa(rsc->fns->active(rsc, TRUE)));
473 status_print("orphaned=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_orphan));
474 status_print("blocked=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_block));
475 status_print("managed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_managed));
476 status_print("failed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_failed));
477 status_print("failure_ignored=\"%s\" ",
478 pe__rsc_bool_str(rsc, pe_rsc_failure_ignored));
479 status_print("nodes_running_on=\"%d\" ", g_list_length(rsc->running_on));
480
481 if (options & pe_print_pending) {
482 const char *pending_task = native_pending_task(rsc);
483
484 if (pending_task) {
485 status_print("pending=\"%s\" ", pending_task);
486 }
487 }
488
489
490 if (options & pe_print_rsconly) {
491 status_print("/>\n");
492
493 } else if (rsc->running_on != NULL) {
494 GList *gIter = rsc->running_on;
495
496 status_print(">\n");
497 for (; gIter != NULL; gIter = gIter->next) {
498 pe_node_t *node = (pe_node_t *) gIter->data;
499
500 status_print("%s <node name=\"%s\" id=\"%s\" cached=\"%s\"/>\n", pre_text,
501 node->details->uname, node->details->id,
502 pcmk__btoa(node->details->online == FALSE));
503 }
504 status_print("%s</resource>\n", pre_text);
505 } else {
506 status_print("/>\n");
507 }
508 }
509
510
511 static bool
512 add_output_flag(GString *s, const char *flag_desc, bool have_flags)
513 {
514 g_string_append(s, (have_flags? ", " : " ("));
515 g_string_append(s, flag_desc);
516 return true;
517 }
518
519
520 static bool
521 add_output_node(GString *s, const char *node, bool have_nodes)
522 {
523 g_string_append(s, (have_nodes? " " : " [ "));
524 g_string_append(s, node);
525 return true;
526 }
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542 gchar *
543 pcmk__native_output_string(pe_resource_t *rsc, const char *name, pe_node_t *node,
544 uint32_t show_opts, const char *target_role, bool show_nodes)
545 {
546 const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
547 const char *provider = NULL;
548 const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
549 gchar *retval = NULL;
550 GString *outstr = NULL;
551 bool have_flags = false;
552
553 if (rsc->variant != pe_native) {
554 return NULL;
555 }
556
557 CRM_CHECK(name != NULL, name = "unknown");
558 CRM_CHECK(kind != NULL, kind = "unknown");
559 CRM_CHECK(class != NULL, class = "unknown");
560
561 if (pcmk_is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
562 provider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
563 }
564
565 if ((node == NULL) && (rsc->lock_node != NULL)) {
566 node = rsc->lock_node;
567 }
568 if (pcmk_is_set(show_opts, pcmk_show_rsc_only)
569 || pcmk__list_of_multiple(rsc->running_on)) {
570 node = NULL;
571 }
572
573
574 outstr = g_string_sized_new(strlen(name) + strlen(class) + strlen(kind)
575 + (provider? (strlen(provider) + 2) : 0)
576 + (node? strlen(node->details->uname) + 1 : 0)
577 + 11);
578
579
580 g_string_printf(outstr, "%s\t(%s%s%s:%s):\t", name, class,
581 ((provider == NULL)? "" : PROVIDER_SEP),
582 ((provider == NULL)? "" : provider), kind);
583
584
585 if (pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
586 g_string_append(outstr, " ORPHANED");
587 }
588 if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
589 enum rsc_role_e role = native_displayable_role(rsc);
590
591 if (role > RSC_ROLE_UNPROMOTED) {
592 g_string_append_printf(outstr, " FAILED %s", role2text(role));
593 } else {
594 g_string_append(outstr, " FAILED");
595 }
596 } else {
597 g_string_append_printf(outstr, " %s", native_displayable_state(rsc, pcmk_is_set(show_opts, pcmk_show_pending)));
598 }
599 if (node) {
600 g_string_append_printf(outstr, " %s", node->details->uname);
601 }
602
603
604 if (native_displayable_role(rsc) == RSC_ROLE_STOPPED) {
605 xmlNode *probe_op = pe__failed_probe_for_rsc(rsc, node ? node->details->uname : NULL);
606 if (probe_op != NULL) {
607 int rc;
608
609 pcmk__scan_min_int(crm_element_value(probe_op, XML_LRM_ATTR_RC), &rc, 0);
610 g_string_append_printf(outstr, " (%s) ", services_ocf_exitcode_str(rc));
611 }
612 }
613
614
615 if (node && !(node->details->online) && node->details->unclean) {
616 have_flags = add_output_flag(outstr, "UNCLEAN", have_flags);
617 }
618 if (node && (node == rsc->lock_node)) {
619 have_flags = add_output_flag(outstr, "LOCKED", have_flags);
620 }
621 if (pcmk_is_set(show_opts, pcmk_show_pending)) {
622 const char *pending_task = native_pending_task(rsc);
623
624 if (pending_task) {
625 have_flags = add_output_flag(outstr, pending_task, have_flags);
626 }
627 }
628 if (target_role) {
629 enum rsc_role_e target_role_e = text2role(target_role);
630
631
632
633
634
635 if (target_role_e == RSC_ROLE_STOPPED) {
636 have_flags = add_output_flag(outstr, "disabled", have_flags);
637
638 } else if (pcmk_is_set(uber_parent(rsc)->flags, pe_rsc_promotable)
639 && target_role_e == RSC_ROLE_UNPROMOTED) {
640 have_flags = add_output_flag(outstr, "target-role:", have_flags);
641 g_string_append(outstr, target_role);
642 }
643 }
644 if (pcmk_is_set(rsc->flags, pe_rsc_block)) {
645 have_flags = add_output_flag(outstr, "blocked", have_flags);
646 } else if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
647 have_flags = add_output_flag(outstr, "unmanaged", have_flags);
648 }
649 if (pcmk_is_set(rsc->flags, pe_rsc_failure_ignored)) {
650 have_flags = add_output_flag(outstr, "failure ignored", have_flags);
651 }
652 if (have_flags) {
653 g_string_append(outstr, ")");
654 }
655
656
657 if (pcmk_is_set(show_opts, pcmk_show_rsc_only)
658 || pcmk__list_of_multiple(rsc->running_on)) {
659 const char *desc = crm_element_value(rsc->xml, XML_ATTR_DESC);
660
661 if (desc) {
662 g_string_append_printf(outstr, " %s", desc);
663 }
664 }
665
666 if (show_nodes && !pcmk_is_set(show_opts, pcmk_show_rsc_only)
667 && pcmk__list_of_multiple(rsc->running_on)) {
668 bool have_nodes = false;
669
670 for (GList *iter = rsc->running_on; iter != NULL; iter = iter->next) {
671 pe_node_t *n = (pe_node_t *) iter->data;
672
673 have_nodes = add_output_node(outstr, n->details->uname, have_nodes);
674 }
675 if (have_nodes) {
676 g_string_append(outstr, " ]");
677 }
678 }
679
680 retval = outstr->str;
681 g_string_free(outstr, FALSE);
682 return retval;
683 }
684
685 int
686 pe__common_output_html(pcmk__output_t *out, pe_resource_t * rsc,
687 const char *name, pe_node_t *node, uint32_t show_opts)
688 {
689 const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
690 const char *target_role = NULL;
691
692 xmlNodePtr list_node = NULL;
693 const char *cl = NULL;
694
695 CRM_ASSERT(rsc->variant == pe_native);
696 CRM_ASSERT(kind != NULL);
697
698 if (rsc->meta) {
699 const char *is_internal = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERNAL_RSC);
700
701 if (crm_is_true(is_internal)
702 && !pcmk_is_set(show_opts, pcmk_show_implicit_rscs)) {
703
704 crm_trace("skipping print of internal resource %s", rsc->id);
705 return pcmk_rc_no_output;
706 }
707 target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
708 }
709
710 if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
711 cl = "rsc-managed";
712
713 } else if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
714 cl = "rsc-failed";
715
716 } else if (rsc->variant == pe_native && (rsc->running_on == NULL)) {
717 cl = "rsc-failed";
718
719 } else if (pcmk__list_of_multiple(rsc->running_on)) {
720 cl = "rsc-multiple";
721
722 } else if (pcmk_is_set(rsc->flags, pe_rsc_failure_ignored)) {
723 cl = "rsc-failure-ignored";
724
725 } else {
726 cl = "rsc-ok";
727 }
728
729 {
730 gchar *s = pcmk__native_output_string(rsc, name, node, show_opts,
731 target_role, true);
732
733 list_node = pcmk__output_create_html_node(out, "li", NULL, NULL, NULL);
734 pcmk_create_html_node(list_node, "span", NULL, cl, s);
735 g_free(s);
736 }
737
738 return pcmk_rc_ok;
739 }
740
741 int
742 pe__common_output_text(pcmk__output_t *out, pe_resource_t * rsc,
743 const char *name, pe_node_t *node, uint32_t show_opts)
744 {
745 const char *target_role = NULL;
746
747 CRM_ASSERT(rsc->variant == pe_native);
748
749 if (rsc->meta) {
750 const char *is_internal = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERNAL_RSC);
751
752 if (crm_is_true(is_internal)
753 && !pcmk_is_set(show_opts, pcmk_show_implicit_rscs)) {
754
755 crm_trace("skipping print of internal resource %s", rsc->id);
756 return pcmk_rc_no_output;
757 }
758 target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
759 }
760
761 {
762 gchar *s = pcmk__native_output_string(rsc, name, node, show_opts,
763 target_role, true);
764
765 out->list_item(out, NULL, "%s", s);
766 g_free(s);
767 }
768
769 return pcmk_rc_ok;
770 }
771
772 void
773 common_print(pe_resource_t * rsc, const char *pre_text, const char *name, pe_node_t *node, long options, void *print_data)
774 {
775 const char *target_role = NULL;
776
777 CRM_ASSERT(rsc->variant == pe_native);
778
779 if (rsc->meta) {
780 const char *is_internal = g_hash_table_lookup(rsc->meta,
781 XML_RSC_ATTR_INTERNAL_RSC);
782
783 if (crm_is_true(is_internal)
784 && !pcmk_is_set(options, pe_print_implicit)) {
785
786 crm_trace("skipping print of internal resource %s", rsc->id);
787 return;
788 }
789 target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
790 }
791
792 if (options & pe_print_xml) {
793 native_print_xml(rsc, pre_text, options, print_data);
794 return;
795 }
796
797 if ((pre_text == NULL) && (options & pe_print_printf)) {
798 pre_text = " ";
799 }
800
801 if (options & pe_print_html) {
802 if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
803 status_print("<font color=\"yellow\">");
804
805 } else if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
806 status_print("<font color=\"red\">");
807
808 } else if (rsc->running_on == NULL) {
809 status_print("<font color=\"red\">");
810
811 } else if (pcmk__list_of_multiple(rsc->running_on)) {
812 status_print("<font color=\"orange\">");
813
814 } else if (pcmk_is_set(rsc->flags, pe_rsc_failure_ignored)) {
815 status_print("<font color=\"yellow\">");
816
817 } else {
818 status_print("<font color=\"green\">");
819 }
820 }
821
822 {
823 gchar *resource_s = pcmk__native_output_string(rsc, name, node, options,
824 target_role, false);
825 status_print("%s%s", (pre_text? pre_text : ""), resource_s);
826 g_free(resource_s);
827 }
828
829 if (pcmk_is_set(options, pe_print_html)) {
830 status_print(" </font> ");
831 }
832
833 if (!pcmk_is_set(options, pe_print_rsconly)
834 && pcmk__list_of_multiple(rsc->running_on)) {
835
836 GList *gIter = rsc->running_on;
837 int counter = 0;
838
839 if (options & pe_print_html) {
840 status_print("<ul>\n");
841 } else if ((options & pe_print_printf)
842 || (options & pe_print_ncurses)) {
843 status_print("[");
844 }
845
846 for (; gIter != NULL; gIter = gIter->next) {
847 pe_node_t *n = (pe_node_t *) gIter->data;
848
849 counter++;
850
851 if (options & pe_print_html) {
852 status_print("<li>\n%s", n->details->uname);
853
854 } else if ((options & pe_print_printf)
855 || (options & pe_print_ncurses)) {
856 status_print(" %s", n->details->uname);
857
858 } else if ((options & pe_print_log)) {
859 status_print("\t%d : %s", counter, n->details->uname);
860
861 } else {
862 status_print("%s", n->details->uname);
863 }
864 if (options & pe_print_html) {
865 status_print("</li>\n");
866
867 }
868 }
869
870 if (options & pe_print_html) {
871 status_print("</ul>\n");
872 } else if ((options & pe_print_printf)
873 || (options & pe_print_ncurses)) {
874 status_print(" ]");
875 }
876 }
877
878 if (options & pe_print_html) {
879 status_print("<br/>\n");
880 } else if (options & pe_print_suppres_nl) {
881
882 } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) {
883 status_print("\n");
884 }
885 }
886
887 void
888 native_print(pe_resource_t * rsc, const char *pre_text, long options, void *print_data)
889 {
890 pe_node_t *node = NULL;
891
892 CRM_ASSERT(rsc->variant == pe_native);
893 if (options & pe_print_xml) {
894 native_print_xml(rsc, pre_text, options, print_data);
895 return;
896 }
897
898 node = pe__current_node(rsc);
899
900 if (node == NULL) {
901
902 node = rsc->pending_node;
903 }
904
905 common_print(rsc, pre_text, rsc_printable_id(rsc), node, options, print_data);
906 }
907
908 PCMK__OUTPUT_ARGS("primitive", "uint32_t", "pe_resource_t *", "GList *", "GList *")
909 int
910 pe__resource_xml(pcmk__output_t *out, va_list args)
911 {
912 uint32_t show_opts = va_arg(args, uint32_t);
913 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
914 GList *only_node G_GNUC_UNUSED = va_arg(args, GList *);
915 GList *only_rsc = va_arg(args, GList *);
916
917 bool print_pending = pcmk_is_set(show_opts, pcmk_show_pending);
918 const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
919 const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
920 const char *rsc_state = native_displayable_state(rsc, print_pending);
921
922 char ra_name[LINE_MAX];
923 char *nodes_running_on = NULL;
924 int rc = pcmk_rc_no_output;
925 const char *target_role = NULL;
926
927 if (rsc->meta != NULL) {
928 target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
929 }
930
931 CRM_ASSERT(rsc->variant == pe_native);
932
933 if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
934 return pcmk_rc_no_output;
935 }
936
937
938 snprintf(ra_name, LINE_MAX, "%s%s%s:%s", class,
939 ((prov == NULL)? "" : PROVIDER_SEP), ((prov == NULL)? "" : prov),
940 crm_element_value(rsc->xml, XML_ATTR_TYPE));
941
942 nodes_running_on = pcmk__itoa(g_list_length(rsc->running_on));
943
944 rc = pe__name_and_nvpairs_xml(out, true, "resource", 12,
945 "id", rsc_printable_id(rsc),
946 "resource_agent", ra_name,
947 "role", rsc_state,
948 "target_role", target_role,
949 "active", pcmk__btoa(rsc->fns->active(rsc, TRUE)),
950 "orphaned", pe__rsc_bool_str(rsc, pe_rsc_orphan),
951 "blocked", pe__rsc_bool_str(rsc, pe_rsc_block),
952 "managed", pe__rsc_bool_str(rsc, pe_rsc_managed),
953 "failed", pe__rsc_bool_str(rsc, pe_rsc_failed),
954 "failure_ignored", pe__rsc_bool_str(rsc, pe_rsc_failure_ignored),
955 "nodes_running_on", nodes_running_on,
956 "pending", (print_pending? native_pending_task(rsc) : NULL));
957 free(nodes_running_on);
958
959 CRM_ASSERT(rc == pcmk_rc_ok);
960
961 if (rsc->running_on != NULL) {
962 GList *gIter = rsc->running_on;
963
964 for (; gIter != NULL; gIter = gIter->next) {
965 pe_node_t *node = (pe_node_t *) gIter->data;
966
967 rc = pe__name_and_nvpairs_xml(out, false, "node", 3,
968 "name", node->details->uname,
969 "id", node->details->id,
970 "cached", pcmk__btoa(node->details->online));
971 CRM_ASSERT(rc == pcmk_rc_ok);
972 }
973 }
974
975 pcmk__output_xml_pop_parent(out);
976 return rc;
977 }
978
979 PCMK__OUTPUT_ARGS("primitive", "uint32_t", "pe_resource_t *", "GList *", "GList *")
980 int
981 pe__resource_html(pcmk__output_t *out, va_list args)
982 {
983 uint32_t show_opts = va_arg(args, uint32_t);
984 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
985 GList *only_node G_GNUC_UNUSED = va_arg(args, GList *);
986 GList *only_rsc = va_arg(args, GList *);
987
988 pe_node_t *node = pe__current_node(rsc);
989
990 if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
991 return pcmk_rc_no_output;
992 }
993
994 CRM_ASSERT(rsc->variant == pe_native);
995
996 if (node == NULL) {
997
998 node = rsc->pending_node;
999 }
1000 return pe__common_output_html(out, rsc, rsc_printable_id(rsc), node, show_opts);
1001 }
1002
1003 PCMK__OUTPUT_ARGS("primitive", "uint32_t", "pe_resource_t *", "GList *", "GList *")
1004 int
1005 pe__resource_text(pcmk__output_t *out, va_list args)
1006 {
1007 uint32_t show_opts = va_arg(args, uint32_t);
1008 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
1009 GList *only_node G_GNUC_UNUSED = va_arg(args, GList *);
1010 GList *only_rsc = va_arg(args, GList *);
1011
1012 pe_node_t *node = pe__current_node(rsc);
1013
1014 CRM_ASSERT(rsc->variant == pe_native);
1015
1016 if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
1017 return pcmk_rc_no_output;
1018 }
1019
1020 if (node == NULL) {
1021
1022 node = rsc->pending_node;
1023 }
1024 return pe__common_output_text(out, rsc, rsc_printable_id(rsc), node, show_opts);
1025 }
1026
1027 void
1028 native_free(pe_resource_t * rsc)
1029 {
1030 pe_rsc_trace(rsc, "Freeing resource action list (not the data)");
1031 common_free(rsc);
1032 }
1033
1034 enum rsc_role_e
1035 native_resource_state(const pe_resource_t * rsc, gboolean current)
1036 {
1037 enum rsc_role_e role = rsc->next_role;
1038
1039 if (current) {
1040 role = rsc->role;
1041 }
1042 pe_rsc_trace(rsc, "%s state: %s", rsc->id, role2text(role));
1043 return role;
1044 }
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057 pe_node_t *
1058 native_location(const pe_resource_t *rsc, GList **list, int current)
1059 {
1060 pe_node_t *one = NULL;
1061 GList *result = NULL;
1062
1063 if (rsc->children) {
1064 GList *gIter = rsc->children;
1065
1066 for (; gIter != NULL; gIter = gIter->next) {
1067 pe_resource_t *child = (pe_resource_t *) gIter->data;
1068
1069 child->fns->location(child, &result, current);
1070 }
1071
1072 } else if (current) {
1073
1074 if (rsc->running_on) {
1075 result = g_list_copy(rsc->running_on);
1076 }
1077 if ((current == 2) && rsc->pending_node
1078 && !pe_find_node_id(result, rsc->pending_node->details->id)) {
1079 result = g_list_append(result, rsc->pending_node);
1080 }
1081
1082 } else if (current == FALSE && rsc->allocated_to) {
1083 result = g_list_append(NULL, rsc->allocated_to);
1084 }
1085
1086 if (result && (result->next == NULL)) {
1087 one = result->data;
1088 }
1089
1090 if (list) {
1091 GList *gIter = result;
1092
1093 for (; gIter != NULL; gIter = gIter->next) {
1094 pe_node_t *node = (pe_node_t *) gIter->data;
1095
1096 if (*list == NULL || pe_find_node_id(*list, node->details->id) == NULL) {
1097 *list = g_list_append(*list, node);
1098 }
1099 }
1100 }
1101
1102 g_list_free(result);
1103 return one;
1104 }
1105
1106 static void
1107 get_rscs_brief(GList *rsc_list, GHashTable * rsc_table, GHashTable * active_table)
1108 {
1109 GList *gIter = rsc_list;
1110
1111 for (; gIter != NULL; gIter = gIter->next) {
1112 pe_resource_t *rsc = (pe_resource_t *) gIter->data;
1113
1114 const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
1115 const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
1116
1117 int offset = 0;
1118 char buffer[LINE_MAX];
1119
1120 int *rsc_counter = NULL;
1121 int *active_counter = NULL;
1122
1123 if (rsc->variant != pe_native) {
1124 continue;
1125 }
1126
1127 offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", class);
1128 if (pcmk_is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
1129 const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
1130
1131 if (prov != NULL) {
1132 offset += snprintf(buffer + offset, LINE_MAX - offset,
1133 PROVIDER_SEP "%s", prov);
1134 }
1135 }
1136 offset += snprintf(buffer + offset, LINE_MAX - offset, ":%s", kind);
1137 CRM_LOG_ASSERT(offset > 0);
1138
1139 if (rsc_table) {
1140 rsc_counter = g_hash_table_lookup(rsc_table, buffer);
1141 if (rsc_counter == NULL) {
1142 rsc_counter = calloc(1, sizeof(int));
1143 *rsc_counter = 0;
1144 g_hash_table_insert(rsc_table, strdup(buffer), rsc_counter);
1145 }
1146 (*rsc_counter)++;
1147 }
1148
1149 if (active_table) {
1150 GList *gIter2 = rsc->running_on;
1151
1152 for (; gIter2 != NULL; gIter2 = gIter2->next) {
1153 pe_node_t *node = (pe_node_t *) gIter2->data;
1154 GHashTable *node_table = NULL;
1155
1156 if (node->details->unclean == FALSE && node->details->online == FALSE &&
1157 pcmk_is_set(rsc->flags, pe_rsc_managed)) {
1158 continue;
1159 }
1160
1161 node_table = g_hash_table_lookup(active_table, node->details->uname);
1162 if (node_table == NULL) {
1163 node_table = pcmk__strkey_table(free, free);
1164 g_hash_table_insert(active_table, strdup(node->details->uname), node_table);
1165 }
1166
1167 active_counter = g_hash_table_lookup(node_table, buffer);
1168 if (active_counter == NULL) {
1169 active_counter = calloc(1, sizeof(int));
1170 *active_counter = 0;
1171 g_hash_table_insert(node_table, strdup(buffer), active_counter);
1172 }
1173 (*active_counter)++;
1174 }
1175 }
1176 }
1177 }
1178
1179 static void
1180 destroy_node_table(gpointer data)
1181 {
1182 GHashTable *node_table = data;
1183
1184 if (node_table) {
1185 g_hash_table_destroy(node_table);
1186 }
1187 }
1188
1189 void
1190 print_rscs_brief(GList *rsc_list, const char *pre_text, long options,
1191 void *print_data, gboolean print_all)
1192 {
1193 GHashTable *rsc_table = pcmk__strkey_table(free, free);
1194 GHashTable *active_table = pcmk__strkey_table(free, destroy_node_table);
1195 GHashTableIter hash_iter;
1196 char *type = NULL;
1197 int *rsc_counter = NULL;
1198
1199 get_rscs_brief(rsc_list, rsc_table, active_table);
1200
1201 g_hash_table_iter_init(&hash_iter, rsc_table);
1202 while (g_hash_table_iter_next(&hash_iter, (gpointer *)&type, (gpointer *)&rsc_counter)) {
1203 GHashTableIter hash_iter2;
1204 char *node_name = NULL;
1205 GHashTable *node_table = NULL;
1206 int active_counter_all = 0;
1207
1208 g_hash_table_iter_init(&hash_iter2, active_table);
1209 while (g_hash_table_iter_next(&hash_iter2, (gpointer *)&node_name, (gpointer *)&node_table)) {
1210 int *active_counter = g_hash_table_lookup(node_table, type);
1211
1212 if (active_counter == NULL || *active_counter == 0) {
1213 continue;
1214
1215 } else {
1216 active_counter_all += *active_counter;
1217 }
1218
1219 if (options & pe_print_rsconly) {
1220 node_name = NULL;
1221 }
1222
1223 if (options & pe_print_html) {
1224 status_print("<li>\n");
1225 }
1226
1227 if (print_all) {
1228 status_print("%s%d/%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
1229 active_counter ? *active_counter : 0,
1230 rsc_counter ? *rsc_counter : 0, type,
1231 active_counter && (*active_counter > 0) && node_name ? node_name : "");
1232 } else {
1233 status_print("%s%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
1234 active_counter ? *active_counter : 0, type,
1235 active_counter && (*active_counter > 0) && node_name ? node_name : "");
1236 }
1237
1238 if (options & pe_print_html) {
1239 status_print("</li>\n");
1240 }
1241 }
1242
1243 if (print_all && active_counter_all == 0) {
1244 if (options & pe_print_html) {
1245 status_print("<li>\n");
1246 }
1247
1248 status_print("%s%d/%d\t(%s):\tActive\n", pre_text ? pre_text : "",
1249 active_counter_all,
1250 rsc_counter ? *rsc_counter : 0, type);
1251
1252 if (options & pe_print_html) {
1253 status_print("</li>\n");
1254 }
1255 }
1256 }
1257
1258 if (rsc_table) {
1259 g_hash_table_destroy(rsc_table);
1260 rsc_table = NULL;
1261 }
1262 if (active_table) {
1263 g_hash_table_destroy(active_table);
1264 active_table = NULL;
1265 }
1266 }
1267
1268 int
1269 pe__rscs_brief_output(pcmk__output_t *out, GList *rsc_list, uint32_t show_opts)
1270 {
1271 GHashTable *rsc_table = pcmk__strkey_table(free, free);
1272 GHashTable *active_table = pcmk__strkey_table(free, destroy_node_table);
1273 GList *sorted_rscs;
1274 int rc = pcmk_rc_no_output;
1275
1276 get_rscs_brief(rsc_list, rsc_table, active_table);
1277
1278
1279
1280
1281 sorted_rscs = g_hash_table_get_keys(rsc_table);
1282 sorted_rscs = g_list_sort(sorted_rscs, (GCompareFunc) strcmp);
1283
1284 for (GList *gIter = sorted_rscs; gIter; gIter = gIter->next) {
1285 char *type = (char *) gIter->data;
1286 int *rsc_counter = g_hash_table_lookup(rsc_table, type);
1287
1288 GList *sorted_nodes = NULL;
1289 int active_counter_all = 0;
1290
1291
1292
1293
1294
1295 sorted_nodes = g_hash_table_get_keys(active_table);
1296 sorted_nodes = g_list_sort(sorted_nodes, (GCompareFunc) pcmk__numeric_strcasecmp);
1297
1298 for (GList *gIter2 = sorted_nodes; gIter2; gIter2 = gIter2->next) {
1299 char *node_name = (char *) gIter2->data;
1300 GHashTable *node_table = g_hash_table_lookup(active_table, node_name);
1301 int *active_counter = NULL;
1302
1303 if (node_table == NULL) {
1304 continue;
1305 }
1306
1307 active_counter = g_hash_table_lookup(node_table, type);
1308
1309 if (active_counter == NULL || *active_counter == 0) {
1310 continue;
1311
1312 } else {
1313 active_counter_all += *active_counter;
1314 }
1315
1316 if (pcmk_is_set(show_opts, pcmk_show_rsc_only)) {
1317 node_name = NULL;
1318 }
1319
1320 if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
1321 out->list_item(out, NULL, "%d/%d\t(%s):\tActive %s",
1322 *active_counter,
1323 rsc_counter ? *rsc_counter : 0, type,
1324 (*active_counter > 0) && node_name ? node_name : "");
1325 } else {
1326 out->list_item(out, NULL, "%d\t(%s):\tActive %s",
1327 *active_counter, type,
1328 (*active_counter > 0) && node_name ? node_name : "");
1329 }
1330
1331 rc = pcmk_rc_ok;
1332 }
1333
1334 if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs) && active_counter_all == 0) {
1335 out->list_item(out, NULL, "%d/%d\t(%s):\tActive",
1336 active_counter_all,
1337 rsc_counter ? *rsc_counter : 0, type);
1338 rc = pcmk_rc_ok;
1339 }
1340
1341 if (sorted_nodes) {
1342 g_list_free(sorted_nodes);
1343 }
1344 }
1345
1346 if (rsc_table) {
1347 g_hash_table_destroy(rsc_table);
1348 rsc_table = NULL;
1349 }
1350 if (active_table) {
1351 g_hash_table_destroy(active_table);
1352 active_table = NULL;
1353 }
1354 if (sorted_rscs) {
1355 g_list_free(sorted_rscs);
1356 }
1357
1358 return rc;
1359 }
1360
1361 gboolean
1362 pe__native_is_filtered(pe_resource_t *rsc, GList *only_rsc, gboolean check_parent)
1363 {
1364 if (pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
1365 pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches)) {
1366 return FALSE;
1367 } else if (check_parent && rsc->parent) {
1368 pe_resource_t *up = uber_parent(rsc);
1369
1370 if (pe_rsc_is_bundled(rsc)) {
1371 return up->parent->fns->is_filtered(up->parent, only_rsc, FALSE);
1372 } else {
1373 return up->fns->is_filtered(up, only_rsc, FALSE);
1374 }
1375 }
1376
1377 return TRUE;
1378 }