pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
clone.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>
14
15#include <crm/pengine/status.h>
17#include <pe_status_private.h>
18#include <crm/common/xml.h>
19#include <crm/common/output.h>
22
23typedef struct clone_variant_data_s {
24 int clone_max;
25 int clone_node_max;
26
27 int promoted_max;
28 int promoted_node_max;
29
30 int total_clones;
31
32 uint32_t flags; // Group of enum pcmk__clone_flags
33
34 notify_data_t *stop_notify;
35 notify_data_t *start_notify;
36 notify_data_t *demote_notify;
37 notify_data_t *promote_notify;
38
39 xmlNode *xml_obj_child;
41
42#define get_clone_variant_data(data, rsc) do { \
43 pcmk__assert(pcmk__is_clone(rsc)); \
44 data = rsc->priv->variant_opaque; \
45 } while (0)
46
55int
57{
58 const clone_variant_data_t *clone_data = NULL;
59
60 get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
61 return clone_data->clone_max;
62}
63
72int
74{
75 const clone_variant_data_t *clone_data = NULL;
76
77 get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
78 return clone_data->clone_node_max;
79}
80
89int
91{
92 clone_variant_data_t *clone_data = NULL;
93
94 get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
95 return clone_data->promoted_max;
96}
97
106int
108{
109 clone_variant_data_t *clone_data = NULL;
110
111 get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
112 return clone_data->promoted_node_max;
113}
114
115static GList *
116sorted_hash_table_values(GHashTable *table)
117{
118 GList *retval = NULL;
119 GHashTableIter iter;
120 gpointer key, value;
121
122 g_hash_table_iter_init(&iter, table);
123 while (g_hash_table_iter_next(&iter, &key, &value)) {
124 if (!g_list_find_custom(retval, value, (GCompareFunc) strcmp)) {
125 retval = g_list_prepend(retval, (char *) value);
126 }
127 }
128
129 retval = g_list_sort(retval, (GCompareFunc) strcmp);
130 return retval;
131}
132
133static GList *
134nodes_with_status(GHashTable *table, const char *status)
135{
136 GList *retval = NULL;
137 GHashTableIter iter;
138 gpointer key, value;
139
140 g_hash_table_iter_init(&iter, table);
141 while (g_hash_table_iter_next(&iter, &key, &value)) {
142 if (!strcmp((char *) value, status)) {
143 retval = g_list_prepend(retval, key);
144 }
145 }
146
147 retval = g_list_sort(retval, (GCompareFunc) pcmk__numeric_strcasecmp);
148 return retval;
149}
150
151static GString *
152node_list_to_str(const GList *list)
153{
154 GString *retval = NULL;
155
156 for (const GList *iter = list; iter != NULL; iter = iter->next) {
157 pcmk__add_word(&retval, 1024, (const char *) iter->data);
158 }
159
160 return retval;
161}
162
163static void
164clone_header(pcmk__output_t *out, int *rc, const pcmk_resource_t *rsc,
165 clone_variant_data_t *clone_data, const char *desc)
166{
167 GString *attrs = NULL;
168
170 pcmk__add_separated_word(&attrs, 64, "promotable", ", ");
171 }
172
174 pcmk__add_separated_word(&attrs, 64, "unique", ", ");
175 }
176
177 if (pe__resource_is_disabled(rsc)) {
178 pcmk__add_separated_word(&attrs, 64, "disabled", ", ");
179 }
180
182 pcmk__add_separated_word(&attrs, 64, "maintenance", ", ");
183
184 } else if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
185 pcmk__add_separated_word(&attrs, 64, "unmanaged", ", ");
186 }
187
188 if (attrs != NULL) {
189 PCMK__OUTPUT_LIST_HEADER(out, FALSE, *rc, "Clone Set: %s [%s] (%s)%s%s%s",
190 rsc->id,
191 pcmk__xe_id(clone_data->xml_obj_child),
192 (const char *) attrs->str, desc ? " (" : "",
193 desc ? desc : "", desc ? ")" : "");
194 g_string_free(attrs, TRUE);
195 } else {
196 PCMK__OUTPUT_LIST_HEADER(out, FALSE, *rc, "Clone Set: %s [%s]%s%s%s",
197 rsc->id,
198 pcmk__xe_id(clone_data->xml_obj_child),
199 desc ? " (" : "", desc ? desc : "",
200 desc ? ")" : "");
201 }
202}
203
204void
205pe__force_anon(const char *standard, pcmk_resource_t *rsc, const char *rid,
207{
208 if (pcmk__is_clone(rsc)) {
209 clone_variant_data_t *clone_data = rsc->priv->variant_opaque;
210
211 pcmk__config_warn("Ignoring " PCMK_META_GLOBALLY_UNIQUE " for %s "
212 "because %s resources such as %s can be used only as "
213 "anonymous clones", rsc->id, standard, rid);
214
215 clone_data->clone_node_max = 1;
216 clone_data->clone_max = QB_MIN(clone_data->clone_max,
217 g_list_length(scheduler->nodes));
218 }
219}
220
223{
224 gboolean as_orphan = FALSE;
225 char *inc_num = NULL;
226 char *inc_max = NULL;
227 pcmk_resource_t *child_rsc = NULL;
228 xmlNode *child_copy = NULL;
229 clone_variant_data_t *clone_data = NULL;
230
231 get_clone_variant_data(clone_data, rsc);
232
233 CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE);
234
235 if (clone_data->total_clones >= clone_data->clone_max) {
236 // If we've already used all available instances, this is an orphan
237 as_orphan = TRUE;
238 }
239
240 // Allocate instance numbers in numerical order (starting at 0)
241 inc_num = pcmk__itoa(clone_data->total_clones);
242 inc_max = pcmk__itoa(clone_data->clone_max);
243
244 child_copy = pcmk__xml_copy(NULL, clone_data->xml_obj_child);
245
246 crm_xml_add(child_copy, PCMK__META_CLONE, inc_num);
247
248 if (pe__unpack_resource(child_copy, &child_rsc, rsc,
249 scheduler) != pcmk_rc_ok) {
250 goto bail;
251 }
252/* child_rsc->globally_unique = rsc->globally_unique; */
253
254 pcmk__assert(child_rsc != NULL);
255 clone_data->total_clones += 1;
256 pcmk__rsc_trace(child_rsc, "Setting clone attributes for: %s",
257 child_rsc->id);
258 rsc->priv->children = g_list_append(rsc->priv->children, child_rsc);
259 if (as_orphan) {
261 }
262
263 pcmk__insert_meta(child_rsc->priv, PCMK_META_CLONE_MAX, inc_max);
264 pcmk__rsc_trace(rsc, "Added %s instance %s", rsc->id, child_rsc->id);
265
266 bail:
267 free(inc_num);
268 free(inc_max);
269
270 return child_rsc;
271}
272
286static int
287unpack_meta_int(const pcmk_resource_t *rsc, const char *meta_name,
288 const char *deprecated_name, int default_value)
289{
290 int integer = default_value;
291 const char *value = g_hash_table_lookup(rsc->priv->meta, meta_name);
292
293 if ((value == NULL) && (deprecated_name != NULL)) {
294 value = g_hash_table_lookup(rsc->priv->meta, deprecated_name);
295
296 if (value != NULL) {
297 if (pcmk__str_eq(deprecated_name, PCMK__META_PROMOTED_MAX_LEGACY,
300 "Support for the " PCMK__META_PROMOTED_MAX_LEGACY
301 " meta-attribute (such as in %s) is deprecated "
302 "and will be removed in a future release. Use the "
303 PCMK_META_PROMOTED_MAX " meta-attribute instead.",
304 rsc->id);
305 } else if (pcmk__str_eq(deprecated_name, PCMK__META_PROMOTED_NODE_MAX_LEGACY,
308 "Support for the " PCMK__META_PROMOTED_NODE_MAX_LEGACY
309 " meta-attribute (such as in %s) is deprecated "
310 "and will be removed in a future release. Use the "
311 PCMK_META_PROMOTED_NODE_MAX " meta-attribute instead.",
312 rsc->id);
313 }
314 }
315 }
316 if (value != NULL) {
317 pcmk__scan_min_int(value, &integer, 0);
318 }
319 return integer;
320}
321
322bool
324{
325 int lpc = 0;
326 int num_nodes = g_list_length(rsc->priv->scheduler->nodes);
327 xmlNode *a_child = NULL;
328 xmlNode *xml_obj = rsc->priv->xml;
329 clone_variant_data_t *clone_data = NULL;
330
331 pcmk__rsc_trace(rsc, "Processing resource %s...", rsc->id);
332
333 clone_data = pcmk__assert_alloc(1, sizeof(clone_variant_data_t));
334 rsc->priv->variant_opaque = clone_data;
335
337 // Use 1 as default but 0 for minimum and invalid
338 // @COMPAT PCMK__META_PROMOTED_MAX_LEGACY deprecated since 2.0.0
339 clone_data->promoted_max =
340 unpack_meta_int(rsc, PCMK_META_PROMOTED_MAX,
342
343 // Use 1 as default but 0 for minimum and invalid
344 // @COMPAT PCMK__META_PROMOTED_NODE_MAX_LEGACY deprecated since 2.0.0
345 clone_data->promoted_node_max =
346 unpack_meta_int(rsc, PCMK_META_PROMOTED_NODE_MAX,
348 }
349
350 // Use 1 as default but 0 for minimum and invalid
351 clone_data->clone_node_max = unpack_meta_int(rsc, PCMK_META_CLONE_NODE_MAX,
352 NULL, 1);
353
354 /* Use number of nodes (but always at least 1, which is handy for crm_verify
355 * for a CIB without nodes) as default, but 0 for minimum and invalid
356 *
357 * @TODO Exclude bundle nodes when counting
358 */
359 clone_data->clone_max = unpack_meta_int(rsc, PCMK_META_CLONE_MAX, NULL,
360 QB_MAX(1, num_nodes));
361
362 if (crm_is_true(g_hash_table_lookup(rsc->priv->meta,
364 clone_data->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,
365 "Clone", rsc->id,
366 clone_data->flags,
368 "pcmk__clone_ordered");
369 }
370
372 && (clone_data->clone_node_max > 1)) {
373
374 pcmk__config_err("Ignoring " PCMK_META_CLONE_NODE_MAX " of %d for %s "
375 "because anonymous clones support only one instance "
376 "per node", clone_data->clone_node_max, rsc->id);
377 clone_data->clone_node_max = 1;
378 }
379
380 pcmk__rsc_trace(rsc, "Options for %s", rsc->id);
381 pcmk__rsc_trace(rsc, "\tClone max: %d", clone_data->clone_max);
382 pcmk__rsc_trace(rsc, "\tClone node max: %d", clone_data->clone_node_max);
383 pcmk__rsc_trace(rsc, "\tClone is unique: %s",
384 pcmk__flag_text(rsc->flags, pcmk__rsc_unique));
385 pcmk__rsc_trace(rsc, "\tClone is promotable: %s",
386 pcmk__flag_text(rsc->flags, pcmk__rsc_promotable));
387
388 // Clones may contain a single group or primitive
389 for (a_child = pcmk__xe_first_child(xml_obj, NULL, NULL, NULL);
390 a_child != NULL; a_child = pcmk__xe_next(a_child, NULL)) {
391
392 if (pcmk__str_any_of((const char *) a_child->name,
394 clone_data->xml_obj_child = a_child;
395 break;
396 }
397 }
398
399 if (clone_data->xml_obj_child == NULL) {
400 pcmk__config_err("%s has nothing to clone", rsc->id);
401 return FALSE;
402 }
403
404 /*
405 * Make clones ever so slightly sticky by default
406 *
407 * This helps ensure clone instances are not shuffled around the cluster
408 * for no benefit in situations when pre-allocation is not appropriate
409 */
410 if (g_hash_table_lookup(rsc->priv->meta,
413 }
414
415 /* This ensures that the PCMK_META_GLOBALLY_UNIQUE value always exists for
416 * children to inherit when being unpacked, as well as in resource agents'
417 * environment.
418 */
420 pcmk__flag_text(rsc->flags, pcmk__rsc_unique));
421
422 if (clone_data->clone_max <= 0) {
423 /* Create one child instance so that unpack_find_resource() will hook up
424 * any orphans up to the parent correctly.
425 */
426 if (pe__create_clone_child(rsc, rsc->priv->scheduler) == NULL) {
427 return FALSE;
428 }
429
430 } else {
431 // Create a child instance for each available instance number
432 for (lpc = 0; lpc < clone_data->clone_max; lpc++) {
433 if (pe__create_clone_child(rsc, rsc->priv->scheduler) == NULL) {
434 return FALSE;
435 }
436 }
437 }
438
439 pcmk__rsc_trace(rsc, "Added %d children to resource %s...",
440 clone_data->clone_max, rsc->id);
441 return TRUE;
442}
443
444bool
445clone_active(const pcmk_resource_t *rsc, bool all)
446{
447 for (GList *gIter = rsc->priv->children;
448 gIter != NULL; gIter = gIter->next) {
449
450 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
451 bool child_active = child_rsc->priv->fns->active(child_rsc, all);
452
453 if (all == FALSE && child_active) {
454 return TRUE;
455 } else if (all && child_active == FALSE) {
456 return FALSE;
457 }
458 }
459
460 if (all) {
461 return TRUE;
462 } else {
463 return FALSE;
464 }
465}
466
467static const char *
468configured_role_str(pcmk_resource_t * rsc)
469{
470 const char *target_role = g_hash_table_lookup(rsc->priv->meta,
472
473 if ((target_role == NULL) && (rsc->priv->children != NULL)) {
474 // Any instance will do
475 pcmk_resource_t *instance = rsc->priv->children->data;
476
477 target_role = g_hash_table_lookup(instance->priv->meta,
479 }
480 return target_role;
481}
482
483static enum rsc_role_e
484configured_role(pcmk_resource_t *rsc)
485{
486 enum rsc_role_e role = pcmk_role_unknown;
487 const char *target_role = configured_role_str(rsc);
488
489 if (target_role != NULL) {
490 role = pcmk_parse_role(target_role);
491 if (role == pcmk_role_unknown) {
493 " for resource %s", rsc->id);
494 }
495 }
496 return role;
497}
498
499bool
500is_set_recursive(const pcmk_resource_t *rsc, long long flag, bool any)
501{
502 bool all = !any;
503
504 if (pcmk_is_set(rsc->flags, flag)) {
505 if(any) {
506 return TRUE;
507 }
508 } else if(all) {
509 return FALSE;
510 }
511
512 for (GList *gIter = rsc->priv->children;
513 gIter != NULL; gIter = gIter->next) {
514
515 if(is_set_recursive(gIter->data, flag, any)) {
516 if(any) {
517 return TRUE;
518 }
519
520 } else if(all) {
521 return FALSE;
522 }
523 }
524
525 if(all) {
526 return TRUE;
527 }
528 return FALSE;
529}
530
531PCMK__OUTPUT_ARGS("clone", "uint32_t", "pcmk_resource_t *", "GList *",
532 "GList *")
533int
534pe__clone_xml(pcmk__output_t *out, va_list args)
535{
536 uint32_t show_opts = va_arg(args, uint32_t);
537 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
538 GList *only_node = va_arg(args, GList *);
539 GList *only_rsc = va_arg(args, GList *);
540
541 GList *all = NULL;
542 int rc = pcmk_rc_no_output;
543 gboolean printed_header = FALSE;
544 bool print_everything = true;
545
546 if (rsc->priv->fns->is_filtered(rsc, only_rsc, true)) {
547 return rc;
548 }
549
550 print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
551 (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
552
553 all = g_list_prepend(all, (gpointer) "*");
554
555 for (GList *gIter = rsc->priv->children;
556 gIter != NULL; gIter = gIter->next) {
557
558 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
559
560 if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
561 continue;
562 }
563
564 if (child_rsc->priv->fns->is_filtered(child_rsc, only_rsc,
565 print_everything)) {
566 continue;
567 }
568
569 if (!printed_header) {
570 const char *multi_state = pcmk__flag_text(rsc->flags,
572 const char *unique = pcmk__flag_text(rsc->flags, pcmk__rsc_unique);
573 const char *maintenance = pcmk__flag_text(rsc->flags,
575 const char *managed = pcmk__flag_text(rsc->flags,
577 const char *disabled = pcmk__btoa(pe__resource_is_disabled(rsc));
578 const char *failed = pcmk__flag_text(rsc->flags, pcmk__rsc_failed);
579 const char *ignored = pcmk__flag_text(rsc->flags,
581 const char *target_role = configured_role_str(rsc);
582 const char *desc = pe__resource_description(rsc, show_opts);
583
584 printed_header = TRUE;
585
587 PCMK_XA_ID, rsc->id,
588 PCMK_XA_MULTI_STATE, multi_state,
589 PCMK_XA_UNIQUE, unique,
590 PCMK_XA_MAINTENANCE, maintenance,
591 PCMK_XA_MANAGED, managed,
592 PCMK_XA_DISABLED, disabled,
593 PCMK_XA_FAILED, failed,
595 PCMK_XA_TARGET_ROLE, target_role,
597 NULL);
599 }
600
601 out->message(out, (const char *) child_rsc->priv->xml->name,
602 show_opts, child_rsc, only_node, all);
603 }
604
605 if (printed_header) {
607 }
608
609 g_list_free(all);
610 return rc;
611}
612
613PCMK__OUTPUT_ARGS("clone", "uint32_t", "pcmk_resource_t *", "GList *",
614 "GList *")
615int
616pe__clone_default(pcmk__output_t *out, va_list args)
617{
618 uint32_t show_opts = va_arg(args, uint32_t);
619 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
620 GList *only_node = va_arg(args, GList *);
621 GList *only_rsc = va_arg(args, GList *);
622
623 GHashTable *stopped = NULL;
624
625 GString *list_text = NULL;
626
627 GList *promoted_list = NULL;
628 GList *started_list = NULL;
629 GList *gIter = NULL;
630
631 const char *desc = NULL;
632
633 clone_variant_data_t *clone_data = NULL;
634 int active_instances = 0;
635 int rc = pcmk_rc_no_output;
636 gboolean print_everything = TRUE;
637
638 desc = pe__resource_description(rsc, show_opts);
639
640 get_clone_variant_data(clone_data, rsc);
641
642 if (rsc->priv->fns->is_filtered(rsc, only_rsc, true)) {
643 return rc;
644 }
645
646 print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
647 (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
648
649 for (gIter = rsc->priv->children; gIter != NULL; gIter = gIter->next) {
650 gboolean print_full = FALSE;
651 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
652 bool partially_active = child_rsc->priv->fns->active(child_rsc, false);
653
654 if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
655 continue;
656 }
657
658 if (child_rsc->priv->fns->is_filtered(child_rsc, only_rsc,
659 print_everything)) {
660 continue;
661 }
662
663 if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
664 print_full = TRUE;
665 }
666
668 // Print individual instance when unique (except stopped orphans)
669 if (partially_active
671 print_full = TRUE;
672 }
673
674 // Everything else in this block is for anonymous clones
675
676 } else if (pcmk_is_set(show_opts, pcmk_show_pending)
677 && (child_rsc->priv->pending_action != NULL)
678 && (strcmp(child_rsc->priv->pending_action,
679 "probe") != 0)) {
680 // Print individual instance when non-probe action is pending
681 print_full = TRUE;
682
683 } else if (partially_active == FALSE) {
684 // List stopped instances when requested (except orphans)
685 if (!pcmk_is_set(child_rsc->flags, pcmk__rsc_removed)
686 && !pcmk_is_set(show_opts, pcmk_show_clone_detail)
687 && pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
688 if (stopped == NULL) {
689 stopped = pcmk__strkey_table(free, free);
690 }
691 pcmk__insert_dup(stopped, child_rsc->id, "Stopped");
692 }
693
694 } else if (is_set_recursive(child_rsc, pcmk__rsc_removed, TRUE)
695 || !is_set_recursive(child_rsc, pcmk__rsc_managed, FALSE)
696 || is_set_recursive(child_rsc, pcmk__rsc_failed, TRUE)) {
697
698 // Print individual instance when active orphaned/unmanaged/failed
699 print_full = TRUE;
700
701 } else if (child_rsc->priv->fns->active(child_rsc, true)) {
702 // Instance of fully active anonymous clone
703
704 pcmk_node_t *location = NULL;
705
706 location = child_rsc->priv->fns->location(child_rsc, NULL,
708 if (location) {
709 // Instance is active on a single node
710
711 enum rsc_role_e a_role;
712
713 a_role = child_rsc->priv->fns->state(child_rsc, TRUE);
714
715 if (location->details->online == FALSE && location->details->unclean) {
716 print_full = TRUE;
717
718 } else if (a_role > pcmk_role_unpromoted) {
719 promoted_list = g_list_append(promoted_list, location);
720
721 } else {
722 started_list = g_list_append(started_list, location);
723 }
724
725 } else {
726 /* uncolocated group - bleh */
727 print_full = TRUE;
728 }
729
730 } else {
731 // Instance of partially active anonymous clone
732 print_full = TRUE;
733 }
734
735 if (print_full) {
736 GList *all = NULL;
737
738 clone_header(out, &rc, rsc, clone_data, desc);
739
740 /* Print every resource that's a child of this clone. */
741 all = g_list_prepend(all, (gpointer) "*");
742 out->message(out, (const char *) child_rsc->priv->xml->name,
743 show_opts, child_rsc, only_node, all);
744 g_list_free(all);
745 }
746 }
747
748 if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
750 return pcmk_rc_ok;
751 }
752
753 /* Promoted */
754 promoted_list = g_list_sort(promoted_list, pe__cmp_node_name);
755 for (gIter = promoted_list; gIter; gIter = gIter->next) {
756 pcmk_node_t *host = gIter->data;
757
758 if (!pcmk__str_in_list(host->priv->name, only_node,
760 continue;
761 }
762
763 pcmk__add_word(&list_text, 1024, host->priv->name);
764 active_instances++;
765 }
766 g_list_free(promoted_list);
767
768 if ((list_text != NULL) && (list_text->len > 0)) {
769 clone_header(out, &rc, rsc, clone_data, desc);
770
771 out->list_item(out, NULL, PCMK_ROLE_PROMOTED ": [ %s ]",
772 (const char *) list_text->str);
773 g_string_truncate(list_text, 0);
774 }
775
776 /* Started/Unpromoted */
777 started_list = g_list_sort(started_list, pe__cmp_node_name);
778 for (gIter = started_list; gIter; gIter = gIter->next) {
779 pcmk_node_t *host = gIter->data;
780
781 if (!pcmk__str_in_list(host->priv->name, only_node,
783 continue;
784 }
785
786 pcmk__add_word(&list_text, 1024, host->priv->name);
787 active_instances++;
788 }
789 g_list_free(started_list);
790
791 if ((list_text != NULL) && (list_text->len > 0)) {
792 clone_header(out, &rc, rsc, clone_data, desc);
793
795 enum rsc_role_e role = configured_role(rsc);
796
797 if (role == pcmk_role_unpromoted) {
798 out->list_item(out, NULL,
800 " (" PCMK_META_TARGET_ROLE "): [ %s ]",
801 (const char *) list_text->str);
802 } else {
803 out->list_item(out, NULL, PCMK_ROLE_UNPROMOTED ": [ %s ]",
804 (const char *) list_text->str);
805 }
806
807 } else {
808 out->list_item(out, NULL, "Started: [ %s ]",
809 (const char *) list_text->str);
810 }
811 }
812
813 if (list_text != NULL) {
814 g_string_free(list_text, TRUE);
815 }
816
817 if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
819 && (clone_data->clone_max > active_instances)) {
820
821 GList *nIter;
822 GList *list = g_hash_table_get_values(rsc->priv->allowed_nodes);
823
824 /* Custom stopped table for non-unique clones */
825 if (stopped != NULL) {
826 g_hash_table_destroy(stopped);
827 stopped = NULL;
828 }
829
830 if (list == NULL) {
831 /* Clusters with PCMK_OPT_SYMMETRIC_CLUSTER=false haven't
832 * calculated allowed nodes yet. If we've not probed for them
833 * yet, the Stopped list will be empty.
834 */
835 list = g_hash_table_get_values(rsc->priv->probed_nodes);
836 }
837
838 list = g_list_sort(list, pe__cmp_node_name);
839 for (nIter = list; nIter != NULL; nIter = nIter->next) {
840 pcmk_node_t *node = (pcmk_node_t *) nIter->data;
841
843 node->priv->name) == NULL)
844 && pcmk__str_in_list(node->priv->name, only_node,
846
847 xmlNode *probe_op = NULL;
848 const char *state = "Stopped";
849
850 if (configured_role(rsc) == pcmk_role_stopped) {
851 state = "Stopped (disabled)";
852 }
853
854 if (stopped == NULL) {
855 stopped = pcmk__strkey_table(free, free);
856 }
857
858 probe_op = pe__failed_probe_for_rsc(rsc,
859 node->priv->name);
860 if (probe_op != NULL) {
861 int rc;
862
865 &rc, 0);
866 g_hash_table_insert(stopped, strdup(node->priv->name),
867 crm_strdup_printf("Stopped (%s)",
868 crm_exit_str(rc)));
869 } else {
870 pcmk__insert_dup(stopped, node->priv->name, state);
871 }
872 }
873 }
874 g_list_free(list);
875 }
876
877 if (stopped != NULL) {
878 GList *list = sorted_hash_table_values(stopped);
879
880 clone_header(out, &rc, rsc, clone_data, desc);
881
882 for (GList *status_iter = list; status_iter != NULL; status_iter = status_iter->next) {
883 const char *status = status_iter->data;
884 GList *nodes = nodes_with_status(stopped, status);
885 GString *nodes_str = node_list_to_str(nodes);
886
887 if (nodes_str != NULL) {
888 if (nodes_str->len > 0) {
889 out->list_item(out, NULL, "%s: [ %s ]", status,
890 (const char *) nodes_str->str);
891 }
892 g_string_free(nodes_str, TRUE);
893 }
894
895 g_list_free(nodes);
896 }
897
898 g_list_free(list);
899 g_hash_table_destroy(stopped);
900
901 /* If there are no instances of this clone (perhaps because there are no
902 * nodes configured), simply output the clone header by itself. This can
903 * come up in PCS testing.
904 */
905 } else if (active_instances == 0) {
906 clone_header(out, &rc, rsc, clone_data, desc);
908 return rc;
909 }
910 }
911
913 return rc;
914}
915
916void
918{
919 clone_variant_data_t *clone_data = NULL;
920
921 get_clone_variant_data(clone_data, rsc);
922
923 pcmk__rsc_trace(rsc, "Freeing %s", rsc->id);
924
925 for (GList *gIter = rsc->priv->children;
926 gIter != NULL; gIter = gIter->next) {
927
928 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
929
930 pcmk__assert(child_rsc != NULL);
931 pcmk__rsc_trace(child_rsc, "Freeing child %s", child_rsc->id);
932 pcmk__xml_free(child_rsc->priv->xml);
933 child_rsc->priv->xml = NULL;
934 /* There could be a saved unexpanded xml */
935 pcmk__xml_free(child_rsc->priv->orig_xml);
936 child_rsc->priv->orig_xml = NULL;
937 pcmk__free_resource(child_rsc);
938 }
939
940 g_list_free(rsc->priv->children);
941
942 if (clone_data) {
943 pcmk__assert((clone_data->demote_notify == NULL)
944 && (clone_data->stop_notify == NULL)
945 && (clone_data->start_notify == NULL)
946 && (clone_data->promote_notify == NULL));
947 }
948
949 common_free(rsc);
950}
951
952enum rsc_role_e
953clone_resource_state(const pcmk_resource_t *rsc, bool current)
954{
955 enum rsc_role_e clone_role = pcmk_role_unknown;
956
957 for (GList *gIter = rsc->priv->children;
958 gIter != NULL; gIter = gIter->next) {
959
960 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
961 enum rsc_role_e a_role = child_rsc->priv->fns->state(child_rsc,
962 current);
963
964 if (a_role > clone_role) {
965 clone_role = a_role;
966 }
967 }
968
969 pcmk__rsc_trace(rsc, "%s role: %s", rsc->id, pcmk_role_text(clone_role));
970 return clone_role;
971}
972
980bool
983{
984 if (pcmk__is_clone(rsc)) {
985 clone_variant_data_t *clone_data = rsc->priv->variant_opaque;
986
987 if (clone_data->clone_max == g_list_length(scheduler->nodes)) {
988 return TRUE;
989 }
990 }
991 return FALSE;
992}
993
994bool
995pe__clone_is_filtered(const pcmk_resource_t *rsc, const GList *only_rsc,
996 bool check_parent)
997{
998 bool passes = FALSE;
999 clone_variant_data_t *clone_data = NULL;
1000
1002 passes = true;
1003 } else {
1004 get_clone_variant_data(clone_data, rsc);
1005 passes = pcmk__str_in_list(pcmk__xe_id(clone_data->xml_obj_child),
1006 only_rsc, pcmk__str_star_matches);
1007
1008 if (!passes) {
1009 for (const GList *iter = rsc->priv->children;
1010 iter != NULL; iter = iter->next) {
1011
1012 const pcmk_resource_t *child_rsc = NULL;
1013
1014 child_rsc = (const pcmk_resource_t *) iter->data;
1015 if (!child_rsc->priv->fns->is_filtered(child_rsc, only_rsc,
1016 false)) {
1017 passes = true;
1018 break;
1019 }
1020 }
1021 }
1022 }
1023 return !passes;
1024}
1025
1026const char *
1028{
1029 clone_variant_data_t *clone_data = NULL;
1030 get_clone_variant_data(clone_data, rsc);
1031 return pcmk__xe_id(clone_data->xml_obj_child);
1032}
1033
1042bool
1044{
1045 clone_variant_data_t *clone_data = NULL;
1046
1047 get_clone_variant_data(clone_data, clone);
1048 return pcmk_is_set(clone_data->flags, pcmk__clone_ordered);
1049}
1050
1061int
1063{
1064 clone_variant_data_t *clone_data = NULL;
1065
1066 get_clone_variant_data(clone_data, clone);
1067 if (pcmk_is_set(clone_data->flags, flag)) {
1068 return pcmk_rc_already;
1069 }
1070 clone_data->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,
1071 "Clone", clone->id,
1072 clone_data->flags, flag, "flag");
1073 return pcmk_rc_ok;
1074}
1075
1085bool
1087{
1088 clone_variant_data_t *clone_data = NULL;
1089
1090 get_clone_variant_data(clone_data, clone);
1091 pcmk__assert(clone_data != NULL);
1092
1093 return pcmk_all_flags_set(clone_data->flags, flags);
1094}
1095
1104void
1106 bool any_demoting)
1107{
1108 pcmk_action_t *action = NULL;
1109 pcmk_action_t *action_complete = NULL;
1110 clone_variant_data_t *clone_data = NULL;
1111
1112 get_clone_variant_data(clone_data, clone);
1113
1114 // Create a "promote" action for the clone itself
1116 !any_promoting, true);
1117
1118 // Create a "promoted" action for when all promotions are done
1119 action_complete = pe__new_rsc_pseudo_action(clone, PCMK_ACTION_PROMOTED,
1120 !any_promoting, true);
1121 action_complete->priority = PCMK_SCORE_INFINITY;
1122
1123 // Create notification pseudo-actions for promotion
1124 if (clone_data->promote_notify == NULL) {
1125 clone_data->promote_notify = pe__action_notif_pseudo_ops(clone,
1127 action,
1128 action_complete);
1129 }
1130
1131 // Create a "demote" action for the clone itself
1133 !any_demoting, true);
1134
1135 // Create a "demoted" action for when all demotions are done
1136 action_complete = pe__new_rsc_pseudo_action(clone, PCMK_ACTION_DEMOTED,
1137 !any_demoting, true);
1138 action_complete->priority = PCMK_SCORE_INFINITY;
1139
1140 // Create notification pseudo-actions for demotion
1141 if (clone_data->demote_notify == NULL) {
1142 clone_data->demote_notify = pe__action_notif_pseudo_ops(clone,
1144 action,
1145 action_complete);
1146
1147 if (clone_data->promote_notify != NULL) {
1148 order_actions(clone_data->stop_notify->post_done,
1149 clone_data->promote_notify->pre, pcmk__ar_ordered);
1150 order_actions(clone_data->start_notify->post_done,
1151 clone_data->promote_notify->pre, pcmk__ar_ordered);
1152 order_actions(clone_data->demote_notify->post_done,
1153 clone_data->promote_notify->pre, pcmk__ar_ordered);
1154 order_actions(clone_data->demote_notify->post_done,
1155 clone_data->start_notify->pre, pcmk__ar_ordered);
1156 order_actions(clone_data->demote_notify->post_done,
1157 clone_data->stop_notify->pre, pcmk__ar_ordered);
1158 }
1159 }
1160}
1161
1168void
1170{
1171 clone_variant_data_t *clone_data = NULL;
1172
1173 get_clone_variant_data(clone_data, clone);
1174
1175 pe__create_action_notifications(clone, clone_data->start_notify);
1176 pe__create_action_notifications(clone, clone_data->stop_notify);
1177 pe__create_action_notifications(clone, clone_data->promote_notify);
1178 pe__create_action_notifications(clone, clone_data->demote_notify);
1179}
1180
1187void
1189{
1190 clone_variant_data_t *clone_data = NULL;
1191
1192 get_clone_variant_data(clone_data, clone);
1193
1194 pe__free_action_notification_data(clone_data->demote_notify);
1195 clone_data->demote_notify = NULL;
1196
1197 pe__free_action_notification_data(clone_data->stop_notify);
1198 clone_data->stop_notify = NULL;
1199
1200 pe__free_action_notification_data(clone_data->start_notify);
1201 clone_data->start_notify = NULL;
1202
1203 pe__free_action_notification_data(clone_data->promote_notify);
1204 clone_data->promote_notify = NULL;
1205}
1206
1217void
1219 pcmk_action_t *start, pcmk_action_t *started,
1220 pcmk_action_t *stop, pcmk_action_t *stopped)
1221{
1222 clone_variant_data_t *clone_data = NULL;
1223
1224 get_clone_variant_data(clone_data, clone);
1225
1226 if (clone_data->start_notify == NULL) {
1227 clone_data->start_notify = pe__action_notif_pseudo_ops(clone,
1229 start, started);
1230 }
1231
1232 if (clone_data->stop_notify == NULL) {
1233 clone_data->stop_notify = pe__action_notif_pseudo_ops(clone,
1235 stop, stopped);
1236 if ((clone_data->start_notify != NULL)
1237 && (clone_data->stop_notify != NULL)) {
1238 order_actions(clone_data->stop_notify->post_done,
1239 clone_data->start_notify->pre, pcmk__ar_ordered);
1240 }
1241 }
1242}
1243
1252unsigned int
1254{
1255 const clone_variant_data_t *clone_data = NULL;
1256
1257 get_clone_variant_data(clone_data, rsc);
1258 return clone_data->clone_node_max;
1259}
@ pcmk__ar_ordered
Actions are ordered (optionally, if no other flags are set)
#define PCMK_ACTION_PROMOTED
Definition actions.h:58
#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_DEMOTED
Definition actions.h:41
#define PCMK_ACTION_DEMOTE
Definition actions.h:40
bool clone_active(const pcmk_resource_t *rsc, bool all)
Definition clone.c:445
bool is_set_recursive(const pcmk_resource_t *rsc, long long flag, bool any)
Definition clone.c:500
void pe__create_promotable_pseudo_ops(pcmk_resource_t *clone, bool any_promoting, bool any_demoting)
Definition clone.c:1105
void pe__create_clone_notifications(pcmk_resource_t *clone)
Definition clone.c:1169
int pe__clone_promoted_node_max(const pcmk_resource_t *clone)
Definition clone.c:107
int pe__clone_max(const pcmk_resource_t *clone)
Definition clone.c:56
#define get_clone_variant_data(data, rsc)
Definition clone.c:42
pcmk_resource_t * pe__create_clone_child(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
Definition clone.c:222
bool pe__is_universal_clone(const pcmk_resource_t *rsc, const pcmk_scheduler_t *scheduler)
Definition clone.c:981
void clone_free(pcmk_resource_t *rsc)
Definition clone.c:917
bool clone_unpack(pcmk_resource_t *rsc)
Definition clone.c:323
void pe__create_clone_notif_pseudo_ops(pcmk_resource_t *clone, pcmk_action_t *start, pcmk_action_t *started, pcmk_action_t *stop, pcmk_action_t *stopped)
Definition clone.c:1218
struct clone_variant_data_s clone_variant_data_t
void pe__force_anon(const char *standard, pcmk_resource_t *rsc, const char *rid, pcmk_scheduler_t *scheduler)
Definition clone.c:205
bool pe__clone_flag_is_set(const pcmk_resource_t *clone, uint32_t flags)
Definition clone.c:1086
bool pe__clone_is_ordered(const pcmk_resource_t *clone)
Definition clone.c:1043
unsigned int pe__clone_max_per_node(const pcmk_resource_t *rsc)
Definition clone.c:1253
int pe__set_clone_flag(pcmk_resource_t *clone, enum pcmk__clone_flags flag)
Definition clone.c:1062
int pe__clone_node_max(const pcmk_resource_t *clone)
Definition clone.c:73
int pe__clone_promoted_max(const pcmk_resource_t *clone)
Definition clone.c:90
const char * pe__clone_child_id(const pcmk_resource_t *rsc)
Definition clone.c:1027
void pe__free_clone_notification_data(pcmk_resource_t *clone)
Definition clone.c:1188
bool pe__clone_is_filtered(const pcmk_resource_t *rsc, const GList *only_rsc, bool check_parent)
Definition clone.c:995
enum rsc_role_e clone_resource_state(const pcmk_resource_t *rsc, bool current)
Definition clone.c:953
pcmk__clone_flags
@ pcmk__clone_ordered
#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
int pe__unpack_resource(xmlNode *xml_obj, pcmk_resource_t **rsc, pcmk_resource_t *parent, pcmk_scheduler_t *scheduler)
Definition complex.c:686
pcmk__cpg_host_t host
Definition cpg.c:4
#define CRM_CHECK(expr, failure_action)
Definition logging.h:213
#define LOG_TRACE
Definition logging.h:38
#define pcmk__config_warn(fmt...)
#define pcmk__config_err(fmt...)
@ pcmk__wo_clone_master_max
@ pcmk__wo_clone_master_node_max
#define pcmk__warn_once(wo_flag, fmt...)
pcmk_scheduler_t * scheduler
pcmk_node_t * pcmk__find_node_in_list(const GList *nodes, const char *node_name)
Definition nodes.c:198
#define pcmk__insert_meta(obj, name, value)
#define PCMK_META_RESOURCE_STICKINESS
Definition options.h:112
#define PCMK_META_CLONE_NODE_MAX
Definition options.h:85
#define PCMK_META_PROMOTED_MAX
Definition options.h:103
#define PCMK_META_CLONE_MAX
Definition options.h:83
#define PCMK_META_ORDERED
Definition options.h:100
#define PCMK_META_TARGET_ROLE
Definition options.h:114
#define PCMK_META_GLOBALLY_UNIQUE
Definition options.h:90
#define PCMK_META_PROMOTED_NODE_MAX
Definition options.h:104
#define PCMK__META_PROMOTED_MAX_LEGACY
#define PCMK__META_CLONE
#define PCMK__META_PROMOTED_NODE_MAX_LEGACY
Control output from tools.
@ pcmk_show_pending
Definition output.h:65
@ pcmk_show_clone_detail
Definition output.h:59
@ pcmk_show_inactive_rscs
Definition output.h:63
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
Definition output_xml.c:566
#define PCMK__OUTPUT_LIST_HEADER(out_obj, cond, retcode, title...)
#define PCMK__OUTPUT_LIST_FOOTER(out_obj, retcode)
const char * action
Definition pcmk_fence.c:32
void pe__free_action_notification_data(notify_data_t *n_data)
Definition pe_notif.c:979
notify_data_t * pe__action_notif_pseudo_ops(pcmk_resource_t *rsc, const char *task, pcmk_action_t *action, pcmk_action_t *complete)
Definition pe_notif.c:440
void pe__create_action_notifications(pcmk_resource_t *rsc, notify_data_t *n_data)
Definition pe_notif.c:962
int pe__clone_xml(pcmk__output_t *out, va_list args)
const char * pe__resource_description(const pcmk_resource_t *rsc, uint32_t show_opts)
Definition pe_output.c:24
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 pe__set_resource_flags_recursive(pcmk_resource_t *rsc, uint64_t flags)
Definition utils.c:615
pcmk_action_t * pe__new_rsc_pseudo_action(pcmk_resource_t *rsc, const char *task, bool optional, bool runnable)
gboolean order_actions(pcmk_action_t *first, pcmk_action_t *then, uint32_t flags)
Definition utils.c:483
int pe__clone_default(pcmk__output_t *out, va_list args)
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition utils.c:182
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
bool pe__resource_is_disabled(const pcmk_resource_t *rsc)
Definition utils.c:728
bool pcmk__rsc_filtered_by_node(pcmk_resource_t *rsc, GList *only_node)
Definition utils.c:782
@ pcmk__rsc_managed
@ pcmk__rsc_maintenance
@ pcmk__rsc_unique
@ pcmk__rsc_removed
@ pcmk__rsc_promotable
@ pcmk__rsc_ignore_failure
@ pcmk__rsc_failed
void pcmk__free_resource(gpointer user_data)
Definition resources.c:25
@ pcmk__rsc_node_current
@ pcmk_rc_no_output
Definition results.h:128
@ pcmk_rc_ok
Definition results.h:159
@ pcmk_rc_already
Definition results.h:150
const char * crm_exit_str(crm_exit_t exit_code)
Definition results.c:757
#define pcmk__assert(expr)
#define PCMK_ROLE_PROMOTED
Definition roles.h:28
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_unknown
Resource role is unknown.
Definition roles.h:35
@ pcmk_role_unpromoted
Unpromoted.
Definition roles.h:38
@ pcmk_role_stopped
Stopped.
Definition roles.h:36
#define PCMK_ROLE_UNPROMOTED
Definition roles.h:27
#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.
const char * rsc_printable_id(const pcmk_resource_t *rsc)
Definition utils.c:581
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
gboolean crm_is_true(const char *s)
Definition strings.c:490
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition strings.c:703
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
@ pcmk__str_casei
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1053
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
Definition strings.c:796
pcmk_action_t * pre
pcmk_action_t * post_done
gboolean online
Definition nodes.h:50
gboolean unclean
Definition nodes.h:58
This structure contains everything that makes up a single output formatter.
pcmk_scheduler_t * scheduler
const pcmk__rsc_methods_t * fns
unsigned long long flags
Definition resources.h:69
pcmk__resource_private_t * priv
Definition resources.h:61
enum rsc_role_e(* state)(const pcmk_resource_t *rsc, bool current)
bool(* is_filtered)(const pcmk_resource_t *rsc, const GList *only_rsc, bool check_parent)
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
Wrappers for and extensions to libxml2.
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml_element.c:43
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition xml.c:832
void pcmk__xml_free(xmlNode *xml)
Definition xml.c:816
#define PCMK_XA_MULTI_STATE
Definition xml_names.h:329
#define PCMK_XA_DESCRIPTION
Definition xml_names.h:261
#define PCMK_XA_FAILED
Definition xml_names.h:283
#define PCMK_XE_GROUP
Definition xml_names.h:119
#define PCMK_XA_ID
Definition xml_names.h:301
#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_XE_CLONE
Definition xml_names.h:80
#define PCMK_XE_PRIMITIVE
Definition xml_names.h:164
#define PCMK_XA_UNIQUE
Definition xml_names.h:434
#define PCMK_XA_MANAGED
Definition xml_names.h:323
#define PCMK_XA_DISABLED
Definition xml_names.h:265
#define PCMK__XA_RC_CODE