pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
pcmk_sched_bundle.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2022 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 <crm/msg_xml.h>
15#include <pacemaker-internal.h>
16
18
19#define PE__VARIANT_BUNDLE 1
20#include <lib/pengine/variant.h>
21
22static bool
23is_bundle_node(pe__bundle_variant_data_t *data, pe_node_t *node)
24{
25 for (GList *gIter = data->replicas; gIter != NULL; gIter = gIter->next) {
26 pe__bundle_replica_t *replica = gIter->data;
27
28 if (node->details == replica->node->details) {
29 return TRUE;
30 }
31 }
32 return FALSE;
33}
34
35void distribute_children(pe_resource_t *rsc, GList *children, GList *nodes,
36 int max, int per_host_max, pe_working_set_t * data_set);
37
38static GList *
39get_container_list(const pe_resource_t *rsc)
40{
41 GList *containers = NULL;
42
43 if (rsc->variant == pe_container) {
44 pe__bundle_variant_data_t *data = NULL;
45
46 get_bundle_variant_data(data, rsc);
47 for (GList *gIter = data->replicas; gIter != NULL;
48 gIter = gIter->next) {
49 pe__bundle_replica_t *replica = gIter->data;
50
51 containers = g_list_append(containers, replica->container);
52 }
53 }
54 return containers;
55}
56
57static inline GList *
58get_containers_or_children(const pe_resource_t *rsc)
59{
60 return (rsc->variant == pe_container)?
61 get_container_list(rsc) : rsc->children;
62}
63
75{
76 GList *containers = NULL;
77 GList *nodes = NULL;
78 pe__bundle_variant_data_t *bundle_data = NULL;
79
80 CRM_CHECK(rsc != NULL, return NULL);
81
82 get_bundle_variant_data(bundle_data, rsc);
83
85 containers = get_container_list(rsc);
86
88 rsc, __func__, rsc->allowed_nodes, rsc->cluster);
89
90 nodes = g_hash_table_get_values(rsc->allowed_nodes);
91 nodes = pcmk__sort_nodes(nodes, NULL);
92 containers = g_list_sort(containers, pcmk__cmp_instance);
93 distribute_children(rsc, containers, nodes, bundle_data->nreplicas,
94 bundle_data->nreplicas_per_host, rsc->cluster);
95 g_list_free(nodes);
96 g_list_free(containers);
97
98 for (GList *gIter = bundle_data->replicas; gIter != NULL;
99 gIter = gIter->next) {
100 pe__bundle_replica_t *replica = gIter->data;
101 pe_node_t *container_host = NULL;
102
103 CRM_ASSERT(replica);
104 if (replica->ip) {
105 pe_rsc_trace(rsc, "Allocating bundle %s IP %s",
106 rsc->id, replica->ip->id);
107 replica->ip->cmds->assign(replica->ip, prefer);
108 }
109
110 container_host = replica->container->allocated_to;
111 if (replica->remote && pe__is_guest_or_remote_node(container_host)) {
112 /* We need 'nested' connection resources to be on the same
113 * host because pacemaker-remoted only supports a single
114 * active connection
115 */
116 pcmk__new_colocation("child-remote-with-docker-remote", NULL,
117 INFINITY, replica->remote,
118 container_host->details->remote_rsc, NULL,
119 NULL, true, rsc->cluster);
120 }
121
122 if (replica->remote) {
123 pe_rsc_trace(rsc, "Allocating bundle %s connection %s",
124 rsc->id, replica->remote->id);
125 replica->remote->cmds->assign(replica->remote, prefer);
126 }
127
128 // Explicitly allocate replicas' children before bundle child
129 if (replica->child) {
130 pe_node_t *node = NULL;
131 GHashTableIter iter;
132
133 g_hash_table_iter_init(&iter, replica->child->allowed_nodes);
134 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) {
135 if (node->details != replica->node->details) {
136 node->weight = -INFINITY;
137 } else if (!pcmk__threshold_reached(replica->child, node,
138 NULL)) {
139 node->weight = INFINITY;
140 }
141 }
142
143 pe__set_resource_flags(replica->child->parent, pe_rsc_allocating);
144 pe_rsc_trace(rsc, "Allocating bundle %s replica child %s",
145 rsc->id, replica->child->id);
146 replica->child->cmds->assign(replica->child, replica->node);
147 pe__clear_resource_flags(replica->child->parent,
149 }
150 }
151
152 if (bundle_data->child) {
153 pe_node_t *node = NULL;
154 GHashTableIter iter;
155 g_hash_table_iter_init(&iter, bundle_data->child->allowed_nodes);
156 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) {
157 if (is_bundle_node(bundle_data, node)) {
158 node->weight = 0;
159 } else {
160 node->weight = -INFINITY;
161 }
162 }
163 pe_rsc_trace(rsc, "Allocating bundle %s child %s",
164 rsc->id, bundle_data->child->id);
165 bundle_data->child->cmds->assign(bundle_data->child, prefer);
166 }
167
169 return NULL;
170}
171
172
173void
175{
176 pe_action_t *action = NULL;
177 GList *containers = NULL;
178 pe__bundle_variant_data_t *bundle_data = NULL;
179
180 CRM_CHECK(rsc != NULL, return);
181
182 containers = get_container_list(rsc);
183 get_bundle_variant_data(bundle_data, rsc);
184 for (GList *gIter = bundle_data->replicas; gIter != NULL;
185 gIter = gIter->next) {
186 pe__bundle_replica_t *replica = gIter->data;
187
188 CRM_ASSERT(replica);
189 if (replica->ip) {
190 replica->ip->cmds->create_actions(replica->ip);
191 }
192 if (replica->container) {
193 replica->container->cmds->create_actions(replica->container);
194 }
195 if (replica->remote) {
196 replica->remote->cmds->create_actions(replica->remote);
197 }
198 }
199
200 clone_create_pseudo_actions(rsc, containers, NULL, NULL);
201
202 if (bundle_data->child) {
203 bundle_data->child->cmds->create_actions(bundle_data->child);
204
205 if (pcmk_is_set(bundle_data->child->flags, pe_rsc_promotable)) {
206 /* promote */
207 pe__new_rsc_pseudo_action(rsc, RSC_PROMOTE, true, true);
209 action->priority = INFINITY;
210
211 /* demote */
212 pe__new_rsc_pseudo_action(rsc, RSC_DEMOTE, true, true);
213 action = pe__new_rsc_pseudo_action(rsc, RSC_DEMOTED, true, true);
214 action->priority = INFINITY;
215 }
216 }
217
218 g_list_free(containers);
219}
220
221void
223{
224 pe__bundle_variant_data_t *bundle_data = NULL;
225
226 CRM_CHECK(rsc != NULL, return);
227
228 get_bundle_variant_data(bundle_data, rsc);
229
230 if (bundle_data->child) {
231 pcmk__order_resource_actions(rsc, RSC_START, bundle_data->child,
233 pcmk__order_resource_actions(rsc, RSC_STOP, bundle_data->child,
235
236 if (bundle_data->child->children) {
237 pcmk__order_resource_actions(bundle_data->child, RSC_STARTED, rsc,
240 pcmk__order_resource_actions(bundle_data->child, RSC_STOPPED, rsc,
243 } else {
244 pcmk__order_resource_actions(bundle_data->child, RSC_START, rsc,
247 pcmk__order_resource_actions(bundle_data->child, RSC_STOP, rsc,
250 }
251 }
252
253 for (GList *gIter = bundle_data->replicas; gIter != NULL;
254 gIter = gIter->next) {
255 pe__bundle_replica_t *replica = gIter->data;
256
257 CRM_ASSERT(replica);
258 CRM_ASSERT(replica->container);
259
260 replica->container->cmds->internal_constraints(replica->container);
261
262 pcmk__order_starts(rsc, replica->container,
264
265 if (replica->child) {
266 pcmk__order_stops(rsc, replica->child,
268 }
269 pcmk__order_stops(rsc, replica->container,
271 pcmk__order_resource_actions(replica->container, RSC_START, rsc,
274 pcmk__order_resource_actions(replica->container, RSC_STOP, rsc,
277
278 if (replica->ip) {
279 replica->ip->cmds->internal_constraints(replica->ip);
280
281 // Start IP then container
282 pcmk__order_starts(replica->ip, replica->container,
284 pcmk__order_stops(replica->container, replica->ip,
286
287 pcmk__new_colocation("ip-with-docker", NULL, INFINITY, replica->ip,
288 replica->container, NULL, NULL, true,
289 rsc->cluster);
290 }
291
292 if (replica->remote) {
293 /* This handles ordering and colocating remote relative to container
294 * (via "resource-with-container"). Since IP is also ordered and
295 * colocated relative to the container, we don't need to do anything
296 * explicit here with IP.
297 */
298 replica->remote->cmds->internal_constraints(replica->remote);
299 }
300
301 if (replica->child) {
302 CRM_ASSERT(replica->remote);
303
304 // "Start remote then child" is implicit in scheduler's remote logic
305 }
306
307 }
308
309 if (bundle_data->child) {
310 bundle_data->child->cmds->internal_constraints(bundle_data->child);
311 if (pcmk_is_set(bundle_data->child->flags, pe_rsc_promotable)) {
313
314 /* child demoted before global demoted */
315 pcmk__order_resource_actions(bundle_data->child, RSC_DEMOTED, rsc,
318
319 /* global demote before child demote */
320 pcmk__order_resource_actions(rsc, RSC_DEMOTE, bundle_data->child,
323
324 /* child promoted before global promoted */
325 pcmk__order_resource_actions(bundle_data->child, RSC_PROMOTED, rsc,
328
329 /* global promote before child promote */
330 pcmk__order_resource_actions(rsc, RSC_PROMOTE, bundle_data->child,
333 }
334 }
335}
336
337static pe_resource_t *
338compatible_replica_for_node(const pe_resource_t *rsc_lh,
339 const pe_node_t *candidate,
340 const pe_resource_t *rsc, enum rsc_role_e filter,
341 gboolean current)
342{
343 pe__bundle_variant_data_t *bundle_data = NULL;
344
345 CRM_CHECK(candidate != NULL, return NULL);
346 get_bundle_variant_data(bundle_data, rsc);
347
348 crm_trace("Looking for compatible child from %s for %s on %s",
349 rsc_lh->id, rsc->id, pe__node_name(candidate));
350
351 for (GList *gIter = bundle_data->replicas; gIter != NULL;
352 gIter = gIter->next) {
353 pe__bundle_replica_t *replica = gIter->data;
354
355 if (is_child_compatible(replica->container, candidate, filter, current)) {
356 crm_trace("Pairing %s with %s on %s",
357 rsc_lh->id, replica->container->id,
358 pe__node_name(candidate));
359 return replica->container;
360 }
361 }
362
363 crm_trace("Can't pair %s with %s", rsc_lh->id, rsc->id);
364 return NULL;
365}
366
367static pe_resource_t *
368compatible_replica(const pe_resource_t *rsc_lh, const pe_resource_t *rsc,
369 enum rsc_role_e filter, gboolean current,
371{
372 GList *scratch = NULL;
373 pe_resource_t *pair = NULL;
374 pe_node_t *active_node_lh = NULL;
375
376 active_node_lh = rsc_lh->fns->location(rsc_lh, NULL, current);
377 if (active_node_lh) {
378 return compatible_replica_for_node(rsc_lh, active_node_lh, rsc, filter,
379 current);
380 }
381
382 scratch = g_hash_table_get_values(rsc_lh->allowed_nodes);
383 scratch = pcmk__sort_nodes(scratch, NULL);
384
385 for (GList *gIter = scratch; gIter != NULL; gIter = gIter->next) {
386 pe_node_t *node = (pe_node_t *) gIter->data;
387
388 pair = compatible_replica_for_node(rsc_lh, node, rsc, filter, current);
389 if (pair) {
390 goto done;
391 }
392 }
393
394 pe_rsc_debug(rsc, "Can't pair %s with %s", rsc_lh->id, (rsc? rsc->id : "none"));
395 done:
396 g_list_free(scratch);
397 return pair;
398}
399
401{
402 /* Strictly speaking, there should be a 'copies_per_node' addition
403 * to the resource function table and each case would be a
404 * function. However that would be serious overkill to return an
405 * int. In fact, it seems to me that both function tables
406 * could/should be replaced by resources.{c,h} full of
407 * rsc_{some_operation} functions containing a switch as below
408 * which calls out to functions named {variant}_{some_operation}
409 * as needed.
410 */
411 switch(rsc->variant) {
412 case pe_unknown:
413 return 0;
414 case pe_native:
415 case pe_group:
416 return 1;
417 case pe_clone:
418 {
419 const char *max_clones_node = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION_NODEMAX);
420
421 if (max_clones_node == NULL) {
422 return 1;
423
424 } else {
425 int max_i;
426
427 pcmk__scan_min_int(max_clones_node, &max_i, 0);
428 return max_i;
429 }
430 }
431 case pe_container:
432 {
433 pe__bundle_variant_data_t *data = NULL;
434 get_bundle_variant_data(data, rsc);
435 return data->nreplicas_per_host;
436 }
437 }
438 return 0;
439}
440
454void
456 const pe_resource_t *primary,
457 const pcmk__colocation_t *colocation,
458 bool for_dependent)
459{
460 GList *allocated_primaries = NULL;
461 pe__bundle_variant_data_t *bundle_data = NULL;
462
463 /* This should never be called for the bundle itself as a dependent.
464 * Instead, we add its colocation constraints to its replicas and call the
465 * apply_coloc_score() for the replicas as dependents.
466 */
467 CRM_ASSERT(!for_dependent);
468
469 CRM_CHECK((colocation != NULL) && (dependent != NULL) && (primary != NULL),
470 return);
471 CRM_ASSERT(dependent->variant == pe_native);
472
473 if (pcmk_is_set(primary->flags, pe_rsc_provisional)) {
474 pe_rsc_trace(primary, "%s is still provisional", primary->id);
475 return;
476
477 } else if (colocation->dependent->variant > pe_group) {
478 pe_resource_t *primary_replica = compatible_replica(dependent, primary,
480 FALSE,
481 dependent->cluster);
482
483 if (primary_replica) {
484 pe_rsc_debug(primary, "Pairing %s with %s",
485 dependent->id, primary_replica->id);
486 dependent->cmds->apply_coloc_score(dependent, primary_replica,
487 colocation, true);
488
489 } else if (colocation->score >= INFINITY) {
490 crm_notice("Cannot pair %s with instance of %s",
491 dependent->id, primary->id);
492 pcmk__assign_resource(dependent, NULL, true);
493
494 } else {
495 pe_rsc_debug(primary, "Cannot pair %s with instance of %s",
496 dependent->id, primary->id);
497 }
498
499 return;
500 }
501
502 get_bundle_variant_data(bundle_data, primary);
503 pe_rsc_trace(primary, "Processing constraint %s: %s -> %s %d",
504 colocation->id, dependent->id, primary->id, colocation->score);
505
506 for (GList *gIter = bundle_data->replicas; gIter != NULL;
507 gIter = gIter->next) {
508 pe__bundle_replica_t *replica = gIter->data;
509
510 if (colocation->score < INFINITY) {
511 replica->container->cmds->apply_coloc_score(dependent,
512 replica->container,
513 colocation, false);
514
515 } else {
516 pe_node_t *chosen = replica->container->fns->location(replica->container,
517 NULL, FALSE);
518
519 if ((chosen == NULL)
520 || is_set_recursive(replica->container, pe_rsc_block, TRUE)) {
521 continue;
522 }
523 if ((colocation->primary_role >= RSC_ROLE_PROMOTED)
524 && (replica->child == NULL)) {
525 continue;
526 }
527 if ((colocation->primary_role >= RSC_ROLE_PROMOTED)
528 && (replica->child->next_role < RSC_ROLE_PROMOTED)) {
529 continue;
530 }
531
532 pe_rsc_trace(primary, "Allowing %s: %s %d",
533 colocation->id, pe__node_name(chosen), chosen->weight);
534 allocated_primaries = g_list_prepend(allocated_primaries, chosen);
535 }
536 }
537
538 if (colocation->score >= INFINITY) {
539 node_list_exclude(dependent->allowed_nodes, allocated_primaries, FALSE);
540 }
541 g_list_free(allocated_primaries);
542}
543
546{
547 GList *containers = NULL;
548 enum pe_action_flags flags = 0;
549 pe__bundle_variant_data_t *data = NULL;
550
551 get_bundle_variant_data(data, action->rsc);
552 if(data->child) {
553 enum action_tasks task = get_complex_task(data->child, action->task, TRUE);
554 switch(task) {
555 case no_action:
556 case action_notify:
557 case action_notified:
558 case action_promote:
559 case action_promoted:
560 case action_demote:
561 case action_demoted:
562 return summary_action_flags(action, data->child->children, node);
563 default:
564 break;
565 }
566 }
567
568 containers = get_container_list(action->rsc);
569 flags = summary_action_flags(action, containers, node);
570 g_list_free(containers);
571 return flags;
572}
573
576 const pe_node_t *local_node,
577 const pe_resource_t *rsc, enum rsc_role_e filter,
578 gboolean current)
579{
580 GList *gIter = NULL;
581 GList *children = NULL;
582
583 if (local_node == NULL) {
584 crm_err("Can't colocate unrunnable child %s with %s", local_child->id, rsc->id);
585 return NULL;
586 }
587
588 crm_trace("Looking for compatible child from %s for %s on %s",
589 local_child->id, rsc->id, pe__node_name(local_node));
590
591 children = get_containers_or_children(rsc);
592 for (gIter = children; gIter != NULL; gIter = gIter->next) {
593 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
594
595 if(is_child_compatible(child_rsc, local_node, filter, current)) {
596 crm_trace("Pairing %s with %s on %s",
597 local_child->id, child_rsc->id, pe__node_name(local_node));
598 return child_rsc;
599 }
600 }
601
602 crm_trace("Can't pair %s with %s", local_child->id, rsc->id);
603 if(children != rsc->children) {
604 g_list_free(children);
605 }
606 return NULL;
607}
608
609static pe__bundle_replica_t *
610replica_for_container(const pe_resource_t *rsc, const pe_resource_t *container,
611 const pe_node_t *node)
612{
613 if (rsc->variant == pe_container) {
614 const pe__bundle_variant_data_t *data = NULL;
615
616 get_bundle_variant_data(data, rsc);
617 for (GList *gIter = data->replicas; gIter != NULL;
618 gIter = gIter->next) {
619 pe__bundle_replica_t *replica = gIter->data;
620
621 if (replica->child
622 && (container == replica->container)
623 && pe__same_node(node, replica->node)) {
624 return replica;
625 }
626 }
627 }
628 return NULL;
629}
630
631static uint32_t
632multi_update_interleave_actions(pe_action_t *first, pe_action_t *then,
633 const pe_node_t *node, uint32_t filter,
634 uint32_t type, pe_working_set_t *data_set)
635{
636 GList *gIter = NULL;
637 GList *children = NULL;
638 gboolean current = FALSE;
639 uint32_t changed = pcmk__updated_none;
640
641 /* Fix this - lazy */
642 if (pcmk__ends_with(first->uuid, "_stopped_0")
643 || pcmk__ends_with(first->uuid, "_demoted_0")) {
644 current = TRUE;
645 }
646
647 children = get_containers_or_children(then->rsc);
648 for (gIter = children; gIter != NULL; gIter = gIter->next) {
649 pe_resource_t *then_child = gIter->data;
650 pe_resource_t *first_child = find_compatible_child(then_child,
651 first->rsc,
653 current);
654 if (first_child == NULL && current) {
655 crm_trace("Ignore");
656
657 } else if (first_child == NULL) {
658 crm_debug("No match found for %s (%d / %s / %s)", then_child->id, current, first->uuid, then->uuid);
659
660 /* Me no like this hack - but what else can we do?
661 *
662 * If there is no-one active or about to be active
663 * on the same node as then_child, then they must
664 * not be allowed to start
665 */
666 if (pcmk_any_flags_set(type, pe_order_runnable_left|pe_order_implies_then) /* Mandatory */ ) {
667 pe_rsc_info(then->rsc, "Inhibiting %s from being active", then_child->id);
668 if (pcmk__assign_resource(then_child, NULL, true)) {
670 }
671 }
672
673 } else {
674 pe_action_t *first_action = NULL;
675 pe_action_t *then_action = NULL;
676
677 enum action_tasks task = clone_child_action(first);
678 const char *first_task = task2text(task);
679
680 pe__bundle_replica_t *first_replica = NULL;
681 pe__bundle_replica_t *then_replica = NULL;
682
683 first_replica = replica_for_container(first->rsc, first_child,
684 node);
685 if (strstr(first->task, "stop") && first_replica && first_replica->child) {
686 /* Except for 'stopped' we should be looking at the
687 * in-container resource, actions for the child will
688 * happen later and are therefor more likely to align
689 * with the user's intent.
690 */
691 first_action = find_first_action(first_replica->child->actions,
692 NULL, task2text(task), node);
693 } else {
694 first_action = find_first_action(first_child->actions, NULL, task2text(task), node);
695 }
696
697 then_replica = replica_for_container(then->rsc, then_child, node);
698 if (strstr(then->task, "mote")
699 && then_replica && then_replica->child) {
700 /* Promote/demote actions will never be found for the
701 * container resource, look in the child instead
702 *
703 * Alternatively treat:
704 * 'XXXX then promote YYYY' as 'XXXX then start container for YYYY', and
705 * 'demote XXXX then stop YYYY' as 'stop container for XXXX then stop YYYY'
706 */
707 then_action = find_first_action(then_replica->child->actions,
708 NULL, then->task, node);
709 } else {
710 then_action = find_first_action(then_child->actions, NULL, then->task, node);
711 }
712
713 if (first_action == NULL) {
714 if (!pcmk_is_set(first_child->flags, pe_rsc_orphan)
715 && !pcmk__str_any_of(first_task, RSC_STOP, RSC_DEMOTE, NULL)) {
716 crm_err("Internal error: No action found for %s in %s (first)",
717 first_task, first_child->id);
718
719 } else {
720 crm_trace("No action found for %s in %s%s (first)",
721 first_task, first_child->id,
722 pcmk_is_set(first_child->flags, pe_rsc_orphan)? " (ORPHAN)" : "");
723 }
724 continue;
725 }
726
727 /* We're only interested if 'then' is neither stopping nor being demoted */
728 if (then_action == NULL) {
729 if (!pcmk_is_set(then_child->flags, pe_rsc_orphan)
730 && !pcmk__str_any_of(then->task, RSC_STOP, RSC_DEMOTE, NULL)) {
731 crm_err("Internal error: No action found for %s in %s (then)",
732 then->task, then_child->id);
733
734 } else {
735 crm_trace("No action found for %s in %s%s (then)",
736 then->task, then_child->id,
737 pcmk_is_set(then_child->flags, pe_rsc_orphan)? " (ORPHAN)" : "");
738 }
739 continue;
740 }
741
742 if (order_actions(first_action, then_action, type)) {
743 crm_debug("Created constraint for %s (%d) -> %s (%d) %.6x",
744 first_action->uuid,
745 pcmk_is_set(first_action->flags, pe_action_optional),
746 then_action->uuid,
747 pcmk_is_set(then_action->flags, pe_action_optional),
748 type);
749 pcmk__set_updated_flags(changed, first,
751 }
752 if(first_action && then_action) {
753 changed |= then_child->cmds->update_ordered_actions(first_action,
754 then_action,
755 node,
756 first_child->cmds->action_flags(first_action, node),
757 filter,
758 type,
759 data_set);
760 } else {
761 crm_err("Nothing found either for %s (%p) or %s (%p) %s",
762 first_child->id, first_action,
763 then_child->id, then_action, task2text(task));
764 }
765 }
766 }
767
768 if(children != then->rsc->children) {
769 g_list_free(children);
770 }
771 return changed;
772}
773
774static bool
775can_interleave_actions(pe_action_t *first, pe_action_t *then)
776{
777 bool interleave = FALSE;
778 pe_resource_t *rsc = NULL;
779 const char *interleave_s = NULL;
780
781 if(first->rsc == NULL || then->rsc == NULL) {
782 crm_trace("Not interleaving %s with %s (both must be resources)", first->uuid, then->uuid);
783 return FALSE;
784 } else if(first->rsc == then->rsc) {
785 crm_trace("Not interleaving %s with %s (must belong to different resources)", first->uuid, then->uuid);
786 return FALSE;
787 } else if(first->rsc->variant < pe_clone || then->rsc->variant < pe_clone) {
788 crm_trace("Not interleaving %s with %s (both sides must be clones or bundles)", first->uuid, then->uuid);
789 return FALSE;
790 }
791
792 if (pcmk__ends_with(then->uuid, "_stop_0")
793 || pcmk__ends_with(then->uuid, "_demote_0")) {
794 rsc = first->rsc;
795 } else {
796 rsc = then->rsc;
797 }
798
799 interleave_s = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERLEAVE);
800 interleave = crm_is_true(interleave_s);
801 crm_trace("Interleave %s -> %s: %s (based on %s)",
802 first->uuid, then->uuid, interleave ? "yes" : "no", rsc->id);
803
804 return interleave;
805}
806
829uint32_t
831 const pe_node_t *node, uint32_t flags,
832 uint32_t filter, uint32_t type,
834{
835 uint32_t changed = pcmk__updated_none;
836
837 crm_trace("%s -> %s", first->uuid, then->uuid);
838
839 if(can_interleave_actions(first, then)) {
840 changed = multi_update_interleave_actions(first, then, node, filter,
841 type, data_set);
842
843 } else if(then->rsc) {
844 GList *gIter = NULL;
845 GList *children = NULL;
846
847 // Handle the 'primitive' ordering case
848 changed |= pcmk__update_ordered_actions(first, then, node, flags,
849 filter, type, data_set);
850
851 // Now any children (or containers in the case of a bundle)
852 children = get_containers_or_children(then->rsc);
853 for (gIter = children; gIter != NULL; gIter = gIter->next) {
854 pe_resource_t *then_child = (pe_resource_t *) gIter->data;
855 uint32_t then_child_changed = pcmk__updated_none;
856 pe_action_t *then_child_action = find_first_action(then_child->actions, NULL, then->task, node);
857
858 if (then_child_action) {
859 uint32_t then_child_flags = then_child->cmds->action_flags(then_child_action,
860 node);
861
862 if (pcmk_is_set(then_child_flags, pe_action_runnable)) {
863 then_child_changed |= then_child->cmds->update_ordered_actions(first,
864 then_child_action,
865 node,
866 flags,
867 filter,
868 type,
869 data_set);
870 }
871 changed |= then_child_changed;
872 if (pcmk_is_set(then_child_changed, pcmk__updated_then)) {
873 for (GList *lpc = then_child_action->actions_after; lpc != NULL; lpc = lpc->next) {
874 pe_action_wrapper_t *next = (pe_action_wrapper_t *) lpc->data;
875
877 data_set);
878 }
879 }
880 }
881 }
882
883 if(children != then->rsc->children) {
884 g_list_free(children);
885 }
886 }
887 return changed;
888}
889
890void
892{
893 pe__bundle_variant_data_t *bundle_data = NULL;
894 get_bundle_variant_data(bundle_data, rsc);
895
896 pcmk__apply_location(rsc, constraint);
897
898 for (GList *gIter = bundle_data->replicas; gIter != NULL;
899 gIter = gIter->next) {
900 pe__bundle_replica_t *replica = gIter->data;
901
902 if (replica->container) {
903 replica->container->cmds->apply_location(replica->container,
904 constraint);
905 }
906 if (replica->ip) {
907 replica->ip->cmds->apply_location(replica->ip, constraint);
908 }
909 }
910
911 if (bundle_data->child
912 && ((constraint->role_filter == RSC_ROLE_UNPROMOTED)
913 || (constraint->role_filter == RSC_ROLE_PROMOTED))) {
914 bundle_data->child->cmds->apply_location(bundle_data->child,
915 constraint);
916 bundle_data->child->rsc_location = g_list_prepend(bundle_data->child->rsc_location,
917 constraint);
918 }
919}
920
927void
929{
930 pe__bundle_variant_data_t *bundle_data = NULL;
931
932 CRM_CHECK(rsc != NULL, return);
933
934 get_bundle_variant_data(bundle_data, rsc);
935
936 if (bundle_data->child) {
937 bundle_data->child->cmds->add_actions_to_graph(bundle_data->child);
938 }
939
940 for (GList *gIter = bundle_data->replicas; gIter != NULL;
941 gIter = gIter->next) {
942 pe__bundle_replica_t *replica = gIter->data;
943
944 CRM_ASSERT(replica);
945 if (replica->remote && replica->container
946 && pe__bundle_needs_remote_name(replica->remote, rsc->cluster)) {
947
948 /* REMOTE_CONTAINER_HACK: Allow remote nodes to run containers that
949 * run pacemaker-remoted inside, without needing a separate IP for
950 * the container. This is done by configuring the inner remote's
951 * connection host as the magic string "#uname", then
952 * replacing it with the underlying host when needed.
953 */
954 xmlNode *nvpair = get_xpath_object("//nvpair[@name='" XML_RSC_ATTR_REMOTE_RA_ADDR "']",
955 replica->remote->xml, LOG_ERR);
956 const char *calculated_addr = NULL;
957
958 // Replace the value in replica->remote->xml (if appropriate)
959 calculated_addr = pe__add_bundle_remote_name(replica->remote,
960 rsc->cluster,
961 nvpair, "value");
962 if (calculated_addr) {
963 /* Since this is for the bundle as a resource, and not any
964 * particular action, replace the value in the default
965 * parameters (not evaluated for node). create_graph_action()
966 * will grab it from there to replace it in node-evaluated
967 * parameters.
968 */
969 GHashTable *params = pe_rsc_params(replica->remote,
970 NULL, rsc->cluster);
971
972 g_hash_table_replace(params,
974 strdup(calculated_addr));
975 } else {
976 /* The only way to get here is if the remote connection is
977 * neither currently running nor scheduled to run. That means we
978 * won't be doing any operations that require addr (only start
979 * requires it; we additionally use it to compare digests when
980 * unpacking status, promote, and migrate_from history, but
981 * that's already happened by this point).
982 */
983 crm_info("Unable to determine address for bundle %s remote connection",
984 rsc->id);
985 }
986 }
987 if (replica->ip) {
988 replica->ip->cmds->add_actions_to_graph(replica->ip);
989 }
990 if (replica->container) {
991 replica->container->cmds->add_actions_to_graph(replica->container);
992 }
993 if (replica->remote) {
994 replica->remote->cmds->add_actions_to_graph(replica->remote);
995 }
996 }
997}
998
1009bool
1011{
1012 bool any_created = false;
1013 pe__bundle_variant_data_t *bundle_data = NULL;
1014
1015 CRM_CHECK(rsc != NULL, return false);
1016
1017 get_bundle_variant_data(bundle_data, rsc);
1018 for (GList *gIter = bundle_data->replicas; gIter != NULL;
1019 gIter = gIter->next) {
1020 pe__bundle_replica_t *replica = gIter->data;
1021
1022 CRM_ASSERT(replica);
1023 if ((replica->ip != NULL)
1024 && replica->ip->cmds->create_probe(replica->ip, node)) {
1025 any_created = true;
1026 }
1027 if ((replica->child != NULL) && (node->details == replica->node->details)
1028 && replica->child->cmds->create_probe(replica->child, node)) {
1029 any_created = true;
1030 }
1031 if ((replica->container != NULL)
1032 && replica->container->cmds->create_probe(replica->container,
1033 node)) {
1034 any_created = true;
1035
1036 /* If we're limited to one replica per host (due to
1037 * the lack of an IP range probably), then we don't
1038 * want any of our peer containers starting until
1039 * we've established that no other copies are already
1040 * running.
1041 *
1042 * Partly this is to ensure that nreplicas_per_host is
1043 * observed, but also to ensure that the containers
1044 * don't fail to start because the necessary port
1045 * mappings (which won't include an IP for uniqueness)
1046 * are already taken
1047 */
1048
1049 for (GList *tIter = bundle_data->replicas;
1050 tIter && (bundle_data->nreplicas_per_host == 1);
1051 tIter = tIter->next) {
1052 pe__bundle_replica_t *other = tIter->data;
1053
1054 if ((other != replica) && (other != NULL)
1055 && (other->container != NULL)) {
1056
1057 pcmk__new_ordering(replica->container,
1058 pcmk__op_key(replica->container->id, RSC_STATUS, 0),
1059 NULL, other->container,
1060 pcmk__op_key(other->container->id, RSC_START, 0),
1061 NULL,
1063 rsc->cluster);
1064 }
1065 }
1066 }
1067 if ((replica->container != NULL) && (replica->remote != NULL)
1068 && replica->remote->cmds->create_probe(replica->remote, node)) {
1069
1070 /* Do not probe the remote resource until we know where the
1071 * container is running. This is required for REMOTE_CONTAINER_HACK
1072 * to correctly probe remote resources.
1073 */
1074 char *probe_uuid = pcmk__op_key(replica->remote->id, RSC_STATUS,
1075 0);
1076 pe_action_t *probe = find_first_action(replica->remote->actions,
1077 probe_uuid, NULL, node);
1078
1079 free(probe_uuid);
1080 if (probe != NULL) {
1081 any_created = true;
1082 crm_trace("Ordering %s probe on %s",
1083 replica->remote->id, pe__node_name(node));
1084 pcmk__new_ordering(replica->container,
1085 pcmk__op_key(replica->container->id, RSC_START, 0),
1086 NULL, replica->remote, NULL, probe,
1087 pe_order_probe, rsc->cluster);
1088 }
1089 }
1090 }
1091 return any_created;
1092}
1093
1094void
1096{
1097 pe__bundle_variant_data_t *bundle_data = NULL;
1098
1099 CRM_CHECK(rsc != NULL, return);
1100
1101 get_bundle_variant_data(bundle_data, rsc);
1102 for (GList *gIter = bundle_data->replicas; gIter != NULL;
1103 gIter = gIter->next) {
1104 pe__bundle_replica_t *replica = gIter->data;
1105
1106 CRM_ASSERT(replica);
1107 if (replica->ip != NULL) {
1108 replica->ip->cmds->output_actions(replica->ip);
1109 }
1110 if (replica->container != NULL) {
1111 replica->container->cmds->output_actions(replica->container);
1112 }
1113 if (replica->remote != NULL) {
1114 replica->remote->cmds->output_actions(replica->remote);
1115 }
1116 if (replica->child != NULL) {
1117 replica->child->cmds->output_actions(replica->child);
1118 }
1119 }
1120}
1121
1122// Bundle implementation of resource_alloc_functions_t:add_utilization()
1123void
1125 const pe_resource_t *orig_rsc, GList *all_rscs,
1126 GHashTable *utilization)
1127{
1128 pe__bundle_variant_data_t *bundle_data = NULL;
1129 pe__bundle_replica_t *replica = NULL;
1130
1131 if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
1132 return;
1133 }
1134
1135 get_bundle_variant_data(bundle_data, rsc);
1136 if (bundle_data->replicas == NULL) {
1137 return;
1138 }
1139
1140 /* All bundle replicas are identical, so using the utilization of the first
1141 * is sufficient for any. Only the implicit container resource can have
1142 * utilization values.
1143 */
1144 replica = (pe__bundle_replica_t *) bundle_data->replicas->data;
1145 if (replica->container != NULL) {
1146 replica->container->cmds->add_utilization(replica->container, orig_rsc,
1147 all_rscs, utilization);
1148 }
1149}
1150
1151// Bundle implementation of resource_alloc_functions_t:shutdown_lock()
1152void
1154{
1155 return; // Bundles currently don't support shutdown locks
1156}
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition: operations.c:45
uint64_t flags
Definition: remote.c:3
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
const char * task2text(enum action_tasks task)
Definition: common.c:401
action_tasks
Definition: common.h:61
@ no_action
Definition: common.h:62
@ action_demote
Definition: common.h:72
@ action_demoted
Definition: common.h:73
@ action_notified
Definition: common.h:69
@ action_promote
Definition: common.h:70
@ action_promoted
Definition: common.h:71
@ action_notify
Definition: common.h:68
rsc_role_e
Possible roles that a resource can be in.
Definition: common.h:92
@ RSC_ROLE_PROMOTED
Definition: common.h:97
@ RSC_ROLE_UNKNOWN
Definition: common.h:93
@ RSC_ROLE_UNPROMOTED
Definition: common.h:96
GHashTable * pe_rsc_params(pe_resource_t *rsc, const pe_node_t *node, pe_working_set_t *data_set)
Get a table of resource parameters.
Definition: complex.c:429
enum crm_ais_msg_types type
Definition: cpg.c:3
char data[0]
Definition: cpg.c:10
#define RSC_PROMOTE
Definition: crm.h:205
#define RSC_DEMOTE
Definition: crm.h:207
#define RSC_STARTED
Definition: crm.h:200
#define RSC_STOPPED
Definition: crm.h:203
#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_STATUS
Definition: crm.h:213
#define RSC_DEMOTED
Definition: crm.h:208
G_GNUC_INTERNAL void pcmk__new_colocation(const char *id, const char *node_attr, int score, pe_resource_t *dependent, pe_resource_t *primary, const char *dependent_role, const char *primary_role, bool influence, pe_working_set_t *data_set)
#define pcmk__order_starts(rsc1, rsc2, flags)
#define pcmk__order_resource_actions(first_rsc, first_task, then_rsc, then_task, flags)
G_GNUC_INTERNAL void pcmk__update_action_for_orderings(pe_action_t *action, pe_working_set_t *data_set)
#define pcmk__set_updated_flags(au_flags, action, flags_to_set)
G_GNUC_INTERNAL GList * pcmk__sort_nodes(GList *nodes, pe_node_t *active_node)
G_GNUC_INTERNAL gint pcmk__cmp_instance(gconstpointer a, gconstpointer b)
G_GNUC_INTERNAL bool pcmk__assign_resource(pe_resource_t *rsc, pe_node_t *node, bool force)
@ pcmk__updated_none
@ pcmk__updated_first
@ pcmk__updated_then
G_GNUC_INTERNAL bool pcmk__threshold_reached(pe_resource_t *rsc, pe_node_t *node, pe_resource_t **failed)
G_GNUC_INTERNAL void pcmk__promotable_restart_ordering(pe_resource_t *rsc)
#define pcmk__order_stops(rsc1, rsc2, flags)
G_GNUC_INTERNAL void pcmk__apply_location(pe_resource_t *rsc, pe__location_t *constraint)
G_GNUC_INTERNAL uint32_t pcmk__update_ordered_actions(pe_action_t *first, pe_action_t *then, const pe_node_t *node, uint32_t flags, uint32_t filter, uint32_t type, pe_working_set_t *data_set)
G_GNUC_INTERNAL void pcmk__new_ordering(pe_resource_t *first_rsc, char *first_task, pe_action_t *first_action, pe_resource_t *then_rsc, char *then_task, pe_action_t *then_action, uint32_t flags, pe_working_set_t *data_set)
#define crm_info(fmt, args...)
Definition: logging.h:362
#define crm_notice(fmt, args...)
Definition: logging.h:361
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define crm_debug(fmt, args...)
Definition: logging.h:364
#define crm_err(fmt, args...)
Definition: logging.h:359
#define crm_trace(fmt, args...)
Definition: logging.h:365
#define XML_RSC_ATTR_INTERLEAVE
Definition: msg_xml.h:227
#define XML_RSC_ATTR_REMOTE_RA_ADDR
Definition: msg_xml.h:250
#define XML_RSC_ATTR_INCARNATION_NODEMAX
Definition: msg_xml.h:231
pe_working_set_t * data_set
const char * action
Definition: pcmk_fence.c:30
bool pcmk__bundle_create_probe(pe_resource_t *rsc, pe_node_t *node)
void pcmk__bundle_create_actions(pe_resource_t *rsc)
void pcmk__bundle_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
enum pe_action_flags pcmk__bundle_action_flags(pe_action_t *action, const pe_node_t *node)
pe_resource_t * find_compatible_child_by_node(const pe_resource_t *local_child, const pe_node_t *local_node, const pe_resource_t *rsc, enum rsc_role_e filter, gboolean current)
void pcmk__output_bundle_actions(pe_resource_t *rsc)
void pcmk__bundle_add_utilization(const pe_resource_t *rsc, const pe_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
void distribute_children(pe_resource_t *rsc, GList *children, GList *nodes, int max, int per_host_max, pe_working_set_t *data_set)
void pcmk__bundle_expand(pe_resource_t *rsc)
void pcmk__bundle_apply_coloc_score(pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
void pcmk__bundle_shutdown_lock(pe_resource_t *rsc)
int copies_per_node(pe_resource_t *rsc)
uint32_t pcmk__multi_update_actions(pe_action_t *first, pe_action_t *then, const pe_node_t *node, uint32_t flags, uint32_t filter, uint32_t type, pe_working_set_t *data_set)
void pcmk__bundle_internal_constraints(pe_resource_t *rsc)
pe_node_t * pcmk__bundle_allocate(pe_resource_t *rsc, const pe_node_t *prefer)
void clone_create_pseudo_actions(pe_resource_t *rsc, GList *children, notify_data_t **start_notify, notify_data_t **stop_notify)
enum pe_action_flags summary_action_flags(pe_action_t *action, GList *children, const pe_node_t *node)
enum action_tasks clone_child_action(pe_action_t *action)
gboolean is_child_compatible(const pe_resource_t *child_rsc, const pe_node_t *local_node, enum rsc_role_e filter, gboolean current)
pe_resource_t * find_compatible_child(const pe_resource_t *local_child, const pe_resource_t *rsc, enum rsc_role_e filter, gboolean current)
#define pe_rsc_block
Definition: pe_types.h:258
@ pe_order_implies_first_printed
Definition: pe_types.h:508
@ pe_order_implies_then
Definition: pe_types.h:485
@ pe_order_same_node
Definition: pe_types.h:506
@ pe_order_preserve
Definition: pe_types.h:516
@ pe_order_implies_then_printed
Definition: pe_types.h:509
@ pe_order_optional
Definition: pe_types.h:481
@ pe_order_implies_first
Definition: pe_types.h:484
@ pe_order_runnable_left
Definition: pe_types.h:491
@ pe_order_probe
Definition: pe_types.h:498
#define pe_rsc_provisional
Definition: pe_types.h:266
#define pe_rsc_allocating
Definition: pe_types.h:267
#define pe_rsc_orphan
Definition: pe_types.h:256
#define pe_flag_show_scores
Definition: pe_types.h:134
pe_action_flags
Definition: pe_types.h:298
@ pe_action_optional
Definition: pe_types.h:301
@ pe_action_runnable
Definition: pe_types.h:300
@ pe_group
Definition: pe_types.h:39
@ pe_container
Definition: pe_types.h:41
@ pe_unknown
Definition: pe_types.h:37
@ pe_native
Definition: pe_types.h:38
@ pe_clone
Definition: pe_types.h:40
#define pe_rsc_promotable
Definition: pe_types.h:264
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition: internal.h:394
void node_list_exclude(GHashTable *list, GList *list2, gboolean merge_scores)
Definition: utils.c:108
const char * pe__add_bundle_remote_name(pe_resource_t *rsc, pe_working_set_t *data_set, xmlNode *xml, const char *field)
Definition: bundle.c:708
bool is_set_recursive(const pe_resource_t *rsc, long long flag, bool any)
Definition: clone.c:496
pe_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pe_node_t *on_node)
Definition: pe_actions.c:1296
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:80
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:46
bool pe__bundle_needs_remote_name(pe_resource_t *rsc, pe_working_set_t *data_set)
Definition: bundle.c:690
pe_action_t * pe__new_rsc_pseudo_action(pe_resource_t *rsc, const char *task, bool optional, bool runnable)
Definition: pe_actions.c:1647
enum action_tasks get_complex_task(pe_resource_t *rsc, const char *name, gboolean allow_non_atomic)
Definition: pe_actions.c:1262
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:474
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:47
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:74
#define pe_rsc_info(rsc, fmt, args...)
Definition: internal.h:45
bool pe__is_guest_or_remote_node(const pe_node_t *node)
Definition: remote.c:41
#define CRM_ASSERT(expr)
Definition: results.h:42
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition: strings.c:127
bool pcmk__ends_with(const char *s, const char *match)
Definition: strings.c:536
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:952
pe_resource_t * dependent
enum rsc_role_e role_filter
Definition: internal.h:189
pe_resource_t * rsc
Definition: pe_types.h:406
char * uuid
Definition: pe_types.h:411
char * task
Definition: pe_types.h:410
enum pe_action_flags flags
Definition: pe_types.h:415
pe_action_t * action
Definition: pe_types.h:530
int weight
Definition: pe_types.h:249
struct pe_node_shared_s * details
Definition: pe_types.h:252
pe_resource_t * remote_rsc
Definition: pe_types.h:237
GList * actions
Definition: pe_types.h:366
enum pe_obj_types variant
Definition: pe_types.h:338
GHashTable * meta
Definition: pe_types.h:380
GList * children
Definition: pe_types.h:384
pe_working_set_t * cluster
Definition: pe_types.h:335
pe_resource_t * container
Definition: pe_types.h:387
char * id
Definition: pe_types.h:329
GHashTable * allowed_nodes
Definition: pe_types.h:375
unsigned long long flags
Definition: pe_types.h:355
resource_alloc_functions_t * cmds
Definition: pe_types.h:341
resource_object_functions_t * fns
Definition: pe_types.h:340
unsigned long long flags
Definition: pe_types.h:153
uint32_t(* update_ordered_actions)(pe_action_t *first, pe_action_t *then, const pe_node_t *node, uint32_t flags, uint32_t filter, uint32_t type, pe_working_set_t *data_set)
void(* apply_coloc_score)(pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
enum pe_action_flags(* action_flags)(pe_action_t *action, const pe_node_t *node)
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:55
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:214