pacemaker 2.1.7-2.1.7
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
clone.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2023 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/msg_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((rsc != NULL) && (rsc->variant == pcmk_rsc_variant_clone)); \
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, ID(clone_data->xml_obj_child),
198 (const char *) attrs->str, desc ? " (" : "",
199 desc ? desc : "", desc ? ")" : "");
200 g_string_free(attrs, TRUE);
201 } else {
202 PCMK__OUTPUT_LIST_HEADER(out, FALSE, *rc, "Clone Set: %s [%s]%s%s%s",
203 rsc->id, ID(clone_data->xml_obj_child),
204 desc ? " (" : "", desc ? desc : "",
205 desc ? ")" : "");
206 }
207}
208
209void
210pe__force_anon(const char *standard, pcmk_resource_t *rsc, const char *rid,
212{
213 if (pe_rsc_is_clone(rsc)) {
214 clone_variant_data_t *clone_data = rsc->variant_opaque;
215
216 pe_warn("Ignoring " XML_RSC_ATTR_UNIQUE " for %s because %s resources "
217 "such as %s can be used only as anonymous clones",
218 rsc->id, standard, rid);
219
220 clone_data->clone_node_max = 1;
221 clone_data->clone_max = QB_MIN(clone_data->clone_max,
222 g_list_length(scheduler->nodes));
223 }
224}
225
227find_clone_instance(const pcmk_resource_t *rsc, const char *sub_id)
228{
229 char *child_id = NULL;
230 pcmk_resource_t *child = NULL;
231 const char *child_base = NULL;
232 clone_variant_data_t *clone_data = NULL;
233
234 get_clone_variant_data(clone_data, rsc);
235
236 child_base = ID(clone_data->xml_obj_child);
237 child_id = crm_strdup_printf("%s:%s", child_base, sub_id);
238 child = pe_find_resource(rsc->children, child_id);
239
240 free(child_id);
241 return child;
242}
243
246{
247 gboolean as_orphan = FALSE;
248 char *inc_num = NULL;
249 char *inc_max = NULL;
250 pcmk_resource_t *child_rsc = NULL;
251 xmlNode *child_copy = NULL;
252 clone_variant_data_t *clone_data = NULL;
253
254 get_clone_variant_data(clone_data, rsc);
255
256 CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE);
257
258 if (clone_data->total_clones >= clone_data->clone_max) {
259 // If we've already used all available instances, this is an orphan
260 as_orphan = TRUE;
261 }
262
263 // Allocate instance numbers in numerical order (starting at 0)
264 inc_num = pcmk__itoa(clone_data->total_clones);
265 inc_max = pcmk__itoa(clone_data->clone_max);
266
267 child_copy = copy_xml(clone_data->xml_obj_child);
268
269 crm_xml_add(child_copy, XML_RSC_ATTR_INCARNATION, inc_num);
270
271 if (pe__unpack_resource(child_copy, &child_rsc, rsc,
272 scheduler) != pcmk_rc_ok) {
273 goto bail;
274 }
275/* child_rsc->globally_unique = rsc->globally_unique; */
276
277 CRM_ASSERT(child_rsc);
278 clone_data->total_clones += 1;
279 pe_rsc_trace(child_rsc, "Setting clone attributes for: %s", child_rsc->id);
280 rsc->children = g_list_append(rsc->children, child_rsc);
281 if (as_orphan) {
283 }
284
285 add_hash_param(child_rsc->meta, PCMK_META_CLONE_MAX, inc_max);
286 pe_rsc_trace(rsc, "Added %s instance %s", rsc->id, child_rsc->id);
287
288 bail:
289 free(inc_num);
290 free(inc_max);
291
292 return child_rsc;
293}
294
308static int
309unpack_meta_int(const pcmk_resource_t *rsc, const char *meta_name,
310 const char *deprecated_name, int default_value)
311{
312 int integer = default_value;
313 const char *value = g_hash_table_lookup(rsc->meta, meta_name);
314
315 if ((value == NULL) && (deprecated_name != NULL)) {
316 value = g_hash_table_lookup(rsc->meta, deprecated_name);
317 }
318 if (value != NULL) {
319 pcmk__scan_min_int(value, &integer, 0);
320 }
321 return integer;
322}
323
324gboolean
326{
327 int lpc = 0;
328 xmlNode *a_child = NULL;
329 xmlNode *xml_obj = rsc->xml;
330 clone_variant_data_t *clone_data = NULL;
331
332 pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
333
334 clone_data = calloc(1, sizeof(clone_variant_data_t));
335 rsc->variant_opaque = clone_data;
336
338 // Use 1 as default but 0 for minimum and invalid
339 // @COMPAT PCMK_XA_PROMOTED_MAX_LEGACY deprecated since 2.0.0
340 clone_data->promoted_max = unpack_meta_int(rsc, PCMK_META_PROMOTED_MAX,
342 1);
343
344 // Use 1 as default but 0 for minimum and invalid
345 // @COMPAT PCMK_XA_PROMOTED_NODE_MAX_LEGACY deprecated since 2.0.0
346 clone_data->promoted_node_max =
347 unpack_meta_int(rsc, PCMK_META_PROMOTED_NODE_MAX,
349 }
350
351 // Implied by calloc()
352 /* clone_data->xml_obj_child = NULL; */
353
354 // Use 1 as default but 0 for minimum and invalid
355 clone_data->clone_node_max = unpack_meta_int(rsc, PCMK_META_CLONE_NODE_MAX,
356 NULL, 1);
357
358 /* Use number of nodes (but always at least 1, which is handy for crm_verify
359 * for a CIB without nodes) as default, but 0 for minimum and invalid
360 */
361 clone_data->clone_max = unpack_meta_int(rsc, PCMK_META_CLONE_MAX, NULL,
362 QB_MAX(1, g_list_length(scheduler->nodes)));
363
364 if (crm_is_true(g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_ORDERED))) {
365 clone_data->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,
366 "Clone", rsc->id,
367 clone_data->flags,
369 "pcmk__clone_ordered");
370 }
371
373 && (clone_data->clone_node_max > 1)) {
374
375 pcmk__config_err("Ignoring " PCMK_META_CLONE_NODE_MAX " of %d for %s "
376 "because anonymous clones support only one instance "
377 "per node", clone_data->clone_node_max, rsc->id);
378 clone_data->clone_node_max = 1;
379 }
380
381 pe_rsc_trace(rsc, "Options for %s", rsc->id);
382 pe_rsc_trace(rsc, "\tClone max: %d", clone_data->clone_max);
383 pe_rsc_trace(rsc, "\tClone node max: %d", clone_data->clone_node_max);
384 pe_rsc_trace(rsc, "\tClone is unique: %s",
385 pe__rsc_bool_str(rsc, pcmk_rsc_unique));
386 pe_rsc_trace(rsc, "\tClone is promotable: %s",
387 pe__rsc_bool_str(rsc, pcmk_rsc_promotable));
388
389 // Clones may contain a single group or primitive
390 for (a_child = pcmk__xe_first_child(xml_obj); a_child != NULL;
391 a_child = pcmk__xe_next(a_child)) {
392
393 if (pcmk__str_any_of((const char *)a_child->name, XML_CIB_TAG_RESOURCE, XML_CIB_TAG_GROUP, NULL)) {
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->meta, XML_RSC_ATTR_STICKINESS) == NULL) {
412 }
413
414 /* This ensures that the globally-unique value always exists for children to
415 * inherit when being unpacked, as well as in resource agents' environment.
416 */
418 pe__rsc_bool_str(rsc, pcmk_rsc_unique));
419
420 if (clone_data->clone_max <= 0) {
421 /* Create one child instance so that unpack_find_resource() will hook up
422 * any orphans up to the parent correctly.
423 */
424 if (pe__create_clone_child(rsc, scheduler) == NULL) {
425 return FALSE;
426 }
427
428 } else {
429 // Create a child instance for each available instance number
430 for (lpc = 0; lpc < clone_data->clone_max; lpc++) {
431 if (pe__create_clone_child(rsc, scheduler) == NULL) {
432 return FALSE;
433 }
434 }
435 }
436
437 pe_rsc_trace(rsc, "Added %d children to resource %s...", clone_data->clone_max, rsc->id);
438 return TRUE;
439}
440
441gboolean
442clone_active(pcmk_resource_t * rsc, gboolean all)
443{
444 GList *gIter = rsc->children;
445
446 for (; gIter != NULL; gIter = gIter->next) {
447 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
448 gboolean child_active = child_rsc->fns->active(child_rsc, all);
449
450 if (all == FALSE && child_active) {
451 return TRUE;
452 } else if (all && child_active == FALSE) {
453 return FALSE;
454 }
455 }
456
457 if (all) {
458 return TRUE;
459 } else {
460 return FALSE;
461 }
462}
463
468static void
469short_print(const char *list, const char *prefix, const char *type,
470 const char *suffix, long options, void *print_data)
471{
472 if(suffix == NULL) {
473 suffix = "";
474 }
475
476 if (!pcmk__str_empty(list)) {
477 if (options & pe_print_html) {
478 status_print("<li>");
479 }
480 status_print("%s%s: [ %s ]%s", prefix, type, list, suffix);
481
482 if (options & pe_print_html) {
483 status_print("</li>\n");
484
485 } else if (options & pe_print_suppres_nl) {
486 /* nothing */
487 } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) {
488 status_print("\n");
489 }
490
491 }
492}
493
494static const char *
495configured_role_str(pcmk_resource_t * rsc)
496{
497 const char *target_role = g_hash_table_lookup(rsc->meta,
499
500 if ((target_role == NULL) && rsc->children && rsc->children->data) {
501 pcmk_resource_t *instance = rsc->children->data; // Any instance will do
502
503 target_role = g_hash_table_lookup(instance->meta,
505 }
506 return target_role;
507}
508
509static enum rsc_role_e
510configured_role(pcmk_resource_t *rsc)
511{
512 const char *target_role = configured_role_str(rsc);
513
514 if (target_role) {
515 return text2role(target_role);
516 }
517 return pcmk_role_unknown;
518}
519
524static void
525clone_print_xml(pcmk_resource_t *rsc, const char *pre_text, long options,
526 void *print_data)
527{
528 char *child_text = crm_strdup_printf("%s ", pre_text);
529 const char *target_role = configured_role_str(rsc);
530 GList *gIter = rsc->children;
531
532 status_print("%s<clone ", pre_text);
533 status_print(XML_ATTR_ID "=\"%s\" ", rsc->id);
534 status_print("multi_state=\"%s\" ",
535 pe__rsc_bool_str(rsc, pcmk_rsc_promotable));
536 status_print("unique=\"%s\" ", pe__rsc_bool_str(rsc, pcmk_rsc_unique));
537 status_print("managed=\"%s\" ",
538 pe__rsc_bool_str(rsc, pcmk_rsc_managed));
539 status_print("failed=\"%s\" ", pe__rsc_bool_str(rsc, pcmk_rsc_failed));
540 status_print("failure_ignored=\"%s\" ",
541 pe__rsc_bool_str(rsc, pcmk_rsc_ignore_failure));
542 if (target_role) {
543 status_print("target_role=\"%s\" ", target_role);
544 }
545 status_print(">\n");
546
547 for (; gIter != NULL; gIter = gIter->next) {
548 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
549
550 child_rsc->fns->print(child_rsc, child_text, options, print_data);
551 }
552
553 status_print("%s</clone>\n", pre_text);
554 free(child_text);
555}
556
557bool
558is_set_recursive(const pcmk_resource_t *rsc, long long flag, bool any)
559{
560 GList *gIter;
561 bool all = !any;
562
563 if (pcmk_is_set(rsc->flags, flag)) {
564 if(any) {
565 return TRUE;
566 }
567 } else if(all) {
568 return FALSE;
569 }
570
571 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
572 if(is_set_recursive(gIter->data, flag, any)) {
573 if(any) {
574 return TRUE;
575 }
576
577 } else if(all) {
578 return FALSE;
579 }
580 }
581
582 if(all) {
583 return TRUE;
584 }
585 return FALSE;
586}
587
592void
593clone_print(pcmk_resource_t *rsc, const char *pre_text, long options,
594 void *print_data)
595{
596 GString *list_text = NULL;
597 char *child_text = NULL;
598 GString *stopped_list = NULL;
599
600 GList *promoted_list = NULL;
601 GList *started_list = NULL;
602 GList *gIter = rsc->children;
603
604 clone_variant_data_t *clone_data = NULL;
605 int active_instances = 0;
606
607 if (pre_text == NULL) {
608 pre_text = " ";
609 }
610
611 if (options & pe_print_xml) {
612 clone_print_xml(rsc, pre_text, options, print_data);
613 return;
614 }
615
616 get_clone_variant_data(clone_data, rsc);
617
618 child_text = crm_strdup_printf("%s ", pre_text);
619
620 status_print("%sClone Set: %s [%s]%s%s%s",
621 pre_text ? pre_text : "", rsc->id, ID(clone_data->xml_obj_child),
622 pcmk_is_set(rsc->flags, pcmk_rsc_promotable)? " (promotable)" : "",
623 pcmk_is_set(rsc->flags, pcmk_rsc_unique)? " (unique)" : "",
624 pcmk_is_set(rsc->flags, pcmk_rsc_managed)? "" : " (unmanaged)");
625
626 if (options & pe_print_html) {
627 status_print("\n<ul>\n");
628
629 } else if ((options & pe_print_log) == 0) {
630 status_print("\n");
631 }
632
633 for (; gIter != NULL; gIter = gIter->next) {
634 gboolean print_full = FALSE;
635 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
636 gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
637
638 if (options & pe_print_clone_details) {
639 print_full = TRUE;
640 }
641
642 if (pcmk_is_set(rsc->flags, pcmk_rsc_unique)) {
643 // Print individual instance when unique (except stopped orphans)
644 if (partially_active
646 print_full = TRUE;
647 }
648
649 // Everything else in this block is for anonymous clones
650
651 } else if (pcmk_is_set(options, pe_print_pending)
652 && (child_rsc->pending_task != NULL)
653 && strcmp(child_rsc->pending_task, "probe")) {
654 // Print individual instance when non-probe action is pending
655 print_full = TRUE;
656
657 } else if (partially_active == FALSE) {
658 // List stopped instances when requested (except orphans)
659 if (!pcmk_is_set(child_rsc->flags, pcmk_rsc_removed)
660 && !pcmk_is_set(options, pe_print_clone_active)) {
661
662 pcmk__add_word(&stopped_list, 1024, child_rsc->id);
663 }
664
665 } else if (is_set_recursive(child_rsc, pcmk_rsc_removed, TRUE)
666 || !is_set_recursive(child_rsc, pcmk_rsc_managed, FALSE)
667 || is_set_recursive(child_rsc, pcmk_rsc_failed, TRUE)) {
668
669 // Print individual instance when active orphaned/unmanaged/failed
670 print_full = TRUE;
671
672 } else if (child_rsc->fns->active(child_rsc, TRUE)) {
673 // Instance of fully active anonymous clone
674
675 pcmk_node_t *location = NULL;
676
677 location = child_rsc->fns->location(child_rsc, NULL, TRUE);
678 if (location) {
679 // Instance is active on a single node
680
681 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
682
683 if (location->details->online == FALSE && location->details->unclean) {
684 print_full = TRUE;
685
686 } else if (a_role > pcmk_role_unpromoted) {
687 promoted_list = g_list_append(promoted_list, location);
688
689 } else {
690 started_list = g_list_append(started_list, location);
691 }
692
693 } else {
694 /* uncolocated group - bleh */
695 print_full = TRUE;
696 }
697
698 } else {
699 // Instance of partially active anonymous clone
700 print_full = TRUE;
701 }
702
703 if (print_full) {
704 if (options & pe_print_html) {
705 status_print("<li>\n");
706 }
707 child_rsc->fns->print(child_rsc, child_text, options, print_data);
708 if (options & pe_print_html) {
709 status_print("</li>\n");
710 }
711 }
712 }
713
714 /* Promoted */
715 promoted_list = g_list_sort(promoted_list, pe__cmp_node_name);
716 for (gIter = promoted_list; gIter; gIter = gIter->next) {
717 pcmk_node_t *host = gIter->data;
718
719 pcmk__add_word(&list_text, 1024, host->details->uname);
720 active_instances++;
721 }
722
723 if (list_text != NULL) {
724 short_print((const char *) list_text->str, child_text,
725 PROMOTED_INSTANCES, NULL, options, print_data);
726 g_string_truncate(list_text, 0);
727 }
728 g_list_free(promoted_list);
729
730 /* Started/Unpromoted */
731 started_list = g_list_sort(started_list, pe__cmp_node_name);
732 for (gIter = started_list; gIter; gIter = gIter->next) {
733 pcmk_node_t *host = gIter->data;
734
735 pcmk__add_word(&list_text, 1024, host->details->uname);
736 active_instances++;
737 }
738
739 if (list_text != NULL) {
741 enum rsc_role_e role = configured_role(rsc);
742
743 if (role == pcmk_role_unpromoted) {
744 short_print((const char *) list_text->str, child_text,
745 UNPROMOTED_INSTANCES " (target-role)", NULL,
746 options, print_data);
747 } else {
748 short_print((const char *) list_text->str, child_text,
749 UNPROMOTED_INSTANCES, NULL, options, print_data);
750 }
751
752 } else {
753 short_print((const char *) list_text->str, child_text, "Started",
754 NULL, options, print_data);
755 }
756 }
757
758 g_list_free(started_list);
759
760 if (!pcmk_is_set(options, pe_print_clone_active)) {
761 const char *state = "Stopped";
762 enum rsc_role_e role = configured_role(rsc);
763
764 if (role == pcmk_role_stopped) {
765 state = "Stopped (disabled)";
766 }
767
769 && (clone_data->clone_max > active_instances)) {
770
771 GList *nIter;
772 GList *list = g_hash_table_get_values(rsc->allowed_nodes);
773
774 /* Custom stopped list for non-unique clones */
775 if (stopped_list != NULL) {
776 g_string_truncate(stopped_list, 0);
777 }
778
779 if (list == NULL) {
780 /* Clusters with symmetrical=false haven't calculated allowed_nodes yet
781 * If we've not probed for them yet, the Stopped list will be empty
782 */
783 list = g_hash_table_get_values(rsc->known_on);
784 }
785
786 list = g_list_sort(list, pe__cmp_node_name);
787 for (nIter = list; nIter != NULL; nIter = nIter->next) {
788 pcmk_node_t *node = (pcmk_node_t *) nIter->data;
789
790 if (pe_find_node(rsc->running_on, node->details->uname) == NULL) {
791 pcmk__add_word(&stopped_list, 1024, node->details->uname);
792 }
793 }
794 g_list_free(list);
795 }
796
797 if (stopped_list != NULL) {
798 short_print((const char *) stopped_list->str, child_text, state,
799 NULL, options, print_data);
800 }
801 }
802
803 if (options & pe_print_html) {
804 status_print("</ul>\n");
805 }
806
807 if (list_text != NULL) {
808 g_string_free(list_text, TRUE);
809 }
810
811 if (stopped_list != NULL) {
812 g_string_free(stopped_list, TRUE);
813 }
814 free(child_text);
815}
816
817PCMK__OUTPUT_ARGS("clone", "uint32_t", "pcmk_resource_t *", "GList *",
818 "GList *")
819int
820pe__clone_xml(pcmk__output_t *out, va_list args)
821{
822 uint32_t show_opts = va_arg(args, uint32_t);
823 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
824 GList *only_node = va_arg(args, GList *);
825 GList *only_rsc = va_arg(args, GList *);
826
827
828 const char *desc = NULL;
829 GList *gIter = rsc->children;
830 GList *all = NULL;
831 int rc = pcmk_rc_no_output;
832 gboolean printed_header = FALSE;
833 gboolean print_everything = TRUE;
834
835
836
837 if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
838 return rc;
839 }
840
841 print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
842 (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
843
844 all = g_list_prepend(all, (gpointer) "*");
845
846 for (; gIter != NULL; gIter = gIter->next) {
847 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
848
849 if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
850 continue;
851 }
852
853 if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
854 continue;
855 }
856
857 if (!printed_header) {
858 printed_header = TRUE;
859
860 desc = pe__resource_description(rsc, show_opts);
861 rc = pe__name_and_nvpairs_xml(out, true, "clone", 10,
862 "id", rsc->id,
863 "multi_state",
864 pe__rsc_bool_str(rsc, pcmk_rsc_promotable),
865 "unique", pe__rsc_bool_str(rsc, pcmk_rsc_unique),
866 "maintenance",
867 pe__rsc_bool_str(rsc, pcmk_rsc_maintenance),
868 "managed", pe__rsc_bool_str(rsc, pcmk_rsc_managed),
869 "disabled", pcmk__btoa(pe__resource_is_disabled(rsc)),
870 "failed", pe__rsc_bool_str(rsc, pcmk_rsc_failed),
871 "failure_ignored",
872 pe__rsc_bool_str(rsc, pcmk_rsc_ignore_failure),
873 "target_role", configured_role_str(rsc),
874 "description", desc);
875 CRM_ASSERT(rc == pcmk_rc_ok);
876 }
877
878 out->message(out, crm_map_element_name(child_rsc->xml), show_opts,
879 child_rsc, only_node, all);
880 }
881
882 if (printed_header) {
884 }
885
886 g_list_free(all);
887 return rc;
888}
889
890PCMK__OUTPUT_ARGS("clone", "uint32_t", "pcmk_resource_t *", "GList *",
891 "GList *")
892int
893pe__clone_default(pcmk__output_t *out, va_list args)
894{
895 uint32_t show_opts = va_arg(args, uint32_t);
896 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
897 GList *only_node = va_arg(args, GList *);
898 GList *only_rsc = va_arg(args, GList *);
899
900 GHashTable *stopped = NULL;
901
902 GString *list_text = NULL;
903
904 GList *promoted_list = NULL;
905 GList *started_list = NULL;
906 GList *gIter = rsc->children;
907
908 const char *desc = NULL;
909
910 clone_variant_data_t *clone_data = NULL;
911 int active_instances = 0;
912 int rc = pcmk_rc_no_output;
913 gboolean print_everything = TRUE;
914
915 desc = pe__resource_description(rsc, show_opts);
916
917 get_clone_variant_data(clone_data, rsc);
918
919 if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
920 return rc;
921 }
922
923 print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
924 (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
925
926 for (; gIter != NULL; gIter = gIter->next) {
927 gboolean print_full = FALSE;
928 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
929 gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
930
931 if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
932 continue;
933 }
934
935 if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
936 continue;
937 }
938
939 if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
940 print_full = TRUE;
941 }
942
943 if (pcmk_is_set(rsc->flags, pcmk_rsc_unique)) {
944 // Print individual instance when unique (except stopped orphans)
945 if (partially_active
947 print_full = TRUE;
948 }
949
950 // Everything else in this block is for anonymous clones
951
952 } else if (pcmk_is_set(show_opts, pcmk_show_pending)
953 && (child_rsc->pending_task != NULL)
954 && strcmp(child_rsc->pending_task, "probe")) {
955 // Print individual instance when non-probe action is pending
956 print_full = TRUE;
957
958 } else if (partially_active == FALSE) {
959 // List stopped instances when requested (except orphans)
960 if (!pcmk_is_set(child_rsc->flags, pcmk_rsc_removed)
961 && !pcmk_is_set(show_opts, pcmk_show_clone_detail)
962 && pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
963 if (stopped == NULL) {
964 stopped = pcmk__strkey_table(free, free);
965 }
966 g_hash_table_insert(stopped, strdup(child_rsc->id), strdup("Stopped"));
967 }
968
969 } else if (is_set_recursive(child_rsc, pcmk_rsc_removed, TRUE)
970 || !is_set_recursive(child_rsc, pcmk_rsc_managed, FALSE)
971 || is_set_recursive(child_rsc, pcmk_rsc_failed, TRUE)) {
972
973 // Print individual instance when active orphaned/unmanaged/failed
974 print_full = TRUE;
975
976 } else if (child_rsc->fns->active(child_rsc, TRUE)) {
977 // Instance of fully active anonymous clone
978
979 pcmk_node_t *location = NULL;
980
981 location = child_rsc->fns->location(child_rsc, NULL, TRUE);
982 if (location) {
983 // Instance is active on a single node
984
985 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
986
987 if (location->details->online == FALSE && location->details->unclean) {
988 print_full = TRUE;
989
990 } else if (a_role > pcmk_role_unpromoted) {
991 promoted_list = g_list_append(promoted_list, location);
992
993 } else {
994 started_list = g_list_append(started_list, location);
995 }
996
997 } else {
998 /* uncolocated group - bleh */
999 print_full = TRUE;
1000 }
1001
1002 } else {
1003 // Instance of partially active anonymous clone
1004 print_full = TRUE;
1005 }
1006
1007 if (print_full) {
1008 GList *all = NULL;
1009
1010 clone_header(out, &rc, rsc, clone_data, desc);
1011
1012 /* Print every resource that's a child of this clone. */
1013 all = g_list_prepend(all, (gpointer) "*");
1014 out->message(out, crm_map_element_name(child_rsc->xml), show_opts,
1015 child_rsc, only_node, all);
1016 g_list_free(all);
1017 }
1018 }
1019
1020 if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
1021 PCMK__OUTPUT_LIST_FOOTER(out, rc);
1022 return pcmk_rc_ok;
1023 }
1024
1025 /* Promoted */
1026 promoted_list = g_list_sort(promoted_list, pe__cmp_node_name);
1027 for (gIter = promoted_list; gIter; gIter = gIter->next) {
1028 pcmk_node_t *host = gIter->data;
1029
1030 if (!pcmk__str_in_list(host->details->uname, only_node,
1032 continue;
1033 }
1034
1035 pcmk__add_word(&list_text, 1024, host->details->uname);
1036 active_instances++;
1037 }
1038 g_list_free(promoted_list);
1039
1040 if ((list_text != NULL) && (list_text->len > 0)) {
1041 clone_header(out, &rc, rsc, clone_data, desc);
1042
1043 out->list_item(out, NULL, PROMOTED_INSTANCES ": [ %s ]",
1044 (const char *) list_text->str);
1045 g_string_truncate(list_text, 0);
1046 }
1047
1048 /* Started/Unpromoted */
1049 started_list = g_list_sort(started_list, pe__cmp_node_name);
1050 for (gIter = started_list; gIter; gIter = gIter->next) {
1051 pcmk_node_t *host = gIter->data;
1052
1053 if (!pcmk__str_in_list(host->details->uname, only_node,
1055 continue;
1056 }
1057
1058 pcmk__add_word(&list_text, 1024, host->details->uname);
1059 active_instances++;
1060 }
1061 g_list_free(started_list);
1062
1063 if ((list_text != NULL) && (list_text->len > 0)) {
1064 clone_header(out, &rc, rsc, clone_data, desc);
1065
1067 enum rsc_role_e role = configured_role(rsc);
1068
1069 if (role == pcmk_role_unpromoted) {
1070 out->list_item(out, NULL,
1071 UNPROMOTED_INSTANCES " (target-role): [ %s ]",
1072 (const char *) list_text->str);
1073 } else {
1074 out->list_item(out, NULL, UNPROMOTED_INSTANCES ": [ %s ]",
1075 (const char *) list_text->str);
1076 }
1077
1078 } else {
1079 out->list_item(out, NULL, "Started: [ %s ]",
1080 (const char *) list_text->str);
1081 }
1082 }
1083
1084 if (list_text != NULL) {
1085 g_string_free(list_text, TRUE);
1086 }
1087
1088 if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
1090 && (clone_data->clone_max > active_instances)) {
1091
1092 GList *nIter;
1093 GList *list = g_hash_table_get_values(rsc->allowed_nodes);
1094
1095 /* Custom stopped table for non-unique clones */
1096 if (stopped != NULL) {
1097 g_hash_table_destroy(stopped);
1098 stopped = NULL;
1099 }
1100
1101 if (list == NULL) {
1102 /* Clusters with symmetrical=false haven't calculated allowed_nodes yet
1103 * If we've not probed for them yet, the Stopped list will be empty
1104 */
1105 list = g_hash_table_get_values(rsc->known_on);
1106 }
1107
1108 list = g_list_sort(list, pe__cmp_node_name);
1109 for (nIter = list; nIter != NULL; nIter = nIter->next) {
1110 pcmk_node_t *node = (pcmk_node_t *) nIter->data;
1111
1112 if (pe_find_node(rsc->running_on, node->details->uname) == NULL &&
1113 pcmk__str_in_list(node->details->uname, only_node,
1115 xmlNode *probe_op = pe__failed_probe_for_rsc(rsc, node->details->uname);
1116 const char *state = "Stopped";
1117
1118 if (configured_role(rsc) == pcmk_role_stopped) {
1119 state = "Stopped (disabled)";
1120 }
1121
1122 if (stopped == NULL) {
1123 stopped = pcmk__strkey_table(free, free);
1124 }
1125 if (probe_op != NULL) {
1126 int rc;
1127
1129 g_hash_table_insert(stopped, strdup(node->details->uname),
1130 crm_strdup_printf("Stopped (%s)", services_ocf_exitcode_str(rc)));
1131 } else {
1132 g_hash_table_insert(stopped, strdup(node->details->uname),
1133 strdup(state));
1134 }
1135 }
1136 }
1137 g_list_free(list);
1138 }
1139
1140 if (stopped != NULL) {
1141 GList *list = sorted_hash_table_values(stopped);
1142
1143 clone_header(out, &rc, rsc, clone_data, desc);
1144
1145 for (GList *status_iter = list; status_iter != NULL; status_iter = status_iter->next) {
1146 const char *status = status_iter->data;
1147 GList *nodes = nodes_with_status(stopped, status);
1148 GString *nodes_str = node_list_to_str(nodes);
1149
1150 if (nodes_str != NULL) {
1151 if (nodes_str->len > 0) {
1152 out->list_item(out, NULL, "%s: [ %s ]", status,
1153 (const char *) nodes_str->str);
1154 }
1155 g_string_free(nodes_str, TRUE);
1156 }
1157
1158 g_list_free(nodes);
1159 }
1160
1161 g_list_free(list);
1162 g_hash_table_destroy(stopped);
1163
1164 /* If there are no instances of this clone (perhaps because there are no
1165 * nodes configured), simply output the clone header by itself. This can
1166 * come up in PCS testing.
1167 */
1168 } else if (active_instances == 0) {
1169 clone_header(out, &rc, rsc, clone_data, desc);
1170 PCMK__OUTPUT_LIST_FOOTER(out, rc);
1171 return rc;
1172 }
1173 }
1174
1175 PCMK__OUTPUT_LIST_FOOTER(out, rc);
1176 return rc;
1177}
1178
1179void
1181{
1182 clone_variant_data_t *clone_data = NULL;
1183
1184 get_clone_variant_data(clone_data, rsc);
1185
1186 pe_rsc_trace(rsc, "Freeing %s", rsc->id);
1187
1188 for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1189 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
1190
1191 CRM_ASSERT(child_rsc);
1192 pe_rsc_trace(child_rsc, "Freeing child %s", child_rsc->id);
1193 free_xml(child_rsc->xml);
1194 child_rsc->xml = NULL;
1195 /* There could be a saved unexpanded xml */
1196 free_xml(child_rsc->orig_xml);
1197 child_rsc->orig_xml = NULL;
1198 child_rsc->fns->free(child_rsc);
1199 }
1200
1201 g_list_free(rsc->children);
1202
1203 if (clone_data) {
1204 CRM_ASSERT(clone_data->demote_notify == NULL);
1205 CRM_ASSERT(clone_data->stop_notify == NULL);
1206 CRM_ASSERT(clone_data->start_notify == NULL);
1207 CRM_ASSERT(clone_data->promote_notify == NULL);
1208 }
1209
1210 common_free(rsc);
1211}
1212
1213enum rsc_role_e
1214clone_resource_state(const pcmk_resource_t * rsc, gboolean current)
1215{
1216 enum rsc_role_e clone_role = pcmk_role_unknown;
1217 GList *gIter = rsc->children;
1218
1219 for (; gIter != NULL; gIter = gIter->next) {
1220 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
1221 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, current);
1222
1223 if (a_role > clone_role) {
1224 clone_role = a_role;
1225 }
1226 }
1227
1228 pe_rsc_trace(rsc, "%s role: %s", rsc->id, role2text(clone_role));
1229 return clone_role;
1230}
1231
1239bool
1242{
1243 if (pe_rsc_is_clone(rsc)) {
1244 clone_variant_data_t *clone_data = rsc->variant_opaque;
1245
1246 if (clone_data->clone_max == g_list_length(scheduler->nodes)) {
1247 return TRUE;
1248 }
1249 }
1250 return FALSE;
1251}
1252
1253gboolean
1254pe__clone_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc,
1255 gboolean check_parent)
1256{
1257 gboolean passes = FALSE;
1258 clone_variant_data_t *clone_data = NULL;
1259
1261 passes = TRUE;
1262 } else {
1263 get_clone_variant_data(clone_data, rsc);
1264 passes = pcmk__str_in_list(ID(clone_data->xml_obj_child), only_rsc, pcmk__str_star_matches);
1265
1266 if (!passes) {
1267 for (const GList *iter = rsc->children;
1268 iter != NULL; iter = iter->next) {
1269
1270 const pcmk_resource_t *child_rsc = NULL;
1271
1272 child_rsc = (const pcmk_resource_t *) iter->data;
1273 if (!child_rsc->fns->is_filtered(child_rsc, only_rsc, FALSE)) {
1274 passes = TRUE;
1275 break;
1276 }
1277 }
1278 }
1279 }
1280 return !passes;
1281}
1282
1283const char *
1285{
1286 clone_variant_data_t *clone_data = NULL;
1287 get_clone_variant_data(clone_data, rsc);
1288 return ID(clone_data->xml_obj_child);
1289}
1290
1299bool
1301{
1302 clone_variant_data_t *clone_data = NULL;
1303
1304 get_clone_variant_data(clone_data, clone);
1305 return pcmk_is_set(clone_data->flags, pcmk__clone_ordered);
1306}
1307
1318int
1320{
1321 clone_variant_data_t *clone_data = NULL;
1322
1323 get_clone_variant_data(clone_data, clone);
1324 if (pcmk_is_set(clone_data->flags, flag)) {
1325 return pcmk_rc_already;
1326 }
1327 clone_data->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,
1328 "Clone", clone->id,
1329 clone_data->flags, flag, "flag");
1330 return pcmk_rc_ok;
1331}
1332
1342bool
1344{
1345 clone_variant_data_t *clone_data = NULL;
1346
1347 get_clone_variant_data(clone_data, clone);
1348 CRM_ASSERT(clone_data != NULL);
1349
1350 return pcmk_all_flags_set(clone_data->flags, flags);
1351}
1352
1361void
1363 bool any_demoting)
1364{
1365 pcmk_action_t *action = NULL;
1366 pcmk_action_t *action_complete = NULL;
1367 clone_variant_data_t *clone_data = NULL;
1368
1369 get_clone_variant_data(clone_data, clone);
1370
1371 // Create a "promote" action for the clone itself
1373 !any_promoting, true);
1374
1375 // Create a "promoted" action for when all promotions are done
1376 action_complete = pe__new_rsc_pseudo_action(clone, PCMK_ACTION_PROMOTED,
1377 !any_promoting, true);
1378 action_complete->priority = INFINITY;
1379
1380 // Create notification pseudo-actions for promotion
1381 if (clone_data->promote_notify == NULL) {
1382 clone_data->promote_notify = pe__action_notif_pseudo_ops(clone,
1384 action,
1385 action_complete);
1386 }
1387
1388 // Create a "demote" action for the clone itself
1390 !any_demoting, true);
1391
1392 // Create a "demoted" action for when all demotions are done
1393 action_complete = pe__new_rsc_pseudo_action(clone, PCMK_ACTION_DEMOTED,
1394 !any_demoting, true);
1395 action_complete->priority = INFINITY;
1396
1397 // Create notification pseudo-actions for demotion
1398 if (clone_data->demote_notify == NULL) {
1399 clone_data->demote_notify = pe__action_notif_pseudo_ops(clone,
1401 action,
1402 action_complete);
1403
1404 if (clone_data->promote_notify != NULL) {
1405 order_actions(clone_data->stop_notify->post_done,
1406 clone_data->promote_notify->pre, pcmk__ar_ordered);
1407 order_actions(clone_data->start_notify->post_done,
1408 clone_data->promote_notify->pre, pcmk__ar_ordered);
1409 order_actions(clone_data->demote_notify->post_done,
1410 clone_data->promote_notify->pre, pcmk__ar_ordered);
1411 order_actions(clone_data->demote_notify->post_done,
1412 clone_data->start_notify->pre, pcmk__ar_ordered);
1413 order_actions(clone_data->demote_notify->post_done,
1414 clone_data->stop_notify->pre, pcmk__ar_ordered);
1415 }
1416 }
1417}
1418
1425void
1427{
1428 clone_variant_data_t *clone_data = NULL;
1429
1430 get_clone_variant_data(clone_data, clone);
1431
1432 pe__create_action_notifications(clone, clone_data->start_notify);
1433 pe__create_action_notifications(clone, clone_data->stop_notify);
1434 pe__create_action_notifications(clone, clone_data->promote_notify);
1435 pe__create_action_notifications(clone, clone_data->demote_notify);
1436}
1437
1444void
1446{
1447 clone_variant_data_t *clone_data = NULL;
1448
1449 get_clone_variant_data(clone_data, clone);
1450
1451 pe__free_action_notification_data(clone_data->demote_notify);
1452 clone_data->demote_notify = NULL;
1453
1454 pe__free_action_notification_data(clone_data->stop_notify);
1455 clone_data->stop_notify = NULL;
1456
1457 pe__free_action_notification_data(clone_data->start_notify);
1458 clone_data->start_notify = NULL;
1459
1460 pe__free_action_notification_data(clone_data->promote_notify);
1461 clone_data->promote_notify = NULL;
1462}
1463
1474void
1476 pcmk_action_t *start, pcmk_action_t *started,
1477 pcmk_action_t *stop, pcmk_action_t *stopped)
1478{
1479 clone_variant_data_t *clone_data = NULL;
1480
1481 get_clone_variant_data(clone_data, clone);
1482
1483 if (clone_data->start_notify == NULL) {
1484 clone_data->start_notify = pe__action_notif_pseudo_ops(clone,
1486 start, started);
1487 }
1488
1489 if (clone_data->stop_notify == NULL) {
1490 clone_data->stop_notify = pe__action_notif_pseudo_ops(clone,
1492 stop, stopped);
1493 if ((clone_data->start_notify != NULL)
1494 && (clone_data->stop_notify != NULL)) {
1495 order_actions(clone_data->stop_notify->post_done,
1496 clone_data->start_notify->pre, pcmk__ar_ordered);
1497 }
1498 }
1499}
1500
1509unsigned int
1511{
1512 const clone_variant_data_t *clone_data = NULL;
1513
1514 get_clone_variant_data(clone_data, rsc);
1515 return clone_data->clone_node_max;
1516}
@ pcmk__ar_ordered
Actions are ordered (optionally, if no other flags are set)
#define PCMK_ACTION_PROMOTED
Definition actions.h:66
#define PCMK_ACTION_STOP
Definition actions.h:74
#define PCMK_ACTION_PROMOTE
Definition actions.h:65
#define PCMK_ACTION_START
Definition actions.h:71
#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:558
void pe__create_promotable_pseudo_ops(pcmk_resource_t *clone, bool any_promoting, bool any_demoting)
Definition clone.c:1362
void pe__create_clone_notifications(pcmk_resource_t *clone)
Definition clone.c:1426
enum rsc_role_e clone_resource_state(const pcmk_resource_t *rsc, gboolean current)
Definition clone.c:1214
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:245
bool pe__is_universal_clone(const pcmk_resource_t *rsc, const pcmk_scheduler_t *scheduler)
Definition clone.c:1240
pcmk_resource_t * find_clone_instance(const pcmk_resource_t *rsc, const char *sub_id)
Definition clone.c:227
gboolean clone_unpack(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
Definition clone.c:325
void clone_free(pcmk_resource_t *rsc)
Definition clone.c:1180
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:1475
void clone_print(pcmk_resource_t *rsc, const char *pre_text, long options, void *print_data)
Definition clone.c:593
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:210
bool pe__clone_flag_is_set(const pcmk_resource_t *clone, uint32_t flags)
Definition clone.c:1343
bool pe__clone_is_ordered(const pcmk_resource_t *clone)
Definition clone.c:1300
gboolean clone_active(pcmk_resource_t *rsc, gboolean all)
Definition clone.c:442
unsigned int pe__clone_max_per_node(const pcmk_resource_t *rsc)
Definition clone.c:1510
int pe__set_clone_flag(pcmk_resource_t *clone, enum pcmk__clone_flags flag)
Definition clone.c:1319
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:1284
void pe__free_clone_notification_data(pcmk_resource_t *clone)
Definition clone.c:1445
gboolean pe__clone_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent)
Definition clone.c:1254
#define UNPROMOTED_INSTANCES
Definition clone.c:28
pcmk__clone_flags
@ pcmk__clone_ordered
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:416
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:99
const char * role2text(enum rsc_role_e role)
Definition common.c:458
enum rsc_role_e text2role(const char *role)
Definition common.c:487
int pe__unpack_resource(xmlNode *xml_obj, pcmk_resource_t **rsc, pcmk_resource_t *parent, pcmk_scheduler_t *scheduler)
Definition complex.c:603
pcmk__cpg_host_t host
Definition cpg.c:4
enum crm_ais_msg_types type
Definition cpg.c:3
#define INFINITY
Definition crm.h:98
#define CRM_CHECK(expr, failure_action)
Definition logging.h:238
#define LOG_TRACE
Definition logging.h:38
#define pcmk__config_err(fmt...)
#define ID(x)
Definition msg_xml.h:474
#define XML_RSC_ATTR_TARGET_ROLE
Definition msg_xml.h:249
#define PCMK_META_CLONE_NODE_MAX
Definition msg_xml.h:66
#define XML_RSC_ATTR_STICKINESS
Definition msg_xml.h:252
#define XML_ATTR_ID
Definition msg_xml.h:156
#define PCMK_META_PROMOTED_MAX
Definition msg_xml.h:70
#define XML_RSC_ATTR_INCARNATION
Definition msg_xml.h:246
#define PCMK_META_CLONE_MAX
Definition msg_xml.h:64
#define PCMK_XA_PROMOTED_NODE_MAX_LEGACY
Definition msg_xml.h:57
#define XML_CIB_TAG_GROUP
Definition msg_xml.h:236
#define XML_RSC_ATTR_ORDERED
Definition msg_xml.h:244
#define XML_RSC_ATTR_UNIQUE
Definition msg_xml.h:250
#define XML_LRM_ATTR_RC
Definition msg_xml.h:317
#define XML_CIB_TAG_RESOURCE
Definition msg_xml.h:235
#define PCMK_META_PROMOTED_NODE_MAX
Definition msg_xml.h:71
#define PCMK_XA_PROMOTED_MAX_LEGACY
Definition msg_xml.h:56
pcmk_scheduler_t * scheduler
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:447
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:302
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:522
#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:960
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:435
void pe__create_action_notifications(pcmk_resource_t *rsc, notify_data_t *n_data)
Definition pe_notif.c:943
#define status_print(fmt, args...)
int pe__clone_xml(pcmk__output_t *out, va_list args)
int pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name, size_t pairs_count,...)
Definition pe_output.c:597
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:962
gboolean order_actions(pcmk_action_t *lh_action, pcmk_action_t *rh_action, uint32_t flags)
Definition utils.c:450
void pe__set_resource_flags_recursive(pcmk_resource_t *rsc, uint64_t flags)
Definition utils.c:571
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)
#define pe_warn(fmt...)
Definition internal.h:44
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition utils.c:146
#define pe_rsc_trace(rsc, fmt, args...)
Definition internal.h:37
xmlNode * pe__failed_probe_for_rsc(const pcmk_resource_t *rsc, const char *name)
Definition utils.c:869
void common_free(pcmk_resource_t *rsc)
Definition complex.c:980
bool pe__resource_is_disabled(const pcmk_resource_t *rsc)
Definition utils.c:725
bool pcmk__rsc_filtered_by_node(pcmk_resource_t *rsc, GList *only_node)
Definition utils.c:775
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition common.c:508
@ pe_print_ncurses
Definition resources.h:244
@ pe_print_printf
Definition resources.h:245
@ pe_print_log
Definition resources.h:242
@ pe_print_xml
Definition resources.h:252
@ pe_print_clone_active
Definition resources.h:256
@ pe_print_pending
Definition resources.h:254
@ pe_print_suppres_nl
Definition resources.h:251
@ pe_print_clone_details
Definition resources.h:255
@ pe_print_html
Definition resources.h:243
@ pcmk_rsc_promotable
Whether resource can be promoted and demoted.
Definition resources.h:124
@ pcmk_rsc_unique
Whether resource is not an anonymous clone instance.
Definition resources.h:118
@ pcmk_rsc_maintenance
Whether resource, its node, or entire cluster is in maintenance mode.
Definition resources.h:181
@ pcmk_rsc_removed
Whether resource has been removed from the configuration.
Definition resources.h:103
@ pcmk_rsc_managed
Whether resource is managed.
Definition resources.h:106
@ pcmk_rsc_ignore_failure
Whether resource has an ignorable failure.
Definition resources.h:175
@ pcmk_rsc_failed
Whether resource is considered failed.
Definition resources.h:151
#define CRM_ASSERT(expr)
Definition results.h:42
@ pcmk_rc_no_output
Definition results.h:124
@ pcmk_rc_ok
Definition results.h:154
@ pcmk_rc_already
Definition results.h:146
rsc_role_e
Definition roles.h:27
@ pcmk_role_unknown
Resource role is unknown.
Definition roles.h:28
@ pcmk_role_unpromoted
Unpromoted.
Definition roles.h:31
@ pcmk_role_stopped
Stopped.
Definition roles.h:29
Cluster status and scheduling.
pcmk_resource_t * pe_find_resource(GList *rsc_list, const char *id_rh)
Definition status.c:391
pcmk_node_t * pe_find_node(const GList *node_list, const char *node_name)
Find a node by name in a list of nodes.
Definition status.c:473
const char * rsc_printable_id(const pcmk_resource_t *rsc)
Definition utils.c:546
int pcmk__numeric_strcasecmp(const char *s1, const char *s2)
Definition strings.c:1023
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:888
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:608
@ pcmk__str_star_matches
@ pcmk__str_casei
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:957
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
Definition strings.c:700
This structure contains everything that makes up a single output formatter.
Implementation of pcmk_action_t.
Definition actions.h:390
int priority
Definition actions.h:398
Implementation of pcmk_node_t.
Definition nodes.h:130
struct pe_node_shared_s * details
Basic node information.
Definition nodes.h:134
gboolean online
Whether online.
Definition nodes.h:72
const char * uname
Node name in cluster.
Definition nodes.h:68
gboolean unclean
Whether node requires fencing.
Definition nodes.h:76
Implementation of pcmk_resource_t.
Definition resources.h:399
GList * running_on
Nodes where resource may be active.
Definition resources.h:460
GHashTable * meta
Resource's meta-attributes.
Definition resources.h:471
GList * children
Resource's child resources, if any.
Definition resources.h:475
pcmk_rsc_methods_t * fns
Resource object methods.
Definition resources.h:416
GHashTable * known_on
Nodes where resource has been probed (key is node ID, not name)
Definition resources.h:463
char * id
Resource ID in configuration.
Definition resources.h:400
xmlNode * xml
Resource configuration (possibly expanded from template)
Definition resources.h:404
GHashTable * allowed_nodes
Nodes where resource may run (key is node ID, not name)
Definition resources.h:466
void * variant_opaque
Variant-specific (and private) data.
Definition resources.h:415
unsigned long long flags
Group of enum pcmk_rsc_flags.
Definition resources.h:429
char * pending_task
Pending action in history, if any.
Definition resources.h:428
xmlNode * orig_xml
Original resource configuration, if using template.
Definition resources.h:407
Implementation of pcmk_scheduler_t.
Definition scheduler.h:172
GList * nodes
Nodes in cluster.
Definition scheduler.h:195
void(* free)(pcmk_resource_t *rsc)
Free all memory used by a resource.
Definition resources.h:347
void(* print)(pcmk_resource_t *rsc, const char *pre_text, long options, void *print_data)
Definition resources.h:306
enum rsc_role_e(* state)(const pcmk_resource_t *rsc, gboolean current)
Get resource's current or assigned role.
Definition resources.h:327
pcmk_node_t *(* location)(const pcmk_resource_t *rsc, GList **list, int current)
List nodes where a resource (or any of its children) is.
Definition resources.h:339
gboolean(* is_filtered)(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent)
Check whether a given resource is in a list of resources.
Definition resources.h:369
gboolean(* active)(pcmk_resource_t *rsc, gboolean all)
Check whether a resource is active.
Definition resources.h:317
void free_xml(xmlNode *child)
Definition xml.c:783
xmlNode * copy_xml(xmlNode *src_node)
Definition xml.c:789