pacemaker 2.1.6-6fdc9deea29
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-2023 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU 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
19static void stop_resource(pe_resource_t *rsc, pe_node_t *node, bool optional);
20static void start_resource(pe_resource_t *rsc, pe_node_t *node, bool optional);
21static void demote_resource(pe_resource_t *rsc, pe_node_t *node, bool optional);
22static void promote_resource(pe_resource_t *rsc, pe_node_t *node,
23 bool optional);
24static void assert_role_error(pe_resource_t *rsc, pe_node_t *node,
25 bool optional);
26
27static enum rsc_role_e rsc_state_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX] = {
28 /* This array lists the immediate next role when transitioning from one role
29 * to a target role. For example, when going from Stopped to Promoted, the
30 * next role is Unpromoted, because the resource must be started before it
31 * can be promoted. The current state then becomes Started, which is fed
32 * into this array again, giving a next role of Promoted.
33 *
34 * Current role Immediate next role Final target role
35 * ------------ ------------------- -----------------
36 */
37 /* Unknown */ { RSC_ROLE_UNKNOWN, /* Unknown */
38 RSC_ROLE_STOPPED, /* Stopped */
39 RSC_ROLE_STOPPED, /* Started */
40 RSC_ROLE_STOPPED, /* Unpromoted */
41 RSC_ROLE_STOPPED, /* Promoted */
42 },
43 /* Stopped */ { RSC_ROLE_STOPPED, /* Unknown */
44 RSC_ROLE_STOPPED, /* Stopped */
45 RSC_ROLE_STARTED, /* Started */
46 RSC_ROLE_UNPROMOTED, /* Unpromoted */
47 RSC_ROLE_UNPROMOTED, /* Promoted */
48 },
49 /* Started */ { RSC_ROLE_STOPPED, /* Unknown */
50 RSC_ROLE_STOPPED, /* Stopped */
51 RSC_ROLE_STARTED, /* Started */
52 RSC_ROLE_UNPROMOTED, /* Unpromoted */
53 RSC_ROLE_PROMOTED, /* Promoted */
54 },
55 /* Unpromoted */ { RSC_ROLE_STOPPED, /* Unknown */
56 RSC_ROLE_STOPPED, /* Stopped */
57 RSC_ROLE_STOPPED, /* Started */
58 RSC_ROLE_UNPROMOTED, /* Unpromoted */
59 RSC_ROLE_PROMOTED, /* Promoted */
60 },
61 /* Promoted */ { RSC_ROLE_STOPPED, /* Unknown */
62 RSC_ROLE_UNPROMOTED, /* Stopped */
63 RSC_ROLE_UNPROMOTED, /* Started */
64 RSC_ROLE_UNPROMOTED, /* Unpromoted */
65 RSC_ROLE_PROMOTED, /* Promoted */
66 },
67};
68
77typedef void (*rsc_transition_fn)(pe_resource_t *rsc, pe_node_t *node,
78 bool optional);
79
80static rsc_transition_fn rsc_action_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX] = {
81 /* This array lists the function needed to transition directly from one role
82 * to another. NULL indicates that nothing is needed.
83 *
84 * Current role Transition function Next role
85 * ------------ ------------------- ----------
86 */
87 /* Unknown */ { assert_role_error, /* Unknown */
88 stop_resource, /* Stopped */
89 assert_role_error, /* Started */
90 assert_role_error, /* Unpromoted */
91 assert_role_error, /* Promoted */
92 },
93 /* Stopped */ { assert_role_error, /* Unknown */
94 NULL, /* Stopped */
95 start_resource, /* Started */
96 start_resource, /* Unpromoted */
97 assert_role_error, /* Promoted */
98 },
99 /* Started */ { assert_role_error, /* Unknown */
100 stop_resource, /* Stopped */
101 NULL, /* Started */
102 NULL, /* Unpromoted */
103 promote_resource, /* Promoted */
104 },
105 /* Unpromoted */ { assert_role_error, /* Unknown */
106 stop_resource, /* Stopped */
107 stop_resource, /* Started */
108 NULL, /* Unpromoted */
109 promote_resource, /* Promoted */
110 },
111 /* Promoted */ { assert_role_error, /* Unknown */
112 demote_resource, /* Stopped */
113 demote_resource, /* Started */
114 demote_resource, /* Unpromoted */
115 NULL, /* Promoted */
116 },
117};
118
127static GList *
128sorted_allowed_nodes(const pe_resource_t *rsc)
129{
130 if (rsc->allowed_nodes != NULL) {
131 GList *nodes = g_hash_table_get_values(rsc->allowed_nodes);
132
133 if (nodes != NULL) {
134 return pcmk__sort_nodes(nodes, pe__current_node(rsc));
135 }
136 }
137 return NULL;
138}
139
149static bool
150assign_best_node(pe_resource_t *rsc, const pe_node_t *prefer)
151{
152 GList *nodes = NULL;
153 pe_node_t *chosen = NULL;
154 pe_node_t *best = NULL;
155 bool result = false;
156 const pe_node_t *most_free_node = pcmk__ban_insufficient_capacity(rsc);
157
158 if (prefer == NULL) {
159 prefer = most_free_node;
160 }
161
163 // We've already finished assignment of resources to nodes
164 return rsc->allocated_to != NULL;
165 }
166
167 // Sort allowed nodes by weight
168 nodes = sorted_allowed_nodes(rsc);
169 if (nodes != NULL) {
170 best = (pe_node_t *) nodes->data; // First node has best score
171 }
172
173 if ((prefer != NULL) && (nodes != NULL)) {
174 // Get the allowed node version of prefer
175 chosen = g_hash_table_lookup(rsc->allowed_nodes, prefer->details->id);
176
177 if (chosen == NULL) {
178 pe_rsc_trace(rsc, "Preferred node %s for %s was unknown",
179 pe__node_name(prefer), rsc->id);
180
181 /* Favor the preferred node as long as its weight is at least as good as
182 * the best allowed node's.
183 *
184 * An alternative would be to favor the preferred node even if the best
185 * node is better, when the best node's weight is less than INFINITY.
186 */
187 } else if (chosen->weight < best->weight) {
188 pe_rsc_trace(rsc, "Preferred node %s for %s was unsuitable",
189 pe__node_name(chosen), rsc->id);
190 chosen = NULL;
191
192 } else if (!pcmk__node_available(chosen, true, false)) {
193 pe_rsc_trace(rsc, "Preferred node %s for %s was unavailable",
194 pe__node_name(chosen), rsc->id);
195 chosen = NULL;
196
197 } else {
198 pe_rsc_trace(rsc,
199 "Chose preferred node %s for %s (ignoring %d candidates)",
200 pe__node_name(chosen), rsc->id, g_list_length(nodes));
201 }
202 }
203
204 if ((chosen == NULL) && (best != NULL)) {
205 /* Either there is no preferred node, or the preferred node is not
206 * suitable, but another node is allowed to run the resource.
207 */
208
209 chosen = best;
210
211 if (!pe_rsc_is_unique_clone(rsc->parent)
212 && (chosen->weight > 0) // Zero not acceptable
213 && pcmk__node_available(chosen, false, false)) {
214 /* If the resource is already running on a node, prefer that node if
215 * it is just as good as the chosen node.
216 *
217 * We don't do this for unique clone instances, because
218 * pcmk__assign_instances() has already assigned instances to their
219 * running nodes when appropriate, and if we get here, we don't want
220 * remaining unassigned instances to prefer a node that's already
221 * running another instance.
222 */
223 pe_node_t *running = pe__current_node(rsc);
224
225 if (running == NULL) {
226 // Nothing to do
227
228 } else if (!pcmk__node_available(running, true, false)) {
229 pe_rsc_trace(rsc, "Current node for %s (%s) can't run resources",
230 rsc->id, pe__node_name(running));
231
232 } else {
233 int nodes_with_best_score = 1;
234
235 for (GList *iter = nodes->next; iter; iter = iter->next) {
236 pe_node_t *allowed = (pe_node_t *) iter->data;
237
238 if (allowed->weight != chosen->weight) {
239 // The nodes are sorted by weight, so no more are equal
240 break;
241 }
242 if (pe__same_node(allowed, running)) {
243 // Scores are equal, so prefer the current node
244 chosen = allowed;
245 }
246 nodes_with_best_score++;
247 }
248
249 if (nodes_with_best_score > 1) {
250 do_crm_log(((chosen->weight >= INFINITY)? LOG_WARNING : LOG_INFO),
251 "Chose %s for %s from %d nodes with score %s",
252 pe__node_name(chosen), rsc->id,
253 nodes_with_best_score,
254 pcmk_readable_score(chosen->weight));
255 }
256 }
257 }
258
259 pe_rsc_trace(rsc, "Chose %s for %s from %d candidates",
260 pe__node_name(chosen), rsc->id, g_list_length(nodes));
261 }
262
263 result = pcmk__finalize_assignment(rsc, chosen, false);
264 g_list_free(nodes);
265 return result;
266}
267
275static void
276apply_this_with(gpointer data, gpointer user_data)
277{
279 pe_resource_t *rsc = (pe_resource_t *) user_data;
280
281 GHashTable *archive = NULL;
282 pe_resource_t *other = colocation->primary;
283
284 // In certain cases, we will need to revert the node scores
285 if ((colocation->dependent_role >= RSC_ROLE_PROMOTED)
286 || ((colocation->score < 0) && (colocation->score > -INFINITY))) {
287 archive = pcmk__copy_node_table(rsc->allowed_nodes);
288 }
289
290 if (pcmk_is_set(other->flags, pe_rsc_provisional)) {
291 pe_rsc_trace(rsc,
292 "%s: Assigning colocation %s primary %s first"
293 "(score=%d role=%s)",
294 rsc->id, colocation->id, other->id,
295 colocation->score, role2text(colocation->dependent_role));
296 other->cmds->assign(other, NULL);
297 }
298
299 // Apply the colocation score to this resource's allowed node scores
300 rsc->cmds->apply_coloc_score(rsc, other, colocation, true);
301 if ((archive != NULL)
303 pe_rsc_info(rsc,
304 "%s: Reverting scores from colocation with %s "
305 "because no nodes allowed",
306 rsc->id, other->id);
307 g_hash_table_destroy(rsc->allowed_nodes);
308 rsc->allowed_nodes = archive;
309 archive = NULL;
310 }
311 if (archive != NULL) {
312 g_hash_table_destroy(archive);
313 }
314}
315
322static void
323remote_connection_assigned(const pe_resource_t *connection)
324{
325 pe_node_t *remote_node = pe_find_node(connection->cluster->nodes,
326 connection->id);
327
328 CRM_CHECK(remote_node != NULL, return);
329
330 if ((connection->allocated_to != NULL)
331 && (connection->next_role != RSC_ROLE_STOPPED)) {
332
333 crm_trace("Pacemaker Remote node %s will be online",
334 remote_node->details->id);
335 remote_node->details->online = TRUE;
336 if (remote_node->details->unseen) {
337 // Avoid unnecessary fence, since we will attempt connection
338 remote_node->details->unclean = FALSE;
339 }
340
341 } else {
342 crm_trace("Pacemaker Remote node %s will be shut down "
343 "(%sassigned connection's next role is %s)",
344 remote_node->details->id,
345 ((connection->allocated_to == NULL)? "un" : ""),
346 role2text(connection->next_role));
347 remote_node->details->shutdown = TRUE;
348 }
349}
350
360pe_node_t *
362{
363 GList *this_with_colocations = NULL;
364 GList *with_this_colocations = NULL;
365 GList *iter = NULL;
366 pcmk__colocation_t *colocation = NULL;
367
368 CRM_ASSERT(rsc != NULL);
369
370 // Never assign a child without parent being assigned first
371 if ((rsc->parent != NULL)
373 pe_rsc_debug(rsc, "%s: Assigning parent %s first",
374 rsc->id, rsc->parent->id);
375 rsc->parent->cmds->assign(rsc->parent, prefer);
376 }
377
379 return rsc->allocated_to; // Assignment has already been done
380 }
381
382 // Ensure we detect assignment loops
384 pe_rsc_debug(rsc, "Breaking assignment loop involving %s", rsc->id);
385 return NULL;
386 }
388
389 pe__show_node_weights(true, rsc, "Pre-assignment", rsc->allowed_nodes,
390 rsc->cluster);
391
392 this_with_colocations = pcmk__this_with_colocations(rsc);
393 with_this_colocations = pcmk__with_this_colocations(rsc);
394
395 // Apply mandatory colocations first, to satisfy as many as possible
396 for (iter = this_with_colocations; iter != NULL; iter = iter->next) {
397 colocation = iter->data;
398 if ((colocation->score <= -CRM_SCORE_INFINITY)
399 || (colocation->score >= CRM_SCORE_INFINITY)) {
400 apply_this_with(iter->data, rsc);
401 }
402 }
403 for (iter = with_this_colocations; iter != NULL; iter = iter->next) {
404 colocation = iter->data;
405 if ((colocation->score <= -CRM_SCORE_INFINITY)
406 || (colocation->score >= CRM_SCORE_INFINITY)) {
407 pcmk__add_dependent_scores(iter->data, rsc);
408 }
409 }
410
411 pe__show_node_weights(true, rsc, "Mandatory-colocations",
412 rsc->allowed_nodes, rsc->cluster);
413
414 // Then apply optional colocations
415 for (iter = this_with_colocations; iter != NULL; iter = iter->next) {
416 colocation = iter->data;
417
418 if ((colocation->score > -CRM_SCORE_INFINITY)
419 && (colocation->score < CRM_SCORE_INFINITY)) {
420 apply_this_with(iter->data, rsc);
421 }
422 }
423 for (iter = with_this_colocations; iter != NULL; iter = iter->next) {
424 colocation = iter->data;
425
426 if ((colocation->score > -CRM_SCORE_INFINITY)
427 && (colocation->score < CRM_SCORE_INFINITY)) {
428 pcmk__add_dependent_scores(iter->data, rsc);
429 }
430 }
431
432 g_list_free(this_with_colocations);
433 g_list_free(with_this_colocations);
434
435 if (rsc->next_role == RSC_ROLE_STOPPED) {
436 pe_rsc_trace(rsc,
437 "Banning %s from all nodes because it will be stopped",
438 rsc->id);
440 rsc->cluster);
441
442 } else if ((rsc->next_role > rsc->role)
445 crm_notice("Resource %s cannot be elevated from %s to %s due to "
446 "no-quorum-policy=freeze",
447 rsc->id, role2text(rsc->role), role2text(rsc->next_role));
448 pe__set_next_role(rsc, rsc->role, "no-quorum-policy=freeze");
449 }
450
452 rsc, __func__, rsc->allowed_nodes, rsc->cluster);
453
454 // Unmanage resource if fencing is enabled but no device is configured
458 }
459
460 if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
461 // Unmanaged resources stay on their current node
462 const char *reason = NULL;
463 pe_node_t *assign_to = NULL;
464
465 pe__set_next_role(rsc, rsc->role, "unmanaged");
466 assign_to = pe__current_node(rsc);
467 if (assign_to == NULL) {
468 reason = "inactive";
469 } else if (rsc->role == RSC_ROLE_PROMOTED) {
470 reason = "promoted";
471 } else if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
472 reason = "failed";
473 } else {
474 reason = "active";
475 }
476 pe_rsc_info(rsc, "Unmanaged resource %s assigned to %s: %s", rsc->id,
477 (assign_to? assign_to->details->uname : "no node"), reason);
478 pcmk__finalize_assignment(rsc, assign_to, true);
479
481 pe_rsc_debug(rsc, "Forcing %s to stop: stop-all-resources", rsc->id);
482 pcmk__finalize_assignment(rsc, NULL, true);
483
484 } else if (pcmk_is_set(rsc->flags, pe_rsc_provisional)
485 && assign_best_node(rsc, prefer)) {
486 // Assignment successful
487
488 } else if (rsc->allocated_to == NULL) {
489 if (!pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
490 pe_rsc_info(rsc, "Resource %s cannot run anywhere", rsc->id);
491 } else if (rsc->running_on != NULL) {
492 pe_rsc_info(rsc, "Stopping orphan resource %s", rsc->id);
493 }
494
495 } else {
496 pe_rsc_debug(rsc, "%s: pre-assigned to %s", rsc->id,
497 pe__node_name(rsc->allocated_to));
498 }
499
501
502 if (rsc->is_remote_node) {
503 remote_connection_assigned(rsc);
504 }
505
506 return rsc->allocated_to;
507}
508
520static void
521schedule_restart_actions(pe_resource_t *rsc, pe_node_t *current,
522 bool need_stop, bool need_promote)
523{
524 enum rsc_role_e role = rsc->role;
525 enum rsc_role_e next_role;
526 rsc_transition_fn fn = NULL;
527
529
530 // Bring resource down to a stop on its current node
531 while (role != RSC_ROLE_STOPPED) {
532 next_role = rsc_state_matrix[role][RSC_ROLE_STOPPED];
533 pe_rsc_trace(rsc, "Creating %s action to take %s down from %s to %s",
534 (need_stop? "required" : "optional"), rsc->id,
535 role2text(role), role2text(next_role));
536 fn = rsc_action_matrix[role][next_role];
537 if (fn == NULL) {
538 break;
539 }
540 fn(rsc, current, !need_stop);
541 role = next_role;
542 }
543
544 // Bring resource up to its next role on its next node
545 while ((rsc->role <= rsc->next_role) && (role != rsc->role)
546 && !pcmk_is_set(rsc->flags, pe_rsc_block)) {
547 bool required = need_stop;
548
549 next_role = rsc_state_matrix[role][rsc->role];
550 if ((next_role == RSC_ROLE_PROMOTED) && need_promote) {
551 required = true;
552 }
553 pe_rsc_trace(rsc, "Creating %s action to take %s up from %s to %s",
554 (required? "required" : "optional"), rsc->id,
555 role2text(role), role2text(next_role));
556 fn = rsc_action_matrix[role][next_role];
557 if (fn == NULL) {
558 break;
559 }
560 fn(rsc, rsc->allocated_to, !required);
561 role = next_role;
562 }
563
565}
566
575static const char *
576set_default_next_role(pe_resource_t *rsc)
577{
578 if (rsc->next_role != RSC_ROLE_UNKNOWN) {
579 return "explicit";
580 }
581
582 if (rsc->allocated_to == NULL) {
583 pe__set_next_role(rsc, RSC_ROLE_STOPPED, "assignment");
584 } else {
585 pe__set_next_role(rsc, RSC_ROLE_STARTED, "assignment");
586 }
587 return "implicit";
588}
589
596static void
597create_pending_start(pe_resource_t *rsc)
598{
599 pe_action_t *start = NULL;
600
601 pe_rsc_trace(rsc,
602 "Creating action for %s to represent already pending start",
603 rsc->id);
604 start = start_action(rsc, rsc->allocated_to, TRUE);
606}
607
614static void
615schedule_role_transition_actions(pe_resource_t *rsc)
616{
617 enum rsc_role_e role = rsc->role;
618
619 while (role != rsc->next_role) {
620 enum rsc_role_e next_role = rsc_state_matrix[role][rsc->next_role];
621 rsc_transition_fn fn = NULL;
622
623 pe_rsc_trace(rsc,
624 "Creating action to take %s from %s to %s (ending at %s)",
625 rsc->id, role2text(role), role2text(next_role),
626 role2text(rsc->next_role));
627 fn = rsc_action_matrix[role][next_role];
628 if (fn == NULL) {
629 break;
630 }
631 fn(rsc, rsc->allocated_to, false);
632 role = next_role;
633 }
634}
635
642void
644{
645 bool need_stop = false;
646 bool need_promote = false;
647 bool is_moving = false;
648 bool allow_migrate = false;
649 bool multiply_active = false;
650
651 pe_node_t *current = NULL;
652 unsigned int num_all_active = 0;
653 unsigned int num_clean_active = 0;
654 const char *next_role_source = NULL;
655
656 CRM_ASSERT(rsc != NULL);
657
658 next_role_source = set_default_next_role(rsc);
659 pe_rsc_trace(rsc,
660 "Creating all actions for %s transition from %s to %s "
661 "(%s) on %s",
662 rsc->id, role2text(rsc->role), role2text(rsc->next_role),
663 next_role_source, pe__node_name(rsc->allocated_to));
664
665 current = rsc->fns->active_node(rsc, &num_all_active, &num_clean_active);
666
668 rsc);
669
670 if ((current != NULL) && (rsc->allocated_to != NULL)
671 && (current->details != rsc->allocated_to->details)
672 && (rsc->next_role >= RSC_ROLE_STARTED)) {
673
674 pe_rsc_trace(rsc, "Moving %s from %s to %s",
675 rsc->id, pe__node_name(current),
676 pe__node_name(rsc->allocated_to));
677 is_moving = true;
678 allow_migrate = pcmk__rsc_can_migrate(rsc, current);
679
680 // This is needed even if migrating (though I'm not sure why ...)
681 need_stop = true;
682 }
683
684 // Check whether resource is partially migrated and/or multiply active
685 if ((rsc->partial_migration_source != NULL)
686 && (rsc->partial_migration_target != NULL)
687 && allow_migrate && (num_all_active == 2)
688 && pe__same_node(current, rsc->partial_migration_source)
689 && pe__same_node(rsc->allocated_to, rsc->partial_migration_target)) {
690 /* A partial migration is in progress, and the migration target remains
691 * the same as when the migration began.
692 */
693 pe_rsc_trace(rsc, "Partial migration of %s from %s to %s will continue",
694 rsc->id, pe__node_name(rsc->partial_migration_source),
695 pe__node_name(rsc->partial_migration_target));
696
697 } else if ((rsc->partial_migration_source != NULL)
698 || (rsc->partial_migration_target != NULL)) {
699 // A partial migration is in progress but can't be continued
700
701 if (num_all_active > 2) {
702 // The resource is migrating *and* multiply active!
703 crm_notice("Forcing recovery of %s because it is migrating "
704 "from %s to %s and possibly active elsewhere",
705 rsc->id, pe__node_name(rsc->partial_migration_source),
706 pe__node_name(rsc->partial_migration_target));
707 } else {
708 // The migration source or target isn't available
709 crm_notice("Forcing recovery of %s because it can no longer "
710 "migrate from %s to %s",
711 rsc->id, pe__node_name(rsc->partial_migration_source),
712 pe__node_name(rsc->partial_migration_target));
713 }
714 need_stop = true;
716 allow_migrate = false;
717
718 } else if (pcmk_is_set(rsc->flags, pe_rsc_needs_fencing)) {
719 multiply_active = (num_all_active > 1);
720 } else {
721 /* If a resource has "requires" set to nothing or quorum, don't consider
722 * it active on unclean nodes (similar to how all resources behave when
723 * stonith-enabled is false). We can start such resources elsewhere
724 * before fencing completes, and if we considered the resource active on
725 * the failed node, we would attempt recovery for being active on
726 * multiple nodes.
727 */
728 multiply_active = (num_clean_active > 1);
729 }
730
731 if (multiply_active) {
732 const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
733
734 // Resource was (possibly) incorrectly multiply active
735 pe_proc_err("%s resource %s might be active on %u nodes (%s)",
736 pcmk__s(class, "Untyped"), rsc->id, num_all_active,
737 recovery2text(rsc->recovery_type));
738 crm_notice("See https://wiki.clusterlabs.org/wiki/FAQ"
739 "#Resource_is_Too_Active for more information");
740
741 switch (rsc->recovery_type) {
743 need_stop = true;
744 break;
746 need_stop = true; // stop_resource() will skip expected node
748 break;
749 default:
750 break;
751 }
752
753 } else {
755 }
756
758 create_pending_start(rsc);
759 }
760
761 if (is_moving) {
762 // Remaining tests are only for resources staying where they are
763
764 } else if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
765 if (pcmk_is_set(rsc->flags, pe_rsc_stop)) {
766 need_stop = true;
767 pe_rsc_trace(rsc, "Recovering %s", rsc->id);
768 } else {
769 pe_rsc_trace(rsc, "Recovering %s by demotion", rsc->id);
770 if (rsc->next_role == RSC_ROLE_PROMOTED) {
771 need_promote = true;
772 }
773 }
774
775 } else if (pcmk_is_set(rsc->flags, pe_rsc_block)) {
776 pe_rsc_trace(rsc, "Blocking further actions on %s", rsc->id);
777 need_stop = true;
778
779 } else if ((rsc->role > RSC_ROLE_STARTED) && (current != NULL)
780 && (rsc->allocated_to != NULL)) {
781 pe_action_t *start = NULL;
782
783 pe_rsc_trace(rsc, "Creating start action for promoted resource %s",
784 rsc->id);
785 start = start_action(rsc, rsc->allocated_to, TRUE);
786 if (!pcmk_is_set(start->flags, pe_action_optional)) {
787 // Recovery of a promoted resource
788 pe_rsc_trace(rsc, "%s restart is required for recovery", rsc->id);
789 need_stop = true;
790 }
791 }
792
793 // Create any actions needed to bring resource down and back up to same role
794 schedule_restart_actions(rsc, current, need_stop, need_promote);
795
796 // Create any actions needed to take resource from this role to the next
797 schedule_role_transition_actions(rsc);
798
800
801 if (allow_migrate) {
802 pcmk__create_migration_actions(rsc, current);
803 }
804}
805
812static void
813rsc_avoids_remote_nodes(const pe_resource_t *rsc)
814{
815 GHashTableIter iter;
816 pe_node_t *node = NULL;
817
818 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
819 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
820 if (node->details->remote_rsc != NULL) {
821 node->weight = -INFINITY;
822 }
823 }
824}
825
839static GList *
840allowed_nodes_as_list(const pe_resource_t *rsc)
841{
842 GList *allowed_nodes = NULL;
843
844 if (rsc->allowed_nodes) {
845 allowed_nodes = g_hash_table_get_values(rsc->allowed_nodes);
846 }
847
848 if (!pcmk__is_daemon) {
849 allowed_nodes = g_list_sort(allowed_nodes, pe__cmp_node_name);
850 }
851
852 return allowed_nodes;
853}
854
861void
863{
864 GList *allowed_nodes = NULL;
865 bool check_unfencing = false;
866 bool check_utilization = false;
867
868 CRM_ASSERT(rsc != NULL);
869
870 if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
871 pe_rsc_trace(rsc,
872 "Skipping implicit constraints for unmanaged resource %s",
873 rsc->id);
874 return;
875 }
876
877 // Whether resource requires unfencing
878 check_unfencing = !pcmk_is_set(rsc->flags, pe_rsc_fence_device)
881
882 // Whether a non-default placement strategy is used
883 check_utilization = (g_hash_table_size(rsc->utilization) > 0)
884 && !pcmk__str_eq(rsc->cluster->placement_strategy,
885 "default", pcmk__str_casei);
886
887 // Order stops before starts (i.e. restart)
888 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, RSC_STOP, 0), NULL,
889 rsc, pcmk__op_key(rsc->id, RSC_START, 0), NULL,
891 rsc->cluster);
892
893 // Promotable ordering: demote before stop, start before promote
896 || (rsc->role > RSC_ROLE_UNPROMOTED)) {
897
898 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, RSC_DEMOTE, 0), NULL,
899 rsc, pcmk__op_key(rsc->id, RSC_STOP, 0), NULL,
901
902 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, RSC_START, 0), NULL,
903 rsc, pcmk__op_key(rsc->id, RSC_PROMOTE, 0), NULL,
905 }
906
907 // Don't clear resource history if probing on same node
909 NULL, rsc, pcmk__op_key(rsc->id, RSC_STATUS, 0),
911 rsc->cluster);
912
913 // Certain checks need allowed nodes
914 if (check_unfencing || check_utilization || (rsc->container != NULL)) {
915 allowed_nodes = allowed_nodes_as_list(rsc);
916 }
917
918 if (check_unfencing) {
919 g_list_foreach(allowed_nodes, pcmk__order_restart_vs_unfence, rsc);
920 }
921
922 if (check_utilization) {
923 pcmk__create_utilization_constraints(rsc, allowed_nodes);
924 }
925
926 if (rsc->container != NULL) {
927 pe_resource_t *remote_rsc = NULL;
928
929 if (rsc->is_remote_node) {
930 // rsc is the implicit remote connection for a guest or bundle node
931
932 /* Guest resources are not allowed to run on Pacemaker Remote nodes,
933 * to avoid nesting remotes. However, bundles are allowed.
934 */
936 rsc_avoids_remote_nodes(rsc->container);
937 }
938
939 /* If someone cleans up a guest or bundle node's container, we will
940 * likely schedule a (re-)probe of the container and recovery of the
941 * connection. Order the connection stop after the container probe,
942 * so that if we detect the container running, we will trigger a new
943 * transition and avoid the unnecessary recovery.
944 */
947
948 /* A user can specify that a resource must start on a Pacemaker Remote
949 * node by explicitly configuring it with the container=NODENAME
950 * meta-attribute. This is of questionable merit, since location
951 * constraints can accomplish the same thing. But we support it, so here
952 * we check whether a resource (that is not itself a remote connection)
953 * has container set to a remote node or guest node resource.
954 */
955 } else if (rsc->container->is_remote_node) {
956 remote_rsc = rsc->container;
957 } else {
959 rsc->container);
960 }
961
962 if (remote_rsc != NULL) {
963 /* Force the resource on the Pacemaker Remote node instead of
964 * colocating the resource with the container resource.
965 */
966 for (GList *item = allowed_nodes; item; item = item->next) {
967 pe_node_t *node = item->data;
968
969 if (node->details->remote_rsc != remote_rsc) {
970 node->weight = -INFINITY;
971 }
972 }
973
974 } else {
975 /* This resource is either a filler for a container that does NOT
976 * represent a Pacemaker Remote node, or a Pacemaker Remote
977 * connection resource for a guest node or bundle.
978 */
979 int score;
980
981 crm_trace("Order and colocate %s relative to its container %s",
982 rsc->id, rsc->container->id);
983
986 NULL, rsc, pcmk__op_key(rsc->id, RSC_START, 0),
987 NULL,
989 rsc->cluster);
990
991 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, RSC_STOP, 0), NULL,
992 rsc->container,
994 NULL, pe_order_implies_first, rsc->cluster);
995
997 score = 10000; /* Highly preferred but not essential */
998 } else {
999 score = INFINITY; /* Force them to run on the same host */
1000 }
1001 pcmk__new_colocation("resource-with-container", NULL, score, rsc,
1002 rsc->container, NULL, NULL, true,
1003 rsc->cluster);
1004 }
1005 }
1006
1008 /* Remote connections and fencing devices are not allowed to run on
1009 * Pacemaker Remote nodes
1010 */
1011 rsc_avoids_remote_nodes(rsc);
1012 }
1013 g_list_free(allowed_nodes);
1014}
1015
1029void
1031 const pe_resource_t *primary,
1032 const pcmk__colocation_t *colocation,
1033 bool for_dependent)
1034{
1035 enum pcmk__coloc_affects filter_results;
1036
1037 CRM_CHECK((colocation != NULL) && (dependent != NULL) && (primary != NULL),
1038 return);
1039
1040 if (for_dependent) {
1041 // Always process on behalf of primary resource
1042 primary->cmds->apply_coloc_score(dependent, primary, colocation, false);
1043 return;
1044 }
1045
1046 filter_results = pcmk__colocation_affects(dependent, primary, colocation,
1047 false);
1048 pe_rsc_trace(dependent, "%s %s with %s (%s, score=%d, filter=%d)",
1049 ((colocation->score > 0)? "Colocating" : "Anti-colocating"),
1050 dependent->id, primary->id, colocation->id, colocation->score,
1051 filter_results);
1052
1053 switch (filter_results) {
1055 pcmk__apply_coloc_to_priority(dependent, primary, colocation);
1056 break;
1058 pcmk__apply_coloc_to_weights(dependent, primary, colocation);
1059 break;
1060 default: // pcmk__coloc_affects_nothing
1061 return;
1062 }
1063}
1064
1065/* Primitive implementation of
1066 * resource_alloc_functions_t:with_this_colocations()
1067 */
1068void
1070 const pe_resource_t *orig_rsc, GList **list)
1071{
1072 // Primitives don't have children, so rsc should also be orig_rsc
1073 CRM_CHECK((rsc != NULL) && (rsc->variant == pe_native)
1074 && (rsc == orig_rsc) && (list != NULL),
1075 return);
1076
1077 // Add primitive's own colocations plus any relevant ones from parent
1079 if (rsc->parent != NULL) {
1080 rsc->parent->cmds->with_this_colocations(rsc->parent, rsc, list);
1081 }
1082}
1083
1084/* Primitive implementation of
1085 * resource_alloc_functions_t:this_with_colocations()
1086 */
1087void
1089 const pe_resource_t *orig_rsc, GList **list)
1090{
1091 // Primitives don't have children, so rsc should also be orig_rsc
1092 CRM_CHECK((rsc != NULL) && (rsc->variant == pe_native)
1093 && (rsc == orig_rsc) && (list != NULL),
1094 return);
1095
1096 // Add primitive's own colocations plus any relevant ones from parent
1098 if (rsc->parent != NULL) {
1099 rsc->parent->cmds->this_with_colocations(rsc->parent, rsc, list);
1100 }
1101}
1102
1112enum pe_action_flags
1114{
1115 CRM_ASSERT(action != NULL);
1116 return action->flags;
1117}
1118
1132static bool
1133is_expected_node(const pe_resource_t *rsc, const pe_node_t *node)
1134{
1135 return pcmk_all_flags_set(rsc->flags,
1137 && (rsc->next_role > RSC_ROLE_STOPPED)
1138 && pe__same_node(rsc->allocated_to, node);
1139}
1140
1149static void
1150stop_resource(pe_resource_t *rsc, pe_node_t *node, bool optional)
1151{
1152 for (GList *iter = rsc->running_on; iter != NULL; iter = iter->next) {
1153 pe_node_t *current = (pe_node_t *) iter->data;
1154 pe_action_t *stop = NULL;
1155
1156 if (is_expected_node(rsc, current)) {
1157 /* We are scheduling restart actions for a multiply active resource
1158 * with multiple-active=stop_unexpected, and this is where it should
1159 * not be stopped.
1160 */
1161 pe_rsc_trace(rsc,
1162 "Skipping stop of multiply active resource %s "
1163 "on expected node %s",
1164 rsc->id, pe__node_name(current));
1165 continue;
1166 }
1167
1168 if (rsc->partial_migration_target != NULL) {
1169 // Continue migration if node originally was and remains target
1170 if (pe__same_node(current, rsc->partial_migration_target)
1171 && pe__same_node(current, rsc->allocated_to)) {
1172 pe_rsc_trace(rsc,
1173 "Skipping stop of %s on %s "
1174 "because partial migration there will continue",
1175 rsc->id, pe__node_name(current));
1176 continue;
1177 } else {
1178 pe_rsc_trace(rsc,
1179 "Forcing stop of %s on %s "
1180 "because migration target changed",
1181 rsc->id, pe__node_name(current));
1182 optional = false;
1183 }
1184 }
1185
1186 pe_rsc_trace(rsc, "Scheduling stop of %s on %s",
1187 rsc->id, pe__node_name(current));
1188 stop = stop_action(rsc, current, optional);
1189
1190 if (rsc->allocated_to == NULL) {
1191 pe_action_set_reason(stop, "node availability", true);
1192 } else if (pcmk_all_flags_set(rsc->flags, pe_rsc_restarting
1194 /* We are stopping a multiply active resource on a node that is
1195 * not its expected node, and we are still scheduling restart
1196 * actions, so the stop is for being multiply active.
1197 */
1198 pe_action_set_reason(stop, "being multiply active", true);
1199 }
1200
1201 if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
1203 }
1204
1206 pcmk__schedule_cleanup(rsc, current, optional);
1207 }
1208
1210 pe_action_t *unfence = pe_fence_op(current, "on", true, NULL, false,
1211 rsc->cluster);
1212
1213 order_actions(stop, unfence, pe_order_implies_first);
1214 if (!pcmk__node_unfenced(current)) {
1215 pe_proc_err("Stopping %s until %s can be unfenced",
1216 rsc->id, pe__node_name(current));
1217 }
1218 }
1219 }
1220}
1221
1230static void
1231start_resource(pe_resource_t *rsc, pe_node_t *node, bool optional)
1232{
1233 pe_action_t *start = NULL;
1234
1235 CRM_ASSERT(node != NULL);
1236
1237 pe_rsc_trace(rsc, "Scheduling %s start of %s on %s (score %d)",
1238 (optional? "optional" : "required"), rsc->id,
1239 pe__node_name(node), node->weight);
1240 start = start_action(rsc, node, TRUE);
1241
1243
1244 if (pcmk_is_set(start->flags, pe_action_runnable) && !optional) {
1246 }
1247
1248 if (is_expected_node(rsc, node)) {
1249 /* This could be a problem if the start becomes necessary for other
1250 * reasons later.
1251 */
1252 pe_rsc_trace(rsc,
1253 "Start of multiply active resource %s "
1254 "on expected node %s will be a pseudo-action",
1255 rsc->id, pe__node_name(node));
1257 }
1258}
1259
1268static void
1269promote_resource(pe_resource_t *rsc, pe_node_t *node, bool optional)
1270{
1271 GList *iter = NULL;
1272 GList *action_list = NULL;
1273 bool runnable = true;
1274
1275 CRM_ASSERT(node != NULL);
1276
1277 // Any start must be runnable for promotion to be runnable
1278 action_list = pe__resource_actions(rsc, node, RSC_START, true);
1279 for (iter = action_list; iter != NULL; iter = iter->next) {
1280 pe_action_t *start = (pe_action_t *) iter->data;
1281
1282 if (!pcmk_is_set(start->flags, pe_action_runnable)) {
1283 runnable = false;
1284 }
1285 }
1286 g_list_free(action_list);
1287
1288 if (runnable) {
1289 pe_action_t *promote = promote_action(rsc, node, optional);
1290
1291 pe_rsc_trace(rsc, "Scheduling %s promotion of %s on %s",
1292 (optional? "optional" : "required"), rsc->id,
1293 pe__node_name(node));
1294
1295 if (is_expected_node(rsc, node)) {
1296 /* This could be a problem if the promote becomes necessary for
1297 * other reasons later.
1298 */
1299 pe_rsc_trace(rsc,
1300 "Promotion of multiply active resource %s "
1301 "on expected node %s will be a pseudo-action",
1302 rsc->id, pe__node_name(node));
1304 }
1305 } else {
1306 pe_rsc_trace(rsc, "Not promoting %s on %s: start unrunnable",
1307 rsc->id, pe__node_name(node));
1308 action_list = pe__resource_actions(rsc, node, RSC_PROMOTE, true);
1309 for (iter = action_list; iter != NULL; iter = iter->next) {
1310 pe_action_t *promote = (pe_action_t *) iter->data;
1311
1313 }
1314 g_list_free(action_list);
1315 }
1316}
1317
1326static void
1327demote_resource(pe_resource_t *rsc, pe_node_t *node, bool optional)
1328{
1329 /* Since this will only be called for a primitive (possibly as an instance
1330 * of a collective resource), the resource is multiply active if it is
1331 * running on more than one node, so we want to demote on all of them as
1332 * part of recovery, regardless of which one is the desired node.
1333 */
1334 for (GList *iter = rsc->running_on; iter != NULL; iter = iter->next) {
1335 pe_node_t *current = (pe_node_t *) iter->data;
1336
1337 if (is_expected_node(rsc, current)) {
1338 pe_rsc_trace(rsc,
1339 "Skipping demote of multiply active resource %s "
1340 "on expected node %s",
1341 rsc->id, pe__node_name(current));
1342 } else {
1343 pe_rsc_trace(rsc, "Scheduling %s demotion of %s on %s",
1344 (optional? "optional" : "required"), rsc->id,
1345 pe__node_name(current));
1346 demote_action(rsc, current, optional);
1347 }
1348 }
1349}
1350
1351static void
1352assert_role_error(pe_resource_t *rsc, pe_node_t *node, bool optional)
1353{
1354 CRM_ASSERT(false);
1355}
1356
1365void
1366pcmk__schedule_cleanup(pe_resource_t *rsc, const pe_node_t *node, bool optional)
1367{
1368 /* If the cleanup is required, its orderings are optional, because they're
1369 * relevant only if both actions are required. Conversely, if the cleanup is
1370 * optional, the orderings make the then action required if the first action
1371 * becomes required.
1372 */
1373 uint32_t flag = optional? pe_order_implies_then : pe_order_optional;
1374
1375 CRM_CHECK((rsc != NULL) && (node != NULL), return);
1376
1377 if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
1378 pe_rsc_trace(rsc, "Skipping clean-up of %s on %s: resource failed",
1379 rsc->id, pe__node_name(node));
1380 return;
1381 }
1382
1383 if (node->details->unclean || !node->details->online) {
1384 pe_rsc_trace(rsc, "Skipping clean-up of %s on %s: node unavailable",
1385 rsc->id, pe__node_name(node));
1386 return;
1387 }
1388
1389 crm_notice("Scheduling clean-up of %s on %s", rsc->id, pe__node_name(node));
1390 delete_action(rsc, node, optional);
1391
1392 // stop -> clean-up -> start
1395}
1396
1404void
1406{
1407 char *name = NULL;
1408 char *value = NULL;
1409 const pe_resource_t *parent = NULL;
1410
1411 CRM_ASSERT((rsc != NULL) && (xml != NULL));
1412
1413 /* Clone instance numbers get set internally as meta-attributes, and are
1414 * needed in the transition graph (for example, to tell unique clone
1415 * instances apart).
1416 */
1417 value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INCARNATION);
1418 if (value != NULL) {
1420 crm_xml_add(xml, name, value);
1421 free(name);
1422 }
1423
1424 // Not sure if this one is really needed ...
1425 value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_REMOTE_NODE);
1426 if (value != NULL) {
1428 crm_xml_add(xml, name, value);
1429 free(name);
1430 }
1431
1432 /* The container meta-attribute can be set on the primitive itself or one of
1433 * its parents (for example, a group inside a container resource), so check
1434 * them all, and keep the highest one found.
1435 */
1436 for (parent = rsc; parent != NULL; parent = parent->parent) {
1437 if (parent->container != NULL) {
1439 parent->container->id);
1440 }
1441 }
1442
1443 /* Bundle replica children will get their external-ip set internally as a
1444 * meta-attribute. The graph action needs it, but under a different naming
1445 * convention than other meta-attributes.
1446 */
1447 value = g_hash_table_lookup(rsc->meta, "external-ip");
1448 if (value != NULL) {
1449 crm_xml_add(xml, "pcmk_external_ip", value);
1450 }
1451}
1452
1453// Primitive implementation of resource_alloc_functions_t:add_utilization()
1454void
1456 const pe_resource_t *orig_rsc, GList *all_rscs,
1457 GHashTable *utilization)
1458{
1459 if (!pcmk_is_set(rsc->flags, pe_rsc_provisional)) {
1460 return;
1461 }
1462
1463 pe_rsc_trace(orig_rsc, "%s: Adding primitive %s as colocated utilization",
1464 orig_rsc->id, rsc->id);
1465 pcmk__release_node_capacity(utilization, rsc);
1466}
1467
1476static time_t
1477shutdown_time(pe_node_t *node)
1478{
1479 const char *shutdown = pe_node_attribute_raw(node, XML_CIB_ATTR_SHUTDOWN);
1480 time_t result = 0;
1481
1482 if (shutdown != NULL) {
1483 long long result_ll;
1484
1485 if (pcmk__scan_ll(shutdown, &result_ll, 0LL) == pcmk_rc_ok) {
1486 result = (time_t) result_ll;
1487 }
1488 }
1489 return (result == 0)? get_effective_time(node->details->data_set) : result;
1490}
1491
1499static void
1500ban_if_not_locked(gpointer data, gpointer user_data)
1501{
1502 const pe_node_t *node = (const pe_node_t *) data;
1503 pe_resource_t *rsc = (pe_resource_t *) user_data;
1504
1505 if (strcmp(node->details->uname, rsc->lock_node->details->uname) != 0) {
1508 }
1509}
1510
1511// Primitive implementation of resource_alloc_functions_t:shutdown_lock()
1512void
1514{
1515 const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
1516
1517 // Fence devices and remote connections can't be locked
1518 if (pcmk__str_eq(class, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_null_matches)
1519 || pe__resource_is_remote_conn(rsc, rsc->cluster)) {
1520 return;
1521 }
1522
1523 if (rsc->lock_node != NULL) {
1524 // The lock was obtained from resource history
1525
1526 if (rsc->running_on != NULL) {
1527 /* The resource was started elsewhere even though it is now
1528 * considered locked. This shouldn't be possible, but as a
1529 * failsafe, we don't want to disturb the resource now.
1530 */
1531 pe_rsc_info(rsc,
1532 "Cancelling shutdown lock because %s is already active",
1533 rsc->id);
1535 rsc->lock_node = NULL;
1536 rsc->lock_time = 0;
1537 }
1538
1539 // Only a resource active on exactly one node can be locked
1540 } else if (pcmk__list_of_1(rsc->running_on)) {
1541 pe_node_t *node = rsc->running_on->data;
1542
1543 if (node->details->shutdown) {
1544 if (node->details->unclean) {
1545 pe_rsc_debug(rsc, "Not locking %s to unclean %s for shutdown",
1546 rsc->id, pe__node_name(node));
1547 } else {
1548 rsc->lock_node = node;
1549 rsc->lock_time = shutdown_time(node);
1550 }
1551 }
1552 }
1553
1554 if (rsc->lock_node == NULL) {
1555 // No lock needed
1556 return;
1557 }
1558
1559 if (rsc->cluster->shutdown_lock > 0) {
1560 time_t lock_expiration = rsc->lock_time + rsc->cluster->shutdown_lock;
1561
1562 pe_rsc_info(rsc, "Locking %s to %s due to shutdown (expires @%lld)",
1563 rsc->id, pe__node_name(rsc->lock_node),
1564 (long long) lock_expiration);
1565 pe__update_recheck_time(++lock_expiration, rsc->cluster);
1566 } else {
1567 pe_rsc_info(rsc, "Locking %s to %s due to shutdown",
1568 rsc->id, pe__node_name(rsc->lock_node));
1569 }
1570
1571 // If resource is locked to one node, ban it from all other nodes
1572 g_list_foreach(rsc->cluster->nodes, ban_if_not_locked, rsc);
1573}
#define PCMK_RESOURCE_CLASS_STONITH
Definition agents.h:31
const char * parent
Definition cib.c:25
const char * name
Definition cib.c:24
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:42
bool pcmk__is_daemon
Definition logging.c:47
uint64_t flags
Definition remote.c:3
const char * pcmk_readable_score(int score)
Return a displayable static string for a score value.
Definition scores.c:86
char * crm_meta_name(const char *field)
Definition utils.c:468
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:121
@ recovery_stop_start
Definition common.h:79
@ recovery_stop_unexpected
Definition common.h:82
const char * role2text(enum rsc_role_e role)
Definition common.c:450
rsc_role_e
Possible roles that a resource can be in.
Definition common.h:92
@ RSC_ROLE_STARTED
Definition common.h:95
@ RSC_ROLE_STOPPED
Definition common.h:94
@ RSC_ROLE_PROMOTED
Definition common.h:97
@ RSC_ROLE_UNKNOWN
Definition common.h:93
@ RSC_ROLE_UNPROMOTED
Definition common.h:96
#define RSC_ROLE_MAX
Definition common.h:108
char data[0]
Definition cpg.c:10
uint32_t id
Definition cpg.c:0
#define CRM_SCORE_INFINITY
Definition crm.h:85
#define RSC_PROMOTE
Definition crm.h:205
#define RSC_DEMOTE
Definition crm.h:207
#define RSC_START
Definition crm.h:199
#define CRM_META
Definition crm.h:78
#define INFINITY
Definition crm.h:99
#define RSC_STOP
Definition crm.h:202
#define RSC_STATUS
Definition crm.h:213
#define CRM_OP_LRM_DELETE
Definition crm.h:149
#define RSC_DELETE
Definition crm.h:193
G_GNUC_INTERNAL bool pcmk__node_unfenced(const pe_node_t *node)
void pcmk__abort_dangling_migration(void *data, void *user_data)
G_GNUC_INTERNAL void pcmk__create_utilization_constraints(pe_resource_t *rsc, const GList *allowed_nodes)
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)
G_GNUC_INTERNAL void pcmk__add_with_this_list(GList **list, GList *addition)
G_GNUC_INTERNAL bool pcmk__any_node_available(GHashTable *nodes)
#define pcmk__order_resource_actions(first_rsc, first_task, then_rsc, then_task, flags)
void pcmk__create_migration_actions(pe_resource_t *rsc, const pe_node_t *current)
G_GNUC_INTERNAL enum pcmk__coloc_affects pcmk__colocation_affects(const pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation, bool preview)
pcmk__coloc_affects
@ pcmk__coloc_affects_location
@ pcmk__coloc_affects_role
G_GNUC_INTERNAL GList * pcmk__sort_nodes(GList *nodes, pe_node_t *active_node)
G_GNUC_INTERNAL void pcmk__order_restart_vs_unfence(gpointer data, gpointer user_data)
G_GNUC_INTERNAL bool pcmk__finalize_assignment(pe_resource_t *rsc, pe_node_t *chosen, bool force)
G_GNUC_INTERNAL void pcmk__add_dependent_scores(gpointer data, gpointer user_data)
G_GNUC_INTERNAL const pe_node_t * pcmk__ban_insufficient_capacity(pe_resource_t *rsc)
G_GNUC_INTERNAL void pcmk__release_node_capacity(GHashTable *current_utilization, const pe_resource_t *rsc)
G_GNUC_INTERNAL void pcmk__order_vs_unfence(const pe_resource_t *rsc, pe_node_t *node, pe_action_t *action, enum pe_ordering order)
G_GNUC_INTERNAL void pcmk__add_this_with_list(GList **list, GList *addition)
G_GNUC_INTERNAL void pcmk__create_recurring_actions(pe_resource_t *rsc)
bool pcmk__rsc_can_migrate(const pe_resource_t *rsc, const pe_node_t *current)
G_GNUC_INTERNAL void pcmk__apply_coloc_to_priority(pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation)
G_GNUC_INTERNAL bool pcmk__node_available(const pe_node_t *node, bool consider_score, bool consider_guest)
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)
G_GNUC_INTERNAL GHashTable * pcmk__copy_node_table(GHashTable *nodes)
G_GNUC_INTERNAL void pcmk__apply_coloc_to_weights(pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation)
#define do_crm_log(level, fmt, args...)
Log a message.
Definition logging.h:172
#define crm_notice(fmt, args...)
Definition logging.h:377
#define CRM_CHECK(expr, failure_action)
Definition logging.h:235
#define crm_trace(fmt, args...)
Definition logging.h:381
#define XML_RSC_ATTR_TARGET_ROLE
Definition msg_xml.h:249
#define XML_RSC_ATTR_REMOTE_NODE
Definition msg_xml.h:260
#define XML_RSC_ATTR_CONTAINER
Definition msg_xml.h:257
#define XML_CONFIG_ATTR_SHUTDOWN_LOCK
Definition msg_xml.h:413
#define XML_RSC_ATTR_INCARNATION
Definition msg_xml.h:241
#define XML_AGENT_ATTR_CLASS
Definition msg_xml.h:282
#define XML_CIB_ATTR_SHUTDOWN
Definition msg_xml.h:301
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:496
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition nvpair.c:302
const char * action
Definition pcmk_fence.c:30
pcmk__action_result_t result
Definition pcmk_fence.c:35
void pcmk__primitive_add_graph_meta(const pe_resource_t *rsc, xmlNode *xml)
void pcmk__primitive_create_actions(pe_resource_t *rsc)
void pcmk__primitive_with_colocations(const pe_resource_t *rsc, const pe_resource_t *orig_rsc, GList **list)
void pcmk__schedule_cleanup(pe_resource_t *rsc, const pe_node_t *node, bool optional)
void pcmk__with_primitive_colocations(const pe_resource_t *rsc, const pe_resource_t *orig_rsc, GList **list)
void pcmk__primitive_internal_constraints(pe_resource_t *rsc)
void pcmk__primitive_add_utilization(const pe_resource_t *rsc, const pe_resource_t *orig_rsc, GList *all_rscs, GHashTable *utilization)
void(* rsc_transition_fn)(pe_resource_t *rsc, pe_node_t *node, bool optional)
void pcmk__primitive_apply_coloc_score(pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
pe_node_t * pcmk__primitive_assign(pe_resource_t *rsc, const pe_node_t *prefer)
void pcmk__primitive_shutdown_lock(pe_resource_t *rsc)
enum pe_action_flags pcmk__primitive_action_flags(pe_action_t *action, const pe_node_t *node)
GList * pcmk__this_with_colocations(const pe_resource_t *rsc)
GList * pcmk__with_this_colocations(const pe_resource_t *rsc)
@ no_quorum_freeze
Definition pe_types.h:80
#define pe_rsc_fence_device
Definition pe_types.h:279
#define pe_flag_have_stonith_resource
Definition pe_types.h:116
#define pe_rsc_needs_unfencing
Definition pe_types.h:313
#define pe_flag_have_quorum
Definition pe_types.h:111
#define pe_rsc_block
Definition pe_types.h:274
#define pe_rsc_stop_unexpected
Definition pe_types.h:303
#define pe_rsc_managed
Definition pe_types.h:273
@ pe_order_restart
Definition pe_types.h:530
@ pe_order_implies_then
Definition pe_types.h:512
@ pe_order_same_node
Definition pe_types.h:533
@ pe_order_then_cancels_first
Definition pe_types.h:544
@ pe_order_optional
Definition pe_types.h:508
@ pe_order_implies_first
Definition pe_types.h:511
@ pe_order_runnable_left
Definition pe_types.h:518
@ pe_order_promoted_implies_first
Definition pe_types.h:513
#define pe_rsc_provisional
Definition pe_types.h:282
#define pe_flag_enable_unfencing
Definition pe_types.h:117
#define pe_rsc_allocating
Definition pe_types.h:283
#define pe_rsc_orphan
Definition pe_types.h:272
#define pe_flag_stop_everything
Definition pe_types.h:122
#define pe_rsc_allow_remote_remotes
Definition pe_types.h:289
#define pe_rsc_restarting
Definition pe_types.h:285
#define pe_flag_show_scores
Definition pe_types.h:150
pe_action_flags
Definition pe_types.h:316
@ pe_action_optional
Definition pe_types.h:319
@ pe_action_runnable
Definition pe_types.h:318
@ pe_action_pseudo
Definition pe_types.h:317
@ pe_action_print_always
Definition pe_types.h:320
@ pe_native
Definition pe_types.h:38
#define pe_rsc_stop
Definition pe_types.h:287
#define pe_flag_stonith_enabled
Definition pe_types.h:115
#define pe_rsc_needs_fencing
Definition pe_types.h:312
#define pe_flag_remove_after_stop
Definition pe_types.h:127
#define pe_rsc_failed
Definition pe_types.h:292
#define pe_rsc_promotable
Definition pe_types.h:280
#define pe_rsc_start_pending
Definition pe_types.h:295
GList * pe__resource_actions(const pe_resource_t *rsc, const pe_node_t *node, const char *task, bool require_node)
Find all actions of given type for a resource.
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition internal.h:385
#define delete_action(rsc, node, optional)
Definition internal.h:396
const char * pe_node_attribute_raw(const pe_node_t *node, const char *name)
Definition common.c:558
#define demote_action(rsc, node, optional)
Definition internal.h:432
#define start_action(rsc, node, optional)
Definition internal.h:412
void pe__set_next_role(pe_resource_t *rsc, enum rsc_role_e role, const char *why)
Definition complex.c:1166
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition internal.h:83
#define pe_rsc_debug(rsc, fmt, args...)
Definition internal.h:49
gint pe__cmp_node_name(gconstpointer a, gconstpointer b)
Definition utils.c:185
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition utils.c:488
#define pe_rsc_trace(rsc, fmt, args...)
Definition internal.h:50
pe_action_t * pe_fence_op(pe_node_t *node, const char *op, bool optional, const char *reason, bool priority_delay, pe_working_set_t *data_set)
pe_action_t * pe__clear_resource_history(pe_resource_t *rsc, const pe_node_t *node, pe_working_set_t *data_set)
void resource_location(pe_resource_t *rsc, const pe_node_t *node, int score, const char *tag, pe_working_set_t *data_set)
Definition utils.c:398
#define pe__set_resource_flags(resource, flags_to_set)
Definition internal.h:77
time_t get_effective_time(pe_working_set_t *data_set)
Definition utils.c:434
#define stop_action(rsc, node, optional)
Definition internal.h:406
#define pe_rsc_info(rsc, fmt, args...)
Definition internal.h:48
#define pe_proc_err(fmt...)
Definition internal.h:62
void pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set)
Definition utils.c:715
#define pe__clear_action_flags(action, flags_to_clear)
Definition internal.h:98
#define promote_action(rsc, node, optional)
Definition internal.h:422
void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
const pe_resource_t * pe__const_top_resource(const pe_resource_t *rsc, bool include_bundle)
Definition complex.c:947
#define pe__set_action_flags(action, flags_to_set)
Definition internal.h:89
pe_resource_t * pe__resource_contains_guest_node(const pe_working_set_t *data_set, const pe_resource_t *rsc)
Definition remote.c:66
bool pe__resource_is_remote_conn(const pe_resource_t *rsc, const pe_working_set_t *data_set)
Definition remote.c:17
#define CRM_ASSERT(expr)
Definition results.h:42
@ pcmk_rc_ok
Definition results.h:151
pe_node_t * pe_find_node(const GList *node_list, const char *node_name)
Find a node by name in a list of nodes.
Definition status.c:473
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
pe_resource_t * primary
enum pe_action_flags flags
Definition pe_types.h:442
int weight
Definition pe_types.h:265
struct pe_node_shared_s * details
Definition pe_types.h:268
gboolean shutdown
Definition pe_types.h:242
const char * id
Definition pe_types.h:231
gboolean online
Definition pe_types.h:236
const char * uname
Definition pe_types.h:232
pe_working_set_t * data_set
Cluster that this node is part of.
Definition pe_types.h:261
pe_resource_t * remote_rsc
Definition pe_types.h:253
gboolean unclean
Definition pe_types.h:240
gboolean unseen
Definition pe_types.h:241
GList * running_on
Definition pe_types.h:398
enum pe_obj_types variant
Definition pe_types.h:356
GHashTable * meta
Definition pe_types.h:405
GList * rsc_cons
Definition pe_types.h:389
GList * rsc_cons_lhs
Definition pe_types.h:388
pe_working_set_t * cluster
Definition pe_types.h:353
pe_resource_t * container
Definition pe_types.h:412
gboolean is_remote_node
Definition pe_types.h:376
GHashTable * utilization
Definition pe_types.h:407
GHashTable * allowed_nodes
Definition pe_types.h:400
GList * dangling_migrations
Definition pe_types.h:410
pe_node_t * partial_migration_source
Definition pe_types.h:397
pe_node_t * allocated_to
Definition pe_types.h:395
unsigned long long flags
Definition pe_types.h:373
pe_resource_t * parent
Definition pe_types.h:354
pe_node_t * partial_migration_target
Definition pe_types.h:396
resource_alloc_functions_t * cmds
Definition pe_types.h:359
enum rsc_role_e next_role
Definition pe_types.h:403
enum rsc_role_e role
Definition pe_types.h:402
resource_object_functions_t * fns
Definition pe_types.h:358
time_t lock_time
Definition pe_types.h:419
pe_node_t * lock_node
Definition pe_types.h:417
const char * placement_strategy
Definition pe_types.h:167
guint shutdown_lock
Definition pe_types.h:212
unsigned long long flags
Definition pe_types.h:169
enum pe_quorum_policy no_quorum_policy
Definition pe_types.h:172
void(* apply_coloc_score)(pe_resource_t *dependent, const pe_resource_t *primary, const pcmk__colocation_t *colocation, bool for_dependent)
void(* this_with_colocations)(const pe_resource_t *rsc, const pe_resource_t *orig_rsc, GList **list)
void(* with_this_colocations)(const pe_resource_t *rsc, const pe_resource_t *orig_rsc, GList **list)
pe_node_t *(* assign)(pe_resource_t *rsc, const pe_node_t *prefer)
pe_node_t *(* active_node)(const pe_resource_t *rsc, unsigned int *count_all, unsigned int *count_clean)
Definition pe_types.h:73