This source file includes following definitions.
- action_flags_for_ordering
- action_uuid_for_ordering
- action_for_ordering
- update
- update_action_for_ordering_flags
- pcmk__update_action_for_orderings
- is_primitive_action
- handle_asymmetric_ordering
- handle_restart_ordering
- pcmk__update_ordered_actions
- pcmk__log_action
- pcmk__new_shutdown_action
- add_op_digest_to_xml
- pcmk__create_history_xml
- pcmk__action_locks_rsc_to_node
- sort_action_id
- pcmk__deduplicate_action_inputs
- pcmk__output_actions
- task_for_digest
- only_sanitized_changed
- force_restart
- schedule_reload
- pcmk__check_action_config
- rsc_history_as_list
- process_rsc_history
- process_node_history
- pcmk__handle_rsc_config_changes
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdio.h>
13 #include <sys/param.h>
14 #include <glib.h>
15
16 #include <crm/lrmd_internal.h>
17 #include <crm/common/scheduler_internal.h>
18 #include <pacemaker-internal.h>
19 #include "libpacemaker_private.h"
20
21
22
23
24
25
26
27
28
29
30
31 static uint32_t
32 action_flags_for_ordering(pcmk_action_t *action, const pcmk_node_t *node)
33 {
34 bool runnable = false;
35 uint32_t flags;
36
37
38 if (action->rsc == NULL) {
39 return action->flags;
40 }
41
42
43
44
45
46 flags = action->rsc->cmds->action_flags(action, NULL);
47 if ((node == NULL) || !pcmk__is_clone(action->rsc)) {
48 return flags;
49 }
50
51
52
53
54 runnable = pcmk_is_set(flags, pcmk_action_runnable);
55
56
57 flags = action->rsc->cmds->action_flags(action, node);
58
59
60
61
62
63
64
65
66
67 if (runnable && !pcmk_is_set(flags, pcmk_action_runnable)) {
68 pcmk__set_raw_action_flags(flags, action->rsc->id,
69 pcmk_action_runnable);
70 }
71 return flags;
72 }
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 static char *
93 action_uuid_for_ordering(const char *first_uuid,
94 const pcmk_resource_t *first_rsc)
95 {
96 guint interval_ms = 0;
97 char *uuid = NULL;
98 char *rid = NULL;
99 char *first_task_str = NULL;
100 enum action_tasks first_task = pcmk_action_unspecified;
101 enum action_tasks remapped_task = pcmk_action_unspecified;
102
103
104 if ((strstr(first_uuid, PCMK_ACTION_NOTIFY) != NULL)
105 || (first_rsc->variant < pcmk_rsc_variant_group)) {
106 goto done;
107 }
108
109
110 pcmk__assert(parse_op_key(first_uuid, &rid, &first_task_str, &interval_ms));
111 if (interval_ms > 0) {
112 goto done;
113 }
114
115 first_task = pcmk_parse_action(first_task_str);
116 switch (first_task) {
117 case pcmk_action_stop:
118 case pcmk_action_start:
119 case pcmk_action_notify:
120 case pcmk_action_promote:
121 case pcmk_action_demote:
122 remapped_task = first_task + 1;
123 break;
124 case pcmk_action_stopped:
125 case pcmk_action_started:
126 case pcmk_action_notified:
127 case pcmk_action_promoted:
128 case pcmk_action_demoted:
129 remapped_task = first_task;
130 break;
131 case pcmk_action_monitor:
132 case pcmk_action_shutdown:
133 case pcmk_action_fence:
134 break;
135 default:
136 crm_err("Unknown action '%s' in ordering", first_task_str);
137 break;
138 }
139
140 if (remapped_task != pcmk_action_unspecified) {
141
142
143
144 if (pcmk_is_set(first_rsc->flags, pcmk_rsc_notify)
145 && (pcmk__is_clone(first_rsc) || pcmk__is_bundled(first_rsc))) {
146 uuid = pcmk__notify_key(rid, "confirmed-post",
147 pcmk_action_text(remapped_task));
148 } else {
149 uuid = pcmk__op_key(rid, pcmk_action_text(remapped_task), 0);
150 }
151 pcmk__rsc_trace(first_rsc,
152 "Remapped action UUID %s to %s for ordering purposes",
153 first_uuid, uuid);
154 }
155
156 done:
157 free(first_task_str);
158 free(rid);
159 return (uuid != NULL)? uuid : pcmk__str_copy(first_uuid);
160 }
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178 static pcmk_action_t *
179 action_for_ordering(pcmk_action_t *action)
180 {
181 pcmk_action_t *result = action;
182 pcmk_resource_t *rsc = action->rsc;
183
184 if ((rsc != NULL) && (rsc->variant >= pcmk_rsc_variant_group)
185 && (action->uuid != NULL)) {
186 char *uuid = action_uuid_for_ordering(action->uuid, rsc);
187
188 result = find_first_action(rsc->actions, uuid, NULL, NULL);
189 if (result == NULL) {
190 crm_warn("Not remapping %s to %s because %s does not have "
191 "remapped action", action->uuid, uuid, rsc->id);
192 result = action;
193 }
194 free(uuid);
195 }
196 return result;
197 }
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218 static inline uint32_t
219 update(pcmk_resource_t *rsc, pcmk_action_t *first, pcmk_action_t *then,
220 const pcmk_node_t *node, uint32_t flags, uint32_t filter, uint32_t type,
221 pcmk_scheduler_t *scheduler)
222 {
223 return rsc->cmds->update_ordered_actions(first, then, node, flags, filter,
224 type, scheduler);
225 }
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240 static uint32_t
241 update_action_for_ordering_flags(pcmk_action_t *first, pcmk_action_t *then,
242 uint32_t first_flags, uint32_t then_flags,
243 pcmk__related_action_t *order,
244 pcmk_scheduler_t *scheduler)
245 {
246 uint32_t changed = pcmk__updated_none;
247
248
249
250
251
252
253 pcmk_node_t *node = then->node;
254
255 if (pcmk_is_set(order->type, pcmk__ar_first_implies_same_node_then)) {
256
257
258
259
260
261 pcmk__clear_relation_flags(order->type,
262 pcmk__ar_first_implies_same_node_then);
263 pcmk__set_relation_flags(order->type, pcmk__ar_first_implies_then);
264 node = first->node;
265 pcmk__rsc_trace(then->rsc,
266 "%s then %s: mapped "
267 "pcmk__ar_first_implies_same_node_then to "
268 "pcmk__ar_first_implies_then on %s",
269 first->uuid, then->uuid, pcmk__node_name(node));
270 }
271
272 if (pcmk_is_set(order->type, pcmk__ar_first_implies_then)) {
273 if (then->rsc != NULL) {
274 changed |= update(then->rsc, first, then, node,
275 first_flags & pcmk_action_optional,
276 pcmk_action_optional, pcmk__ar_first_implies_then,
277 scheduler);
278 } else if (!pcmk_is_set(first_flags, pcmk_action_optional)
279 && pcmk_is_set(then->flags, pcmk_action_optional)) {
280 pcmk__clear_action_flags(then, pcmk_action_optional);
281 pcmk__set_updated_flags(changed, first, pcmk__updated_then);
282 }
283 pcmk__rsc_trace(then->rsc,
284 "%s then %s: %s after pcmk__ar_first_implies_then",
285 first->uuid, then->uuid,
286 (changed? "changed" : "unchanged"));
287 }
288
289 if (pcmk_is_set(order->type, pcmk__ar_intermediate_stop)
290 && (then->rsc != NULL)) {
291 enum pe_action_flags restart = pcmk_action_optional
292 |pcmk_action_runnable;
293
294 changed |= update(then->rsc, first, then, node, first_flags, restart,
295 pcmk__ar_intermediate_stop, scheduler);
296 pcmk__rsc_trace(then->rsc,
297 "%s then %s: %s after pcmk__ar_intermediate_stop",
298 first->uuid, then->uuid,
299 (changed? "changed" : "unchanged"));
300 }
301
302 if (pcmk_is_set(order->type, pcmk__ar_then_implies_first)) {
303 if (first->rsc != NULL) {
304 changed |= update(first->rsc, first, then, node, first_flags,
305 pcmk_action_optional, pcmk__ar_then_implies_first,
306 scheduler);
307 } else if (!pcmk_is_set(first_flags, pcmk_action_optional)
308 && pcmk_is_set(first->flags, pcmk_action_runnable)) {
309 pcmk__clear_action_flags(first, pcmk_action_runnable);
310 pcmk__set_updated_flags(changed, first, pcmk__updated_first);
311 }
312 pcmk__rsc_trace(then->rsc,
313 "%s then %s: %s after pcmk__ar_then_implies_first",
314 first->uuid, then->uuid,
315 (changed? "changed" : "unchanged"));
316 }
317
318 if (pcmk_is_set(order->type, pcmk__ar_promoted_then_implies_first)) {
319 if (then->rsc != NULL) {
320 changed |= update(then->rsc, first, then, node,
321 first_flags & pcmk_action_optional,
322 pcmk_action_optional,
323 pcmk__ar_promoted_then_implies_first, scheduler);
324 }
325 pcmk__rsc_trace(then->rsc,
326 "%s then %s: %s after "
327 "pcmk__ar_promoted_then_implies_first",
328 first->uuid, then->uuid,
329 (changed? "changed" : "unchanged"));
330 }
331
332 if (pcmk_is_set(order->type, pcmk__ar_min_runnable)) {
333 if (then->rsc != NULL) {
334 changed |= update(then->rsc, first, then, node, first_flags,
335 pcmk_action_runnable, pcmk__ar_min_runnable,
336 scheduler);
337
338 } else if (pcmk_is_set(first_flags, pcmk_action_runnable)) {
339
340 then->runnable_before++;
341
342
343
344
345 if ((then->runnable_before >= then->required_runnable_before)
346 && !pcmk_is_set(then->flags, pcmk_action_runnable)) {
347
348 pcmk__set_action_flags(then, pcmk_action_runnable);
349 pcmk__set_updated_flags(changed, first, pcmk__updated_then);
350 }
351 }
352 pcmk__rsc_trace(then->rsc, "%s then %s: %s after pcmk__ar_min_runnable",
353 first->uuid, then->uuid,
354 (changed? "changed" : "unchanged"));
355 }
356
357 if (pcmk_is_set(order->type, pcmk__ar_nested_remote_probe)
358 && (then->rsc != NULL)) {
359
360 if (!pcmk_is_set(first_flags, pcmk_action_runnable)
361 && (first->rsc != NULL) && (first->rsc->running_on != NULL)) {
362
363 pcmk__rsc_trace(then->rsc,
364 "%s then %s: ignoring because first is stopping",
365 first->uuid, then->uuid);
366 order->type = (enum pe_ordering) pcmk__ar_none;
367 } else {
368 changed |= update(then->rsc, first, then, node, first_flags,
369 pcmk_action_runnable,
370 pcmk__ar_unrunnable_first_blocks, scheduler);
371 }
372 pcmk__rsc_trace(then->rsc,
373 "%s then %s: %s after pcmk__ar_nested_remote_probe",
374 first->uuid, then->uuid,
375 (changed? "changed" : "unchanged"));
376 }
377
378 if (pcmk_is_set(order->type, pcmk__ar_unrunnable_first_blocks)) {
379 if (then->rsc != NULL) {
380 changed |= update(then->rsc, first, then, node, first_flags,
381 pcmk_action_runnable,
382 pcmk__ar_unrunnable_first_blocks, scheduler);
383
384 } else if (!pcmk_is_set(first_flags, pcmk_action_runnable)
385 && pcmk_is_set(then->flags, pcmk_action_runnable)) {
386
387 pcmk__clear_action_flags(then, pcmk_action_runnable);
388 pcmk__set_updated_flags(changed, first, pcmk__updated_then);
389 }
390 pcmk__rsc_trace(then->rsc,
391 "%s then %s: %s after pcmk__ar_unrunnable_first_blocks",
392 first->uuid, then->uuid,
393 (changed? "changed" : "unchanged"));
394 }
395
396 if (pcmk_is_set(order->type, pcmk__ar_unmigratable_then_blocks)) {
397 if (then->rsc != NULL) {
398 changed |= update(then->rsc, first, then, node, first_flags,
399 pcmk_action_optional,
400 pcmk__ar_unmigratable_then_blocks, scheduler);
401 }
402 pcmk__rsc_trace(then->rsc,
403 "%s then %s: %s after "
404 "pcmk__ar_unmigratable_then_blocks",
405 first->uuid, then->uuid,
406 (changed? "changed" : "unchanged"));
407 }
408
409 if (pcmk_is_set(order->type, pcmk__ar_first_else_then)) {
410 if (then->rsc != NULL) {
411 changed |= update(then->rsc, first, then, node, first_flags,
412 pcmk_action_optional, pcmk__ar_first_else_then,
413 scheduler);
414 }
415 pcmk__rsc_trace(then->rsc,
416 "%s then %s: %s after pcmk__ar_first_else_then",
417 first->uuid, then->uuid,
418 (changed? "changed" : "unchanged"));
419 }
420
421 if (pcmk_is_set(order->type, pcmk__ar_ordered)) {
422 if (then->rsc != NULL) {
423 changed |= update(then->rsc, first, then, node, first_flags,
424 pcmk_action_runnable, pcmk__ar_ordered,
425 scheduler);
426 }
427 pcmk__rsc_trace(then->rsc, "%s then %s: %s after pcmk__ar_ordered",
428 first->uuid, then->uuid,
429 (changed? "changed" : "unchanged"));
430 }
431
432 if (pcmk_is_set(order->type, pcmk__ar_asymmetric)) {
433 if (then->rsc != NULL) {
434 changed |= update(then->rsc, first, then, node, first_flags,
435 pcmk_action_runnable, pcmk__ar_asymmetric,
436 scheduler);
437 }
438 pcmk__rsc_trace(then->rsc, "%s then %s: %s after pcmk__ar_asymmetric",
439 first->uuid, then->uuid,
440 (changed? "changed" : "unchanged"));
441 }
442
443 if (pcmk_is_set(first->flags, pcmk_action_runnable)
444 && pcmk_is_set(order->type, pcmk__ar_first_implies_then_graphed)
445 && !pcmk_is_set(first_flags, pcmk_action_optional)) {
446
447 pcmk__rsc_trace(then->rsc, "%s will be in graph because %s is required",
448 then->uuid, first->uuid);
449 pcmk__set_action_flags(then, pcmk_action_always_in_graph);
450
451 }
452
453 if (pcmk_is_set(order->type, pcmk__ar_then_implies_first_graphed)
454 && !pcmk_is_set(then_flags, pcmk_action_optional)) {
455
456 pcmk__rsc_trace(then->rsc, "%s will be in graph because %s is required",
457 first->uuid, then->uuid);
458 pcmk__set_action_flags(first, pcmk_action_always_in_graph);
459
460 }
461
462 if (pcmk_any_flags_set(order->type, pcmk__ar_first_implies_then
463 |pcmk__ar_then_implies_first
464 |pcmk__ar_intermediate_stop)
465 && (first->rsc != NULL)
466 && !pcmk_is_set(first->rsc->flags, pcmk_rsc_managed)
467 && pcmk_is_set(first->rsc->flags, pcmk_rsc_blocked)
468 && !pcmk_is_set(first->flags, pcmk_action_runnable)
469 && pcmk__str_eq(first->task, PCMK_ACTION_STOP, pcmk__str_none)) {
470
471 if (pcmk_is_set(then->flags, pcmk_action_runnable)) {
472 pcmk__clear_action_flags(then, pcmk_action_runnable);
473 pcmk__set_updated_flags(changed, first, pcmk__updated_then);
474 }
475 pcmk__rsc_trace(then->rsc,
476 "%s then %s: %s after checking whether first "
477 "is blocked, unmanaged, unrunnable stop",
478 first->uuid, then->uuid,
479 (changed? "changed" : "unchanged"));
480 }
481
482 return changed;
483 }
484
485
486
487 #define action_type_str(flags) \
488 (pcmk_is_set((flags), pcmk_action_pseudo)? "pseudo-action" : "action")
489
490 #define action_optional_str(flags) \
491 (pcmk_is_set((flags), pcmk_action_optional)? "optional" : "required")
492
493 #define action_runnable_str(flags) \
494 (pcmk_is_set((flags), pcmk_action_runnable)? "runnable" : "unrunnable")
495
496 #define action_node_str(a) \
497 (((a)->node == NULL)? "no node" : (a)->node->details->uname)
498
499
500
501
502
503
504
505
506 void
507 pcmk__update_action_for_orderings(pcmk_action_t *then,
508 pcmk_scheduler_t *scheduler)
509 {
510 GList *lpc = NULL;
511 uint32_t changed = pcmk__updated_none;
512 int last_flags = then->flags;
513
514 pcmk__rsc_trace(then->rsc, "Updating %s %s (%s %s) on %s",
515 action_type_str(then->flags), then->uuid,
516 action_optional_str(then->flags),
517 action_runnable_str(then->flags), action_node_str(then));
518
519 if (pcmk_is_set(then->flags, pcmk_action_min_runnable)) {
520
521
522
523
524
525 then->runnable_before = 0;
526
527 if (then->required_runnable_before == 0) {
528
529
530
531
532 then->required_runnable_before = 1;
533 }
534
535
536
537
538
539 pcmk__clear_action_flags(then, pcmk_action_runnable);
540 }
541
542 for (lpc = then->actions_before; lpc != NULL; lpc = lpc->next) {
543 pcmk__related_action_t *other = lpc->data;
544 pcmk_action_t *first = other->action;
545
546 pcmk_node_t *then_node = then->node;
547 pcmk_node_t *first_node = first->node;
548
549 if ((first->rsc != NULL)
550 && pcmk__is_group(first->rsc)
551 && pcmk__str_eq(first->task, PCMK_ACTION_START, pcmk__str_none)) {
552
553 first_node = first->rsc->fns->location(first->rsc, NULL, FALSE);
554 if (first_node != NULL) {
555 pcmk__rsc_trace(first->rsc, "Found %s for 'first' %s",
556 pcmk__node_name(first_node), first->uuid);
557 }
558 }
559
560 if (pcmk__is_group(then->rsc)
561 && pcmk__str_eq(then->task, PCMK_ACTION_START, pcmk__str_none)) {
562
563 then_node = then->rsc->fns->location(then->rsc, NULL, FALSE);
564 if (then_node != NULL) {
565 pcmk__rsc_trace(then->rsc, "Found %s for 'then' %s",
566 pcmk__node_name(then_node), then->uuid);
567 }
568 }
569
570
571 if (pcmk_is_set(other->type, pcmk__ar_if_on_same_node)
572 && (first_node != NULL) && (then_node != NULL)
573 && !pcmk__same_node(first_node, then_node)) {
574
575 pcmk__rsc_trace(then->rsc,
576 "Disabled ordering %s on %s then %s on %s: "
577 "not same node",
578 other->action->uuid, pcmk__node_name(first_node),
579 then->uuid, pcmk__node_name(then_node));
580 other->type = (enum pe_ordering) pcmk__ar_none;
581 continue;
582 }
583
584 pcmk__clear_updated_flags(changed, then, pcmk__updated_first);
585
586 if ((first->rsc != NULL)
587 && pcmk_is_set(other->type, pcmk__ar_then_cancels_first)
588 && !pcmk_is_set(then->flags, pcmk_action_optional)) {
589
590
591
592
593 pcmk__set_action_flags(other->action, pcmk_action_optional);
594 if (!strcmp(first->task, PCMK_ACTION_RELOAD_AGENT)) {
595 pcmk__clear_rsc_flags(first->rsc, pcmk_rsc_reload);
596 }
597 }
598
599 if ((first->rsc != NULL) && (then->rsc != NULL)
600 && (first->rsc != then->rsc) && !is_parent(then->rsc, first->rsc)) {
601 first = action_for_ordering(first);
602 }
603 if (first != other->action) {
604 pcmk__rsc_trace(then->rsc, "Ordering %s after %s instead of %s",
605 then->uuid, first->uuid, other->action->uuid);
606 }
607
608 pcmk__rsc_trace(then->rsc,
609 "%s (%#.6x) then %s (%#.6x): type=%#.6x node=%s",
610 first->uuid, first->flags, then->uuid, then->flags,
611 other->type, action_node_str(first));
612
613 if (first == other->action) {
614
615
616
617
618 uint32_t first_flags, then_flags;
619
620 first_flags = action_flags_for_ordering(first, then_node);
621 then_flags = action_flags_for_ordering(then, first_node);
622
623 changed |= update_action_for_ordering_flags(first, then,
624 first_flags, then_flags,
625 other, scheduler);
626
627
628
629
630 } else if (order_actions(first, then, other->type)) {
631
632
633
634 pcmk__set_updated_flags(changed, then, pcmk__updated_then);
635 pcmk__rsc_trace(then->rsc,
636 "Disabled ordering %s then %s in favor of %s "
637 "then %s",
638 other->action->uuid, then->uuid, first->uuid,
639 then->uuid);
640 other->type = (enum pe_ordering) pcmk__ar_none;
641 }
642
643
644 if (pcmk_is_set(changed, pcmk__updated_first)) {
645 crm_trace("Re-processing %s and its 'after' actions "
646 "because it changed", first->uuid);
647 for (GList *lpc2 = first->actions_after; lpc2 != NULL;
648 lpc2 = lpc2->next) {
649 pcmk__related_action_t *other = lpc2->data;
650
651 pcmk__update_action_for_orderings(other->action, scheduler);
652 }
653 pcmk__update_action_for_orderings(first, scheduler);
654 }
655 }
656
657 if (pcmk_is_set(then->flags, pcmk_action_min_runnable)) {
658 if (last_flags == then->flags) {
659 pcmk__clear_updated_flags(changed, then, pcmk__updated_then);
660 } else {
661 pcmk__set_updated_flags(changed, then, pcmk__updated_then);
662 }
663 }
664
665 if (pcmk_is_set(changed, pcmk__updated_then)) {
666 crm_trace("Re-processing %s and its 'after' actions because it changed",
667 then->uuid);
668 if (pcmk_is_set(last_flags, pcmk_action_runnable)
669 && !pcmk_is_set(then->flags, pcmk_action_runnable)) {
670 pcmk__block_colocation_dependents(then);
671 }
672 pcmk__update_action_for_orderings(then, scheduler);
673 for (lpc = then->actions_after; lpc != NULL; lpc = lpc->next) {
674 pcmk__related_action_t *other = lpc->data;
675
676 pcmk__update_action_for_orderings(other->action, scheduler);
677 }
678 }
679 }
680
681 static inline bool
682 is_primitive_action(const pcmk_action_t *action)
683 {
684 return (action != NULL) && pcmk__is_primitive(action->rsc);
685 }
686
687
688
689
690
691
692
693
694
695 #define clear_action_flag_because(action, flag, reason) do { \
696 if (pcmk_is_set((action)->flags, (flag))) { \
697 pcmk__clear_action_flags(action, flag); \
698 if ((action)->rsc != (reason)->rsc) { \
699 char *reason_text = pe__action2reason((reason), (flag)); \
700 pe_action_set_reason((action), reason_text, false); \
701 free(reason_text); \
702 } \
703 } \
704 } while (0)
705
706
707
708
709
710
711
712
713
714
715
716 static void
717 handle_asymmetric_ordering(const pcmk_action_t *first, pcmk_action_t *then)
718 {
719
720
721
722 if ((then->rsc == NULL)
723 || pcmk_is_set(first->flags, pcmk_action_runnable)) {
724 return;
725 }
726
727
728 if (pcmk_is_set(then->flags, pcmk_action_optional)) {
729 enum rsc_role_e then_rsc_role = then->rsc->fns->state(then->rsc, TRUE);
730
731 if ((then_rsc_role == pcmk_role_stopped)
732 && pcmk__str_eq(then->task, PCMK_ACTION_STOP, pcmk__str_none)) {
733
734
735
736 return;
737 } else if ((then_rsc_role >= pcmk_role_started)
738 && pcmk__str_eq(then->task, PCMK_ACTION_START, pcmk__str_none)
739 && pe__rsc_running_on_only(then->rsc, then->node)) {
740
741
742
743 return;
744 }
745 }
746
747
748 clear_action_flag_because(then, pcmk_action_optional, first);
749 clear_action_flag_because(then, pcmk_action_runnable, first);
750 }
751
752
753
754
755
756
757
758
759
760
761
762
763 static void
764 handle_restart_ordering(pcmk_action_t *first, pcmk_action_t *then,
765 uint32_t filter)
766 {
767 const char *reason = NULL;
768
769 pcmk__assert(is_primitive_action(first) && is_primitive_action(then));
770
771
772
773
774 if (pcmk_is_set(filter, pcmk_action_optional)
775 && !pcmk_is_set(then->flags, pcmk_action_optional)) {
776 reason = "restart";
777 }
778
779
780
781
782 if (pcmk_is_set(filter, pcmk_action_runnable)
783 && !pcmk_is_set(then->flags, pcmk_action_runnable)
784 && pcmk_is_set(then->rsc->flags, pcmk_rsc_managed)
785 && (first->rsc == then->rsc)) {
786 reason = "stop";
787 }
788
789 if (reason == NULL) {
790 return;
791 }
792
793 pcmk__rsc_trace(first->rsc, "Handling %s -> %s for %s",
794 first->uuid, then->uuid, reason);
795
796
797 if (pcmk_is_set(first->flags, pcmk_action_runnable)) {
798 clear_action_flag_because(first, pcmk_action_optional, then);
799 }
800
801
802 if (!pcmk_is_set(then->flags, pcmk_action_optional)) {
803 clear_action_flag_because(first, pcmk_action_optional, then);
804 }
805
806
807 if (!pcmk_is_set(then->flags, pcmk_action_migratable)) {
808 clear_action_flag_because(first, pcmk_action_migratable, then);
809 }
810
811
812 if (!pcmk_is_set(first->flags, pcmk_action_optional)
813 && !pcmk_is_set(first->flags, pcmk_action_runnable)) {
814 clear_action_flag_because(then, pcmk_action_runnable, first);
815 }
816 }
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840 uint32_t
841 pcmk__update_ordered_actions(pcmk_action_t *first, pcmk_action_t *then,
842 const pcmk_node_t *node, uint32_t flags,
843 uint32_t filter, uint32_t type,
844 pcmk_scheduler_t *scheduler)
845 {
846 uint32_t changed = pcmk__updated_none;
847 uint32_t then_flags = 0U;
848 uint32_t first_flags = 0U;
849
850 pcmk__assert((first != NULL) && (then != NULL) && (scheduler != NULL));
851
852 then_flags = then->flags;
853 first_flags = first->flags;
854 if (pcmk_is_set(type, pcmk__ar_asymmetric)) {
855 handle_asymmetric_ordering(first, then);
856 }
857
858 if (pcmk_is_set(type, pcmk__ar_then_implies_first)
859 && !pcmk_is_set(then_flags, pcmk_action_optional)) {
860
861
862 if (pcmk_is_set(filter, pcmk_action_optional)
863 && !pcmk_is_set(flags, pcmk_action_optional)
864 && pcmk_is_set(first_flags, pcmk_action_optional)) {
865 clear_action_flag_because(first, pcmk_action_optional, then);
866 }
867
868 if (pcmk_is_set(flags, pcmk_action_migratable)
869 && !pcmk_is_set(then->flags, pcmk_action_migratable)) {
870 clear_action_flag_because(first, pcmk_action_migratable, then);
871 }
872 }
873
874 if (pcmk_is_set(type, pcmk__ar_promoted_then_implies_first)
875 && (then->rsc != NULL) && (then->rsc->role == pcmk_role_promoted)
876 && pcmk_is_set(filter, pcmk_action_optional)
877 && !pcmk_is_set(then->flags, pcmk_action_optional)) {
878
879 clear_action_flag_because(first, pcmk_action_optional, then);
880
881 if (pcmk_is_set(first->flags, pcmk_action_migratable)
882 && !pcmk_is_set(then->flags, pcmk_action_migratable)) {
883 clear_action_flag_because(first, pcmk_action_migratable, then);
884 }
885 }
886
887 if (pcmk_is_set(type, pcmk__ar_unmigratable_then_blocks)
888 && pcmk_is_set(filter, pcmk_action_optional)) {
889
890 if (!pcmk_all_flags_set(then->flags, pcmk_action_migratable
891 |pcmk_action_runnable)) {
892 clear_action_flag_because(first, pcmk_action_runnable, then);
893 }
894
895 if (!pcmk_is_set(then->flags, pcmk_action_optional)) {
896 clear_action_flag_because(first, pcmk_action_optional, then);
897 }
898 }
899
900 if (pcmk_is_set(type, pcmk__ar_first_else_then)
901 && pcmk_is_set(filter, pcmk_action_optional)
902 && !pcmk_is_set(first->flags, pcmk_action_runnable)) {
903
904 clear_action_flag_because(then, pcmk_action_migratable, first);
905 pcmk__clear_action_flags(then, pcmk_action_pseudo);
906 }
907
908 if (pcmk_is_set(type, pcmk__ar_unrunnable_first_blocks)
909 && pcmk_is_set(filter, pcmk_action_runnable)
910 && pcmk_is_set(then->flags, pcmk_action_runnable)
911 && !pcmk_is_set(flags, pcmk_action_runnable)) {
912
913 clear_action_flag_because(then, pcmk_action_runnable, first);
914 clear_action_flag_because(then, pcmk_action_migratable, first);
915 }
916
917 if (pcmk_is_set(type, pcmk__ar_first_implies_then)
918 && pcmk_is_set(filter, pcmk_action_optional)
919 && pcmk_is_set(then->flags, pcmk_action_optional)
920 && !pcmk_is_set(flags, pcmk_action_optional)
921 && !pcmk_is_set(first->flags, pcmk_action_migratable)) {
922
923 clear_action_flag_because(then, pcmk_action_optional, first);
924 }
925
926 if (pcmk_is_set(type, pcmk__ar_intermediate_stop)) {
927 handle_restart_ordering(first, then, filter);
928 }
929
930 if (then_flags != then->flags) {
931 pcmk__set_updated_flags(changed, first, pcmk__updated_then);
932 pcmk__rsc_trace(then->rsc,
933 "%s on %s: flags are now %#.6x (was %#.6x) "
934 "because of 'first' %s (%#.6x)",
935 then->uuid, pcmk__node_name(then->node),
936 then->flags, then_flags, first->uuid, first->flags);
937
938 if ((then->rsc != NULL) && (then->rsc->parent != NULL)) {
939
940 pcmk__update_action_for_orderings(then, scheduler);
941 }
942 }
943
944 if (first_flags != first->flags) {
945 pcmk__set_updated_flags(changed, first, pcmk__updated_first);
946 pcmk__rsc_trace(first->rsc,
947 "%s on %s: flags are now %#.6x (was %#.6x) "
948 "because of 'then' %s (%#.6x)",
949 first->uuid, pcmk__node_name(first->node),
950 first->flags, first_flags, then->uuid, then->flags);
951 }
952
953 return changed;
954 }
955
956
957
958
959
960
961
962
963
964 void
965 pcmk__log_action(const char *pre_text, const pcmk_action_t *action,
966 bool details)
967 {
968 const char *node_uname = NULL;
969 const char *node_uuid = NULL;
970 const char *desc = NULL;
971
972 CRM_CHECK(action != NULL, return);
973
974 if (!pcmk_is_set(action->flags, pcmk_action_pseudo)) {
975 if (action->node != NULL) {
976 node_uname = action->node->details->uname;
977 node_uuid = action->node->details->id;
978 } else {
979 node_uname = "<none>";
980 }
981 }
982
983 switch (pcmk_parse_action(action->task)) {
984 case pcmk_action_fence:
985 case pcmk_action_shutdown:
986 if (pcmk_is_set(action->flags, pcmk_action_pseudo)) {
987 desc = "Pseudo ";
988 } else if (pcmk_is_set(action->flags, pcmk_action_optional)) {
989 desc = "Optional ";
990 } else if (!pcmk_is_set(action->flags, pcmk_action_runnable)) {
991 desc = "!!Non-Startable!! ";
992 } else {
993 desc = "(Provisional) ";
994 }
995 crm_trace("%s%s%sAction %d: %s%s%s%s%s%s",
996 ((pre_text == NULL)? "" : pre_text),
997 ((pre_text == NULL)? "" : ": "),
998 desc, action->id, action->uuid,
999 (node_uname? "\ton " : ""), (node_uname? node_uname : ""),
1000 (node_uuid? "\t\t(" : ""), (node_uuid? node_uuid : ""),
1001 (node_uuid? ")" : ""));
1002 break;
1003 default:
1004 if (pcmk_is_set(action->flags, pcmk_action_optional)) {
1005 desc = "Optional ";
1006 } else if (pcmk_is_set(action->flags, pcmk_action_pseudo)) {
1007 desc = "Pseudo ";
1008 } else if (!pcmk_is_set(action->flags, pcmk_action_runnable)) {
1009 desc = "!!Non-Startable!! ";
1010 } else {
1011 desc = "(Provisional) ";
1012 }
1013 crm_trace("%s%s%sAction %d: %s %s%s%s%s%s%s",
1014 ((pre_text == NULL)? "" : pre_text),
1015 ((pre_text == NULL)? "" : ": "),
1016 desc, action->id, action->uuid,
1017 (action->rsc? action->rsc->id : "<none>"),
1018 (node_uname? "\ton " : ""), (node_uname? node_uname : ""),
1019 (node_uuid? "\t\t(" : ""), (node_uuid? node_uuid : ""),
1020 (node_uuid? ")" : ""));
1021 break;
1022 }
1023
1024 if (details) {
1025 const GList *iter = NULL;
1026 const pcmk__related_action_t *other = NULL;
1027
1028 crm_trace("\t\t====== Preceding Actions");
1029 for (iter = action->actions_before; iter != NULL; iter = iter->next) {
1030 other = (const pcmk__related_action_t *) iter->data;
1031 pcmk__log_action("\t\t", other->action, false);
1032 }
1033 crm_trace("\t\t====== Subsequent Actions");
1034 for (iter = action->actions_after; iter != NULL; iter = iter->next) {
1035 other = (const pcmk__related_action_t *) iter->data;
1036 pcmk__log_action("\t\t", other->action, false);
1037 }
1038 crm_trace("\t\t====== End");
1039
1040 } else {
1041 crm_trace("\t\t(before=%d, after=%d)",
1042 g_list_length(action->actions_before),
1043 g_list_length(action->actions_after));
1044 }
1045 }
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055 pcmk_action_t *
1056 pcmk__new_shutdown_action(pcmk_node_t *node)
1057 {
1058 char *shutdown_id = NULL;
1059 pcmk_action_t *shutdown_op = NULL;
1060
1061 pcmk__assert(node != NULL);
1062
1063 shutdown_id = crm_strdup_printf("%s-%s", PCMK_ACTION_DO_SHUTDOWN,
1064 node->details->uname);
1065
1066 shutdown_op = custom_action(NULL, shutdown_id, PCMK_ACTION_DO_SHUTDOWN,
1067 node, FALSE, node->details->data_set);
1068
1069 pcmk__order_stops_before_shutdown(node, shutdown_op);
1070 pcmk__insert_meta(shutdown_op, PCMK__META_OP_NO_WAIT, PCMK_VALUE_TRUE);
1071 return shutdown_op;
1072 }
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085 static void
1086 add_op_digest_to_xml(const lrmd_event_data_t *op, xmlNode *update)
1087 {
1088 char *digest = NULL;
1089 xmlNode *args_xml = NULL;
1090
1091 if (op->params == NULL) {
1092 return;
1093 }
1094 args_xml = pcmk__xe_create(NULL, PCMK_XE_PARAMETERS);
1095 g_hash_table_foreach(op->params, hash2field, args_xml);
1096 pcmk__filter_op_for_digest(args_xml);
1097 digest = calculate_operation_digest(args_xml, NULL);
1098 crm_xml_add(update, PCMK__XA_OP_DIGEST, digest);
1099 free_xml(args_xml);
1100 free(digest);
1101 }
1102
1103 #define FAKE_TE_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118 xmlNode *
1119 pcmk__create_history_xml(xmlNode *parent, lrmd_event_data_t *op,
1120 const char *caller_version, int target_rc,
1121 const char *node, const char *origin)
1122 {
1123 char *key = NULL;
1124 char *magic = NULL;
1125 char *op_id = NULL;
1126 char *op_id_additional = NULL;
1127 char *local_user_data = NULL;
1128 const char *exit_reason = NULL;
1129
1130 xmlNode *xml_op = NULL;
1131 const char *task = NULL;
1132
1133 CRM_CHECK(op != NULL, return NULL);
1134 crm_trace("Creating history XML for %s-interval %s action for %s on %s "
1135 "(DC version: %s, origin: %s)",
1136 pcmk__readable_interval(op->interval_ms), op->op_type, op->rsc_id,
1137 ((node == NULL)? "no node" : node), caller_version, origin);
1138
1139 task = op->op_type;
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150 if (pcmk__str_any_of(task, PCMK_ACTION_RELOAD, PCMK_ACTION_RELOAD_AGENT,
1151 NULL)) {
1152 if (op->op_status == PCMK_EXEC_DONE) {
1153 task = PCMK_ACTION_START;
1154 } else {
1155 task = PCMK_ACTION_MONITOR;
1156 }
1157 }
1158
1159 key = pcmk__op_key(op->rsc_id, task, op->interval_ms);
1160 if (pcmk__str_eq(task, PCMK_ACTION_NOTIFY, pcmk__str_none)) {
1161 const char *n_type = crm_meta_value(op->params, "notify_type");
1162 const char *n_task = crm_meta_value(op->params, "notify_operation");
1163
1164 CRM_LOG_ASSERT(n_type != NULL);
1165 CRM_LOG_ASSERT(n_task != NULL);
1166 op_id = pcmk__notify_key(op->rsc_id, n_type, n_task);
1167
1168 if (op->op_status != PCMK_EXEC_PENDING) {
1169
1170
1171
1172
1173
1174 lrmd__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
1175 }
1176
1177
1178
1179
1180 } else if (pcmk__str_any_of(op->op_type, PCMK_ACTION_MIGRATE_TO,
1181 PCMK_ACTION_MIGRATE_FROM, NULL)) {
1182 op_id = strdup(key);
1183
1184 } else if (did_rsc_op_fail(op, target_rc)) {
1185 op_id = pcmk__op_key(op->rsc_id, "last_failure", 0);
1186 if (op->interval_ms == 0) {
1187
1188
1189
1190 op_id_additional = pcmk__op_key(op->rsc_id, "last", 0);
1191 }
1192 exit_reason = op->exit_reason;
1193
1194 } else if (op->interval_ms > 0) {
1195 op_id = strdup(key);
1196
1197 } else {
1198 op_id = pcmk__op_key(op->rsc_id, "last", 0);
1199 }
1200
1201 again:
1202 xml_op = pcmk__xe_first_child(parent, PCMK__XE_LRM_RSC_OP, PCMK_XA_ID,
1203 op_id);
1204 if (xml_op == NULL) {
1205 xml_op = pcmk__xe_create(parent, PCMK__XE_LRM_RSC_OP);
1206 }
1207
1208 if (op->user_data == NULL) {
1209 crm_debug("Generating fake transition key for: " PCMK__OP_FMT
1210 " %d from %s", op->rsc_id, op->op_type, op->interval_ms,
1211 op->call_id, origin);
1212 local_user_data = pcmk__transition_key(-1, op->call_id, target_rc,
1213 FAKE_TE_ID);
1214 op->user_data = local_user_data;
1215 }
1216
1217 if (magic == NULL) {
1218 magic = crm_strdup_printf("%d:%d;%s", op->op_status, op->rc,
1219 (const char *) op->user_data);
1220 }
1221
1222 crm_xml_add(xml_op, PCMK_XA_ID, op_id);
1223 crm_xml_add(xml_op, PCMK__XA_OPERATION_KEY, key);
1224 crm_xml_add(xml_op, PCMK_XA_OPERATION, task);
1225 crm_xml_add(xml_op, PCMK_XA_CRM_DEBUG_ORIGIN, origin);
1226 crm_xml_add(xml_op, PCMK_XA_CRM_FEATURE_SET, caller_version);
1227 crm_xml_add(xml_op, PCMK__XA_TRANSITION_KEY, op->user_data);
1228 crm_xml_add(xml_op, PCMK__XA_TRANSITION_MAGIC, magic);
1229 crm_xml_add(xml_op, PCMK_XA_EXIT_REASON, pcmk__s(exit_reason, ""));
1230 crm_xml_add(xml_op, PCMK__META_ON_NODE, node);
1231
1232 crm_xml_add_int(xml_op, PCMK__XA_CALL_ID, op->call_id);
1233 crm_xml_add_int(xml_op, PCMK__XA_RC_CODE, op->rc);
1234 crm_xml_add_int(xml_op, PCMK__XA_OP_STATUS, op->op_status);
1235 crm_xml_add_ms(xml_op, PCMK_META_INTERVAL, op->interval_ms);
1236
1237 if (compare_version("2.1", caller_version) <= 0) {
1238 if (op->t_run || op->t_rcchange || op->exec_time || op->queue_time) {
1239 crm_trace("Timing data (" PCMK__OP_FMT
1240 "): last=%u change=%u exec=%u queue=%u",
1241 op->rsc_id, op->op_type, op->interval_ms,
1242 op->t_run, op->t_rcchange, op->exec_time, op->queue_time);
1243
1244 if ((op->interval_ms != 0) && (op->t_rcchange != 0)) {
1245
1246 crm_xml_add_ll(xml_op, PCMK_XA_LAST_RC_CHANGE,
1247 (long long) op->t_rcchange);
1248 } else {
1249 crm_xml_add_ll(xml_op, PCMK_XA_LAST_RC_CHANGE,
1250 (long long) op->t_run);
1251 }
1252
1253 crm_xml_add_int(xml_op, PCMK_XA_EXEC_TIME, op->exec_time);
1254 crm_xml_add_int(xml_op, PCMK_XA_QUEUE_TIME, op->queue_time);
1255 }
1256 }
1257
1258 if (pcmk__str_any_of(op->op_type, PCMK_ACTION_MIGRATE_TO,
1259 PCMK_ACTION_MIGRATE_FROM, NULL)) {
1260
1261
1262
1263 const char *name = PCMK__META_MIGRATE_SOURCE;
1264
1265 crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1266
1267 name = PCMK__META_MIGRATE_TARGET;
1268 crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1269 }
1270
1271 add_op_digest_to_xml(op, xml_op);
1272
1273 if (op_id_additional) {
1274 free(op_id);
1275 op_id = op_id_additional;
1276 op_id_additional = NULL;
1277 goto again;
1278 }
1279
1280 if (local_user_data) {
1281 free(local_user_data);
1282 op->user_data = NULL;
1283 }
1284 free(magic);
1285 free(op_id);
1286 free(key);
1287 return xml_op;
1288 }
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304 bool
1305 pcmk__action_locks_rsc_to_node(const pcmk_action_t *action)
1306 {
1307
1308 if ((action == NULL) || (action->rsc == NULL)
1309 || !pcmk__same_node(action->node, action->rsc->lock_node)) {
1310 return false;
1311 }
1312
1313
1314
1315
1316 if (action->node->details->shutdown && (action->task != NULL)
1317 && (strcmp(action->task, PCMK_ACTION_STOP) != 0)) {
1318 return false;
1319 }
1320
1321 return true;
1322 }
1323
1324
1325 static gint
1326 sort_action_id(gconstpointer a, gconstpointer b)
1327 {
1328 const pcmk__related_action_t *action_wrapper2 = a;
1329 const pcmk__related_action_t *action_wrapper1 = b;
1330
1331 if (a == NULL) {
1332 return 1;
1333 }
1334 if (b == NULL) {
1335 return -1;
1336 }
1337 if (action_wrapper1->action->id < action_wrapper2->action->id) {
1338 return 1;
1339 }
1340 if (action_wrapper1->action->id > action_wrapper2->action->id) {
1341 return -1;
1342 }
1343 return 0;
1344 }
1345
1346
1347
1348
1349
1350
1351
1352 void
1353 pcmk__deduplicate_action_inputs(pcmk_action_t *action)
1354 {
1355 GList *item = NULL;
1356 GList *next = NULL;
1357 pcmk__related_action_t *last_input = NULL;
1358
1359 action->actions_before = g_list_sort(action->actions_before,
1360 sort_action_id);
1361 for (item = action->actions_before; item != NULL; item = next) {
1362 pcmk__related_action_t *input = item->data;
1363
1364 next = item->next;
1365 if ((last_input != NULL)
1366 && (input->action->id == last_input->action->id)) {
1367 crm_trace("Input %s (%d) duplicate skipped for action %s (%d)",
1368 input->action->uuid, input->action->id,
1369 action->uuid, action->id);
1370
1371
1372
1373
1374
1375 last_input->type |= input->type;
1376 if (input->state == pe_link_dumped) {
1377 last_input->state = pe_link_dumped;
1378 }
1379
1380 free(item->data);
1381 action->actions_before = g_list_delete_link(action->actions_before,
1382 item);
1383 } else {
1384 last_input = input;
1385 input->state = pe_link_not_dumped;
1386 }
1387 }
1388 }
1389
1390
1391
1392
1393
1394
1395
1396 void
1397 pcmk__output_actions(pcmk_scheduler_t *scheduler)
1398 {
1399 pcmk__output_t *out = scheduler->priv;
1400
1401
1402 for (GList *iter = scheduler->actions; iter != NULL; iter = iter->next) {
1403 char *node_name = NULL;
1404 char *task = NULL;
1405 pcmk_action_t *action = (pcmk_action_t *) iter->data;
1406
1407 if (action->rsc != NULL) {
1408 continue;
1409
1410 } else if (pcmk_is_set(action->flags, pcmk_action_optional)) {
1411 continue;
1412 }
1413
1414 if (pcmk__str_eq(action->task, PCMK_ACTION_DO_SHUTDOWN,
1415 pcmk__str_none)) {
1416 task = strdup("Shutdown");
1417
1418 } else if (pcmk__str_eq(action->task, PCMK_ACTION_STONITH,
1419 pcmk__str_none)) {
1420 const char *op = g_hash_table_lookup(action->meta,
1421 PCMK__META_STONITH_ACTION);
1422
1423 task = crm_strdup_printf("Fence (%s)", op);
1424
1425 } else {
1426 continue;
1427 }
1428
1429 if (pcmk__is_guest_or_bundle_node(action->node)) {
1430 const pcmk_resource_t *remote = action->node->details->remote_rsc;
1431
1432 node_name = crm_strdup_printf("%s (resource: %s)",
1433 pcmk__node_name(action->node),
1434 remote->container->id);
1435 } else if (action->node != NULL) {
1436 node_name = crm_strdup_printf("%s", pcmk__node_name(action->node));
1437 }
1438
1439 out->message(out, "node-action", task, node_name, action->reason);
1440
1441 free(node_name);
1442 free(task);
1443 }
1444
1445
1446 for (GList *iter = scheduler->resources; iter != NULL; iter = iter->next) {
1447 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
1448
1449 rsc->cmds->output_actions(rsc);
1450 }
1451 }
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462 static const char *
1463 task_for_digest(const char *task, guint interval_ms)
1464 {
1465
1466
1467
1468 if ((interval_ms == 0)
1469 && pcmk__str_any_of(task, PCMK_ACTION_MONITOR, PCMK_ACTION_MIGRATE_FROM,
1470 PCMK_ACTION_PROMOTE, NULL)) {
1471 task = PCMK_ACTION_START;
1472 }
1473 return task;
1474 }
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493 static bool
1494 only_sanitized_changed(const xmlNode *xml_op,
1495 const pcmk__op_digest_t *digest_data,
1496 const pcmk_scheduler_t *scheduler)
1497 {
1498 const char *digest_secure = NULL;
1499
1500 if (!pcmk_is_set(scheduler->flags, pcmk_sched_sanitized)) {
1501
1502 return false;
1503 }
1504
1505 digest_secure = crm_element_value(xml_op, PCMK__XA_OP_SECURE_DIGEST);
1506
1507 return (digest_data->rc != pcmk__digest_match) && (digest_secure != NULL)
1508 && (digest_data->digest_secure_calc != NULL)
1509 && (strcmp(digest_data->digest_secure_calc, digest_secure) == 0);
1510 }
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521 static void
1522 force_restart(pcmk_resource_t *rsc, const char *task, guint interval_ms,
1523 pcmk_node_t *node)
1524 {
1525 char *key = pcmk__op_key(rsc->id, task, interval_ms);
1526 pcmk_action_t *required = custom_action(rsc, key, task, NULL, FALSE,
1527 rsc->cluster);
1528
1529 pe_action_set_reason(required, "resource definition change", true);
1530 trigger_unfencing(rsc, node, "Device parameters changed", NULL,
1531 rsc->cluster);
1532 }
1533
1534
1535
1536
1537
1538
1539
1540
1541 static void
1542 schedule_reload(gpointer data, gpointer user_data)
1543 {
1544 pcmk_resource_t *rsc = data;
1545 const pcmk_node_t *node = user_data;
1546 pcmk_action_t *reload = NULL;
1547
1548
1549 if (rsc->variant > pcmk_rsc_variant_primitive) {
1550 g_list_foreach(rsc->children, schedule_reload, user_data);
1551 return;
1552 }
1553
1554
1555 if ((node == NULL)
1556 || !pcmk_is_set(rsc->flags, pcmk_rsc_managed)
1557 || pcmk_is_set(rsc->flags, pcmk_rsc_failed)) {
1558 pcmk__rsc_trace(rsc, "Skip reload of %s:%s%s %s",
1559 rsc->id,
1560 pcmk_is_set(rsc->flags, pcmk_rsc_managed)? "" : " unmanaged",
1561 pcmk_is_set(rsc->flags, pcmk_rsc_failed)? " failed" : "",
1562 (node == NULL)? "inactive" : node->details->uname);
1563 return;
1564 }
1565
1566
1567
1568
1569 if (pcmk_is_set(rsc->flags, pcmk_rsc_start_pending)) {
1570 pcmk__rsc_trace(rsc,
1571 "%s: preventing agent reload because start pending",
1572 rsc->id);
1573 custom_action(rsc, stop_key(rsc), PCMK_ACTION_STOP, node, FALSE,
1574 rsc->cluster);
1575 return;
1576 }
1577
1578
1579 pcmk__set_rsc_flags(rsc, pcmk_rsc_reload);
1580 reload = custom_action(rsc, reload_key(rsc), PCMK_ACTION_RELOAD_AGENT, node,
1581 FALSE, rsc->cluster);
1582 pe_action_set_reason(reload, "resource definition change", FALSE);
1583
1584
1585 pcmk__new_ordering(NULL, NULL, reload, rsc, stop_key(rsc), NULL,
1586 pcmk__ar_ordered|pcmk__ar_then_cancels_first,
1587 rsc->cluster);
1588 pcmk__new_ordering(NULL, NULL, reload, rsc, demote_key(rsc), NULL,
1589 pcmk__ar_ordered|pcmk__ar_then_cancels_first,
1590 rsc->cluster);
1591 }
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607 bool
1608 pcmk__check_action_config(pcmk_resource_t *rsc, pcmk_node_t *node,
1609 const xmlNode *xml_op)
1610 {
1611 guint interval_ms = 0;
1612 const char *task = NULL;
1613 const pcmk__op_digest_t *digest_data = NULL;
1614
1615 CRM_CHECK((rsc != NULL) && (node != NULL) && (xml_op != NULL),
1616 return false);
1617
1618 task = crm_element_value(xml_op, PCMK_XA_OPERATION);
1619 CRM_CHECK(task != NULL, return false);
1620
1621 crm_element_value_ms(xml_op, PCMK_META_INTERVAL, &interval_ms);
1622
1623
1624 if (interval_ms > 0) {
1625 if (pcmk__find_action_config(rsc, task, interval_ms, false) != NULL) {
1626 pcmk__rsc_trace(rsc,
1627 "%s-interval %s for %s on %s is in configuration",
1628 pcmk__readable_interval(interval_ms), task, rsc->id,
1629 pcmk__node_name(node));
1630 } else if (pcmk_is_set(rsc->cluster->flags,
1631 pcmk_sched_cancel_removed_actions)) {
1632 pcmk__schedule_cancel(rsc,
1633 crm_element_value(xml_op, PCMK__XA_CALL_ID),
1634 task, interval_ms, node, "orphan");
1635 return true;
1636 } else {
1637 pcmk__rsc_debug(rsc, "%s-interval %s for %s on %s is orphaned",
1638 pcmk__readable_interval(interval_ms), task, rsc->id,
1639 pcmk__node_name(node));
1640 return true;
1641 }
1642 }
1643
1644 crm_trace("Checking %s-interval %s for %s on %s for configuration changes",
1645 pcmk__readable_interval(interval_ms), task, rsc->id,
1646 pcmk__node_name(node));
1647 task = task_for_digest(task, interval_ms);
1648 digest_data = rsc_action_digest_cmp(rsc, xml_op, node, rsc->cluster);
1649
1650 if (only_sanitized_changed(xml_op, digest_data, rsc->cluster)) {
1651 if (!pcmk__is_daemon && (rsc->cluster->priv != NULL)) {
1652 pcmk__output_t *out = rsc->cluster->priv;
1653
1654 out->info(out,
1655 "Only 'private' parameters to %s-interval %s for %s "
1656 "on %s changed: %s",
1657 pcmk__readable_interval(interval_ms), task, rsc->id,
1658 pcmk__node_name(node),
1659 crm_element_value(xml_op, PCMK__XA_TRANSITION_MAGIC));
1660 }
1661 return false;
1662 }
1663
1664 switch (digest_data->rc) {
1665 case pcmk__digest_restart:
1666 crm_log_xml_debug(digest_data->params_restart, "params:restart");
1667 force_restart(rsc, task, interval_ms, node);
1668 return true;
1669
1670 case pcmk__digest_unknown:
1671 case pcmk__digest_mismatch:
1672
1673
1674 if (interval_ms > 0) {
1675
1676
1677
1678
1679 crm_log_xml_debug(digest_data->params_all, "params:reschedule");
1680 pcmk__reschedule_recurring(rsc, task, interval_ms, node);
1681
1682 } else if (crm_element_value(xml_op,
1683 PCMK__XA_OP_RESTART_DIGEST) != NULL) {
1684
1685 trigger_unfencing(rsc, node,
1686 "Device parameters changed (reload)", NULL,
1687 rsc->cluster);
1688 crm_log_xml_debug(digest_data->params_all, "params:reload");
1689 schedule_reload((gpointer) rsc, (gpointer) node);
1690
1691 } else {
1692 pcmk__rsc_trace(rsc,
1693 "Restarting %s "
1694 "because agent doesn't support reload",
1695 rsc->id);
1696 crm_log_xml_debug(digest_data->params_restart,
1697 "params:restart");
1698 force_restart(rsc, task, interval_ms, node);
1699 }
1700 return true;
1701
1702 default:
1703 break;
1704 }
1705 return false;
1706 }
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716 static GList *
1717 rsc_history_as_list(const xmlNode *rsc_entry, int *start_index, int *stop_index)
1718 {
1719 GList *ops = NULL;
1720
1721 for (xmlNode *rsc_op = pcmk__xe_first_child(rsc_entry, PCMK__XE_LRM_RSC_OP,
1722 NULL, NULL);
1723 rsc_op != NULL; rsc_op = pcmk__xe_next_same(rsc_op)) {
1724
1725 ops = g_list_prepend(ops, rsc_op);
1726 }
1727 ops = g_list_sort(ops, sort_op_by_callid);
1728 calculate_active_ops(ops, start_index, stop_index);
1729 return ops;
1730 }
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746 static void
1747 process_rsc_history(const xmlNode *rsc_entry, pcmk_resource_t *rsc,
1748 pcmk_node_t *node)
1749 {
1750 int offset = -1;
1751 int stop_index = 0;
1752 int start_index = 0;
1753 GList *sorted_op_list = NULL;
1754
1755 if (pcmk_is_set(rsc->flags, pcmk_rsc_removed)) {
1756 if (pcmk__is_anonymous_clone(pe__const_top_resource(rsc, false))) {
1757 pcmk__rsc_trace(rsc,
1758 "Skipping configuration check "
1759 "for orphaned clone instance %s",
1760 rsc->id);
1761 } else {
1762 pcmk__rsc_trace(rsc,
1763 "Skipping configuration check and scheduling "
1764 "clean-up for orphaned resource %s", rsc->id);
1765 pcmk__schedule_cleanup(rsc, node, false);
1766 }
1767 return;
1768 }
1769
1770 if (pe_find_node_id(rsc->running_on, node->details->id) == NULL) {
1771 if (pcmk__rsc_agent_changed(rsc, node, rsc_entry, false)) {
1772 pcmk__schedule_cleanup(rsc, node, false);
1773 }
1774 pcmk__rsc_trace(rsc,
1775 "Skipping configuration check for %s "
1776 "because no longer active on %s",
1777 rsc->id, pcmk__node_name(node));
1778 return;
1779 }
1780
1781 pcmk__rsc_trace(rsc, "Checking for configuration changes for %s on %s",
1782 rsc->id, pcmk__node_name(node));
1783
1784 if (pcmk__rsc_agent_changed(rsc, node, rsc_entry, true)) {
1785 pcmk__schedule_cleanup(rsc, node, false);
1786 }
1787
1788 sorted_op_list = rsc_history_as_list(rsc_entry, &start_index, &stop_index);
1789 if (start_index < stop_index) {
1790 return;
1791 }
1792
1793 for (GList *iter = sorted_op_list; iter != NULL; iter = iter->next) {
1794 xmlNode *rsc_op = (xmlNode *) iter->data;
1795 const char *task = NULL;
1796 guint interval_ms = 0;
1797
1798 if (++offset < start_index) {
1799
1800 continue;
1801 }
1802
1803 task = crm_element_value(rsc_op, PCMK_XA_OPERATION);
1804 crm_element_value_ms(rsc_op, PCMK_META_INTERVAL, &interval_ms);
1805
1806 if ((interval_ms > 0)
1807 && (pcmk_is_set(rsc->flags, pcmk_rsc_maintenance)
1808 || node->details->maintenance)) {
1809
1810 pcmk__schedule_cancel(rsc,
1811 crm_element_value(rsc_op, PCMK__XA_CALL_ID),
1812 task, interval_ms, node, "maintenance mode");
1813
1814 } else if ((interval_ms > 0)
1815 || pcmk__strcase_any_of(task, PCMK_ACTION_MONITOR,
1816 PCMK_ACTION_START,
1817 PCMK_ACTION_PROMOTE,
1818 PCMK_ACTION_MIGRATE_FROM, NULL)) {
1819
1820
1821
1822
1823 if (pe__bundle_needs_remote_name(rsc)) {
1824
1825
1826
1827
1828
1829
1830
1831 pe__add_param_check(rsc_op, rsc, node, pcmk__check_active,
1832 rsc->cluster);
1833
1834 } else if (pcmk__check_action_config(rsc, node, rsc_op)
1835 && (pe_get_failcount(node, rsc, NULL, pcmk__fc_effective,
1836 NULL) != 0)) {
1837 pe__clear_failcount(rsc, node, "action definition changed",
1838 rsc->cluster);
1839 }
1840 }
1841 }
1842 g_list_free(sorted_op_list);
1843 }
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858 static void
1859 process_node_history(pcmk_node_t *node, const xmlNode *lrm_rscs)
1860 {
1861 crm_trace("Processing node history for %s", pcmk__node_name(node));
1862 for (const xmlNode *rsc_entry = pcmk__xe_first_child(lrm_rscs,
1863 PCMK__XE_LRM_RESOURCE,
1864 NULL, NULL);
1865 rsc_entry != NULL; rsc_entry = pcmk__xe_next_same(rsc_entry)) {
1866
1867 if (rsc_entry->children != NULL) {
1868 GList *result = pcmk__rscs_matching_id(pcmk__xe_id(rsc_entry),
1869 node->details->data_set);
1870
1871 for (GList *iter = result; iter != NULL; iter = iter->next) {
1872 pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
1873
1874 if (pcmk__is_primitive(rsc)) {
1875 process_rsc_history(rsc_entry, rsc, node);
1876 }
1877 }
1878 g_list_free(result);
1879 }
1880 }
1881 }
1882
1883
1884 #define XPATH_NODE_HISTORY "/" PCMK_XE_CIB "/" PCMK_XE_STATUS \
1885 "/" PCMK__XE_NODE_STATE \
1886 "[@" PCMK_XA_UNAME "='%s']" \
1887 "/" PCMK__XE_LRM "/" PCMK__XE_LRM_RESOURCES
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901 void
1902 pcmk__handle_rsc_config_changes(pcmk_scheduler_t *scheduler)
1903 {
1904 crm_trace("Check resource and action configuration for changes");
1905
1906
1907
1908
1909
1910 for (GList *iter = scheduler->nodes; iter != NULL; iter = iter->next) {
1911 pcmk_node_t *node = (pcmk_node_t *) iter->data;
1912
1913
1914
1915
1916
1917 if (node->details->maintenance
1918 || pcmk__node_available(node, false, false)) {
1919
1920 char *xpath = NULL;
1921 xmlNode *history = NULL;
1922
1923 xpath = crm_strdup_printf(XPATH_NODE_HISTORY, node->details->uname);
1924 history = get_xpath_object(xpath, scheduler->input, LOG_NEVER);
1925 free(xpath);
1926
1927 process_node_history(node, history);
1928 }
1929 }
1930 }