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_active
- native_pending_state
- native_pending_action
- native_displayable_role
- native_displayable_state
- add_output_flag
- add_output_node
- pcmk__native_output_string
- pe__common_output_html
- pe__common_output_text
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- native_free
- native_resource_state
- native_location
- get_rscs_brief
- destroy_node_table
- pe__rscs_brief_output
- pe__native_is_filtered
- pe__primitive_max_per_node
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdbool.h>
13 #include <stdint.h>
14
15 #include <crm/common/output.h>
16 #include <crm/pengine/status.h>
17 #include <crm/pengine/complex.h>
18 #include <crm/pengine/internal.h>
19 #include <crm/common/xml.h>
20 #include <pe_status_private.h>
21
22
23
24
25
26 static bool
27 is_multiply_active(const pcmk_resource_t *rsc)
28 {
29 unsigned int count = 0;
30
31 if (pcmk__is_primitive(rsc)) {
32 pe__find_active_requires(rsc, &count);
33 }
34 return count > 1;
35 }
36
37 static void
38 native_priority_to_node(pcmk_resource_t *rsc, pcmk_node_t *node,
39 gboolean failed)
40 {
41 int priority = 0;
42 const bool promoted = (rsc->priv->orig_role == pcmk_role_promoted);
43
44 if ((rsc->priv->priority == 0) || failed) {
45 return;
46 }
47
48 if (promoted) {
49
50 priority = rsc->priv->priority + 1;
51
52 } else {
53 priority = rsc->priv->priority;
54 }
55
56 node->priv->priority += priority;
57 pcmk__rsc_trace(rsc, "%s now has priority %d with %s'%s' (priority: %d%s)",
58 pcmk__node_name(node), node->priv->priority,
59 (promoted? "promoted " : ""),
60 rsc->id, rsc->priv->priority, (promoted? " + 1" : ""));
61
62
63
64 if ((node->priv->remote != NULL)
65 && (node->priv->remote->priv->launcher != NULL)) {
66 const pcmk_resource_t *launcher = NULL;
67
68 launcher = node->priv->remote->priv->launcher;
69 for (GList *gIter = launcher->priv->active_nodes;
70 gIter != NULL; gIter = gIter->next) {
71
72 pcmk_node_t *a_node = gIter->data;
73
74 a_node->priv->priority += priority;
75 pcmk__rsc_trace(rsc,
76 "%s now has priority %d with %s'%s' "
77 "(priority: %d%s) from guest node %s",
78 pcmk__node_name(a_node), a_node->priv->priority,
79 (promoted? "promoted " : ""), rsc->id,
80 rsc->priv->priority, (promoted? " + 1" : ""),
81 pcmk__node_name(node));
82 }
83 }
84 }
85
86 void
87 native_add_running(pcmk_resource_t *rsc, pcmk_node_t *node,
88 pcmk_scheduler_t *scheduler, gboolean failed)
89 {
90 pcmk_resource_t *parent = rsc->priv->parent;
91
92 CRM_CHECK(node != NULL, return);
93
94 for (GList *gIter = rsc->priv->active_nodes;
95 gIter != NULL; gIter = gIter->next) {
96
97 pcmk_node_t *a_node = (pcmk_node_t *) gIter->data;
98
99 if (pcmk__same_node(a_node, node)) {
100 return;
101 }
102 }
103
104 pcmk__rsc_trace(rsc, "Adding %s to %s %s", rsc->id, pcmk__node_name(node),
105 pcmk_is_set(rsc->flags, pcmk__rsc_managed)? "" : "(unmanaged)");
106
107 rsc->priv->active_nodes = g_list_append(rsc->priv->active_nodes, node);
108 if (pcmk__is_primitive(rsc)) {
109 node->details->running_rsc = g_list_append(node->details->running_rsc, rsc);
110 native_priority_to_node(rsc, node, failed);
111 if (node->details->maintenance) {
112 pcmk__clear_rsc_flags(rsc, pcmk__rsc_managed);
113 pcmk__set_rsc_flags(rsc, pcmk__rsc_maintenance);
114 }
115 }
116
117 if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
118 pcmk_resource_t *p = parent;
119
120 pcmk__rsc_info(rsc, "resource %s isn't managed", rsc->id);
121 resource_location(rsc, node, PCMK_SCORE_INFINITY,
122 "not_managed_default", scheduler);
123
124 while(p) {
125
126 p->priv->active_nodes = g_list_append(p->priv->active_nodes, node);
127 p = p->priv->parent;
128 }
129 return;
130 }
131
132 if (is_multiply_active(rsc)) {
133 switch (rsc->priv->multiply_active_policy) {
134 case pcmk__multiply_active_stop:
135 {
136 GHashTableIter gIter;
137 pcmk_node_t *local_node = NULL;
138
139
140 if (rsc->priv->allowed_nodes != NULL) {
141 g_hash_table_destroy(rsc->priv->allowed_nodes);
142 }
143 rsc->priv->allowed_nodes =
144 pe__node_list2table(scheduler->nodes);
145 g_hash_table_iter_init(&gIter, rsc->priv->allowed_nodes);
146 while (g_hash_table_iter_next(&gIter, NULL, (void **)&local_node)) {
147 local_node->assign->score = -PCMK_SCORE_INFINITY;
148 }
149 }
150 break;
151 case pcmk__multiply_active_block:
152 pcmk__clear_rsc_flags(rsc, pcmk__rsc_managed);
153 pcmk__set_rsc_flags(rsc, pcmk__rsc_blocked);
154
155
156
157
158
159 if ((pcmk__is_group(parent) || pcmk__is_bundle(parent))
160 && (parent->priv->multiply_active_policy
161 == pcmk__multiply_active_block)) {
162
163 for (GList *gIter = parent->priv->children;
164 gIter != NULL; gIter = gIter->next) {
165 pcmk_resource_t *child = gIter->data;
166
167 pcmk__clear_rsc_flags(child, pcmk__rsc_managed);
168 pcmk__set_rsc_flags(child, pcmk__rsc_blocked);
169 }
170 }
171 break;
172
173
174 default:
175
176
177
178 break;
179 }
180 crm_debug("%s is active on multiple nodes including %s: %s",
181 rsc->id, pcmk__node_name(node),
182 pcmk__multiply_active_text(rsc));
183
184 } else {
185 pcmk__rsc_trace(rsc, "Resource %s is active on %s",
186 rsc->id, pcmk__node_name(node));
187 }
188
189 if (parent != NULL) {
190 native_add_running(parent, node, scheduler, FALSE);
191 }
192 }
193
194 static void
195 recursive_clear_unique(pcmk_resource_t *rsc, gpointer user_data)
196 {
197 pcmk__clear_rsc_flags(rsc, pcmk__rsc_unique);
198 pcmk__insert_meta(rsc->priv, PCMK_META_GLOBALLY_UNIQUE,
199 PCMK_VALUE_FALSE);
200 g_list_foreach(rsc->priv->children, (GFunc) recursive_clear_unique,
201 NULL);
202 }
203
204 bool
205 native_unpack(pcmk_resource_t *rsc)
206 {
207 pcmk_resource_t *parent = uber_parent(rsc);
208 const char *standard = crm_element_value(rsc->priv->xml, PCMK_XA_CLASS);
209 uint32_t ra_caps = pcmk_get_ra_caps(standard);
210
211 pcmk__rsc_trace(rsc, "Processing resource %s...", rsc->id);
212
213
214 if (!pcmk_is_set(ra_caps, pcmk_ra_cap_unique)
215 && pcmk_is_set(rsc->flags, pcmk__rsc_unique)
216 && pcmk__is_clone(parent)) {
217
218
219
220
221
222
223 pe__force_anon(standard, parent, rsc->id, rsc->priv->scheduler);
224
225
226
227
228
229
230 recursive_clear_unique(parent, NULL);
231 recursive_clear_unique(rsc, NULL);
232 }
233 if (!pcmk_is_set(ra_caps, pcmk_ra_cap_promotable)
234 && pcmk_is_set(parent->flags, pcmk__rsc_promotable)) {
235
236 pcmk__config_err("Resource %s is of type %s and therefore "
237 "cannot be used as a promotable clone resource",
238 rsc->id, standard);
239 return FALSE;
240 }
241 return TRUE;
242 }
243
244 static bool
245 rsc_is_on_node(pcmk_resource_t *rsc, const pcmk_node_t *node, int flags)
246 {
247 pcmk__rsc_trace(rsc, "Checking whether %s is on %s",
248 rsc->id, pcmk__node_name(node));
249
250 if (pcmk_is_set(flags, pcmk_rsc_match_current_node)
251 && (rsc->priv->active_nodes != NULL)) {
252
253 for (GList *iter = rsc->priv->active_nodes;
254 iter != NULL; iter = iter->next) {
255
256 if (pcmk__same_node((pcmk_node_t *) iter->data, node)) {
257 return true;
258 }
259 }
260
261 } else if (!pcmk_is_set(flags, pcmk_rsc_match_current_node)
262 && (rsc->priv->assigned_node != NULL)
263 && pcmk__same_node(rsc->priv->assigned_node, node)) {
264 return true;
265 }
266 return false;
267 }
268
269 pcmk_resource_t *
270 native_find_rsc(pcmk_resource_t *rsc, const char *id,
271 const pcmk_node_t *on_node, uint32_t flags)
272 {
273 bool match = false;
274 pcmk_resource_t *result = NULL;
275
276 CRM_CHECK(id && rsc && rsc->id, return NULL);
277
278 if (pcmk_is_set(flags, pcmk_rsc_match_clone_only)) {
279 const char *rid = pcmk__xe_id(rsc->priv->xml);
280
281 if (!pcmk__is_clone(pe__const_top_resource(rsc, false))) {
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, pcmk_rsc_match_history)
292 && pcmk__str_eq(rsc->priv->history_id, id, pcmk__str_none)) {
293 match = true;
294
295 } else if (pcmk_is_set(flags, pcmk_rsc_match_basename)
296 || (pcmk_is_set(flags, pcmk_rsc_match_anon_basename)
297 && !pcmk_is_set(rsc->flags, pcmk__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->priv->children;
312 gIter != NULL; gIter = gIter->next) {
313
314 pcmk_resource_t *child = (pcmk_resource_t *) gIter->data;
315
316 result = rsc->priv->fns->find_rsc(child, id, on_node, flags);
317 if (result) {
318 return result;
319 }
320 }
321 return NULL;
322 }
323
324 bool
325 native_active(const pcmk_resource_t *rsc, bool all)
326 {
327 for (GList *gIter = rsc->priv->active_nodes;
328 gIter != NULL; gIter = gIter->next) {
329
330 pcmk_node_t *a_node = (pcmk_node_t *) gIter->data;
331
332 if (a_node->details->unclean) {
333 pcmk__rsc_trace(rsc, "Resource %s: %s is unclean",
334 rsc->id, pcmk__node_name(a_node));
335 return TRUE;
336 } else if (!a_node->details->online
337 && pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
338 pcmk__rsc_trace(rsc, "Resource %s: %s is offline",
339 rsc->id, pcmk__node_name(a_node));
340 } else {
341 pcmk__rsc_trace(rsc, "Resource %s active on %s",
342 rsc->id, pcmk__node_name(a_node));
343 return TRUE;
344 }
345 }
346 return FALSE;
347 }
348
349 struct print_data_s {
350 long options;
351 void *print_data;
352 };
353
354 static const char *
355 native_pending_state(const pcmk_resource_t *rsc)
356 {
357 const char *pending_state = NULL;
358
359 if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_START,
360 pcmk__str_none)) {
361 pending_state = "Starting";
362
363 } else if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_STOP,
364 pcmk__str_none)) {
365 pending_state = "Stopping";
366
367 } else if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_MIGRATE_TO,
368 pcmk__str_none)) {
369 pending_state = "Migrating";
370
371 } else if (pcmk__str_eq(rsc->priv->pending_action,
372 PCMK_ACTION_MIGRATE_FROM, pcmk__str_none)) {
373
374 pending_state = "Migrating";
375
376 } else if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_PROMOTE,
377 pcmk__str_none)) {
378 pending_state = "Promoting";
379
380 } else if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_DEMOTE,
381 pcmk__str_none)) {
382 pending_state = "Demoting";
383 }
384
385 return pending_state;
386 }
387
388 static const char *
389 native_pending_action(const pcmk_resource_t *rsc)
390 {
391 const char *pending_action = NULL;
392
393 if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_MONITOR,
394 pcmk__str_none)) {
395 pending_action = "Monitoring";
396
397
398
399
400
401
402 #if 0
403 } else if (pcmk__str_eq(rsc->private->pending_action, "probe",
404 pcmk__str_none)) {
405 pending_action = "Checking";
406 #endif
407 }
408
409 return pending_action;
410 }
411
412 static enum rsc_role_e
413 native_displayable_role(const pcmk_resource_t *rsc)
414 {
415 enum rsc_role_e role = rsc->priv->orig_role;
416
417 if ((role == pcmk_role_started)
418 && pcmk_is_set(pe__const_top_resource(rsc, false)->flags,
419 pcmk__rsc_promotable)) {
420
421 role = pcmk_role_unpromoted;
422 }
423 return role;
424 }
425
426 static const char *
427 native_displayable_state(const pcmk_resource_t *rsc, bool print_pending)
428 {
429 const char *rsc_state = NULL;
430
431 if (print_pending) {
432 rsc_state = native_pending_state(rsc);
433 }
434 if (rsc_state == NULL) {
435 rsc_state = pcmk_role_text(native_displayable_role(rsc));
436 }
437 return rsc_state;
438 }
439
440
441 static bool
442 add_output_flag(GString *s, const char *flag_desc, bool have_flags)
443 {
444 g_string_append(s, (have_flags? ", " : " ("));
445 g_string_append(s, flag_desc);
446 return true;
447 }
448
449
450 static bool
451 add_output_node(GString *s, const char *node, bool have_nodes)
452 {
453 g_string_append(s, (have_nodes? " " : " [ "));
454 g_string_append(s, node);
455 return true;
456 }
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472 gchar *
473 pcmk__native_output_string(const pcmk_resource_t *rsc, const char *name,
474 const pcmk_node_t *node, uint32_t show_opts,
475 const char *target_role, bool show_nodes)
476 {
477 const char *class = crm_element_value(rsc->priv->xml, PCMK_XA_CLASS);
478 const char *provider = NULL;
479 const char *kind = crm_element_value(rsc->priv->xml, PCMK_XA_TYPE);
480 GString *outstr = NULL;
481 bool have_flags = false;
482
483 if (!pcmk__is_primitive(rsc)) {
484 return NULL;
485 }
486
487 CRM_CHECK(name != NULL, name = "unknown");
488 CRM_CHECK(kind != NULL, kind = "unknown");
489 CRM_CHECK(class != NULL, class = "unknown");
490
491 if (pcmk_is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
492 provider = crm_element_value(rsc->priv->xml, PCMK_XA_PROVIDER);
493 }
494
495 if ((node == NULL) && (rsc->priv->lock_node != NULL)) {
496 node = rsc->priv->lock_node;
497 }
498 if (pcmk_any_flags_set(show_opts, pcmk_show_rsc_only)
499 || pcmk__list_of_multiple(rsc->priv->active_nodes)) {
500 node = NULL;
501 }
502
503 outstr = g_string_sized_new(128);
504
505
506 pcmk__g_strcat(outstr,
507 name, "\t(", class, ((provider == NULL)? "" : ":"),
508 pcmk__s(provider, ""), ":", kind, "):\t", NULL);
509
510
511 if (pcmk_is_set(rsc->flags, pcmk__rsc_removed)) {
512 g_string_append(outstr, " ORPHANED");
513 }
514 if (pcmk_is_set(rsc->flags, pcmk__rsc_failed)) {
515 enum rsc_role_e role = native_displayable_role(rsc);
516
517 g_string_append(outstr, " FAILED");
518 if (role > pcmk_role_unpromoted) {
519 pcmk__add_word(&outstr, 0, pcmk_role_text(role));
520 }
521 } else {
522 bool show_pending = pcmk_is_set(show_opts, pcmk_show_pending);
523
524 pcmk__add_word(&outstr, 0, native_displayable_state(rsc, show_pending));
525 }
526 if (node) {
527 pcmk__add_word(&outstr, 0, pcmk__node_name(node));
528 }
529
530
531 if (native_displayable_role(rsc) == pcmk_role_stopped) {
532 xmlNode *probe_op = pe__failed_probe_for_rsc(rsc,
533 node ? node->priv->name : NULL);
534 if (probe_op != NULL) {
535 int rc;
536
537 pcmk__scan_min_int(crm_element_value(probe_op, PCMK__XA_RC_CODE),
538 &rc, 0);
539 pcmk__g_strcat(outstr, " (", crm_exit_str(rc), ") ", NULL);
540 }
541 }
542
543
544 if (node && !(node->details->online) && node->details->unclean) {
545 have_flags = add_output_flag(outstr, "UNCLEAN", have_flags);
546 }
547 if ((node != NULL) && pcmk__same_node(node, rsc->priv->lock_node)) {
548 have_flags = add_output_flag(outstr, "LOCKED", have_flags);
549 }
550 if (pcmk_is_set(show_opts, pcmk_show_pending)) {
551 const char *pending_action = native_pending_action(rsc);
552
553 if (pending_action != NULL) {
554 have_flags = add_output_flag(outstr, pending_action, have_flags);
555 }
556 }
557 if (target_role != NULL) {
558 switch (pcmk_parse_role(target_role)) {
559 case pcmk_role_unknown:
560 pcmk__config_err("Invalid " PCMK_META_TARGET_ROLE
561 " %s for resource %s", target_role, rsc->id);
562 break;
563
564 case pcmk_role_stopped:
565 have_flags = add_output_flag(outstr, "disabled", have_flags);
566 break;
567
568 case pcmk_role_unpromoted:
569 if (pcmk_is_set(pe__const_top_resource(rsc, false)->flags,
570 pcmk__rsc_promotable)) {
571 have_flags = add_output_flag(outstr,
572 PCMK_META_TARGET_ROLE ":",
573 have_flags);
574 g_string_append(outstr, target_role);
575 }
576 break;
577
578 default:
579
580
581
582
583 break;
584 }
585 }
586
587
588 if (pcmk_any_flags_set(rsc->flags,
589 pcmk__rsc_blocked|pcmk__rsc_maintenance)) {
590 if (pcmk_is_set(rsc->flags, pcmk__rsc_blocked)) {
591 have_flags = add_output_flag(outstr, "blocked", have_flags);
592
593 } else if (pcmk_is_set(rsc->flags, pcmk__rsc_maintenance)) {
594 have_flags = add_output_flag(outstr, "maintenance", have_flags);
595 }
596 } else if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
597 have_flags = add_output_flag(outstr, "unmanaged", have_flags);
598 }
599
600 if (pcmk_is_set(rsc->flags, pcmk__rsc_ignore_failure)) {
601 have_flags = add_output_flag(outstr, "failure ignored", have_flags);
602 }
603
604
605 if (have_flags) {
606 g_string_append_c(outstr, ')');
607 }
608
609
610 if (pcmk_any_flags_set(show_opts, pcmk_show_rsc_only|pcmk_show_description)
611 || pcmk__list_of_multiple(rsc->priv->active_nodes)) {
612 const char *desc = crm_element_value(rsc->priv->xml,
613 PCMK_XA_DESCRIPTION);
614
615 if (desc) {
616 g_string_append(outstr, " (");
617 g_string_append(outstr, desc);
618 g_string_append(outstr, ")");
619
620 }
621 }
622
623 if (show_nodes && !pcmk_is_set(show_opts, pcmk_show_rsc_only)
624 && pcmk__list_of_multiple(rsc->priv->active_nodes)) {
625 bool have_nodes = false;
626
627 for (GList *iter = rsc->priv->active_nodes;
628 iter != NULL; iter = iter->next) {
629
630 pcmk_node_t *n = (pcmk_node_t *) iter->data;
631
632 have_nodes = add_output_node(outstr, n->priv->name, have_nodes);
633 }
634 if (have_nodes) {
635 g_string_append(outstr, " ]");
636 }
637 }
638
639 return g_string_free(outstr, FALSE);
640 }
641
642 int
643 pe__common_output_html(pcmk__output_t *out, const pcmk_resource_t *rsc,
644 const char *name, const pcmk_node_t *node,
645 uint32_t show_opts)
646 {
647 const char *kind = crm_element_value(rsc->priv->xml, PCMK_XA_TYPE);
648 const char *target_role = NULL;
649 const char *cl = NULL;
650
651 xmlNode *child = NULL;
652 gchar *content = NULL;
653
654 pcmk__assert((kind != NULL) && pcmk__is_primitive(rsc));
655
656 if (crm_is_true(g_hash_table_lookup(rsc->priv->meta,
657 PCMK__META_INTERNAL_RSC))
658 && !pcmk_is_set(show_opts, pcmk_show_implicit_rscs)) {
659
660 crm_trace("skipping print of internal resource %s", rsc->id);
661 return pcmk_rc_no_output;
662 }
663 target_role = g_hash_table_lookup(rsc->priv->meta,
664 PCMK_META_TARGET_ROLE);
665
666 if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
667 cl = PCMK__VALUE_RSC_MANAGED;
668
669 } else if (pcmk_is_set(rsc->flags, pcmk__rsc_failed)) {
670 cl = PCMK__VALUE_RSC_FAILED;
671
672 } else if (pcmk__is_primitive(rsc)
673 && (rsc->priv->active_nodes == NULL)) {
674 cl = PCMK__VALUE_RSC_FAILED;
675
676 } else if (pcmk__list_of_multiple(rsc->priv->active_nodes)) {
677 cl = PCMK__VALUE_RSC_MULTIPLE;
678
679 } else if (pcmk_is_set(rsc->flags, pcmk__rsc_ignore_failure)) {
680 cl = PCMK__VALUE_RSC_FAILURE_IGNORED;
681
682 } else {
683 cl = PCMK__VALUE_RSC_OK;
684 }
685
686 child = pcmk__output_create_html_node(out, "li", NULL, NULL, NULL);
687 child = pcmk__html_create(child, PCMK__XE_SPAN, NULL, cl);
688 content = pcmk__native_output_string(rsc, name, node, show_opts,
689 target_role, true);
690 pcmk__xe_set_content(child, "%s", content);
691 g_free(content);
692
693 return pcmk_rc_ok;
694 }
695
696 int
697 pe__common_output_text(pcmk__output_t *out, const pcmk_resource_t *rsc,
698 const char *name, const pcmk_node_t *node,
699 uint32_t show_opts)
700 {
701 const char *target_role = NULL;
702
703 pcmk__assert(pcmk__is_primitive(rsc));
704
705 if (crm_is_true(g_hash_table_lookup(rsc->priv->meta,
706 PCMK__META_INTERNAL_RSC))
707 && !pcmk_is_set(show_opts, pcmk_show_implicit_rscs)) {
708
709 crm_trace("skipping print of internal resource %s", rsc->id);
710 return pcmk_rc_no_output;
711 }
712 target_role = g_hash_table_lookup(rsc->priv->meta,
713 PCMK_META_TARGET_ROLE);
714
715 {
716 gchar *s = pcmk__native_output_string(rsc, name, node, show_opts,
717 target_role, true);
718
719 out->list_item(out, NULL, "%s", s);
720 g_free(s);
721 }
722
723 return pcmk_rc_ok;
724 }
725
726 PCMK__OUTPUT_ARGS("primitive", "uint32_t", "pcmk_resource_t *", "GList *",
727 "GList *")
728 int
729 pe__resource_xml(pcmk__output_t *out, va_list args)
730 {
731 uint32_t show_opts = va_arg(args, uint32_t);
732 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
733 GList *only_node G_GNUC_UNUSED = va_arg(args, GList *);
734 GList *only_rsc = va_arg(args, GList *);
735
736 int rc = pcmk_rc_no_output;
737 bool print_pending = pcmk_is_set(show_opts, pcmk_show_pending);
738 const char *class = crm_element_value(rsc->priv->xml, PCMK_XA_CLASS);
739 const char *prov = crm_element_value(rsc->priv->xml, PCMK_XA_PROVIDER);
740
741 char ra_name[LINE_MAX];
742 const char *rsc_state = native_displayable_state(rsc, print_pending);
743 const char *target_role = NULL;
744 const char *active = pcmk__btoa(rsc->priv->fns->active(rsc, true));
745 const char *orphaned = pcmk__flag_text(rsc->flags, pcmk__rsc_removed);
746 const char *blocked = pcmk__flag_text(rsc->flags, pcmk__rsc_blocked);
747 const char *maintenance = pcmk__flag_text(rsc->flags,
748 pcmk__rsc_maintenance);
749 const char *managed = pcmk__flag_text(rsc->flags, pcmk__rsc_managed);
750 const char *failed = pcmk__flag_text(rsc->flags, pcmk__rsc_failed);
751 const char *ignored = pcmk__flag_text(rsc->flags, pcmk__rsc_ignore_failure);
752 char *nodes_running_on = NULL;
753 const char *pending = print_pending? native_pending_action(rsc) : NULL;
754 const char *locked_to = NULL;
755 const char *desc = pe__resource_description(rsc, show_opts);
756
757 pcmk__assert(pcmk__is_primitive(rsc));
758
759 if (rsc->priv->fns->is_filtered(rsc, only_rsc, true)) {
760 return pcmk_rc_no_output;
761 }
762
763
764 snprintf(ra_name, LINE_MAX, "%s%s%s:%s", class,
765 ((prov == NULL)? "" : ":"), ((prov == NULL)? "" : prov),
766 crm_element_value(rsc->priv->xml, PCMK_XA_TYPE));
767
768 target_role = g_hash_table_lookup(rsc->priv->meta,
769 PCMK_META_TARGET_ROLE);
770
771 nodes_running_on = pcmk__itoa(g_list_length(rsc->priv->active_nodes));
772
773 if (rsc->priv->lock_node != NULL) {
774 locked_to = rsc->priv->lock_node->priv->name;
775 }
776
777 rc = pe__name_and_nvpairs_xml(out, true, PCMK_XE_RESOURCE,
778 PCMK_XA_ID, rsc_printable_id(rsc),
779 PCMK_XA_RESOURCE_AGENT, ra_name,
780 PCMK_XA_ROLE, rsc_state,
781 PCMK_XA_TARGET_ROLE, target_role,
782 PCMK_XA_ACTIVE, active,
783 PCMK_XA_ORPHANED, orphaned,
784 PCMK_XA_BLOCKED, blocked,
785 PCMK_XA_MAINTENANCE, maintenance,
786 PCMK_XA_MANAGED, managed,
787 PCMK_XA_FAILED, failed,
788 PCMK_XA_FAILURE_IGNORED, ignored,
789 PCMK_XA_NODES_RUNNING_ON, nodes_running_on,
790 PCMK_XA_PENDING, pending,
791 PCMK_XA_LOCKED_TO, locked_to,
792 PCMK_XA_DESCRIPTION, desc,
793 NULL);
794 free(nodes_running_on);
795
796 pcmk__assert(rc == pcmk_rc_ok);
797
798 for (GList *gIter = rsc->priv->active_nodes;
799 gIter != NULL; gIter = gIter->next) {
800
801 pcmk_node_t *node = (pcmk_node_t *) gIter->data;
802 const char *cached = pcmk__btoa(node->details->online);
803
804 rc = pe__name_and_nvpairs_xml(out, false, PCMK_XE_NODE,
805 PCMK_XA_NAME, node->priv->name,
806 PCMK_XA_ID, node->priv->id,
807 PCMK_XA_CACHED, cached,
808 NULL);
809 pcmk__assert(rc == pcmk_rc_ok);
810 }
811
812 pcmk__output_xml_pop_parent(out);
813 return rc;
814 }
815
816 PCMK__OUTPUT_ARGS("primitive", "uint32_t", "pcmk_resource_t *", "GList *",
817 "GList *")
818 int
819 pe__resource_html(pcmk__output_t *out, va_list args)
820 {
821 uint32_t show_opts = va_arg(args, uint32_t);
822 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
823 GList *only_node G_GNUC_UNUSED = va_arg(args, GList *);
824 GList *only_rsc = va_arg(args, GList *);
825
826 const pcmk_node_t *node = pcmk__current_node(rsc);
827
828 if (rsc->priv->fns->is_filtered(rsc, only_rsc, true)) {
829 return pcmk_rc_no_output;
830 }
831
832 pcmk__assert(pcmk__is_primitive(rsc));
833
834 if (node == NULL) {
835
836 node = rsc->priv->pending_node;
837 }
838 return pe__common_output_html(out, rsc, rsc_printable_id(rsc), node, show_opts);
839 }
840
841 PCMK__OUTPUT_ARGS("primitive", "uint32_t", "pcmk_resource_t *", "GList *",
842 "GList *")
843 int
844 pe__resource_text(pcmk__output_t *out, va_list args)
845 {
846 uint32_t show_opts = va_arg(args, uint32_t);
847 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
848 GList *only_node G_GNUC_UNUSED = va_arg(args, GList *);
849 GList *only_rsc = va_arg(args, GList *);
850
851 const pcmk_node_t *node = pcmk__current_node(rsc);
852
853 pcmk__assert(pcmk__is_primitive(rsc));
854
855 if (rsc->priv->fns->is_filtered(rsc, only_rsc, true)) {
856 return pcmk_rc_no_output;
857 }
858
859 if (node == NULL) {
860
861 node = rsc->priv->pending_node;
862 }
863 return pe__common_output_text(out, rsc, rsc_printable_id(rsc), node, show_opts);
864 }
865
866 void
867 native_free(pcmk_resource_t * rsc)
868 {
869 pcmk__rsc_trace(rsc, "Freeing resource action list (not the data)");
870 common_free(rsc);
871 }
872
873 enum rsc_role_e
874 native_resource_state(const pcmk_resource_t *rsc, bool current)
875 {
876 enum rsc_role_e role = rsc->priv->next_role;
877
878 if (current) {
879 role = rsc->priv->orig_role;
880 }
881 pcmk__rsc_trace(rsc, "%s state: %s", rsc->id, pcmk_role_text(role));
882 return role;
883 }
884
885
886
887
888
889
890
891
892
893
894
895
896 pcmk_node_t *
897 native_location(const pcmk_resource_t *rsc, GList **list, uint32_t target)
898 {
899 pcmk_node_t *one = NULL;
900 GList *result = NULL;
901
902 if (rsc->priv->children != NULL) {
903
904 for (GList *gIter = rsc->priv->children;
905 gIter != NULL; gIter = gIter->next) {
906
907 pcmk_resource_t *child = (pcmk_resource_t *) gIter->data;
908
909 child->priv->fns->location(child, &result, target);
910 }
911
912 } else {
913 if (pcmk_is_set(target, pcmk__rsc_node_current)) {
914 result = g_list_copy(rsc->priv->active_nodes);
915 }
916 if (pcmk_is_set(target, pcmk__rsc_node_pending)
917 && (rsc->priv->pending_node != NULL)
918 && !pe_find_node_id(result, rsc->priv->pending_node->priv->id)) {
919 result = g_list_append(result, (gpointer) rsc->priv->pending_node);
920 }
921 if (pcmk_is_set(target, pcmk__rsc_node_assigned)
922 && (rsc->priv->assigned_node != NULL)) {
923 result = g_list_append(result, rsc->priv->assigned_node);
924 }
925 }
926
927 if (result && (result->next == NULL)) {
928 one = result->data;
929 }
930
931 if (list) {
932 GList *gIter = result;
933
934 for (; gIter != NULL; gIter = gIter->next) {
935 pcmk_node_t *node = (pcmk_node_t *) gIter->data;
936
937 if ((*list == NULL)
938 || (pe_find_node_id(*list, node->priv->id) == NULL)) {
939 *list = g_list_append(*list, node);
940 }
941 }
942 }
943
944 g_list_free(result);
945 return one;
946 }
947
948 static void
949 get_rscs_brief(GList *rsc_list, GHashTable * rsc_table, GHashTable * active_table)
950 {
951 GList *gIter = rsc_list;
952
953 for (; gIter != NULL; gIter = gIter->next) {
954 pcmk_resource_t *rsc = (pcmk_resource_t *) gIter->data;
955
956 const char *class = crm_element_value(rsc->priv->xml, PCMK_XA_CLASS);
957 const char *kind = crm_element_value(rsc->priv->xml, PCMK_XA_TYPE);
958
959 int offset = 0;
960 char buffer[LINE_MAX];
961
962 int *rsc_counter = NULL;
963 int *active_counter = NULL;
964
965 if (!pcmk__is_primitive(rsc)) {
966 continue;
967 }
968
969 offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", class);
970 if (pcmk_is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
971 const char *prov = crm_element_value(rsc->priv->xml,
972 PCMK_XA_PROVIDER);
973
974 if (prov != NULL) {
975 offset += snprintf(buffer + offset, LINE_MAX - offset,
976 ":%s", prov);
977 }
978 }
979 offset += snprintf(buffer + offset, LINE_MAX - offset, ":%s", kind);
980 CRM_LOG_ASSERT(offset > 0);
981
982 if (rsc_table) {
983 rsc_counter = g_hash_table_lookup(rsc_table, buffer);
984 if (rsc_counter == NULL) {
985 rsc_counter = pcmk__assert_alloc(1, sizeof(int));
986 *rsc_counter = 0;
987 g_hash_table_insert(rsc_table, strdup(buffer), rsc_counter);
988 }
989 (*rsc_counter)++;
990 }
991
992 if (active_table) {
993 for (GList *gIter2 = rsc->priv->active_nodes;
994 gIter2 != NULL; gIter2 = gIter2->next) {
995
996 pcmk_node_t *node = (pcmk_node_t *) gIter2->data;
997 GHashTable *node_table = NULL;
998
999 if (node->details->unclean == FALSE && node->details->online == FALSE &&
1000 pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
1001 continue;
1002 }
1003
1004 node_table = g_hash_table_lookup(active_table,
1005 node->priv->name);
1006 if (node_table == NULL) {
1007 node_table = pcmk__strkey_table(free, free);
1008 g_hash_table_insert(active_table,
1009 strdup(node->priv->name),
1010 node_table);
1011 }
1012
1013 active_counter = g_hash_table_lookup(node_table, buffer);
1014 if (active_counter == NULL) {
1015 active_counter = pcmk__assert_alloc(1, sizeof(int));
1016 *active_counter = 0;
1017 g_hash_table_insert(node_table, strdup(buffer), active_counter);
1018 }
1019 (*active_counter)++;
1020 }
1021 }
1022 }
1023 }
1024
1025 static void
1026 destroy_node_table(gpointer data)
1027 {
1028 GHashTable *node_table = data;
1029
1030 if (node_table) {
1031 g_hash_table_destroy(node_table);
1032 }
1033 }
1034
1035 int
1036 pe__rscs_brief_output(pcmk__output_t *out, GList *rsc_list, uint32_t show_opts)
1037 {
1038 GHashTable *rsc_table = pcmk__strkey_table(free, free);
1039 GHashTable *active_table = pcmk__strkey_table(free, destroy_node_table);
1040 GList *sorted_rscs;
1041 int rc = pcmk_rc_no_output;
1042
1043 get_rscs_brief(rsc_list, rsc_table, active_table);
1044
1045
1046
1047
1048 sorted_rscs = g_hash_table_get_keys(rsc_table);
1049 sorted_rscs = g_list_sort(sorted_rscs, (GCompareFunc) strcmp);
1050
1051 for (GList *gIter = sorted_rscs; gIter; gIter = gIter->next) {
1052 char *type = (char *) gIter->data;
1053 int *rsc_counter = g_hash_table_lookup(rsc_table, type);
1054
1055 GList *sorted_nodes = NULL;
1056 int active_counter_all = 0;
1057
1058
1059
1060
1061
1062 sorted_nodes = g_hash_table_get_keys(active_table);
1063 sorted_nodes = g_list_sort(sorted_nodes, (GCompareFunc) pcmk__numeric_strcasecmp);
1064
1065 for (GList *gIter2 = sorted_nodes; gIter2; gIter2 = gIter2->next) {
1066 char *node_name = (char *) gIter2->data;
1067 GHashTable *node_table = g_hash_table_lookup(active_table, node_name);
1068 int *active_counter = NULL;
1069
1070 if (node_table == NULL) {
1071 continue;
1072 }
1073
1074 active_counter = g_hash_table_lookup(node_table, type);
1075
1076 if (active_counter == NULL || *active_counter == 0) {
1077 continue;
1078
1079 } else {
1080 active_counter_all += *active_counter;
1081 }
1082
1083 if (pcmk_is_set(show_opts, pcmk_show_rsc_only)) {
1084 node_name = NULL;
1085 }
1086
1087 if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
1088 out->list_item(out, NULL, "%d/%d\t(%s):\tActive %s",
1089 *active_counter,
1090 rsc_counter ? *rsc_counter : 0, type,
1091 (*active_counter > 0) && node_name ? node_name : "");
1092 } else {
1093 out->list_item(out, NULL, "%d\t(%s):\tActive %s",
1094 *active_counter, type,
1095 (*active_counter > 0) && node_name ? node_name : "");
1096 }
1097
1098 rc = pcmk_rc_ok;
1099 }
1100
1101 if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs) && active_counter_all == 0) {
1102 out->list_item(out, NULL, "%d/%d\t(%s):\tActive",
1103 active_counter_all,
1104 rsc_counter ? *rsc_counter : 0, type);
1105 rc = pcmk_rc_ok;
1106 }
1107
1108 if (sorted_nodes) {
1109 g_list_free(sorted_nodes);
1110 }
1111 }
1112
1113 if (rsc_table) {
1114 g_hash_table_destroy(rsc_table);
1115 rsc_table = NULL;
1116 }
1117 if (active_table) {
1118 g_hash_table_destroy(active_table);
1119 active_table = NULL;
1120 }
1121 if (sorted_rscs) {
1122 g_list_free(sorted_rscs);
1123 }
1124
1125 return rc;
1126 }
1127
1128 bool
1129 pe__native_is_filtered(const pcmk_resource_t *rsc, const GList *only_rsc,
1130 bool check_parent)
1131 {
1132 if (pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
1133 pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches)) {
1134 return false;
1135 } else if (check_parent && (rsc->priv->parent != NULL)) {
1136 const pcmk_resource_t *up = pe__const_top_resource(rsc, true);
1137
1138 return up->priv->fns->is_filtered(up, only_rsc, false);
1139 }
1140
1141 return true;
1142 }
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152 unsigned int
1153 pe__primitive_max_per_node(const pcmk_resource_t *rsc)
1154 {
1155 pcmk__assert(pcmk__is_primitive(rsc));
1156 return 1U;
1157 }