This source file includes following definitions.
- pe_can_fence
- pe__copy_node
- pe__node_list2table
- pe__cmp_node_name
- pe__output_node_weights
- pe__log_node_weights
- pe__show_node_scores_as
- pe__cmp_rsc_priority
- resource_node_score
- resource_location
- get_target_role
- order_actions
- destroy_ticket
- ticket_new
- rsc_printable_id
- pe__clear_resource_flags_recursive
- pe__clear_resource_flags_on_all
- pe__set_resource_flags_recursive
- trigger_unfencing
- pe__shutdown_requested
- pe__unpack_dataset_nvpairs
- pe__resource_is_disabled
- pe__rsc_running_on_only
- pe__rsc_running_on_any
- pcmk__rsc_filtered_by_node
- pe__filter_rsc_list
- pe__build_node_name_list
- pe__build_rsc_list
- pe__failed_probe_for_rsc
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <glib.h>
13 #include <stdbool.h>
14
15 #include <crm/crm.h>
16 #include <crm/common/xml.h>
17 #include <crm/pengine/internal.h>
18
19 #include "pe_status_private.h"
20
21 extern bool pcmk__is_daemon;
22
23 gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data);
24
25
26
27
28
29
30
31
32
33
34 bool
35 pe_can_fence(const pcmk_scheduler_t *scheduler, const pcmk_node_t *node)
36 {
37 if (pcmk__is_guest_or_bundle_node(node)) {
38
39
40
41 pcmk_resource_t *rsc = node->priv->remote->priv->launcher;
42
43 for (GList *n = rsc->priv->active_nodes; n != NULL; n = n->next) {
44 pcmk_node_t *launcher_node = n->data;
45
46 if (!launcher_node->details->online
47 && !pe_can_fence(scheduler, launcher_node)) {
48 return false;
49 }
50 }
51 return true;
52
53 } else if (!pcmk_is_set(scheduler->flags, pcmk__sched_fencing_enabled)) {
54 return false;
55
56 } else if (!pcmk_is_set(scheduler->flags, pcmk__sched_have_fencing)) {
57 return false;
58
59 } else if (pcmk_is_set(scheduler->flags, pcmk__sched_quorate)) {
60 return true;
61
62 } else if (scheduler->no_quorum_policy == pcmk_no_quorum_ignore) {
63 return true;
64
65 } else if (node == NULL) {
66 return false;
67
68 } else if (node->details->online) {
69
70
71
72
73 if (pcmk__is_pacemaker_remote_node(node)
74 && !pcmk_is_set(scheduler->flags, pcmk__sched_fence_remote_no_quorum)) {
75
76
77
78
79
80
81
82
83
84
85
86
87
88 pcmk_resource_t *rsc = node->priv->remote;
89 pcmk_node_t *n = NULL;
90 GHashTableIter iter;
91
92 g_hash_table_iter_init(&iter, rsc->priv->allowed_nodes);
93 while (g_hash_table_iter_next(&iter, NULL, (void **) &n)) {
94
95
96
97 if (!n->details->online) {
98 return false;
99 }
100 }
101 }
102
103 crm_notice("We can fence %s without quorum because they're in our membership",
104 pcmk__node_name(node));
105 return true;
106 }
107
108 crm_trace("Cannot fence %s", pcmk__node_name(node));
109 return false;
110 }
111
112
113
114
115
116
117
118
119
120
121
122
123 pcmk_node_t *
124 pe__copy_node(const pcmk_node_t *this_node)
125 {
126 pcmk_node_t *new_node = NULL;
127
128 pcmk__assert(this_node != NULL);
129
130 new_node = pcmk__assert_alloc(1, sizeof(pcmk_node_t));
131 new_node->assign = pcmk__assert_alloc(1,
132 sizeof(struct pcmk__node_assignment));
133
134 new_node->assign->probe_mode = this_node->assign->probe_mode;
135 new_node->assign->score = this_node->assign->score;
136 new_node->assign->count = this_node->assign->count;
137 new_node->details = this_node->details;
138 new_node->priv = this_node->priv;
139
140 return new_node;
141 }
142
143
144
145
146
147
148
149
150
151 GHashTable *
152 pe__node_list2table(const GList *list)
153 {
154 GHashTable *result = NULL;
155
156 result = pcmk__strkey_table(NULL, pcmk__free_node_copy);
157 for (const GList *gIter = list; gIter != NULL; gIter = gIter->next) {
158 pcmk_node_t *new_node = NULL;
159
160 new_node = pe__copy_node((const pcmk_node_t *) gIter->data);
161 g_hash_table_insert(result, (gpointer) new_node->priv->id, new_node);
162 }
163 return result;
164 }
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181 gint
182 pe__cmp_node_name(gconstpointer a, gconstpointer b)
183 {
184 const pcmk_node_t *node1 = (const pcmk_node_t *) a;
185 const pcmk_node_t *node2 = (const pcmk_node_t *) b;
186
187 if ((node1 == NULL) && (node2 == NULL)) {
188 return 0;
189 }
190
191 if (node1 == NULL) {
192 return -1;
193 }
194
195 if (node2 == NULL) {
196 return 1;
197 }
198
199 return pcmk__numeric_strcasecmp(node1->priv->name, node2->priv->name);
200 }
201
202
203
204
205
206
207
208
209
210
211 static void
212 pe__output_node_weights(const pcmk_resource_t *rsc, const char *comment,
213 GHashTable *nodes, pcmk_scheduler_t *scheduler)
214 {
215 pcmk__output_t *out = scheduler->priv->out;
216
217
218 GList *list = g_list_sort(g_hash_table_get_values(nodes),
219 pe__cmp_node_name);
220
221 for (const GList *gIter = list; gIter != NULL; gIter = gIter->next) {
222 const pcmk_node_t *node = (const pcmk_node_t *) gIter->data;
223
224 out->message(out, "node-weight", rsc, comment, node->priv->name,
225 pcmk_readable_score(node->assign->score));
226 }
227 g_list_free(list);
228 }
229
230
231
232
233
234
235
236
237
238
239
240
241 static void
242 pe__log_node_weights(const char *file, const char *function, int line,
243 const pcmk_resource_t *rsc, const char *comment,
244 GHashTable *nodes)
245 {
246 GHashTableIter iter;
247 pcmk_node_t *node = NULL;
248
249
250 pcmk__if_tracing({}, return);
251
252 g_hash_table_iter_init(&iter, nodes);
253 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
254 if (rsc) {
255 qb_log_from_external_source(function, file,
256 "%s: %s allocation score on %s: %s",
257 LOG_TRACE, line, 0,
258 comment, rsc->id,
259 pcmk__node_name(node),
260 pcmk_readable_score(node->assign->score));
261 } else {
262 qb_log_from_external_source(function, file, "%s: %s = %s",
263 LOG_TRACE, line, 0,
264 comment, pcmk__node_name(node),
265 pcmk_readable_score(node->assign->score));
266 }
267 }
268 }
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284 void
285 pe__show_node_scores_as(const char *file, const char *function, int line,
286 bool to_log, const pcmk_resource_t *rsc,
287 const char *comment, GHashTable *nodes,
288 pcmk_scheduler_t *scheduler)
289 {
290 if ((rsc != NULL) && pcmk_is_set(rsc->flags, pcmk__rsc_removed)) {
291
292 return;
293 }
294 if (nodes == NULL) {
295
296 return;
297 }
298
299 if (to_log) {
300 pe__log_node_weights(file, function, line, rsc, comment, nodes);
301 } else {
302 pe__output_node_weights(rsc, comment, nodes, scheduler);
303 }
304
305 if (rsc == NULL) {
306 return;
307 }
308
309
310 for (GList *gIter = rsc->priv->children;
311 gIter != NULL; gIter = gIter->next) {
312
313 pcmk_resource_t *child = (pcmk_resource_t *) gIter->data;
314
315 pe__show_node_scores_as(file, function, line, to_log, child, comment,
316 child->priv->allowed_nodes, scheduler);
317 }
318 }
319
320
321
322
323
324
325
326
327
328
329
330
331 gint
332 pe__cmp_rsc_priority(gconstpointer a, gconstpointer b)
333 {
334 const pcmk_resource_t *resource1 = (const pcmk_resource_t *)a;
335 const pcmk_resource_t *resource2 = (const pcmk_resource_t *)b;
336
337 if (a == NULL && b == NULL) {
338 return 0;
339 }
340 if (a == NULL) {
341 return 1;
342 }
343 if (b == NULL) {
344 return -1;
345 }
346
347 if (resource1->priv->priority > resource2->priv->priority) {
348 return -1;
349 }
350
351 if (resource1->priv->priority < resource2->priv->priority) {
352 return 1;
353 }
354
355 return 0;
356 }
357
358 static void
359 resource_node_score(pcmk_resource_t *rsc, const pcmk_node_t *node, int score,
360 const char *tag)
361 {
362 pcmk_node_t *match = NULL;
363
364 if ((pcmk_is_set(rsc->flags, pcmk__rsc_exclusive_probes)
365 || (node->assign->probe_mode == pcmk__probe_never))
366 && pcmk__str_eq(tag, "symmetric_default", pcmk__str_casei)) {
367
368
369
370
371 return;
372
373 } else {
374 for (GList *gIter = rsc->priv->children;
375 gIter != NULL; gIter = gIter->next) {
376
377 pcmk_resource_t *child_rsc = (pcmk_resource_t *) gIter->data;
378
379 resource_node_score(child_rsc, node, score, tag);
380 }
381 }
382
383 match = g_hash_table_lookup(rsc->priv->allowed_nodes, node->priv->id);
384 if (match == NULL) {
385 match = pe__copy_node(node);
386 g_hash_table_insert(rsc->priv->allowed_nodes,
387 (gpointer) match->priv->id, match);
388 }
389 match->assign->score = pcmk__add_scores(match->assign->score, score);
390 pcmk__rsc_trace(rsc,
391 "Enabling %s preference (%s) for %s on %s (now %s)",
392 tag, pcmk_readable_score(score), rsc->id,
393 pcmk__node_name(node),
394 pcmk_readable_score(match->assign->score));
395 }
396
397 void
398 resource_location(pcmk_resource_t *rsc, const pcmk_node_t *node, int score,
399 const char *tag, pcmk_scheduler_t *scheduler)
400 {
401 if (node != NULL) {
402 resource_node_score(rsc, node, score, tag);
403
404 } else if (scheduler != NULL) {
405 GList *gIter = scheduler->nodes;
406
407 for (; gIter != NULL; gIter = gIter->next) {
408 pcmk_node_t *node_iter = (pcmk_node_t *) gIter->data;
409
410 resource_node_score(rsc, node_iter, score, tag);
411 }
412
413 } else {
414 GHashTableIter iter;
415 pcmk_node_t *node_iter = NULL;
416
417 g_hash_table_iter_init(&iter, rsc->priv->allowed_nodes);
418 while (g_hash_table_iter_next(&iter, NULL, (void **)&node_iter)) {
419 resource_node_score(rsc, node_iter, score, tag);
420 }
421 }
422
423 if ((node == NULL) && (score == -PCMK_SCORE_INFINITY)
424 && (rsc->priv->assigned_node != NULL)) {
425
426
427 crm_info("Unassigning %s from %s",
428 rsc->id, pcmk__node_name(rsc->priv->assigned_node));
429 pcmk__free_node_copy(rsc->priv->assigned_node);
430 rsc->priv->assigned_node = NULL;
431 }
432 }
433
434 gboolean
435 get_target_role(const pcmk_resource_t *rsc, enum rsc_role_e *role)
436 {
437 enum rsc_role_e local_role = pcmk_role_unknown;
438 const char *value = g_hash_table_lookup(rsc->priv->meta,
439 PCMK_META_TARGET_ROLE);
440
441 CRM_CHECK(role != NULL, return FALSE);
442
443 if (pcmk__str_eq(value, PCMK_ROLE_STARTED,
444 pcmk__str_null_matches|pcmk__str_casei)) {
445 return FALSE;
446 }
447 if (pcmk__str_eq(PCMK_VALUE_DEFAULT, value, pcmk__str_casei)) {
448
449 pcmk__config_warn("Support for setting " PCMK_META_TARGET_ROLE
450 " to the explicit value '" PCMK_VALUE_DEFAULT
451 "' is deprecated and will be removed in a "
452 "future release (just leave it unset)");
453 return FALSE;
454 }
455
456 local_role = pcmk_parse_role(value);
457 if (local_role == pcmk_role_unknown) {
458 pcmk__config_err("Ignoring '" PCMK_META_TARGET_ROLE "' for %s "
459 "because '%s' is not valid", rsc->id, value);
460 return FALSE;
461
462 } else if (local_role > pcmk_role_started) {
463 if (pcmk_is_set(pe__const_top_resource(rsc, false)->flags,
464 pcmk__rsc_promotable)) {
465 if (local_role > pcmk_role_unpromoted) {
466
467 return FALSE;
468 }
469
470 } else {
471 pcmk__config_err("Ignoring '" PCMK_META_TARGET_ROLE "' for %s "
472 "because '%s' only makes sense for promotable "
473 "clones", rsc->id, value);
474 return FALSE;
475 }
476 }
477
478 *role = local_role;
479 return TRUE;
480 }
481
482 gboolean
483 order_actions(pcmk_action_t *first, pcmk_action_t *then, uint32_t flags)
484 {
485 GList *gIter = NULL;
486 pcmk__related_action_t *wrapper = NULL;
487 GList *list = NULL;
488
489 if (flags == pcmk__ar_none) {
490 return FALSE;
491 }
492
493 if ((first == NULL) || (then == NULL)) {
494 return FALSE;
495 }
496
497 crm_trace("Creating action wrappers for ordering: %s then %s",
498 first->uuid, then->uuid);
499
500
501 pcmk__assert(first != then);
502
503
504 gIter = first->actions_after;
505 for (; gIter != NULL; gIter = gIter->next) {
506 pcmk__related_action_t *after = gIter->data;
507
508 if ((after->action == then)
509 && pcmk_any_flags_set(after->flags, flags)) {
510 return FALSE;
511 }
512 }
513
514 wrapper = pcmk__assert_alloc(1, sizeof(pcmk__related_action_t));
515 wrapper->action = then;
516 wrapper->flags = flags;
517 list = first->actions_after;
518 list = g_list_prepend(list, wrapper);
519 first->actions_after = list;
520
521 wrapper = pcmk__assert_alloc(1, sizeof(pcmk__related_action_t));
522 wrapper->action = first;
523 wrapper->flags = flags;
524 list = then->actions_before;
525 list = g_list_prepend(list, wrapper);
526 then->actions_before = list;
527 return TRUE;
528 }
529
530 void
531 destroy_ticket(gpointer data)
532 {
533 pcmk__ticket_t *ticket = data;
534
535 if (ticket->state) {
536 g_hash_table_destroy(ticket->state);
537 }
538 free(ticket->id);
539 free(ticket);
540 }
541
542 pcmk__ticket_t *
543 ticket_new(const char *ticket_id, pcmk_scheduler_t *scheduler)
544 {
545 pcmk__ticket_t *ticket = NULL;
546
547 if (pcmk__str_empty(ticket_id)) {
548 return NULL;
549 }
550
551 if (scheduler->priv->ticket_constraints == NULL) {
552 scheduler->priv->ticket_constraints =
553 pcmk__strkey_table(free, destroy_ticket);
554 }
555
556 ticket = g_hash_table_lookup(scheduler->priv->ticket_constraints,
557 ticket_id);
558 if (ticket == NULL) {
559
560 ticket = calloc(1, sizeof(pcmk__ticket_t));
561 if (ticket == NULL) {
562 pcmk__sched_err(scheduler, "Cannot allocate ticket '%s'",
563 ticket_id);
564 return NULL;
565 }
566
567 crm_trace("Creating ticket entry for %s", ticket_id);
568
569 ticket->id = strdup(ticket_id);
570 ticket->last_granted = -1;
571 ticket->state = pcmk__strkey_table(free, free);
572
573 g_hash_table_insert(scheduler->priv->ticket_constraints,
574 pcmk__str_copy(ticket->id), ticket);
575 }
576
577 return ticket;
578 }
579
580 const char *
581 rsc_printable_id(const pcmk_resource_t *rsc)
582 {
583 if (pcmk_is_set(rsc->flags, pcmk__rsc_unique)) {
584 return rsc->id;
585 }
586 return pcmk__xe_id(rsc->priv->xml);
587 }
588
589 void
590 pe__clear_resource_flags_recursive(pcmk_resource_t *rsc, uint64_t flags)
591 {
592 pcmk__clear_rsc_flags(rsc, flags);
593
594 for (GList *gIter = rsc->priv->children;
595 gIter != NULL; gIter = gIter->next) {
596
597 pe__clear_resource_flags_recursive((pcmk_resource_t *) gIter->data,
598 flags);
599 }
600 }
601
602 void
603 pe__clear_resource_flags_on_all(pcmk_scheduler_t *scheduler, uint64_t flag)
604 {
605 for (GList *lpc = scheduler->priv->resources;
606 lpc != NULL; lpc = lpc->next) {
607
608 pcmk_resource_t *r = (pcmk_resource_t *) lpc->data;
609
610 pe__clear_resource_flags_recursive(r, flag);
611 }
612 }
613
614 void
615 pe__set_resource_flags_recursive(pcmk_resource_t *rsc, uint64_t flags)
616 {
617 pcmk__set_rsc_flags(rsc, flags);
618
619 for (GList *gIter = rsc->priv->children;
620 gIter != NULL; gIter = gIter->next) {
621
622 pe__set_resource_flags_recursive((pcmk_resource_t *) gIter->data,
623 flags);
624 }
625 }
626
627 void
628 trigger_unfencing(pcmk_resource_t *rsc, pcmk_node_t *node, const char *reason,
629 pcmk_action_t *dependency, pcmk_scheduler_t *scheduler)
630 {
631 if (!pcmk_is_set(scheduler->flags, pcmk__sched_enable_unfencing)) {
632
633 return;
634
635 } else if ((rsc != NULL)
636 && !pcmk_is_set(rsc->flags, pcmk__rsc_fence_device)) {
637
638 return;
639
640 } else if(node
641 && node->details->online
642 && node->details->unclean == FALSE
643 && node->details->shutdown == FALSE) {
644 pcmk_action_t *unfence = pe_fence_op(node, PCMK_ACTION_ON, FALSE,
645 reason, FALSE, scheduler);
646
647 if(dependency) {
648 order_actions(unfence, dependency, pcmk__ar_ordered);
649 }
650
651 } else if(rsc) {
652 GHashTableIter iter;
653
654 g_hash_table_iter_init(&iter, rsc->priv->allowed_nodes);
655 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
656 if(node->details->online && node->details->unclean == FALSE && node->details->shutdown == FALSE) {
657 trigger_unfencing(rsc, node, reason, dependency, scheduler);
658 }
659 }
660 }
661 }
662
663
664
665
666
667
668
669
670
671
672
673
674
675 bool
676 pe__shutdown_requested(const pcmk_node_t *node)
677 {
678 const char *shutdown = pcmk__node_attr(node, PCMK__NODE_ATTR_SHUTDOWN, NULL,
679 pcmk__rsc_node_current);
680
681 return !pcmk__str_eq(shutdown, "0", pcmk__str_null_matches);
682 }
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697 void
698 pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name,
699 const pcmk_rule_input_t *rule_input,
700 GHashTable *hash, const char *always_first,
701 pcmk_scheduler_t *scheduler)
702 {
703 crm_time_t *next_change = NULL;
704
705 CRM_CHECK((set_name != NULL) && (rule_input != NULL) && (hash != NULL)
706 && (scheduler != NULL), return);
707
708
709 CRM_CHECK((rule_input->node_attrs == NULL)
710 || (strcmp(set_name, PCMK_XE_META_ATTRIBUTES) != 0), return);
711
712 if (xml_obj == NULL) {
713 return;
714 }
715
716 next_change = crm_time_new_undefined();
717 pcmk_unpack_nvpair_blocks(xml_obj, set_name, always_first, rule_input, hash,
718 next_change);
719 if (crm_time_is_defined(next_change)) {
720 time_t recheck = (time_t) crm_time_get_seconds_since_epoch(next_change);
721
722 pcmk__update_recheck_time(recheck, scheduler, "rule evaluation");
723 }
724 crm_time_free(next_change);
725 }
726
727 bool
728 pe__resource_is_disabled(const pcmk_resource_t *rsc)
729 {
730 const char *target_role = NULL;
731
732 CRM_CHECK(rsc != NULL, return false);
733 target_role = g_hash_table_lookup(rsc->priv->meta,
734 PCMK_META_TARGET_ROLE);
735 if (target_role) {
736
737 enum rsc_role_e target_role_e = pcmk_parse_role(target_role);
738
739 if ((target_role_e == pcmk_role_stopped)
740 || ((target_role_e == pcmk_role_unpromoted)
741 && pcmk_is_set(pe__const_top_resource(rsc, false)->flags,
742 pcmk__rsc_promotable))) {
743 return true;
744 }
745 }
746 return false;
747 }
748
749
750
751
752
753
754
755
756
757
758 bool
759 pe__rsc_running_on_only(const pcmk_resource_t *rsc, const pcmk_node_t *node)
760 {
761 return (rsc != NULL) && pcmk__list_of_1(rsc->priv->active_nodes)
762 && pcmk__same_node((const pcmk_node_t *)
763 rsc->priv->active_nodes->data, node);
764 }
765
766 bool
767 pe__rsc_running_on_any(pcmk_resource_t *rsc, GList *node_list)
768 {
769 if (rsc != NULL) {
770 for (GList *ele = rsc->priv->active_nodes; ele; ele = ele->next) {
771 pcmk_node_t *node = (pcmk_node_t *) ele->data;
772 if (pcmk__str_in_list(node->priv->name, node_list,
773 pcmk__str_star_matches|pcmk__str_casei)) {
774 return true;
775 }
776 }
777 }
778 return false;
779 }
780
781 bool
782 pcmk__rsc_filtered_by_node(pcmk_resource_t *rsc, GList *only_node)
783 {
784 return rsc->priv->fns->active(rsc, false)
785 && !pe__rsc_running_on_any(rsc, only_node);
786 }
787
788 GList *
789 pe__filter_rsc_list(GList *rscs, GList *filter)
790 {
791 GList *retval = NULL;
792
793 for (GList *gIter = rscs; gIter; gIter = gIter->next) {
794 pcmk_resource_t *rsc = (pcmk_resource_t *) gIter->data;
795
796
797
798
799 if (pcmk__str_in_list(rsc_printable_id(rsc), filter, pcmk__str_star_matches) ||
800 ((rsc->priv->parent != NULL)
801 && pcmk__str_in_list(rsc_printable_id(rsc->priv->parent),
802 filter, pcmk__str_star_matches))) {
803 retval = g_list_prepend(retval, rsc);
804 }
805 }
806
807 return retval;
808 }
809
810 GList *
811 pe__build_node_name_list(pcmk_scheduler_t *scheduler, const char *s)
812 {
813 GList *nodes = NULL;
814
815 if (pcmk__str_eq(s, "*", pcmk__str_null_matches)) {
816
817
818
819
820 nodes = g_list_prepend(nodes, strdup("*"));
821 } else {
822 pcmk_node_t *node = pcmk_find_node(scheduler, s);
823
824 if (node) {
825
826
827
828 nodes = g_list_prepend(nodes, strdup(s));
829 } else {
830
831
832
833
834
835
836 nodes = pe__unames_with_tag(scheduler, s);
837 }
838 }
839
840 return nodes;
841 }
842
843 GList *
844 pe__build_rsc_list(pcmk_scheduler_t *scheduler, const char *s)
845 {
846 GList *resources = NULL;
847
848 if (pcmk__str_eq(s, "*", pcmk__str_null_matches)) {
849 resources = g_list_prepend(resources, strdup("*"));
850 } else {
851 const uint32_t flags = pcmk_rsc_match_history|pcmk_rsc_match_basename;
852 pcmk_resource_t *rsc =
853 pe_find_resource_with_flags(scheduler->priv->resources, s, flags);
854
855 if (rsc) {
856
857
858
859
860
861 if (strstr(s, ":") != NULL) {
862 resources = g_list_prepend(resources, strdup(rsc->id));
863 } else {
864 resources = g_list_prepend(resources, strdup(rsc_printable_id(rsc)));
865 }
866 } else {
867
868
869
870
871 resources = pe__rscs_with_tag(scheduler, s);
872 }
873 }
874
875 return resources;
876 }
877
878 xmlNode *
879 pe__failed_probe_for_rsc(const pcmk_resource_t *rsc, const char *name)
880 {
881 const pcmk_resource_t *parent = pe__const_top_resource(rsc, false);
882 const char *rsc_id = rsc->id;
883 const pcmk_scheduler_t *scheduler = rsc->priv->scheduler;
884
885 if (pcmk__is_clone(parent)) {
886 rsc_id = pe__clone_child_id(parent);
887 }
888
889 for (xmlNode *xml_op = pcmk__xe_first_child(scheduler->priv->failed,
890 NULL, NULL, NULL);
891 xml_op != NULL; xml_op = pcmk__xe_next(xml_op, NULL)) {
892
893 const char *value = NULL;
894 char *op_id = NULL;
895
896
897 if (!pcmk_xe_mask_probe_failure(xml_op)) {
898 continue;
899 }
900
901
902
903
904 value = crm_element_value(xml_op, PCMK__META_ON_NODE);
905 if (value == NULL || !pcmk__str_eq(value, name, pcmk__str_casei|pcmk__str_null_matches)) {
906 continue;
907 }
908
909 if (!parse_op_key(pcmk__xe_history_key(xml_op), &op_id, NULL, NULL)) {
910 continue;
911 }
912
913
914 if (!pcmk__str_eq(op_id, rsc_id, pcmk__str_none)) {
915 free(op_id);
916 continue;
917 }
918
919 free(op_id);
920 return xml_op;
921 }
922
923 return NULL;
924 }