This source file includes following definitions.
- pcmk__rsc_agent_changed
- add_rsc_if_matching
- pcmk__rscs_matching_id
- set_assignment_methods_for_rsc
- pcmk__set_assignment_methods
- add_colocated_resources
- pcmk__colocated_resources
- pcmk__noop_add_graph_meta
- pcmk__output_resource_actions
- add_assigned_resource
- pcmk__assign_resource
- pcmk__unassign_resource
- pcmk__threshold_reached
- get_node_score
- cmp_resources
- pcmk__sort_resources
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <crm/common/xml.h>
15 #include <pacemaker-internal.h>
16
17 #include "libpacemaker_private.h"
18
19
20 static pcmk__assignment_methods_t assignment_methods[] = {
21 {
22 pcmk__primitive_assign,
23 pcmk__primitive_create_actions,
24 pcmk__probe_rsc_on_node,
25 pcmk__primitive_internal_constraints,
26 pcmk__primitive_apply_coloc_score,
27 pcmk__colocated_resources,
28 pcmk__with_primitive_colocations,
29 pcmk__primitive_with_colocations,
30 pcmk__add_colocated_node_scores,
31 pcmk__apply_location,
32 pcmk__primitive_action_flags,
33 pcmk__update_ordered_actions,
34 pcmk__output_resource_actions,
35 pcmk__add_rsc_actions_to_graph,
36 pcmk__primitive_add_graph_meta,
37 pcmk__primitive_add_utilization,
38 pcmk__primitive_shutdown_lock,
39 },
40 {
41 pcmk__group_assign,
42 pcmk__group_create_actions,
43 pcmk__probe_rsc_on_node,
44 pcmk__group_internal_constraints,
45 pcmk__group_apply_coloc_score,
46 pcmk__group_colocated_resources,
47 pcmk__with_group_colocations,
48 pcmk__group_with_colocations,
49 pcmk__group_add_colocated_node_scores,
50 pcmk__group_apply_location,
51 pcmk__group_action_flags,
52 pcmk__group_update_ordered_actions,
53 pcmk__output_resource_actions,
54 pcmk__add_rsc_actions_to_graph,
55 pcmk__noop_add_graph_meta,
56 pcmk__group_add_utilization,
57 pcmk__group_shutdown_lock,
58 },
59 {
60 pcmk__clone_assign,
61 pcmk__clone_create_actions,
62 pcmk__clone_create_probe,
63 pcmk__clone_internal_constraints,
64 pcmk__clone_apply_coloc_score,
65 pcmk__colocated_resources,
66 pcmk__with_clone_colocations,
67 pcmk__clone_with_colocations,
68 pcmk__add_colocated_node_scores,
69 pcmk__clone_apply_location,
70 pcmk__clone_action_flags,
71 pcmk__instance_update_ordered_actions,
72 pcmk__output_resource_actions,
73 pcmk__clone_add_actions_to_graph,
74 pcmk__clone_add_graph_meta,
75 pcmk__clone_add_utilization,
76 pcmk__clone_shutdown_lock,
77 },
78 {
79 pcmk__bundle_assign,
80 pcmk__bundle_create_actions,
81 pcmk__bundle_create_probe,
82 pcmk__bundle_internal_constraints,
83 pcmk__bundle_apply_coloc_score,
84 pcmk__colocated_resources,
85 pcmk__with_bundle_colocations,
86 pcmk__bundle_with_colocations,
87 pcmk__add_colocated_node_scores,
88 pcmk__bundle_apply_location,
89 pcmk__bundle_action_flags,
90 pcmk__instance_update_ordered_actions,
91 pcmk__output_bundle_actions,
92 pcmk__bundle_add_actions_to_graph,
93 pcmk__noop_add_graph_meta,
94 pcmk__bundle_add_utilization,
95 pcmk__bundle_shutdown_lock,
96 }
97 };
98
99
100
101
102
103
104
105
106
107
108
109
110 bool
111 pcmk__rsc_agent_changed(pcmk_resource_t *rsc, pcmk_node_t *node,
112 const xmlNode *rsc_entry, bool active_on_node)
113 {
114 bool changed = false;
115 const char *attr_list[] = {
116 PCMK_XA_TYPE,
117 PCMK_XA_CLASS,
118 PCMK_XA_PROVIDER,
119 };
120
121 for (int i = 0; i < PCMK__NELEM(attr_list); i++) {
122 const char *value = crm_element_value(rsc->priv->xml, attr_list[i]);
123 const char *old_value = crm_element_value(rsc_entry, attr_list[i]);
124
125 if (!pcmk__str_eq(value, old_value, pcmk__str_none)) {
126 changed = true;
127 trigger_unfencing(rsc, node, "Device definition changed", NULL,
128 rsc->priv->scheduler);
129 if (active_on_node) {
130 crm_notice("Forcing restart of %s on %s "
131 "because %s changed from '%s' to '%s'",
132 rsc->id, pcmk__node_name(node), attr_list[i],
133 pcmk__s(old_value, ""), pcmk__s(value, ""));
134 }
135 }
136 }
137 if (changed && active_on_node) {
138
139 custom_action(rsc, stop_key(rsc), PCMK_ACTION_STOP, node, FALSE,
140 rsc->priv->scheduler);
141 pcmk__set_rsc_flags(rsc, pcmk__rsc_start_pending);
142 }
143 return changed;
144 }
145
146
147
148
149
150
151
152
153
154
155
156 static GList *
157 add_rsc_if_matching(GList *result, pcmk_resource_t *rsc, const char *id)
158 {
159 if (pcmk__str_eq(id, rsc->id, pcmk__str_none)
160 || pcmk__str_eq(id, rsc->priv->history_id, pcmk__str_none)) {
161 result = g_list_prepend(result, rsc);
162 }
163
164 for (GList *iter = rsc->priv->children;
165 iter != NULL; iter = iter->next) {
166
167 pcmk_resource_t *child = (pcmk_resource_t *) iter->data;
168
169 result = add_rsc_if_matching(result, child, id);
170 }
171 return result;
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185 GList *
186 pcmk__rscs_matching_id(const char *id, const pcmk_scheduler_t *scheduler)
187 {
188 GList *result = NULL;
189
190 CRM_CHECK((id != NULL) && (scheduler != NULL), return NULL);
191
192 for (GList *iter = scheduler->priv->resources;
193 iter != NULL; iter = iter->next) {
194
195 result = add_rsc_if_matching(result, (pcmk_resource_t *) iter->data,
196 id);
197 }
198 return result;
199 }
200
201
202
203
204
205
206
207
208 static void
209 set_assignment_methods_for_rsc(gpointer data, gpointer user_data)
210 {
211 pcmk_resource_t *rsc = data;
212
213 rsc->priv->cmds = &assignment_methods[rsc->priv->variant];
214 g_list_foreach(rsc->priv->children, set_assignment_methods_for_rsc,
215 NULL);
216 }
217
218
219
220
221
222
223
224 void
225 pcmk__set_assignment_methods(pcmk_scheduler_t *scheduler)
226 {
227 g_list_foreach(scheduler->priv->resources, set_assignment_methods_for_rsc,
228 NULL);
229 }
230
231
232
233
234
235
236
237
238
239
240
241 static inline void
242 add_colocated_resources(const pcmk_resource_t *rsc,
243 const pcmk_resource_t *orig_rsc, GList **list)
244 {
245 *list = rsc->priv->cmds->colocated_resources(rsc, orig_rsc, *list);
246 }
247
248
249 GList *
250 pcmk__colocated_resources(const pcmk_resource_t *rsc,
251 const pcmk_resource_t *orig_rsc,
252 GList *colocated_rscs)
253 {
254 const GList *iter = NULL;
255 GList *colocations = NULL;
256
257 if (orig_rsc == NULL) {
258 orig_rsc = rsc;
259 }
260
261 if ((rsc == NULL) || (g_list_find(colocated_rscs, rsc) != NULL)) {
262 return colocated_rscs;
263 }
264
265 pcmk__rsc_trace(orig_rsc, "%s is in colocation chain with %s",
266 rsc->id, orig_rsc->id);
267 colocated_rscs = g_list_prepend(colocated_rscs, (gpointer) rsc);
268
269
270 colocations = pcmk__this_with_colocations(rsc);
271 for (iter = colocations; iter != NULL; iter = iter->next) {
272 const pcmk__colocation_t *constraint = iter->data;
273 const pcmk_resource_t *primary = constraint->primary;
274
275 if (primary == orig_rsc) {
276 continue;
277 }
278
279 if ((constraint->score == PCMK_SCORE_INFINITY) &&
280 (pcmk__colocation_affects(rsc, primary, constraint,
281 true) == pcmk__coloc_affects_location)) {
282 add_colocated_resources(primary, orig_rsc, &colocated_rscs);
283 }
284 }
285 g_list_free(colocations);
286
287
288 colocations = pcmk__with_this_colocations(rsc);
289 for (iter = colocations; iter != NULL; iter = iter->next) {
290 const pcmk__colocation_t *constraint = iter->data;
291 const pcmk_resource_t *dependent = constraint->dependent;
292
293 if (dependent == orig_rsc) {
294 continue;
295 }
296
297 if (pcmk__is_clone(rsc) && !pcmk__is_clone(dependent)) {
298 continue;
299 }
300
301 if ((constraint->score == PCMK_SCORE_INFINITY) &&
302 (pcmk__colocation_affects(dependent, rsc, constraint,
303 true) == pcmk__coloc_affects_location)) {
304 add_colocated_resources(dependent, orig_rsc, &colocated_rscs);
305 }
306 }
307 g_list_free(colocations);
308
309 return colocated_rscs;
310 }
311
312
313 void
314 pcmk__noop_add_graph_meta(const pcmk_resource_t *rsc, xmlNode *xml)
315 {
316 }
317
318
319
320
321
322
323
324 void
325 pcmk__output_resource_actions(pcmk_resource_t *rsc)
326 {
327 pcmk_node_t *next = NULL;
328 pcmk_node_t *current = NULL;
329 pcmk__output_t *out = NULL;
330
331 pcmk__assert(rsc != NULL);
332
333 out = rsc->priv->scheduler->priv->out;
334 if (rsc->priv->children != NULL) {
335
336 for (GList *iter = rsc->priv->children;
337 iter != NULL; iter = iter->next) {
338
339 pcmk_resource_t *child = (pcmk_resource_t *) iter->data;
340
341 child->priv->cmds->output_actions(child);
342 }
343 return;
344 }
345
346 next = rsc->priv->assigned_node;
347 if (rsc->priv->active_nodes != NULL) {
348 current = pcmk__current_node(rsc);
349 if (rsc->priv->orig_role == pcmk_role_stopped) {
350
351
352
353 rsc->priv->orig_role = pcmk_role_started;
354 }
355 }
356
357 if ((current == NULL) && pcmk_is_set(rsc->flags, pcmk__rsc_removed)) {
358
359 return;
360 }
361
362 out->message(out, "rsc-action", rsc, current, next);
363 }
364
365
366
367
368
369
370
371
372 static inline void
373 add_assigned_resource(pcmk_node_t *node, pcmk_resource_t *rsc)
374 {
375 node->priv->assigned_resources =
376 g_list_prepend(node->priv->assigned_resources, rsc);
377 }
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414 bool
415 pcmk__assign_resource(pcmk_resource_t *rsc, pcmk_node_t *node, bool force,
416 bool stop_if_fail)
417 {
418 bool changed = false;
419 pcmk_scheduler_t *scheduler = NULL;
420
421 pcmk__assert(rsc != NULL);
422 scheduler = rsc->priv->scheduler;
423
424 if (rsc->priv->children != NULL) {
425
426 for (GList *iter = rsc->priv->children;
427 iter != NULL; iter = iter->next) {
428
429 pcmk_resource_t *child_rsc = iter->data;
430
431 changed |= pcmk__assign_resource(child_rsc, node, force,
432 stop_if_fail);
433 }
434 return changed;
435 }
436
437
438
439 if (!force && (node != NULL)
440 && ((node->assign->score < 0)
441
442 || (!pcmk__node_available(node, true, false)
443 && !pcmk__is_guest_or_bundle_node(node)))) {
444
445 pcmk__rsc_debug(rsc,
446 "All nodes for resource %s are unavailable, unclean or "
447 "shutting down (%s can%s run resources, with score %s)",
448 rsc->id, pcmk__node_name(node),
449 (pcmk__node_available(node, true, false)? "" : "not"),
450 pcmk_readable_score(node->assign->score));
451
452 if (stop_if_fail) {
453 pe__set_next_role(rsc, pcmk_role_stopped, "node availability");
454 }
455 node = NULL;
456 }
457
458 if (rsc->priv->assigned_node != NULL) {
459 changed = !pcmk__same_node(rsc->priv->assigned_node, node);
460 } else {
461 changed = (node != NULL);
462 }
463 pcmk__unassign_resource(rsc);
464 pcmk__clear_rsc_flags(rsc, pcmk__rsc_unassigned);
465
466 if (node == NULL) {
467 char *rc_stopped = NULL;
468
469 pcmk__rsc_debug(rsc, "Could not assign %s to a node", rsc->id);
470
471 if (!stop_if_fail) {
472 return changed;
473 }
474 pe__set_next_role(rsc, pcmk_role_stopped, "unable to assign");
475
476 for (GList *iter = rsc->priv->actions;
477 iter != NULL; iter = iter->next) {
478
479 pcmk_action_t *op = (pcmk_action_t *) iter->data;
480
481 pcmk__rsc_debug(rsc, "Updating %s for %s assignment failure",
482 op->uuid, rsc->id);
483
484 if (pcmk__str_eq(op->task, PCMK_ACTION_STOP, pcmk__str_none)) {
485 pcmk__clear_action_flags(op, pcmk__action_optional);
486
487 } else if (pcmk__str_eq(op->task, PCMK_ACTION_START,
488 pcmk__str_none)) {
489 pcmk__clear_action_flags(op, pcmk__action_runnable);
490
491 } else {
492
493 const char *interval_ms_s = NULL;
494 const char *target_rc_s = NULL;
495
496 interval_ms_s = g_hash_table_lookup(op->meta,
497 PCMK_META_INTERVAL);
498 target_rc_s = g_hash_table_lookup(op->meta,
499 PCMK__META_OP_TARGET_RC);
500 if (rc_stopped == NULL) {
501 rc_stopped = pcmk__itoa(PCMK_OCF_NOT_RUNNING);
502 }
503
504 if (!pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches)
505 && !pcmk__str_eq(rc_stopped, target_rc_s, pcmk__str_none)) {
506
507 pcmk__clear_action_flags(op, pcmk__action_runnable);
508 }
509 }
510 }
511 free(rc_stopped);
512 return changed;
513 }
514
515 pcmk__rsc_debug(rsc, "Assigning %s to %s", rsc->id, pcmk__node_name(node));
516 rsc->priv->assigned_node = pe__copy_node(node);
517
518 add_assigned_resource(node, rsc);
519 node->priv->num_resources++;
520 node->assign->count++;
521 pcmk__consume_node_capacity(node->priv->utilization, rsc);
522
523 if (pcmk_is_set(scheduler->flags, pcmk__sched_show_utilization)) {
524 pcmk__output_t *out = scheduler->priv->out;
525
526 out->message(out, "resource-util", rsc, node, __func__);
527 }
528 return changed;
529 }
530
531
532
533
534
535
536
537
538
539
540
541
542 void
543 pcmk__unassign_resource(pcmk_resource_t *rsc)
544 {
545 pcmk_node_t *old = rsc->priv->assigned_node;
546
547 if (old == NULL) {
548 crm_info("Unassigning %s", rsc->id);
549 } else {
550 crm_info("Unassigning %s from %s", rsc->id, pcmk__node_name(old));
551 }
552
553 pcmk__set_rsc_flags(rsc, pcmk__rsc_unassigned);
554
555 if (rsc->priv->children == NULL) {
556 if (old == NULL) {
557 return;
558 }
559 rsc->priv->assigned_node = NULL;
560
561
562
563
564 old->priv->assigned_resources =
565 g_list_remove(old->priv->assigned_resources, rsc);
566 old->priv->num_resources--;
567 pcmk__release_node_capacity(old->priv->utilization, rsc);
568 pcmk__free_node_copy(old);
569 return;
570 }
571
572 for (GList *iter = rsc->priv->children;
573 iter != NULL; iter = iter->next) {
574
575 pcmk__unassign_resource((pcmk_resource_t *) iter->data);
576 }
577 }
578
579
580
581
582
583
584
585
586
587
588
589
590 bool
591 pcmk__threshold_reached(pcmk_resource_t *rsc, const pcmk_node_t *node,
592 pcmk_resource_t **failed)
593 {
594 int fail_count, remaining_tries;
595 pcmk_resource_t *rsc_to_ban = rsc;
596
597
598 if (rsc->priv->ban_after_failures == 0) {
599 return false;
600 }
601
602
603 if (pcmk_is_set(rsc->flags, pcmk__rsc_ignore_failure)) {
604 return false;
605 }
606
607
608 fail_count = pe_get_failcount(node, rsc, NULL,
609 pcmk__fc_effective|pcmk__fc_launched, NULL);
610 if (fail_count <= 0) {
611 return false;
612 }
613
614
615 if (!pcmk_is_set(rsc->flags, pcmk__rsc_unique)) {
616 rsc_to_ban = uber_parent(rsc);
617 }
618
619
620 remaining_tries = rsc->priv->ban_after_failures - fail_count;
621
622 if (remaining_tries <= 0) {
623 pcmk__sched_warn(rsc->priv->scheduler,
624 "%s cannot run on %s due to reaching migration "
625 "threshold (clean up resource to allow again) "
626 QB_XS " failures=%d "
627 PCMK_META_MIGRATION_THRESHOLD "=%d",
628 rsc_to_ban->id, pcmk__node_name(node), fail_count,
629 rsc->priv->ban_after_failures);
630 if (failed != NULL) {
631 *failed = rsc_to_ban;
632 }
633 return true;
634 }
635
636 crm_info("%s can fail %d more time%s on "
637 "%s before reaching migration threshold (%d)",
638 rsc_to_ban->id, remaining_tries, pcmk__plural_s(remaining_tries),
639 pcmk__node_name(node), rsc->priv->ban_after_failures);
640 return false;
641 }
642
643
644
645
646
647
648
649
650
651
652 static int
653 get_node_score(const pcmk_node_t *node, GHashTable *nodes)
654 {
655 pcmk_node_t *found_node = NULL;
656
657 if ((node != NULL) && (nodes != NULL)) {
658 found_node = g_hash_table_lookup(nodes, node->priv->id);
659 }
660 if (found_node == NULL) {
661 return -PCMK_SCORE_INFINITY;
662 }
663 return found_node->assign->score;
664 }
665
666
667
668
669
670
671
672
673
674
675
676
677 static gint
678 cmp_resources(gconstpointer a, gconstpointer b, gpointer data)
679 {
680
681
682
683
684 pcmk_resource_t *resource1 = (pcmk_resource_t *) a;
685 pcmk_resource_t *resource2 = (pcmk_resource_t *) b;
686 const GList *nodes = data;
687
688 int rc = 0;
689 int r1_score = -PCMK_SCORE_INFINITY;
690 int r2_score = -PCMK_SCORE_INFINITY;
691 pcmk_node_t *r1_node = NULL;
692 pcmk_node_t *r2_node = NULL;
693 GHashTable *r1_nodes = NULL;
694 GHashTable *r2_nodes = NULL;
695 const char *reason = NULL;
696
697
698 reason = "priority";
699 r1_score = resource1->priv->priority;
700 r2_score = resource2->priv->priority;
701 if (r1_score > r2_score) {
702 rc = -1;
703 goto done;
704 }
705 if (r1_score < r2_score) {
706 rc = 1;
707 goto done;
708 }
709
710
711 reason = "no node list";
712 if (nodes == NULL) {
713 goto done;
714 }
715
716
717 resource1->priv->cmds->add_colocated_node_scores(resource1, NULL,
718 resource1->id,
719 &r1_nodes, NULL, 1,
720 pcmk__coloc_select_this_with);
721 resource2->priv->cmds->add_colocated_node_scores(resource2, NULL,
722 resource2->id,
723 &r2_nodes, NULL, 1,
724 pcmk__coloc_select_this_with);
725 pe__show_node_scores(true, NULL, resource1->id, r1_nodes,
726 resource1->priv->scheduler);
727 pe__show_node_scores(true, NULL, resource2->id, r2_nodes,
728 resource2->priv->scheduler);
729
730
731 reason = "current location";
732 if (resource1->priv->active_nodes != NULL) {
733 r1_node = pcmk__current_node(resource1);
734 }
735 if (resource2->priv->active_nodes != NULL) {
736 r2_node = pcmk__current_node(resource2);
737 }
738 r1_score = get_node_score(r1_node, r1_nodes);
739 r2_score = get_node_score(r2_node, r2_nodes);
740 if (r1_score > r2_score) {
741 rc = -1;
742 goto done;
743 }
744 if (r1_score < r2_score) {
745 rc = 1;
746 goto done;
747 }
748
749
750 reason = "score";
751 for (const GList *iter = nodes; iter != NULL; iter = iter->next) {
752 const pcmk_node_t *node = (const pcmk_node_t *) iter->data;
753
754 r1_score = get_node_score(node, r1_nodes);
755 r2_score = get_node_score(node, r2_nodes);
756 if (r1_score > r2_score) {
757 rc = -1;
758 goto done;
759 }
760 if (r1_score < r2_score) {
761 rc = 1;
762 goto done;
763 }
764 }
765
766 done:
767 crm_trace("%s (%d)%s%s %c %s (%d)%s%s: %s",
768 resource1->id, r1_score,
769 ((r1_node == NULL)? "" : " on "),
770 ((r1_node == NULL)? "" : r1_node->priv->id),
771 ((rc < 0)? '>' : ((rc > 0)? '<' : '=')),
772 resource2->id, r2_score,
773 ((r2_node == NULL)? "" : " on "),
774 ((r2_node == NULL)? "" : r2_node->priv->id),
775 reason);
776 if (r1_nodes != NULL) {
777 g_hash_table_destroy(r1_nodes);
778 }
779 if (r2_nodes != NULL) {
780 g_hash_table_destroy(r2_nodes);
781 }
782 return rc;
783 }
784
785
786
787
788
789
790
791 void
792 pcmk__sort_resources(pcmk_scheduler_t *scheduler)
793 {
794 GList *nodes = g_list_copy(scheduler->nodes);
795
796 nodes = pcmk__sort_nodes(nodes, NULL);
797 scheduler->priv->resources =
798 g_list_sort_with_data(scheduler->priv->resources, cmp_resources, nodes);
799 g_list_free(nodes);
800 }