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