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/msg_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 XML_ATTR_TYPE,
117 XML_AGENT_ATTR_CLASS,
118 XML_AGENT_ATTR_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, pe__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 pe__set_resource_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 pe_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 == 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 (pe_rsc_is_clone(rsc) && !pe_rsc_is_clone(dependent)) {
290 continue;
291 }
292
293 if ((constraint->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 CRM_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 = pe__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 CRM_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 && !pe__is_guest_node(node)))) {
428
429 pe_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, pe__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 = !pe__same_node(rsc->allocated_to, node);
444 } else {
445 changed = (node != NULL);
446 }
447 pcmk__unassign_resource(rsc);
448 pe__clear_resource_flags(rsc, pcmk_rsc_unassigned);
449
450 if (node == NULL) {
451 char *rc_stopped = NULL;
452
453 pe_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 pe_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 pe__clear_action_flags(op, pcmk_action_optional);
468
469 } else if (pcmk__str_eq(op->task, PCMK_ACTION_START,
470 pcmk__str_none)) {
471 pe__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 XML_LRM_ATTR_INTERVAL_MS);
480 target_rc_s = g_hash_table_lookup(op->meta,
481 XML_ATTR_TE_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 pe__clear_action_flags(op, pcmk_action_runnable);
490 }
491 }
492 }
493 free(rc_stopped);
494 return changed;
495 }
496
497 pe_rsc_debug(rsc, "Assigning %s to %s", rsc->id, pe__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, pe__node_name(old));
533 }
534
535 pe__set_resource_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 crm_warn("%s cannot run on %s due to reaching migration threshold "
604 "(clean up resource to allow again)"
605 CRM_XS " failures=%d migration-threshold=%d",
606 rsc_to_ban->id, pe__node_name(node), fail_count,
607 rsc->migration_threshold);
608 if (failed != NULL) {
609 *failed = rsc_to_ban;
610 }
611 return true;
612 }
613
614 crm_info("%s can fail %d more time%s on "
615 "%s before reaching migration threshold (%d)",
616 rsc_to_ban->id, remaining_tries, pcmk__plural_s(remaining_tries),
617 pe__node_name(node), rsc->migration_threshold);
618 return false;
619 }
620
621
622
623
624
625
626
627
628
629
630 static int
631 get_node_score(const pcmk_node_t *node, GHashTable *nodes)
632 {
633 pcmk_node_t *found_node = NULL;
634
635 if ((node != NULL) && (nodes != NULL)) {
636 found_node = g_hash_table_lookup(nodes, node->details->id);
637 }
638 return (found_node == NULL)? -INFINITY : found_node->weight;
639 }
640
641
642
643
644
645
646
647
648
649
650
651
652 static gint
653 cmp_resources(gconstpointer a, gconstpointer b, gpointer data)
654 {
655
656
657
658
659 pcmk_resource_t *resource1 = (pcmk_resource_t *) a;
660 pcmk_resource_t *resource2 = (pcmk_resource_t *) b;
661 const GList *nodes = data;
662
663 int rc = 0;
664 int r1_score = -INFINITY;
665 int r2_score = -INFINITY;
666 pcmk_node_t *r1_node = NULL;
667 pcmk_node_t *r2_node = NULL;
668 GHashTable *r1_nodes = NULL;
669 GHashTable *r2_nodes = NULL;
670 const char *reason = NULL;
671
672
673 reason = "priority";
674 r1_score = resource1->priority;
675 r2_score = resource2->priority;
676 if (r1_score > r2_score) {
677 rc = -1;
678 goto done;
679 }
680 if (r1_score < r2_score) {
681 rc = 1;
682 goto done;
683 }
684
685
686 reason = "no node list";
687 if (nodes == NULL) {
688 goto done;
689 }
690
691
692 resource1->cmds->add_colocated_node_scores(resource1, NULL, resource1->id,
693 &r1_nodes, NULL, 1,
694 pcmk__coloc_select_this_with);
695 resource2->cmds->add_colocated_node_scores(resource2, NULL, resource2->id,
696 &r2_nodes, NULL, 1,
697 pcmk__coloc_select_this_with);
698 pe__show_node_scores(true, NULL, resource1->id, r1_nodes,
699 resource1->cluster);
700 pe__show_node_scores(true, NULL, resource2->id, r2_nodes,
701 resource2->cluster);
702
703
704 reason = "current location";
705 if (resource1->running_on != NULL) {
706 r1_node = pe__current_node(resource1);
707 }
708 if (resource2->running_on != NULL) {
709 r2_node = pe__current_node(resource2);
710 }
711 r1_score = get_node_score(r1_node, r1_nodes);
712 r2_score = get_node_score(r2_node, r2_nodes);
713 if (r1_score > r2_score) {
714 rc = -1;
715 goto done;
716 }
717 if (r1_score < r2_score) {
718 rc = 1;
719 goto done;
720 }
721
722
723 reason = "score";
724 for (const GList *iter = nodes; iter != NULL; iter = iter->next) {
725 const pcmk_node_t *node = (const pcmk_node_t *) iter->data;
726
727 r1_score = get_node_score(node, r1_nodes);
728 r2_score = get_node_score(node, r2_nodes);
729 if (r1_score > r2_score) {
730 rc = -1;
731 goto done;
732 }
733 if (r1_score < r2_score) {
734 rc = 1;
735 goto done;
736 }
737 }
738
739 done:
740 crm_trace("%s (%d)%s%s %c %s (%d)%s%s: %s",
741 resource1->id, r1_score,
742 ((r1_node == NULL)? "" : " on "),
743 ((r1_node == NULL)? "" : r1_node->details->id),
744 ((rc < 0)? '>' : ((rc > 0)? '<' : '=')),
745 resource2->id, r2_score,
746 ((r2_node == NULL)? "" : " on "),
747 ((r2_node == NULL)? "" : r2_node->details->id),
748 reason);
749 if (r1_nodes != NULL) {
750 g_hash_table_destroy(r1_nodes);
751 }
752 if (r2_nodes != NULL) {
753 g_hash_table_destroy(r2_nodes);
754 }
755 return rc;
756 }
757
758
759
760
761
762
763
764 void
765 pcmk__sort_resources(pcmk_scheduler_t *scheduler)
766 {
767 GList *nodes = g_list_copy(scheduler->nodes);
768
769 nodes = pcmk__sort_nodes(nodes, NULL);
770 scheduler->resources = g_list_sort_with_data(scheduler->resources,
771 cmp_resources, nodes);
772 g_list_free(nodes);
773 }