This source file includes following definitions.
- pcmk__rsc_agent_changed
- add_rsc_if_matching
- pcmk__rscs_matching_id
- set_allocation_methods_for_rsc
- pcmk__set_allocation_methods
- pcmk__colocated_resources
- pcmk__noop_add_graph_meta
- pcmk__output_resource_actions
- pcmk__finalize_assignment
- pcmk__assign_resource
- pcmk__unassign_resource
- pcmk__threshold_reached
- convert_const_pointer
- get_node_weight
- 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 resource_alloc_functions_t allocation_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 clone_create_actions,
62 clone_create_probe,
63 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 clone_rsc_location,
70 clone_action_flags,
71 pcmk__instance_update_ordered_actions,
72 pcmk__output_resource_actions,
73 clone_expand,
74 clone_append_meta,
75 pcmk__clone_add_utilization,
76 pcmk__clone_shutdown_lock,
77 },
78 {
79 pcmk__bundle_allocate,
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_rsc_location,
89 pcmk__bundle_action_flags,
90 pcmk__instance_update_ordered_actions,
91 pcmk__output_bundle_actions,
92 pcmk__bundle_expand,
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(pe_resource_t *rsc, pe_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), CRMD_ACTION_STOP, node, FALSE, TRUE,
140 rsc->cluster);
141 pe__set_resource_flags(rsc, pe_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, pe_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 pe_resource_t *child = (pe_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 pe_working_set_t *data_set)
184 {
185 GList *result = NULL;
186
187 CRM_CHECK((id != NULL) && (data_set != NULL), return NULL);
188 for (GList *iter = data_set->resources; iter != NULL; iter = iter->next) {
189 result = add_rsc_if_matching(result, (pe_resource_t *) iter->data, id);
190 }
191 return result;
192 }
193
194
195
196
197
198
199
200
201 static void
202 set_allocation_methods_for_rsc(pe_resource_t *rsc, void *ignored)
203 {
204 rsc->cmds = &allocation_methods[rsc->variant];
205 g_list_foreach(rsc->children, (GFunc) set_allocation_methods_for_rsc, NULL);
206 }
207
208
209
210
211
212
213
214 void
215 pcmk__set_allocation_methods(pe_working_set_t *data_set)
216 {
217 g_list_foreach(data_set->resources, (GFunc) set_allocation_methods_for_rsc,
218 NULL);
219 }
220
221
222 GList *
223 pcmk__colocated_resources(const pe_resource_t *rsc, const pe_resource_t *orig_rsc,
224 GList *colocated_rscs)
225 {
226 const GList *iter = NULL;
227 GList *colocations = NULL;
228
229 if (orig_rsc == NULL) {
230 orig_rsc = rsc;
231 }
232
233 if ((rsc == NULL) || (g_list_find(colocated_rscs, rsc) != NULL)) {
234 return colocated_rscs;
235 }
236
237 pe_rsc_trace(orig_rsc, "%s is in colocation chain with %s",
238 rsc->id, orig_rsc->id);
239 colocated_rscs = g_list_prepend(colocated_rscs, (gpointer) rsc);
240
241
242 colocations = pcmk__this_with_colocations(rsc);
243 for (iter = colocations; iter != NULL; iter = iter->next) {
244 const pcmk__colocation_t *constraint = iter->data;
245 const pe_resource_t *primary = constraint->primary;
246
247 if (primary == orig_rsc) {
248 continue;
249 }
250
251 if ((constraint->score == INFINITY) &&
252 (pcmk__colocation_affects(rsc, primary, constraint,
253 true) == pcmk__coloc_affects_location)) {
254
255 colocated_rscs = primary->cmds->colocated_resources(primary,
256 orig_rsc,
257 colocated_rscs);
258 }
259 }
260 g_list_free(colocations);
261
262
263 colocations = pcmk__with_this_colocations(rsc);
264 for (iter = colocations; iter != NULL; iter = iter->next) {
265 const pcmk__colocation_t *constraint = iter->data;
266 const pe_resource_t *dependent = constraint->dependent;
267
268 if (dependent == orig_rsc) {
269 continue;
270 }
271
272 if (pe_rsc_is_clone(rsc) && !pe_rsc_is_clone(dependent)) {
273 continue;
274 }
275
276 if ((constraint->score == INFINITY) &&
277 (pcmk__colocation_affects(dependent, rsc, constraint,
278 true) == pcmk__coloc_affects_location)) {
279
280 colocated_rscs = dependent->cmds->colocated_resources(dependent,
281 orig_rsc,
282 colocated_rscs);
283 }
284 }
285 g_list_free(colocations);
286
287 return colocated_rscs;
288 }
289
290
291 void
292 pcmk__noop_add_graph_meta(const pe_resource_t *rsc, xmlNode *xml)
293 {
294 }
295
296 void
297 pcmk__output_resource_actions(pe_resource_t *rsc)
298 {
299 pcmk__output_t *out = rsc->cluster->priv;
300
301 pe_node_t *next = NULL;
302 pe_node_t *current = NULL;
303
304 if (rsc->children != NULL) {
305 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
306 pe_resource_t *child = (pe_resource_t *) iter->data;
307
308 child->cmds->output_actions(child);
309 }
310 return;
311 }
312
313 next = rsc->allocated_to;
314 if (rsc->running_on) {
315 current = pe__current_node(rsc);
316 if (rsc->role == RSC_ROLE_STOPPED) {
317
318
319
320 rsc->role = RSC_ROLE_STARTED;
321 }
322 }
323
324 if ((current == NULL) && pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
325
326 return;
327 }
328
329 out->message(out, "rsc-action", rsc, current, next);
330 }
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353 bool
354 pcmk__finalize_assignment(pe_resource_t *rsc, pe_node_t *chosen, bool force)
355 {
356 pcmk__output_t *out = rsc->cluster->priv;
357
358 CRM_ASSERT(rsc->variant == pe_native);
359
360 if (!force && (chosen != NULL)) {
361 if ((chosen->weight < 0)
362
363 || (!pcmk__node_available(chosen, true, false)
364 && !pe__is_guest_node(chosen))) {
365
366 crm_debug("All nodes for resource %s are unavailable, unclean or "
367 "shutting down (%s can%s run resources, with weight %d)",
368 rsc->id, pe__node_name(chosen),
369 (pcmk__node_available(chosen, true, false)? "" : "not"),
370 chosen->weight);
371 pe__set_next_role(rsc, RSC_ROLE_STOPPED, "node availability");
372 chosen = NULL;
373 }
374 }
375
376 pcmk__unassign_resource(rsc);
377 pe__clear_resource_flags(rsc, pe_rsc_provisional);
378
379 if (chosen == NULL) {
380 crm_debug("Could not allocate a node for %s", rsc->id);
381 pe__set_next_role(rsc, RSC_ROLE_STOPPED, "unable to allocate");
382
383 for (GList *iter = rsc->actions; iter != NULL; iter = iter->next) {
384 pe_action_t *op = (pe_action_t *) iter->data;
385
386 crm_debug("Updating %s for allocation failure", op->uuid);
387
388 if (pcmk__str_eq(op->task, RSC_STOP, pcmk__str_casei)) {
389 pe__clear_action_flags(op, pe_action_optional);
390
391 } else if (pcmk__str_eq(op->task, RSC_START, pcmk__str_casei)) {
392 pe__clear_action_flags(op, pe_action_runnable);
393
394
395 } else {
396
397 const char *interval_ms_s = NULL;
398 const char *target_rc_s = NULL;
399 char *rc_stopped = pcmk__itoa(PCMK_OCF_NOT_RUNNING);
400
401 interval_ms_s = g_hash_table_lookup(op->meta,
402 XML_LRM_ATTR_INTERVAL_MS);
403 target_rc_s = g_hash_table_lookup(op->meta,
404 XML_ATTR_TE_TARGET_RC);
405 if ((interval_ms_s != NULL)
406 && !pcmk__str_eq(interval_ms_s, "0", pcmk__str_none)
407 && !pcmk__str_eq(rc_stopped, target_rc_s, pcmk__str_none)) {
408 pe__clear_action_flags(op, pe_action_runnable);
409 }
410 free(rc_stopped);
411 }
412 }
413 return false;
414 }
415
416 crm_debug("Assigning %s to %s", rsc->id, pe__node_name(chosen));
417 rsc->allocated_to = pe__copy_node(chosen);
418
419 chosen->details->allocated_rsc = g_list_prepend(chosen->details->allocated_rsc,
420 rsc);
421 chosen->details->num_resources++;
422 chosen->count++;
423 pcmk__consume_node_capacity(chosen->details->utilization, rsc);
424
425 if (pcmk_is_set(rsc->cluster->flags, pe_flag_show_utilization)) {
426 out->message(out, "resource-util", rsc, chosen, __func__);
427 }
428 return true;
429 }
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451 bool
452 pcmk__assign_resource(pe_resource_t *rsc, pe_node_t *node, bool force)
453 {
454 bool changed = false;
455
456 if (rsc->children == NULL) {
457 if (rsc->allocated_to != NULL) {
458 changed = true;
459 }
460 pcmk__finalize_assignment(rsc, node, force);
461
462 } else {
463 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
464 pe_resource_t *child_rsc = (pe_resource_t *) iter->data;
465
466 changed |= pcmk__assign_resource(child_rsc, node, force);
467 }
468 }
469 return changed;
470 }
471
472
473
474
475
476
477
478
479
480
481
482 void
483 pcmk__unassign_resource(pe_resource_t *rsc)
484 {
485 pe_node_t *old = rsc->allocated_to;
486
487 if (old == NULL) {
488 return;
489 }
490
491 crm_info("Unassigning %s from %s", rsc->id, pe__node_name(old));
492 pe__set_resource_flags(rsc, pe_rsc_provisional);
493 rsc->allocated_to = NULL;
494
495
496
497
498 old->details->allocated_rsc = g_list_remove(old->details->allocated_rsc,
499 rsc);
500 old->details->num_resources--;
501 pcmk__release_node_capacity(old->details->utilization, rsc);
502 free(old);
503 }
504
505
506
507
508
509
510
511
512
513
514
515
516 bool
517 pcmk__threshold_reached(pe_resource_t *rsc, const pe_node_t *node,
518 pe_resource_t **failed)
519 {
520 int fail_count, remaining_tries;
521 pe_resource_t *rsc_to_ban = rsc;
522
523
524 if (rsc->migration_threshold == 0) {
525 return false;
526 }
527
528
529 if (pcmk_is_set(rsc->flags, pe_rsc_failure_ignored)) {
530 return false;
531 }
532
533
534 fail_count = pe_get_failcount(node, rsc, NULL,
535 pe_fc_effective|pe_fc_fillers, NULL);
536 if (fail_count <= 0) {
537 return false;
538 }
539
540
541 if (!pcmk_is_set(rsc->flags, pe_rsc_unique)) {
542 rsc_to_ban = uber_parent(rsc);
543 }
544
545
546 remaining_tries = rsc->migration_threshold - fail_count;
547
548 if (remaining_tries <= 0) {
549 crm_warn("%s cannot run on %s due to reaching migration threshold "
550 "(clean up resource to allow again)"
551 CRM_XS " failures=%d migration-threshold=%d",
552 rsc_to_ban->id, pe__node_name(node), fail_count,
553 rsc->migration_threshold);
554 if (failed != NULL) {
555 *failed = rsc_to_ban;
556 }
557 return true;
558 }
559
560 crm_info("%s can fail %d more time%s on "
561 "%s before reaching migration threshold (%d)",
562 rsc_to_ban->id, remaining_tries, pcmk__plural_s(remaining_tries),
563 pe__node_name(node), rsc->migration_threshold);
564 return false;
565 }
566
567 static void *
568 convert_const_pointer(const void *ptr)
569 {
570
571 return (void *)ptr;
572 }
573
574
575
576
577
578
579
580
581
582
583 static int
584 get_node_weight(const pe_node_t *node, GHashTable *nodes)
585 {
586 pe_node_t *weighted_node = NULL;
587
588 if ((node != NULL) && (nodes != NULL)) {
589 weighted_node = g_hash_table_lookup(nodes, node->details->id);
590 }
591 return (weighted_node == NULL)? -INFINITY : weighted_node->weight;
592 }
593
594
595
596
597
598
599
600
601
602
603
604
605 static gint
606 cmp_resources(gconstpointer a, gconstpointer b, gpointer data)
607 {
608 const pe_resource_t *resource1 = a;
609 const pe_resource_t *resource2 = b;
610 const GList *nodes = (const GList *) data;
611
612 int rc = 0;
613 int r1_weight = -INFINITY;
614 int r2_weight = -INFINITY;
615 pe_node_t *r1_node = NULL;
616 pe_node_t *r2_node = NULL;
617 GHashTable *r1_nodes = NULL;
618 GHashTable *r2_nodes = NULL;
619 const char *reason = NULL;
620
621
622 reason = "priority";
623 r1_weight = resource1->priority;
624 r2_weight = resource2->priority;
625 if (r1_weight > r2_weight) {
626 rc = -1;
627 goto done;
628 }
629 if (r1_weight < r2_weight) {
630 rc = 1;
631 goto done;
632 }
633
634
635 reason = "no node list";
636 if (nodes == NULL) {
637 goto done;
638 }
639
640
641 resource1->cmds->add_colocated_node_scores(convert_const_pointer(resource1),
642 resource1->id, &r1_nodes, NULL,
643 1, pcmk__coloc_select_this_with);
644 resource2->cmds->add_colocated_node_scores(convert_const_pointer(resource2),
645 resource2->id, &r2_nodes, NULL,
646 1, pcmk__coloc_select_this_with);
647 pe__show_node_weights(true, NULL, resource1->id, r1_nodes,
648 resource1->cluster);
649 pe__show_node_weights(true, NULL, resource2->id, r2_nodes,
650 resource2->cluster);
651
652
653 reason = "current location";
654 if (resource1->running_on != NULL) {
655 r1_node = pe__current_node(resource1);
656 }
657 if (resource2->running_on != NULL) {
658 r2_node = pe__current_node(resource2);
659 }
660 r1_weight = get_node_weight(r1_node, r1_nodes);
661 r2_weight = get_node_weight(r2_node, r2_nodes);
662 if (r1_weight > r2_weight) {
663 rc = -1;
664 goto done;
665 }
666 if (r1_weight < r2_weight) {
667 rc = 1;
668 goto done;
669 }
670
671
672 reason = "score";
673 for (const GList *iter = nodes; iter != NULL; iter = iter->next) {
674 const pe_node_t *node = (const pe_node_t *) iter->data;
675
676 r1_weight = get_node_weight(node, r1_nodes);
677 r2_weight = get_node_weight(node, r2_nodes);
678 if (r1_weight > r2_weight) {
679 rc = -1;
680 goto done;
681 }
682 if (r1_weight < r2_weight) {
683 rc = 1;
684 goto done;
685 }
686 }
687
688 done:
689 crm_trace("%s (%d)%s%s %c %s (%d)%s%s: %s",
690 resource1->id, r1_weight,
691 ((r1_node == NULL)? "" : " on "),
692 ((r1_node == NULL)? "" : r1_node->details->id),
693 ((rc < 0)? '>' : ((rc > 0)? '<' : '=')),
694 resource2->id, r2_weight,
695 ((r2_node == NULL)? "" : " on "),
696 ((r2_node == NULL)? "" : r2_node->details->id),
697 reason);
698 if (r1_nodes != NULL) {
699 g_hash_table_destroy(r1_nodes);
700 }
701 if (r2_nodes != NULL) {
702 g_hash_table_destroy(r2_nodes);
703 }
704 return rc;
705 }
706
707
708
709
710
711
712
713 void
714 pcmk__sort_resources(pe_working_set_t *data_set)
715 {
716 GList *nodes = g_list_copy(data_set->nodes);
717
718 nodes = pcmk__sort_nodes(nodes, NULL);
719 data_set->resources = g_list_sort_with_data(data_set->resources,
720 cmp_resources, nodes);
721 g_list_free(nodes);
722 }