pacemaker 2.1.8-2.1.8
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_sched_primitive.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2024 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU 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#include <stdint.h> // uint8_t, uint32_t
14
15#include <crm/common/xml.h>
16#include <pacemaker-internal.h>
17
19
20static void stop_resource(pcmk_resource_t *rsc, pcmk_node_t *node,
21 bool optional);
22static void start_resource(pcmk_resource_t *rsc, pcmk_node_t *node,
23 bool optional);
24static void demote_resource(pcmk_resource_t *rsc, pcmk_node_t *node,
25 bool optional);
26static void promote_resource(pcmk_resource_t *rsc, pcmk_node_t *node,
27 bool optional);
28static void assert_role_error(pcmk_resource_t *rsc, pcmk_node_t *node,
29 bool optional);
30
31#define RSC_ROLE_MAX (pcmk_role_promoted + 1)
32
33static enum rsc_role_e rsc_state_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX] = {
34 /* This array lists the immediate next role when transitioning from one role
35 * to a target role. For example, when going from Stopped to Promoted, the
36 * next role is Unpromoted, because the resource must be started before it
37 * can be promoted. The current state then becomes Started, which is fed
38 * into this array again, giving a next role of Promoted.
39 *
40 * Current role Immediate next role Final target role
41 * ------------ ------------------- -----------------
42 */
43 /* Unknown */ { pcmk_role_unknown, /* Unknown */
44 pcmk_role_stopped, /* Stopped */
45 pcmk_role_stopped, /* Started */
46 pcmk_role_stopped, /* Unpromoted */
47 pcmk_role_stopped, /* Promoted */
48 },
49 /* Stopped */ { pcmk_role_stopped, /* Unknown */
50 pcmk_role_stopped, /* Stopped */
51 pcmk_role_started, /* Started */
52 pcmk_role_unpromoted, /* Unpromoted */
53 pcmk_role_unpromoted, /* Promoted */
54 },
55 /* Started */ { pcmk_role_stopped, /* Unknown */
56 pcmk_role_stopped, /* Stopped */
57 pcmk_role_started, /* Started */
58 pcmk_role_unpromoted, /* Unpromoted */
59 pcmk_role_promoted, /* Promoted */
60 },
61 /* Unpromoted */ { pcmk_role_stopped, /* Unknown */
62 pcmk_role_stopped, /* Stopped */
63 pcmk_role_stopped, /* Started */
64 pcmk_role_unpromoted, /* Unpromoted */
65 pcmk_role_promoted, /* Promoted */
66 },
67 /* Promoted */ { pcmk_role_stopped, /* Unknown */
68 pcmk_role_unpromoted, /* Stopped */
69 pcmk_role_unpromoted, /* Started */
70 pcmk_role_unpromoted, /* Unpromoted */
71 pcmk_role_promoted, /* Promoted */
72 },
73};
74
83typedef void (*rsc_transition_fn)(pcmk_resource_t *rsc, pcmk_node_t *node,
84 bool optional);
85
86static rsc_transition_fn rsc_action_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX] = {
87 /* This array lists the function needed to transition directly from one role
88 * to another. NULL indicates that nothing is needed.
89 *
90 * Current role Transition function Next role
91 * ------------ ------------------- ----------
92 */
93 /* Unknown */ { assert_role_error, /* Unknown */
94 stop_resource, /* Stopped */
95 assert_role_error, /* Started */
96 assert_role_error, /* Unpromoted */
97 assert_role_error, /* Promoted */
98 },
99 /* Stopped */ { assert_role_error, /* Unknown */
100 NULL, /* Stopped */
101 start_resource, /* Started */
102 start_resource, /* Unpromoted */
103 assert_role_error, /* Promoted */
104 },
105 /* Started */ { assert_role_error, /* Unknown */
106 stop_resource, /* Stopped */
107 NULL, /* Started */
108 NULL, /* Unpromoted */
109 promote_resource, /* Promoted */
110 },
111 /* Unpromoted */ { assert_role_error, /* Unknown */
112 stop_resource, /* Stopped */
113 stop_resource, /* Started */
114 NULL, /* Unpromoted */
115 promote_resource, /* Promoted */
116 },
117 /* Promoted */ { assert_role_error, /* Unknown */
118 demote_resource, /* Stopped */
119 demote_resource, /* Started */
120 demote_resource, /* Unpromoted */
121 NULL, /* Promoted */
122 },
123};
124
133static GList *
134sorted_allowed_nodes(const pcmk_resource_t *rsc)
135{
136 if (rsc->allowed_nodes != NULL) {
137 GList *nodes = g_hash_table_get_values(rsc->allowed_nodes);
138
139 if (nodes != NULL) {
140 return pcmk__sort_nodes(nodes, pcmk__current_node(rsc));
141 }
142 }
143 return NULL;
144}
145
165static bool
166assign_best_node(pcmk_resource_t *rsc, const pcmk_node_t *prefer,
167 bool stop_if_fail)
168{
169 GList *nodes = NULL;
170 pcmk_node_t *chosen = NULL;
171 pcmk_node_t *best = NULL;
172 const pcmk_node_t *most_free_node = pcmk__ban_insufficient_capacity(rsc);
173
174 if (prefer == NULL) {
175 prefer = most_free_node;
176 }
177
179 // We've already finished assignment of resources to nodes
180 return rsc->allocated_to != NULL;
181 }
182
183 // Sort allowed nodes by score
184 nodes = sorted_allowed_nodes(rsc);
185 if (nodes != NULL) {
186 best = (pcmk_node_t *) nodes->data; // First node has best score
187 }
188
189 if ((prefer != NULL) && (nodes != NULL)) {
190 // Get the allowed node version of prefer
191 chosen = g_hash_table_lookup(rsc->allowed_nodes, prefer->details->id);
192
193 if (chosen == NULL) {
194 pcmk__rsc_trace(rsc, "Preferred node %s for %s was unknown",
195 pcmk__node_name(prefer), rsc->id);
196
197 /* Favor the preferred node as long as its score is at least as good as
198 * the best allowed node's.
199 *
200 * An alternative would be to favor the preferred node even if the best
201 * node is better, when the best node's score is less than INFINITY.
202 */
203 } else if (chosen->weight < best->weight) {
204 pcmk__rsc_trace(rsc, "Preferred node %s for %s was unsuitable",
205 pcmk__node_name(chosen), rsc->id);
206 chosen = NULL;
207
208 } else if (!pcmk__node_available(chosen, true, false)) {
209 pcmk__rsc_trace(rsc, "Preferred node %s for %s was unavailable",
210 pcmk__node_name(chosen), rsc->id);
211 chosen = NULL;
212
213 } else {
214 pcmk__rsc_trace(rsc,
215 "Chose preferred node %s for %s "
216 "(ignoring %d candidates)",
217 pcmk__node_name(chosen), rsc->id,
218 g_list_length(nodes));
219 }
220 }
221
222 if ((chosen == NULL) && (best != NULL)) {
223 /* Either there is no preferred node, or the preferred node is not
224 * suitable, but another node is allowed to run the resource.
225 */
226
227 chosen = best;
228
229 if (!pcmk__is_unique_clone(rsc->parent)
230 && (chosen->weight > 0) // Zero not acceptable
231 && pcmk__node_available(chosen, false, false)) {
232 /* If the resource is already running on a node, prefer that node if
233 * it is just as good as the chosen node.
234 *
235 * We don't do this for unique clone instances, because
236 * pcmk__assign_instances() has already assigned instances to their
237 * running nodes when appropriate, and if we get here, we don't want
238 * remaining unassigned instances to prefer a node that's already
239 * running another instance.
240 */
241 pcmk_node_t *running = pcmk__current_node(rsc);
242
243 if (running == NULL) {
244 // Nothing to do
245
246 } else if (!pcmk__node_available(running, true, false)) {
247 pcmk__rsc_trace(rsc,
248 "Current node for %s (%s) can't run resources",
249 rsc->id, pcmk__node_name(running));
250
251 } else {
252 int nodes_with_best_score = 1;
253
254 for (GList *iter = nodes->next; iter; iter = iter->next) {
255 pcmk_node_t *allowed = (pcmk_node_t *) iter->data;
256
257 if (allowed->weight != chosen->weight) {
258 // The nodes are sorted by score, so no more are equal
259 break;
260 }
261 if (pcmk__same_node(allowed, running)) {
262 // Scores are equal, so prefer the current node
263 chosen = allowed;
264 }
265 nodes_with_best_score++;
266 }
267
268 if (nodes_with_best_score > 1) {
269 uint8_t log_level = LOG_INFO;
270
271 if (chosen->weight >= PCMK_SCORE_INFINITY) {
272 log_level = LOG_WARNING;
273 }
274 do_crm_log(log_level,
275 "Chose %s for %s from %d nodes with score %s",
276 pcmk__node_name(chosen), rsc->id,
277 nodes_with_best_score,
278 pcmk_readable_score(chosen->weight));
279 }
280 }
281 }
282
283 pcmk__rsc_trace(rsc, "Chose %s for %s from %d candidates",
284 pcmk__node_name(chosen), rsc->id, g_list_length(nodes));
285 }
286
287 pcmk__assign_resource(rsc, chosen, false, stop_if_fail);
288 g_list_free(nodes);
289 return rsc->allocated_to != NULL;
290}
291
299static void
300apply_this_with(pcmk__colocation_t *colocation, pcmk_resource_t *rsc)
301{
302 GHashTable *archive = NULL;
303 pcmk_resource_t *other = colocation->primary;
304
305 // In certain cases, we will need to revert the node scores
306 if ((colocation->dependent_role >= pcmk_role_promoted)
307 || ((colocation->score < 0)
308 && (colocation->score > -PCMK_SCORE_INFINITY))) {
309 archive = pcmk__copy_node_table(rsc->allowed_nodes);
310 }
311
313 pcmk__rsc_trace(rsc,
314 "%s: Assigning colocation %s primary %s first"
315 "(score=%d role=%s)",
316 rsc->id, colocation->id, other->id,
317 colocation->score,
318 pcmk_role_text(colocation->dependent_role));
319 other->cmds->assign(other, NULL, true);
320 }
321
322 // Apply the colocation score to this resource's allowed node scores
323 rsc->cmds->apply_coloc_score(rsc, other, colocation, true);
324 if ((archive != NULL)
326 pcmk__rsc_info(rsc,
327 "%s: Reverting scores from colocation with %s "
328 "because no nodes allowed",
329 rsc->id, other->id);
330 g_hash_table_destroy(rsc->allowed_nodes);
331 rsc->allowed_nodes = archive;
332 archive = NULL;
333 }
334 if (archive != NULL) {
335 g_hash_table_destroy(archive);
336 }
337}
338
345static void
346remote_connection_assigned(const pcmk_resource_t *connection)
347{
348 pcmk_node_t *remote_node = pcmk_find_node(connection->cluster,
349 connection->id);
350
351 CRM_CHECK(remote_node != NULL, return);
352
353 if ((connection->allocated_to != NULL)
354 && (connection->next_role != pcmk_role_stopped)) {
355
356 crm_trace("Pacemaker Remote node %s will be online",
357 remote_node->details->id);
358 remote_node->details->online = TRUE;
359 if (remote_node->details->unseen) {
360 // Avoid unnecessary fence, since we will attempt connection
361 remote_node->details->unclean = FALSE;
362 }
363
364 } else {
365 crm_trace("Pacemaker Remote node %s will be shut down "
366 "(%sassigned connection's next role is %s)",
367 remote_node->details->id,
368 ((connection->allocated_to == NULL)? "un" : ""),
369 pcmk_role_text(connection->next_role));
370 remote_node->details->shutdown = TRUE;
371 }
372}
373
394 bool stop_if_fail)
395{
396 GList *this_with_colocations = NULL;
397 GList *with_this_colocations = NULL;
398 GList *iter = NULL;
399 pcmk__colocation_t *colocation = NULL;
400
401 CRM_ASSERT(pcmk__is_primitive(rsc));
402
403 // Never assign a child without parent being assigned first
404 if ((rsc->parent != NULL)
406 pcmk__rsc_debug(rsc, "%s: Assigning parent %s first",
407 rsc->id, rsc->parent->id);
408 rsc->parent->cmds->assign(rsc->parent, prefer, stop_if_fail);
409 }
410
412 // Assignment has already been done
413 const char *node_name = "no node";
414
415 if (rsc->allocated_to != NULL) {
416 node_name = pcmk__node_name(rsc->allocated_to);
417 }
418 pcmk__rsc_debug(rsc, "%s: pre-assigned to %s", rsc->id, node_name);
419 return rsc->allocated_to;
420 }
421
422 // Ensure we detect assignment loops
424 pcmk__rsc_debug(rsc, "Breaking assignment loop involving %s", rsc->id);
425 return NULL;
426 }
428
429 pe__show_node_scores(true, rsc, "Pre-assignment", rsc->allowed_nodes,
430 rsc->cluster);
431
432 this_with_colocations = pcmk__this_with_colocations(rsc);
433 with_this_colocations = pcmk__with_this_colocations(rsc);
434
435 // Apply mandatory colocations first, to satisfy as many as possible
436 for (iter = this_with_colocations; iter != NULL; iter = iter->next) {
437 colocation = iter->data;
438
439 if ((colocation->score <= -PCMK_SCORE_INFINITY)
440 || (colocation->score >= PCMK_SCORE_INFINITY)) {
441 apply_this_with(colocation, rsc);
442 }
443 }
444 for (iter = with_this_colocations; iter != NULL; iter = iter->next) {
445 colocation = iter->data;
446
447 if ((colocation->score <= -PCMK_SCORE_INFINITY)
448 || (colocation->score >= PCMK_SCORE_INFINITY)) {
449 pcmk__add_dependent_scores(colocation, rsc);
450 }
451 }
452
453 pe__show_node_scores(true, rsc, "Mandatory-colocations",
454 rsc->allowed_nodes, rsc->cluster);
455
456 // Then apply optional colocations
457 for (iter = this_with_colocations; iter != NULL; iter = iter->next) {
458 colocation = iter->data;
459
460 if ((colocation->score > -PCMK_SCORE_INFINITY)
461 && (colocation->score < PCMK_SCORE_INFINITY)) {
462 apply_this_with(colocation, rsc);
463 }
464 }
465 for (iter = with_this_colocations; iter != NULL; iter = iter->next) {
466 colocation = iter->data;
467
468 if ((colocation->score > -PCMK_SCORE_INFINITY)
469 && (colocation->score < PCMK_SCORE_INFINITY)) {
470 pcmk__add_dependent_scores(colocation, rsc);
471 }
472 }
473
474 g_list_free(this_with_colocations);
475 g_list_free(with_this_colocations);
476
477 if (rsc->next_role == pcmk_role_stopped) {
478 pcmk__rsc_trace(rsc,
479 "Banning %s from all nodes because it will be stopped",
480 rsc->id);
483
484 } else if ((rsc->next_role > rsc->role)
487 crm_notice("Resource %s cannot be elevated from %s to %s due to "
489 rsc->id, pcmk_role_text(rsc->role),
491 pe__set_next_role(rsc, rsc->role,
493 }
494
497 rsc, __func__, rsc->allowed_nodes, rsc->cluster);
498
499 // Unmanage resource if fencing is enabled but no device is configured
503 }
504
505 if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
506 // Unmanaged resources stay on their current node
507 const char *reason = NULL;
508 pcmk_node_t *assign_to = NULL;
509
510 pe__set_next_role(rsc, rsc->role, "unmanaged");
511 assign_to = pcmk__current_node(rsc);
512 if (assign_to == NULL) {
513 reason = "inactive";
514 } else if (rsc->role == pcmk_role_promoted) {
515 reason = "promoted";
516 } else if (pcmk_is_set(rsc->flags, pcmk_rsc_failed)) {
517 reason = "failed";
518 } else {
519 reason = "active";
520 }
521 pcmk__rsc_info(rsc, "Unmanaged resource %s assigned to %s: %s", rsc->id,
522 (assign_to? assign_to->details->uname : "no node"),
523 reason);
524 pcmk__assign_resource(rsc, assign_to, true, stop_if_fail);
525
526 } else if (pcmk_is_set(rsc->cluster->flags, pcmk_sched_stop_all)) {
527 // Must stop at some point, but be consistent with stop_if_fail
528 if (stop_if_fail) {
529 pcmk__rsc_debug(rsc,
530 "Forcing %s to stop: " PCMK_OPT_STOP_ALL_RESOURCES,
531 rsc->id);
532 }
533 pcmk__assign_resource(rsc, NULL, true, stop_if_fail);
534
535 } else if (!assign_best_node(rsc, prefer, stop_if_fail)) {
536 // Assignment failed
537 if (!pcmk_is_set(rsc->flags, pcmk_rsc_removed)) {
538 pcmk__rsc_info(rsc, "Resource %s cannot run anywhere", rsc->id);
539 } else if ((rsc->running_on != NULL) && stop_if_fail) {
540 pcmk__rsc_info(rsc, "Stopping removed resource %s", rsc->id);
541 }
542 }
543
545
546 if (rsc->is_remote_node) {
547 remote_connection_assigned(rsc);
548 }
549
550 return rsc->allocated_to;
551}
552
564static void
565schedule_restart_actions(pcmk_resource_t *rsc, pcmk_node_t *current,
566 bool need_stop, bool need_promote)
567{
568 enum rsc_role_e role = rsc->role;
569 enum rsc_role_e next_role;
570 rsc_transition_fn fn = NULL;
571
573
574 // Bring resource down to a stop on its current node
575 while (role != pcmk_role_stopped) {
576 next_role = rsc_state_matrix[role][pcmk_role_stopped];
577 pcmk__rsc_trace(rsc, "Creating %s action to take %s down from %s to %s",
578 (need_stop? "required" : "optional"), rsc->id,
579 pcmk_role_text(role), pcmk_role_text(next_role));
580 fn = rsc_action_matrix[role][next_role];
581 if (fn == NULL) {
582 break;
583 }
584 fn(rsc, current, !need_stop);
585 role = next_role;
586 }
587
588 // Bring resource up to its next role on its next node
589 while ((rsc->role <= rsc->next_role) && (role != rsc->role)
591 bool required = need_stop;
592
593 next_role = rsc_state_matrix[role][rsc->role];
594 if ((next_role == pcmk_role_promoted) && need_promote) {
595 required = true;
596 }
597 pcmk__rsc_trace(rsc, "Creating %s action to take %s up from %s to %s",
598 (required? "required" : "optional"), rsc->id,
599 pcmk_role_text(role), pcmk_role_text(next_role));
600 fn = rsc_action_matrix[role][next_role];
601 if (fn == NULL) {
602 break;
603 }
604 fn(rsc, rsc->allocated_to, !required);
605 role = next_role;
606 }
607
609}
610
619static const char *
620set_default_next_role(pcmk_resource_t *rsc)
621{
622 if (rsc->next_role != pcmk_role_unknown) {
623 return "explicit";
624 }
625
626 if (rsc->allocated_to == NULL) {
627 pe__set_next_role(rsc, pcmk_role_stopped, "assignment");
628 } else {
629 pe__set_next_role(rsc, pcmk_role_started, "assignment");
630 }
631 return "implicit";
632}
633
640static void
641create_pending_start(pcmk_resource_t *rsc)
642{
643 pcmk_action_t *start = NULL;
644
645 pcmk__rsc_trace(rsc,
646 "Creating action for %s to represent already pending start",
647 rsc->id);
648 start = start_action(rsc, rsc->allocated_to, TRUE);
650}
651
658static void
659schedule_role_transition_actions(pcmk_resource_t *rsc)
660{
661 enum rsc_role_e role = rsc->role;
662
663 while (role != rsc->next_role) {
664 enum rsc_role_e next_role = rsc_state_matrix[role][rsc->next_role];
665 rsc_transition_fn fn = NULL;
666
667 pcmk__rsc_trace(rsc,
668 "Creating action to take %s from %s to %s "
669 "(ending at %s)",
670 rsc->id, pcmk_role_text(role),
671 pcmk_role_text(next_role),
673 fn = rsc_action_matrix[role][next_role];
674 if (fn == NULL) {
675 break;
676 }
677 fn(rsc, rsc->allocated_to, false);
678 role = next_role;
679 }
680}
681
688void
690{
691 bool need_stop = false;
692 bool need_promote = false;
693 bool is_moving = false;
694 bool allow_migrate = false;
695 bool multiply_active = false;
696
697 pcmk_node_t *current = NULL;
698 unsigned int num_all_active = 0;
699 unsigned int num_clean_active = 0;
700 const char *next_role_source = NULL;
701
702 CRM_ASSERT(pcmk__is_primitive(rsc));
703
704 next_role_source = set_default_next_role(rsc);
705 pcmk__rsc_trace(rsc,
706 "Creating all actions for %s transition from %s to %s "
707 "(%s) on %s",
708 rsc->id, pcmk_role_text(rsc->role),
709 pcmk_role_text(rsc->next_role), next_role_source,
710 pcmk__node_name(rsc->allocated_to));
711
712 current = rsc->fns->active_node(rsc, &num_all_active, &num_clean_active);
713
715 rsc);
716
717 if ((current != NULL) && (rsc->allocated_to != NULL)
718 && !pcmk__same_node(current, rsc->allocated_to)
719 && (rsc->next_role >= pcmk_role_started)) {
720
721 pcmk__rsc_trace(rsc, "Moving %s from %s to %s",
722 rsc->id, pcmk__node_name(current),
723 pcmk__node_name(rsc->allocated_to));
724 is_moving = true;
725 allow_migrate = pcmk__rsc_can_migrate(rsc, current);
726
727 // This is needed even if migrating (though I'm not sure why ...)
728 need_stop = true;
729 }
730
731 // Check whether resource is partially migrated and/or multiply active
732 if ((rsc->partial_migration_source != NULL)
733 && (rsc->partial_migration_target != NULL)
734 && allow_migrate && (num_all_active == 2)
735 && pcmk__same_node(current, rsc->partial_migration_source)
736 && pcmk__same_node(rsc->allocated_to, rsc->partial_migration_target)) {
737 /* A partial migration is in progress, and the migration target remains
738 * the same as when the migration began.
739 */
740 pcmk__rsc_trace(rsc,
741 "Partial migration of %s from %s to %s will continue",
742 rsc->id, pcmk__node_name(rsc->partial_migration_source),
743 pcmk__node_name(rsc->partial_migration_target));
744
745 } else if ((rsc->partial_migration_source != NULL)
746 || (rsc->partial_migration_target != NULL)) {
747 // A partial migration is in progress but can't be continued
748
749 if (num_all_active > 2) {
750 // The resource is migrating *and* multiply active!
751 crm_notice("Forcing recovery of %s because it is migrating "
752 "from %s to %s and possibly active elsewhere",
753 rsc->id, pcmk__node_name(rsc->partial_migration_source),
754 pcmk__node_name(rsc->partial_migration_target));
755 } else {
756 // The migration source or target isn't available
757 crm_notice("Forcing recovery of %s because it can no longer "
758 "migrate from %s to %s",
759 rsc->id, pcmk__node_name(rsc->partial_migration_source),
760 pcmk__node_name(rsc->partial_migration_target));
761 }
762 need_stop = true;
764 allow_migrate = false;
765
766 } else if (pcmk_is_set(rsc->flags, pcmk_rsc_needs_fencing)) {
767 multiply_active = (num_all_active > 1);
768 } else {
769 /* If a resource has PCMK_META_REQUIRES set to PCMK_VALUE_NOTHING or
770 * PCMK_VALUE_QUORUM, don't consider it active on unclean nodes (similar
771 * to how all resources behave when PCMK_OPT_STONITH_ENABLED is false).
772 * We can start such resources elsewhere before fencing completes, and
773 * if we considered the resource active on the failed node, we would
774 * attempt recovery for being active on multiple nodes.
775 */
776 multiply_active = (num_clean_active > 1);
777 }
778
779 if (multiply_active) {
780 const char *class = crm_element_value(rsc->xml, PCMK_XA_CLASS);
781
782 // Resource was (possibly) incorrectly multiply active
783 pcmk__sched_err("%s resource %s might be active on %u nodes (%s)",
784 pcmk__s(class, "Untyped"), rsc->id, num_all_active,
785 pcmk__multiply_active_text(rsc->recovery_type));
786 crm_notice("For more information, see \"What are multiply active "
787 "resources?\" at "
788 "https://projects.clusterlabs.org/w/clusterlabs/faq/");
789
790 switch (rsc->recovery_type) {
792 need_stop = true;
793 break;
795 need_stop = true; // stop_resource() will skip expected node
797 break;
798 default:
799 break;
800 }
801
802 } else {
804 }
805
807 create_pending_start(rsc);
808 }
809
810 if (is_moving) {
811 // Remaining tests are only for resources staying where they are
812
813 } else if (pcmk_is_set(rsc->flags, pcmk_rsc_failed)) {
815 need_stop = true;
816 pcmk__rsc_trace(rsc, "Recovering %s", rsc->id);
817 } else {
818 pcmk__rsc_trace(rsc, "Recovering %s by demotion", rsc->id);
819 if (rsc->next_role == pcmk_role_promoted) {
820 need_promote = true;
821 }
822 }
823
824 } else if (pcmk_is_set(rsc->flags, pcmk_rsc_blocked)) {
825 pcmk__rsc_trace(rsc, "Blocking further actions on %s", rsc->id);
826 need_stop = true;
827
828 } else if ((rsc->role > pcmk_role_started) && (current != NULL)
829 && (rsc->allocated_to != NULL)) {
830 pcmk_action_t *start = NULL;
831
832 pcmk__rsc_trace(rsc, "Creating start action for promoted resource %s",
833 rsc->id);
834 start = start_action(rsc, rsc->allocated_to, TRUE);
835 if (!pcmk_is_set(start->flags, pcmk_action_optional)) {
836 // Recovery of a promoted resource
837 pcmk__rsc_trace(rsc, "%s restart is required for recovery", rsc->id);
838 need_stop = true;
839 }
840 }
841
842 // Create any actions needed to bring resource down and back up to same role
843 schedule_restart_actions(rsc, current, need_stop, need_promote);
844
845 // Create any actions needed to take resource from this role to the next
846 schedule_role_transition_actions(rsc);
847
849
850 if (allow_migrate) {
851 pcmk__create_migration_actions(rsc, current);
852 }
853}
854
861static void
862rsc_avoids_remote_nodes(const pcmk_resource_t *rsc)
863{
864 GHashTableIter iter;
865 pcmk_node_t *node = NULL;
866
867 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
868 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
869 if (node->details->remote_rsc != NULL) {
870 node->weight = -PCMK_SCORE_INFINITY;
871 }
872 }
873}
874
888static GList *
889allowed_nodes_as_list(const pcmk_resource_t *rsc)
890{
891 GList *allowed_nodes = NULL;
892
893 if (rsc->allowed_nodes) {
894 allowed_nodes = g_hash_table_get_values(rsc->allowed_nodes);
895 }
896
897 if (!pcmk__is_daemon) {
898 allowed_nodes = g_list_sort(allowed_nodes, pe__cmp_node_name);
899 }
900
901 return allowed_nodes;
902}
903
910void
912{
913 GList *allowed_nodes = NULL;
914 bool check_unfencing = false;
915 bool check_utilization = false;
916
917 CRM_ASSERT(pcmk__is_primitive(rsc));
918
919 if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
920 pcmk__rsc_trace(rsc,
921 "Skipping implicit constraints for unmanaged resource "
922 "%s", rsc->id);
923 return;
924 }
925
926 // Whether resource requires unfencing
927 check_unfencing = !pcmk_is_set(rsc->flags, pcmk_rsc_fence_device)
928 && pcmk_is_set(rsc->cluster->flags,
931
932 // Whether a non-default placement strategy is used
933 check_utilization = (g_hash_table_size(rsc->utilization) > 0)
934 && !pcmk__str_eq(rsc->cluster->placement_strategy,
936
937 // Order stops before starts (i.e. restart)
939 rsc, pcmk__op_key(rsc->id, PCMK_ACTION_START, 0), NULL,
943 rsc->cluster);
944
945 // Promotable ordering: demote before stop, start before promote
948 || (rsc->role > pcmk_role_unpromoted)) {
949
951 NULL,
952 rsc, pcmk__op_key(rsc->id, PCMK_ACTION_STOP, 0),
953 NULL,
955
957 NULL,
958 rsc, pcmk__op_key(rsc->id, PCMK_ACTION_PROMOTE, 0),
959 NULL,
961 }
962
963 // Don't clear resource history if probing on same node
965 NULL, rsc,
967 NULL,
969 rsc->cluster);
970
971 // Certain checks need allowed nodes
972 if (check_unfencing || check_utilization || (rsc->container != NULL)) {
973 allowed_nodes = allowed_nodes_as_list(rsc);
974 }
975
976 if (check_unfencing) {
977 g_list_foreach(allowed_nodes, pcmk__order_restart_vs_unfence, rsc);
978 }
979
980 if (check_utilization) {
981 pcmk__create_utilization_constraints(rsc, allowed_nodes);
982 }
983
984 if (rsc->container != NULL) {
985 pcmk_resource_t *remote_rsc = NULL;
986
987 if (rsc->is_remote_node) {
988 // rsc is the implicit remote connection for a guest or bundle node
989
990 /* Guest resources are not allowed to run on Pacemaker Remote nodes,
991 * to avoid nesting remotes. However, bundles are allowed.
992 */
994 rsc_avoids_remote_nodes(rsc->container);
995 }
996
997 /* If someone cleans up a guest or bundle node's container, we will
998 * likely schedule a (re-)probe of the container and recovery of the
999 * connection. Order the connection stop after the container probe,
1000 * so that if we detect the container running, we will trigger a new
1001 * transition and avoid the unnecessary recovery.
1002 */
1004 rsc, PCMK_ACTION_STOP,
1006
1007 /* A user can specify that a resource must start on a Pacemaker Remote
1008 * node by explicitly configuring it with the container=NODENAME
1009 * meta-attribute. This is of questionable merit, since location
1010 * constraints can accomplish the same thing. But we support it, so here
1011 * we check whether a resource (that is not itself a remote connection)
1012 * has container set to a remote node or guest node resource.
1013 */
1014 } else if (rsc->container->is_remote_node) {
1015 remote_rsc = rsc->container;
1016 } else {
1017 remote_rsc = pe__resource_contains_guest_node(rsc->cluster,
1018 rsc->container);
1019 }
1020
1021 if (remote_rsc != NULL) {
1022 /* Force the resource on the Pacemaker Remote node instead of
1023 * colocating the resource with the container resource.
1024 */
1025 for (GList *item = allowed_nodes; item; item = item->next) {
1026 pcmk_node_t *node = item->data;
1027
1028 if (node->details->remote_rsc != remote_rsc) {
1029 node->weight = -PCMK_SCORE_INFINITY;
1030 }
1031 }
1032
1033 } else {
1034 /* This resource is either a filler for a container that does NOT
1035 * represent a Pacemaker Remote node, or a Pacemaker Remote
1036 * connection resource for a guest node or bundle.
1037 */
1038 int score;
1039
1040 crm_trace("Order and colocate %s relative to its container %s",
1041 rsc->id, rsc->container->id);
1042
1046 NULL, rsc,
1048 NULL,
1051 rsc->cluster);
1052
1055 NULL,
1056 rsc->container,
1058 PCMK_ACTION_STOP, 0),
1060
1062 score = 10000; /* Highly preferred but not essential */
1063 } else {
1064 score = PCMK_SCORE_INFINITY; // Force to run on same host
1065 }
1066 pcmk__new_colocation("#resource-with-container", NULL, score, rsc,
1067 rsc->container, NULL, NULL,
1069 }
1070 }
1071
1072 if (rsc->is_remote_node
1074 /* Remote connections and fencing devices are not allowed to run on
1075 * Pacemaker Remote nodes
1076 */
1077 rsc_avoids_remote_nodes(rsc);
1078 }
1079 g_list_free(allowed_nodes);
1080}
1081
1097int
1099 const pcmk_resource_t *primary,
1100 const pcmk__colocation_t *colocation,
1101 bool for_dependent)
1102{
1103 enum pcmk__coloc_affects filter_results;
1104
1105 CRM_ASSERT((dependent != NULL) && (primary != NULL)
1106 && (colocation != NULL));
1107
1108 if (for_dependent) {
1109 // Always process on behalf of primary resource
1110 return primary->cmds->apply_coloc_score(dependent, primary, colocation,
1111 false);
1112 }
1113
1114 filter_results = pcmk__colocation_affects(dependent, primary, colocation,
1115 false);
1116 pcmk__rsc_trace(dependent, "%s %s with %s (%s, score=%d, filter=%d)",
1117 ((colocation->score > 0)? "Colocating" : "Anti-colocating"),
1118 dependent->id, primary->id, colocation->id,
1119 colocation->score,
1120 filter_results);
1121
1122 switch (filter_results) {
1124 return pcmk__apply_coloc_to_priority(dependent, primary,
1125 colocation);
1126
1128 pcmk__apply_coloc_to_scores(dependent, primary, colocation);
1129 return 0;
1130
1131 default: // pcmk__coloc_affects_nothing
1132 return 0;
1133 }
1134}
1135
1136/* Primitive implementation of
1137 * pcmk_assignment_methods_t:with_this_colocations()
1138 */
1139void
1141 const pcmk_resource_t *orig_rsc, GList **list)
1142{
1143 CRM_ASSERT(pcmk__is_primitive(rsc) && (list != NULL));
1144
1145 if (rsc == orig_rsc) {
1146 /* For the resource itself, add all of its own colocations and relevant
1147 * colocations from its parent (if any).
1148 */
1149 pcmk__add_with_this_list(list, rsc->rsc_cons_lhs, orig_rsc);
1150 if (rsc->parent != NULL) {
1151 rsc->parent->cmds->with_this_colocations(rsc->parent, orig_rsc, list);
1152 }
1153 } else {
1154 // For an ancestor, add only explicitly configured constraints
1155 for (GList *iter = rsc->rsc_cons_lhs; iter != NULL; iter = iter->next) {
1156 pcmk__colocation_t *colocation = iter->data;
1157
1158 if (pcmk_is_set(colocation->flags, pcmk__coloc_explicit)) {
1159 pcmk__add_with_this(list, colocation, orig_rsc);
1160 }
1161 }
1162 }
1163}
1164
1165/* Primitive implementation of
1166 * pcmk_assignment_methods_t:this_with_colocations()
1167 */
1168void
1170 const pcmk_resource_t *orig_rsc, GList **list)
1171{
1172 CRM_ASSERT(pcmk__is_primitive(rsc) && (list != NULL));
1173
1174 if (rsc == orig_rsc) {
1175 /* For the resource itself, add all of its own colocations and relevant
1176 * colocations from its parent (if any).
1177 */
1178 pcmk__add_this_with_list(list, rsc->rsc_cons, orig_rsc);
1179 if (rsc->parent != NULL) {
1180 rsc->parent->cmds->this_with_colocations(rsc->parent, orig_rsc, list);
1181 }
1182 } else {
1183 // For an ancestor, add only explicitly configured constraints
1184 for (GList *iter = rsc->rsc_cons; iter != NULL; iter = iter->next) {
1185 pcmk__colocation_t *colocation = iter->data;
1186
1187 if (pcmk_is_set(colocation->flags, pcmk__coloc_explicit)) {
1188 pcmk__add_this_with(list, colocation, orig_rsc);
1189 }
1190 }
1191 }
1192}
1193
1203uint32_t
1205{
1206 CRM_ASSERT(action != NULL);
1207 return (uint32_t) action->flags;
1208}
1209
1224static bool
1225is_expected_node(const pcmk_resource_t *rsc, const pcmk_node_t *node)
1226{
1227 return pcmk_all_flags_set(rsc->flags,
1229 && (rsc->next_role > pcmk_role_stopped)
1230 && pcmk__same_node(rsc->allocated_to, node);
1231}
1232
1241static void
1242stop_resource(pcmk_resource_t *rsc, pcmk_node_t *node, bool optional)
1243{
1244 for (GList *iter = rsc->running_on; iter != NULL; iter = iter->next) {
1245 pcmk_node_t *current = (pcmk_node_t *) iter->data;
1246 pcmk_action_t *stop = NULL;
1247
1248 if (is_expected_node(rsc, current)) {
1249 /* We are scheduling restart actions for a multiply active resource
1250 * with PCMK_META_MULTIPLE_ACTIVE=PCMK_VALUE_STOP_UNEXPECTED, and
1251 * this is where it should not be stopped.
1252 */
1253 pcmk__rsc_trace(rsc,
1254 "Skipping stop of multiply active resource %s "
1255 "on expected node %s",
1256 rsc->id, pcmk__node_name(current));
1257 continue;
1258 }
1259
1260 if (rsc->partial_migration_target != NULL) {
1261 // Continue migration if node originally was and remains target
1262 if (pcmk__same_node(current, rsc->partial_migration_target)
1263 && pcmk__same_node(current, rsc->allocated_to)) {
1264 pcmk__rsc_trace(rsc,
1265 "Skipping stop of %s on %s "
1266 "because partial migration there will continue",
1267 rsc->id, pcmk__node_name(current));
1268 continue;
1269 } else {
1270 pcmk__rsc_trace(rsc,
1271 "Forcing stop of %s on %s "
1272 "because migration target changed",
1273 rsc->id, pcmk__node_name(current));
1274 optional = false;
1275 }
1276 }
1277
1278 pcmk__rsc_trace(rsc, "Scheduling stop of %s on %s",
1279 rsc->id, pcmk__node_name(current));
1280 stop = stop_action(rsc, current, optional);
1281
1282 if (rsc->allocated_to == NULL) {
1283 pe_action_set_reason(stop, "node availability", true);
1284 } else if (pcmk_all_flags_set(rsc->flags, pcmk_rsc_restarting
1286 /* We are stopping a multiply active resource on a node that is
1287 * not its expected node, and we are still scheduling restart
1288 * actions, so the stop is for being multiply active.
1289 */
1290 pe_action_set_reason(stop, "being multiply active", true);
1291 }
1292
1293 if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
1295 }
1296
1298 pcmk__schedule_cleanup(rsc, current, optional);
1299 }
1300
1302 pcmk_action_t *unfence = pe_fence_op(current, PCMK_ACTION_ON, true,
1303 NULL, false, rsc->cluster);
1304
1306 if (!pcmk__node_unfenced(current)) {
1307 pcmk__sched_err("Stopping %s until %s can be unfenced",
1308 rsc->id, pcmk__node_name(current));
1309 }
1310 }
1311 }
1312}
1313
1322static void
1323start_resource(pcmk_resource_t *rsc, pcmk_node_t *node, bool optional)
1324{
1325 pcmk_action_t *start = NULL;
1326
1327 CRM_ASSERT(node != NULL);
1328
1329 pcmk__rsc_trace(rsc, "Scheduling %s start of %s on %s (score %d)",
1330 (optional? "optional" : "required"), rsc->id,
1331 pcmk__node_name(node), node->weight);
1332 start = start_action(rsc, node, TRUE);
1333
1335
1336 if (pcmk_is_set(start->flags, pcmk_action_runnable) && !optional) {
1338 }
1339
1340 if (is_expected_node(rsc, node)) {
1341 /* This could be a problem if the start becomes necessary for other
1342 * reasons later.
1343 */
1344 pcmk__rsc_trace(rsc,
1345 "Start of multiply active resource %s "
1346 "on expected node %s will be a pseudo-action",
1347 rsc->id, pcmk__node_name(node));
1349 }
1350}
1351
1360static void
1361promote_resource(pcmk_resource_t *rsc, pcmk_node_t *node, bool optional)
1362{
1363 GList *iter = NULL;
1364 GList *action_list = NULL;
1365 bool runnable = true;
1366
1367 CRM_ASSERT(node != NULL);
1368
1369 // Any start must be runnable for promotion to be runnable
1370 action_list = pe__resource_actions(rsc, node, PCMK_ACTION_START, true);
1371 for (iter = action_list; iter != NULL; iter = iter->next) {
1372 pcmk_action_t *start = (pcmk_action_t *) iter->data;
1373
1374 if (!pcmk_is_set(start->flags, pcmk_action_runnable)) {
1375 runnable = false;
1376 }
1377 }
1378 g_list_free(action_list);
1379
1380 if (runnable) {
1381 pcmk_action_t *promote = promote_action(rsc, node, optional);
1382
1383 pcmk__rsc_trace(rsc, "Scheduling %s promotion of %s on %s",
1384 (optional? "optional" : "required"), rsc->id,
1385 pcmk__node_name(node));
1386
1387 if (is_expected_node(rsc, node)) {
1388 /* This could be a problem if the promote becomes necessary for
1389 * other reasons later.
1390 */
1391 pcmk__rsc_trace(rsc,
1392 "Promotion of multiply active resource %s "
1393 "on expected node %s will be a pseudo-action",
1394 rsc->id, pcmk__node_name(node));
1396 }
1397 } else {
1398 pcmk__rsc_trace(rsc, "Not promoting %s on %s: start unrunnable",
1399 rsc->id, pcmk__node_name(node));
1400 action_list = pe__resource_actions(rsc, node, PCMK_ACTION_PROMOTE,
1401 true);
1402 for (iter = action_list; iter != NULL; iter = iter->next) {
1403 pcmk_action_t *promote = (pcmk_action_t *) iter->data;
1404
1406 }
1407 g_list_free(action_list);
1408 }
1409}
1410
1419static void
1420demote_resource(pcmk_resource_t *rsc, pcmk_node_t *node, bool optional)
1421{
1422 /* Since this will only be called for a primitive (possibly as an instance
1423 * of a collective resource), the resource is multiply active if it is
1424 * running on more than one node, so we want to demote on all of them as
1425 * part of recovery, regardless of which one is the desired node.
1426 */
1427 for (GList *iter = rsc->running_on; iter != NULL; iter = iter->next) {
1428 pcmk_node_t *current = (pcmk_node_t *) iter->data;
1429
1430 if (is_expected_node(rsc, current)) {
1431 pcmk__rsc_trace(rsc,
1432 "Skipping demote of multiply active resource %s "
1433 "on expected node %s",
1434 rsc->id, pcmk__node_name(current));
1435 } else {
1436 pcmk__rsc_trace(rsc, "Scheduling %s demotion of %s on %s",
1437 (optional? "optional" : "required"), rsc->id,
1438 pcmk__node_name(current));
1439 demote_action(rsc, current, optional);
1440 }
1441 }
1442}
1443
1444static void
1445assert_role_error(pcmk_resource_t *rsc, pcmk_node_t *node, bool optional)
1446{
1447 CRM_ASSERT(false);
1448}
1449
1458void
1460 bool optional)
1461{
1462 /* If the cleanup is required, its orderings are optional, because they're
1463 * relevant only if both actions are required. Conversely, if the cleanup is
1464 * optional, the orderings make the then action required if the first action
1465 * becomes required.
1466 */
1467 uint32_t flag = optional? pcmk__ar_first_implies_then : pcmk__ar_ordered;
1468
1469 CRM_CHECK((rsc != NULL) && (node != NULL), return);
1470
1471 if (pcmk_is_set(rsc->flags, pcmk_rsc_failed)) {
1472 pcmk__rsc_trace(rsc, "Skipping clean-up of %s on %s: resource failed",
1473 rsc->id, pcmk__node_name(node));
1474 return;
1475 }
1476
1477 if (node->details->unclean || !node->details->online) {
1478 pcmk__rsc_trace(rsc, "Skipping clean-up of %s on %s: node unavailable",
1479 rsc->id, pcmk__node_name(node));
1480 return;
1481 }
1482
1483 crm_notice("Scheduling clean-up of %s on %s",
1484 rsc->id, pcmk__node_name(node));
1485 delete_action(rsc, node, optional);
1486
1487 // stop -> clean-up -> start
1489 rsc, PCMK_ACTION_DELETE, flag);
1491 rsc, PCMK_ACTION_START, flag);
1492}
1493
1501void
1503{
1504 char *name = NULL;
1505 char *value = NULL;
1506 const pcmk_resource_t *parent = NULL;
1507
1508 CRM_ASSERT(pcmk__is_primitive(rsc) && (xml != NULL));
1509
1510 /* Clone instance numbers get set internally as meta-attributes, and are
1511 * needed in the transition graph (for example, to tell unique clone
1512 * instances apart).
1513 */
1514 value = g_hash_table_lookup(rsc->meta, PCMK__META_CLONE);
1515 if (value != NULL) {
1517 crm_xml_add(xml, name, value);
1518 free(name);
1519 }
1520
1521 // Not sure if this one is really needed ...
1522 value = g_hash_table_lookup(rsc->meta, PCMK_META_REMOTE_NODE);
1523 if (value != NULL) {
1525 crm_xml_add(xml, name, value);
1526 free(name);
1527 }
1528
1529 /* The container meta-attribute can be set on the primitive itself or one of
1530 * its parents (for example, a group inside a container resource), so check
1531 * them all, and keep the highest one found.
1532 */
1533 for (parent = rsc; parent != NULL; parent = parent->parent) {
1534 if (parent->container != NULL) {
1536 parent->container->id);
1537 }
1538 }
1539
1540 /* Bundle replica children will get their external-ip set internally as a
1541 * meta-attribute. The graph action needs it, but under a different naming
1542 * convention than other meta-attributes.
1543 */
1544 value = g_hash_table_lookup(rsc->meta, "external-ip");
1545 if (value != NULL) {
1546 crm_xml_add(xml, "pcmk_external_ip", value);
1547 }
1548}
1549
1550// Primitive implementation of pcmk_assignment_methods_t:add_utilization()
1551void
1553 const pcmk_resource_t *orig_rsc,
1554 GList *all_rscs, GHashTable *utilization)
1555{
1556 CRM_ASSERT(pcmk__is_primitive(rsc)
1557 && (orig_rsc != NULL) && (utilization != NULL));
1558
1560 return;
1561 }
1562
1563 pcmk__rsc_trace(orig_rsc,
1564 "%s: Adding primitive %s as colocated utilization",
1565 orig_rsc->id, rsc->id);
1566 pcmk__release_node_capacity(utilization, rsc);
1567}
1568
1577static time_t
1578shutdown_time(pcmk_node_t *node)
1579{
1580 const char *shutdown = pcmk__node_attr(node, PCMK__NODE_ATTR_SHUTDOWN, NULL,
1582 time_t result = 0;
1583
1584 if (shutdown != NULL) {
1585 long long result_ll;
1586
1587 if (pcmk__scan_ll(shutdown, &result_ll, 0LL) == pcmk_rc_ok) {
1588 result = (time_t) result_ll;
1589 }
1590 }
1591 return (result == 0)? get_effective_time(node->details->data_set) : result;
1592}
1593
1601static void
1602ban_if_not_locked(gpointer data, gpointer user_data)
1603{
1604 const pcmk_node_t *node = (const pcmk_node_t *) data;
1605 pcmk_resource_t *rsc = (pcmk_resource_t *) user_data;
1606
1607 if (strcmp(node->details->uname, rsc->lock_node->details->uname) != 0) {
1610 }
1611}
1612
1613// Primitive implementation of pcmk_assignment_methods_t:shutdown_lock()
1614void
1616{
1617 const char *class = NULL;
1618
1619 CRM_ASSERT(pcmk__is_primitive(rsc));
1620
1621 class = crm_element_value(rsc->xml, PCMK_XA_CLASS);
1622
1623 // Fence devices and remote connections can't be locked
1624 if (pcmk__str_eq(class, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_null_matches)
1625 || rsc->is_remote_node) {
1626 return;
1627 }
1628
1629 if (rsc->lock_node != NULL) {
1630 // The lock was obtained from resource history
1631
1632 if (rsc->running_on != NULL) {
1633 /* The resource was started elsewhere even though it is now
1634 * considered locked. This shouldn't be possible, but as a
1635 * failsafe, we don't want to disturb the resource now.
1636 */
1637 pcmk__rsc_info(rsc,
1638 "Cancelling shutdown lock "
1639 "because %s is already active", rsc->id);
1641 rsc->lock_node = NULL;
1642 rsc->lock_time = 0;
1643 }
1644
1645 // Only a resource active on exactly one node can be locked
1646 } else if (pcmk__list_of_1(rsc->running_on)) {
1647 pcmk_node_t *node = rsc->running_on->data;
1648
1649 if (node->details->shutdown) {
1650 if (node->details->unclean) {
1651 pcmk__rsc_debug(rsc,
1652 "Not locking %s to unclean %s for shutdown",
1653 rsc->id, pcmk__node_name(node));
1654 } else {
1655 rsc->lock_node = node;
1656 rsc->lock_time = shutdown_time(node);
1657 }
1658 }
1659 }
1660
1661 if (rsc->lock_node == NULL) {
1662 // No lock needed
1663 return;
1664 }
1665
1666 if (rsc->cluster->shutdown_lock > 0) {
1667 time_t lock_expiration = rsc->lock_time + rsc->cluster->shutdown_lock;
1668
1669 pcmk__rsc_info(rsc, "Locking %s to %s due to shutdown (expires @%lld)",
1670 rsc->id, pcmk__node_name(rsc->lock_node),
1671 (long long) lock_expiration);
1672 pe__update_recheck_time(++lock_expiration, rsc->cluster,
1673 "shutdown lock expiration");
1674 } else {
1675 pcmk__rsc_info(rsc, "Locking %s to %s due to shutdown",
1676 rsc->id, pcmk__node_name(rsc->lock_node));
1677 }
1678
1679 // If resource is locked to one node, ban it from all other nodes
1680 g_list_foreach(rsc->cluster->nodes, ban_if_not_locked, rsc);
1681}
@ pcmk__ar_if_on_same_node
Relation applies only if actions are on same node.
@ pcmk__ar_first_implies_then
@ pcmk__ar_then_implies_first
@ pcmk__ar_intermediate_stop
@ pcmk__ar_promoted_then_implies_first
@ 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_then_cancels_first
If 'then' action becomes required, 'first' becomes optional.
#define PCMK_ACTION_STOP
Definition actions.h:75
#define PCMK_ACTION_PROMOTE
Definition actions.h:66
#define PCMK_ACTION_LRM_DELETE
Definition actions.h:53
#define PCMK_ACTION_START
Definition actions.h:72
#define PCMK_ACTION_DELETE
Definition actions.h:48
@ pcmk_action_runnable
Definition actions.h:207
@ pcmk_action_pseudo
Definition actions.h:204
@ pcmk_action_optional
Definition actions.h:210
@ pcmk_action_always_in_graph
Definition actions.h:213
#define PCMK_ACTION_MONITOR
Definition actions.h:60
#define PCMK_ACTION_ON
Definition actions.h:64
#define PCMK_ACTION_DEMOTE
Definition actions.h:49
#define pcmk__set_action_flags(action, flags_to_set)
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:196
#define pcmk__clear_action_flags(action, flags_to_clear)
#define PCMK_RESOURCE_CLASS_STONITH
Definition agents.h:31
const char * pcmk__node_attr(const pcmk_node_t *node, const char *name, const char *target, enum pcmk__rsc_node node_type)
Definition attrs.c:118
const char * parent
Definition cib.c:27
const char * name
Definition cib.c:26
bool pcmk__is_daemon
Definition logging.c:47
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:98
char data[0]
Definition cpg.c:10
uint32_t id
Definition cpg.c:0
#define CRM_META
Definition crm.h:81
@ pcmk__rsc_node_current
Where resource is running.
G_GNUC_INTERNAL enum pcmk__coloc_affects pcmk__colocation_affects(const pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool preview)
G_GNUC_INTERNAL void pcmk__add_this_with_list(GList **list, GList *addition, const pcmk_resource_t *rsc)
void pcmk__abort_dangling_migration(void *data, void *user_data)
void pcmk__create_migration_actions(pcmk_resource_t *rsc, const pcmk_node_t *current)
G_GNUC_INTERNAL void pcmk__create_recurring_actions(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, const char *primary_role, uint32_t flags)
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)
G_GNUC_INTERNAL bool pcmk__any_node_available(GHashTable *nodes)
#define pcmk__order_resource_actions(first_rsc, first_task, then_rsc, then_task, flags)
G_GNUC_INTERNAL void pcmk__apply_coloc_to_scores(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation)
pcmk__coloc_affects
@ pcmk__coloc_affects_location
@ pcmk__coloc_affects_role
@ pcmk__coloc_influence
@ pcmk__coloc_explicit
G_GNUC_INTERNAL bool pcmk__assign_resource(pcmk_resource_t *rsc, pcmk_node_t *node, bool force, bool stop_if_fail)
G_GNUC_INTERNAL void pcmk__order_vs_unfence(const pcmk_resource_t *rsc, pcmk_node_t *node, pcmk_action_t *action, enum pcmk__action_relation_flags order)
G_GNUC_INTERNAL GList * pcmk__with_this_colocations(const pcmk_resource_t *rsc)
G_GNUC_INTERNAL void pcmk__add_this_with(GList **list, const pcmk__colocation_t *colocation, const pcmk_resource_t *rsc)
G_GNUC_INTERNAL int pcmk__apply_coloc_to_priority(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation)
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__order_restart_vs_unfence(gpointer data, gpointer user_data)
G_GNUC_INTERNAL void pcmk__add_with_this(GList **list, const pcmk__colocation_t *colocation, const pcmk_resource_t *rsc)
G_GNUC_INTERNAL void pcmk__create_utilization_constraints(pcmk_resource_t *rsc, const GList *allowed_nodes)
G_GNUC_INTERNAL const pcmk_node_t * pcmk__ban_insufficient_capacity(pcmk_resource_t *rsc)
G_GNUC_INTERNAL void pcmk__add_dependent_scores(gpointer data, gpointer user_data)
G_GNUC_INTERNAL GList * pcmk__this_with_colocations(const pcmk_resource_t *rsc)
bool pcmk__rsc_can_migrate(const pcmk_resource_t *rsc, const pcmk_node_t *current)
G_GNUC_INTERNAL bool pcmk__node_unfenced(const pcmk_node_t *node)
G_GNUC_INTERNAL void pcmk__release_node_capacity(GHashTable *current_utilization, const pcmk_resource_t *rsc)
G_GNUC_INTERNAL bool pcmk__node_available(const pcmk_node_t *node, bool consider_score, bool consider_guest)
G_GNUC_INTERNAL GHashTable * pcmk__copy_node_table(GHashTable *nodes)
#define do_crm_log(level, fmt, args...)
Log a message.
Definition logging.h:181
#define crm_notice(fmt, args...)
Definition logging.h:395
#define CRM_CHECK(expr, failure_action)
Definition logging.h:245
#define crm_trace(fmt, args...)
Definition logging.h:402
#define PCMK__NODE_ATTR_SHUTDOWN
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:446
char * crm_meta_name(const char *field)
Get the environment variable equivalent of a meta-attribute name.
Definition nvpair.c:959
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition nvpair.c:301
#define PCMK_OPT_STOP_ALL_RESOURCES
Definition options.h:69
#define PCMK_OPT_NO_QUORUM_POLICY
Definition options.h:46
#define PCMK_META_REMOTE_NODE
Definition options.h:108
#define PCMK_VALUE_FREEZE
Definition options.h:155
#define PCMK_META_TARGET_ROLE
Definition options.h:113
#define PCMK_VALUE_DEFAULT
Definition options.h:142
#define PCMK_OPT_SHUTDOWN_LOCK
Definition options.h:60
#define PCMK__META_CONTAINER
#define PCMK__META_CLONE
const char * action
Definition pcmk_fence.c:30
pcmk__action_result_t result
Definition pcmk_fence.c:35
pcmk_node_t * pcmk__primitive_assign(pcmk_resource_t *rsc, const pcmk_node_t *prefer, bool stop_if_fail)
void pcmk__primitive_internal_constraints(pcmk_resource_t *rsc)
void pcmk__primitive_add_utilization(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
void pcmk__primitive_add_graph_meta(const pcmk_resource_t *rsc, xmlNode *xml)
void(* rsc_transition_fn)(pcmk_resource_t *rsc, pcmk_node_t *node, bool optional)
void pcmk__with_primitive_colocations(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
uint32_t pcmk__primitive_action_flags(pcmk_action_t *action, const pcmk_node_t *node)
int pcmk__primitive_apply_coloc_score(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
void pcmk__primitive_create_actions(pcmk_resource_t *rsc)
void pcmk__schedule_cleanup(pcmk_resource_t *rsc, const pcmk_node_t *node, bool optional)
#define RSC_ROLE_MAX
void pcmk__primitive_with_colocations(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
void pcmk__primitive_shutdown_lock(pcmk_resource_t *rsc)
#define delete_action(rsc, node, optional)
Definition internal.h:209
time_t get_effective_time(pcmk_scheduler_t *scheduler)
Definition utils.c:395
GList * pe__resource_actions(const pcmk_resource_t *rsc, const pcmk_node_t *node, const char *task, bool require_node)
Find all actions of given type for a resource.
#define demote_action(rsc, node, optional)
Definition internal.h:230
const pcmk_resource_t * pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle)
Definition complex.c:1032
gboolean order_actions(pcmk_action_t *lh_action, pcmk_action_t *rh_action, uint32_t flags)
Definition utils.c:457
#define pe__show_node_scores(level, rsc, text, nodes, scheduler)
Definition internal.h:176
#define start_action(rsc, node, optional)
Definition internal.h:220
void resource_location(pcmk_resource_t *rsc, const pcmk_node_t *node, int score, const char *tag, pcmk_scheduler_t *scheduler)
Definition utils.c:359
void pe__update_recheck_time(time_t recheck, pcmk_scheduler_t *scheduler, const char *reason)
Definition utils.c:694
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition utils.c:145
void pe_action_set_reason(pcmk_action_t *action, const char *reason, bool overwrite)
pcmk_action_t * pe_fence_op(pcmk_node_t *node, const char *op, bool optional, const char *reason, bool priority_delay, pcmk_scheduler_t *scheduler)
void pe__set_next_role(pcmk_resource_t *rsc, enum rsc_role_e role, const char *why)
Definition complex.c:1253
#define stop_action(rsc, node, optional)
Definition internal.h:214
void pe__clear_resource_history(pcmk_resource_t *rsc, const pcmk_node_t *node)
#define promote_action(rsc, node, optional)
Definition internal.h:225
pcmk_resource_t * pe__resource_contains_guest_node(const pcmk_scheduler_t *scheduler, const pcmk_resource_t *rsc)
Definition remote.c:29
@ pcmk_multiply_active_restart
Definition resources.h:66
@ pcmk_multiply_active_unexpected
Definition resources.h:69
@ pcmk_rsc_promotable
Definition resources.h:106
@ pcmk_rsc_unassigned
Definition resources.h:109
@ pcmk_rsc_assigning
Definition resources.h:112
@ pcmk_rsc_stop_if_failed
Definition resources.h:121
@ pcmk_rsc_needs_fencing
Definition resources.h:175
@ pcmk_rsc_needs_unfencing
Definition resources.h:178
@ pcmk_rsc_removed
Definition resources.h:85
@ pcmk_rsc_remote_nesting_allowed
Definition resources.h:127
@ pcmk_rsc_start_pending
Definition resources.h:142
@ pcmk_rsc_blocked
Definition resources.h:91
@ pcmk_rsc_restarting
Definition resources.h:118
@ pcmk_rsc_fence_device
Definition resources.h:103
@ pcmk_rsc_stop_unexpected
Definition resources.h:154
@ pcmk_rsc_managed
Definition resources.h:88
@ pcmk_rsc_failed
Definition resources.h:133
const char * pcmk__multiply_active_text(enum rsc_recovery_type recovery)
Get readable description of a multiply-active recovery type.
Definition resources.c:54
#define CRM_ASSERT(expr)
Definition results.h:42
@ pcmk_rc_ok
Definition results.h:162
const char * pcmk_role_text(enum rsc_role_e role)
Get readable description of a resource role.
Definition roles.c:23
rsc_role_e
Definition roles.h:34
@ pcmk_role_started
Started.
Definition roles.h:37
@ 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
@ pcmk_role_stopped
Stopped.
Definition roles.h:36
#define pcmk__set_rsc_flags(resource, flags_to_set)
#define pcmk__clear_rsc_flags(resource, flags_to_clear)
@ pcmk_no_quorum_freeze
Definition scheduler.h:41
pcmk_node_t * pcmk_find_node(const pcmk_scheduler_t *scheduler, const char *node_name)
Find a node by name in scheduler data.
Definition scheduler.c:103
@ pcmk_sched_fencing_enabled
Definition scheduler.h:89
@ pcmk_sched_have_fencing
Definition scheduler.h:96
@ pcmk_sched_quorate
Definition scheduler.h:80
@ pcmk_sched_output_scores
Definition scheduler.h:173
@ pcmk_sched_enable_unfencing
Definition scheduler.h:99
@ pcmk_sched_remove_after_stop
Definition scheduler.h:127
@ pcmk_sched_stop_all
Definition scheduler.h:117
#define pcmk__rsc_info(rsc, fmt, args...)
#define pcmk__rsc_trace(rsc, fmt, args...)
#define pcmk__rsc_debug(rsc, fmt, args...)
#define pcmk__sched_err(fmt...)
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition scores.c:86
#define PCMK_SCORE_INFINITY
Integer score to use to represent "infinity".
Definition scores.h:24
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
Definition strings.c:97
@ pcmk__str_null_matches
@ pcmk__str_casei
pcmk_resource_t * primary
enum pe_action_flags flags
Definition actions.h:349
int weight
Definition nodes.h:162
struct pe_node_shared_s * details
Definition nodes.h:167
gboolean shutdown
Definition nodes.h:97
const char * id
Definition nodes.h:72
gboolean online
Definition nodes.h:80
const char * uname
Definition nodes.h:73
pcmk_scheduler_t * data_set
Definition nodes.h:153
gboolean unclean
Definition nodes.h:91
pcmk_resource_t * remote_rsc
Definition nodes.h:135
gboolean unseen
Definition nodes.h:93
pcmk_assignment_methods_t * cmds
Definition resources.h:413
GList * running_on
Definition resources.h:456
pcmk_node_t * partial_migration_target
Definition resources.h:450
GHashTable * meta
Definition resources.h:467
GList * rsc_cons
Definition resources.h:442
GList * rsc_cons_lhs
Definition resources.h:441
pcmk_scheduler_t * cluster
Definition resources.h:408
pcmk_node_t * partial_migration_source
Definition resources.h:453
pcmk_resource_t * container
Definition resources.h:476
pcmk_rsc_methods_t * fns
Definition resources.h:412
gboolean is_remote_node
Definition resources.h:431
pcmk_node_t * allocated_to
Definition resources.h:447
GHashTable * utilization
Definition resources.h:469
GHashTable * allowed_nodes
Definition resources.h:462
GList * dangling_migrations
Definition resources.h:474
pcmk_node_t * lock_node
Definition resources.h:481
unsigned long long flags
Definition resources.h:428
enum rsc_role_e next_role
Definition resources.h:465
enum rsc_role_e role
Definition resources.h:464
pcmk_resource_t * parent
Definition resources.h:409
time_t lock_time
Definition resources.h:483
const char * placement_strategy
Definition scheduler.h:206
unsigned long long flags
Definition scheduler.h:211
enum pe_quorum_policy no_quorum_policy
Definition scheduler.h:217
void(* this_with_colocations)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
int(* apply_coloc_score)(pcmk_resource_t *dependent, const pcmk_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
void(* with_this_colocations)(const pcmk_resource_t *rsc, const pcmk_resource_t *orig_rsc, GList **list)
pcmk_node_t *(* assign)(pcmk_resource_t *rsc, const pcmk_node_t *prefer, bool stop_if_fail)
pcmk_node_t *(* active_node)(const pcmk_resource_t *rsc, unsigned int *count_all, unsigned int *count_clean)
Definition resources.h:373
Wrappers for and extensions to libxml2.
#define PCMK_XA_CLASS
Definition xml_names.h:241