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