pacemaker 2.1.8-2.1.8
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
clone.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2024 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 <stdint.h>
13
14#include <crm/pengine/rules.h>
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
23#ifdef PCMK__COMPAT_2_0
24#define PROMOTED_INSTANCES PCMK__ROLE_PROMOTED_LEGACY "s"
25#define UNPROMOTED_INSTANCES PCMK__ROLE_UNPROMOTED_LEGACY "s"
26#else
27#define PROMOTED_INSTANCES PCMK_ROLE_PROMOTED
28#define UNPROMOTED_INSTANCES PCMK_ROLE_UNPROMOTED
29#endif
30
31typedef struct clone_variant_data_s {
32 int clone_max;
33 int clone_node_max;
34
35 int promoted_max;
36 int promoted_node_max;
37
38 int total_clones;
39
40 uint32_t flags; // Group of enum pcmk__clone_flags
41
42 notify_data_t *stop_notify;
43 notify_data_t *start_notify;
44 notify_data_t *demote_notify;
45 notify_data_t *promote_notify;
46
47 xmlNode *xml_obj_child;
49
50#define get_clone_variant_data(data, rsc) \
51 CRM_ASSERT(pcmk__is_clone(rsc) && (rsc->variant_opaque != NULL)); \
52 data = (clone_variant_data_t *) rsc->variant_opaque;
53
62int
64{
65 const clone_variant_data_t *clone_data = NULL;
66
67 get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
68 return clone_data->clone_max;
69}
70
79int
81{
82 const clone_variant_data_t *clone_data = NULL;
83
84 get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
85 return clone_data->clone_node_max;
86}
87
96int
98{
99 clone_variant_data_t *clone_data = NULL;
100
101 get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
102 return clone_data->promoted_max;
103}
104
113int
115{
116 clone_variant_data_t *clone_data = NULL;
117
118 get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
119 return clone_data->promoted_node_max;
120}
121
122static GList *
123sorted_hash_table_values(GHashTable *table)
124{
125 GList *retval = NULL;
126 GHashTableIter iter;
127 gpointer key, value;
128
129 g_hash_table_iter_init(&iter, table);
130 while (g_hash_table_iter_next(&iter, &key, &value)) {
131 if (!g_list_find_custom(retval, value, (GCompareFunc) strcmp)) {
132 retval = g_list_prepend(retval, (char *) value);
133 }
134 }
135
136 retval = g_list_sort(retval, (GCompareFunc) strcmp);
137 return retval;
138}
139
140static GList *
141nodes_with_status(GHashTable *table, const char *status)
142{
143 GList *retval = NULL;
144 GHashTableIter iter;
145 gpointer key, value;
146
147 g_hash_table_iter_init(&iter, table);
148 while (g_hash_table_iter_next(&iter, &key, &value)) {
149 if (!strcmp((char *) value, status)) {
150 retval = g_list_prepend(retval, key);
151 }
152 }
153
154 retval = g_list_sort(retval, (GCompareFunc) pcmk__numeric_strcasecmp);
155 return retval;
156}
157
158static GString *
159node_list_to_str(const GList *list)
160{
161 GString *retval = NULL;
162
163 for (const GList *iter = list; iter != NULL; iter = iter->next) {
164 pcmk__add_word(&retval, 1024, (const char *) iter->data);
165 }
166
167 return retval;
168}
169
170static void
171clone_header(pcmk__output_t *out, int *rc, const pcmk_resource_t *rsc,
172 clone_variant_data_t *clone_data, const char *desc)
173{
174 GString *attrs = NULL;
175
177 pcmk__add_separated_word(&attrs, 64, "promotable", ", ");
178 }
179
180 if (pcmk_is_set(rsc->flags, pcmk_rsc_unique)) {
181 pcmk__add_separated_word(&attrs, 64, "unique", ", ");
182 }
183
184 if (pe__resource_is_disabled(rsc)) {
185 pcmk__add_separated_word(&attrs, 64, "disabled", ", ");
186 }
187
189 pcmk__add_separated_word(&attrs, 64, "maintenance", ", ");
190
191 } else if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
192 pcmk__add_separated_word(&attrs, 64, "unmanaged", ", ");
193 }
194
195 if (attrs != NULL) {
196 PCMK__OUTPUT_LIST_HEADER(out, FALSE, *rc, "Clone Set: %s [%s] (%s)%s%s%s",
197 rsc->id,
198 pcmk__xe_id(clone_data->xml_obj_child),
199 (const char *) attrs->str, desc ? " (" : "",
200 desc ? desc : "", desc ? ")" : "");
201 g_string_free(attrs, TRUE);
202 } else {
203 PCMK__OUTPUT_LIST_HEADER(out, FALSE, *rc, "Clone Set: %s [%s]%s%s%s",
204 rsc->id,
205 pcmk__xe_id(clone_data->xml_obj_child),
206 desc ? " (" : "", desc ? desc : "",
207 desc ? ")" : "");
208 }
209}
210
211void
212pe__force_anon(const char *standard, pcmk_resource_t *rsc, const char *rid,
214{
215 if (pcmk__is_clone(rsc)) {
216 clone_variant_data_t *clone_data = rsc->variant_opaque;
217
218 pcmk__config_warn("Ignoring " PCMK_META_GLOBALLY_UNIQUE " for %s "
219 "because %s resources such as %s can be used only as "
220 "anonymous clones", rsc->id, standard, rid);
221
222 clone_data->clone_node_max = 1;
223 clone_data->clone_max = QB_MIN(clone_data->clone_max,
224 g_list_length(scheduler->nodes));
225 }
226}
227
229find_clone_instance(const pcmk_resource_t *rsc, const char *sub_id)
230{
231 char *child_id = NULL;
232 pcmk_resource_t *child = NULL;
233 const char *child_base = NULL;
234 clone_variant_data_t *clone_data = NULL;
235
236 get_clone_variant_data(clone_data, rsc);
237
238 child_base = pcmk__xe_id(clone_data->xml_obj_child);
239 child_id = crm_strdup_printf("%s:%s", child_base, sub_id);
240 child = pe_find_resource(rsc->children, child_id);
241
242 free(child_id);
243 return child;
244}
245
248{
249 gboolean as_orphan = FALSE;
250 char *inc_num = NULL;
251 char *inc_max = NULL;
252 pcmk_resource_t *child_rsc = NULL;
253 xmlNode *child_copy = NULL;
254 clone_variant_data_t *clone_data = NULL;
255
256 get_clone_variant_data(clone_data, rsc);
257
258 CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE);
259
260 if (clone_data->total_clones >= clone_data->clone_max) {
261 // If we've already used all available instances, this is an orphan
262 as_orphan = TRUE;
263 }
264
265 // Allocate instance numbers in numerical order (starting at 0)
266 inc_num = pcmk__itoa(clone_data->total_clones);
267 inc_max = pcmk__itoa(clone_data->clone_max);
268
269 child_copy = pcmk__xml_copy(NULL, clone_data->xml_obj_child);
270
271 crm_xml_add(child_copy, PCMK__META_CLONE, inc_num);
272
273 if (pe__unpack_resource(child_copy, &child_rsc, rsc,
274 scheduler) != pcmk_rc_ok) {
275 goto bail;
276 }
277/* child_rsc->globally_unique = rsc->globally_unique; */
278
279 CRM_ASSERT(child_rsc);
280 clone_data->total_clones += 1;
281 pcmk__rsc_trace(child_rsc, "Setting clone attributes for: %s",
282 child_rsc->id);
283 rsc->children = g_list_append(rsc->children, child_rsc);
284 if (as_orphan) {
286 }
287
288 pcmk__insert_meta(child_rsc, PCMK_META_CLONE_MAX, inc_max);
289 pcmk__rsc_trace(rsc, "Added %s instance %s", rsc->id, child_rsc->id);
290
291 bail:
292 free(inc_num);
293 free(inc_max);
294
295 return child_rsc;
296}
297
311static int
312unpack_meta_int(const pcmk_resource_t *rsc, const char *meta_name,
313 const char *deprecated_name, int default_value)
314{
315 int integer = default_value;
316 const char *value = g_hash_table_lookup(rsc->meta, meta_name);
317
318 if ((value == NULL) && (deprecated_name != NULL)) {
319 value = g_hash_table_lookup(rsc->meta, deprecated_name);
320
321 if (value != NULL) {
322 if (pcmk__str_eq(deprecated_name, PCMK__META_PROMOTED_MAX_LEGACY,
325 "Support for the " PCMK__META_PROMOTED_MAX_LEGACY
326 " meta-attribute (such as in %s) is deprecated "
327 "and will be removed in a future release. Use the "
328 PCMK_META_PROMOTED_MAX " meta-attribute instead.",
329 rsc->id);
330 } else if (pcmk__str_eq(deprecated_name, PCMK__META_PROMOTED_NODE_MAX_LEGACY,
333 "Support for the " PCMK__META_PROMOTED_NODE_MAX_LEGACY
334 " meta-attribute (such as in %s) is deprecated "
335 "and will be removed in a future release. Use the "
336 PCMK_META_PROMOTED_NODE_MAX " meta-attribute instead.",
337 rsc->id);
338 }
339 }
340 }
341 if (value != NULL) {
342 pcmk__scan_min_int(value, &integer, 0);
343 }
344 return integer;
345}
346
347gboolean
349{
350 int lpc = 0;
351 xmlNode *a_child = NULL;
352 xmlNode *xml_obj = rsc->xml;
353 clone_variant_data_t *clone_data = NULL;
354
355 pcmk__rsc_trace(rsc, "Processing resource %s...", rsc->id);
356
357 clone_data = pcmk__assert_alloc(1, sizeof(clone_variant_data_t));
358 rsc->variant_opaque = clone_data;
359
361 // Use 1 as default but 0 for minimum and invalid
362 // @COMPAT PCMK__META_PROMOTED_MAX_LEGACY deprecated since 2.0.0
363 clone_data->promoted_max =
364 unpack_meta_int(rsc, PCMK_META_PROMOTED_MAX,
366
367 // Use 1 as default but 0 for minimum and invalid
368 // @COMPAT PCMK__META_PROMOTED_NODE_MAX_LEGACY deprecated since 2.0.0
369 clone_data->promoted_node_max =
370 unpack_meta_int(rsc, PCMK_META_PROMOTED_NODE_MAX,
372 }
373
374 // Use 1 as default but 0 for minimum and invalid
375 clone_data->clone_node_max = unpack_meta_int(rsc, PCMK_META_CLONE_NODE_MAX,
376 NULL, 1);
377
378 /* Use number of nodes (but always at least 1, which is handy for crm_verify
379 * for a CIB without nodes) as default, but 0 for minimum and invalid
380 */
381 clone_data->clone_max = unpack_meta_int(rsc, PCMK_META_CLONE_MAX, NULL,
382 QB_MAX(1, g_list_length(scheduler->nodes)));
383
384 if (crm_is_true(g_hash_table_lookup(rsc->meta, PCMK_META_ORDERED))) {
385 clone_data->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,
386 "Clone", rsc->id,
387 clone_data->flags,
389 "pcmk__clone_ordered");
390 }
391
393 && (clone_data->clone_node_max > 1)) {
394
395 pcmk__config_err("Ignoring " PCMK_META_CLONE_NODE_MAX " of %d for %s "
396 "because anonymous clones support only one instance "
397 "per node", clone_data->clone_node_max, rsc->id);
398 clone_data->clone_node_max = 1;
399 }
400
401 pcmk__rsc_trace(rsc, "Options for %s", rsc->id);
402 pcmk__rsc_trace(rsc, "\tClone max: %d", clone_data->clone_max);
403 pcmk__rsc_trace(rsc, "\tClone node max: %d", clone_data->clone_node_max);
404 pcmk__rsc_trace(rsc, "\tClone is unique: %s",
405 pcmk__flag_text(rsc->flags, pcmk_rsc_unique));
406 pcmk__rsc_trace(rsc, "\tClone is promotable: %s",
407 pcmk__flag_text(rsc->flags, pcmk_rsc_promotable));
408
409 // Clones may contain a single group or primitive
410 for (a_child = pcmk__xe_first_child(xml_obj, NULL, NULL, NULL);
411 a_child != NULL; a_child = pcmk__xe_next(a_child)) {
412
413 if (pcmk__str_any_of((const char *) a_child->name,
415 clone_data->xml_obj_child = a_child;
416 break;
417 }
418 }
419
420 if (clone_data->xml_obj_child == NULL) {
421 pcmk__config_err("%s has nothing to clone", rsc->id);
422 return FALSE;
423 }
424
425 /*
426 * Make clones ever so slightly sticky by default
427 *
428 * This helps ensure clone instances are not shuffled around the cluster
429 * for no benefit in situations when pre-allocation is not appropriate
430 */
431 if (g_hash_table_lookup(rsc->meta, PCMK_META_RESOURCE_STICKINESS) == NULL) {
433 }
434
435 /* This ensures that the PCMK_META_GLOBALLY_UNIQUE value always exists for
436 * children to inherit when being unpacked, as well as in resource agents'
437 * environment.
438 */
440 pcmk__flag_text(rsc->flags, pcmk_rsc_unique));
441
442 if (clone_data->clone_max <= 0) {
443 /* Create one child instance so that unpack_find_resource() will hook up
444 * any orphans up to the parent correctly.
445 */
446 if (pe__create_clone_child(rsc, scheduler) == NULL) {
447 return FALSE;
448 }
449
450 } else {
451 // Create a child instance for each available instance number
452 for (lpc = 0; lpc < clone_data->clone_max; lpc++) {
453 if (pe__create_clone_child(rsc, scheduler) == NULL) {
454 return FALSE;
455 }
456 }
457 }
458
459 pcmk__rsc_trace(rsc, "Added %d children to resource %s...",
460 clone_data->clone_max, rsc->id);
461 return TRUE;
462}
463
464gboolean
465clone_active(pcmk_resource_t * rsc, gboolean all)
466{
467 GList *gIter = rsc->children;
468
469 for (; gIter != NULL; gIter = gIter->next) {
470 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
471 gboolean child_active = child_rsc->fns->active(child_rsc, all);
472
473 if (all == FALSE && child_active) {
474 return TRUE;
475 } else if (all && child_active == FALSE) {
476 return FALSE;
477 }
478 }
479
480 if (all) {
481 return TRUE;
482 } else {
483 return FALSE;
484 }
485}
486
491static void
492short_print(const char *list, const char *prefix, const char *type,
493 const char *suffix, long options, void *print_data)
494{
495 if(suffix == NULL) {
496 suffix = "";
497 }
498
499 if (!pcmk__str_empty(list)) {
500 if (options & pe_print_html) {
501 status_print("<li>");
502 }
503 status_print("%s%s: [ %s ]%s", prefix, type, list, suffix);
504
505 if (options & pe_print_html) {
506 status_print("</li>\n");
507
508 } else if (options & pe_print_suppres_nl) {
509 /* nothing */
510 } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) {
511 status_print("\n");
512 }
513
514 }
515}
516
517static const char *
518configured_role_str(pcmk_resource_t * rsc)
519{
520 const char *target_role = g_hash_table_lookup(rsc->meta,
522
523 if ((target_role == NULL) && rsc->children && rsc->children->data) {
524 pcmk_resource_t *instance = rsc->children->data; // Any instance will do
525
526 target_role = g_hash_table_lookup(instance->meta,
528 }
529 return target_role;
530}
531
532static enum rsc_role_e
533configured_role(pcmk_resource_t *rsc)
534{
535 enum rsc_role_e role = pcmk_role_unknown;
536 const char *target_role = configured_role_str(rsc);
537
538 if (target_role != NULL) {
539 role = pcmk_parse_role(target_role);
540 if (role == pcmk_role_unknown) {
542 " for resource %s", rsc->id);
543 }
544 }
545 return role;
546}
547
552static void
553clone_print_xml(pcmk_resource_t *rsc, const char *pre_text, long options,
554 void *print_data)
555{
556 char *child_text = crm_strdup_printf("%s ", pre_text);
557 const char *target_role = configured_role_str(rsc);
558 GList *gIter = rsc->children;
559
560 status_print("%s<clone ", pre_text);
561 status_print(PCMK_XA_ID "=\"%s\" ", rsc->id);
562 status_print("multi_state=\"%s\" ",
563 pcmk__flag_text(rsc->flags, pcmk_rsc_promotable));
564 status_print("unique=\"%s\" ",
565 pcmk__flag_text(rsc->flags, pcmk_rsc_unique));
566 status_print("managed=\"%s\" ",
567 pcmk__flag_text(rsc->flags, pcmk_rsc_managed));
568 status_print("failed=\"%s\" ",
569 pcmk__flag_text(rsc->flags, pcmk_rsc_failed));
570 status_print("failure_ignored=\"%s\" ",
571 pcmk__flag_text(rsc->flags, pcmk_rsc_ignore_failure));
572 if (target_role) {
573 status_print("target_role=\"%s\" ", target_role);
574 }
575 status_print(">\n");
576
577 for (; gIter != NULL; gIter = gIter->next) {
578 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
579
580 child_rsc->fns->print(child_rsc, child_text, options, print_data);
581 }
582
583 status_print("%s</clone>\n", pre_text);
584 free(child_text);
585}
586
587bool
588is_set_recursive(const pcmk_resource_t *rsc, long long flag, bool any)
589{
590 GList *gIter;
591 bool all = !any;
592
593 if (pcmk_is_set(rsc->flags, flag)) {
594 if(any) {
595 return TRUE;
596 }
597 } else if(all) {
598 return FALSE;
599 }
600
601 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
602 if(is_set_recursive(gIter->data, flag, any)) {
603 if(any) {
604 return TRUE;
605 }
606
607 } else if(all) {
608 return FALSE;
609 }
610 }
611
612 if(all) {
613 return TRUE;
614 }
615 return FALSE;
616}
617
622void
623clone_print(pcmk_resource_t *rsc, const char *pre_text, long options,
624 void *print_data)
625{
626 GString *list_text = NULL;
627 char *child_text = NULL;
628 GString *stopped_list = NULL;
629
630 GList *promoted_list = NULL;
631 GList *started_list = NULL;
632 GList *gIter = rsc->children;
633
634 clone_variant_data_t *clone_data = NULL;
635 int active_instances = 0;
636
637 if (pre_text == NULL) {
638 pre_text = " ";
639 }
640
641 if (options & pe_print_xml) {
642 clone_print_xml(rsc, pre_text, options, print_data);
643 return;
644 }
645
646 get_clone_variant_data(clone_data, rsc);
647
648 child_text = crm_strdup_printf("%s ", pre_text);
649
650 status_print("%sClone Set: %s [%s]%s%s%s",
651 pcmk__s(pre_text, ""), rsc->id,
652 pcmk__xe_id(clone_data->xml_obj_child),
653 pcmk_is_set(rsc->flags, pcmk_rsc_promotable)? " (promotable)" : "",
654 pcmk_is_set(rsc->flags, pcmk_rsc_unique)? " (unique)" : "",
655 pcmk_is_set(rsc->flags, pcmk_rsc_managed)? "" : " (unmanaged)");
656
657 if (options & pe_print_html) {
658 status_print("\n<ul>\n");
659
660 } else if ((options & pe_print_log) == 0) {
661 status_print("\n");
662 }
663
664 for (; gIter != NULL; gIter = gIter->next) {
665 gboolean print_full = FALSE;
666 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
667 gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
668
669 if (options & pe_print_clone_details) {
670 print_full = TRUE;
671 }
672
673 if (pcmk_is_set(rsc->flags, pcmk_rsc_unique)) {
674 // Print individual instance when unique (except stopped orphans)
675 if (partially_active
677 print_full = TRUE;
678 }
679
680 // Everything else in this block is for anonymous clones
681
682 } else if (pcmk_is_set(options, pe_print_pending)
683 && (child_rsc->pending_task != NULL)
684 && strcmp(child_rsc->pending_task, "probe")) {
685 // Print individual instance when non-probe action is pending
686 print_full = TRUE;
687
688 } else if (partially_active == FALSE) {
689 // List stopped instances when requested (except orphans)
690 if (!pcmk_is_set(child_rsc->flags, pcmk_rsc_removed)
691 && !pcmk_is_set(options, pe_print_clone_active)) {
692
693 pcmk__add_word(&stopped_list, 1024, child_rsc->id);
694 }
695
696 } else if (is_set_recursive(child_rsc, pcmk_rsc_removed, TRUE)
697 || !is_set_recursive(child_rsc, pcmk_rsc_managed, FALSE)
698 || is_set_recursive(child_rsc, pcmk_rsc_failed, TRUE)) {
699
700 // Print individual instance when active orphaned/unmanaged/failed
701 print_full = TRUE;
702
703 } else if (child_rsc->fns->active(child_rsc, TRUE)) {
704 // Instance of fully active anonymous clone
705
706 pcmk_node_t *location = NULL;
707
708 location = child_rsc->fns->location(child_rsc, NULL, TRUE);
709 if (location) {
710 // Instance is active on a single node
711
712 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
713
714 if (location->details->online == FALSE && location->details->unclean) {
715 print_full = TRUE;
716
717 } else if (a_role > pcmk_role_unpromoted) {
718 promoted_list = g_list_append(promoted_list, location);
719
720 } else {
721 started_list = g_list_append(started_list, location);
722 }
723
724 } else {
725 /* uncolocated group - bleh */
726 print_full = TRUE;
727 }
728
729 } else {
730 // Instance of partially active anonymous clone
731 print_full = TRUE;
732 }
733
734 if (print_full) {
735 if (options & pe_print_html) {
736 status_print("<li>\n");
737 }
738 child_rsc->fns->print(child_rsc, child_text, options, print_data);
739 if (options & pe_print_html) {
740 status_print("</li>\n");
741 }
742 }
743 }
744
745 /* Promoted */
746 promoted_list = g_list_sort(promoted_list, pe__cmp_node_name);
747 for (gIter = promoted_list; gIter; gIter = gIter->next) {
748 pcmk_node_t *host = gIter->data;
749
750 pcmk__add_word(&list_text, 1024, host->details->uname);
751 active_instances++;
752 }
753
754 if (list_text != NULL) {
755 short_print((const char *) list_text->str, child_text,
756 PROMOTED_INSTANCES, NULL, options, print_data);
757 g_string_truncate(list_text, 0);
758 }
759 g_list_free(promoted_list);
760
761 /* Started/Unpromoted */
762 started_list = g_list_sort(started_list, pe__cmp_node_name);
763 for (gIter = started_list; gIter; gIter = gIter->next) {
764 pcmk_node_t *host = gIter->data;
765
766 pcmk__add_word(&list_text, 1024, host->details->uname);
767 active_instances++;
768 }
769
770 if (list_text != NULL) {
772 enum rsc_role_e role = configured_role(rsc);
773
774 if (role == pcmk_role_unpromoted) {
775 short_print((const char *) list_text->str, child_text,
777 NULL, options, print_data);
778 } else {
779 short_print((const char *) list_text->str, child_text,
780 UNPROMOTED_INSTANCES, NULL, options, print_data);
781 }
782
783 } else {
784 short_print((const char *) list_text->str, child_text, "Started",
785 NULL, options, print_data);
786 }
787 }
788
789 g_list_free(started_list);
790
791 if (!pcmk_is_set(options, pe_print_clone_active)) {
792 const char *state = "Stopped";
793 enum rsc_role_e role = configured_role(rsc);
794
795 if (role == pcmk_role_stopped) {
796 state = "Stopped (disabled)";
797 }
798
800 && (clone_data->clone_max > active_instances)) {
801
802 GList *nIter;
803 GList *list = g_hash_table_get_values(rsc->allowed_nodes);
804
805 /* Custom stopped list for non-unique clones */
806 if (stopped_list != NULL) {
807 g_string_truncate(stopped_list, 0);
808 }
809
810 if (list == NULL) {
811 /* Clusters with PCMK_OPT_SYMMETRIC_CLUSTER=false haven't
812 * calculated allowed_nodes yet. If we've not probed for them
813 * yet, the Stopped list will be empty.
814 */
815 list = g_hash_table_get_values(rsc->known_on);
816 }
817
818 list = g_list_sort(list, pe__cmp_node_name);
819 for (nIter = list; nIter != NULL; nIter = nIter->next) {
820 pcmk_node_t *node = (pcmk_node_t *) nIter->data;
821
823 node->details->uname) == NULL) {
824 pcmk__add_word(&stopped_list, 1024, node->details->uname);
825 }
826 }
827 g_list_free(list);
828 }
829
830 if (stopped_list != NULL) {
831 short_print((const char *) stopped_list->str, child_text, state,
832 NULL, options, print_data);
833 }
834 }
835
836 if (options & pe_print_html) {
837 status_print("</ul>\n");
838 }
839
840 if (list_text != NULL) {
841 g_string_free(list_text, TRUE);
842 }
843
844 if (stopped_list != NULL) {
845 g_string_free(stopped_list, TRUE);
846 }
847 free(child_text);
848}
849
850PCMK__OUTPUT_ARGS("clone", "uint32_t", "pcmk_resource_t *", "GList *",
851 "GList *")
852int
853pe__clone_xml(pcmk__output_t *out, va_list args)
854{
855 uint32_t show_opts = va_arg(args, uint32_t);
856 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
857 GList *only_node = va_arg(args, GList *);
858 GList *only_rsc = va_arg(args, GList *);
859
860 GList *gIter = rsc->children;
861 GList *all = NULL;
862 int rc = pcmk_rc_no_output;
863 gboolean printed_header = FALSE;
864 gboolean print_everything = TRUE;
865
866 if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
867 return rc;
868 }
869
870 print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
871 (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
872
873 all = g_list_prepend(all, (gpointer) "*");
874
875 for (; gIter != NULL; gIter = gIter->next) {
876 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
877
878 if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
879 continue;
880 }
881
882 if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
883 continue;
884 }
885
886 if (!printed_header) {
887 const char *multi_state = pcmk__flag_text(rsc->flags,
889 const char *unique = pcmk__flag_text(rsc->flags, pcmk_rsc_unique);
890 const char *maintenance = pcmk__flag_text(rsc->flags,
892 const char *managed = pcmk__flag_text(rsc->flags, pcmk_rsc_managed);
893 const char *disabled = pcmk__btoa(pe__resource_is_disabled(rsc));
894 const char *failed = pcmk__flag_text(rsc->flags, pcmk_rsc_failed);
895 const char *ignored = pcmk__flag_text(rsc->flags,
897 const char *target_role = configured_role_str(rsc);
898 const char *desc = pe__resource_description(rsc, show_opts);
899
900 printed_header = TRUE;
901
903 PCMK_XA_ID, rsc->id,
904 PCMK_XA_MULTI_STATE, multi_state,
905 PCMK_XA_UNIQUE, unique,
906 PCMK_XA_MAINTENANCE, maintenance,
907 PCMK_XA_MANAGED, managed,
908 PCMK_XA_DISABLED, disabled,
909 PCMK_XA_FAILED, failed,
911 PCMK_XA_TARGET_ROLE, target_role,
913 NULL);
914 CRM_ASSERT(rc == pcmk_rc_ok);
915 }
916
917 out->message(out, (const char *) child_rsc->xml->name, show_opts,
918 child_rsc, only_node, all);
919 }
920
921 if (printed_header) {
923 }
924
925 g_list_free(all);
926 return rc;
927}
928
929PCMK__OUTPUT_ARGS("clone", "uint32_t", "pcmk_resource_t *", "GList *",
930 "GList *")
931int
932pe__clone_default(pcmk__output_t *out, va_list args)
933{
934 uint32_t show_opts = va_arg(args, uint32_t);
935 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
936 GList *only_node = va_arg(args, GList *);
937 GList *only_rsc = va_arg(args, GList *);
938
939 GHashTable *stopped = NULL;
940
941 GString *list_text = NULL;
942
943 GList *promoted_list = NULL;
944 GList *started_list = NULL;
945 GList *gIter = rsc->children;
946
947 const char *desc = NULL;
948
949 clone_variant_data_t *clone_data = NULL;
950 int active_instances = 0;
951 int rc = pcmk_rc_no_output;
952 gboolean print_everything = TRUE;
953
954 desc = pe__resource_description(rsc, show_opts);
955
956 get_clone_variant_data(clone_data, rsc);
957
958 if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
959 return rc;
960 }
961
962 print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
963 (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
964
965 for (; gIter != NULL; gIter = gIter->next) {
966 gboolean print_full = FALSE;
967 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
968 gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
969
970 if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
971 continue;
972 }
973
974 if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
975 continue;
976 }
977
978 if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
979 print_full = TRUE;
980 }
981
982 if (pcmk_is_set(rsc->flags, pcmk_rsc_unique)) {
983 // Print individual instance when unique (except stopped orphans)
984 if (partially_active
986 print_full = TRUE;
987 }
988
989 // Everything else in this block is for anonymous clones
990
991 } else if (pcmk_is_set(show_opts, pcmk_show_pending)
992 && (child_rsc->pending_task != NULL)
993 && strcmp(child_rsc->pending_task, "probe")) {
994 // Print individual instance when non-probe action is pending
995 print_full = TRUE;
996
997 } else if (partially_active == FALSE) {
998 // List stopped instances when requested (except orphans)
999 if (!pcmk_is_set(child_rsc->flags, pcmk_rsc_removed)
1000 && !pcmk_is_set(show_opts, pcmk_show_clone_detail)
1001 && pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
1002 if (stopped == NULL) {
1003 stopped = pcmk__strkey_table(free, free);
1004 }
1005 pcmk__insert_dup(stopped, child_rsc->id, "Stopped");
1006 }
1007
1008 } else if (is_set_recursive(child_rsc, pcmk_rsc_removed, TRUE)
1009 || !is_set_recursive(child_rsc, pcmk_rsc_managed, FALSE)
1010 || is_set_recursive(child_rsc, pcmk_rsc_failed, TRUE)) {
1011
1012 // Print individual instance when active orphaned/unmanaged/failed
1013 print_full = TRUE;
1014
1015 } else if (child_rsc->fns->active(child_rsc, TRUE)) {
1016 // Instance of fully active anonymous clone
1017
1018 pcmk_node_t *location = NULL;
1019
1020 location = child_rsc->fns->location(child_rsc, NULL, TRUE);
1021 if (location) {
1022 // Instance is active on a single node
1023
1024 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
1025
1026 if (location->details->online == FALSE && location->details->unclean) {
1027 print_full = TRUE;
1028
1029 } else if (a_role > pcmk_role_unpromoted) {
1030 promoted_list = g_list_append(promoted_list, location);
1031
1032 } else {
1033 started_list = g_list_append(started_list, location);
1034 }
1035
1036 } else {
1037 /* uncolocated group - bleh */
1038 print_full = TRUE;
1039 }
1040
1041 } else {
1042 // Instance of partially active anonymous clone
1043 print_full = TRUE;
1044 }
1045
1046 if (print_full) {
1047 GList *all = NULL;
1048
1049 clone_header(out, &rc, rsc, clone_data, desc);
1050
1051 /* Print every resource that's a child of this clone. */
1052 all = g_list_prepend(all, (gpointer) "*");
1053 out->message(out, (const char *) child_rsc->xml->name, show_opts,
1054 child_rsc, only_node, all);
1055 g_list_free(all);
1056 }
1057 }
1058
1059 if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
1060 PCMK__OUTPUT_LIST_FOOTER(out, rc);
1061 return pcmk_rc_ok;
1062 }
1063
1064 /* Promoted */
1065 promoted_list = g_list_sort(promoted_list, pe__cmp_node_name);
1066 for (gIter = promoted_list; gIter; gIter = gIter->next) {
1067 pcmk_node_t *host = gIter->data;
1068
1069 if (!pcmk__str_in_list(host->details->uname, only_node,
1071 continue;
1072 }
1073
1074 pcmk__add_word(&list_text, 1024, host->details->uname);
1075 active_instances++;
1076 }
1077 g_list_free(promoted_list);
1078
1079 if ((list_text != NULL) && (list_text->len > 0)) {
1080 clone_header(out, &rc, rsc, clone_data, desc);
1081
1082 out->list_item(out, NULL, PROMOTED_INSTANCES ": [ %s ]",
1083 (const char *) list_text->str);
1084 g_string_truncate(list_text, 0);
1085 }
1086
1087 /* Started/Unpromoted */
1088 started_list = g_list_sort(started_list, pe__cmp_node_name);
1089 for (gIter = started_list; gIter; gIter = gIter->next) {
1090 pcmk_node_t *host = gIter->data;
1091
1092 if (!pcmk__str_in_list(host->details->uname, only_node,
1094 continue;
1095 }
1096
1097 pcmk__add_word(&list_text, 1024, host->details->uname);
1098 active_instances++;
1099 }
1100 g_list_free(started_list);
1101
1102 if ((list_text != NULL) && (list_text->len > 0)) {
1103 clone_header(out, &rc, rsc, clone_data, desc);
1104
1106 enum rsc_role_e role = configured_role(rsc);
1107
1108 if (role == pcmk_role_unpromoted) {
1109 out->list_item(out, NULL,
1111 " (" PCMK_META_TARGET_ROLE "): [ %s ]",
1112 (const char *) list_text->str);
1113 } else {
1114 out->list_item(out, NULL, UNPROMOTED_INSTANCES ": [ %s ]",
1115 (const char *) list_text->str);
1116 }
1117
1118 } else {
1119 out->list_item(out, NULL, "Started: [ %s ]",
1120 (const char *) list_text->str);
1121 }
1122 }
1123
1124 if (list_text != NULL) {
1125 g_string_free(list_text, TRUE);
1126 }
1127
1128 if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
1130 && (clone_data->clone_max > active_instances)) {
1131
1132 GList *nIter;
1133 GList *list = g_hash_table_get_values(rsc->allowed_nodes);
1134
1135 /* Custom stopped table for non-unique clones */
1136 if (stopped != NULL) {
1137 g_hash_table_destroy(stopped);
1138 stopped = NULL;
1139 }
1140
1141 if (list == NULL) {
1142 /* Clusters with PCMK_OPT_SYMMETRIC_CLUSTER=false haven't
1143 * calculated allowed_nodes yet. If we've not probed for them
1144 * yet, the Stopped list will be empty.
1145 */
1146 list = g_hash_table_get_values(rsc->known_on);
1147 }
1148
1149 list = g_list_sort(list, pe__cmp_node_name);
1150 for (nIter = list; nIter != NULL; nIter = nIter->next) {
1151 pcmk_node_t *node = (pcmk_node_t *) nIter->data;
1152
1154 node->details->uname) == NULL)
1155 && pcmk__str_in_list(node->details->uname, only_node,
1157 xmlNode *probe_op = pe__failed_probe_for_rsc(rsc, node->details->uname);
1158 const char *state = "Stopped";
1159
1160 if (configured_role(rsc) == pcmk_role_stopped) {
1161 state = "Stopped (disabled)";
1162 }
1163
1164 if (stopped == NULL) {
1165 stopped = pcmk__strkey_table(free, free);
1166 }
1167 if (probe_op != NULL) {
1168 int rc;
1169
1172 &rc, 0);
1173 g_hash_table_insert(stopped, strdup(node->details->uname),
1174 crm_strdup_printf("Stopped (%s)", services_ocf_exitcode_str(rc)));
1175 } else {
1176 pcmk__insert_dup(stopped, node->details->uname, state);
1177 }
1178 }
1179 }
1180 g_list_free(list);
1181 }
1182
1183 if (stopped != NULL) {
1184 GList *list = sorted_hash_table_values(stopped);
1185
1186 clone_header(out, &rc, rsc, clone_data, desc);
1187
1188 for (GList *status_iter = list; status_iter != NULL; status_iter = status_iter->next) {
1189 const char *status = status_iter->data;
1190 GList *nodes = nodes_with_status(stopped, status);
1191 GString *nodes_str = node_list_to_str(nodes);
1192
1193 if (nodes_str != NULL) {
1194 if (nodes_str->len > 0) {
1195 out->list_item(out, NULL, "%s: [ %s ]", status,
1196 (const char *) nodes_str->str);
1197 }
1198 g_string_free(nodes_str, TRUE);
1199 }
1200
1201 g_list_free(nodes);
1202 }
1203
1204 g_list_free(list);
1205 g_hash_table_destroy(stopped);
1206
1207 /* If there are no instances of this clone (perhaps because there are no
1208 * nodes configured), simply output the clone header by itself. This can
1209 * come up in PCS testing.
1210 */
1211 } else if (active_instances == 0) {
1212 clone_header(out, &rc, rsc, clone_data, desc);
1213 PCMK__OUTPUT_LIST_FOOTER(out, rc);
1214 return rc;
1215 }
1216 }
1217
1218 PCMK__OUTPUT_LIST_FOOTER(out, rc);
1219 return rc;
1220}
1221
1222void
1224{
1225 clone_variant_data_t *clone_data = NULL;
1226
1227 get_clone_variant_data(clone_data, rsc);
1228
1229 pcmk__rsc_trace(rsc, "Freeing %s", rsc->id);
1230
1231 for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1232 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
1233
1234 CRM_ASSERT(child_rsc);
1235 pcmk__rsc_trace(child_rsc, "Freeing child %s", child_rsc->id);
1236 free_xml(child_rsc->xml);
1237 child_rsc->xml = NULL;
1238 /* There could be a saved unexpanded xml */
1239 free_xml(child_rsc->orig_xml);
1240 child_rsc->orig_xml = NULL;
1241 child_rsc->fns->free(child_rsc);
1242 }
1243
1244 g_list_free(rsc->children);
1245
1246 if (clone_data) {
1247 CRM_ASSERT(clone_data->demote_notify == NULL);
1248 CRM_ASSERT(clone_data->stop_notify == NULL);
1249 CRM_ASSERT(clone_data->start_notify == NULL);
1250 CRM_ASSERT(clone_data->promote_notify == NULL);
1251 }
1252
1253 common_free(rsc);
1254}
1255
1256enum rsc_role_e
1257clone_resource_state(const pcmk_resource_t * rsc, gboolean current)
1258{
1259 enum rsc_role_e clone_role = pcmk_role_unknown;
1260 GList *gIter = rsc->children;
1261
1262 for (; gIter != NULL; gIter = gIter->next) {
1263 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
1264 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, current);
1265
1266 if (a_role > clone_role) {
1267 clone_role = a_role;
1268 }
1269 }
1270
1271 pcmk__rsc_trace(rsc, "%s role: %s", rsc->id, pcmk_role_text(clone_role));
1272 return clone_role;
1273}
1274
1282bool
1285{
1286 if (pcmk__is_clone(rsc)) {
1287 clone_variant_data_t *clone_data = rsc->variant_opaque;
1288
1289 if (clone_data->clone_max == g_list_length(scheduler->nodes)) {
1290 return TRUE;
1291 }
1292 }
1293 return FALSE;
1294}
1295
1296gboolean
1297pe__clone_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc,
1298 gboolean check_parent)
1299{
1300 gboolean passes = FALSE;
1301 clone_variant_data_t *clone_data = NULL;
1302
1304 passes = TRUE;
1305 } else {
1306 get_clone_variant_data(clone_data, rsc);
1307 passes = pcmk__str_in_list(pcmk__xe_id(clone_data->xml_obj_child),
1308 only_rsc, pcmk__str_star_matches);
1309
1310 if (!passes) {
1311 for (const GList *iter = rsc->children;
1312 iter != NULL; iter = iter->next) {
1313
1314 const pcmk_resource_t *child_rsc = NULL;
1315
1316 child_rsc = (const pcmk_resource_t *) iter->data;
1317 if (!child_rsc->fns->is_filtered(child_rsc, only_rsc, FALSE)) {
1318 passes = TRUE;
1319 break;
1320 }
1321 }
1322 }
1323 }
1324 return !passes;
1325}
1326
1327const char *
1329{
1330 clone_variant_data_t *clone_data = NULL;
1331 get_clone_variant_data(clone_data, rsc);
1332 return pcmk__xe_id(clone_data->xml_obj_child);
1333}
1334
1343bool
1345{
1346 clone_variant_data_t *clone_data = NULL;
1347
1348 get_clone_variant_data(clone_data, clone);
1349 return pcmk_is_set(clone_data->flags, pcmk__clone_ordered);
1350}
1351
1362int
1364{
1365 clone_variant_data_t *clone_data = NULL;
1366
1367 get_clone_variant_data(clone_data, clone);
1368 if (pcmk_is_set(clone_data->flags, flag)) {
1369 return pcmk_rc_already;
1370 }
1371 clone_data->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,
1372 "Clone", clone->id,
1373 clone_data->flags, flag, "flag");
1374 return pcmk_rc_ok;
1375}
1376
1386bool
1388{
1389 clone_variant_data_t *clone_data = NULL;
1390
1391 get_clone_variant_data(clone_data, clone);
1392 CRM_ASSERT(clone_data != NULL);
1393
1394 return pcmk_all_flags_set(clone_data->flags, flags);
1395}
1396
1405void
1407 bool any_demoting)
1408{
1409 pcmk_action_t *action = NULL;
1410 pcmk_action_t *action_complete = NULL;
1411 clone_variant_data_t *clone_data = NULL;
1412
1413 get_clone_variant_data(clone_data, clone);
1414
1415 // Create a "promote" action for the clone itself
1417 !any_promoting, true);
1418
1419 // Create a "promoted" action for when all promotions are done
1420 action_complete = pe__new_rsc_pseudo_action(clone, PCMK_ACTION_PROMOTED,
1421 !any_promoting, true);
1422 action_complete->priority = PCMK_SCORE_INFINITY;
1423
1424 // Create notification pseudo-actions for promotion
1425 if (clone_data->promote_notify == NULL) {
1426 clone_data->promote_notify = pe__action_notif_pseudo_ops(clone,
1428 action,
1429 action_complete);
1430 }
1431
1432 // Create a "demote" action for the clone itself
1434 !any_demoting, true);
1435
1436 // Create a "demoted" action for when all demotions are done
1437 action_complete = pe__new_rsc_pseudo_action(clone, PCMK_ACTION_DEMOTED,
1438 !any_demoting, true);
1439 action_complete->priority = PCMK_SCORE_INFINITY;
1440
1441 // Create notification pseudo-actions for demotion
1442 if (clone_data->demote_notify == NULL) {
1443 clone_data->demote_notify = pe__action_notif_pseudo_ops(clone,
1445 action,
1446 action_complete);
1447
1448 if (clone_data->promote_notify != NULL) {
1449 order_actions(clone_data->stop_notify->post_done,
1450 clone_data->promote_notify->pre, pcmk__ar_ordered);
1451 order_actions(clone_data->start_notify->post_done,
1452 clone_data->promote_notify->pre, pcmk__ar_ordered);
1453 order_actions(clone_data->demote_notify->post_done,
1454 clone_data->promote_notify->pre, pcmk__ar_ordered);
1455 order_actions(clone_data->demote_notify->post_done,
1456 clone_data->start_notify->pre, pcmk__ar_ordered);
1457 order_actions(clone_data->demote_notify->post_done,
1458 clone_data->stop_notify->pre, pcmk__ar_ordered);
1459 }
1460 }
1461}
1462
1469void
1471{
1472 clone_variant_data_t *clone_data = NULL;
1473
1474 get_clone_variant_data(clone_data, clone);
1475
1476 pe__create_action_notifications(clone, clone_data->start_notify);
1477 pe__create_action_notifications(clone, clone_data->stop_notify);
1478 pe__create_action_notifications(clone, clone_data->promote_notify);
1479 pe__create_action_notifications(clone, clone_data->demote_notify);
1480}
1481
1488void
1490{
1491 clone_variant_data_t *clone_data = NULL;
1492
1493 get_clone_variant_data(clone_data, clone);
1494
1495 pe__free_action_notification_data(clone_data->demote_notify);
1496 clone_data->demote_notify = NULL;
1497
1498 pe__free_action_notification_data(clone_data->stop_notify);
1499 clone_data->stop_notify = NULL;
1500
1501 pe__free_action_notification_data(clone_data->start_notify);
1502 clone_data->start_notify = NULL;
1503
1504 pe__free_action_notification_data(clone_data->promote_notify);
1505 clone_data->promote_notify = NULL;
1506}
1507
1518void
1520 pcmk_action_t *start, pcmk_action_t *started,
1521 pcmk_action_t *stop, pcmk_action_t *stopped)
1522{
1523 clone_variant_data_t *clone_data = NULL;
1524
1525 get_clone_variant_data(clone_data, clone);
1526
1527 if (clone_data->start_notify == NULL) {
1528 clone_data->start_notify = pe__action_notif_pseudo_ops(clone,
1530 start, started);
1531 }
1532
1533 if (clone_data->stop_notify == NULL) {
1534 clone_data->stop_notify = pe__action_notif_pseudo_ops(clone,
1536 stop, stopped);
1537 if ((clone_data->start_notify != NULL)
1538 && (clone_data->stop_notify != NULL)) {
1539 order_actions(clone_data->stop_notify->post_done,
1540 clone_data->start_notify->pre, pcmk__ar_ordered);
1541 }
1542 }
1543}
1544
1553unsigned int
1555{
1556 const clone_variant_data_t *clone_data = NULL;
1557
1558 get_clone_variant_data(clone_data, rsc);
1559 return clone_data->clone_node_max;
1560}
@ pcmk__ar_ordered
Actions are ordered (optionally, if no other flags are set)
#define PCMK_ACTION_PROMOTED
Definition actions.h:67
#define PCMK_ACTION_STOP
Definition actions.h:75
#define PCMK_ACTION_PROMOTE
Definition actions.h:66
#define PCMK_ACTION_START
Definition actions.h:72
#define PCMK_ACTION_DEMOTED
Definition actions.h:50
#define PCMK_ACTION_DEMOTE
Definition actions.h:49
bool is_set_recursive(const pcmk_resource_t *rsc, long long flag, bool any)
Definition clone.c:588
void pe__create_promotable_pseudo_ops(pcmk_resource_t *clone, bool any_promoting, bool any_demoting)
Definition clone.c:1406
void pe__create_clone_notifications(pcmk_resource_t *clone)
Definition clone.c:1470
enum rsc_role_e clone_resource_state(const pcmk_resource_t *rsc, gboolean current)
Definition clone.c:1257
int pe__clone_promoted_node_max(const pcmk_resource_t *clone)
Definition clone.c:114
int pe__clone_max(const pcmk_resource_t *clone)
Definition clone.c:63
#define get_clone_variant_data(data, rsc)
Definition clone.c:50
pcmk_resource_t * pe__create_clone_child(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
Definition clone.c:247
bool pe__is_universal_clone(const pcmk_resource_t *rsc, const pcmk_scheduler_t *scheduler)
Definition clone.c:1283
pcmk_resource_t * find_clone_instance(const pcmk_resource_t *rsc, const char *sub_id)
Definition clone.c:229
gboolean clone_unpack(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
Definition clone.c:348
void clone_free(pcmk_resource_t *rsc)
Definition clone.c:1223
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:1519
void clone_print(pcmk_resource_t *rsc, const char *pre_text, long options, void *print_data)
Definition clone.c:623
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:212
bool pe__clone_flag_is_set(const pcmk_resource_t *clone, uint32_t flags)
Definition clone.c:1387
bool pe__clone_is_ordered(const pcmk_resource_t *clone)
Definition clone.c:1344
gboolean clone_active(pcmk_resource_t *rsc, gboolean all)
Definition clone.c:465
unsigned int pe__clone_max_per_node(const pcmk_resource_t *rsc)
Definition clone.c:1554
int pe__set_clone_flag(pcmk_resource_t *clone, enum pcmk__clone_flags flag)
Definition clone.c:1363
int pe__clone_node_max(const pcmk_resource_t *clone)
Definition clone.c:80
int pe__clone_promoted_max(const pcmk_resource_t *clone)
Definition clone.c:97
#define PROMOTED_INSTANCES
Definition clone.c:27
const char * pe__clone_child_id(const pcmk_resource_t *rsc)
Definition clone.c:1328
void pe__free_clone_notification_data(pcmk_resource_t *clone)
Definition clone.c:1489
gboolean pe__clone_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent)
Definition clone.c:1297
#define UNPROMOTED_INSTANCES
Definition clone.c:28
pcmk__clone_flags
@ pcmk__clone_ordered
#define pcmk__assert_alloc(nmemb, size)
Definition internal.h:297
uint64_t flags
Definition remote.c:3
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
gboolean crm_is_true(const char *s)
Definition strings.c:488
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:98
int pe__unpack_resource(xmlNode *xml_obj, pcmk_resource_t **rsc, pcmk_resource_t *parent, pcmk_scheduler_t *scheduler)
Definition complex.c:639
pcmk__cpg_host_t host
Definition cpg.c:4
enum crm_ais_msg_types type
Definition cpg.c:3
#define CRM_CHECK(expr, failure_action)
Definition logging.h:245
#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:150
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:446
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition nvpair.c:301
#define pcmk__insert_meta(obj, name, value)
#define PCMK_META_RESOURCE_STICKINESS
Definition options.h:111
#define PCMK_META_CLONE_NODE_MAX
Definition options.h:84
#define PCMK_META_PROMOTED_MAX
Definition options.h:102
#define PCMK_META_CLONE_MAX
Definition options.h:82
#define PCMK_META_ORDERED
Definition options.h:99
#define PCMK_META_TARGET_ROLE
Definition options.h:113
#define PCMK_META_GLOBALLY_UNIQUE
Definition options.h:89
#define PCMK_META_PROMOTED_NODE_MAX
Definition options.h:103
#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:564
#define PCMK__OUTPUT_LIST_HEADER(out_obj, cond, retcode, title...)
#define PCMK__OUTPUT_ARGS(ARGS...)
#define PCMK__OUTPUT_LIST_FOOTER(out_obj, retcode)
const char * action
Definition pcmk_fence.c:30
void pe__free_action_notification_data(notify_data_t *n_data)
Definition pe_notif.c:956
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:432
void pe__create_action_notifications(pcmk_resource_t *rsc, notify_data_t *n_data)
Definition pe_notif.c:939
#define status_print(fmt, args...)
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:22
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition complex.c:1032
gboolean order_actions(pcmk_action_t *lh_action, pcmk_action_t *rh_action, uint32_t flags)
Definition utils.c:457
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:610
void pe__set_resource_flags_recursive(pcmk_resource_t *rsc, uint64_t flags)
Definition utils.c:581
pcmk_action_t * pe__new_rsc_pseudo_action(pcmk_resource_t *rsc, const char *task, bool optional, bool runnable)
int pe__clone_default(pcmk__output_t *out, va_list args)
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition utils.c:145
xmlNode * pe__failed_probe_for_rsc(const pcmk_resource_t *rsc, const char *name)
Definition utils.c:883
void common_free(pcmk_resource_t *rsc)
Definition complex.c:1049
bool pe__resource_is_disabled(const pcmk_resource_t *rsc)
Definition utils.c:737
bool pcmk__rsc_filtered_by_node(pcmk_resource_t *rsc, GList *only_node)
Definition utils.c:789
@ pe_print_ncurses
Definition resources.h:230
@ pe_print_printf
Definition resources.h:231
@ pe_print_log
Definition resources.h:228
@ pe_print_xml
Definition resources.h:238
@ pe_print_clone_active
Definition resources.h:242
@ pe_print_pending
Definition resources.h:240
@ pe_print_suppres_nl
Definition resources.h:237
@ pe_print_clone_details
Definition resources.h:241
@ pe_print_html
Definition resources.h:229
@ pcmk_rsc_promotable
Definition resources.h:106
@ pcmk_rsc_unique
Definition resources.h:100
@ pcmk_rsc_maintenance
Definition resources.h:166
@ pcmk_rsc_removed
Definition resources.h:85
@ pcmk_rsc_managed
Definition resources.h:88
@ pcmk_rsc_ignore_failure
Definition resources.h:160
@ pcmk_rsc_failed
Definition resources.h:133
#define CRM_ASSERT(expr)
Definition results.h:42
@ pcmk_rc_no_output
Definition results.h:131
@ pcmk_rc_ok
Definition results.h:162
@ pcmk_rc_already
Definition results.h:153
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:59
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__rsc_trace(rsc, fmt, args...)
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition scores.h:24
Cluster status and scheduling.
pcmk_resource_t * pe_find_resource(GList *rsc_list, const char *id_rh)
Definition status.c:430
const char * rsc_printable_id(const pcmk_resource_t *rsc)
Definition utils.c:553
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition strings.c:701
int pcmk__numeric_strcasecmp(const char *s1, const char *s2)
Definition strings.c:1078
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition strings.c:127
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition strings.c:981
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:683
@ 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:1050
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
Definition strings.c:794
This structure contains everything that makes up a single output formatter.
int priority
Definition actions.h:338
struct pe_node_shared_s * details
Definition nodes.h:167
gboolean online
Definition nodes.h:80
const char * uname
Definition nodes.h:73
gboolean unclean
Definition nodes.h:91
GList * running_on
Definition resources.h:456
GHashTable * meta
Definition resources.h:467
GList * children
Definition resources.h:471
pcmk_rsc_methods_t * fns
Definition resources.h:412
GHashTable * known_on
Definition resources.h:459
xmlNode * xml
Definition resources.h:400
GHashTable * allowed_nodes
Definition resources.h:462
void * variant_opaque
Definition resources.h:411
unsigned long long flags
Definition resources.h:428
char * pending_task
Definition resources.h:424
xmlNode * orig_xml
Definition resources.h:403
void(* free)(pcmk_resource_t *rsc)
Definition resources.h:336
void(* print)(pcmk_resource_t *rsc, const char *pre_text, long options, void *print_data)
Definition resources.h:295
enum rsc_role_e(* state)(const pcmk_resource_t *rsc, gboolean current)
Definition resources.h:316
pcmk_node_t *(* location)(const pcmk_resource_t *rsc, GList **list, int current)
Definition resources.h:328
gboolean(* is_filtered)(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent)
Definition resources.h:358
gboolean(* active)(pcmk_resource_t *rsc, gboolean all)
Definition resources.h:306
Wrappers for and extensions to libxml2.
void free_xml(xmlNode *child)
Definition xml.c:867
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition xml.c:883
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml.c:440
#define PCMK_XA_MULTI_STATE
Definition xml_names.h:324
#define PCMK_XA_DESCRIPTION
Definition xml_names.h:256
#define PCMK_XA_FAILED
Definition xml_names.h:278
#define PCMK_XE_GROUP
Definition xml_names.h:116
#define PCMK_XA_ID
Definition xml_names.h:296
#define PCMK_XA_FAILURE_IGNORED
Definition xml_names.h:279
#define PCMK_XA_TARGET_ROLE
Definition xml_names.h:417
#define PCMK_XA_MAINTENANCE
Definition xml_names.h:316
#define PCMK_XE_CLONE
Definition xml_names.h:80
#define PCMK_XE_PRIMITIVE
Definition xml_names.h:160
#define PCMK_XA_UNIQUE
Definition xml_names.h:429
#define PCMK_XA_MANAGED
Definition xml_names.h:318
#define PCMK_XA_DISABLED
Definition xml_names.h:260
#define PCMK__XA_RC_CODE