pacemaker 2.1.6-6fdc9deea29
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>
21
22#ifdef PCMK__COMPAT_2_0
23#define PROMOTED_INSTANCES RSC_ROLE_PROMOTED_LEGACY_S "s"
24#define UNPROMOTED_INSTANCES RSC_ROLE_UNPROMOTED_LEGACY_S "s"
25#else
26#define PROMOTED_INSTANCES RSC_ROLE_PROMOTED_S
27#define UNPROMOTED_INSTANCES RSC_ROLE_UNPROMOTED_S
28#endif
29
30typedef struct clone_variant_data_s {
31 int clone_max;
32 int clone_node_max;
33
34 int promoted_max;
35 int promoted_node_max;
36
37 int total_clones;
38
39 uint32_t flags; // Group of enum pe__clone_flags
40
41 notify_data_t *stop_notify;
42 notify_data_t *start_notify;
43 notify_data_t *demote_notify;
44 notify_data_t *promote_notify;
45
46 xmlNode *xml_obj_child;
48
49#define get_clone_variant_data(data, rsc) \
50 CRM_ASSERT((rsc != NULL) && (rsc->variant == pe_clone)); \
51 data = (clone_variant_data_t *) rsc->variant_opaque;
52
61int
63{
64 const clone_variant_data_t *clone_data = NULL;
65
66 get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
67 return clone_data->clone_max;
68}
69
78int
80{
81 const clone_variant_data_t *clone_data = NULL;
82
83 get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
84 return clone_data->clone_node_max;
85}
86
95int
97{
98 clone_variant_data_t *clone_data = NULL;
99
100 get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
101 return clone_data->promoted_max;
102}
103
112int
114{
115 clone_variant_data_t *clone_data = NULL;
116
117 get_clone_variant_data(clone_data, pe__const_top_resource(clone, false));
118 return clone_data->promoted_node_max;
119}
120
121static GList *
122sorted_hash_table_values(GHashTable *table)
123{
124 GList *retval = NULL;
125 GHashTableIter iter;
126 gpointer key, value;
127
128 g_hash_table_iter_init(&iter, table);
129 while (g_hash_table_iter_next(&iter, &key, &value)) {
130 if (!g_list_find_custom(retval, value, (GCompareFunc) strcmp)) {
131 retval = g_list_prepend(retval, (char *) value);
132 }
133 }
134
135 retval = g_list_sort(retval, (GCompareFunc) strcmp);
136 return retval;
137}
138
139static GList *
140nodes_with_status(GHashTable *table, const char *status)
141{
142 GList *retval = NULL;
143 GHashTableIter iter;
144 gpointer key, value;
145
146 g_hash_table_iter_init(&iter, table);
147 while (g_hash_table_iter_next(&iter, &key, &value)) {
148 if (!strcmp((char *) value, status)) {
149 retval = g_list_prepend(retval, key);
150 }
151 }
152
153 retval = g_list_sort(retval, (GCompareFunc) pcmk__numeric_strcasecmp);
154 return retval;
155}
156
157static GString *
158node_list_to_str(const GList *list)
159{
160 GString *retval = NULL;
161
162 for (const GList *iter = list; iter != NULL; iter = iter->next) {
163 pcmk__add_word(&retval, 1024, (const char *) iter->data);
164 }
165
166 return retval;
167}
168
169static void
170clone_header(pcmk__output_t *out, int *rc, const pe_resource_t *rsc,
171 clone_variant_data_t *clone_data, const char *desc)
172{
173 GString *attrs = NULL;
174
176 pcmk__add_separated_word(&attrs, 64, "promotable", ", ");
177 }
178
179 if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
180 pcmk__add_separated_word(&attrs, 64, "unique", ", ");
181 }
182
183 if (pe__resource_is_disabled(rsc)) {
184 pcmk__add_separated_word(&attrs, 64, "disabled", ", ");
185 }
186
188 pcmk__add_separated_word(&attrs, 64, "maintenance", ", ");
189
190 } else if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
191 pcmk__add_separated_word(&attrs, 64, "unmanaged", ", ");
192 }
193
194 if (attrs != NULL) {
195 PCMK__OUTPUT_LIST_HEADER(out, FALSE, *rc, "Clone Set: %s [%s] (%s)%s%s%s",
196 rsc->id, ID(clone_data->xml_obj_child),
197 (const char *) attrs->str, desc ? " (" : "",
198 desc ? desc : "", desc ? ")" : "");
199 g_string_free(attrs, TRUE);
200 } else {
201 PCMK__OUTPUT_LIST_HEADER(out, FALSE, *rc, "Clone Set: %s [%s]%s%s%s",
202 rsc->id, ID(clone_data->xml_obj_child),
203 desc ? " (" : "", desc ? desc : "",
204 desc ? ")" : "");
205 }
206}
207
208void
209pe__force_anon(const char *standard, pe_resource_t *rsc, const char *rid,
211{
212 if (pe_rsc_is_clone(rsc)) {
213 clone_variant_data_t *clone_data = rsc->variant_opaque;
214
215 pe_warn("Ignoring " XML_RSC_ATTR_UNIQUE " for %s because %s resources "
216 "such as %s can be used only as anonymous clones",
217 rsc->id, standard, rid);
218
219 clone_data->clone_node_max = 1;
220 clone_data->clone_max = QB_MIN(clone_data->clone_max,
221 g_list_length(data_set->nodes));
222 }
223}
224
226find_clone_instance(const pe_resource_t *rsc, const char *sub_id)
227{
228 char *child_id = NULL;
229 pe_resource_t *child = NULL;
230 const char *child_base = NULL;
231 clone_variant_data_t *clone_data = NULL;
232
233 get_clone_variant_data(clone_data, rsc);
234
235 child_base = ID(clone_data->xml_obj_child);
236 child_id = crm_strdup_printf("%s:%s", child_base, sub_id);
237 child = pe_find_resource(rsc->children, child_id);
238
239 free(child_id);
240 return child;
241}
242
245{
246 gboolean as_orphan = FALSE;
247 char *inc_num = NULL;
248 char *inc_max = NULL;
249 pe_resource_t *child_rsc = NULL;
250 xmlNode *child_copy = NULL;
251 clone_variant_data_t *clone_data = NULL;
252
253 get_clone_variant_data(clone_data, rsc);
254
255 CRM_CHECK(clone_data->xml_obj_child != NULL, return FALSE);
256
257 if (clone_data->total_clones >= clone_data->clone_max) {
258 // If we've already used all available instances, this is an orphan
259 as_orphan = TRUE;
260 }
261
262 // Allocate instance numbers in numerical order (starting at 0)
263 inc_num = pcmk__itoa(clone_data->total_clones);
264 inc_max = pcmk__itoa(clone_data->clone_max);
265
266 child_copy = copy_xml(clone_data->xml_obj_child);
267
268 crm_xml_add(child_copy, XML_RSC_ATTR_INCARNATION, inc_num);
269
270 if (pe__unpack_resource(child_copy, &child_rsc, rsc,
271 data_set) != pcmk_rc_ok) {
272 goto bail;
273 }
274/* child_rsc->globally_unique = rsc->globally_unique; */
275
276 CRM_ASSERT(child_rsc);
277 clone_data->total_clones += 1;
278 pe_rsc_trace(child_rsc, "Setting clone attributes for: %s", child_rsc->id);
279 rsc->children = g_list_append(rsc->children, child_rsc);
280 if (as_orphan) {
282 }
283
285 pe_rsc_trace(rsc, "Added %s instance %s", rsc->id, child_rsc->id);
286
287 bail:
288 free(inc_num);
289 free(inc_max);
290
291 return child_rsc;
292}
293
294gboolean
296{
297 int lpc = 0;
298 xmlNode *a_child = NULL;
299 xmlNode *xml_obj = rsc->xml;
300 clone_variant_data_t *clone_data = NULL;
301
302 const char *max_clones = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_MAX);
303 const char *max_clones_node = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_NODEMAX);
304
305 pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
306
307 clone_data = calloc(1, sizeof(clone_variant_data_t));
308 rsc->variant_opaque = clone_data;
309
311 const char *promoted_max = NULL;
312 const char *promoted_node_max = NULL;
313
314 promoted_max = g_hash_table_lookup(rsc->meta,
316 if (promoted_max == NULL) {
317 // @COMPAT deprecated since 2.0.0
318 promoted_max = g_hash_table_lookup(rsc->meta,
320 }
321
322 promoted_node_max = g_hash_table_lookup(rsc->meta,
324 if (promoted_node_max == NULL) {
325 // @COMPAT deprecated since 2.0.0
326 promoted_node_max =
327 g_hash_table_lookup(rsc->meta,
329 }
330
331 // Use 1 as default but 0 for minimum and invalid
332 if (promoted_max == NULL) {
333 clone_data->promoted_max = 1;
334 } else {
335 pcmk__scan_min_int(promoted_max, &(clone_data->promoted_max), 0);
336 }
337
338 // Use 1 as default but 0 for minimum and invalid
339 if (promoted_node_max == NULL) {
340 clone_data->promoted_node_max = 1;
341 } else {
342 pcmk__scan_min_int(promoted_node_max,
343 &(clone_data->promoted_node_max), 0);
344 }
345 }
346
347 // Implied by calloc()
348 /* clone_data->xml_obj_child = NULL; */
349
350 // Use 1 as default but 0 for minimum and invalid
351 if (max_clones_node == NULL) {
352 clone_data->clone_node_max = 1;
353 } else {
354 pcmk__scan_min_int(max_clones_node, &(clone_data->clone_node_max), 0);
355 }
356
357 /* Use number of nodes (but always at least 1, which is handy for crm_verify
358 * for a CIB without nodes) as default, but 0 for minimum and invalid
359 */
360 if (max_clones == NULL) {
361 clone_data->clone_max = QB_MAX(1, g_list_length(data_set->nodes));
362 } else {
363 pcmk__scan_min_int(max_clones, &(clone_data->clone_max), 0);
364 }
365
366 if (crm_is_true(g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_ORDERED))) {
367 clone_data->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,
368 "Clone", rsc->id,
369 clone_data->flags,
371 "pe__clone_ordered");
372 }
373
374 if ((rsc->flags & pe_rsc_unique) == 0 && clone_data->clone_node_max > 1) {
375 pcmk__config_err("Ignoring " XML_RSC_ATTR_PROMOTED_MAX " for %s "
376 "because anonymous clones support only one instance "
377 "per node", 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, pe_rsc_unique));
386 pe_rsc_trace(rsc, "\tClone is promotable: %s",
387 pe__rsc_bool_str(rsc, pe_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, pe_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, data_set) == 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, data_set) == 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(pe_resource_t * rsc, gboolean all)
443{
444 GList *gIter = rsc->children;
445
446 for (; gIter != NULL; gIter = gIter->next) {
447 pe_resource_t *child_rsc = (pe_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(pe_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 target_role = g_hash_table_lookup(((pe_resource_t*)rsc->children->data)->meta,
503 }
504 return target_role;
505}
506
507static enum rsc_role_e
508configured_role(pe_resource_t * rsc)
509{
510 const char *target_role = configured_role_str(rsc);
511
512 if (target_role) {
513 return text2role(target_role);
514 }
515 return RSC_ROLE_UNKNOWN;
516}
517
522static void
523clone_print_xml(pe_resource_t *rsc, const char *pre_text, long options,
524 void *print_data)
525{
526 char *child_text = crm_strdup_printf("%s ", pre_text);
527 const char *target_role = configured_role_str(rsc);
528 GList *gIter = rsc->children;
529
530 status_print("%s<clone ", pre_text);
531 status_print(XML_ATTR_ID "=\"%s\" ", rsc->id);
532 status_print("multi_state=\"%s\" ",
533 pe__rsc_bool_str(rsc, pe_rsc_promotable));
534 status_print("unique=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_unique));
535 status_print("managed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_managed));
536 status_print("failed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_failed));
537 status_print("failure_ignored=\"%s\" ",
538 pe__rsc_bool_str(rsc, pe_rsc_failure_ignored));
539 if (target_role) {
540 status_print("target_role=\"%s\" ", target_role);
541 }
542 status_print(">\n");
543
544 for (; gIter != NULL; gIter = gIter->next) {
545 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
546
547 child_rsc->fns->print(child_rsc, child_text, options, print_data);
548 }
549
550 status_print("%s</clone>\n", pre_text);
551 free(child_text);
552}
553
554bool
555is_set_recursive(const pe_resource_t *rsc, long long flag, bool any)
556{
557 GList *gIter;
558 bool all = !any;
559
560 if (pcmk_is_set(rsc->flags, flag)) {
561 if(any) {
562 return TRUE;
563 }
564 } else if(all) {
565 return FALSE;
566 }
567
568 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
569 if(is_set_recursive(gIter->data, flag, any)) {
570 if(any) {
571 return TRUE;
572 }
573
574 } else if(all) {
575 return FALSE;
576 }
577 }
578
579 if(all) {
580 return TRUE;
581 }
582 return FALSE;
583}
584
589void
590clone_print(pe_resource_t *rsc, const char *pre_text, long options,
591 void *print_data)
592{
593 GString *list_text = NULL;
594 char *child_text = NULL;
595 GString *stopped_list = NULL;
596
597 GList *promoted_list = NULL;
598 GList *started_list = NULL;
599 GList *gIter = rsc->children;
600
601 clone_variant_data_t *clone_data = NULL;
602 int active_instances = 0;
603
604 if (pre_text == NULL) {
605 pre_text = " ";
606 }
607
608 if (options & pe_print_xml) {
609 clone_print_xml(rsc, pre_text, options, print_data);
610 return;
611 }
612
613 get_clone_variant_data(clone_data, rsc);
614
615 child_text = crm_strdup_printf("%s ", pre_text);
616
617 status_print("%sClone Set: %s [%s]%s%s%s",
618 pre_text ? pre_text : "", rsc->id, ID(clone_data->xml_obj_child),
619 pcmk_is_set(rsc->flags, pe_rsc_promotable)? " (promotable)" : "",
620 pcmk_is_set(rsc->flags, pe_rsc_unique)? " (unique)" : "",
621 pcmk_is_set(rsc->flags, pe_rsc_managed)? "" : " (unmanaged)");
622
623 if (options & pe_print_html) {
624 status_print("\n<ul>\n");
625
626 } else if ((options & pe_print_log) == 0) {
627 status_print("\n");
628 }
629
630 for (; gIter != NULL; gIter = gIter->next) {
631 gboolean print_full = FALSE;
632 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
633 gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
634
635 if (options & pe_print_clone_details) {
636 print_full = TRUE;
637 }
638
639 if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
640 // Print individual instance when unique (except stopped orphans)
641 if (partially_active || !pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
642 print_full = TRUE;
643 }
644
645 // Everything else in this block is for anonymous clones
646
647 } else if (pcmk_is_set(options, pe_print_pending)
648 && (child_rsc->pending_task != NULL)
649 && strcmp(child_rsc->pending_task, "probe")) {
650 // Print individual instance when non-probe action is pending
651 print_full = TRUE;
652
653 } else if (partially_active == FALSE) {
654 // List stopped instances when requested (except orphans)
655 if (!pcmk_is_set(child_rsc->flags, pe_rsc_orphan)
656 && !pcmk_is_set(options, pe_print_clone_active)) {
657
658 pcmk__add_word(&stopped_list, 1024, child_rsc->id);
659 }
660
661 } else if (is_set_recursive(child_rsc, pe_rsc_orphan, TRUE)
662 || is_set_recursive(child_rsc, pe_rsc_managed, FALSE) == FALSE
663 || is_set_recursive(child_rsc, pe_rsc_failed, TRUE)) {
664
665 // Print individual instance when active orphaned/unmanaged/failed
666 print_full = TRUE;
667
668 } else if (child_rsc->fns->active(child_rsc, TRUE)) {
669 // Instance of fully active anonymous clone
670
671 pe_node_t *location = child_rsc->fns->location(child_rsc, NULL, TRUE);
672
673 if (location) {
674 // Instance is active on a single node
675
676 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
677
678 if (location->details->online == FALSE && location->details->unclean) {
679 print_full = TRUE;
680
681 } else if (a_role > RSC_ROLE_UNPROMOTED) {
682 promoted_list = g_list_append(promoted_list, location);
683
684 } else {
685 started_list = g_list_append(started_list, location);
686 }
687
688 } else {
689 /* uncolocated group - bleh */
690 print_full = TRUE;
691 }
692
693 } else {
694 // Instance of partially active anonymous clone
695 print_full = TRUE;
696 }
697
698 if (print_full) {
699 if (options & pe_print_html) {
700 status_print("<li>\n");
701 }
702 child_rsc->fns->print(child_rsc, child_text, options, print_data);
703 if (options & pe_print_html) {
704 status_print("</li>\n");
705 }
706 }
707 }
708
709 /* Promoted */
710 promoted_list = g_list_sort(promoted_list, pe__cmp_node_name);
711 for (gIter = promoted_list; gIter; gIter = gIter->next) {
712 pe_node_t *host = gIter->data;
713
714 pcmk__add_word(&list_text, 1024, host->details->uname);
715 active_instances++;
716 }
717
718 if (list_text != NULL) {
719 short_print((const char *) list_text->str, child_text,
720 PROMOTED_INSTANCES, NULL, options, print_data);
721 g_string_truncate(list_text, 0);
722 }
723 g_list_free(promoted_list);
724
725 /* Started/Unpromoted */
726 started_list = g_list_sort(started_list, pe__cmp_node_name);
727 for (gIter = started_list; gIter; gIter = gIter->next) {
728 pe_node_t *host = gIter->data;
729
730 pcmk__add_word(&list_text, 1024, host->details->uname);
731 active_instances++;
732 }
733
734 if (list_text != NULL) {
736 enum rsc_role_e role = configured_role(rsc);
737
738 if (role == RSC_ROLE_UNPROMOTED) {
739 short_print((const char *) list_text->str, child_text,
740 UNPROMOTED_INSTANCES " (target-role)", NULL,
741 options, print_data);
742 } else {
743 short_print((const char *) list_text->str, child_text,
744 UNPROMOTED_INSTANCES, NULL, options, print_data);
745 }
746
747 } else {
748 short_print((const char *) list_text->str, child_text, "Started",
749 NULL, options, print_data);
750 }
751 }
752
753 g_list_free(started_list);
754
755 if (!pcmk_is_set(options, pe_print_clone_active)) {
756 const char *state = "Stopped";
757 enum rsc_role_e role = configured_role(rsc);
758
759 if (role == RSC_ROLE_STOPPED) {
760 state = "Stopped (disabled)";
761 }
762
764 && (clone_data->clone_max > active_instances)) {
765
766 GList *nIter;
767 GList *list = g_hash_table_get_values(rsc->allowed_nodes);
768
769 /* Custom stopped list for non-unique clones */
770 if (stopped_list != NULL) {
771 g_string_truncate(stopped_list, 0);
772 }
773
774 if (list == NULL) {
775 /* Clusters with symmetrical=false haven't calculated allowed_nodes yet
776 * If we've not probed for them yet, the Stopped list will be empty
777 */
778 list = g_hash_table_get_values(rsc->known_on);
779 }
780
781 list = g_list_sort(list, pe__cmp_node_name);
782 for (nIter = list; nIter != NULL; nIter = nIter->next) {
783 pe_node_t *node = (pe_node_t *)nIter->data;
784
785 if (pe_find_node(rsc->running_on, node->details->uname) == NULL) {
786 pcmk__add_word(&stopped_list, 1024, node->details->uname);
787 }
788 }
789 g_list_free(list);
790 }
791
792 if (stopped_list != NULL) {
793 short_print((const char *) stopped_list->str, child_text, state,
794 NULL, options, print_data);
795 }
796 }
797
798 if (options & pe_print_html) {
799 status_print("</ul>\n");
800 }
801
802 if (list_text != NULL) {
803 g_string_free(list_text, TRUE);
804 }
805
806 if (stopped_list != NULL) {
807 g_string_free(stopped_list, TRUE);
808 }
809 free(child_text);
810}
811
812PCMK__OUTPUT_ARGS("clone", "uint32_t", "pe_resource_t *", "GList *", "GList *")
813int
814pe__clone_xml(pcmk__output_t *out, va_list args)
815{
816 uint32_t show_opts = va_arg(args, uint32_t);
817 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
818 GList *only_node = va_arg(args, GList *);
819 GList *only_rsc = va_arg(args, GList *);
820
821
822 const char *desc = NULL;
823 GList *gIter = rsc->children;
824 GList *all = NULL;
825 int rc = pcmk_rc_no_output;
826 gboolean printed_header = FALSE;
827 gboolean print_everything = TRUE;
828
829
830
831 if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
832 return rc;
833 }
834
835 print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
836 (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
837
838 all = g_list_prepend(all, (gpointer) "*");
839
840 for (; gIter != NULL; gIter = gIter->next) {
841 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
842
843 if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
844 continue;
845 }
846
847 if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
848 continue;
849 }
850
851 if (!printed_header) {
852 printed_header = TRUE;
853
854 desc = pe__resource_description(rsc, show_opts);
855
856 rc = pe__name_and_nvpairs_xml(out, true, "clone", 10,
857 "id", rsc->id,
858 "multi_state", pe__rsc_bool_str(rsc, pe_rsc_promotable),
859 "unique", pe__rsc_bool_str(rsc, pe_rsc_unique),
860 "maintenance", pe__rsc_bool_str(rsc, pe_rsc_maintenance),
861 "managed", pe__rsc_bool_str(rsc, pe_rsc_managed),
862 "disabled", pcmk__btoa(pe__resource_is_disabled(rsc)),
863 "failed", pe__rsc_bool_str(rsc, pe_rsc_failed),
864 "failure_ignored", pe__rsc_bool_str(rsc, pe_rsc_failure_ignored),
865 "target_role", configured_role_str(rsc),
866 "description", desc);
867 CRM_ASSERT(rc == pcmk_rc_ok);
868 }
869
870 out->message(out, crm_map_element_name(child_rsc->xml), show_opts,
871 child_rsc, only_node, all);
872 }
873
874 if (printed_header) {
876 }
877
878 g_list_free(all);
879 return rc;
880}
881
882PCMK__OUTPUT_ARGS("clone", "uint32_t", "pe_resource_t *", "GList *", "GList *")
883int
885{
886 uint32_t show_opts = va_arg(args, uint32_t);
887 pe_resource_t *rsc = va_arg(args, pe_resource_t *);
888 GList *only_node = va_arg(args, GList *);
889 GList *only_rsc = va_arg(args, GList *);
890
891 GHashTable *stopped = NULL;
892
893 GString *list_text = NULL;
894
895 GList *promoted_list = NULL;
896 GList *started_list = NULL;
897 GList *gIter = rsc->children;
898
899 const char *desc = NULL;
900
901 clone_variant_data_t *clone_data = NULL;
902 int active_instances = 0;
903 int rc = pcmk_rc_no_output;
904 gboolean print_everything = TRUE;
905
906 desc = pe__resource_description(rsc, show_opts);
907
908 get_clone_variant_data(clone_data, rsc);
909
910 if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
911 return rc;
912 }
913
914 print_everything = pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches) ||
915 (strstr(rsc->id, ":") != NULL && pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches));
916
917 for (; gIter != NULL; gIter = gIter->next) {
918 gboolean print_full = FALSE;
919 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
920 gboolean partially_active = child_rsc->fns->active(child_rsc, FALSE);
921
922 if (pcmk__rsc_filtered_by_node(child_rsc, only_node)) {
923 continue;
924 }
925
926 if (child_rsc->fns->is_filtered(child_rsc, only_rsc, print_everything)) {
927 continue;
928 }
929
930 if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
931 print_full = TRUE;
932 }
933
934 if (pcmk_is_set(rsc->flags, pe_rsc_unique)) {
935 // Print individual instance when unique (except stopped orphans)
936 if (partially_active || !pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
937 print_full = TRUE;
938 }
939
940 // Everything else in this block is for anonymous clones
941
942 } else if (pcmk_is_set(show_opts, pcmk_show_pending)
943 && (child_rsc->pending_task != NULL)
944 && strcmp(child_rsc->pending_task, "probe")) {
945 // Print individual instance when non-probe action is pending
946 print_full = TRUE;
947
948 } else if (partially_active == FALSE) {
949 // List stopped instances when requested (except orphans)
950 if (!pcmk_is_set(child_rsc->flags, pe_rsc_orphan)
951 && !pcmk_is_set(show_opts, pcmk_show_clone_detail)
952 && pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
953 if (stopped == NULL) {
954 stopped = pcmk__strkey_table(free, free);
955 }
956 g_hash_table_insert(stopped, strdup(child_rsc->id), strdup("Stopped"));
957 }
958
959 } else if (is_set_recursive(child_rsc, pe_rsc_orphan, TRUE)
960 || is_set_recursive(child_rsc, pe_rsc_managed, FALSE) == FALSE
961 || is_set_recursive(child_rsc, pe_rsc_failed, TRUE)) {
962
963 // Print individual instance when active orphaned/unmanaged/failed
964 print_full = TRUE;
965
966 } else if (child_rsc->fns->active(child_rsc, TRUE)) {
967 // Instance of fully active anonymous clone
968
969 pe_node_t *location = child_rsc->fns->location(child_rsc, NULL, TRUE);
970
971 if (location) {
972 // Instance is active on a single node
973
974 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, TRUE);
975
976 if (location->details->online == FALSE && location->details->unclean) {
977 print_full = TRUE;
978
979 } else if (a_role > RSC_ROLE_UNPROMOTED) {
980 promoted_list = g_list_append(promoted_list, location);
981
982 } else {
983 started_list = g_list_append(started_list, location);
984 }
985
986 } else {
987 /* uncolocated group - bleh */
988 print_full = TRUE;
989 }
990
991 } else {
992 // Instance of partially active anonymous clone
993 print_full = TRUE;
994 }
995
996 if (print_full) {
997 GList *all = NULL;
998
999 clone_header(out, &rc, rsc, clone_data, desc);
1000
1001 /* Print every resource that's a child of this clone. */
1002 all = g_list_prepend(all, (gpointer) "*");
1003 out->message(out, crm_map_element_name(child_rsc->xml), show_opts,
1004 child_rsc, only_node, all);
1005 g_list_free(all);
1006 }
1007 }
1008
1009 if (pcmk_is_set(show_opts, pcmk_show_clone_detail)) {
1010 PCMK__OUTPUT_LIST_FOOTER(out, rc);
1011 return pcmk_rc_ok;
1012 }
1013
1014 /* Promoted */
1015 promoted_list = g_list_sort(promoted_list, pe__cmp_node_name);
1016 for (gIter = promoted_list; gIter; gIter = gIter->next) {
1017 pe_node_t *host = gIter->data;
1018
1019 if (!pcmk__str_in_list(host->details->uname, only_node,
1021 continue;
1022 }
1023
1024 pcmk__add_word(&list_text, 1024, host->details->uname);
1025 active_instances++;
1026 }
1027 g_list_free(promoted_list);
1028
1029 if ((list_text != NULL) && (list_text->len > 0)) {
1030 clone_header(out, &rc, rsc, clone_data, desc);
1031
1032 out->list_item(out, NULL, PROMOTED_INSTANCES ": [ %s ]",
1033 (const char *) list_text->str);
1034 g_string_truncate(list_text, 0);
1035 }
1036
1037 /* Started/Unpromoted */
1038 started_list = g_list_sort(started_list, pe__cmp_node_name);
1039 for (gIter = started_list; gIter; gIter = gIter->next) {
1040 pe_node_t *host = gIter->data;
1041
1042 if (!pcmk__str_in_list(host->details->uname, only_node,
1044 continue;
1045 }
1046
1047 pcmk__add_word(&list_text, 1024, host->details->uname);
1048 active_instances++;
1049 }
1050 g_list_free(started_list);
1051
1052 if ((list_text != NULL) && (list_text->len > 0)) {
1053 clone_header(out, &rc, rsc, clone_data, desc);
1054
1055 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
1056 enum rsc_role_e role = configured_role(rsc);
1057
1058 if (role == RSC_ROLE_UNPROMOTED) {
1059 out->list_item(out, NULL,
1060 UNPROMOTED_INSTANCES " (target-role): [ %s ]",
1061 (const char *) list_text->str);
1062 } else {
1063 out->list_item(out, NULL, UNPROMOTED_INSTANCES ": [ %s ]",
1064 (const char *) list_text->str);
1065 }
1066
1067 } else {
1068 out->list_item(out, NULL, "Started: [ %s ]",
1069 (const char *) list_text->str);
1070 }
1071 }
1072
1073 if (list_text != NULL) {
1074 g_string_free(list_text, TRUE);
1075 }
1076
1077 if (pcmk_is_set(show_opts, pcmk_show_inactive_rscs)) {
1078 if (!pcmk_is_set(rsc->flags, pe_rsc_unique)
1079 && (clone_data->clone_max > active_instances)) {
1080
1081 GList *nIter;
1082 GList *list = g_hash_table_get_values(rsc->allowed_nodes);
1083
1084 /* Custom stopped table for non-unique clones */
1085 if (stopped != NULL) {
1086 g_hash_table_destroy(stopped);
1087 stopped = NULL;
1088 }
1089
1090 if (list == NULL) {
1091 /* Clusters with symmetrical=false haven't calculated allowed_nodes yet
1092 * If we've not probed for them yet, the Stopped list will be empty
1093 */
1094 list = g_hash_table_get_values(rsc->known_on);
1095 }
1096
1097 list = g_list_sort(list, pe__cmp_node_name);
1098 for (nIter = list; nIter != NULL; nIter = nIter->next) {
1099 pe_node_t *node = (pe_node_t *)nIter->data;
1100
1101 if (pe_find_node(rsc->running_on, node->details->uname) == NULL &&
1102 pcmk__str_in_list(node->details->uname, only_node,
1104 xmlNode *probe_op = pe__failed_probe_for_rsc(rsc, node->details->uname);
1105 const char *state = "Stopped";
1106
1107 if (configured_role(rsc) == RSC_ROLE_STOPPED) {
1108 state = "Stopped (disabled)";
1109 }
1110
1111 if (stopped == NULL) {
1112 stopped = pcmk__strkey_table(free, free);
1113 }
1114 if (probe_op != NULL) {
1115 int rc;
1116
1118 g_hash_table_insert(stopped, strdup(node->details->uname),
1119 crm_strdup_printf("Stopped (%s)", services_ocf_exitcode_str(rc)));
1120 } else {
1121 g_hash_table_insert(stopped, strdup(node->details->uname),
1122 strdup(state));
1123 }
1124 }
1125 }
1126 g_list_free(list);
1127 }
1128
1129 if (stopped != NULL) {
1130 GList *list = sorted_hash_table_values(stopped);
1131
1132 clone_header(out, &rc, rsc, clone_data, desc);
1133
1134 for (GList *status_iter = list; status_iter != NULL; status_iter = status_iter->next) {
1135 const char *status = status_iter->data;
1136 GList *nodes = nodes_with_status(stopped, status);
1137 GString *nodes_str = node_list_to_str(nodes);
1138
1139 if (nodes_str != NULL) {
1140 if (nodes_str->len > 0) {
1141 out->list_item(out, NULL, "%s: [ %s ]", status,
1142 (const char *) nodes_str->str);
1143 }
1144 g_string_free(nodes_str, TRUE);
1145 }
1146
1147 g_list_free(nodes);
1148 }
1149
1150 g_list_free(list);
1151 g_hash_table_destroy(stopped);
1152
1153 /* If there are no instances of this clone (perhaps because there are no
1154 * nodes configured), simply output the clone header by itself. This can
1155 * come up in PCS testing.
1156 */
1157 } else if (active_instances == 0) {
1158 clone_header(out, &rc, rsc, clone_data, desc);
1159 PCMK__OUTPUT_LIST_FOOTER(out, rc);
1160 return rc;
1161 }
1162 }
1163
1164 PCMK__OUTPUT_LIST_FOOTER(out, rc);
1165 return rc;
1166}
1167
1168void
1170{
1171 clone_variant_data_t *clone_data = NULL;
1172
1173 get_clone_variant_data(clone_data, rsc);
1174
1175 pe_rsc_trace(rsc, "Freeing %s", rsc->id);
1176
1177 for (GList *gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
1178 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1179
1180 CRM_ASSERT(child_rsc);
1181 pe_rsc_trace(child_rsc, "Freeing child %s", child_rsc->id);
1182 free_xml(child_rsc->xml);
1183 child_rsc->xml = NULL;
1184 /* There could be a saved unexpanded xml */
1185 free_xml(child_rsc->orig_xml);
1186 child_rsc->orig_xml = NULL;
1187 child_rsc->fns->free(child_rsc);
1188 }
1189
1190 g_list_free(rsc->children);
1191
1192 if (clone_data) {
1193 CRM_ASSERT(clone_data->demote_notify == NULL);
1194 CRM_ASSERT(clone_data->stop_notify == NULL);
1195 CRM_ASSERT(clone_data->start_notify == NULL);
1196 CRM_ASSERT(clone_data->promote_notify == NULL);
1197 }
1198
1199 common_free(rsc);
1200}
1201
1202enum rsc_role_e
1203clone_resource_state(const pe_resource_t * rsc, gboolean current)
1204{
1205 enum rsc_role_e clone_role = RSC_ROLE_UNKNOWN;
1206 GList *gIter = rsc->children;
1207
1208 for (; gIter != NULL; gIter = gIter->next) {
1209 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1210 enum rsc_role_e a_role = child_rsc->fns->state(child_rsc, current);
1211
1212 if (a_role > clone_role) {
1213 clone_role = a_role;
1214 }
1215 }
1216
1217 pe_rsc_trace(rsc, "%s role: %s", rsc->id, role2text(clone_role));
1218 return clone_role;
1219}
1220
1228bool
1231{
1232 if (pe_rsc_is_clone(rsc)) {
1233 clone_variant_data_t *clone_data = rsc->variant_opaque;
1234
1235 if (clone_data->clone_max == g_list_length(data_set->nodes)) {
1236 return TRUE;
1237 }
1238 }
1239 return FALSE;
1240}
1241
1242gboolean
1243pe__clone_is_filtered(const pe_resource_t *rsc, GList *only_rsc,
1244 gboolean check_parent)
1245{
1246 gboolean passes = FALSE;
1247 clone_variant_data_t *clone_data = NULL;
1248
1250 passes = TRUE;
1251 } else {
1252 get_clone_variant_data(clone_data, rsc);
1253 passes = pcmk__str_in_list(ID(clone_data->xml_obj_child), only_rsc, pcmk__str_star_matches);
1254
1255 if (!passes) {
1256 for (const GList *iter = rsc->children;
1257 iter != NULL; iter = iter->next) {
1258
1259 const pe_resource_t *child_rsc = NULL;
1260
1261 child_rsc = (const pe_resource_t *) iter->data;
1262 if (!child_rsc->fns->is_filtered(child_rsc, only_rsc, FALSE)) {
1263 passes = TRUE;
1264 break;
1265 }
1266 }
1267 }
1268 }
1269 return !passes;
1270}
1271
1272const char *
1274{
1275 clone_variant_data_t *clone_data = NULL;
1276 get_clone_variant_data(clone_data, rsc);
1277 return ID(clone_data->xml_obj_child);
1278}
1279
1288bool
1290{
1291 clone_variant_data_t *clone_data = NULL;
1292
1293 get_clone_variant_data(clone_data, clone);
1294 return pcmk_is_set(clone_data->flags, pe__clone_ordered);
1295}
1296
1307int
1309{
1310 clone_variant_data_t *clone_data = NULL;
1311
1312 get_clone_variant_data(clone_data, clone);
1313 if (pcmk_is_set(clone_data->flags, flag)) {
1314 return pcmk_rc_already;
1315 }
1316 clone_data->flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,
1317 "Clone", clone->id,
1318 clone_data->flags, flag, "flag");
1319 return pcmk_rc_ok;
1320}
1321
1330void
1332 bool any_demoting)
1333{
1334 pe_action_t *action = NULL;
1335 pe_action_t *action_complete = NULL;
1336 clone_variant_data_t *clone_data = NULL;
1337
1338 get_clone_variant_data(clone_data, clone);
1339
1340 // Create a "promote" action for the clone itself
1341 action = pe__new_rsc_pseudo_action(clone, RSC_PROMOTE, !any_promoting,
1342 true);
1343
1344 // Create a "promoted" action for when all promotions are done
1345 action_complete = pe__new_rsc_pseudo_action(clone, RSC_PROMOTED,
1346 !any_promoting, true);
1347 action_complete->priority = INFINITY;
1348
1349 // Create notification pseudo-actions for promotion
1350 if (clone_data->promote_notify == NULL) {
1351 clone_data->promote_notify = pe__action_notif_pseudo_ops(clone,
1353 action,
1354 action_complete);
1355 }
1356
1357 // Create a "demote" action for the clone itself
1358 action = pe__new_rsc_pseudo_action(clone, RSC_DEMOTE, !any_demoting, true);
1359
1360 // Create a "demoted" action for when all demotions are done
1361 action_complete = pe__new_rsc_pseudo_action(clone, RSC_DEMOTED,
1362 !any_demoting, true);
1363 action_complete->priority = INFINITY;
1364
1365 // Create notification pseudo-actions for demotion
1366 if (clone_data->demote_notify == NULL) {
1367 clone_data->demote_notify = pe__action_notif_pseudo_ops(clone,
1368 RSC_DEMOTE,
1369 action,
1370 action_complete);
1371
1372 if (clone_data->promote_notify != NULL) {
1373 order_actions(clone_data->stop_notify->post_done,
1374 clone_data->promote_notify->pre,
1376 order_actions(clone_data->start_notify->post_done,
1377 clone_data->promote_notify->pre,
1379 order_actions(clone_data->demote_notify->post_done,
1380 clone_data->promote_notify->pre,
1382 order_actions(clone_data->demote_notify->post_done,
1383 clone_data->start_notify->pre,
1385 order_actions(clone_data->demote_notify->post_done,
1386 clone_data->stop_notify->pre,
1388 }
1389 }
1390}
1391
1398void
1400{
1401 clone_variant_data_t *clone_data = NULL;
1402
1403 get_clone_variant_data(clone_data, clone);
1404
1405 pe__create_action_notifications(clone, clone_data->start_notify);
1406 pe__create_action_notifications(clone, clone_data->stop_notify);
1407 pe__create_action_notifications(clone, clone_data->promote_notify);
1408 pe__create_action_notifications(clone, clone_data->demote_notify);
1409}
1410
1417void
1419{
1420 clone_variant_data_t *clone_data = NULL;
1421
1422 get_clone_variant_data(clone_data, clone);
1423
1424 pe__free_action_notification_data(clone_data->demote_notify);
1425 clone_data->demote_notify = NULL;
1426
1427 pe__free_action_notification_data(clone_data->stop_notify);
1428 clone_data->stop_notify = NULL;
1429
1430 pe__free_action_notification_data(clone_data->start_notify);
1431 clone_data->start_notify = NULL;
1432
1433 pe__free_action_notification_data(clone_data->promote_notify);
1434 clone_data->promote_notify = NULL;
1435}
1436
1447void
1449 pe_action_t *start, pe_action_t *started,
1450 pe_action_t *stop, pe_action_t *stopped)
1451{
1452 clone_variant_data_t *clone_data = NULL;
1453
1454 get_clone_variant_data(clone_data, clone);
1455
1456 if (clone_data->start_notify == NULL) {
1457 clone_data->start_notify = pe__action_notif_pseudo_ops(clone, RSC_START,
1458 start, started);
1459 }
1460
1461 if (clone_data->stop_notify == NULL) {
1462 clone_data->stop_notify = pe__action_notif_pseudo_ops(clone, RSC_STOP,
1463 stop, stopped);
1464 if ((clone_data->start_notify != NULL)
1465 && (clone_data->stop_notify != NULL)) {
1466 order_actions(clone_data->stop_notify->post_done,
1467 clone_data->start_notify->pre, pe_order_optional);
1468 }
1469 }
1470}
pe_resource_t * pe__create_clone_child(pe_resource_t *rsc, pe_working_set_t *data_set)
Definition clone.c:244
int pe__clone_xml(pcmk__output_t *out, va_list args)
Definition clone.c:814
bool pe__clone_is_ordered(const pe_resource_t *clone)
Definition clone.c:1289
void pe__force_anon(const char *standard, pe_resource_t *rsc, const char *rid, pe_working_set_t *data_set)
Definition clone.c:209
void clone_print(pe_resource_t *rsc, const char *pre_text, long options, void *print_data)
Definition clone.c:590
void pe__create_clone_notif_pseudo_ops(pe_resource_t *clone, pe_action_t *start, pe_action_t *started, pe_action_t *stop, pe_action_t *stopped)
Definition clone.c:1448
#define get_clone_variant_data(data, rsc)
Definition clone.c:49
bool is_set_recursive(const pe_resource_t *rsc, long long flag, bool any)
Definition clone.c:555
gboolean pe__clone_is_filtered(const pe_resource_t *rsc, GList *only_rsc, gboolean check_parent)
Definition clone.c:1243
void pe__create_promotable_pseudo_ops(pe_resource_t *clone, bool any_promoting, bool any_demoting)
Definition clone.c:1331
gboolean clone_active(pe_resource_t *rsc, gboolean all)
Definition clone.c:442
const char * pe__clone_child_id(const pe_resource_t *rsc)
Definition clone.c:1273
enum rsc_role_e clone_resource_state(const pe_resource_t *rsc, gboolean current)
Definition clone.c:1203
void pe__create_clone_notifications(pe_resource_t *clone)
Definition clone.c:1399
void clone_free(pe_resource_t *rsc)
Definition clone.c:1169
int pe__clone_default(pcmk__output_t *out, va_list args)
Definition clone.c:884
bool pe__is_universal_clone(const pe_resource_t *rsc, const pe_working_set_t *data_set)
Definition clone.c:1229
int pe__clone_node_max(const pe_resource_t *clone)
Definition clone.c:79
struct clone_variant_data_s clone_variant_data_t
gboolean clone_unpack(pe_resource_t *rsc, pe_working_set_t *data_set)
Definition clone.c:295
int pe__clone_max(const pe_resource_t *clone)
Definition clone.c:62
int pe__clone_promoted_node_max(const pe_resource_t *clone)
Definition clone.c:113
int pe__set_clone_flag(pe_resource_t *clone, enum pe__clone_flags flag)
Definition clone.c:1308
#define PROMOTED_INSTANCES
Definition clone.c:26
void pe__free_clone_notification_data(pe_resource_t *clone)
Definition clone.c:1418
int pe__clone_promoted_max(const pe_resource_t *clone)
Definition clone.c:96
#define UNPROMOTED_INSTANCES
Definition clone.c:27
pe_resource_t * find_clone_instance(const pe_resource_t *rsc, const char *sub_id)
Definition clone.c:226
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:121
@ pe_print_ncurses
Definition common.h:122
@ pe_print_printf
Definition common.h:123
@ pe_print_log
Definition common.h:120
@ pe_print_xml
Definition common.h:130
@ pe_print_clone_active
Definition common.h:134
@ pe_print_pending
Definition common.h:132
@ pe_print_suppres_nl
Definition common.h:129
@ pe_print_clone_details
Definition common.h:133
@ pe_print_html
Definition common.h:121
const char * role2text(enum rsc_role_e role)
Definition common.c:450
rsc_role_e
Possible roles that a resource can be in.
Definition common.h:92
@ RSC_ROLE_STOPPED
Definition common.h:94
@ RSC_ROLE_UNKNOWN
Definition common.h:93
@ RSC_ROLE_UNPROMOTED
Definition common.h:96
enum rsc_role_e text2role(const char *role)
Definition common.c:479
int pe__unpack_resource(xmlNode *xml_obj, pe_resource_t **rsc, pe_resource_t *parent, pe_working_set_t *data_set)
Definition complex.c:590
pcmk__cpg_host_t host
Definition cpg.c:4
enum crm_ais_msg_types type
Definition cpg.c:3
#define RSC_PROMOTE
Definition crm.h:205
#define RSC_DEMOTE
Definition crm.h:207
#define RSC_START
Definition crm.h:199
#define INFINITY
Definition crm.h:99
#define RSC_STOP
Definition crm.h:202
#define RSC_PROMOTED
Definition crm.h:206
#define RSC_DEMOTED
Definition crm.h:208
#define CRM_CHECK(expr, failure_action)
Definition logging.h:235
#define LOG_TRACE
Definition logging.h:37
#define pcmk__config_err(fmt...)
#define ID(x)
Definition msg_xml.h:480
#define XML_RSC_ATTR_TARGET_ROLE
Definition msg_xml.h:249
#define XML_RSC_ATTR_PROMOTED_MAX
Definition msg_xml.h:246
#define XML_RSC_ATTR_STICKINESS
Definition msg_xml.h:252
#define XML_ATTR_ID
Definition msg_xml.h:147
#define XML_RSC_ATTR_INCARNATION_MAX
Definition msg_xml.h:242
#define XML_RSC_ATTR_INCARNATION
Definition msg_xml.h:241
#define XML_RSC_ATTR_PROMOTED_NODEMAX
Definition msg_xml.h:247
#define PCMK_XA_PROMOTED_NODE_MAX_LEGACY
Definition msg_xml.h:55
#define XML_CIB_TAG_GROUP
Definition msg_xml.h:231
#define XML_RSC_ATTR_ORDERED
Definition msg_xml.h:239
#define XML_RSC_ATTR_UNIQUE
Definition msg_xml.h:250
#define XML_LRM_ATTR_RC
Definition msg_xml.h:326
#define XML_RSC_ATTR_INCARNATION_NODEMAX
Definition msg_xml.h:244
#define XML_CIB_TAG_RESOURCE
Definition msg_xml.h:230
#define PCMK_XA_PROMOTED_MAX_LEGACY
Definition msg_xml.h:54
pe_working_set_t * data_set
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:496
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:518
#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__create_action_notifications(pe_resource_t *rsc, notify_data_t *n_data)
Definition pe_notif.c:932
notify_data_t * pe__action_notif_pseudo_ops(pe_resource_t *rsc, const char *task, pe_action_t *action, pe_action_t *complete)
Definition pe_notif.c:431
void pe__free_action_notification_data(notify_data_t *n_data)
Definition pe_notif.c:949
#define status_print(fmt, args...)
#define pe_rsc_managed
Definition pe_types.h:273
@ pe_order_optional
Definition pe_types.h:508
#define pe_rsc_unique
Definition pe_types.h:278
#define pe_rsc_orphan
Definition pe_types.h:272
#define pe_rsc_maintenance
Definition pe_types.h:308
#define pe_rsc_failed
Definition pe_types.h:292
#define pe_rsc_failure_ignored
Definition pe_types.h:306
#define pe_rsc_promotable
Definition pe_types.h:280
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:568
bool pe__resource_is_disabled(const pe_resource_t *rsc)
Definition utils.c:755
const char * pe__resource_description(const pe_resource_t *rsc, uint32_t show_opts)
Definition pe_output.c:19
void pe__set_resource_flags_recursive(pe_resource_t *rsc, uint64_t flags)
Definition utils.c:607
bool pcmk__rsc_filtered_by_node(pe_resource_t *rsc, GList *only_node)
Definition utils.c:805
xmlNode * pe__failed_probe_for_rsc(const pe_resource_t *rsc, const char *name)
Definition utils.c:896
pe_action_t * pe__new_rsc_pseudo_action(pe_resource_t *rsc, const char *task, bool optional, bool runnable)
#define pe_warn(fmt...)
Definition internal.h:57
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition utils.c:185
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition utils.c:488
#define pe_rsc_trace(rsc, fmt, args...)
Definition internal.h:50
pe__clone_flags
Definition internal.h:24
@ pe__clone_ordered
Definition internal.h:26
const pe_resource_t * pe__const_top_resource(const pe_resource_t *rsc, bool include_bundle)
Definition complex.c:947
void common_free(pe_resource_t *rsc)
Definition complex.c:964
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition common.c:500
#define CRM_ASSERT(expr)
Definition results.h:42
@ pcmk_rc_no_output
Definition results.h:121
@ pcmk_rc_ok
Definition results.h:151
@ pcmk_rc_already
Definition results.h:143
Cluster status and scheduling.
pe_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 pe_resource_t *rsc)
Definition utils.c:583
pe_resource_t * pe_find_resource(GList *rsc_list, const char *id_rh)
Definition status.c:391
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:611
@ 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:703
This structure contains everything that makes up a single output formatter.
struct pe_node_shared_s * details
Definition pe_types.h:268
gboolean online
Definition pe_types.h:236
const char * uname
Definition pe_types.h:232
gboolean unclean
Definition pe_types.h:240
GList * running_on
Definition pe_types.h:398
GHashTable * meta
Definition pe_types.h:405
GList * children
Definition pe_types.h:409
GHashTable * known_on
Definition pe_types.h:399
xmlNode * xml
Definition pe_types.h:349
GHashTable * allowed_nodes
Definition pe_types.h:400
void * variant_opaque
Definition pe_types.h:357
unsigned long long flags
Definition pe_types.h:373
char * pending_task
Definition pe_types.h:371
xmlNode * orig_xml
Definition pe_types.h:350
resource_object_functions_t * fns
Definition pe_types.h:358
gboolean(* active)(pe_resource_t *, gboolean)
Definition pe_types.h:53
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition pe_types.h:55
gboolean(* is_filtered)(const pe_resource_t *, GList *, gboolean)
Definition pe_types.h:58
enum rsc_role_e(* state)(const pe_resource_t *, gboolean)
Definition pe_types.h:54
void(* free)(pe_resource_t *)
Definition pe_types.h:56
void(* print)(pe_resource_t *, const char *, long, void *)
Definition pe_types.h:52
void free_xml(xmlNode *child)
Definition xml.c:813
xmlNode * copy_xml(xmlNode *src_node)
Definition xml.c:819