This source file includes following definitions.
- check_params
- failcount_clear_action_exists
- check_failure_threshold
- apply_exclusive_discovery
- apply_stickiness
- apply_shutdown_locks
- apply_node_criteria
- assign_resources
- clear_failcounts_if_orphaned
- schedule_resource_actions
- is_managed
- any_managed_resources
- needs_fencing
- needs_shutdown
- add_nondc_fencing
- schedule_fencing
- schedule_fencing_and_shutdowns
- log_resource_details
- log_all_actions
- log_unrunnable_actions
- pcmk__schedule_actions
- pcmk__init_scheduler
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <crm/crm.h>
13 #include <crm/cib.h>
14 #include <crm/cib/internal.h>
15 #include <crm/common/xml.h>
16 #include <crm/common/xml_internal.h>
17 #include <crm/common/scheduler_internal.h>
18
19 #include <glib.h>
20
21 #include <crm/pengine/status.h>
22 #include <pacemaker-internal.h>
23 #include "libpacemaker_private.h"
24
25 CRM_TRACE_INIT_DATA(pacemaker);
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 static void
43 check_params(pcmk_resource_t *rsc, pcmk_node_t *node, const xmlNode *rsc_op,
44 enum pcmk__check_parameters check)
45 {
46 const char *reason = NULL;
47 pcmk__op_digest_t *digest_data = NULL;
48
49 switch (check) {
50 case pcmk__check_active:
51 if (pcmk__check_action_config(rsc, node, rsc_op)
52 && pe_get_failcount(node, rsc, NULL, pcmk__fc_effective,
53 NULL)) {
54 reason = "action definition changed";
55 }
56 break;
57
58 case pcmk__check_last_failure:
59 digest_data = rsc_action_digest_cmp(rsc, rsc_op, node,
60 rsc->priv->scheduler);
61 switch (digest_data->rc) {
62 case pcmk__digest_unknown:
63 crm_trace("Resource %s history entry %s on %s has "
64 "no digest to compare",
65 rsc->id, pcmk__xe_id(rsc_op), node->priv->id);
66 break;
67 case pcmk__digest_match:
68 break;
69 default:
70 reason = "resource parameters have changed";
71 break;
72 }
73 break;
74 }
75 if (reason != NULL) {
76 pe__clear_failcount(rsc, node, reason, rsc->priv->scheduler);
77 }
78 }
79
80
81
82
83
84
85
86
87
88
89
90 static bool
91 failcount_clear_action_exists(const pcmk_node_t *node,
92 const pcmk_resource_t *rsc)
93 {
94 GList *list = pe__resource_actions(rsc, node, PCMK_ACTION_CLEAR_FAILCOUNT,
95 TRUE);
96
97 if (list != NULL) {
98 g_list_free(list);
99 return true;
100 }
101 return false;
102 }
103
104
105
106
107
108
109
110
111 static void
112 check_failure_threshold(gpointer data, gpointer user_data)
113 {
114 pcmk_resource_t *rsc = data;
115 const pcmk_node_t *node = user_data;
116
117
118 if (rsc->priv->children != NULL) {
119 g_list_foreach(rsc->priv->children, check_failure_threshold,
120 user_data);
121 return;
122 }
123
124 if (!failcount_clear_action_exists(node, rsc)) {
125
126
127
128
129
130
131
132
133
134
135 pcmk_resource_t *failed = NULL;
136
137 if (pcmk__threshold_reached(rsc, node, &failed)) {
138 resource_location(failed, node, -PCMK_SCORE_INFINITY,
139 "__fail_limit__", rsc->priv->scheduler);
140 }
141 }
142 }
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 static void
158 apply_exclusive_discovery(gpointer data, gpointer user_data)
159 {
160 pcmk_resource_t *rsc = data;
161 const pcmk_node_t *node = user_data;
162
163
164
165
166 if (pcmk_is_set(rsc->flags, pcmk__rsc_exclusive_probes)
167 || pcmk_is_set(pe__const_top_resource(rsc, false)->flags,
168 pcmk__rsc_exclusive_probes)) {
169 pcmk_node_t *match = NULL;
170
171
172 g_list_foreach(rsc->priv->children, apply_exclusive_discovery,
173 user_data);
174
175 match = g_hash_table_lookup(rsc->priv->allowed_nodes,
176 node->priv->id);
177 if ((match != NULL)
178 && (match->assign->probe_mode != pcmk__probe_exclusive)) {
179 match->assign->score = -PCMK_SCORE_INFINITY;
180 }
181 }
182 }
183
184
185
186
187
188
189
190
191 static void
192 apply_stickiness(gpointer data, gpointer user_data)
193 {
194 pcmk_resource_t *rsc = data;
195 pcmk_node_t *node = NULL;
196
197
198 if (rsc->priv->children != NULL) {
199 g_list_foreach(rsc->priv->children, apply_stickiness, NULL);
200 return;
201 }
202
203
204
205
206 if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)
207 || (rsc->priv->stickiness < 1)
208 || !pcmk__list_of_1(rsc->priv->active_nodes)) {
209 return;
210 }
211
212 node = rsc->priv->active_nodes->data;
213
214
215
216
217
218
219 if (!pcmk_is_set(rsc->priv->scheduler->flags,
220 pcmk__sched_symmetric_cluster)
221 && (g_hash_table_lookup(rsc->priv->allowed_nodes,
222 node->priv->id) == NULL)) {
223 pcmk__rsc_debug(rsc,
224 "Ignoring %s stickiness because the cluster is "
225 "asymmetric and %s is not explicitly allowed",
226 rsc->id, pcmk__node_name(node));
227 return;
228 }
229
230 pcmk__rsc_debug(rsc, "Resource %s has %d stickiness on %s",
231 rsc->id, rsc->priv->stickiness, pcmk__node_name(node));
232 resource_location(rsc, node, rsc->priv->stickiness, "stickiness",
233 rsc->priv->scheduler);
234 }
235
236
237
238
239
240
241
242 static void
243 apply_shutdown_locks(pcmk_scheduler_t *scheduler)
244 {
245 if (!pcmk_is_set(scheduler->flags, pcmk__sched_shutdown_lock)) {
246 return;
247 }
248 for (GList *iter = scheduler->priv->resources;
249 iter != NULL; iter = iter->next) {
250
251 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
252
253 rsc->priv->cmds->shutdown_lock(rsc);
254 }
255 }
256
257
258
259
260
261
262
263
264
265 static void
266 apply_node_criteria(pcmk_scheduler_t *scheduler)
267 {
268 crm_trace("Applying node-specific scheduling criteria");
269 apply_shutdown_locks(scheduler);
270 pcmk__apply_locations(scheduler);
271 g_list_foreach(scheduler->priv->resources, apply_stickiness, NULL);
272
273 for (GList *node_iter = scheduler->nodes; node_iter != NULL;
274 node_iter = node_iter->next) {
275
276 for (GList *rsc_iter = scheduler->priv->resources;
277 rsc_iter != NULL; rsc_iter = rsc_iter->next) {
278
279 check_failure_threshold(rsc_iter->data, node_iter->data);
280 apply_exclusive_discovery(rsc_iter->data, node_iter->data);
281 }
282 }
283 }
284
285
286
287
288
289
290
291 static void
292 assign_resources(pcmk_scheduler_t *scheduler)
293 {
294 GList *iter = NULL;
295
296 crm_trace("Assigning resources to nodes");
297
298 if (!pcmk__str_eq(scheduler->priv->placement_strategy, PCMK_VALUE_DEFAULT,
299 pcmk__str_casei)) {
300 pcmk__sort_resources(scheduler);
301 }
302 pcmk__show_node_capacities("Original", scheduler);
303
304 if (pcmk_is_set(scheduler->flags, pcmk__sched_have_remote_nodes)) {
305
306
307
308
309 for (iter = scheduler->priv->resources;
310 iter != NULL; iter = iter->next) {
311
312 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
313 const pcmk_node_t *target = rsc->priv->partial_migration_target;
314
315 if (pcmk_is_set(rsc->flags, pcmk__rsc_is_remote_connection)) {
316 pcmk__rsc_trace(rsc, "Assigning remote connection resource '%s'",
317 rsc->id);
318 rsc->priv->cmds->assign(rsc, target, true);
319 }
320 }
321 }
322
323
324 for (iter = scheduler->priv->resources; iter != NULL; iter = iter->next) {
325 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
326
327 if (!pcmk_is_set(rsc->flags, pcmk__rsc_is_remote_connection)) {
328 pcmk__rsc_trace(rsc, "Assigning %s resource '%s'",
329 rsc->priv->xml->name, rsc->id);
330 rsc->priv->cmds->assign(rsc, NULL, true);
331 }
332 }
333
334 pcmk__show_node_capacities("Remaining", scheduler);
335 }
336
337
338
339
340
341
342
343
344 static void
345 clear_failcounts_if_orphaned(gpointer data, gpointer user_data)
346 {
347 pcmk_resource_t *rsc = data;
348
349 if (!pcmk_is_set(rsc->flags, pcmk__rsc_removed)) {
350 return;
351 }
352 crm_trace("Clear fail counts for orphaned resource %s", rsc->id);
353
354
355
356
357
358 for (GList *iter = rsc->priv->scheduler->nodes;
359 iter != NULL; iter = iter->next) {
360
361 pcmk_node_t *node = (pcmk_node_t *) iter->data;
362 pcmk_action_t *clear_op = NULL;
363
364 if (!node->details->online) {
365 continue;
366 }
367 if (pe_get_failcount(node, rsc, NULL, pcmk__fc_effective, NULL) == 0) {
368 continue;
369 }
370
371 clear_op = pe__clear_failcount(rsc, node, "it is orphaned",
372 rsc->priv->scheduler);
373
374
375
376
377 pcmk__new_ordering(clear_op->rsc, NULL, clear_op, rsc, stop_key(rsc),
378 NULL, pcmk__ar_ordered, rsc->priv->scheduler);
379 }
380 }
381
382
383
384
385
386
387
388 static void
389 schedule_resource_actions(pcmk_scheduler_t *scheduler)
390 {
391
392 pcmk__foreach_param_check(scheduler, check_params);
393 pcmk__free_param_checks(scheduler);
394
395 if (pcmk_is_set(scheduler->flags, pcmk__sched_probe_resources)) {
396 crm_trace("Scheduling probes");
397 pcmk__schedule_probes(scheduler);
398 }
399
400 if (pcmk_is_set(scheduler->flags, pcmk__sched_stop_removed_resources)) {
401 g_list_foreach(scheduler->priv->resources, clear_failcounts_if_orphaned,
402 NULL);
403 }
404
405 crm_trace("Scheduling resource actions");
406 for (GList *iter = scheduler->priv->resources;
407 iter != NULL; iter = iter->next) {
408
409 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
410
411 rsc->priv->cmds->create_actions(rsc);
412 }
413 }
414
415
416
417
418
419
420
421
422
423 static bool
424 is_managed(const pcmk_resource_t *rsc)
425 {
426 if (pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
427 return true;
428 }
429 for (GList *iter = rsc->priv->children;
430 iter != NULL; iter = iter->next) {
431
432 if (is_managed((pcmk_resource_t *) iter->data)) {
433 return true;
434 }
435 }
436 return false;
437 }
438
439
440
441
442
443
444
445
446
447 static bool
448 any_managed_resources(const pcmk_scheduler_t *scheduler)
449 {
450 for (const GList *iter = scheduler->priv->resources;
451 iter != NULL; iter = iter->next) {
452 if (is_managed((const pcmk_resource_t *) iter->data)) {
453 return true;
454 }
455 }
456 return false;
457 }
458
459
460
461
462
463
464
465
466
467
468 static bool
469 needs_fencing(const pcmk_node_t *node, bool have_managed)
470 {
471 return have_managed && node->details->unclean
472 && pe_can_fence(node->priv->scheduler, node);
473 }
474
475
476
477
478
479
480
481
482
483 static bool
484 needs_shutdown(const pcmk_node_t *node)
485 {
486 if (pcmk__is_pacemaker_remote_node(node)) {
487
488
489
490 return false;
491 }
492 return node->details->online && node->details->shutdown;
493 }
494
495
496
497
498
499
500
501
502
503
504
505 static GList *
506 add_nondc_fencing(GList *list, pcmk_action_t *action,
507 const pcmk_scheduler_t *scheduler)
508 {
509 if (!pcmk_is_set(scheduler->flags, pcmk__sched_concurrent_fencing)
510 && (list != NULL)) {
511
512
513
514
515
516 order_actions((pcmk_action_t *) list->data, action, pcmk__ar_ordered);
517 }
518 return g_list_prepend(list, action);
519 }
520
521
522
523
524
525
526
527 static pcmk_action_t *
528 schedule_fencing(pcmk_node_t *node)
529 {
530 pcmk_action_t *fencing = pe_fence_op(node, NULL, FALSE, "node is unclean",
531 FALSE, node->priv->scheduler);
532
533 pcmk__sched_warn(node->priv->scheduler, "Scheduling node %s for fencing",
534 pcmk__node_name(node));
535 pcmk__order_vs_fence(fencing, node->priv->scheduler);
536 return fencing;
537 }
538
539
540
541
542
543
544
545 static void
546 schedule_fencing_and_shutdowns(pcmk_scheduler_t *scheduler)
547 {
548 pcmk_action_t *dc_down = NULL;
549 bool integrity_lost = false;
550 bool have_managed = any_managed_resources(scheduler);
551 GList *fencing_ops = NULL;
552 GList *shutdown_ops = NULL;
553
554 crm_trace("Scheduling fencing and shutdowns as needed");
555 if (!have_managed) {
556 crm_notice("No fencing will be done until there are resources "
557 "to manage");
558 }
559
560
561 for (GList *iter = scheduler->nodes; iter != NULL; iter = iter->next) {
562 pcmk_node_t *node = (pcmk_node_t *) iter->data;
563 pcmk_action_t *fencing = NULL;
564 const bool is_dc = pcmk__same_node(node, scheduler->dc_node);
565
566
567
568
569 if (pcmk__is_guest_or_bundle_node(node)) {
570 if (pcmk_is_set(node->priv->flags, pcmk__node_remote_reset)
571 && have_managed && pe_can_fence(scheduler, node)) {
572 pcmk__fence_guest(node);
573 }
574 continue;
575 }
576
577 if (needs_fencing(node, have_managed)) {
578 fencing = schedule_fencing(node);
579
580
581 if (is_dc) {
582 dc_down = fencing;
583 } else {
584 fencing_ops = add_nondc_fencing(fencing_ops, fencing,
585 scheduler);
586 }
587
588 } else if (needs_shutdown(node)) {
589 pcmk_action_t *down_op = pcmk__new_shutdown_action(node);
590
591
592 if (is_dc) {
593 dc_down = down_op;
594 } else {
595 shutdown_ops = g_list_prepend(shutdown_ops, down_op);
596 }
597 }
598
599 if ((fencing == NULL) && node->details->unclean) {
600 integrity_lost = true;
601 pcmk__config_warn("Node %s is unclean but cannot be fenced",
602 pcmk__node_name(node));
603 }
604 }
605
606 if (integrity_lost) {
607 if (!pcmk_is_set(scheduler->flags, pcmk__sched_fencing_enabled)) {
608 pcmk__config_warn("Resource functionality and data integrity "
609 "cannot be guaranteed (configure, enable, "
610 "and test fencing to correct this)");
611
612 } else if (!pcmk_is_set(scheduler->flags, pcmk__sched_quorate)) {
613 crm_notice("Unclean nodes will not be fenced until quorum is "
614 "attained or " PCMK_OPT_NO_QUORUM_POLICY " is set to "
615 PCMK_VALUE_IGNORE);
616 }
617 }
618
619 if (dc_down != NULL) {
620
621
622
623
624
625
626
627 if (pcmk__str_eq(dc_down->task, PCMK_ACTION_DO_SHUTDOWN,
628 pcmk__str_none)) {
629 pcmk__order_after_each(dc_down, shutdown_ops);
630 }
631
632
633
634 if (pcmk_is_set(scheduler->flags, pcmk__sched_concurrent_fencing)) {
635
636
637
638 pcmk__order_after_each(dc_down, fencing_ops);
639 } else if (fencing_ops != NULL) {
640
641
642
643
644
645 order_actions((pcmk_action_t *) fencing_ops->data, dc_down,
646 pcmk__ar_ordered);
647 }
648 }
649 g_list_free(fencing_ops);
650 g_list_free(shutdown_ops);
651 }
652
653 static void
654 log_resource_details(pcmk_scheduler_t *scheduler)
655 {
656 pcmk__output_t *out = scheduler->priv->out;
657 GList *all = NULL;
658
659
660
661
662
663 all = g_list_prepend(all, (gpointer) "*");
664
665 for (GList *item = scheduler->priv->resources;
666 item != NULL; item = item->next) {
667
668 pcmk_resource_t *rsc = (pcmk_resource_t *) item->data;
669
670
671 if (!pcmk_is_set(rsc->flags, pcmk__rsc_removed)
672 || (rsc->priv->orig_role != pcmk_role_stopped)) {
673 out->message(out, (const char *) rsc->priv->xml->name, 0UL,
674 rsc, all, all);
675 }
676 }
677
678 g_list_free(all);
679 }
680
681 static void
682 log_all_actions(pcmk_scheduler_t *scheduler)
683 {
684
685
686
687 pcmk__output_t *prev_out = scheduler->priv->out;
688 pcmk__output_t *out = NULL;
689
690 if (pcmk__log_output_new(&out) != pcmk_rc_ok) {
691 return;
692 }
693
694 pe__register_messages(out);
695 pcmk__register_lib_messages(out);
696 pcmk__output_set_log_level(out, LOG_NOTICE);
697 scheduler->priv->out = out;
698
699 out->begin_list(out, NULL, NULL, "Actions");
700 pcmk__output_actions(scheduler);
701 out->end_list(out);
702 out->finish(out, CRM_EX_OK, true, NULL);
703 pcmk__output_free(out);
704
705 scheduler->priv->out = prev_out;
706 }
707
708
709
710
711
712
713
714 static void
715 log_unrunnable_actions(const pcmk_scheduler_t *scheduler)
716 {
717 const uint64_t flags = pcmk__action_optional
718 |pcmk__action_runnable
719 |pcmk__action_pseudo;
720
721 crm_trace("Required but unrunnable actions:");
722 for (const GList *iter = scheduler->priv->actions;
723 iter != NULL; iter = iter->next) {
724
725 const pcmk_action_t *action = (const pcmk_action_t *) iter->data;
726
727 if (!pcmk_any_flags_set(action->flags, flags)) {
728 pcmk__log_action("\t", action, true);
729 }
730 }
731 }
732
733
734
735
736
737
738
739 void
740 pcmk__schedule_actions(pcmk_scheduler_t *scheduler)
741 {
742 cluster_status(scheduler);
743 pcmk__set_assignment_methods(scheduler);
744 pcmk__apply_node_health(scheduler);
745 pcmk__unpack_constraints(scheduler);
746 if (pcmk_is_set(scheduler->flags, pcmk__sched_validate_only)) {
747 return;
748 }
749
750 if (!pcmk_is_set(scheduler->flags, pcmk__sched_location_only)
751 && pcmk__is_daemon) {
752 log_resource_details(scheduler);
753 }
754
755 apply_node_criteria(scheduler);
756
757 if (pcmk_is_set(scheduler->flags, pcmk__sched_location_only)) {
758 return;
759 }
760
761 pcmk__create_internal_constraints(scheduler);
762 pcmk__handle_rsc_config_changes(scheduler);
763 assign_resources(scheduler);
764 schedule_resource_actions(scheduler);
765
766
767
768
769 pcmk__order_remote_connection_actions(scheduler);
770
771 schedule_fencing_and_shutdowns(scheduler);
772 pcmk__apply_orderings(scheduler);
773 log_all_actions(scheduler);
774 pcmk__create_graph(scheduler);
775
776 if (get_crm_log_level() == LOG_TRACE) {
777 log_unrunnable_actions(scheduler);
778 }
779 }
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802 int
803 pcmk__init_scheduler(pcmk__output_t *out, xmlNodePtr input, const crm_time_t *date,
804 pcmk_scheduler_t **scheduler)
805 {
806
807 pcmk_scheduler_t *new_scheduler = NULL;
808
809 new_scheduler = pcmk_new_scheduler();
810 if (new_scheduler == NULL) {
811 return ENOMEM;
812 }
813
814 pcmk__set_scheduler_flags(new_scheduler, pcmk__sched_no_counts);
815
816
817
818
819 if (input != NULL) {
820 new_scheduler->input = pcmk__xml_copy(NULL, input);
821 if (new_scheduler->input == NULL) {
822 out->err(out, "Failed to copy input XML");
823 pcmk_free_scheduler(new_scheduler);
824 return ENOMEM;
825 }
826
827 } else {
828 int rc = cib__signon_query(out, NULL, &(new_scheduler->input));
829
830 if (rc != pcmk_rc_ok) {
831 pcmk_free_scheduler(new_scheduler);
832 return rc;
833 }
834 }
835
836
837
838 if (date != NULL) {
839
840 new_scheduler->priv->now = pcmk_copy_time(date);
841 }
842
843
844 cluster_status(new_scheduler);
845 *scheduler = new_scheduler;
846
847 return pcmk_rc_ok;
848 }