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->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->cluster);
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->cluster);
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 ((strcmp(rsc->id, id) == 0)
160 || ((rsc->clone_name != NULL) && (strcmp(rsc->clone_name, id) == 0))) {
161 result = g_list_prepend(result, rsc);
162 }
163 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
164 pcmk_resource_t *child = (pcmk_resource_t *) iter->data;
165
166 result = add_rsc_if_matching(result, child, id);
167 }
168 return result;
169 }
170
171
172
173
174
175
176
177
178
179
180
181
182 GList *
183 pcmk__rscs_matching_id(const char *id, const pcmk_scheduler_t *scheduler)
184 {
185 GList *result = NULL;
186
187 CRM_CHECK((id != NULL) && (scheduler != NULL), return NULL);
188 for (GList *iter = scheduler->resources; iter != NULL; iter = iter->next) {
189 result = add_rsc_if_matching(result, (pcmk_resource_t *) iter->data,
190 id);
191 }
192 return result;
193 }
194
195
196
197
198
199
200
201
202 static void
203 set_assignment_methods_for_rsc(gpointer data, gpointer user_data)
204 {
205 pcmk_resource_t *rsc = data;
206
207 rsc->cmds = &assignment_methods[rsc->variant];
208 g_list_foreach(rsc->children, set_assignment_methods_for_rsc, NULL);
209 }
210
211
212
213
214
215
216
217 void
218 pcmk__set_assignment_methods(pcmk_scheduler_t *scheduler)
219 {
220 g_list_foreach(scheduler->resources, set_assignment_methods_for_rsc, NULL);
221 }
222
223
224
225
226
227
228
229
230
231
232
233 static inline void
234 add_colocated_resources(const pcmk_resource_t *rsc,
235 const pcmk_resource_t *orig_rsc, GList **list)
236 {
237 *list = rsc->cmds->colocated_resources(rsc, orig_rsc, *list);
238 }
239
240
241 GList *
242 pcmk__colocated_resources(const pcmk_resource_t *rsc,
243 const pcmk_resource_t *orig_rsc,
244 GList *colocated_rscs)
245 {
246 const GList *iter = NULL;
247 GList *colocations = NULL;
248
249 if (orig_rsc == NULL) {
250 orig_rsc = rsc;
251 }
252
253 if ((rsc == NULL) || (g_list_find(colocated_rscs, rsc) != NULL)) {
254 return colocated_rscs;
255 }
256
257 pcmk__rsc_trace(orig_rsc, "%s is in colocation chain with %s",
258 rsc->id, orig_rsc->id);
259 colocated_rscs = g_list_prepend(colocated_rscs, (gpointer) rsc);
260
261
262 colocations = pcmk__this_with_colocations(rsc);
263 for (iter = colocations; iter != NULL; iter = iter->next) {
264 const pcmk__colocation_t *constraint = iter->data;
265 const pcmk_resource_t *primary = constraint->primary;
266
267 if (primary == orig_rsc) {
268 continue;
269 }
270
271 if ((constraint->score == PCMK_SCORE_INFINITY) &&
272 (pcmk__colocation_affects(rsc, primary, constraint,
273 true) == pcmk__coloc_affects_location)) {
274 add_colocated_resources(primary, orig_rsc, &colocated_rscs);
275 }
276 }
277 g_list_free(colocations);
278
279
280 colocations = pcmk__with_this_colocations(rsc);
281 for (iter = colocations; iter != NULL; iter = iter->next) {
282 const pcmk__colocation_t *constraint = iter->data;
283 const pcmk_resource_t *dependent = constraint->dependent;
284
285 if (dependent == orig_rsc) {
286 continue;
287 }
288
289 if (pcmk__is_clone(rsc) && !pcmk__is_clone(dependent)) {
290 continue;
291 }
292
293 if ((constraint->score == PCMK_SCORE_INFINITY) &&
294 (pcmk__colocation_affects(dependent, rsc, constraint,
295 true) == pcmk__coloc_affects_location)) {
296 add_colocated_resources(dependent, orig_rsc, &colocated_rscs);
297 }
298 }
299 g_list_free(colocations);
300
301 return colocated_rscs;
302 }
303
304
305 void
306 pcmk__noop_add_graph_meta(const pcmk_resource_t *rsc, xmlNode *xml)
307 {
308 }
309
310
311
312
313
314
315
316 void
317 pcmk__output_resource_actions(pcmk_resource_t *rsc)
318 {
319 pcmk_node_t *next = NULL;
320 pcmk_node_t *current = NULL;
321 pcmk__output_t *out = NULL;
322
323 pcmk__assert(rsc != NULL);
324
325 out = rsc->cluster->priv;
326 if (rsc->children != NULL) {
327 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
328 pcmk_resource_t *child = (pcmk_resource_t *) iter->data;
329
330 child->cmds->output_actions(child);
331 }
332 return;
333 }
334
335 next = rsc->allocated_to;
336 if (rsc->running_on) {
337 current = pcmk__current_node(rsc);
338 if (rsc->role == pcmk_role_stopped) {
339
340
341
342 rsc->role = pcmk_role_started;
343 }
344 }
345
346 if ((current == NULL) && pcmk_is_set(rsc->flags, pcmk_rsc_removed)) {
347
348 return;
349 }
350
351 out->message(out, "rsc-action", rsc, current, next);
352 }
353
354
355
356
357
358
359
360
361 static inline void
362 add_assigned_resource(pcmk_node_t *node, pcmk_resource_t *rsc)
363 {
364 node->details->allocated_rsc = g_list_prepend(node->details->allocated_rsc,
365 rsc);
366 }
367
368
369
370
371
372
373
374
375
376
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 bool
404 pcmk__assign_resource(pcmk_resource_t *rsc, pcmk_node_t *node, bool force,
405 bool stop_if_fail)
406 {
407 bool changed = false;
408
409 pcmk__assert(rsc != NULL);
410
411 if (rsc->children != NULL) {
412 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
413 pcmk_resource_t *child_rsc = iter->data;
414
415 changed |= pcmk__assign_resource(child_rsc, node, force,
416 stop_if_fail);
417 }
418 return changed;
419 }
420
421
422
423 if (!force && (node != NULL)
424 && ((node->weight < 0)
425
426 || (!pcmk__node_available(node, true, false)
427 && !pcmk__is_guest_or_bundle_node(node)))) {
428
429 pcmk__rsc_debug(rsc,
430 "All nodes for resource %s are unavailable, unclean or "
431 "shutting down (%s can%s run resources, with score %s)",
432 rsc->id, pcmk__node_name(node),
433 (pcmk__node_available(node, true, false)? "" : "not"),
434 pcmk_readable_score(node->weight));
435
436 if (stop_if_fail) {
437 pe__set_next_role(rsc, pcmk_role_stopped, "node availability");
438 }
439 node = NULL;
440 }
441
442 if (rsc->allocated_to != NULL) {
443 changed = !pcmk__same_node(rsc->allocated_to, node);
444 } else {
445 changed = (node != NULL);
446 }
447 pcmk__unassign_resource(rsc);
448 pcmk__clear_rsc_flags(rsc, pcmk_rsc_unassigned);
449
450 if (node == NULL) {
451 char *rc_stopped = NULL;
452
453 pcmk__rsc_debug(rsc, "Could not assign %s to a node", rsc->id);
454
455 if (!stop_if_fail) {
456 return changed;
457 }
458 pe__set_next_role(rsc, pcmk_role_stopped, "unable to assign");
459
460 for (GList *iter = rsc->actions; iter != NULL; iter = iter->next) {
461 pcmk_action_t *op = (pcmk_action_t *) iter->data;
462
463 pcmk__rsc_debug(rsc, "Updating %s for %s assignment failure",
464 op->uuid, rsc->id);
465
466 if (pcmk__str_eq(op->task, PCMK_ACTION_STOP, pcmk__str_none)) {
467 pcmk__clear_action_flags(op, pcmk_action_optional);
468
469 } else if (pcmk__str_eq(op->task, PCMK_ACTION_START,
470 pcmk__str_none)) {
471 pcmk__clear_action_flags(op, pcmk_action_runnable);
472
473 } else {
474
475 const char *interval_ms_s = NULL;
476 const char *target_rc_s = NULL;
477
478 interval_ms_s = g_hash_table_lookup(op->meta,
479 PCMK_META_INTERVAL);
480 target_rc_s = g_hash_table_lookup(op->meta,
481 PCMK__META_OP_TARGET_RC);
482 if (rc_stopped == NULL) {
483 rc_stopped = pcmk__itoa(PCMK_OCF_NOT_RUNNING);
484 }
485
486 if (!pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches)
487 && !pcmk__str_eq(rc_stopped, target_rc_s, pcmk__str_none)) {
488
489 pcmk__clear_action_flags(op, pcmk_action_runnable);
490 }
491 }
492 }
493 free(rc_stopped);
494 return changed;
495 }
496
497 pcmk__rsc_debug(rsc, "Assigning %s to %s", rsc->id, pcmk__node_name(node));
498 rsc->allocated_to = pe__copy_node(node);
499
500 add_assigned_resource(node, rsc);
501 node->details->num_resources++;
502 node->count++;
503 pcmk__consume_node_capacity(node->details->utilization, rsc);
504
505 if (pcmk_is_set(rsc->cluster->flags, pcmk_sched_show_utilization)) {
506 pcmk__output_t *out = rsc->cluster->priv;
507
508 out->message(out, "resource-util", rsc, node, __func__);
509 }
510 return changed;
511 }
512
513
514
515
516
517
518
519
520
521
522
523
524 void
525 pcmk__unassign_resource(pcmk_resource_t *rsc)
526 {
527 pcmk_node_t *old = rsc->allocated_to;
528
529 if (old == NULL) {
530 crm_info("Unassigning %s", rsc->id);
531 } else {
532 crm_info("Unassigning %s from %s", rsc->id, pcmk__node_name(old));
533 }
534
535 pcmk__set_rsc_flags(rsc, pcmk_rsc_unassigned);
536
537 if (rsc->children == NULL) {
538 if (old == NULL) {
539 return;
540 }
541 rsc->allocated_to = NULL;
542
543
544
545
546 old->details->allocated_rsc = g_list_remove(old->details->allocated_rsc,
547 rsc);
548 old->details->num_resources--;
549 pcmk__release_node_capacity(old->details->utilization, rsc);
550 free(old);
551 return;
552 }
553
554 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
555 pcmk__unassign_resource((pcmk_resource_t *) iter->data);
556 }
557 }
558
559
560
561
562
563
564
565
566
567
568
569
570 bool
571 pcmk__threshold_reached(pcmk_resource_t *rsc, const pcmk_node_t *node,
572 pcmk_resource_t **failed)
573 {
574 int fail_count, remaining_tries;
575 pcmk_resource_t *rsc_to_ban = rsc;
576
577
578 if (rsc->migration_threshold == 0) {
579 return false;
580 }
581
582
583 if (pcmk_is_set(rsc->flags, pcmk_rsc_ignore_failure)) {
584 return false;
585 }
586
587
588 fail_count = pe_get_failcount(node, rsc, NULL,
589 pcmk__fc_effective|pcmk__fc_fillers, NULL);
590 if (fail_count <= 0) {
591 return false;
592 }
593
594
595 if (!pcmk_is_set(rsc->flags, pcmk_rsc_unique)) {
596 rsc_to_ban = uber_parent(rsc);
597 }
598
599
600 remaining_tries = rsc->migration_threshold - fail_count;
601
602 if (remaining_tries <= 0) {
603 pcmk__sched_warn("%s cannot run on %s due to reaching migration "
604 "threshold (clean up resource to allow again) "
605 CRM_XS " failures=%d "
606 PCMK_META_MIGRATION_THRESHOLD "=%d",
607 rsc_to_ban->id, pcmk__node_name(node), fail_count,
608 rsc->migration_threshold);
609 if (failed != NULL) {
610 *failed = rsc_to_ban;
611 }
612 return true;
613 }
614
615 crm_info("%s can fail %d more time%s on "
616 "%s before reaching migration threshold (%d)",
617 rsc_to_ban->id, remaining_tries, pcmk__plural_s(remaining_tries),
618 pcmk__node_name(node), rsc->migration_threshold);
619 return false;
620 }
621
622
623
624
625
626
627
628
629
630
631 static int
632 get_node_score(const pcmk_node_t *node, GHashTable *nodes)
633 {
634 pcmk_node_t *found_node = NULL;
635
636 if ((node != NULL) && (nodes != NULL)) {
637 found_node = g_hash_table_lookup(nodes, node->details->id);
638 }
639 return (found_node == NULL)? -PCMK_SCORE_INFINITY : found_node->weight;
640 }
641
642
643
644
645
646
647
648
649
650
651
652
653 static gint
654 cmp_resources(gconstpointer a, gconstpointer b, gpointer data)
655 {
656
657
658
659
660 pcmk_resource_t *resource1 = (pcmk_resource_t *) a;
661 pcmk_resource_t *resource2 = (pcmk_resource_t *) b;
662 const GList *nodes = data;
663
664 int rc = 0;
665 int r1_score = -PCMK_SCORE_INFINITY;
666 int r2_score = -PCMK_SCORE_INFINITY;
667 pcmk_node_t *r1_node = NULL;
668 pcmk_node_t *r2_node = NULL;
669 GHashTable *r1_nodes = NULL;
670 GHashTable *r2_nodes = NULL;
671 const char *reason = NULL;
672
673
674 reason = "priority";
675 r1_score = resource1->priority;
676 r2_score = resource2->priority;
677 if (r1_score > r2_score) {
678 rc = -1;
679 goto done;
680 }
681 if (r1_score < r2_score) {
682 rc = 1;
683 goto done;
684 }
685
686
687 reason = "no node list";
688 if (nodes == NULL) {
689 goto done;
690 }
691
692
693 resource1->cmds->add_colocated_node_scores(resource1, NULL, resource1->id,
694 &r1_nodes, NULL, 1,
695 pcmk__coloc_select_this_with);
696 resource2->cmds->add_colocated_node_scores(resource2, NULL, resource2->id,
697 &r2_nodes, NULL, 1,
698 pcmk__coloc_select_this_with);
699 pe__show_node_scores(true, NULL, resource1->id, r1_nodes,
700 resource1->cluster);
701 pe__show_node_scores(true, NULL, resource2->id, r2_nodes,
702 resource2->cluster);
703
704
705 reason = "current location";
706 if (resource1->running_on != NULL) {
707 r1_node = pcmk__current_node(resource1);
708 }
709 if (resource2->running_on != NULL) {
710 r2_node = pcmk__current_node(resource2);
711 }
712 r1_score = get_node_score(r1_node, r1_nodes);
713 r2_score = get_node_score(r2_node, r2_nodes);
714 if (r1_score > r2_score) {
715 rc = -1;
716 goto done;
717 }
718 if (r1_score < r2_score) {
719 rc = 1;
720 goto done;
721 }
722
723
724 reason = "score";
725 for (const GList *iter = nodes; iter != NULL; iter = iter->next) {
726 const pcmk_node_t *node = (const pcmk_node_t *) iter->data;
727
728 r1_score = get_node_score(node, r1_nodes);
729 r2_score = get_node_score(node, r2_nodes);
730 if (r1_score > r2_score) {
731 rc = -1;
732 goto done;
733 }
734 if (r1_score < r2_score) {
735 rc = 1;
736 goto done;
737 }
738 }
739
740 done:
741 crm_trace("%s (%d)%s%s %c %s (%d)%s%s: %s",
742 resource1->id, r1_score,
743 ((r1_node == NULL)? "" : " on "),
744 ((r1_node == NULL)? "" : r1_node->details->id),
745 ((rc < 0)? '>' : ((rc > 0)? '<' : '=')),
746 resource2->id, r2_score,
747 ((r2_node == NULL)? "" : " on "),
748 ((r2_node == NULL)? "" : r2_node->details->id),
749 reason);
750 if (r1_nodes != NULL) {
751 g_hash_table_destroy(r1_nodes);
752 }
753 if (r2_nodes != NULL) {
754 g_hash_table_destroy(r2_nodes);
755 }
756 return rc;
757 }
758
759
760
761
762
763
764
765 void
766 pcmk__sort_resources(pcmk_scheduler_t *scheduler)
767 {
768 GList *nodes = g_list_copy(scheduler->nodes);
769
770 nodes = pcmk__sort_nodes(nodes, NULL);
771 scheduler->resources = g_list_sort_with_data(scheduler->resources,
772 cmp_resources, nodes);
773 g_list_free(nodes);
774 }