This source file includes following definitions.
- check_params
- failcount_clear_action_exists
- check_failure_threshold
- apply_exclusive_discovery
- apply_stickiness
- apply_shutdown_locks
- count_available_nodes
- 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
- unpack_cib
- 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->cluster);
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->details->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->cluster);
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->children != NULL) {
119 g_list_foreach(rsc->children, check_failure_threshold, user_data);
120 return;
121 }
122
123 if (!failcount_clear_action_exists(node, rsc)) {
124
125
126
127
128
129
130
131
132
133
134 pcmk_resource_t *failed = NULL;
135
136 if (pcmk__threshold_reached(rsc, node, &failed)) {
137 resource_location(failed, node, -PCMK_SCORE_INFINITY,
138 "__fail_limit__", rsc->cluster);
139 }
140 }
141 }
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 static void
157 apply_exclusive_discovery(gpointer data, gpointer user_data)
158 {
159 pcmk_resource_t *rsc = data;
160 const pcmk_node_t *node = user_data;
161
162 if (rsc->exclusive_discover
163 || pe__const_top_resource(rsc, false)->exclusive_discover) {
164 pcmk_node_t *match = NULL;
165
166
167 g_list_foreach(rsc->children, apply_exclusive_discovery, user_data);
168
169 match = g_hash_table_lookup(rsc->allowed_nodes, node->details->id);
170 if ((match != NULL)
171 && (match->rsc_discover_mode != pcmk_probe_exclusive)) {
172 match->weight = -PCMK_SCORE_INFINITY;
173 }
174 }
175 }
176
177
178
179
180
181
182
183
184 static void
185 apply_stickiness(gpointer data, gpointer user_data)
186 {
187 pcmk_resource_t *rsc = data;
188 pcmk_node_t *node = NULL;
189
190
191 if (rsc->children != NULL) {
192 g_list_foreach(rsc->children, apply_stickiness, NULL);
193 return;
194 }
195
196
197
198
199 if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)
200 || (rsc->stickiness < 1) || !pcmk__list_of_1(rsc->running_on)) {
201 return;
202 }
203
204 node = rsc->running_on->data;
205
206
207
208
209
210
211 if (!pcmk_is_set(rsc->cluster->flags, pcmk_sched_symmetric_cluster)
212 && (g_hash_table_lookup(rsc->allowed_nodes,
213 node->details->id) == NULL)) {
214 pcmk__rsc_debug(rsc,
215 "Ignoring %s stickiness because the cluster is "
216 "asymmetric and %s is not explicitly allowed",
217 rsc->id, pcmk__node_name(node));
218 return;
219 }
220
221 pcmk__rsc_debug(rsc, "Resource %s has %d stickiness on %s",
222 rsc->id, rsc->stickiness, pcmk__node_name(node));
223 resource_location(rsc, node, rsc->stickiness, "stickiness", rsc->cluster);
224 }
225
226
227
228
229
230
231
232 static void
233 apply_shutdown_locks(pcmk_scheduler_t *scheduler)
234 {
235 if (!pcmk_is_set(scheduler->flags, pcmk_sched_shutdown_lock)) {
236 return;
237 }
238 for (GList *iter = scheduler->resources; iter != NULL; iter = iter->next) {
239 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
240
241 rsc->cmds->shutdown_lock(rsc);
242 }
243 }
244
245
246
247
248
249
250
251 static void
252 count_available_nodes(pcmk_scheduler_t *scheduler)
253 {
254 if (pcmk_is_set(scheduler->flags, pcmk_sched_no_compat)) {
255 return;
256 }
257
258
259 for (GList *iter = scheduler->nodes; iter != NULL; iter = iter->next) {
260 pcmk_node_t *node = (pcmk_node_t *) iter->data;
261
262 if ((node != NULL) && (node->weight >= 0) && node->details->online
263 && (node->details->type != node_ping)) {
264 scheduler->max_valid_nodes++;
265 }
266 }
267 crm_trace("Online node count: %d", scheduler->max_valid_nodes);
268 }
269
270
271
272
273
274
275
276
277
278 static void
279 apply_node_criteria(pcmk_scheduler_t *scheduler)
280 {
281 crm_trace("Applying node-specific scheduling criteria");
282 apply_shutdown_locks(scheduler);
283 count_available_nodes(scheduler);
284 pcmk__apply_locations(scheduler);
285 g_list_foreach(scheduler->resources, apply_stickiness, NULL);
286
287 for (GList *node_iter = scheduler->nodes; node_iter != NULL;
288 node_iter = node_iter->next) {
289 for (GList *rsc_iter = scheduler->resources; rsc_iter != NULL;
290 rsc_iter = rsc_iter->next) {
291 check_failure_threshold(rsc_iter->data, node_iter->data);
292 apply_exclusive_discovery(rsc_iter->data, node_iter->data);
293 }
294 }
295 }
296
297
298
299
300
301
302
303 static void
304 assign_resources(pcmk_scheduler_t *scheduler)
305 {
306 GList *iter = NULL;
307
308 crm_trace("Assigning resources to nodes");
309
310 if (!pcmk__str_eq(scheduler->placement_strategy, PCMK_VALUE_DEFAULT,
311 pcmk__str_casei)) {
312 pcmk__sort_resources(scheduler);
313 }
314 pcmk__show_node_capacities("Original", scheduler);
315
316 if (pcmk_is_set(scheduler->flags, pcmk_sched_have_remote_nodes)) {
317
318
319
320
321 for (iter = scheduler->resources; iter != NULL; iter = iter->next) {
322 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
323
324 if (rsc->is_remote_node) {
325 pcmk__rsc_trace(rsc, "Assigning remote connection resource '%s'",
326 rsc->id);
327 rsc->cmds->assign(rsc, rsc->partial_migration_target, true);
328 }
329 }
330 }
331
332
333 for (iter = scheduler->resources; iter != NULL; iter = iter->next) {
334 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
335
336 if (!rsc->is_remote_node) {
337 pcmk__rsc_trace(rsc, "Assigning %s resource '%s'",
338 rsc->xml->name, rsc->id);
339 rsc->cmds->assign(rsc, NULL, true);
340 }
341 }
342
343 pcmk__show_node_capacities("Remaining", scheduler);
344 }
345
346
347
348
349
350
351
352
353 static void
354 clear_failcounts_if_orphaned(gpointer data, gpointer user_data)
355 {
356 pcmk_resource_t *rsc = data;
357
358 if (!pcmk_is_set(rsc->flags, pcmk_rsc_removed)) {
359 return;
360 }
361 crm_trace("Clear fail counts for orphaned resource %s", rsc->id);
362
363
364
365
366
367 for (GList *iter = rsc->cluster->nodes; iter != NULL; iter = iter->next) {
368 pcmk_node_t *node = (pcmk_node_t *) iter->data;
369 pcmk_action_t *clear_op = NULL;
370
371 if (!node->details->online) {
372 continue;
373 }
374 if (pe_get_failcount(node, rsc, NULL, pcmk__fc_effective, NULL) == 0) {
375 continue;
376 }
377
378 clear_op = pe__clear_failcount(rsc, node, "it is orphaned",
379 rsc->cluster);
380
381
382
383
384 pcmk__new_ordering(clear_op->rsc, NULL, clear_op, rsc, stop_key(rsc),
385 NULL, pcmk__ar_ordered, rsc->cluster);
386 }
387 }
388
389
390
391
392
393
394
395 static void
396 schedule_resource_actions(pcmk_scheduler_t *scheduler)
397 {
398
399 pe__foreach_param_check(scheduler, check_params);
400 pe__free_param_checks(scheduler);
401
402 if (pcmk_is_set(scheduler->flags, pcmk_sched_probe_resources)) {
403 crm_trace("Scheduling probes");
404 pcmk__schedule_probes(scheduler);
405 }
406
407 if (pcmk_is_set(scheduler->flags, pcmk_sched_stop_removed_resources)) {
408 g_list_foreach(scheduler->resources, clear_failcounts_if_orphaned,
409 NULL);
410 }
411
412 crm_trace("Scheduling resource actions");
413 for (GList *iter = scheduler->resources; iter != NULL; iter = iter->next) {
414 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
415
416 rsc->cmds->create_actions(rsc);
417 }
418 }
419
420
421
422
423
424
425
426
427
428 static bool
429 is_managed(const pcmk_resource_t *rsc)
430 {
431 if (pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
432 return true;
433 }
434 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
435 if (is_managed((pcmk_resource_t *) iter->data)) {
436 return true;
437 }
438 }
439 return false;
440 }
441
442
443
444
445
446
447
448
449
450 static bool
451 any_managed_resources(const pcmk_scheduler_t *scheduler)
452 {
453 for (const GList *iter = scheduler->resources;
454 iter != NULL; iter = iter->next) {
455 if (is_managed((const pcmk_resource_t *) iter->data)) {
456 return true;
457 }
458 }
459 return false;
460 }
461
462
463
464
465
466
467
468
469
470
471 static bool
472 needs_fencing(const pcmk_node_t *node, bool have_managed)
473 {
474 return have_managed && node->details->unclean
475 && pe_can_fence(node->details->data_set, node);
476 }
477
478
479
480
481
482
483
484
485
486 static bool
487 needs_shutdown(const pcmk_node_t *node)
488 {
489 if (pcmk__is_pacemaker_remote_node(node)) {
490
491
492
493 return false;
494 }
495 return node->details->online && node->details->shutdown;
496 }
497
498
499
500
501
502
503
504
505
506
507
508 static GList *
509 add_nondc_fencing(GList *list, pcmk_action_t *action,
510 const pcmk_scheduler_t *scheduler)
511 {
512 if (!pcmk_is_set(scheduler->flags, pcmk_sched_concurrent_fencing)
513 && (list != NULL)) {
514
515
516
517
518
519 order_actions((pcmk_action_t *) list->data, action, pcmk__ar_ordered);
520 }
521 return g_list_prepend(list, action);
522 }
523
524
525
526
527
528
529
530 static pcmk_action_t *
531 schedule_fencing(pcmk_node_t *node)
532 {
533 pcmk_action_t *fencing = pe_fence_op(node, NULL, FALSE, "node is unclean",
534 FALSE, node->details->data_set);
535
536 pcmk__sched_warn("Scheduling node %s for fencing", pcmk__node_name(node));
537 pcmk__order_vs_fence(fencing, node->details->data_set);
538 return fencing;
539 }
540
541
542
543
544
545
546
547 static void
548 schedule_fencing_and_shutdowns(pcmk_scheduler_t *scheduler)
549 {
550 pcmk_action_t *dc_down = NULL;
551 bool integrity_lost = false;
552 bool have_managed = any_managed_resources(scheduler);
553 GList *fencing_ops = NULL;
554 GList *shutdown_ops = NULL;
555
556 crm_trace("Scheduling fencing and shutdowns as needed");
557 if (!have_managed) {
558 crm_notice("No fencing will be done until there are resources "
559 "to manage");
560 }
561
562
563 for (GList *iter = scheduler->nodes; iter != NULL; iter = iter->next) {
564 pcmk_node_t *node = (pcmk_node_t *) iter->data;
565 pcmk_action_t *fencing = NULL;
566
567
568
569
570 if (pcmk__is_guest_or_bundle_node(node)) {
571 if (node->details->remote_requires_reset && have_managed
572 && pe_can_fence(scheduler, node)) {
573 pcmk__fence_guest(node);
574 }
575 continue;
576 }
577
578 if (needs_fencing(node, have_managed)) {
579 fencing = schedule_fencing(node);
580
581
582 if (node->details->is_dc) {
583 dc_down = fencing;
584 } else {
585 fencing_ops = add_nondc_fencing(fencing_ops, fencing,
586 scheduler);
587 }
588
589 } else if (needs_shutdown(node)) {
590 pcmk_action_t *down_op = pcmk__new_shutdown_action(node);
591
592
593 if (node->details->is_dc) {
594 dc_down = down_op;
595 } else {
596 shutdown_ops = g_list_prepend(shutdown_ops, down_op);
597 }
598 }
599
600 if ((fencing == NULL) && node->details->unclean) {
601 integrity_lost = true;
602 pcmk__config_warn("Node %s is unclean but cannot be fenced",
603 pcmk__node_name(node));
604 }
605 }
606
607 if (integrity_lost) {
608 if (!pcmk_is_set(scheduler->flags, pcmk_sched_fencing_enabled)) {
609 pcmk__config_warn("Resource functionality and data integrity "
610 "cannot be guaranteed (configure, enable, "
611 "and test fencing to correct this)");
612
613 } else if (!pcmk_is_set(scheduler->flags, pcmk_sched_quorate)) {
614 crm_notice("Unclean nodes will not be fenced until quorum is "
615 "attained or " PCMK_OPT_NO_QUORUM_POLICY " is set to "
616 PCMK_VALUE_IGNORE);
617 }
618 }
619
620 if (dc_down != NULL) {
621
622
623
624
625
626
627
628 if (pcmk__str_eq(dc_down->task, PCMK_ACTION_DO_SHUTDOWN,
629 pcmk__str_none)) {
630 pcmk__order_after_each(dc_down, shutdown_ops);
631 }
632
633
634
635 if (pcmk_is_set(scheduler->flags, pcmk_sched_concurrent_fencing)) {
636
637
638
639 pcmk__order_after_each(dc_down, fencing_ops);
640 } else if (fencing_ops != NULL) {
641
642
643
644
645
646 order_actions((pcmk_action_t *) fencing_ops->data, dc_down,
647 pcmk__ar_ordered);
648 }
649 }
650 g_list_free(fencing_ops);
651 g_list_free(shutdown_ops);
652 }
653
654 static void
655 log_resource_details(pcmk_scheduler_t *scheduler)
656 {
657 pcmk__output_t *out = scheduler->priv;
658 GList *all = NULL;
659
660
661
662
663
664 all = g_list_prepend(all, (gpointer) "*");
665
666 for (GList *item = scheduler->resources; item != NULL; item = item->next) {
667 pcmk_resource_t *rsc = (pcmk_resource_t *) item->data;
668
669
670 if (!pcmk_is_set(rsc->flags, pcmk_rsc_removed)
671 || (rsc->role != pcmk_role_stopped)) {
672 out->message(out, pcmk__map_element_name(rsc->xml), 0UL, rsc, all,
673 all);
674 }
675 }
676
677 g_list_free(all);
678 }
679
680 static void
681 log_all_actions(pcmk_scheduler_t *scheduler)
682 {
683
684
685
686 pcmk__output_t *prev_out = scheduler->priv;
687 pcmk__output_t *out = NULL;
688
689 if (pcmk__log_output_new(&out) != pcmk_rc_ok) {
690 return;
691 }
692
693 pe__register_messages(out);
694 pcmk__register_lib_messages(out);
695 pcmk__output_set_log_level(out, LOG_NOTICE);
696 scheduler->priv = out;
697
698 out->begin_list(out, NULL, NULL, "Actions");
699 pcmk__output_actions(scheduler);
700 out->end_list(out);
701 out->finish(out, CRM_EX_OK, true, NULL);
702 pcmk__output_free(out);
703
704 scheduler->priv = prev_out;
705 }
706
707
708
709
710
711
712
713 static void
714 log_unrunnable_actions(const pcmk_scheduler_t *scheduler)
715 {
716 const uint64_t flags = pcmk_action_optional
717 |pcmk_action_runnable
718 |pcmk_action_pseudo;
719
720 crm_trace("Required but unrunnable actions:");
721 for (const GList *iter = scheduler->actions;
722 iter != NULL; iter = iter->next) {
723
724 const pcmk_action_t *action = (const pcmk_action_t *) iter->data;
725
726 if (!pcmk_any_flags_set(action->flags, flags)) {
727 pcmk__log_action("\t", action, true);
728 }
729 }
730 }
731
732
733
734
735
736
737
738
739
740 static void
741 unpack_cib(xmlNode *cib, unsigned long long flags, pcmk_scheduler_t *scheduler)
742 {
743 const char* localhost_save = NULL;
744
745 if (pcmk_is_set(scheduler->flags, pcmk_sched_have_status)) {
746 crm_trace("Reusing previously calculated cluster status");
747 pcmk__set_scheduler_flags(scheduler, flags);
748 return;
749 }
750
751 if (scheduler->localhost) {
752 localhost_save = scheduler->localhost;
753 }
754
755 pcmk__assert(cib != NULL);
756 crm_trace("Calculating cluster status");
757
758
759
760
761
762
763 set_working_set_defaults(scheduler);
764
765 if (localhost_save) {
766 scheduler->localhost = localhost_save;
767 }
768
769 pcmk__set_scheduler_flags(scheduler, flags);
770 scheduler->input = cib;
771 cluster_status(scheduler);
772 }
773
774
775
776
777
778
779
780
781
782 void
783 pcmk__schedule_actions(xmlNode *cib, unsigned long long flags,
784 pcmk_scheduler_t *scheduler)
785 {
786 unpack_cib(cib, flags, scheduler);
787 pcmk__set_assignment_methods(scheduler);
788 pcmk__apply_node_health(scheduler);
789 pcmk__unpack_constraints(scheduler);
790 if (pcmk_is_set(scheduler->flags, pcmk_sched_validate_only)) {
791 return;
792 }
793
794 if (!pcmk_is_set(scheduler->flags, pcmk_sched_location_only)
795 && pcmk__is_daemon) {
796 log_resource_details(scheduler);
797 }
798
799 apply_node_criteria(scheduler);
800
801 if (pcmk_is_set(scheduler->flags, pcmk_sched_location_only)) {
802 return;
803 }
804
805 pcmk__create_internal_constraints(scheduler);
806 pcmk__handle_rsc_config_changes(scheduler);
807 assign_resources(scheduler);
808 schedule_resource_actions(scheduler);
809
810
811
812
813 pcmk__order_remote_connection_actions(scheduler);
814
815 schedule_fencing_and_shutdowns(scheduler);
816 pcmk__apply_orderings(scheduler);
817 log_all_actions(scheduler);
818 pcmk__create_graph(scheduler);
819
820 if (get_crm_log_level() == LOG_TRACE) {
821 log_unrunnable_actions(scheduler);
822 }
823 }
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846 int
847 pcmk__init_scheduler(pcmk__output_t *out, xmlNodePtr input, const crm_time_t *date,
848 pcmk_scheduler_t **scheduler)
849 {
850
851 pcmk_scheduler_t *new_scheduler = NULL;
852
853 new_scheduler = pe_new_working_set();
854 if (new_scheduler == NULL) {
855 return ENOMEM;
856 }
857
858 pcmk__set_scheduler_flags(new_scheduler,
859 pcmk_sched_no_counts|pcmk_sched_no_compat);
860
861
862
863
864 if (input != NULL) {
865 new_scheduler->input = pcmk__xml_copy(NULL, input);
866 if (new_scheduler->input == NULL) {
867 out->err(out, "Failed to copy input XML");
868 pe_free_working_set(new_scheduler);
869 return ENOMEM;
870 }
871
872 } else {
873 int rc = cib__signon_query(out, NULL, &(new_scheduler->input));
874
875 if (rc != pcmk_rc_ok) {
876 pe_free_working_set(new_scheduler);
877 return rc;
878 }
879 }
880
881
882
883 if (date != NULL) {
884
885 new_scheduler->now = pcmk_copy_time(date);
886 }
887
888
889 cluster_status(new_scheduler);
890 *scheduler = new_scheduler;
891
892 return pcmk_rc_ok;
893 }