pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
native.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2025 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <stdbool.h> // bool, true, false
13#include <stdint.h> // uint32_t
14
15#include <crm/common/output.h>
16#include <crm/pengine/status.h>
17#include <crm/pengine/complex.h>
19#include <crm/common/xml.h>
20#include <pe_status_private.h>
21
26static bool
27is_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
37static void
38native_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 // Promoted instance takes base priority + 1
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 /* Priority of a resource running on a guest node is added to the cluster
63 * node as well. */
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;
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
86void
88 pcmk_scheduler_t *scheduler, gboolean failed)
89{
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) {
114 }
115 }
116
117 if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
119
120 pcmk__rsc_info(rsc, "resource %s isn't managed", rsc->id);
122 "not_managed_default", scheduler);
123
124 while(p) {
125 /* add without the additional location constraint */
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) {
135 {
136 GHashTableIter gIter;
137 pcmk_node_t *local_node = NULL;
138
139 /* make sure it doesn't come up again */
140 if (rsc->priv->allowed_nodes != NULL) {
141 g_hash_table_destroy(rsc->priv->allowed_nodes);
142 }
143 rsc->priv->allowed_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;
154
155 /* If the resource belongs to a group or bundle configured with
156 * PCMK_META_MULTIPLE_ACTIVE=PCMK_VALUE_BLOCK, block the entire
157 * entity.
158 */
159 if ((pcmk__is_group(parent) || pcmk__is_bundle(parent))
160 && (parent->priv->multiply_active_policy
162
163 for (GList *gIter = parent->priv->children;
164 gIter != NULL; gIter = gIter->next) {
165 pcmk_resource_t *child = gIter->data;
166
169 }
170 }
171 break;
172
173 // pcmk__multiply_active_restart, pcmk__multiply_active_unexpected
174 default:
175 /* The scheduler will do the right thing because the relevant
176 * variables and flags are set when unpacking the history.
177 */
178 break;
179 }
180 crm_debug("%s is active on multiple nodes including %s: %s",
181 rsc->id, pcmk__node_name(node),
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
194static void
195recursive_clear_unique(pcmk_resource_t *rsc, gpointer user_data)
196{
200 g_list_foreach(rsc->priv->children, (GFunc) recursive_clear_unique,
201 NULL);
202}
203
204bool
206{
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 // Only some agent standards support unique and promotable clones
214 if (!pcmk_is_set(ra_caps, pcmk_ra_cap_unique)
216 && pcmk__is_clone(parent)) {
217
218 /* @COMPAT We should probably reject this situation as an error (as we
219 * do for promotable below) rather than warn and convert, but that would
220 * be a backward-incompatible change that we should probably do with a
221 * transform at a schema major version bump.
222 */
223 pe__force_anon(standard, parent, rsc->id, rsc->priv->scheduler);
224
225 /* Clear PCMK_META_GLOBALLY_UNIQUE on the parent and all its descendants
226 * unpacked so far (clearing the parent should make any future children
227 * unpacking correct). We have to clear this resource explicitly because
228 * it isn't hooked into the parent's children yet.
229 */
230 recursive_clear_unique(parent, NULL);
231 recursive_clear_unique(rsc, NULL);
232 }
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
244static bool
245rsc_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
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
262 && (rsc->priv->assigned_node != NULL)
263 && pcmk__same_node(rsc->priv->assigned_node, node)) {
264 return true;
265 }
266 return false;
267}
268
270native_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
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
292 && pcmk__str_eq(rsc->priv->history_id, id, pcmk__str_none)) {
293 match = true;
294
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
324bool
325native_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
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
349struct print_data_s {
350 long options;
351 void *print_data;
352};
353
354static const char *
355native_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,
361 pending_state = "Starting";
362
363 } else if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_STOP,
365 pending_state = "Stopping";
366
367 } else if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_MIGRATE_TO,
369 pending_state = "Migrating";
370
371 } else if (pcmk__str_eq(rsc->priv->pending_action,
373 /* Work might be done in here. */
374 pending_state = "Migrating";
375
376 } else if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_PROMOTE,
378 pending_state = "Promoting";
379
380 } else if (pcmk__str_eq(rsc->priv->pending_action, PCMK_ACTION_DEMOTE,
382 pending_state = "Demoting";
383 }
384
385 return pending_state;
386}
387
388static const char *
389native_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,
395 pending_action = "Monitoring";
396
397 /* Pending probes are not printed, even if pending
398 * operations are requested. If someone ever requests that
399 * behavior, uncomment this and the corresponding part of
400 * unpack.c:unpack_rsc_op().
401 */
402#if 0
403 } else if (pcmk__str_eq(rsc->private->pending_action, "probe",
405 pending_action = "Checking";
406#endif
407 }
408
409 return pending_action;
410}
411
412static enum rsc_role_e
413native_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)
420
422 }
423 return role;
424}
425
426static const char *
427native_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// Append a flag to resource description string's flags list
441static bool
442add_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// Append a node name to resource description string's node list
450static bool
451add_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
472gchar *
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
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 // Resource name and agent
506 pcmk__g_strcat(outstr,
507 name, "\t(", class, ((provider == NULL)? "" : ":"),
508 pcmk__s(provider, ""), ":", kind, "):\t", NULL);
509
510 // State on node
512 g_string_append(outstr, " ORPHANED");
513 }
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 // Failed probe operation
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
538 &rc, 0);
539 pcmk__g_strcat(outstr, " (", crm_exit_str(rc), ") ", NULL);
540 }
541 }
542
543 // Flags, as: (<flag> [...])
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)) {
561 " %s for resource %s", target_role, rsc->id);
562 break;
563
565 have_flags = add_output_flag(outstr, "disabled", have_flags);
566 break;
567
571 have_flags = add_output_flag(outstr,
573 have_flags);
574 g_string_append(outstr, target_role);
575 }
576 break;
577
578 default:
579 /* Only show target role if it limits our abilities (i.e. ignore
580 * Started, as it is the default anyways, and doesn't prevent
581 * the resource from becoming promoted).
582 */
583 break;
584 }
585 }
586
587 // Blocked or maintenance implies unmanaged
588 if (pcmk_any_flags_set(rsc->flags,
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
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 // User-supplied description
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,
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
642int
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,
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,
665
666 if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
668
669 } else if (pcmk_is_set(rsc->flags, pcmk__rsc_failed)) {
671
672 } else if (pcmk__is_primitive(rsc)
673 && (rsc->priv->active_nodes == NULL)) {
675
676 } else if (pcmk__list_of_multiple(rsc->priv->active_nodes)) {
678
679 } else if (pcmk_is_set(rsc->flags, pcmk__rsc_ignore_failure)) {
681
682 } else {
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
696int
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,
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,
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
726PCMK__OUTPUT_ARGS("primitive", "uint32_t", "pcmk_resource_t *", "GList *",
727 "GList *")
728int
729pe__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,
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 // Resource information
764 snprintf(ra_name, LINE_MAX, "%s%s%s:%s", class,
765 ((prov == NULL)? "" : ":"), ((prov == NULL)? "" : prov),
767
768 target_role = g_hash_table_lookup(rsc->priv->meta,
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
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,
789 PCMK_XA_NODES_RUNNING_ON, nodes_running_on,
790 PCMK_XA_PENDING, pending,
791 PCMK_XA_LOCKED_TO, locked_to,
793 NULL);
794 free(nodes_running_on);
795
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);
810 }
811
813 return rc;
814}
815
816PCMK__OUTPUT_ARGS("primitive", "uint32_t", "pcmk_resource_t *", "GList *",
817 "GList *")
818int
819pe__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 // This is set only if a non-probe action is pending on this node
836 node = rsc->priv->pending_node;
837 }
838 return pe__common_output_html(out, rsc, rsc_printable_id(rsc), node, show_opts);
839}
840
841PCMK__OUTPUT_ARGS("primitive", "uint32_t", "pcmk_resource_t *", "GList *",
842 "GList *")
843int
844pe__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 // This is set only if a non-probe action is pending on this node
861 node = rsc->priv->pending_node;
862 }
863 return pe__common_output_text(out, rsc, rsc_printable_id(rsc), node, show_opts);
864}
865
866void
868{
869 pcmk__rsc_trace(rsc, "Freeing resource action list (not the data)");
870 common_free(rsc);
871}
872
873enum rsc_role_e
874native_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
897native_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 {
914 result = g_list_copy(rsc->priv->active_nodes);
915 }
917 && (rsc->priv->pending_node != NULL)
919 result = g_list_append(result, (gpointer) rsc->priv->pending_node);
920 }
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
948static void
949get_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);
971 const char *prov = crm_element_value(rsc->priv->xml,
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 &&
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
1025static void
1026destroy_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
1035int
1036pe__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 /* Make a list of the rsc_table keys so that it can be sorted. This is to make sure
1046 * output order stays consistent between systems.
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 /* Also make a list of the active_table keys so it can be sorted. If there's
1059 * more than one instance of a type of resource running, we need the nodes to
1060 * be sorted to make sure output order stays consistent between systems.
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
1128bool
1129pe__native_is_filtered(const pcmk_resource_t *rsc, const GList *only_rsc,
1130 bool check_parent)
1131{
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
1152unsigned int
1154{
1155 pcmk__assert(pcmk__is_primitive(rsc));
1156 return 1U;
1157}
#define PCMK_ACTION_STOP
Definition actions.h:66
#define PCMK_ACTION_PROMOTE
Definition actions.h:57
#define PCMK_ACTION_START
Definition actions.h:63
#define PCMK_ACTION_MIGRATE_FROM
Definition actions.h:49
#define PCMK_ACTION_MIGRATE_TO
Definition actions.h:50
#define PCMK_ACTION_MONITOR
Definition actions.h:51
#define PCMK_ACTION_DEMOTE
Definition actions.h:40
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition agents.c:27
@ pcmk_ra_cap_unique
Definition agents.h:58
@ pcmk_ra_cap_promotable
Definition agents.h:59
@ pcmk_ra_cap_provider
Definition agents.h:55
const char * parent
Definition cib.c:27
const char * name
Definition cib.c:26
void pe__force_anon(const char *standard, pcmk_resource_t *rsc, const char *rid, pcmk_scheduler_t *scheduler)
Definition clone.c:205
#define pcmk__assert_alloc(nmemb, size)
Definition internal.h:246
uint64_t flags
Definition remote.c:3
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:80
pcmk_resource_t * uber_parent(pcmk_resource_t *rsc)
Definition complex.c:999
char data[0]
Definition cpg.c:10
enum pcmk_ipc_server type
Definition cpg.c:3
#define CRM_LOG_ASSERT(expr)
Definition logging.h:196
#define CRM_CHECK(expr, failure_action)
Definition logging.h:213
#define crm_debug(fmt, args...)
Definition logging.h:368
#define crm_trace(fmt, args...)
Definition logging.h:370
#define pcmk__config_err(fmt...)
int pe__common_output_html(pcmk__output_t *out, const pcmk_resource_t *rsc, const char *name, const pcmk_node_t *node, uint32_t show_opts)
Definition native.c:643
int pe__common_output_text(pcmk__output_t *out, const pcmk_resource_t *rsc, const char *name, const pcmk_node_t *node, uint32_t show_opts)
Definition native.c:697
int pe__rscs_brief_output(pcmk__output_t *out, GList *rsc_list, uint32_t show_opts)
Definition native.c:1036
bool native_unpack(pcmk_resource_t *rsc)
Definition native.c:205
bool native_active(const pcmk_resource_t *rsc, bool all)
Definition native.c:325
void native_free(pcmk_resource_t *rsc)
Definition native.c:867
pcmk_resource_t * native_find_rsc(pcmk_resource_t *rsc, const char *id, const pcmk_node_t *on_node, uint32_t flags)
Definition native.c:270
bool pe__native_is_filtered(const pcmk_resource_t *rsc, const GList *only_rsc, bool check_parent)
Definition native.c:1129
pcmk_node_t * native_location(const pcmk_resource_t *rsc, GList **list, uint32_t target)
Definition native.c:897
unsigned int pe__primitive_max_per_node(const pcmk_resource_t *rsc)
Definition native.c:1153
gchar * pcmk__native_output_string(const pcmk_resource_t *rsc, const char *name, const pcmk_node_t *node, uint32_t show_opts, const char *target_role, bool show_nodes)
Definition native.c:473
void native_add_running(pcmk_resource_t *rsc, pcmk_node_t *node, pcmk_scheduler_t *scheduler, gboolean failed)
Definition native.c:87
enum rsc_role_e native_resource_state(const pcmk_resource_t *rsc, bool current)
Definition native.c:874
pcmk_scheduler_t * scheduler
#define pcmk__insert_meta(obj, name, value)
#define PCMK_META_TARGET_ROLE
Definition options.h:114
#define PCMK_META_GLOBALLY_UNIQUE
Definition options.h:90
#define PCMK_VALUE_FALSE
Definition options.h:154
#define PCMK__VALUE_RSC_OK
#define PCMK__VALUE_RSC_FAILURE_IGNORED
#define PCMK__META_INTERNAL_RSC
#define PCMK__VALUE_RSC_FAILED
#define PCMK__VALUE_RSC_MULTIPLE
#define PCMK__VALUE_RSC_MANAGED
Control output from tools.
@ pcmk_show_implicit_rscs
Definition output.h:61
@ pcmk_show_pending
Definition output.h:65
@ pcmk_show_rsc_only
Definition output.h:66
@ pcmk_show_inactive_rscs
Definition output.h:63
@ pcmk_show_description
Definition output.h:69
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
Definition output_xml.c:566
xmlNode * pcmk__html_create(xmlNode *parent, const char *name, const char *id, const char *class_name)
xmlNodePtr pcmk__output_create_html_node(pcmk__output_t *out, const char *element_name, const char *id, const char *class_name, const char *text)
pcmk__action_result_t result
Definition pcmk_fence.c:37
const char * target
Definition pcmk_fence.c:31
GHashTable * pe__node_list2table(const GList *list)
Definition utils.c:152
const char * pe__resource_description(const pcmk_resource_t *rsc, uint32_t show_opts)
Definition pe_output.c:24
pcmk_node_t * pe__find_active_requires(const pcmk_resource_t *rsc, unsigned int *count)
Definition complex.c:1199
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition complex.c:1025
int pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name,...) G_GNUC_NULL_TERMINATED
Definition pe_output.c:619
void resource_location(pcmk_resource_t *rsc, const pcmk_node_t *node, int score, const char *tag, pcmk_scheduler_t *scheduler)
Definition utils.c:398
xmlNode * pe__failed_probe_for_rsc(const pcmk_resource_t *rsc, const char *name)
Definition utils.c:879
void common_free(pcmk_resource_t *rsc)
Definition complex.c:1042
int pe__resource_xml(pcmk__output_t *out, va_list args)
int pe__resource_text(pcmk__output_t *out, va_list args)
int pe__resource_html(pcmk__output_t *out, va_list args)
@ pcmk_rsc_match_anon_basename
Also match anonymous clone instances by base name.
Definition resources.h:37
@ pcmk_rsc_match_clone_only
Match only clones and their instances, by either clone or instance ID.
Definition resources.h:40
@ pcmk_rsc_match_basename
Match clone instances (even unique) by base name as well as exact ID.
Definition resources.h:46
@ pcmk_rsc_match_history
Also match clone instance ID from resource history.
Definition resources.h:34
@ pcmk_rsc_match_current_node
If matching by node, compare current node instead of assigned node.
Definition resources.h:43
@ pcmk__rsc_managed
@ pcmk__rsc_maintenance
@ pcmk__rsc_blocked
@ pcmk__rsc_unique
@ pcmk__rsc_removed
@ pcmk__rsc_promotable
@ pcmk__rsc_ignore_failure
@ pcmk__rsc_failed
#define pcmk__set_rsc_flags(resource, flags_to_set)
const char * pcmk__multiply_active_text(const pcmk_resource_t *rsc)
Get readable description of a multiply-active recovery type.
Definition resources.c:70
@ pcmk__multiply_active_block
Do nothing to resource.
@ pcmk__multiply_active_stop
Stop on all and leave stopped.
@ pcmk__rsc_node_current
@ pcmk__rsc_node_pending
@ pcmk__rsc_node_assigned
#define pcmk__clear_rsc_flags(resource, flags_to_clear)
@ pcmk_rc_no_output
Definition results.h:128
@ pcmk_rc_ok
Definition results.h:159
const char * crm_exit_str(crm_exit_t exit_code)
Definition results.c:757
#define pcmk__assert(expr)
const char * pcmk_role_text(enum rsc_role_e role)
Get readable description of a resource role.
Definition roles.c:23
enum rsc_role_e pcmk_parse_role(const char *role)
Parse a resource role from a string role specification.
Definition roles.c:51
rsc_role_e
Definition roles.h:34
@ pcmk_role_started
Started.
Definition roles.h:37
@ pcmk_role_unknown
Resource role is unknown.
Definition roles.h:35
@ pcmk_role_unpromoted
Unpromoted.
Definition roles.h:38
@ pcmk_role_promoted
Promoted.
Definition roles.h:39
@ pcmk_role_stopped
Stopped.
Definition roles.h:36
#define pcmk__rsc_info(rsc, fmt, args...)
#define pcmk__rsc_trace(rsc, fmt, args...)
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition scores.h:26
Cluster status and scheduling.
pcmk_node_t * pe_find_node_id(const GList *node_list, const char *id)
Find a node by ID in a list of nodes.
Definition status.c:248
const char * rsc_printable_id(const pcmk_resource_t *rsc)
Definition utils.c:581
gboolean crm_is_true(const char *s)
Definition strings.c:490
int pcmk__numeric_strcasecmp(const char *s1, const char *s2)
Definition strings.c:1081
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition strings.c:116
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition strings.c:984
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:685
@ pcmk__str_none
@ pcmk__str_star_matches
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1299
gboolean online
Definition nodes.h:50
GList * running_rsc
Definition nodes.h:70
gboolean maintenance
Definition nodes.h:66
gboolean unclean
Definition nodes.h:58
pcmk_resource_t * remote
This structure contains everything that makes up a single output formatter.
void void(* list_item)(pcmk__output_t *out, const char *name, const char *format,...) G_GNUC_PRINTF(3
const pcmk_node_t * pending_node
const pcmk_node_t * lock_node
pcmk_scheduler_t * scheduler
enum pcmk__multiply_active multiply_active_policy
const pcmk__rsc_methods_t * fns
unsigned long long flags
Definition resources.h:69
pcmk__resource_private_t * priv
Definition resources.h:61
pcmk_resource_t *(* find_rsc)(pcmk_resource_t *rsc, const char *search, const pcmk_node_t *node, uint32_t flags)
bool(* is_filtered)(const pcmk_resource_t *rsc, const GList *only_rsc, bool check_parent)
pcmk_node_t *(* location)(const pcmk_resource_t *rsc, GList **list, uint32_t target)
bool(* active)(const pcmk_resource_t *rsc, bool all)
GList * nodes
Definition scheduler.h:97
pcmk__node_private_t * priv
Definition nodes.h:85
struct pcmk__node_details * details
Definition nodes.h:82
struct pcmk__node_assignment * assign
Definition nodes.h:79
Wrappers for and extensions to libxml2.
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
void pcmk__xe_set_content(xmlNode *node, const char *format,...) G_GNUC_PRINTF(2
#define PCMK_XA_DESCRIPTION
Definition xml_names.h:261
#define PCMK_XA_CLASS
Definition xml_names.h:246
#define PCMK_XE_NODE
Definition xml_names.h:136
#define PCMK_XA_RESOURCE_AGENT
Definition xml_names.h:383
#define PCMK_XA_ORPHANED
Definition xml_names.h:353
#define PCMK_XA_LOCKED_TO
Definition xml_names.h:318
#define PCMK_XA_FAILED
Definition xml_names.h:283
#define PCMK_XA_ID
Definition xml_names.h:301
#define PCMK_XA_ROLE
Definition xml_names.h:387
#define PCMK_XA_PROVIDER
Definition xml_names.h:364
#define PCMK_XA_FAILURE_IGNORED
Definition xml_names.h:284
#define PCMK_XA_TARGET_ROLE
Definition xml_names.h:422
#define PCMK_XA_MAINTENANCE
Definition xml_names.h:321
#define PCMK_XA_ACTIVE
Definition xml_names.h:230
#define PCMK_XA_PENDING
Definition xml_names.h:356
#define PCMK_XA_TYPE
Definition xml_names.h:430
#define PCMK_XA_BLOCKED
Definition xml_names.h:239
#define PCMK_XA_NODES_RUNNING_ON
Definition xml_names.h:340
#define PCMK_XA_NAME
Definition xml_names.h:330
#define PCMK_XE_RESOURCE
Definition xml_names.h:172
#define PCMK_XA_CACHED
Definition xml_names.h:242
#define PCMK_XA_MANAGED
Definition xml_names.h:323
#define PCMK__XE_SPAN
#define PCMK__XA_RC_CODE