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__output_resource_actions
- pcmk__assign_primitive
- 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 #include <crm/msg_xml.h>
12 #include <pacemaker-internal.h>
13
14 #include "libpacemaker_private.h"
15
16
17 static resource_alloc_functions_t allocation_methods[] = {
18 {
19 pcmk__native_merge_weights,
20 pcmk__native_allocate,
21 native_create_actions,
22 native_create_probe,
23 native_internal_constraints,
24 native_rsc_colocation_lh,
25 native_rsc_colocation_rh,
26 pcmk__colocated_resources,
27 native_rsc_location,
28 native_action_flags,
29 native_update_actions,
30 pcmk__output_resource_actions,
31 native_expand,
32 native_append_meta,
33 pcmk__primitive_add_utilization,
34 pcmk__primitive_shutdown_lock,
35 },
36 {
37 pcmk__group_merge_weights,
38 pcmk__group_allocate,
39 group_create_actions,
40 native_create_probe,
41 group_internal_constraints,
42 group_rsc_colocation_lh,
43 group_rsc_colocation_rh,
44 pcmk__group_colocated_resources,
45 group_rsc_location,
46 group_action_flags,
47 group_update_actions,
48 pcmk__output_resource_actions,
49 group_expand,
50 group_append_meta,
51 pcmk__group_add_utilization,
52 pcmk__group_shutdown_lock,
53 },
54 {
55 pcmk__native_merge_weights,
56 pcmk__clone_allocate,
57 clone_create_actions,
58 clone_create_probe,
59 clone_internal_constraints,
60 clone_rsc_colocation_lh,
61 clone_rsc_colocation_rh,
62 pcmk__colocated_resources,
63 clone_rsc_location,
64 clone_action_flags,
65 pcmk__multi_update_actions,
66 pcmk__output_resource_actions,
67 clone_expand,
68 clone_append_meta,
69 pcmk__clone_add_utilization,
70 pcmk__clone_shutdown_lock,
71 },
72 {
73 pcmk__native_merge_weights,
74 pcmk__bundle_allocate,
75 pcmk__bundle_create_actions,
76 pcmk__bundle_create_probe,
77 pcmk__bundle_internal_constraints,
78 pcmk__bundle_rsc_colocation_lh,
79 pcmk__bundle_rsc_colocation_rh,
80 pcmk__colocated_resources,
81 pcmk__bundle_rsc_location,
82 pcmk__bundle_action_flags,
83 pcmk__multi_update_actions,
84 pcmk__output_bundle_actions,
85 pcmk__bundle_expand,
86 pcmk__bundle_append_meta,
87 pcmk__bundle_add_utilization,
88 pcmk__bundle_shutdown_lock,
89 }
90 };
91
92
93
94
95
96
97
98
99
100
101
102
103 bool
104 pcmk__rsc_agent_changed(pe_resource_t *rsc, pe_node_t *node,
105 const xmlNode *rsc_entry, bool active_on_node)
106 {
107 bool changed = false;
108 const char *attr_list[] = {
109 XML_ATTR_TYPE,
110 XML_AGENT_ATTR_CLASS,
111 XML_AGENT_ATTR_PROVIDER
112 };
113
114 for (int i = 0; i < PCMK__NELEM(attr_list); i++) {
115 const char *value = crm_element_value(rsc->xml, attr_list[i]);
116 const char *old_value = crm_element_value(rsc_entry, attr_list[i]);
117
118 if (!pcmk__str_eq(value, old_value, pcmk__str_none)) {
119 changed = true;
120 trigger_unfencing(rsc, node, "Device definition changed", NULL,
121 rsc->cluster);
122 if (active_on_node) {
123 crm_notice("Forcing restart of %s on %s "
124 "because %s changed from '%s' to '%s'",
125 rsc->id, node->details->uname, attr_list[i],
126 crm_str(old_value), crm_str(value));
127 }
128 }
129 }
130 if (changed && active_on_node) {
131
132 custom_action(rsc, stop_key(rsc), CRMD_ACTION_STOP, node, FALSE, TRUE,
133 rsc->cluster);
134 pe__set_resource_flags(rsc, pe_rsc_start_pending);
135 }
136 return changed;
137 }
138
139
140
141
142
143
144
145
146
147
148
149 static GList *
150 add_rsc_if_matching(GList *result, pe_resource_t *rsc, const char *id)
151 {
152 if ((strcmp(rsc->id, id) == 0)
153 || ((rsc->clone_name != NULL) && (strcmp(rsc->clone_name, id) == 0))) {
154 result = g_list_prepend(result, rsc);
155 }
156 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
157 pe_resource_t *child = (pe_resource_t *) iter->data;
158
159 result = add_rsc_if_matching(result, child, id);
160 }
161 return result;
162 }
163
164
165
166
167
168
169
170
171
172
173
174
175 GList *
176 pcmk__rscs_matching_id(const char *id, pe_working_set_t *data_set)
177 {
178 GList *result = NULL;
179
180 CRM_CHECK((id != NULL) && (data_set != NULL), return NULL);
181 for (GList *iter = data_set->resources; iter != NULL; iter = iter->next) {
182 result = add_rsc_if_matching(result, (pe_resource_t *) iter->data, id);
183 }
184 return result;
185 }
186
187
188
189
190
191
192
193
194 static void
195 set_allocation_methods_for_rsc(pe_resource_t *rsc, void *ignored)
196 {
197 rsc->cmds = &allocation_methods[rsc->variant];
198 g_list_foreach(rsc->children, (GFunc) set_allocation_methods_for_rsc, NULL);
199 }
200
201
202
203
204
205
206
207 void
208 pcmk__set_allocation_methods(pe_working_set_t *data_set)
209 {
210 g_list_foreach(data_set->resources, (GFunc) set_allocation_methods_for_rsc,
211 NULL);
212 }
213
214
215 GList *
216 pcmk__colocated_resources(pe_resource_t *rsc, pe_resource_t *orig_rsc,
217 GList *colocated_rscs)
218 {
219 GList *gIter = NULL;
220
221 if (orig_rsc == NULL) {
222 orig_rsc = rsc;
223 }
224
225 if ((rsc == NULL) || (g_list_find(colocated_rscs, rsc) != NULL)) {
226 return colocated_rscs;
227 }
228
229 pe_rsc_trace(orig_rsc, "%s is in colocation chain with %s",
230 rsc->id, orig_rsc->id);
231 colocated_rscs = g_list_append(colocated_rscs, rsc);
232
233
234 for (gIter = rsc->rsc_cons; gIter != NULL; gIter = gIter->next) {
235 pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
236 pe_resource_t *primary = constraint->primary;
237
238 if (primary == orig_rsc) {
239 continue;
240 }
241
242 if ((constraint->score == INFINITY) &&
243 (pcmk__colocation_affects(rsc, primary, constraint,
244 true) == pcmk__coloc_affects_location)) {
245
246 colocated_rscs = primary->cmds->colocated_resources(primary,
247 orig_rsc,
248 colocated_rscs);
249 }
250 }
251
252
253 for (gIter = rsc->rsc_cons_lhs; gIter != NULL; gIter = gIter->next) {
254 pcmk__colocation_t *constraint = (pcmk__colocation_t *) gIter->data;
255 pe_resource_t *dependent = constraint->dependent;
256
257 if (dependent == orig_rsc) {
258 continue;
259 }
260
261 if (pe_rsc_is_clone(rsc) && !pe_rsc_is_clone(dependent)) {
262 continue;
263 }
264
265 if ((constraint->score == INFINITY) &&
266 (pcmk__colocation_affects(dependent, rsc, constraint,
267 true) == pcmk__coloc_affects_location)) {
268
269 colocated_rscs = dependent->cmds->colocated_resources(dependent,
270 orig_rsc,
271 colocated_rscs);
272 }
273 }
274
275 return colocated_rscs;
276 }
277
278 void
279 pcmk__output_resource_actions(pe_resource_t *rsc)
280 {
281 pcmk__output_t *out = rsc->cluster->priv;
282
283 pe_node_t *next = NULL;
284 pe_node_t *current = NULL;
285
286 if (rsc->children != NULL) {
287 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
288 pe_resource_t *child = (pe_resource_t *) iter->data;
289
290 child->cmds->output_actions(child);
291 }
292 return;
293 }
294
295 next = rsc->allocated_to;
296 if (rsc->running_on) {
297 current = pe__current_node(rsc);
298 if (rsc->role == RSC_ROLE_STOPPED) {
299
300
301
302
303 rsc->role = RSC_ROLE_STARTED;
304 }
305 }
306
307 if ((current == NULL) && pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
308
309 return;
310 }
311
312 out->message(out, "rsc-action", rsc, current, next);
313 }
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336 bool
337 pcmk__assign_primitive(pe_resource_t *rsc, pe_node_t *chosen, bool force)
338 {
339 pcmk__output_t *out = rsc->cluster->priv;
340
341 CRM_ASSERT(rsc->variant == pe_native);
342
343 if (!force && (chosen != NULL)) {
344 if ((chosen->weight < 0)
345
346 || (!pcmk__node_available(chosen) && !pe__is_guest_node(chosen))) {
347
348 crm_debug("All nodes for resource %s are unavailable, unclean or "
349 "shutting down (%s can%s run resources, with weight %d)",
350 rsc->id, chosen->details->uname,
351 (pcmk__node_available(chosen)? "" : "not"),
352 chosen->weight);
353 pe__set_next_role(rsc, RSC_ROLE_STOPPED, "node availability");
354 chosen = NULL;
355 }
356 }
357
358 pcmk__unassign_resource(rsc);
359 pe__clear_resource_flags(rsc, pe_rsc_provisional);
360
361 if (chosen == NULL) {
362 crm_debug("Could not allocate a node for %s", rsc->id);
363 pe__set_next_role(rsc, RSC_ROLE_STOPPED, "unable to allocate");
364
365 for (GList *iter = rsc->actions; iter != NULL; iter = iter->next) {
366 pe_action_t *op = (pe_action_t *) iter->data;
367
368 crm_debug("Updating %s for allocation failure", op->uuid);
369
370 if (pcmk__str_eq(op->task, RSC_STOP, pcmk__str_casei)) {
371 pe__clear_action_flags(op, pe_action_optional);
372
373 } else if (pcmk__str_eq(op->task, RSC_START, pcmk__str_casei)) {
374 pe__clear_action_flags(op, pe_action_runnable);
375
376
377 } else {
378
379 const char *interval_ms_s = NULL;
380 const char *target_rc_s = NULL;
381 char *rc_stopped = pcmk__itoa(PCMK_OCF_NOT_RUNNING);
382
383 interval_ms_s = g_hash_table_lookup(op->meta,
384 XML_LRM_ATTR_INTERVAL_MS);
385 target_rc_s = g_hash_table_lookup(op->meta,
386 XML_ATTR_TE_TARGET_RC);
387 if ((interval_ms_s != NULL)
388 && !pcmk__str_eq(interval_ms_s, "0", pcmk__str_none)
389 && !pcmk__str_eq(rc_stopped, target_rc_s, pcmk__str_none)) {
390 pe__clear_action_flags(op, pe_action_runnable);
391 }
392 free(rc_stopped);
393 }
394 }
395 return false;
396 }
397
398 crm_debug("Assigning %s to %s", rsc->id, chosen->details->uname);
399 rsc->allocated_to = pe__copy_node(chosen);
400
401 chosen->details->allocated_rsc = g_list_prepend(chosen->details->allocated_rsc,
402 rsc);
403 chosen->details->num_resources++;
404 chosen->count++;
405 pcmk__consume_node_capacity(chosen->details->utilization, rsc);
406
407 if (pcmk_is_set(rsc->cluster->flags, pe_flag_show_utilization)) {
408 out->message(out, "resource-util", rsc, chosen, __func__);
409 }
410 return true;
411 }
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433 bool
434 pcmk__assign_resource(pe_resource_t *rsc, pe_node_t *node, bool force)
435 {
436 bool changed = false;
437
438 if (rsc->children == NULL) {
439 if (rsc->allocated_to != NULL) {
440 changed = true;
441 }
442 pcmk__assign_primitive(rsc, node, force);
443
444 } else {
445 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
446 pe_resource_t *child_rsc = (pe_resource_t *) iter->data;
447
448 changed |= pcmk__assign_resource(child_rsc, node, force);
449 }
450 }
451 return changed;
452 }
453
454
455
456
457
458
459
460
461
462
463
464 void
465 pcmk__unassign_resource(pe_resource_t *rsc)
466 {
467 pe_node_t *old = rsc->allocated_to;
468
469 if (old == NULL) {
470 return;
471 }
472
473 crm_info("Unassigning %s from %s", rsc->id, old->details->uname);
474 pe__set_resource_flags(rsc, pe_rsc_provisional);
475 rsc->allocated_to = NULL;
476
477
478
479
480 old->details->allocated_rsc = g_list_remove(old->details->allocated_rsc,
481 rsc);
482 old->details->num_resources--;
483 pcmk__release_node_capacity(old->details->utilization, rsc);
484 free(old);
485 }
486
487
488
489
490
491
492
493
494
495
496
497
498 bool
499 pcmk__threshold_reached(pe_resource_t *rsc, pe_node_t *node,
500 pe_resource_t **failed)
501 {
502 int fail_count, remaining_tries;
503 pe_resource_t *rsc_to_ban = rsc;
504
505
506 if (rsc->migration_threshold == 0) {
507 return false;
508 }
509
510
511 if (pcmk_is_set(rsc->flags, pe_rsc_failure_ignored)) {
512 return false;
513 }
514
515
516 fail_count = pe_get_failcount(node, rsc, NULL,
517 pe_fc_effective|pe_fc_fillers, NULL,
518 rsc->cluster);
519 if (fail_count <= 0) {
520 return false;
521 }
522
523
524 if (!pcmk_is_set(rsc->flags, pe_rsc_unique)) {
525 rsc_to_ban = uber_parent(rsc);
526 }
527
528
529 remaining_tries = rsc->migration_threshold - fail_count;
530
531 if (remaining_tries <= 0) {
532 crm_warn("%s cannot run on %s due to reaching migration threshold "
533 "(clean up resource to allow again)"
534 CRM_XS " failures=%d migration-threshold=%d",
535 rsc_to_ban->id, node->details->uname, fail_count,
536 rsc->migration_threshold);
537 if (failed != NULL) {
538 *failed = rsc_to_ban;
539 }
540 return true;
541 }
542
543 crm_info("%s can fail %d more time%s on "
544 "%s before reaching migration threshold (%d)",
545 rsc_to_ban->id, remaining_tries, pcmk__plural_s(remaining_tries),
546 node->details->uname, rsc->migration_threshold);
547 return false;
548 }
549
550 static void *
551 convert_const_pointer(const void *ptr)
552 {
553
554 return (void *)ptr;
555 }
556
557
558
559
560
561
562
563
564
565
566 static int
567 get_node_weight(pe_node_t *node, GHashTable *nodes)
568 {
569 pe_node_t *weighted_node = NULL;
570
571 if ((node != NULL) && (nodes != NULL)) {
572 weighted_node = g_hash_table_lookup(nodes, node->details->id);
573 }
574 return (weighted_node == NULL)? -INFINITY : weighted_node->weight;
575 }
576
577
578
579
580
581
582
583
584
585
586
587
588 static gint
589 cmp_resources(gconstpointer a, gconstpointer b, gpointer data)
590 {
591 const pe_resource_t *resource1 = a;
592 const pe_resource_t *resource2 = b;
593 GList *nodes = (GList *) data;
594
595 int rc = 0;
596 int r1_weight = -INFINITY;
597 int r2_weight = -INFINITY;
598 pe_node_t *r1_node = NULL;
599 pe_node_t *r2_node = NULL;
600 GHashTable *r1_nodes = NULL;
601 GHashTable *r2_nodes = NULL;
602 const char *reason = NULL;
603
604
605 reason = "priority";
606 r1_weight = resource1->priority;
607 r2_weight = resource2->priority;
608 if (r1_weight > r2_weight) {
609 rc = -1;
610 goto done;
611 }
612 if (r1_weight < r2_weight) {
613 rc = 1;
614 goto done;
615 }
616
617
618 reason = "no node list";
619 if (nodes == NULL) {
620 goto done;
621 }
622
623
624 r1_nodes = pcmk__native_merge_weights(convert_const_pointer(resource1),
625 resource1->id, NULL, NULL, 1,
626 pe_weights_forward | pe_weights_init);
627 r2_nodes = pcmk__native_merge_weights(convert_const_pointer(resource2),
628 resource2->id, NULL, NULL, 1,
629 pe_weights_forward | pe_weights_init);
630 pe__show_node_weights(true, NULL, resource1->id, r1_nodes,
631 resource1->cluster);
632 pe__show_node_weights(true, NULL, resource2->id, r2_nodes,
633 resource2->cluster);
634
635
636 reason = "current location";
637 if (resource1->running_on != NULL) {
638 r1_node = pe__current_node(resource1);
639 }
640 if (resource2->running_on != NULL) {
641 r2_node = pe__current_node(resource2);
642 }
643 r1_weight = get_node_weight(r1_node, r1_nodes);
644 r2_weight = get_node_weight(r2_node, r2_nodes);
645 if (r1_weight > r2_weight) {
646 rc = -1;
647 goto done;
648 }
649 if (r1_weight < r2_weight) {
650 rc = 1;
651 goto done;
652 }
653
654
655 reason = "score";
656 for (GList *iter = nodes; iter != NULL; iter = iter->next) {
657 pe_node_t *node = (pe_node_t *) iter->data;
658
659 r1_weight = get_node_weight(node, r1_nodes);
660 r2_weight = get_node_weight(node, r2_nodes);
661 if (r1_weight > r2_weight) {
662 rc = -1;
663 goto done;
664 }
665 if (r1_weight < r2_weight) {
666 rc = 1;
667 goto done;
668 }
669 }
670
671 done:
672 crm_trace("%s (%d)%s%s %c %s (%d)%s%s: %s",
673 resource1->id, r1_weight,
674 ((r1_node == NULL)? "" : " on "),
675 ((r1_node == NULL)? "" : r1_node->details->id),
676 ((rc < 0)? '>' : ((rc > 0)? '<' : '=')),
677 resource2->id, r2_weight,
678 ((r2_node == NULL)? "" : " on "),
679 ((r2_node == NULL)? "" : r2_node->details->id),
680 reason);
681 if (r1_nodes != NULL) {
682 g_hash_table_destroy(r1_nodes);
683 }
684 if (r2_nodes != NULL) {
685 g_hash_table_destroy(r2_nodes);
686 }
687 return rc;
688 }
689
690
691
692
693
694
695
696 void
697 pcmk__sort_resources(pe_working_set_t *data_set)
698 {
699 GList *nodes = g_list_copy(data_set->nodes);
700
701 nodes = pcmk__sort_nodes(nodes, NULL, data_set);
702 data_set->resources = g_list_sort_with_data(data_set->resources,
703 cmp_resources, nodes);
704 g_list_free(nodes);
705 }