pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_sched_bundle.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2025 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU General Public License version 2
7 * or later (GPLv2+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <stdbool.h>
13
14#include <libxml/tree.h> // xmlNode
15
16#include <crm/common/xml.h>
17#include <pacemaker-internal.h>
18
20
21struct assign_data {
22 const pcmk_node_t *prefer;
23 bool stop_if_fail;
24};
25
35static bool
36assign_replica(pcmk__bundle_replica_t *replica, void *user_data)
37{
38 pcmk_node_t *container_host = NULL;
39
40 struct assign_data *assign_data = user_data;
41 const pcmk_node_t *prefer = assign_data->prefer;
42 bool stop_if_fail = assign_data->stop_if_fail;
43
44 const pcmk_resource_t *bundle = pe__const_top_resource(replica->container,
45 true);
46
47 if (replica->ip != NULL) {
48 pcmk__rsc_trace(bundle, "Assigning bundle %s IP %s",
49 bundle->id, replica->ip->id);
50 replica->ip->priv->cmds->assign(replica->ip, prefer, stop_if_fail);
51 }
52
53 container_host = replica->container->priv->assigned_node;
54 if (replica->remote != NULL) {
55 if (pcmk__is_pacemaker_remote_node(container_host)) {
56 /* REMOTE_CONTAINER_HACK: "Nested" connection resources must be on
57 * the same host because Pacemaker Remote only supports a single
58 * active connection.
59 */
60 pcmk__new_colocation("#replica-remote-with-host-remote", NULL,
62 container_host->priv->remote, NULL,
64 }
65 pcmk__rsc_trace(bundle, "Assigning bundle %s connection %s",
66 bundle->id, replica->remote->id);
67 replica->remote->priv->cmds->assign(replica->remote, prefer,
68 stop_if_fail);
69 }
70
71 if (replica->child != NULL) {
72 pcmk_node_t *node = NULL;
73 GHashTableIter iter;
74
75 g_hash_table_iter_init(&iter, replica->child->priv->allowed_nodes);
76 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
77 if (!pcmk__same_node(node, replica->node)) {
78 node->assign->score = -PCMK_SCORE_INFINITY;
79 } else if (!pcmk__threshold_reached(replica->child, node, NULL)) {
80 node->assign->score = PCMK_SCORE_INFINITY;
81 }
82 }
83
86 pcmk__rsc_trace(bundle, "Assigning bundle %s replica child %s",
87 bundle->id, replica->child->id);
88 replica->child->priv->cmds->assign(replica->child, replica->node,
89 stop_if_fail);
92 }
93 return true;
94}
95
117 bool stop_if_fail)
118{
119 GList *containers = NULL;
120 pcmk_resource_t *bundled_resource = NULL;
121 struct assign_data assign_data = { prefer, stop_if_fail };
122
123 pcmk__assert(pcmk__is_bundle(rsc));
124
125 pcmk__rsc_trace(rsc, "Assigning bundle %s", rsc->id);
127
130 rsc, __func__, rsc->priv->allowed_nodes,
131 rsc->priv->scheduler);
132
133 // Assign all containers first, so we know what nodes the bundle will be on
134 containers = g_list_sort(pe__bundle_containers(rsc), pcmk__cmp_instance);
135 pcmk__assign_instances(rsc, containers, pe__bundle_max(rsc),
136 rsc->priv->fns->max_per_node(rsc));
137 g_list_free(containers);
138
139 // Then assign remaining replica resources
140 pe__foreach_bundle_replica(rsc, assign_replica, (void *) &assign_data);
141
142 // Finally, assign the bundled resources to each bundle node
143 bundled_resource = pe__bundled_resource(rsc);
144 if (bundled_resource != NULL) {
145 pcmk_node_t *node = NULL;
146 GHashTableIter iter;
147
148 g_hash_table_iter_init(&iter, bundled_resource->priv->allowed_nodes);
149 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) {
150 if (pe__node_is_bundle_instance(rsc, node)) {
151 node->assign->score = 0;
152 } else {
154 }
155 }
156 bundled_resource->priv->cmds->assign(bundled_resource, prefer,
157 stop_if_fail);
158 }
159
161 return NULL;
162}
163
173static bool
174create_replica_actions(pcmk__bundle_replica_t *replica, void *user_data)
175{
176 if (replica->ip != NULL) {
177 replica->ip->priv->cmds->create_actions(replica->ip);
178 }
179 if (replica->container != NULL) {
180 replica->container->priv->cmds->create_actions(replica->container);
181 }
182 if (replica->remote != NULL) {
183 replica->remote->priv->cmds->create_actions(replica->remote);
184 }
185 return true;
186}
187
194void
196{
197 pcmk_action_t *action = NULL;
198 GList *containers = NULL;
199 pcmk_resource_t *bundled_resource = NULL;
200
201 pcmk__assert(pcmk__is_bundle(rsc));
202
203 pe__foreach_bundle_replica(rsc, create_replica_actions, NULL);
204
205 containers = pe__bundle_containers(rsc);
206 pcmk__create_instance_actions(rsc, containers);
207 g_list_free(containers);
208
209 bundled_resource = pe__bundled_resource(rsc);
210 if (bundled_resource != NULL) {
211 bundled_resource->priv->cmds->create_actions(bundled_resource);
212
213 if (pcmk_is_set(bundled_resource->flags, pcmk__rsc_promotable)) {
216 true, true);
217 action->priority = PCMK_SCORE_INFINITY;
218
221 true, true);
222 action->priority = PCMK_SCORE_INFINITY;
223 }
224 }
225}
226
236static bool
237replica_internal_constraints(pcmk__bundle_replica_t *replica, void *user_data)
238{
239 pcmk_resource_t *bundle = user_data;
240
241 replica->container->priv->cmds->internal_constraints(replica->container);
242
243 // Start bundle -> start replica container
244 pcmk__order_starts(bundle, replica->container,
247
248 // Stop bundle -> stop replica child and container
249 if (replica->child != NULL) {
250 pcmk__order_stops(bundle, replica->child,
252 }
253 pcmk__order_stops(bundle, replica->container,
255
256 // Start replica container -> bundle is started
260
261 // Stop replica container -> bundle is stopped
265
266 if (replica->ip != NULL) {
267 replica->ip->priv->cmds->internal_constraints(replica->ip);
268
269 // Replica IP address -> replica container (symmetric)
270 pcmk__order_starts(replica->ip, replica->container,
273 pcmk__order_stops(replica->container, replica->ip,
275
276 pcmk__new_colocation("#ip-with-container", NULL, PCMK_SCORE_INFINITY,
277 replica->ip, replica->container, NULL, NULL,
279 }
280
281 if (replica->remote != NULL) {
282 /* This handles ordering and colocating remote relative to container
283 * (via "#resource-with-container"). Since IP is also ordered and
284 * colocated relative to the container, we don't need to do anything
285 * explicit here with IP.
286 */
287 replica->remote->priv->cmds->internal_constraints(replica->remote);
288 }
289
290 if (replica->child != NULL) {
291 pcmk__assert(replica->remote != NULL);
292 // "Start remote then child" is implicit in scheduler's remote logic
293 }
294 return true;
295}
296
303void
305{
306 pcmk_resource_t *bundled_resource = NULL;
307
308 pcmk__assert(pcmk__is_bundle(rsc));
309
310 pe__foreach_bundle_replica(rsc, replica_internal_constraints, rsc);
311
312 bundled_resource = pe__bundled_resource(rsc);
313 if (bundled_resource == NULL) {
314 return;
315 }
316
317 // Start bundle -> start bundled clone
318 pcmk__order_resource_actions(rsc, PCMK_ACTION_START, bundled_resource,
321
322 // Bundled clone is started -> bundle is started
326
327 // Stop bundle -> stop bundled clone
328 pcmk__order_resource_actions(rsc, PCMK_ACTION_STOP, bundled_resource,
331
332 // Bundled clone is stopped -> bundle is stopped
336
337 bundled_resource->priv->cmds->internal_constraints(bundled_resource);
338
339 if (!pcmk_is_set(bundled_resource->flags, pcmk__rsc_promotable)) {
340 return;
341 }
343
344 // Demote bundle -> demote bundled clone
348
349 // Bundled clone is demoted -> bundle is demoted
353
354 // Promote bundle -> promote bundled clone
356 bundled_resource, PCMK_ACTION_PROMOTE,
358
359 // Bundled clone is promoted -> bundle is promoted
363}
364
365struct match_data {
366 const pcmk_node_t *node; // Node to compare against replica
367 pcmk_resource_t *container; // Replica container corresponding to node
368};
369
380static bool
381match_replica_container(const pcmk__bundle_replica_t *replica, void *user_data)
382{
383 struct match_data *match_data = user_data;
384
385 if (pcmk__instance_matches(replica->container, match_data->node,
386 pcmk_role_unknown, false)) {
387 match_data->container = replica->container;
388 return false; // Match found, don't bother searching further replicas
389 }
390 return true; // No match, keep searching
391}
392
402static const pcmk_node_t *
403get_bundle_node_host(const pcmk_node_t *node)
404{
405 if (pcmk__is_bundle_node(node)) {
406 const pcmk_resource_t *container = NULL;
407
408 container = node->priv->remote->priv->launcher;
409 return container->priv->fns->location(container, NULL,
411 }
412 return node;
413}
414
426static pcmk_resource_t *
427compatible_container(const pcmk_resource_t *dependent,
428 const pcmk_resource_t *bundle)
429{
430 GList *scratch = NULL;
431 struct match_data match_data = { NULL, NULL };
432
433 // If dependent is assigned, only check there
434 match_data.node = dependent->priv->fns->location(dependent, NULL,
436 match_data.node = get_bundle_node_host(match_data.node);
437 if (match_data.node != NULL) {
438 pe__foreach_const_bundle_replica(bundle, match_replica_container,
439 &match_data);
440 return match_data.container;
441 }
442
443 // Otherwise, check for any of the dependent's allowed nodes
444 scratch = g_hash_table_get_values(dependent->priv->allowed_nodes);
445 scratch = pcmk__sort_nodes(scratch, NULL);
446 for (const GList *iter = scratch; iter != NULL; iter = iter->next) {
447 match_data.node = iter->data;
448 match_data.node = get_bundle_node_host(match_data.node);
449 if (match_data.node == NULL) {
450 continue;
451 }
452
453 pe__foreach_const_bundle_replica(bundle, match_replica_container,
454 &match_data);
455 if (match_data.container != NULL) {
456 break;
457 }
458 }
459 g_list_free(scratch);
460 return match_data.container;
461}
462
463struct coloc_data {
464 const pcmk__colocation_t *colocation;
465 pcmk_resource_t *dependent;
466 GList *container_hosts;
467 int priority_delta;
468};
469
479static bool
480replica_apply_coloc_score(const pcmk__bundle_replica_t *replica,
481 void *user_data)
482{
483 struct coloc_data *coloc_data = user_data;
484 pcmk_node_t *chosen = NULL;
485 pcmk_resource_t *container = replica->container;
486
487 if (coloc_data->colocation->score < PCMK_SCORE_INFINITY) {
488 int priority_delta =
489 container->priv->cmds->apply_coloc_score(coloc_data->dependent,
490 container,
491 coloc_data->colocation,
492 false);
493
494 coloc_data->priority_delta =
495 pcmk__add_scores(coloc_data->priority_delta, priority_delta);
496 return true;
497 }
498
499 chosen = container->priv->fns->location(container, NULL,
501 if ((chosen == NULL)
502 || is_set_recursive(container, pcmk__rsc_blocked, true)) {
503 return true;
504 }
505
506 if ((coloc_data->colocation->primary_role >= pcmk_role_promoted)
507 && ((replica->child == NULL)
508 || (replica->child->priv->next_role < pcmk_role_promoted))) {
509 return true;
510 }
511
513 "Allowing mandatory colocation %s using %s @%d",
514 coloc_data->colocation->id, pcmk__node_name(chosen),
515 chosen->assign->score);
516 coloc_data->container_hosts = g_list_prepend(coloc_data->container_hosts,
517 chosen);
518 return true;
519}
520
536int
538 const pcmk_resource_t *primary,
539 const pcmk__colocation_t *colocation,
540 bool for_dependent)
541{
542 struct coloc_data coloc_data = { colocation, dependent, NULL, 0 };
543
544 /* This should never be called for the bundle itself as a dependent.
545 * Instead, we add its colocation constraints to its containers and bundled
546 * primitive and call the apply_coloc_score() method for them as dependents.
547 */
548 pcmk__assert(pcmk__is_bundle(primary) && pcmk__is_primitive(dependent)
549 && (colocation != NULL) && !for_dependent);
550
551 if (pcmk_is_set(primary->flags, pcmk__rsc_unassigned)) {
552 pcmk__rsc_trace(primary,
553 "Skipping applying colocation %s "
554 "because %s is still provisional",
555 colocation->id, primary->id);
556 return 0;
557 }
558 pcmk__rsc_trace(primary, "Applying colocation %s (%s with %s at %s)",
559 colocation->id, dependent->id, primary->id,
560 pcmk_readable_score(colocation->score));
561
562 /* If the constraint dependent is a clone or bundle, "dependent" here is one
563 * of its instances. Look for a compatible instance of this bundle.
564 */
565 if (colocation->dependent->priv->variant > pcmk__rsc_variant_group) {
566 const pcmk_resource_t *primary_container = NULL;
567
568 primary_container = compatible_container(dependent, primary);
569 if (primary_container != NULL) { // Success, we found one
570 pcmk__rsc_debug(primary, "Pairing %s with %s",
571 dependent->id, primary_container->id);
572
573 return dependent->priv->cmds->apply_coloc_score(dependent,
574 primary_container,
575 colocation, true);
576 }
577
578 if (colocation->score >= PCMK_SCORE_INFINITY) {
579 // Failure, and it's fatal
580 crm_notice("%s cannot run because there is no compatible "
581 "instance of %s to colocate with",
582 dependent->id, primary->id);
583 pcmk__assign_resource(dependent, NULL, true, true);
584
585 } else { // Failure, but we can ignore it
586 pcmk__rsc_debug(primary,
587 "%s cannot be colocated with any instance of %s",
588 dependent->id, primary->id);
589 }
590 return 0;
591 }
592
593 pe__foreach_const_bundle_replica(primary, replica_apply_coloc_score,
594 &coloc_data);
595
596 if (colocation->score >= PCMK_SCORE_INFINITY) {
597 pcmk__colocation_intersect_nodes(dependent, primary, colocation,
598 coloc_data.container_hosts, false);
599 }
600 g_list_free(coloc_data.container_hosts);
601 return coloc_data.priority_delta;
602}
603
604// Bundle implementation of pcmk__assignment_methods_t:with_this_colocations()
605void
607 const pcmk_resource_t *orig_rsc, GList **list)
608{
609 const pcmk_resource_t *bundled_rsc = NULL;
610
611 pcmk__assert(pcmk__is_bundle(rsc) && (orig_rsc != NULL) && (list != NULL));
612
613 // The bundle itself and its containers always get its colocations
614 if ((orig_rsc == rsc)
616
618 orig_rsc);
619 return;
620 }
621
622 /* The bundled resource gets the colocations if it's promotable and we've
623 * begun choosing roles
624 */
625 bundled_rsc = pe__bundled_resource(rsc);
626 if ((bundled_rsc == NULL)
627 || !pcmk_is_set(bundled_rsc->flags, pcmk__rsc_promotable)
628 || (pe__const_top_resource(orig_rsc, false) != bundled_rsc)) {
629 return;
630 }
631
632 if (orig_rsc == bundled_rsc) {
633 if (pe__clone_flag_is_set(orig_rsc,
635 /* orig_rsc is the clone and we're setting roles (or have already
636 * done so)
637 */
639 orig_rsc);
640 }
641
642 } else if (!pcmk_is_set(orig_rsc->flags, pcmk__rsc_unassigned)) {
643 /* orig_rsc is an instance and is already assigned. If something
644 * requests colocations for orig_rsc now, it's for setting roles.
645 */
647 orig_rsc);
648 }
649}
650
651// Bundle implementation of pcmk__assignment_methods_t:this_with_colocations()
652void
654 const pcmk_resource_t *orig_rsc, GList **list)
655{
656 const pcmk_resource_t *bundled_rsc = NULL;
657
658 pcmk__assert(pcmk__is_bundle(rsc) && (orig_rsc != NULL) && (list != NULL));
659
660 // The bundle itself and its containers always get its colocations
661 if ((orig_rsc == rsc)
663
665 orig_rsc);
666 return;
667 }
668
669 /* The bundled resource gets the colocations if it's promotable and we've
670 * begun choosing roles
671 */
672 bundled_rsc = pe__bundled_resource(rsc);
673 if ((bundled_rsc == NULL)
674 || !pcmk_is_set(bundled_rsc->flags, pcmk__rsc_promotable)
675 || (pe__const_top_resource(orig_rsc, false) != bundled_rsc)) {
676 return;
677 }
678
679 if (orig_rsc == bundled_rsc) {
680 if (pe__clone_flag_is_set(orig_rsc,
682 /* orig_rsc is the clone and we're setting roles (or have already
683 * done so)
684 */
686 orig_rsc);
687 }
688
689 } else if (!pcmk_is_set(orig_rsc->flags, pcmk__rsc_unassigned)) {
690 /* orig_rsc is an instance and is already assigned. If something
691 * requests colocations for orig_rsc now, it's for setting roles.
692 */
694 orig_rsc);
695 }
696}
697
707uint32_t
709{
710 GList *containers = NULL;
711 uint32_t flags = 0;
712 pcmk_resource_t *bundled_resource = NULL;
713
714 pcmk__assert((action != NULL) && pcmk__is_bundle(action->rsc));
715
716 bundled_resource = pe__bundled_resource(action->rsc);
717 if (bundled_resource != NULL) {
718 GList *children = bundled_resource->priv->children;
719
720 // Clone actions are done on the bundled clone resource, not container
721 switch (get_complex_task(bundled_resource, action->task)) {
729 return pcmk__collective_action_flags(action, children, node);
730 default:
731 break;
732 }
733 }
734
735 containers = pe__bundle_containers(action->rsc);
736 flags = pcmk__collective_action_flags(action, containers, node);
737 g_list_free(containers);
738 return flags;
739}
740
750static bool
751apply_location_to_replica(pcmk__bundle_replica_t *replica, void *user_data)
752{
753 pcmk__location_t *location = user_data;
754
755 replica->container->priv->cmds->apply_location(replica->container,
756 location);
757 if (replica->ip != NULL) {
758 replica->ip->priv->cmds->apply_location(replica->ip, location);
759 }
760 return true;
761}
762
770void
772{
773 pcmk_resource_t *bundled_resource = NULL;
774
775 pcmk__assert((location != NULL) && pcmk__is_bundle(rsc));
776
777 pcmk__apply_location(rsc, location);
778 pe__foreach_bundle_replica(rsc, apply_location_to_replica, location);
779
780 bundled_resource = pe__bundled_resource(rsc);
781 if ((bundled_resource != NULL)
782 && ((location->role_filter == pcmk_role_unpromoted)
783 || (location->role_filter == pcmk_role_promoted))) {
784
785 bundled_resource->priv->cmds->apply_location(bundled_resource,
786 location);
787 bundled_resource->priv->location_constraints =
788 g_list_prepend(bundled_resource->priv->location_constraints,
789 location);
790 }
791}
792
793#define XPATH_REMOTE "//nvpair[@name='" PCMK_REMOTE_RA_ADDR "']"
794
804static bool
805add_replica_actions_to_graph(pcmk__bundle_replica_t *replica, void *user_data)
806{
807 if ((replica->remote != NULL)
809
810 /* REMOTE_CONTAINER_HACK: Allow remote nodes to run containers that
811 * run the remote executor inside, without needing a separate IP for
812 * the container. This is done by configuring the inner remote's
813 * connection host as the magic string "#uname", then
814 * replacing it with the underlying host when needed.
815 */
816 xmlNode *nvpair = pcmk__xpath_find_one(replica->remote->priv->xml->doc,
817 XPATH_REMOTE, LOG_ERR);
818 const char *calculated_addr = NULL;
819
820 // Replace the value in replica->remote->xml (if appropriate)
821 calculated_addr = pe__add_bundle_remote_name(replica->remote, nvpair,
823 if (calculated_addr != NULL) {
824 /* Since this is for the bundle as a resource, and not any
825 * particular action, replace the value in the default
826 * parameters (not evaluated for node). create_graph_action()
827 * will grab it from there to replace it in node-evaluated
828 * parameters.
829 */
830 GHashTable *params = NULL;
831
832 params = pe_rsc_params(replica->remote, NULL,
833 replica->remote->priv->scheduler);
834 pcmk__insert_dup(params, PCMK_REMOTE_RA_ADDR, calculated_addr);
835 } else {
836 pcmk_resource_t *bundle = user_data;
837
838 /* The only way to get here is if the remote connection is
839 * neither currently running nor scheduled to run. That means we
840 * won't be doing any operations that require addr (only start
841 * requires it; we additionally use it to compare digests when
842 * unpacking status, promote, and migrate_from history, but
843 * that's already happened by this point).
844 */
845 pcmk__rsc_info(bundle,
846 "Unable to determine address for bundle %s "
847 "remote connection", bundle->id);
848 }
849 }
850 if (replica->ip != NULL) {
851 replica->ip->priv->cmds->add_actions_to_graph(replica->ip);
852 }
853 replica->container->priv->cmds->add_actions_to_graph(replica->container);
854 if (replica->remote != NULL) {
855 replica->remote->priv->cmds->add_actions_to_graph(replica->remote);
856 }
857 return true;
858}
859
866void
868{
869 pcmk_resource_t *bundled_resource = NULL;
870
871 pcmk__assert(pcmk__is_bundle(rsc));
872
873 bundled_resource = pe__bundled_resource(rsc);
874 if (bundled_resource != NULL) {
875 bundled_resource->priv->cmds->add_actions_to_graph(bundled_resource);
876 }
877 pe__foreach_bundle_replica(rsc, add_replica_actions_to_graph, rsc);
878}
879
880struct probe_data {
881 pcmk_resource_t *bundle; // Bundle being probed
882 pcmk_node_t *node; // Node to create probes on
883 bool any_created; // Whether any probes have been created
884};
885
895static bool
896order_replica_start_after(pcmk__bundle_replica_t *replica, void *user_data)
897{
898 pcmk__bundle_replica_t *probed_replica = user_data;
899
900 if ((replica == probed_replica) || (replica->container == NULL)) {
901 return true;
902 }
903 pcmk__new_ordering(probed_replica->container,
904 pcmk__op_key(probed_replica->container->id,
906 NULL, replica->container,
908 0),
910 replica->container->priv->scheduler);
911 return true;
912}
913
923static bool
924create_replica_probes(pcmk__bundle_replica_t *replica, void *user_data)
925{
926 struct probe_data *probe_data = user_data;
927 pcmk_resource_t *bundle = probe_data->bundle;
928
929 /* This is guaranteed when constructing probe_data in pcmk__bundle_create_probe,
930 * but this makes static analysis happy.
931 */
932 pcmk__assert(bundle != NULL);
933
934 if ((replica->ip != NULL)
935 && replica->ip->priv->cmds->create_probe(replica->ip,
936 probe_data->node)) {
937 probe_data->any_created = true;
938 }
939 if ((replica->child != NULL)
940 && pcmk__same_node(probe_data->node, replica->node)
941 && replica->child->priv->cmds->create_probe(replica->child,
942 probe_data->node)) {
943 probe_data->any_created = true;
944 }
945 if (replica->container->priv->cmds->create_probe(replica->container,
946 probe_data->node)) {
947 probe_data->any_created = true;
948
949 /* If we're limited to one replica per host (due to
950 * the lack of an IP range probably), then we don't
951 * want any of our peer containers starting until
952 * we've established that no other copies are already
953 * running.
954 *
955 * Partly this is to ensure that the maximum replicas per host is
956 * observed, but also to ensure that the containers
957 * don't fail to start because the necessary port
958 * mappings (which won't include an IP for uniqueness)
959 * are already taken
960 */
961 if (bundle->priv->fns->max_per_node(bundle) == 1) {
962 pe__foreach_bundle_replica(bundle, order_replica_start_after,
963 replica);
964 }
965 }
966 if ((replica->remote != NULL)
967 && replica->remote->priv->cmds->create_probe(replica->remote,
968 probe_data->node)) {
969 /* Do not probe the remote resource until we know where the container is
970 * running. This is required for REMOTE_CONTAINER_HACK to correctly
971 * probe remote resources.
972 */
973 char *probe_uuid = pcmk__op_key(replica->remote->id,
975 pcmk_action_t *probe = NULL;
976
977 probe = find_first_action(replica->remote->priv->actions, probe_uuid,
978 NULL, probe_data->node);
979 free(probe_uuid);
980 if (probe != NULL) {
981 probe_data->any_created = true;
982 pcmk__rsc_trace(bundle, "Ordering %s probe on %s",
983 replica->remote->id,
984 pcmk__node_name(probe_data->node));
986 pcmk__op_key(replica->container->id,
988 NULL, replica->remote, NULL, probe,
990 bundle->priv->scheduler);
991 }
992 }
993 return true;
994}
995
1006bool
1008{
1009 struct probe_data probe_data = { rsc, node, false };
1010
1011 pcmk__assert(pcmk__is_bundle(rsc));
1012 pe__foreach_bundle_replica(rsc, create_replica_probes, &probe_data);
1013 return probe_data.any_created;
1014}
1015
1025static bool
1026output_replica_actions(pcmk__bundle_replica_t *replica, void *user_data)
1027{
1028 if (replica->ip != NULL) {
1029 replica->ip->priv->cmds->output_actions(replica->ip);
1030 }
1031 replica->container->priv->cmds->output_actions(replica->container);
1032 if (replica->remote != NULL) {
1033 replica->remote->priv->cmds->output_actions(replica->remote);
1034 }
1035 if (replica->child != NULL) {
1036 replica->child->priv->cmds->output_actions(replica->child);
1037 }
1038 return true;
1039}
1040
1047void
1049{
1050 pcmk__assert(pcmk__is_bundle(rsc));
1051 pe__foreach_bundle_replica(rsc, output_replica_actions, NULL);
1052}
1053
1054// Bundle implementation of pcmk__assignment_methods_t:add_utilization()
1055void
1057 const pcmk_resource_t *orig_rsc, GList *all_rscs,
1058 GHashTable *utilization)
1059{
1060 pcmk_resource_t *container = NULL;
1061
1062 pcmk__assert(pcmk__is_bundle(rsc));
1063
1065 return;
1066 }
1067
1068 /* All bundle replicas are identical, so using the utilization of the first
1069 * is sufficient for any. Only the implicit container resource can have
1070 * utilization values.
1071 */
1072 container = pe__first_container(rsc);
1073 if (container != NULL) {
1074 container->priv->cmds->add_utilization(container, orig_rsc, all_rscs,
1075 utilization);
1076 }
1077}
1078
1079// Bundle implementation of pcmk__assignment_methods_t:shutdown_lock()
1080void
1082{
1083 pcmk__assert(pcmk__is_bundle(rsc));
1084 // Bundles currently don't support shutdown locks
1085}
@ pcmk__ar_if_on_same_node
Relation applies only if actions are on same node.
@ pcmk__ar_then_implies_first
@ pcmk__ar_then_implies_first_graphed
If 'then' is required, 'first' must be added to the transition graph.
@ pcmk__ar_first_implies_then_graphed
If 'first' is required and runnable, 'then' must be in graph.
@ pcmk__ar_nested_remote_probe
@ pcmk__ar_unrunnable_first_blocks
'then' is runnable (and migratable) only if 'first' is runnable
@ pcmk__ar_ordered
Actions are ordered (optionally, if no other flags are set)
@ pcmk__ar_guest_allowed
Ordering applies even if 'first' runs on guest node created by 'then'.
#define PCMK_ACTION_PROMOTED
Definition actions.h:58
#define PCMK_ACTION_STOP
Definition actions.h:66
#define PCMK_ACTION_RUNNING
Definition actions.h:62
#define PCMK_ACTION_PROMOTE
Definition actions.h:57
#define PCMK_ACTION_START
Definition actions.h:63
#define PCMK_ACTION_STOPPED
Definition actions.h:67
#define PCMK_ACTION_MONITOR
Definition actions.h:51
#define PCMK_ACTION_DEMOTED
Definition actions.h:41
#define PCMK_ACTION_DEMOTE
Definition actions.h:40
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition actions.c:225
@ pcmk__action_notify
@ pcmk__action_demote
@ pcmk__action_promote
@ pcmk__action_notified
@ pcmk__action_unspecified
@ pcmk__action_promoted
@ pcmk__action_demoted
@ pcmk__clone_promotion_constrained
uint64_t flags
Definition remote.c:3
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:80
GHashTable * pe_rsc_params(pcmk_resource_t *rsc, const pcmk_node_t *node, pcmk_scheduler_t *scheduler)
Get a table of resource parameters.
Definition complex.c:462
G_GNUC_INTERNAL void pcmk__add_this_with_list(GList **list, GList *addition, const pcmk_resource_t *rsc)
#define pcmk__order_starts(rsc1, rsc2, flags)
G_GNUC_INTERNAL void pcmk__colocation_intersect_nodes(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, const GList *primary_nodes, bool merge_scores)
G_GNUC_INTERNAL void pcmk__new_ordering(pcmk_resource_t *first_rsc, char *first_task, pcmk_action_t *first_action, pcmk_resource_t *then_rsc, char *then_task, pcmk_action_t *then_action, uint32_t flags, pcmk_scheduler_t *sched)
#define pcmk__order_resource_actions(first_rsc, first_task, then_rsc, then_task, flags)
G_GNUC_INTERNAL void pcmk__assign_instances(pcmk_resource_t *collective, GList *instances, int max_total, int max_per_node)
G_GNUC_INTERNAL uint32_t pcmk__collective_action_flags(pcmk_action_t *action, const GList *instances, const pcmk_node_t *node)
@ pcmk__coloc_influence
G_GNUC_INTERNAL bool pcmk__assign_resource(pcmk_resource_t *rsc, pcmk_node_t *node, bool force, bool stop_if_fail)
G_GNUC_INTERNAL gint pcmk__cmp_instance(gconstpointer a, gconstpointer b)
G_GNUC_INTERNAL GList * pcmk__sort_nodes(GList *nodes, pcmk_node_t *active_node)
G_GNUC_INTERNAL void pcmk__add_with_this_list(GList **list, GList *addition, const pcmk_resource_t *rsc)
G_GNUC_INTERNAL void pcmk__new_colocation(const char *id, const char *node_attr, int score, pcmk_resource_t *dependent, pcmk_resource_t *primary, const char *dependent_role_spec, const char *primary_role_spec, uint32_t flags)
G_GNUC_INTERNAL bool pcmk__threshold_reached(pcmk_resource_t *rsc, const pcmk_node_t *node, pcmk_resource_t **failed)
G_GNUC_INTERNAL void pcmk__promotable_restart_ordering(pcmk_resource_t *rsc)
G_GNUC_INTERNAL bool pcmk__instance_matches(const pcmk_resource_t *instance, const pcmk_node_t *node, enum rsc_role_e role, bool current)
#define pcmk__order_stops(rsc1, rsc2, flags)
G_GNUC_INTERNAL void pcmk__create_instance_actions(pcmk_resource_t *rsc, GList *instances)
G_GNUC_INTERNAL void pcmk__apply_location(pcmk_resource_t *rsc, pcmk__location_t *constraint)
#define crm_notice(fmt, args...)
Definition logging.h:363
#define PCMK_REMOTE_RA_ADDR
Definition options.h:123
const char * action
Definition pcmk_fence.c:32
void pcmk__bundle_apply_location(pcmk_resource_t *rsc, pcmk__location_t *location)
#define XPATH_REMOTE
void pcmk__with_bundle_colocations(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
void pcmk__bundle_add_utilization(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
int pcmk__bundle_apply_coloc_score(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
void pcmk__bundle_shutdown_lock(pcmk_resource_t *rsc)
uint32_t pcmk__bundle_action_flags(pcmk_action_t *action, const pcmk_node_t *node)
bool pcmk__bundle_create_probe(pcmk_resource_t *rsc, pcmk_node_t *node)
void pcmk__output_bundle_actions(pcmk_resource_t *rsc)
pcmk_node_t * pcmk__bundle_assign(pcmk_resource_t *rsc, const pcmk_node_t *prefer, bool stop_if_fail)
void pcmk__bundle_add_actions_to_graph(pcmk_resource_t *rsc)
void pcmk__bundle_create_actions(pcmk_resource_t *rsc)
void pcmk__bundle_with_colocations(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
void pcmk__bundle_internal_constraints(pcmk_resource_t *rsc)
const char * pe__add_bundle_remote_name(pcmk_resource_t *rsc, xmlNode *xml, const char *field)
Definition bundle.c:911
void pe__foreach_const_bundle_replica(const pcmk_resource_t *bundle, bool(*fn)(const pcmk__bundle_replica_t *, void *), void *user_data)
Definition bundle.c:234
bool is_set_recursive(const pcmk_resource_t *rsc, long long flag, bool any)
Definition clone.c:500
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition complex.c:1025
#define pe__show_node_scores(level, rsc, text, nodes, scheduler)
Definition internal.h:158
pcmk_action_t * pe__new_rsc_pseudo_action(pcmk_resource_t *rsc, const char *task, bool optional, bool runnable)
bool pe__clone_flag_is_set(const pcmk_resource_t *clone, uint32_t flags)
Definition clone.c:1086
pcmk_resource_t * pe__first_container(const pcmk_resource_t *bundle)
Definition bundle.c:187
pcmk_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pcmk_node_t *on_node)
bool pe__bundle_needs_remote_name(pcmk_resource_t *rsc)
Definition bundle.c:893
GList * pe__bundle_containers(const pcmk_resource_t *bundle)
Definition bundle.c:1989
pcmk_resource_t * pe__bundled_resource(const pcmk_resource_t *rsc)
Definition bundle.c:113
enum pcmk__action_type get_complex_task(const pcmk_resource_t *rsc, const char *name)
bool pe__node_is_bundle_instance(const pcmk_resource_t *bundle, const pcmk_node_t *node)
Definition bundle.c:161
void pe__foreach_bundle_replica(pcmk_resource_t *bundle, bool(*fn)(pcmk__bundle_replica_t *, void *), void *user_data)
Definition bundle.c:210
int pe__bundle_max(const pcmk_resource_t *rsc)
Definition bundle.c:96
@ pcmk__rsc_assigning
@ pcmk__rsc_unassigned
@ pcmk__rsc_blocked
@ pcmk__rsc_promotable
@ pcmk__rsc_replica_container
#define pcmk__set_rsc_flags(resource, flags_to_set)
@ pcmk__rsc_variant_group
Group resource.
@ pcmk__rsc_node_assigned
#define pcmk__clear_rsc_flags(resource, flags_to_clear)
#define pcmk__assert(expr)
@ pcmk_role_unknown
Resource role is unknown.
Definition roles.h:35
@ pcmk_role_unpromoted
Unpromoted.
Definition roles.h:38
@ pcmk_role_promoted
Promoted.
Definition roles.h:39
#define pcmk__rsc_info(rsc, fmt, args...)
#define pcmk__rsc_trace(rsc, fmt, args...)
#define pcmk__rsc_debug(rsc, fmt, args...)
@ pcmk__sched_output_scores
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition scores.c:102
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition scores.h:26
int pcmk__add_scores(int score1, int score2)
Definition scores.c:159
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition strings.c:703
pcmk_node_t *(* assign)(pcmk_resource_t *rsc, const pcmk_node_t *prefer, bool stop_if_fail)
void(* create_actions)(pcmk_resource_t *rsc)
int(* apply_coloc_score)(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
void(* internal_constraints)(pcmk_resource_t *rsc)
bool(* create_probe)(pcmk_resource_t *rsc, pcmk_node_t *node)
void(* add_actions_to_graph)(pcmk_resource_t *rsc)
void(* add_utilization)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
void(* output_actions)(pcmk_resource_t *rsc)
void(* apply_location)(pcmk_resource_t *rsc, pcmk__location_t *location)
A single instance of a bundle.
pcmk_resource_t * child
Instance of bundled resource.
pcmk_resource_t * remote
Pacemaker Remote connection into container.
pcmk_node_t * node
Copy of node created for this instance.
pcmk_resource_t * container
Container associated with this instance.
pcmk_resource_t * ip
IP address resource for ipaddr.
pcmk_resource_t * dependent
Location constraint object.
enum rsc_role_e role_filter
pcmk_resource_t * remote
pcmk_scheduler_t * scheduler
enum pcmk__rsc_variant variant
const pcmk__assignment_methods_t * cmds
const pcmk__rsc_methods_t * fns
unsigned long long flags
Definition resources.h:69
pcmk__resource_private_t * priv
Definition resources.h:61
pcmk_node_t *(* location)(const pcmk_resource_t *rsc, GList **list, uint32_t target)
unsigned int(* max_per_node)(const pcmk_resource_t *rsc)
uint64_t flags
Definition scheduler.h:89
pcmk__node_private_t * priv
Definition nodes.h:85
struct pcmk__node_assignment * assign
Definition nodes.h:79
Wrappers for and extensions to libxml2.
#define PCMK_XA_VALUE
Definition xml_names.h:442
xmlNode * pcmk__xpath_find_one(xmlDoc *doc, const char *path, uint8_t level)
Definition xpath.c:206