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_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 <stdint.h>
13
14 #include <crm/common/output.h>
15 #include <crm/pengine/rules.h>
16 #include <crm/pengine/status.h>
17 #include <crm/pengine/complex.h>
18 #include <crm/pengine/internal.h>
19 #include <crm/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 && node->details->online) {
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 gboolean
205 native_unpack(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
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, 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, int 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
325 char *
326 native_parameter(pcmk_resource_t *rsc, pcmk_node_t *node, gboolean create,
327 const char *name, pcmk_scheduler_t *scheduler)
328 {
329 const char *value = NULL;
330 GHashTable *params = NULL;
331
332 CRM_CHECK(rsc != NULL, return NULL);
333 CRM_CHECK(name != NULL && strlen(name) != 0, return NULL);
334
335 pcmk__rsc_trace(rsc, "Looking up %s in %s", name, rsc->id);
336 params = pe_rsc_params(rsc, node, scheduler);
337 value = g_hash_table_lookup(params, name);
338 if (value == NULL) {
339
340 value = g_hash_table_lookup(rsc->priv->meta, name);
341 }
342 return pcmk__str_copy(value);
343 }
344
345 gboolean
346 native_active(pcmk_resource_t * rsc, gboolean all)
347 {
348 for (GList *gIter = rsc->priv->active_nodes;
349 gIter != NULL; gIter = gIter->next) {
350
351 pcmk_node_t *a_node = (pcmk_node_t *) gIter->data;
352
353 if (a_node->details->unclean) {
354 pcmk__rsc_trace(rsc, "Resource %s: %s is unclean",
355 rsc->id, pcmk__node_name(a_node));
356 return TRUE;
357 } else if (!a_node->details->online
358 && pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
359 pcmk__rsc_trace(rsc, "Resource %s: %s is offline",
360 rsc->id, pcmk__node_name(a_node));
361 } else {
362 pcmk__rsc_trace(rsc, "Resource %s active on %s",
363 rsc->id, pcmk__node_name(a_node));
364 return TRUE;
365 }
366 }
367 return FALSE;
368 }
369
370 struct print_data_s {
371 long options;
372 void *print_data;
373 };
374
375 static const char *
376 native_pending_state(const pcmk_resource_t *rsc)
377 {
378 const char *pending_state = NULL;
379
380 if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_START,
381 pcmk__str_none)) {
382 pending_state = "Starting";
383
384 } else if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_STOP,
385 pcmk__str_none)) {
386 pending_state = "Stopping";
387
388 } else if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_MIGRATE_TO,
389 pcmk__str_none)) {
390 pending_state = "Migrating";
391
392 } else if (pcmk__str_eq(rsc->priv->pending_action,
393 PCMK_ACTION_MIGRATE_FROM, pcmk__str_none)) {
394
395 pending_state = "Migrating";
396
397 } else if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_PROMOTE,
398 pcmk__str_none)) {
399 pending_state = "Promoting";
400
401 } else if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_DEMOTE,
402 pcmk__str_none)) {
403 pending_state = "Demoting";
404 }
405
406 return pending_state;
407 }
408
409 static const char *
410 native_pending_action(const pcmk_resource_t *rsc)
411 {
412 const char *pending_action = NULL;
413
414 if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_MONITOR,
415 pcmk__str_none)) {
416 pending_action = "Monitoring";
417
418
419
420
421
422
423 #if 0
424 } else if (pcmk__str_eq(rsc->private->pending_action, "probe",
425 pcmk__str_none)) {
426 pending_action = "Checking";
427 #endif
428 }
429
430 return pending_action;
431 }
432
433 static enum rsc_role_e
434 native_displayable_role(const pcmk_resource_t *rsc)
435 {
436 enum rsc_role_e role = rsc->priv->orig_role;
437
438 if ((role == pcmk_role_started)
439 && pcmk_is_set(pe__const_top_resource(rsc, false)->flags,
440 pcmk__rsc_promotable)) {
441
442 role = pcmk_role_unpromoted;
443 }
444 return role;
445 }
446
447 static const char *
448 native_displayable_state(const pcmk_resource_t *rsc, bool print_pending)
449 {
450 const char *rsc_state = NULL;
451
452 if (print_pending) {
453 rsc_state = native_pending_state(rsc);
454 }
455 if (rsc_state == NULL) {
456 rsc_state = pcmk_role_text(native_displayable_role(rsc));
457 }
458 return rsc_state;
459 }
460
461
462 static bool
463 add_output_flag(GString *s, const char *flag_desc, bool have_flags)
464 {
465 g_string_append(s, (have_flags? ", " : " ("));
466 g_string_append(s, flag_desc);
467 return true;
468 }
469
470
471 static bool
472 add_output_node(GString *s, const char *node, bool have_nodes)
473 {
474 g_string_append(s, (have_nodes? " " : " [ "));
475 g_string_append(s, node);
476 return true;
477 }
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493 gchar *
494 pcmk__native_output_string(const pcmk_resource_t *rsc, const char *name,
495 const pcmk_node_t *node, uint32_t show_opts,
496 const char *target_role, bool show_nodes)
497 {
498 const char *class = crm_element_value(rsc->priv->xml, PCMK_XA_CLASS);
499 const char *provider = NULL;
500 const char *kind = crm_element_value(rsc->priv->xml, PCMK_XA_TYPE);
501 GString *outstr = NULL;
502 bool have_flags = false;
503
504 if (!pcmk__is_primitive(rsc)) {
505 return NULL;
506 }
507
508 CRM_CHECK(name != NULL, name = "unknown");
509 CRM_CHECK(kind != NULL, kind = "unknown");
510 CRM_CHECK(class != NULL, class = "unknown");
511
512 if (pcmk_is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
513 provider = crm_element_value(rsc->priv->xml, PCMK_XA_PROVIDER);
514 }
515
516 if ((node == NULL) && (rsc->priv->lock_node != NULL)) {
517 node = rsc->priv->lock_node;
518 }
519 if (pcmk_any_flags_set(show_opts, pcmk_show_rsc_only)
520 || pcmk__list_of_multiple(rsc->priv->active_nodes)) {
521 node = NULL;
522 }
523
524 outstr = g_string_sized_new(128);
525
526
527 pcmk__g_strcat(outstr,
528 name, "\t(", class, ((provider == NULL)? "" : ":"),
529 pcmk__s(provider, ""), ":", kind, "):\t", NULL);
530
531
532 if (pcmk_is_set(rsc->flags, pcmk__rsc_removed)) {
533 g_string_append(outstr, " ORPHANED");
534 }
535 if (pcmk_is_set(rsc->flags, pcmk__rsc_failed)) {
536 enum rsc_role_e role = native_displayable_role(rsc);
537
538 g_string_append(outstr, " FAILED");
539 if (role > pcmk_role_unpromoted) {
540 pcmk__add_word(&outstr, 0, pcmk_role_text(role));
541 }
542 } else {
543 bool show_pending = pcmk_is_set(show_opts, pcmk_show_pending);
544
545 pcmk__add_word(&outstr, 0, native_displayable_state(rsc, show_pending));
546 }
547 if (node) {
548 pcmk__add_word(&outstr, 0, pcmk__node_name(node));
549 }
550
551
552 if (native_displayable_role(rsc) == pcmk_role_stopped) {
553 xmlNode *probe_op = pe__failed_probe_for_rsc(rsc,
554 node ? node->priv->name : NULL);
555 if (probe_op != NULL) {
556 int rc;
557
558 pcmk__scan_min_int(crm_element_value(probe_op, PCMK__XA_RC_CODE),
559 &rc, 0);
560 pcmk__g_strcat(outstr, " (", crm_exit_str(rc), ") ", NULL);
561 }
562 }
563
564
565 if (node && !(node->details->online) && node->details->unclean) {
566 have_flags = add_output_flag(outstr, "UNCLEAN", have_flags);
567 }
568 if ((node != NULL) && pcmk__same_node(node, rsc->priv->lock_node)) {
569 have_flags = add_output_flag(outstr, "LOCKED", have_flags);
570 }
571 if (pcmk_is_set(show_opts, pcmk_show_pending)) {
572 const char *pending_action = native_pending_action(rsc);
573
574 if (pending_action != NULL) {
575 have_flags = add_output_flag(outstr, pending_action, have_flags);
576 }
577 }
578 if (target_role != NULL) {
579 switch (pcmk_parse_role(target_role)) {
580 case pcmk_role_unknown:
581 pcmk__config_err("Invalid " PCMK_META_TARGET_ROLE
582 " %s for resource %s", target_role, rsc->id);
583 break;
584
585 case pcmk_role_stopped:
586 have_flags = add_output_flag(outstr, "disabled", have_flags);
587 break;
588
589 case pcmk_role_unpromoted:
590 if (pcmk_is_set(pe__const_top_resource(rsc, false)->flags,
591 pcmk__rsc_promotable)) {
592 have_flags = add_output_flag(outstr,
593 PCMK_META_TARGET_ROLE ":",
594 have_flags);
595 g_string_append(outstr, target_role);
596 }
597 break;
598
599 default:
600
601
602
603
604 break;
605 }
606 }
607
608
609 if (pcmk_any_flags_set(rsc->flags,
610 pcmk__rsc_blocked|pcmk__rsc_maintenance)) {
611 if (pcmk_is_set(rsc->flags, pcmk__rsc_blocked)) {
612 have_flags = add_output_flag(outstr, "blocked", have_flags);
613
614 } else if (pcmk_is_set(rsc->flags, pcmk__rsc_maintenance)) {
615 have_flags = add_output_flag(outstr, "maintenance", have_flags);
616 }
617 } else if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
618 have_flags = add_output_flag(outstr, "unmanaged", have_flags);
619 }
620
621 if (pcmk_is_set(rsc->flags, pcmk__rsc_ignore_failure)) {
622 have_flags = add_output_flag(outstr, "failure ignored", have_flags);
623 }
624
625
626 if (have_flags) {
627 g_string_append_c(outstr, ')');
628 }
629
630
631 if (pcmk_any_flags_set(show_opts, pcmk_show_rsc_only|pcmk_show_description)
632 || pcmk__list_of_multiple(rsc->priv->active_nodes)) {
633 const char *desc = crm_element_value(rsc->priv->xml,
634 PCMK_XA_DESCRIPTION);
635
636 if (desc) {
637 g_string_append(outstr, " (");
638 g_string_append(outstr, desc);
639 g_string_append(outstr, ")");
640
641 }
642 }
643
644 if (show_nodes && !pcmk_is_set(show_opts, pcmk_show_rsc_only)
645 && pcmk__list_of_multiple(rsc->priv->active_nodes)) {
646 bool have_nodes = false;
647
648 for (GList *iter = rsc->priv->active_nodes;
649 iter != NULL; iter = iter->next) {
650
651 pcmk_node_t *n = (pcmk_node_t *) iter->data;
652
653 have_nodes = add_output_node(outstr, n->priv->name, have_nodes);
654 }
655 if (have_nodes) {
656 g_string_append(outstr, " ]");
657 }
658 }
659
660 return g_string_free(outstr, FALSE);
661 }
662
663 int
664 pe__common_output_html(pcmk__output_t *out, const pcmk_resource_t *rsc,
665 const char *name, const pcmk_node_t *node,
666 uint32_t show_opts)
667 {
668 const char *kind = crm_element_value(rsc->priv->xml, PCMK_XA_TYPE);
669 const char *target_role = NULL;
670 const char *cl = NULL;
671
672 xmlNode *child = NULL;
673 gchar *content = NULL;
674
675 pcmk__assert((kind != NULL) && pcmk__is_primitive(rsc));
676
677 if (crm_is_true(g_hash_table_lookup(rsc->priv->meta,
678 PCMK__META_INTERNAL_RSC))
679 && !pcmk_is_set(show_opts, pcmk_show_implicit_rscs)) {
680
681 crm_trace("skipping print of internal resource %s", rsc->id);
682 return pcmk_rc_no_output;
683 }
684 target_role = g_hash_table_lookup(rsc->priv->meta,
685 PCMK_META_TARGET_ROLE);
686
687 if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
688 cl = PCMK__VALUE_RSC_MANAGED;
689
690 } else if (pcmk_is_set(rsc->flags, pcmk__rsc_failed)) {
691 cl = PCMK__VALUE_RSC_FAILED;
692
693 } else if (pcmk__is_primitive(rsc)
694 && (rsc->priv->active_nodes == NULL)) {
695 cl = PCMK__VALUE_RSC_FAILED;
696
697 } else if (pcmk__list_of_multiple(rsc->priv->active_nodes)) {
698 cl = PCMK__VALUE_RSC_MULTIPLE;
699
700 } else if (pcmk_is_set(rsc->flags, pcmk__rsc_ignore_failure)) {
701 cl = PCMK__VALUE_RSC_FAILURE_IGNORED;
702
703 } else {
704 cl = PCMK__VALUE_RSC_OK;
705 }
706
707 child = pcmk__output_create_html_node(out, "li", NULL, NULL, NULL);
708 child = pcmk__html_create(child, PCMK__XE_SPAN, NULL, cl);
709 content = pcmk__native_output_string(rsc, name, node, show_opts,
710 target_role, true);
711 pcmk__xe_set_content(child, "%s", content);
712 g_free(content);
713
714 return pcmk_rc_ok;
715 }
716
717 int
718 pe__common_output_text(pcmk__output_t *out, const pcmk_resource_t *rsc,
719 const char *name, const pcmk_node_t *node,
720 uint32_t show_opts)
721 {
722 const char *target_role = NULL;
723
724 pcmk__assert(pcmk__is_primitive(rsc));
725
726 if (crm_is_true(g_hash_table_lookup(rsc->priv->meta,
727 PCMK__META_INTERNAL_RSC))
728 && !pcmk_is_set(show_opts, pcmk_show_implicit_rscs)) {
729
730 crm_trace("skipping print of internal resource %s", rsc->id);
731 return pcmk_rc_no_output;
732 }
733 target_role = g_hash_table_lookup(rsc->priv->meta,
734 PCMK_META_TARGET_ROLE);
735
736 {
737 gchar *s = pcmk__native_output_string(rsc, name, node, show_opts,
738 target_role, true);
739
740 out->list_item(out, NULL, "%s", s);
741 g_free(s);
742 }
743
744 return pcmk_rc_ok;
745 }
746
747 PCMK__OUTPUT_ARGS("primitive", "uint32_t", "pcmk_resource_t *", "GList *",
748 "GList *")
749 int
750 pe__resource_xml(pcmk__output_t *out, va_list args)
751 {
752 uint32_t show_opts = va_arg(args, uint32_t);
753 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
754 GList *only_node G_GNUC_UNUSED = va_arg(args, GList *);
755 GList *only_rsc = va_arg(args, GList *);
756
757 int rc = pcmk_rc_no_output;
758 bool print_pending = pcmk_is_set(show_opts, pcmk_show_pending);
759 const char *class = crm_element_value(rsc->priv->xml, PCMK_XA_CLASS);
760 const char *prov = crm_element_value(rsc->priv->xml, PCMK_XA_PROVIDER);
761
762 char ra_name[LINE_MAX];
763 const char *rsc_state = native_displayable_state(rsc, print_pending);
764 const char *target_role = NULL;
765 const char *active = pcmk__btoa(rsc->priv->fns->active(rsc, TRUE));
766 const char *orphaned = pcmk__flag_text(rsc->flags, pcmk__rsc_removed);
767 const char *blocked = pcmk__flag_text(rsc->flags, pcmk__rsc_blocked);
768 const char *maintenance = pcmk__flag_text(rsc->flags,
769 pcmk__rsc_maintenance);
770 const char *managed = pcmk__flag_text(rsc->flags, pcmk__rsc_managed);
771 const char *failed = pcmk__flag_text(rsc->flags, pcmk__rsc_failed);
772 const char *ignored = pcmk__flag_text(rsc->flags, pcmk__rsc_ignore_failure);
773 char *nodes_running_on = NULL;
774 const char *pending = print_pending? native_pending_action(rsc) : NULL;
775 const char *locked_to = NULL;
776 const char *desc = pe__resource_description(rsc, show_opts);
777
778 pcmk__assert(pcmk__is_primitive(rsc));
779
780 if (rsc->priv->fns->is_filtered(rsc, only_rsc, TRUE)) {
781 return pcmk_rc_no_output;
782 }
783
784
785 snprintf(ra_name, LINE_MAX, "%s%s%s:%s", class,
786 ((prov == NULL)? "" : ":"), ((prov == NULL)? "" : prov),
787 crm_element_value(rsc->priv->xml, PCMK_XA_TYPE));
788
789 target_role = g_hash_table_lookup(rsc->priv->meta,
790 PCMK_META_TARGET_ROLE);
791
792 nodes_running_on = pcmk__itoa(g_list_length(rsc->priv->active_nodes));
793
794 if (rsc->priv->lock_node != NULL) {
795 locked_to = rsc->priv->lock_node->priv->name;
796 }
797
798 rc = pe__name_and_nvpairs_xml(out, true, PCMK_XE_RESOURCE,
799 PCMK_XA_ID, rsc_printable_id(rsc),
800 PCMK_XA_RESOURCE_AGENT, ra_name,
801 PCMK_XA_ROLE, rsc_state,
802 PCMK_XA_TARGET_ROLE, target_role,
803 PCMK_XA_ACTIVE, active,
804 PCMK_XA_ORPHANED, orphaned,
805 PCMK_XA_BLOCKED, blocked,
806 PCMK_XA_MAINTENANCE, maintenance,
807 PCMK_XA_MANAGED, managed,
808 PCMK_XA_FAILED, failed,
809 PCMK_XA_FAILURE_IGNORED, ignored,
810 PCMK_XA_NODES_RUNNING_ON, nodes_running_on,
811 PCMK_XA_PENDING, pending,
812 PCMK_XA_LOCKED_TO, locked_to,
813 PCMK_XA_DESCRIPTION, desc,
814 NULL);
815 free(nodes_running_on);
816
817 pcmk__assert(rc == pcmk_rc_ok);
818
819 for (GList *gIter = rsc->priv->active_nodes;
820 gIter != NULL; gIter = gIter->next) {
821
822 pcmk_node_t *node = (pcmk_node_t *) gIter->data;
823 const char *cached = pcmk__btoa(node->details->online);
824
825 rc = pe__name_and_nvpairs_xml(out, false, PCMK_XE_NODE,
826 PCMK_XA_NAME, node->priv->name,
827 PCMK_XA_ID, node->priv->id,
828 PCMK_XA_CACHED, cached,
829 NULL);
830 pcmk__assert(rc == pcmk_rc_ok);
831 }
832
833 pcmk__output_xml_pop_parent(out);
834 return rc;
835 }
836
837 PCMK__OUTPUT_ARGS("primitive", "uint32_t", "pcmk_resource_t *", "GList *",
838 "GList *")
839 int
840 pe__resource_html(pcmk__output_t *out, va_list args)
841 {
842 uint32_t show_opts = va_arg(args, uint32_t);
843 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
844 GList *only_node G_GNUC_UNUSED = va_arg(args, GList *);
845 GList *only_rsc = va_arg(args, GList *);
846
847 const pcmk_node_t *node = pcmk__current_node(rsc);
848
849 if (rsc->priv->fns->is_filtered(rsc, only_rsc, TRUE)) {
850 return pcmk_rc_no_output;
851 }
852
853 pcmk__assert(pcmk__is_primitive(rsc));
854
855 if (node == NULL) {
856
857 node = rsc->priv->pending_node;
858 }
859 return pe__common_output_html(out, rsc, rsc_printable_id(rsc), node, show_opts);
860 }
861
862 PCMK__OUTPUT_ARGS("primitive", "uint32_t", "pcmk_resource_t *", "GList *",
863 "GList *")
864 int
865 pe__resource_text(pcmk__output_t *out, va_list args)
866 {
867 uint32_t show_opts = va_arg(args, uint32_t);
868 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
869 GList *only_node G_GNUC_UNUSED = va_arg(args, GList *);
870 GList *only_rsc = va_arg(args, GList *);
871
872 const pcmk_node_t *node = pcmk__current_node(rsc);
873
874 pcmk__assert(pcmk__is_primitive(rsc));
875
876 if (rsc->priv->fns->is_filtered(rsc, only_rsc, TRUE)) {
877 return pcmk_rc_no_output;
878 }
879
880 if (node == NULL) {
881
882 node = rsc->priv->pending_node;
883 }
884 return pe__common_output_text(out, rsc, rsc_printable_id(rsc), node, show_opts);
885 }
886
887 void
888 native_free(pcmk_resource_t * rsc)
889 {
890 pcmk__rsc_trace(rsc, "Freeing resource action list (not the data)");
891 common_free(rsc);
892 }
893
894 enum rsc_role_e
895 native_resource_state(const pcmk_resource_t * rsc, gboolean current)
896 {
897 enum rsc_role_e role = rsc->priv->next_role;
898
899 if (current) {
900 role = rsc->priv->orig_role;
901 }
902 pcmk__rsc_trace(rsc, "%s state: %s", rsc->id, pcmk_role_text(role));
903 return role;
904 }
905
906
907
908
909
910
911
912
913
914
915
916
917 pcmk_node_t *
918 native_location(const pcmk_resource_t *rsc, GList **list, uint32_t target)
919 {
920 pcmk_node_t *one = NULL;
921 GList *result = NULL;
922
923 if (rsc->priv->children != NULL) {
924
925 for (GList *gIter = rsc->priv->children;
926 gIter != NULL; gIter = gIter->next) {
927
928 pcmk_resource_t *child = (pcmk_resource_t *) gIter->data;
929
930 child->priv->fns->location(child, &result, target);
931 }
932
933 } else {
934 if (pcmk_is_set(target, pcmk__rsc_node_current)) {
935 result = g_list_copy(rsc->priv->active_nodes);
936 }
937 if (pcmk_is_set(target, pcmk__rsc_node_pending)
938 && (rsc->priv->pending_node != NULL)
939 && !pe_find_node_id(result, rsc->priv->pending_node->priv->id)) {
940 result = g_list_append(result, (gpointer) rsc->priv->pending_node);
941 }
942 if (pcmk_is_set(target, pcmk__rsc_node_assigned)
943 && (rsc->priv->assigned_node != NULL)) {
944 result = g_list_append(result, rsc->priv->assigned_node);
945 }
946 }
947
948 if (result && (result->next == NULL)) {
949 one = result->data;
950 }
951
952 if (list) {
953 GList *gIter = result;
954
955 for (; gIter != NULL; gIter = gIter->next) {
956 pcmk_node_t *node = (pcmk_node_t *) gIter->data;
957
958 if ((*list == NULL)
959 || (pe_find_node_id(*list, node->priv->id) == NULL)) {
960 *list = g_list_append(*list, node);
961 }
962 }
963 }
964
965 g_list_free(result);
966 return one;
967 }
968
969 static void
970 get_rscs_brief(GList *rsc_list, GHashTable * rsc_table, GHashTable * active_table)
971 {
972 GList *gIter = rsc_list;
973
974 for (; gIter != NULL; gIter = gIter->next) {
975 pcmk_resource_t *rsc = (pcmk_resource_t *) gIter->data;
976
977 const char *class = crm_element_value(rsc->priv->xml, PCMK_XA_CLASS);
978 const char *kind = crm_element_value(rsc->priv->xml, PCMK_XA_TYPE);
979
980 int offset = 0;
981 char buffer[LINE_MAX];
982
983 int *rsc_counter = NULL;
984 int *active_counter = NULL;
985
986 if (!pcmk__is_primitive(rsc)) {
987 continue;
988 }
989
990 offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", class);
991 if (pcmk_is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
992 const char *prov = crm_element_value(rsc->priv->xml,
993 PCMK_XA_PROVIDER);
994
995 if (prov != NULL) {
996 offset += snprintf(buffer + offset, LINE_MAX - offset,
997 ":%s", prov);
998 }
999 }
1000 offset += snprintf(buffer + offset, LINE_MAX - offset, ":%s", kind);
1001 CRM_LOG_ASSERT(offset > 0);
1002
1003 if (rsc_table) {
1004 rsc_counter = g_hash_table_lookup(rsc_table, buffer);
1005 if (rsc_counter == NULL) {
1006 rsc_counter = pcmk__assert_alloc(1, sizeof(int));
1007 *rsc_counter = 0;
1008 g_hash_table_insert(rsc_table, strdup(buffer), rsc_counter);
1009 }
1010 (*rsc_counter)++;
1011 }
1012
1013 if (active_table) {
1014 for (GList *gIter2 = rsc->priv->active_nodes;
1015 gIter2 != NULL; gIter2 = gIter2->next) {
1016
1017 pcmk_node_t *node = (pcmk_node_t *) gIter2->data;
1018 GHashTable *node_table = NULL;
1019
1020 if (node->details->unclean == FALSE && node->details->online == FALSE &&
1021 pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
1022 continue;
1023 }
1024
1025 node_table = g_hash_table_lookup(active_table,
1026 node->priv->name);
1027 if (node_table == NULL) {
1028 node_table = pcmk__strkey_table(free, free);
1029 g_hash_table_insert(active_table,
1030 strdup(node->priv->name),
1031 node_table);
1032 }
1033
1034 active_counter = g_hash_table_lookup(node_table, buffer);
1035 if (active_counter == NULL) {
1036 active_counter = pcmk__assert_alloc(1, sizeof(int));
1037 *active_counter = 0;
1038 g_hash_table_insert(node_table, strdup(buffer), active_counter);
1039 }
1040 (*active_counter)++;
1041 }
1042 }
1043 }
1044 }
1045
1046 static void
1047 destroy_node_table(gpointer data)
1048 {
1049 GHashTable *node_table = data;
1050
1051 if (node_table) {
1052 g_hash_table_destroy(node_table);
1053 }
1054 }
1055
1056 int
1057 pe__rscs_brief_output(pcmk__output_t *out, GList *rsc_list, uint32_t show_opts)
1058 {
1059 GHashTable *rsc_table = pcmk__strkey_table(free, free);
1060 GHashTable *active_table = pcmk__strkey_table(free, destroy_node_table);
1061 GList *sorted_rscs;
1062 int rc = pcmk_rc_no_output;
1063
1064 get_rscs_brief(rsc_list, rsc_table, active_table);
1065
1066
1067
1068
1069 sorted_rscs = g_hash_table_get_keys(rsc_table);
1070 sorted_rscs = g_list_sort(sorted_rscs, (GCompareFunc) strcmp);
1071
1072 for (GList *gIter = sorted_rscs; gIter; gIter = gIter->next) {
1073 char *type = (char *) gIter->data;
1074 int *rsc_counter = g_hash_table_lookup(rsc_table, type);
1075
1076 GList *sorted_nodes = NULL;
1077 int active_counter_all = 0;
1078
1079
1080
1081
1082
1083 sorted_nodes = g_hash_table_get_keys(active_table);
1084 sorted_nodes = g_list_sort(sorted_nodes, (GCompareFunc) pcmk__numeric_strcasecmp);
1085
1086 for (GList *gIter2 = sorted_nodes; gIter2; gIter2 = gIter2->next) {
1087 char *node_name = (char *) gIter2->data;
1088 GHashTable *node_table = g_hash_table_lookup(active_table, node_name);
1089 int *active_counter = NULL;
1090
1091 if (node_table == NULL) {
1092 continue;
1093 }
1094
1095 active_counter = g_hash_table_lookup(node_table, type);
1096
1097 if (active_counter == NULL || *active_counter == 0) {
1098 continue;
1099
1100 } else {
1101 active_counter_all += *active_counter;
1102 }
1103
1104 if (pcmk_is_set(show_opts, pcmk_show_rsc_only)) {
1105 node_name = NULL;
1106 }
1107
1108 if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
1109 out->list_item(out, NULL, "%d/%d\t(%s):\tActive %s",
1110 *active_counter,
1111 rsc_counter ? *rsc_counter : 0, type,
1112 (*active_counter > 0) && node_name ? node_name : "");
1113 } else {
1114 out->list_item(out, NULL, "%d\t(%s):\tActive %s",
1115 *active_counter, type,
1116 (*active_counter > 0) && node_name ? node_name : "");
1117 }
1118
1119 rc = pcmk_rc_ok;
1120 }
1121
1122 if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs) && active_counter_all == 0) {
1123 out->list_item(out, NULL, "%d/%d\t(%s):\tActive",
1124 active_counter_all,
1125 rsc_counter ? *rsc_counter : 0, type);
1126 rc = pcmk_rc_ok;
1127 }
1128
1129 if (sorted_nodes) {
1130 g_list_free(sorted_nodes);
1131 }
1132 }
1133
1134 if (rsc_table) {
1135 g_hash_table_destroy(rsc_table);
1136 rsc_table = NULL;
1137 }
1138 if (active_table) {
1139 g_hash_table_destroy(active_table);
1140 active_table = NULL;
1141 }
1142 if (sorted_rscs) {
1143 g_list_free(sorted_rscs);
1144 }
1145
1146 return rc;
1147 }
1148
1149 gboolean
1150 pe__native_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc,
1151 gboolean check_parent)
1152 {
1153 if (pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
1154 pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches)) {
1155 return FALSE;
1156 } else if (check_parent && (rsc->priv->parent != NULL)) {
1157 const pcmk_resource_t *up = pe__const_top_resource(rsc, true);
1158
1159 return up->priv->fns->is_filtered(up, only_rsc, FALSE);
1160 }
1161
1162 return TRUE;
1163 }
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173 unsigned int
1174 pe__primitive_max_per_node(const pcmk_resource_t *rsc)
1175 {
1176 pcmk__assert(pcmk__is_primitive(rsc));
1177 return 1U;
1178 }