This source file includes following definitions.
- sorted_allowed_nodes
- assign_best_node
- apply_this_with
- remote_connection_assigned
- pcmk__primitive_assign
- schedule_restart_actions
- set_default_next_role
- create_pending_start
- schedule_role_transition_actions
- pcmk__primitive_create_actions
- rsc_avoids_remote_nodes
- allowed_nodes_as_list
- pcmk__primitive_internal_constraints
- pcmk__primitive_apply_coloc_score
- pcmk__with_primitive_colocations
- pcmk__primitive_with_colocations
- pcmk__primitive_action_flags
- is_expected_node
- stop_resource
- start_resource
- promote_resource
- demote_resource
- assert_role_error
- pcmk__schedule_cleanup
- pcmk__primitive_add_graph_meta
- pcmk__primitive_add_utilization
- shutdown_time
- ban_if_not_locked
- pcmk__primitive_shutdown_lock
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdbool.h>
13 #include <stdint.h>
14
15 #include <crm/common/xml.h>
16 #include <pacemaker-internal.h>
17
18 #include "libpacemaker_private.h"
19
20 static void stop_resource(pcmk_resource_t *rsc, pcmk_node_t *node,
21 bool optional);
22 static void start_resource(pcmk_resource_t *rsc, pcmk_node_t *node,
23 bool optional);
24 static void demote_resource(pcmk_resource_t *rsc, pcmk_node_t *node,
25 bool optional);
26 static void promote_resource(pcmk_resource_t *rsc, pcmk_node_t *node,
27 bool optional);
28 static void assert_role_error(pcmk_resource_t *rsc, pcmk_node_t *node,
29 bool optional);
30
31 #define RSC_ROLE_MAX (pcmk_role_promoted + 1)
32
33 static enum rsc_role_e rsc_state_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX] = {
34
35
36
37
38
39
40
41
42
43 { pcmk_role_unknown,
44 pcmk_role_stopped,
45 pcmk_role_stopped,
46 pcmk_role_stopped,
47 pcmk_role_stopped,
48 },
49 { pcmk_role_stopped,
50 pcmk_role_stopped,
51 pcmk_role_started,
52 pcmk_role_unpromoted,
53 pcmk_role_unpromoted,
54 },
55 { pcmk_role_stopped,
56 pcmk_role_stopped,
57 pcmk_role_started,
58 pcmk_role_unpromoted,
59 pcmk_role_promoted,
60 },
61 { pcmk_role_stopped,
62 pcmk_role_stopped,
63 pcmk_role_stopped,
64 pcmk_role_unpromoted,
65 pcmk_role_promoted,
66 },
67 { pcmk_role_stopped,
68 pcmk_role_unpromoted,
69 pcmk_role_unpromoted,
70 pcmk_role_unpromoted,
71 pcmk_role_promoted,
72 },
73 };
74
75
76
77
78
79
80
81
82
83 typedef void (*rsc_transition_fn)(pcmk_resource_t *rsc, pcmk_node_t *node,
84 bool optional);
85
86 static rsc_transition_fn rsc_action_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX] = {
87
88
89
90
91
92
93 { assert_role_error,
94 stop_resource,
95 assert_role_error,
96 assert_role_error,
97 assert_role_error,
98 },
99 { assert_role_error,
100 NULL,
101 start_resource,
102 start_resource,
103 assert_role_error,
104 },
105 { assert_role_error,
106 stop_resource,
107 NULL,
108 NULL,
109 promote_resource,
110 },
111 { assert_role_error,
112 stop_resource,
113 stop_resource,
114 NULL,
115 promote_resource,
116 },
117 { assert_role_error,
118 demote_resource,
119 demote_resource,
120 demote_resource,
121 NULL,
122 },
123 };
124
125
126
127
128
129
130
131
132
133 static GList *
134 sorted_allowed_nodes(const pcmk_resource_t *rsc)
135 {
136 if (rsc->priv->allowed_nodes != NULL) {
137 GList *nodes = g_hash_table_get_values(rsc->priv->allowed_nodes);
138
139 if (nodes != NULL) {
140 return pcmk__sort_nodes(nodes, pcmk__current_node(rsc));
141 }
142 }
143 return NULL;
144 }
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165 static bool
166 assign_best_node(pcmk_resource_t *rsc, const pcmk_node_t *prefer,
167 bool stop_if_fail)
168 {
169 GList *nodes = NULL;
170 pcmk_node_t *chosen = NULL;
171 pcmk_node_t *best = NULL;
172 const pcmk_node_t *most_free_node = pcmk__ban_insufficient_capacity(rsc);
173
174 if (prefer == NULL) {
175 prefer = most_free_node;
176 }
177
178 if (!pcmk_is_set(rsc->flags, pcmk__rsc_unassigned)) {
179
180 return rsc->priv->assigned_node != NULL;
181 }
182
183
184 nodes = sorted_allowed_nodes(rsc);
185 if (nodes != NULL) {
186 best = (pcmk_node_t *) nodes->data;
187 }
188
189 if ((prefer != NULL) && (nodes != NULL)) {
190
191 chosen = g_hash_table_lookup(rsc->priv->allowed_nodes,
192 prefer->priv->id);
193
194 if (chosen == NULL) {
195 pcmk__rsc_trace(rsc, "Preferred node %s for %s was unknown",
196 pcmk__node_name(prefer), rsc->id);
197
198
199
200
201
202
203
204 } else if (chosen->assign->score < best->assign->score) {
205 pcmk__rsc_trace(rsc, "Preferred node %s for %s was unsuitable",
206 pcmk__node_name(chosen), rsc->id);
207 chosen = NULL;
208
209 } else if (!pcmk__node_available(chosen, true, false)) {
210 pcmk__rsc_trace(rsc, "Preferred node %s for %s was unavailable",
211 pcmk__node_name(chosen), rsc->id);
212 chosen = NULL;
213
214 } else {
215 pcmk__rsc_trace(rsc,
216 "Chose preferred node %s for %s "
217 "(ignoring %d candidates)",
218 pcmk__node_name(chosen), rsc->id,
219 g_list_length(nodes));
220 }
221 }
222
223 if ((chosen == NULL) && (best != NULL)) {
224
225
226
227
228 chosen = best;
229
230 if (!pcmk__is_unique_clone(rsc->priv->parent)
231 && (chosen->assign->score > 0)
232 && pcmk__node_available(chosen, false, false)) {
233
234
235
236
237
238
239
240
241
242 pcmk_node_t *running = pcmk__current_node(rsc);
243
244 if (running == NULL) {
245
246
247 } else if (!pcmk__node_available(running, true, false)) {
248 pcmk__rsc_trace(rsc,
249 "Current node for %s (%s) can't run resources",
250 rsc->id, pcmk__node_name(running));
251
252 } else {
253 int nodes_with_best_score = 1;
254
255 for (GList *iter = nodes->next; iter; iter = iter->next) {
256 pcmk_node_t *allowed = (pcmk_node_t *) iter->data;
257
258 if (allowed->assign->score != chosen->assign->score) {
259
260 break;
261 }
262 if (pcmk__same_node(allowed, running)) {
263
264 chosen = allowed;
265 }
266 nodes_with_best_score++;
267 }
268
269 if (nodes_with_best_score > 1) {
270 uint8_t log_level = LOG_INFO;
271
272 if (chosen->assign->score >= PCMK_SCORE_INFINITY) {
273 log_level = LOG_WARNING;
274 }
275 do_crm_log(log_level,
276 "Chose %s for %s from %d nodes with score %s",
277 pcmk__node_name(chosen), rsc->id,
278 nodes_with_best_score,
279 pcmk_readable_score(chosen->assign->score));
280 }
281 }
282 }
283
284 pcmk__rsc_trace(rsc, "Chose %s for %s from %d candidates",
285 pcmk__node_name(chosen), rsc->id, g_list_length(nodes));
286 }
287
288 pcmk__assign_resource(rsc, chosen, false, stop_if_fail);
289 g_list_free(nodes);
290 return rsc->priv->assigned_node != NULL;
291 }
292
293
294
295
296
297
298
299
300 static void
301 apply_this_with(pcmk__colocation_t *colocation, pcmk_resource_t *rsc)
302 {
303 GHashTable *archive = NULL;
304 pcmk_resource_t *other = colocation->primary;
305
306
307 if ((colocation->dependent_role >= pcmk_role_promoted)
308 || ((colocation->score < 0)
309 && (colocation->score > -PCMK_SCORE_INFINITY))) {
310 archive = pcmk__copy_node_table(rsc->priv->allowed_nodes);
311 }
312
313 if (pcmk_is_set(other->flags, pcmk__rsc_unassigned)) {
314 pcmk__rsc_trace(rsc,
315 "%s: Assigning colocation %s primary %s first"
316 "(score=%d role=%s)",
317 rsc->id, colocation->id, other->id,
318 colocation->score,
319 pcmk_role_text(colocation->dependent_role));
320 other->priv->cmds->assign(other, NULL, true);
321 }
322
323
324 rsc->priv->cmds->apply_coloc_score(rsc, other, colocation, true);
325 if ((archive != NULL)
326 && !pcmk__any_node_available(rsc->priv->allowed_nodes)) {
327 pcmk__rsc_info(rsc,
328 "%s: Reverting scores from colocation with %s "
329 "because no nodes allowed",
330 rsc->id, other->id);
331 g_hash_table_destroy(rsc->priv->allowed_nodes);
332 rsc->priv->allowed_nodes = archive;
333 archive = NULL;
334 }
335 if (archive != NULL) {
336 g_hash_table_destroy(archive);
337 }
338 }
339
340
341
342
343
344
345
346 static void
347 remote_connection_assigned(const pcmk_resource_t *connection)
348 {
349 pcmk_node_t *remote_node = pcmk_find_node(connection->priv->scheduler,
350 connection->id);
351
352 CRM_CHECK(remote_node != NULL, return);
353
354 if ((connection->priv->assigned_node != NULL)
355 && (connection->priv->next_role != pcmk_role_stopped)) {
356
357 crm_trace("Pacemaker Remote node %s will be online",
358 remote_node->priv->id);
359 remote_node->details->online = TRUE;
360 if (!pcmk_is_set(remote_node->priv->flags, pcmk__node_seen)) {
361
362 remote_node->details->unclean = FALSE;
363 }
364
365 } else {
366 crm_trace("Pacemaker Remote node %s will be shut down "
367 "(%sassigned connection's next role is %s)",
368 remote_node->priv->id,
369 ((connection->priv->assigned_node == NULL)? "un" : ""),
370 pcmk_role_text(connection->priv->next_role));
371 remote_node->details->shutdown = TRUE;
372 }
373 }
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393 pcmk_node_t *
394 pcmk__primitive_assign(pcmk_resource_t *rsc, const pcmk_node_t *prefer,
395 bool stop_if_fail)
396 {
397 GList *this_with_colocations = NULL;
398 GList *with_this_colocations = NULL;
399 GList *iter = NULL;
400 pcmk_resource_t *parent = NULL;
401 pcmk__colocation_t *colocation = NULL;
402 pcmk_scheduler_t *scheduler = NULL;
403
404 pcmk__assert(pcmk__is_primitive(rsc));
405 scheduler = rsc->priv->scheduler;
406 parent = rsc->priv->parent;
407
408
409 if ((parent != NULL) && !pcmk_is_set(parent->flags, pcmk__rsc_assigning)) {
410 pcmk__rsc_debug(rsc, "%s: Assigning parent %s first",
411 rsc->id, parent->id);
412 parent->priv->cmds->assign(parent, prefer, stop_if_fail);
413 }
414
415 if (!pcmk_is_set(rsc->flags, pcmk__rsc_unassigned)) {
416
417 const char *node_name = "no node";
418
419 if (rsc->priv->assigned_node != NULL) {
420 node_name = pcmk__node_name(rsc->priv->assigned_node);
421 }
422 pcmk__rsc_debug(rsc, "%s: pre-assigned to %s", rsc->id, node_name);
423 return rsc->priv->assigned_node;
424 }
425
426
427 if (pcmk_is_set(rsc->flags, pcmk__rsc_assigning)) {
428 pcmk__rsc_debug(rsc, "Breaking assignment loop involving %s", rsc->id);
429 return NULL;
430 }
431 pcmk__set_rsc_flags(rsc, pcmk__rsc_assigning);
432
433 pe__show_node_scores(true, rsc, "Pre-assignment",
434 rsc->priv->allowed_nodes, scheduler);
435
436 this_with_colocations = pcmk__this_with_colocations(rsc);
437 with_this_colocations = pcmk__with_this_colocations(rsc);
438
439
440 for (iter = this_with_colocations; iter != NULL; iter = iter->next) {
441 colocation = iter->data;
442
443 if ((colocation->score <= -PCMK_SCORE_INFINITY)
444 || (colocation->score >= PCMK_SCORE_INFINITY)) {
445 apply_this_with(colocation, rsc);
446 }
447 }
448 for (iter = with_this_colocations; iter != NULL; iter = iter->next) {
449 colocation = iter->data;
450
451 if ((colocation->score <= -PCMK_SCORE_INFINITY)
452 || (colocation->score >= PCMK_SCORE_INFINITY)) {
453 pcmk__add_dependent_scores(colocation, rsc);
454 }
455 }
456
457 pe__show_node_scores(true, rsc, "Mandatory-colocations",
458 rsc->priv->allowed_nodes, scheduler);
459
460
461 for (iter = this_with_colocations; iter != NULL; iter = iter->next) {
462 colocation = iter->data;
463
464 if ((colocation->score > -PCMK_SCORE_INFINITY)
465 && (colocation->score < PCMK_SCORE_INFINITY)) {
466 apply_this_with(colocation, rsc);
467 }
468 }
469 for (iter = with_this_colocations; iter != NULL; iter = iter->next) {
470 colocation = iter->data;
471
472 if ((colocation->score > -PCMK_SCORE_INFINITY)
473 && (colocation->score < PCMK_SCORE_INFINITY)) {
474 pcmk__add_dependent_scores(colocation, rsc);
475 }
476 }
477
478 g_list_free(this_with_colocations);
479 g_list_free(with_this_colocations);
480
481 if (rsc->priv->next_role == pcmk_role_stopped) {
482 pcmk__rsc_trace(rsc,
483 "Banning %s from all nodes because it will be stopped",
484 rsc->id);
485 resource_location(rsc, NULL, -PCMK_SCORE_INFINITY,
486 PCMK_META_TARGET_ROLE, scheduler);
487
488 } else if ((rsc->priv->next_role > rsc->priv->orig_role)
489 && !pcmk_is_set(scheduler->flags, pcmk__sched_quorate)
490 && (scheduler->no_quorum_policy == pcmk_no_quorum_freeze)) {
491 crm_notice("Resource %s cannot be elevated from %s to %s due to "
492 PCMK_OPT_NO_QUORUM_POLICY "=" PCMK_VALUE_FREEZE,
493 rsc->id, pcmk_role_text(rsc->priv->orig_role),
494 pcmk_role_text(rsc->priv->next_role));
495 pe__set_next_role(rsc, rsc->priv->orig_role,
496 PCMK_OPT_NO_QUORUM_POLICY "=" PCMK_VALUE_FREEZE);
497 }
498
499 pe__show_node_scores(!pcmk_is_set(scheduler->flags,
500 pcmk__sched_output_scores),
501 rsc, __func__, rsc->priv->allowed_nodes, scheduler);
502
503
504 if (pcmk_is_set(scheduler->flags, pcmk__sched_fencing_enabled)
505 && !pcmk_is_set(scheduler->flags, pcmk__sched_have_fencing)) {
506 pcmk__clear_rsc_flags(rsc, pcmk__rsc_managed);
507 }
508
509 if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
510
511 const char *reason = NULL;
512 pcmk_node_t *assign_to = NULL;
513
514 pe__set_next_role(rsc, rsc->priv->orig_role, "unmanaged");
515 assign_to = pcmk__current_node(rsc);
516 if (assign_to == NULL) {
517 reason = "inactive";
518 } else if (rsc->priv->orig_role == pcmk_role_promoted) {
519 reason = "promoted";
520 } else if (pcmk_is_set(rsc->flags, pcmk__rsc_failed)) {
521 reason = "failed";
522 } else {
523 reason = "active";
524 }
525 pcmk__rsc_info(rsc, "Unmanaged resource %s assigned to %s: %s", rsc->id,
526 (assign_to? assign_to->priv->name : "no node"),
527 reason);
528 pcmk__assign_resource(rsc, assign_to, true, stop_if_fail);
529
530 } else if (pcmk_is_set(scheduler->flags, pcmk__sched_stop_all)) {
531
532 if (stop_if_fail) {
533 pcmk__rsc_debug(rsc,
534 "Forcing %s to stop: " PCMK_OPT_STOP_ALL_RESOURCES,
535 rsc->id);
536 }
537 pcmk__assign_resource(rsc, NULL, true, stop_if_fail);
538
539 } else if (!assign_best_node(rsc, prefer, stop_if_fail)) {
540
541 if (!pcmk_is_set(rsc->flags, pcmk__rsc_removed)) {
542 pcmk__rsc_info(rsc, "Resource %s cannot run anywhere", rsc->id);
543 } else if ((rsc->priv->active_nodes != NULL) && stop_if_fail) {
544 pcmk__rsc_info(rsc, "Stopping removed resource %s", rsc->id);
545 }
546 }
547
548 pcmk__clear_rsc_flags(rsc, pcmk__rsc_assigning);
549
550 if (pcmk_is_set(rsc->flags, pcmk__rsc_is_remote_connection)) {
551 remote_connection_assigned(rsc);
552 }
553
554 return rsc->priv->assigned_node;
555 }
556
557
558
559
560
561
562
563
564
565
566
567
568 static void
569 schedule_restart_actions(pcmk_resource_t *rsc, pcmk_node_t *current,
570 bool need_stop, bool need_promote)
571 {
572 enum rsc_role_e role = rsc->priv->orig_role;
573 enum rsc_role_e next_role;
574 rsc_transition_fn fn = NULL;
575
576 pcmk__set_rsc_flags(rsc, pcmk__rsc_restarting);
577
578
579 while (role != pcmk_role_stopped) {
580 next_role = rsc_state_matrix[role][pcmk_role_stopped];
581 pcmk__rsc_trace(rsc, "Creating %s action to take %s down from %s to %s",
582 (need_stop? "required" : "optional"), rsc->id,
583 pcmk_role_text(role), pcmk_role_text(next_role));
584 fn = rsc_action_matrix[role][next_role];
585 if (fn == NULL) {
586 break;
587 }
588 fn(rsc, current, !need_stop);
589 role = next_role;
590 }
591
592
593 while ((rsc->priv->orig_role <= rsc->priv->next_role)
594 && (role != rsc->priv->orig_role)
595 && !pcmk_is_set(rsc->flags, pcmk__rsc_blocked)) {
596 bool required = need_stop;
597
598 next_role = rsc_state_matrix[role][rsc->priv->orig_role];
599 if ((next_role == pcmk_role_promoted) && need_promote) {
600 required = true;
601 }
602 pcmk__rsc_trace(rsc, "Creating %s action to take %s up from %s to %s",
603 (required? "required" : "optional"), rsc->id,
604 pcmk_role_text(role), pcmk_role_text(next_role));
605 fn = rsc_action_matrix[role][next_role];
606 if (fn == NULL) {
607 break;
608 }
609 fn(rsc, rsc->priv->assigned_node, !required);
610 role = next_role;
611 }
612
613 pcmk__clear_rsc_flags(rsc, pcmk__rsc_restarting);
614 }
615
616
617
618
619
620
621
622
623
624 static const char *
625 set_default_next_role(pcmk_resource_t *rsc)
626 {
627 if (rsc->priv->next_role != pcmk_role_unknown) {
628 return "explicit";
629 }
630
631 if (rsc->priv->assigned_node == NULL) {
632 pe__set_next_role(rsc, pcmk_role_stopped, "assignment");
633 } else {
634 pe__set_next_role(rsc, pcmk_role_started, "assignment");
635 }
636 return "implicit";
637 }
638
639
640
641
642
643
644
645 static void
646 create_pending_start(pcmk_resource_t *rsc)
647 {
648 pcmk_action_t *start = NULL;
649
650 pcmk__rsc_trace(rsc,
651 "Creating action for %s to represent already pending start",
652 rsc->id);
653 start = start_action(rsc, rsc->priv->assigned_node, TRUE);
654 pcmk__set_action_flags(start, pcmk__action_always_in_graph);
655 }
656
657
658
659
660
661
662
663 static void
664 schedule_role_transition_actions(pcmk_resource_t *rsc)
665 {
666 enum rsc_role_e role = rsc->priv->orig_role;
667
668 while (role != rsc->priv->next_role) {
669 enum rsc_role_e next_role =
670 rsc_state_matrix[role][rsc->priv->next_role];
671 rsc_transition_fn fn = NULL;
672
673 pcmk__rsc_trace(rsc,
674 "Creating action to take %s from %s to %s "
675 "(ending at %s)",
676 rsc->id, pcmk_role_text(role),
677 pcmk_role_text(next_role),
678 pcmk_role_text(rsc->priv->next_role));
679 fn = rsc_action_matrix[role][next_role];
680 if (fn == NULL) {
681 break;
682 }
683 fn(rsc, rsc->priv->assigned_node, false);
684 role = next_role;
685 }
686 }
687
688
689
690
691
692
693
694 void
695 pcmk__primitive_create_actions(pcmk_resource_t *rsc)
696 {
697 bool need_stop = false;
698 bool need_promote = false;
699 bool is_moving = false;
700 bool allow_migrate = false;
701 bool multiply_active = false;
702
703 pcmk_node_t *current = NULL;
704 pcmk_node_t *migration_target = NULL;
705 unsigned int num_all_active = 0;
706 unsigned int num_clean_active = 0;
707 const char *next_role_source = NULL;
708
709 pcmk__assert(pcmk__is_primitive(rsc));
710
711 next_role_source = set_default_next_role(rsc);
712 pcmk__rsc_trace(rsc,
713 "Creating all actions for %s transition from %s to %s "
714 "(%s) on %s",
715 rsc->id, pcmk_role_text(rsc->priv->orig_role),
716 pcmk_role_text(rsc->priv->next_role), next_role_source,
717 pcmk__node_name(rsc->priv->assigned_node));
718
719 current = rsc->priv->fns->active_node(rsc, &num_all_active,
720 &num_clean_active);
721
722 g_list_foreach(rsc->priv->dangling_migration_sources,
723 pcmk__abort_dangling_migration, rsc);
724
725 if ((current != NULL) && (rsc->priv->assigned_node != NULL)
726 && !pcmk__same_node(current, rsc->priv->assigned_node)
727 && (rsc->priv->next_role >= pcmk_role_started)) {
728
729 pcmk__rsc_trace(rsc, "Moving %s from %s to %s",
730 rsc->id, pcmk__node_name(current),
731 pcmk__node_name(rsc->priv->assigned_node));
732 is_moving = true;
733 allow_migrate = pcmk__rsc_can_migrate(rsc, current);
734
735
736 need_stop = true;
737 }
738
739
740 migration_target = rsc->priv->partial_migration_target;
741 if ((rsc->priv->partial_migration_source != NULL)
742 && (migration_target != NULL) && allow_migrate && (num_all_active == 2)
743 && pcmk__same_node(current, rsc->priv->partial_migration_source)
744 && pcmk__same_node(rsc->priv->assigned_node, migration_target)) {
745
746
747
748 pcmk__rsc_trace(rsc,
749 "Partial migration of %s from %s to %s will continue",
750 rsc->id,
751 pcmk__node_name(rsc->priv->partial_migration_source),
752 pcmk__node_name(migration_target));
753
754 } else if ((rsc->priv->partial_migration_source != NULL)
755 || (migration_target != NULL)) {
756
757
758 if (num_all_active > 2) {
759
760 crm_notice("Forcing recovery of %s because it is migrating "
761 "from %s to %s and possibly active elsewhere",
762 rsc->id,
763 pcmk__node_name(rsc->priv->partial_migration_source),
764 pcmk__node_name(migration_target));
765 } else {
766
767 crm_notice("Forcing recovery of %s because it can no longer "
768 "migrate from %s to %s",
769 rsc->id,
770 pcmk__node_name(rsc->priv->partial_migration_source),
771 pcmk__node_name(migration_target));
772 }
773 need_stop = true;
774 rsc->priv->partial_migration_source = NULL;
775 rsc->priv->partial_migration_target = NULL;
776 allow_migrate = false;
777
778 } else if (pcmk_is_set(rsc->flags, pcmk__rsc_needs_fencing)) {
779 multiply_active = (num_all_active > 1);
780 } else {
781
782
783
784
785
786
787
788 multiply_active = (num_clean_active > 1);
789 }
790
791 if (multiply_active) {
792 const char *class = crm_element_value(rsc->priv->xml, PCMK_XA_CLASS);
793
794
795 pcmk__sched_err(rsc->priv->scheduler,
796 "%s resource %s might be active on %u nodes (%s)",
797 pcmk__s(class, "Untyped"), rsc->id, num_all_active,
798 pcmk__multiply_active_text(rsc));
799 crm_notice("For more information, see \"What are multiply active "
800 "resources?\" at "
801 "https://projects.clusterlabs.org/w/clusterlabs/faq/");
802
803 switch (rsc->priv->multiply_active_policy) {
804 case pcmk__multiply_active_restart:
805 need_stop = true;
806 break;
807 case pcmk__multiply_active_unexpected:
808 need_stop = true;
809 pcmk__set_rsc_flags(rsc, pcmk__rsc_stop_unexpected);
810 break;
811 default:
812 break;
813 }
814
815 } else {
816 pcmk__clear_rsc_flags(rsc, pcmk__rsc_stop_unexpected);
817 }
818
819 if (pcmk_is_set(rsc->flags, pcmk__rsc_start_pending)) {
820 create_pending_start(rsc);
821 }
822
823 if (is_moving) {
824
825
826 } else if (pcmk_is_set(rsc->flags, pcmk__rsc_failed)) {
827 if (pcmk_is_set(rsc->flags, pcmk__rsc_stop_if_failed)) {
828 need_stop = true;
829 pcmk__rsc_trace(rsc, "Recovering %s", rsc->id);
830 } else {
831 pcmk__rsc_trace(rsc, "Recovering %s by demotion", rsc->id);
832 if (rsc->priv->next_role == pcmk_role_promoted) {
833 need_promote = true;
834 }
835 }
836
837 } else if (pcmk_is_set(rsc->flags, pcmk__rsc_blocked)) {
838 pcmk__rsc_trace(rsc, "Blocking further actions on %s", rsc->id);
839 need_stop = true;
840
841 } else if ((rsc->priv->orig_role > pcmk_role_started)
842 && (current != NULL)
843 && (rsc->priv->assigned_node != NULL)) {
844 pcmk_action_t *start = NULL;
845
846 pcmk__rsc_trace(rsc, "Creating start action for promoted resource %s",
847 rsc->id);
848 start = start_action(rsc, rsc->priv->assigned_node, TRUE);
849 if (!pcmk_is_set(start->flags, pcmk__action_optional)) {
850
851 pcmk__rsc_trace(rsc, "%s restart is required for recovery", rsc->id);
852 need_stop = true;
853 }
854 }
855
856
857 schedule_restart_actions(rsc, current, need_stop, need_promote);
858
859
860 schedule_role_transition_actions(rsc);
861
862 pcmk__create_recurring_actions(rsc);
863
864 if (allow_migrate) {
865 pcmk__create_migration_actions(rsc, current);
866 }
867 }
868
869
870
871
872
873
874
875 static void
876 rsc_avoids_remote_nodes(const pcmk_resource_t *rsc)
877 {
878 GHashTableIter iter;
879 pcmk_node_t *node = NULL;
880
881 g_hash_table_iter_init(&iter, rsc->priv->allowed_nodes);
882 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
883 if (node->priv->remote != NULL) {
884 node->assign->score = -PCMK_SCORE_INFINITY;
885 }
886 }
887 }
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902 static GList *
903 allowed_nodes_as_list(const pcmk_resource_t *rsc)
904 {
905 GList *allowed_nodes = NULL;
906
907 if (rsc->priv->allowed_nodes != NULL) {
908 allowed_nodes = g_hash_table_get_values(rsc->priv->allowed_nodes);
909 }
910
911 if (!pcmk__is_daemon) {
912 allowed_nodes = g_list_sort(allowed_nodes, pe__cmp_node_name);
913 }
914
915 return allowed_nodes;
916 }
917
918
919
920
921
922
923
924 void
925 pcmk__primitive_internal_constraints(pcmk_resource_t *rsc)
926 {
927 GList *allowed_nodes = NULL;
928 bool check_unfencing = false;
929 bool check_utilization = false;
930 pcmk_scheduler_t *scheduler = NULL;
931
932 pcmk__assert(pcmk__is_primitive(rsc));
933 scheduler = rsc->priv->scheduler;
934
935 if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
936 pcmk__rsc_trace(rsc,
937 "Skipping implicit constraints for unmanaged resource "
938 "%s", rsc->id);
939 return;
940 }
941
942
943 check_unfencing = !pcmk_is_set(rsc->flags, pcmk__rsc_fence_device)
944 && pcmk_is_set(scheduler->flags,
945 pcmk__sched_enable_unfencing)
946 && pcmk_is_set(rsc->flags, pcmk__rsc_needs_unfencing);
947
948
949 check_utilization = (g_hash_table_size(rsc->priv->utilization) > 0)
950 && !pcmk__str_eq(scheduler->priv->placement_strategy,
951 PCMK_VALUE_DEFAULT, pcmk__str_casei);
952
953
954 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_STOP, 0), NULL,
955 rsc, pcmk__op_key(rsc->id, PCMK_ACTION_START, 0), NULL,
956 pcmk__ar_ordered
957 |pcmk__ar_first_implies_then
958 |pcmk__ar_intermediate_stop, scheduler);
959
960
961 if (pcmk_is_set(pe__const_top_resource(rsc, false)->flags,
962 pcmk__rsc_promotable)
963 || (rsc->priv->orig_role > pcmk_role_unpromoted)) {
964
965 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_DEMOTE, 0),
966 NULL,
967 rsc, pcmk__op_key(rsc->id, PCMK_ACTION_STOP, 0),
968 NULL,
969 pcmk__ar_promoted_then_implies_first, scheduler);
970
971 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_START, 0),
972 NULL,
973 rsc, pcmk__op_key(rsc->id, PCMK_ACTION_PROMOTE, 0),
974 NULL,
975 pcmk__ar_unrunnable_first_blocks, scheduler);
976 }
977
978
979 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_LRM_DELETE, 0),
980 NULL, rsc,
981 pcmk__op_key(rsc->id, PCMK_ACTION_MONITOR, 0),
982 NULL,
983 pcmk__ar_if_on_same_node|pcmk__ar_then_cancels_first,
984 scheduler);
985
986
987 if (check_unfencing || check_utilization
988 || (rsc->priv->launcher != NULL)) {
989
990 allowed_nodes = allowed_nodes_as_list(rsc);
991 }
992
993 if (check_unfencing) {
994 g_list_foreach(allowed_nodes, pcmk__order_restart_vs_unfence, rsc);
995 }
996
997 if (check_utilization) {
998 pcmk__create_utilization_constraints(rsc, allowed_nodes);
999 }
1000
1001 if (rsc->priv->launcher != NULL) {
1002 pcmk_resource_t *remote_rsc = NULL;
1003
1004 if (pcmk_is_set(rsc->flags, pcmk__rsc_is_remote_connection)) {
1005
1006
1007
1008
1009
1010 if (!pcmk_is_set(rsc->flags, pcmk__rsc_remote_nesting_allowed)) {
1011 rsc_avoids_remote_nodes(rsc->priv->launcher);
1012 }
1013
1014
1015
1016
1017
1018
1019
1020 pcmk__order_resource_actions(rsc->priv->launcher,
1021 PCMK_ACTION_MONITOR,
1022 rsc, PCMK_ACTION_STOP,
1023 pcmk__ar_ordered);
1024
1025
1026
1027
1028
1029
1030
1031
1032 } else if (pcmk_is_set(rsc->priv->launcher->flags,
1033 pcmk__rsc_is_remote_connection)) {
1034 remote_rsc = rsc->priv->launcher;
1035 } else {
1036 remote_rsc =
1037 pe__resource_contains_guest_node(scheduler,
1038 rsc->priv->launcher);
1039 }
1040
1041 if (remote_rsc != NULL) {
1042
1043
1044
1045 for (GList *item = allowed_nodes; item; item = item->next) {
1046 pcmk_node_t *node = item->data;
1047
1048 if (node->priv->remote != remote_rsc) {
1049 node->assign->score = -PCMK_SCORE_INFINITY;
1050 }
1051 }
1052
1053 } else {
1054
1055
1056
1057
1058 int score;
1059
1060 crm_trace("Order and colocate %s relative to its launcher %s",
1061 rsc->id, rsc->priv->launcher->id);
1062
1063 pcmk__new_ordering(rsc->priv->launcher,
1064 pcmk__op_key(rsc->priv->launcher->id,
1065 PCMK_ACTION_START, 0),
1066 NULL, rsc,
1067 pcmk__op_key(rsc->id, PCMK_ACTION_START, 0),
1068 NULL,
1069 pcmk__ar_first_implies_then
1070 |pcmk__ar_unrunnable_first_blocks, scheduler);
1071
1072 pcmk__new_ordering(rsc,
1073 pcmk__op_key(rsc->id, PCMK_ACTION_STOP, 0),
1074 NULL,
1075 rsc->priv->launcher,
1076 pcmk__op_key(rsc->priv->launcher->id,
1077 PCMK_ACTION_STOP, 0),
1078 NULL, pcmk__ar_then_implies_first, scheduler);
1079
1080 if (pcmk_is_set(rsc->flags, pcmk__rsc_remote_nesting_allowed)
1081 ) {
1082 score = 10000;
1083 } else {
1084 score = PCMK_SCORE_INFINITY;
1085 }
1086 pcmk__new_colocation("#resource-with-container", NULL, score, rsc,
1087 rsc->priv->launcher, NULL, NULL,
1088 pcmk__coloc_influence);
1089 }
1090 }
1091
1092 if (pcmk_is_set(rsc->flags, pcmk__rsc_is_remote_connection)
1093 || pcmk_is_set(rsc->flags, pcmk__rsc_fence_device)) {
1094
1095
1096
1097 rsc_avoids_remote_nodes(rsc);
1098 }
1099 g_list_free(allowed_nodes);
1100 }
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117 int
1118 pcmk__primitive_apply_coloc_score(pcmk_resource_t *dependent,
1119 const pcmk_resource_t *primary,
1120 const pcmk__colocation_t *colocation,
1121 bool for_dependent)
1122 {
1123 enum pcmk__coloc_affects filter_results;
1124
1125 pcmk__assert((dependent != NULL) && (primary != NULL)
1126 && (colocation != NULL));
1127
1128 if (for_dependent) {
1129
1130 return primary->priv->cmds->apply_coloc_score(dependent, primary,
1131 colocation, false);
1132 }
1133
1134 filter_results = pcmk__colocation_affects(dependent, primary, colocation,
1135 false);
1136 pcmk__rsc_trace(dependent, "%s %s with %s (%s, score=%d, filter=%d)",
1137 ((colocation->score > 0)? "Colocating" : "Anti-colocating"),
1138 dependent->id, primary->id, colocation->id,
1139 colocation->score,
1140 filter_results);
1141
1142 switch (filter_results) {
1143 case pcmk__coloc_affects_role:
1144 return pcmk__apply_coloc_to_priority(dependent, primary,
1145 colocation);
1146
1147 case pcmk__coloc_affects_location:
1148 pcmk__apply_coloc_to_scores(dependent, primary, colocation);
1149 return 0;
1150
1151 default:
1152 return 0;
1153 }
1154 }
1155
1156
1157
1158
1159 void
1160 pcmk__with_primitive_colocations(const pcmk_resource_t *rsc,
1161 const pcmk_resource_t *orig_rsc, GList **list)
1162 {
1163 const pcmk_resource_t *parent = NULL;
1164
1165 pcmk__assert(pcmk__is_primitive(rsc) && (list != NULL));
1166 parent = rsc->priv->parent;
1167
1168 if (rsc == orig_rsc) {
1169
1170
1171
1172 pcmk__add_with_this_list(list, rsc->priv->with_this_colocations,
1173 orig_rsc);
1174 if (parent != NULL) {
1175 parent->priv->cmds->with_this_colocations(parent, orig_rsc, list);
1176 }
1177 } else {
1178
1179 for (GList *iter = rsc->priv->with_this_colocations;
1180 iter != NULL; iter = iter->next) {
1181 pcmk__colocation_t *colocation = iter->data;
1182
1183 if (pcmk_is_set(colocation->flags, pcmk__coloc_explicit)) {
1184 pcmk__add_with_this(list, colocation, orig_rsc);
1185 }
1186 }
1187 }
1188 }
1189
1190
1191
1192
1193 void
1194 pcmk__primitive_with_colocations(const pcmk_resource_t *rsc,
1195 const pcmk_resource_t *orig_rsc, GList **list)
1196 {
1197 const pcmk_resource_t *parent = NULL;
1198
1199 pcmk__assert(pcmk__is_primitive(rsc) && (list != NULL));
1200 parent = rsc->priv->parent;
1201
1202 if (rsc == orig_rsc) {
1203
1204
1205
1206 pcmk__add_this_with_list(list, rsc->priv->this_with_colocations,
1207 orig_rsc);
1208 if (parent != NULL) {
1209 parent->priv->cmds->this_with_colocations(parent, orig_rsc, list);
1210 }
1211 } else {
1212
1213 for (GList *iter = rsc->priv->this_with_colocations;
1214 iter != NULL; iter = iter->next) {
1215 pcmk__colocation_t *colocation = iter->data;
1216
1217 if (pcmk_is_set(colocation->flags, pcmk__coloc_explicit)) {
1218 pcmk__add_this_with(list, colocation, orig_rsc);
1219 }
1220 }
1221 }
1222 }
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233 uint32_t
1234 pcmk__primitive_action_flags(pcmk_action_t *action, const pcmk_node_t *node)
1235 {
1236 pcmk__assert(action != NULL);
1237 return (uint32_t) action->flags;
1238 }
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254 static bool
1255 is_expected_node(const pcmk_resource_t *rsc, const pcmk_node_t *node)
1256 {
1257 return pcmk_all_flags_set(rsc->flags,
1258 pcmk__rsc_stop_unexpected|pcmk__rsc_restarting)
1259 && (rsc->priv->next_role > pcmk_role_stopped)
1260 && pcmk__same_node(rsc->priv->assigned_node, node);
1261 }
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271 static void
1272 stop_resource(pcmk_resource_t *rsc, pcmk_node_t *node, bool optional)
1273 {
1274 for (GList *iter = rsc->priv->active_nodes;
1275 iter != NULL; iter = iter->next) {
1276
1277 pcmk_node_t *current = (pcmk_node_t *) iter->data;
1278 pcmk_action_t *stop = NULL;
1279
1280 if (is_expected_node(rsc, current)) {
1281
1282
1283
1284
1285 pcmk__rsc_trace(rsc,
1286 "Skipping stop of multiply active resource %s "
1287 "on expected node %s",
1288 rsc->id, pcmk__node_name(current));
1289 continue;
1290 }
1291
1292 if (rsc->priv->partial_migration_target != NULL) {
1293
1294 if (pcmk__same_node(current, rsc->priv->partial_migration_target)
1295 && pcmk__same_node(current, rsc->priv->assigned_node)) {
1296 pcmk__rsc_trace(rsc,
1297 "Skipping stop of %s on %s "
1298 "because partial migration there will continue",
1299 rsc->id, pcmk__node_name(current));
1300 continue;
1301 } else {
1302 pcmk__rsc_trace(rsc,
1303 "Forcing stop of %s on %s "
1304 "because migration target changed",
1305 rsc->id, pcmk__node_name(current));
1306 optional = false;
1307 }
1308 }
1309
1310 pcmk__rsc_trace(rsc, "Scheduling stop of %s on %s",
1311 rsc->id, pcmk__node_name(current));
1312 stop = stop_action(rsc, current, optional);
1313
1314 if (rsc->priv->assigned_node == NULL) {
1315 pe_action_set_reason(stop, "node availability", true);
1316 } else if (pcmk_all_flags_set(rsc->flags, pcmk__rsc_restarting
1317 |pcmk__rsc_stop_unexpected)) {
1318
1319
1320
1321
1322 pe_action_set_reason(stop, "being multiply active", true);
1323 }
1324
1325 if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
1326 pcmk__clear_action_flags(stop, pcmk__action_runnable);
1327 }
1328
1329 if (pcmk_is_set(rsc->flags, pcmk__rsc_needs_unfencing)) {
1330 pcmk_action_t *unfence = pe_fence_op(current, PCMK_ACTION_ON, true,
1331 NULL, false,
1332 rsc->priv->scheduler);
1333
1334 order_actions(stop, unfence, pcmk__ar_then_implies_first);
1335 if (!pcmk__node_unfenced(current)) {
1336 pcmk__sched_err(rsc->priv->scheduler,
1337 "Stopping %s until %s can be unfenced",
1338 rsc->id, pcmk__node_name(current));
1339 }
1340 }
1341 }
1342 }
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352 static void
1353 start_resource(pcmk_resource_t *rsc, pcmk_node_t *node, bool optional)
1354 {
1355 pcmk_action_t *start = NULL;
1356
1357 pcmk__assert(node != NULL);
1358
1359 pcmk__rsc_trace(rsc, "Scheduling %s start of %s on %s (score %d)",
1360 (optional? "optional" : "required"), rsc->id,
1361 pcmk__node_name(node), node->assign->score);
1362 start = start_action(rsc, node, TRUE);
1363
1364 pcmk__order_vs_unfence(rsc, node, start, pcmk__ar_first_implies_then);
1365
1366 if (pcmk_is_set(start->flags, pcmk__action_runnable) && !optional) {
1367 pcmk__clear_action_flags(start, pcmk__action_optional);
1368 }
1369
1370 if (is_expected_node(rsc, node)) {
1371
1372
1373
1374 pcmk__rsc_trace(rsc,
1375 "Start of multiply active resouce %s "
1376 "on expected node %s will be a pseudo-action",
1377 rsc->id, pcmk__node_name(node));
1378 pcmk__set_action_flags(start, pcmk__action_pseudo);
1379 }
1380 }
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390 static void
1391 promote_resource(pcmk_resource_t *rsc, pcmk_node_t *node, bool optional)
1392 {
1393 GList *iter = NULL;
1394 GList *action_list = NULL;
1395 bool runnable = true;
1396
1397 pcmk__assert(node != NULL);
1398
1399
1400 action_list = pe__resource_actions(rsc, node, PCMK_ACTION_START, true);
1401 for (iter = action_list; iter != NULL; iter = iter->next) {
1402 pcmk_action_t *start = (pcmk_action_t *) iter->data;
1403
1404 if (!pcmk_is_set(start->flags, pcmk__action_runnable)) {
1405 runnable = false;
1406 }
1407 }
1408 g_list_free(action_list);
1409
1410 if (runnable) {
1411 pcmk_action_t *promote = promote_action(rsc, node, optional);
1412
1413 pcmk__rsc_trace(rsc, "Scheduling %s promotion of %s on %s",
1414 (optional? "optional" : "required"), rsc->id,
1415 pcmk__node_name(node));
1416
1417 if (is_expected_node(rsc, node)) {
1418
1419
1420
1421 pcmk__rsc_trace(rsc,
1422 "Promotion of multiply active resouce %s "
1423 "on expected node %s will be a pseudo-action",
1424 rsc->id, pcmk__node_name(node));
1425 pcmk__set_action_flags(promote, pcmk__action_pseudo);
1426 }
1427 } else {
1428 pcmk__rsc_trace(rsc, "Not promoting %s on %s: start unrunnable",
1429 rsc->id, pcmk__node_name(node));
1430 action_list = pe__resource_actions(rsc, node, PCMK_ACTION_PROMOTE,
1431 true);
1432 for (iter = action_list; iter != NULL; iter = iter->next) {
1433 pcmk_action_t *promote = (pcmk_action_t *) iter->data;
1434
1435 pcmk__clear_action_flags(promote, pcmk__action_runnable);
1436 }
1437 g_list_free(action_list);
1438 }
1439 }
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449 static void
1450 demote_resource(pcmk_resource_t *rsc, pcmk_node_t *node, bool optional)
1451 {
1452
1453
1454
1455
1456
1457 for (GList *iter = rsc->priv->active_nodes;
1458 iter != NULL; iter = iter->next) {
1459
1460 pcmk_node_t *current = (pcmk_node_t *) iter->data;
1461
1462 if (is_expected_node(rsc, current)) {
1463 pcmk__rsc_trace(rsc,
1464 "Skipping demote of multiply active resource %s "
1465 "on expected node %s",
1466 rsc->id, pcmk__node_name(current));
1467 } else {
1468 pcmk__rsc_trace(rsc, "Scheduling %s demotion of %s on %s",
1469 (optional? "optional" : "required"), rsc->id,
1470 pcmk__node_name(current));
1471 demote_action(rsc, current, optional);
1472 }
1473 }
1474 }
1475
1476 static void
1477 assert_role_error(pcmk_resource_t *rsc, pcmk_node_t *node, bool optional)
1478 {
1479 pcmk__assert(false);
1480 }
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490 void
1491 pcmk__schedule_cleanup(pcmk_resource_t *rsc, const pcmk_node_t *node,
1492 bool optional)
1493 {
1494
1495
1496
1497
1498
1499 uint32_t flag = optional? pcmk__ar_first_implies_then : pcmk__ar_ordered;
1500
1501 CRM_CHECK((rsc != NULL) && (node != NULL), return);
1502
1503 if (pcmk_is_set(rsc->flags, pcmk__rsc_failed)) {
1504 pcmk__rsc_trace(rsc, "Skipping clean-up of %s on %s: resource failed",
1505 rsc->id, pcmk__node_name(node));
1506 return;
1507 }
1508
1509 if (node->details->unclean || !node->details->online) {
1510 pcmk__rsc_trace(rsc, "Skipping clean-up of %s on %s: node unavailable",
1511 rsc->id, pcmk__node_name(node));
1512 return;
1513 }
1514
1515 crm_notice("Scheduling clean-up of %s on %s",
1516 rsc->id, pcmk__node_name(node));
1517 delete_action(rsc, node, optional);
1518
1519
1520 pcmk__order_resource_actions(rsc, PCMK_ACTION_STOP,
1521 rsc, PCMK_ACTION_DELETE, flag);
1522 pcmk__order_resource_actions(rsc, PCMK_ACTION_DELETE,
1523 rsc, PCMK_ACTION_START, flag);
1524 }
1525
1526
1527
1528
1529
1530
1531
1532
1533 void
1534 pcmk__primitive_add_graph_meta(const pcmk_resource_t *rsc, xmlNode *xml)
1535 {
1536 char *name = NULL;
1537 char *value = NULL;
1538 const pcmk_resource_t *parent = NULL;
1539
1540 pcmk__assert(pcmk__is_primitive(rsc) && (xml != NULL));
1541
1542
1543
1544
1545
1546 value = g_hash_table_lookup(rsc->priv->meta, PCMK__META_CLONE);
1547 if (value != NULL) {
1548 name = crm_meta_name(PCMK__META_CLONE);
1549 crm_xml_add(xml, name, value);
1550 free(name);
1551 }
1552
1553
1554 value = g_hash_table_lookup(rsc->priv->meta, PCMK_META_REMOTE_NODE);
1555 if (value != NULL) {
1556 name = crm_meta_name(PCMK_META_REMOTE_NODE);
1557 crm_xml_add(xml, name, value);
1558 free(name);
1559 }
1560
1561
1562
1563
1564 for (parent = rsc; parent != NULL; parent = parent->priv->parent) {
1565 if (parent->priv->launcher != NULL) {
1566 crm_xml_add(xml, CRM_META "_" PCMK__META_CONTAINER,
1567 parent->priv->launcher->id);
1568 }
1569 }
1570
1571
1572
1573
1574
1575 value = g_hash_table_lookup(rsc->priv->meta, "external-ip");
1576 if (value != NULL) {
1577 crm_xml_add(xml, "pcmk_external_ip", value);
1578 }
1579 }
1580
1581
1582 void
1583 pcmk__primitive_add_utilization(const pcmk_resource_t *rsc,
1584 const pcmk_resource_t *orig_rsc,
1585 GList *all_rscs, GHashTable *utilization)
1586 {
1587 pcmk__assert(pcmk__is_primitive(rsc) && (orig_rsc != NULL)
1588 && (utilization != NULL));
1589
1590 if (!pcmk_is_set(rsc->flags, pcmk__rsc_unassigned)) {
1591 return;
1592 }
1593
1594 pcmk__rsc_trace(orig_rsc,
1595 "%s: Adding primitive %s as colocated utilization",
1596 orig_rsc->id, rsc->id);
1597 pcmk__release_node_capacity(utilization, rsc);
1598 }
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608 static time_t
1609 shutdown_time(pcmk_node_t *node)
1610 {
1611 const char *shutdown = pcmk__node_attr(node, PCMK__NODE_ATTR_SHUTDOWN, NULL,
1612 pcmk__rsc_node_current);
1613 time_t result = 0;
1614
1615 if (shutdown != NULL) {
1616 long long result_ll;
1617 int rc = pcmk__scan_ll(shutdown, &result_ll, 0LL);
1618
1619 if (rc == pcmk_rc_ok) {
1620 result = (time_t) result_ll;
1621 } else {
1622 crm_warn("Ignoring invalid value '%s' for %s "
1623 PCMK__NODE_ATTR_SHUTDOWN " attribute: %s",
1624 shutdown, pcmk__node_name(node), pcmk_rc_str(rc));
1625 }
1626 }
1627 if (result == 0) {
1628 result = pcmk__scheduler_epoch_time(node->priv->scheduler);
1629 }
1630 return result;
1631 }
1632
1633
1634
1635
1636
1637
1638
1639
1640 static void
1641 ban_if_not_locked(gpointer data, gpointer user_data)
1642 {
1643 const pcmk_node_t *node = (const pcmk_node_t *) data;
1644 pcmk_resource_t *rsc = (pcmk_resource_t *) user_data;
1645
1646 if (!pcmk__same_node(node, rsc->priv->lock_node)) {
1647 resource_location(rsc, node, -PCMK_SCORE_INFINITY,
1648 PCMK_OPT_SHUTDOWN_LOCK, rsc->priv->scheduler);
1649 }
1650 }
1651
1652
1653 void
1654 pcmk__primitive_shutdown_lock(pcmk_resource_t *rsc)
1655 {
1656 pcmk_scheduler_t *scheduler = NULL;
1657
1658 pcmk__assert(pcmk__is_primitive(rsc));
1659 scheduler = rsc->priv->scheduler;
1660
1661
1662 if (pcmk_any_flags_set(rsc->flags, pcmk__rsc_fence_device
1663 |pcmk__rsc_is_remote_connection)) {
1664 return;
1665 }
1666
1667 if (rsc->priv->lock_node != NULL) {
1668
1669
1670 if (rsc->priv->active_nodes != NULL) {
1671
1672
1673
1674
1675 pcmk__rsc_info(rsc,
1676 "Cancelling shutdown lock "
1677 "because %s is already active", rsc->id);
1678 pe__clear_resource_history(rsc, rsc->priv->lock_node);
1679 rsc->priv->lock_node = NULL;
1680 rsc->priv->lock_time = 0;
1681 }
1682
1683
1684 } else if (pcmk__list_of_1(rsc->priv->active_nodes)) {
1685 pcmk_node_t *node = rsc->priv->active_nodes->data;
1686
1687 if (node->details->shutdown) {
1688 if (node->details->unclean) {
1689 pcmk__rsc_debug(rsc,
1690 "Not locking %s to unclean %s for shutdown",
1691 rsc->id, pcmk__node_name(node));
1692 } else {
1693 rsc->priv->lock_node = node;
1694 rsc->priv->lock_time = shutdown_time(node);
1695 }
1696 }
1697 }
1698
1699 if (rsc->priv->lock_node == NULL) {
1700
1701 return;
1702 }
1703
1704 if (scheduler->priv->shutdown_lock_ms > 0U) {
1705 time_t lock_expiration = rsc->priv->lock_time
1706 + pcmk__timeout_ms2s(scheduler->priv->shutdown_lock_ms);
1707
1708 pcmk__rsc_info(rsc, "Locking %s to %s due to shutdown (expires @%lld)",
1709 rsc->id, pcmk__node_name(rsc->priv->lock_node),
1710 (long long) lock_expiration);
1711 pcmk__update_recheck_time(++lock_expiration, scheduler,
1712 "shutdown lock expiration");
1713 } else {
1714 pcmk__rsc_info(rsc, "Locking %s to %s due to shutdown",
1715 rsc->id, pcmk__node_name(rsc->priv->lock_node));
1716 }
1717
1718
1719 g_list_foreach(scheduler->nodes, ban_if_not_locked, rsc);
1720 }