This source file includes following definitions.
- xe_interval
- is_op_dup
- op_cannot_recur
- is_recurring_history
- active_recurring_should_be_optional
- recurring_op_for_active
- cancel_if_running
- order_after_probes
- order_after_stops
- recurring_op_for_inactive
- pcmk__create_recurring_actions
- pcmk__new_cancel_action
- pcmk__schedule_cancel
- pcmk__reschedule_recurring
- pcmk__action_is_recurring
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdbool.h>
13
14 #include <crm/msg_xml.h>
15 #include <pacemaker-internal.h>
16
17 #include "libpacemaker_private.h"
18
19
20 struct op_history {
21
22 const char *id;
23 const char *name;
24
25
26 char *key;
27 enum rsc_role_e role;
28 guint interval_ms;
29 };
30
31
32
33
34
35
36
37
38
39 static guint
40 xe_interval(const xmlNode *xml)
41 {
42 return crm_parse_interval_spec(crm_element_value(xml,
43 XML_LRM_ATTR_INTERVAL));
44 }
45
46
47
48
49
50
51
52
53
54
55
56
57 static bool
58 is_op_dup(const pe_resource_t *rsc, const char *name, guint interval_ms)
59 {
60 const char *id = NULL;
61
62 for (xmlNode *op = first_named_child(rsc->ops_xml, "op");
63 op != NULL; op = crm_next_same_xml(op)) {
64
65
66 if (!pcmk__str_eq(crm_element_value(op, "name"),
67 name, pcmk__str_none)
68 || (xe_interval(op) != interval_ms)) {
69 continue;
70 }
71
72 if (ID(op) == NULL) {
73 continue;
74 }
75
76 if (id == NULL) {
77 id = ID(op);
78 } else {
79 pcmk__config_err("Operation %s is duplicate of %s (do not use "
80 "same name and interval combination more "
81 "than once per resource)", ID(op), id);
82 return true;
83 }
84 }
85 return false;
86 }
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 static bool
105 op_cannot_recur(const char *name)
106 {
107 return pcmk__str_any_of(name, RSC_STOP, RSC_START, RSC_DEMOTE, RSC_PROMOTE,
108 CRMD_ACTION_RELOAD_AGENT, CRMD_ACTION_MIGRATE,
109 CRMD_ACTION_MIGRATED, NULL);
110 }
111
112
113
114
115
116
117
118
119
120
121
122 static bool
123 is_recurring_history(const pe_resource_t *rsc, const xmlNode *xml,
124 struct op_history *op)
125 {
126 const char *role = NULL;
127
128 op->interval_ms = xe_interval(xml);
129 if (op->interval_ms == 0) {
130 return false;
131 }
132
133 op->id = ID(xml);
134 if (pcmk__str_empty(op->id)) {
135 pcmk__config_err("Ignoring resource history entry without ID");
136 return false;
137 }
138
139 op->name = crm_element_value(xml, "name");
140 if (op_cannot_recur(op->name)) {
141 pcmk__config_err("Ignoring %s because %s action cannot be recurring",
142 op->id, pcmk__s(op->name, "unnamed"));
143 return false;
144 }
145
146
147 if (is_op_dup(rsc, op->name, op->interval_ms)) {
148 return false;
149 }
150
151
152 role = crm_element_value(xml, "role");
153 if (role == NULL) {
154 op->role = RSC_ROLE_UNKNOWN;
155 } else {
156 op->role = text2role(role);
157 if (op->role == RSC_ROLE_UNKNOWN) {
158 pcmk__config_err("Ignoring %s because %s is not a valid role",
159 op->id, role);
160 }
161 }
162
163
164 op->key = pcmk__op_key(rsc->id, op->name, op->interval_ms);
165 if (find_rsc_op_entry(rsc, op->key) == NULL) {
166 crm_trace("Not creating recurring action %s for disabled resource %s",
167 op->id, rsc->id);
168 free(op->key);
169 return false;
170 }
171
172 return true;
173 }
174
175
176
177
178
179
180
181
182
183
184
185
186 static bool
187 active_recurring_should_be_optional(const pe_resource_t *rsc,
188 const pe_node_t *node, const char *key,
189 pe_action_t *start)
190 {
191 GList *possible_matches = NULL;
192
193 if (node == NULL) {
194 pe_rsc_trace(rsc, "%s will be mandatory because resource is unmanaged",
195 key);
196 return false;
197 }
198
199 if (!pcmk_is_set(rsc->cmds->action_flags(start, NULL),
200 pe_action_optional)) {
201 pe_rsc_trace(rsc, "%s will be mandatory because %s is",
202 key, start->uuid);
203 return false;
204 }
205
206 possible_matches = find_actions_exact(rsc->actions, key, node);
207 if (possible_matches == NULL) {
208 pe_rsc_trace(rsc, "%s will be mandatory because it is not active on %s",
209 key, pe__node_name(node));
210 return false;
211 }
212
213 for (GList *iter = possible_matches; iter != NULL; iter = iter->next) {
214 pe_action_t *op = (pe_action_t *) iter->data;
215
216 if (pcmk_is_set(op->flags, pe_action_reschedule)) {
217 pe_rsc_trace(rsc,
218 "%s will be mandatory because "
219 "it needs to be rescheduled", key);
220 g_list_free(possible_matches);
221 return false;
222 }
223 }
224
225 g_list_free(possible_matches);
226 return true;
227 }
228
229
230
231
232
233
234
235
236
237
238 static void
239 recurring_op_for_active(pe_resource_t *rsc, pe_action_t *start,
240 const pe_node_t *node, const struct op_history *op)
241 {
242 pe_action_t *mon = NULL;
243 bool is_optional = true;
244
245
246 if (op->role == RSC_ROLE_STOPPED) {
247 return;
248 }
249
250 is_optional = active_recurring_should_be_optional(rsc, node, op->key,
251 start);
252
253 if (((op->role != RSC_ROLE_UNKNOWN) && (rsc->next_role != op->role))
254 || ((op->role == RSC_ROLE_UNKNOWN)
255 && (rsc->next_role == RSC_ROLE_PROMOTED))) {
256
257
258 if (is_optional) {
259 char *after_key = NULL;
260 pe_action_t *cancel_op = pcmk__new_cancel_action(rsc, op->name,
261 op->interval_ms,
262 node);
263
264 switch (rsc->role) {
265 case RSC_ROLE_UNPROMOTED:
266 case RSC_ROLE_STARTED:
267 if (rsc->next_role == RSC_ROLE_PROMOTED) {
268 after_key = promote_key(rsc);
269
270 } else if (rsc->next_role == RSC_ROLE_STOPPED) {
271 after_key = stop_key(rsc);
272 }
273
274 break;
275 case RSC_ROLE_PROMOTED:
276 after_key = demote_key(rsc);
277 break;
278 default:
279 break;
280 }
281
282 if (after_key) {
283 pcmk__new_ordering(rsc, NULL, cancel_op, rsc, after_key, NULL,
284 pe_order_runnable_left, rsc->cluster);
285 }
286 }
287
288 do_crm_log((is_optional? LOG_INFO : LOG_TRACE),
289 "%s recurring action %s because %s configured for %s role "
290 "(not %s)",
291 (is_optional? "Cancelling" : "Ignoring"), op->key, op->id,
292 role2text((op->role == RSC_ROLE_UNKNOWN)? RSC_ROLE_UNPROMOTED : op->role),
293 role2text(rsc->next_role));
294 return;
295 }
296
297 pe_rsc_trace(rsc,
298 "Creating %s recurring action %s for %s (%s %s on %s)",
299 (is_optional? "optional" : "mandatory"), op->key,
300 op->id, rsc->id, role2text(rsc->next_role),
301 pe__node_name(node));
302
303 mon = custom_action(rsc, strdup(op->key), op->name, node, is_optional, TRUE,
304 rsc->cluster);
305
306 if (!pcmk_is_set(start->flags, pe_action_runnable)) {
307 pe_rsc_trace(rsc, "%s is unrunnable because start is", mon->uuid);
308 pe__clear_action_flags(mon, pe_action_runnable);
309
310 } else if ((node == NULL) || !node->details->online
311 || node->details->unclean) {
312 pe_rsc_trace(rsc, "%s is unrunnable because no node is available",
313 mon->uuid);
314 pe__clear_action_flags(mon, pe_action_runnable);
315
316 } else if (!pcmk_is_set(mon->flags, pe_action_optional)) {
317 pe_rsc_info(rsc, "Start %s-interval %s for %s on %s",
318 pcmk__readable_interval(op->interval_ms), mon->task,
319 rsc->id, pe__node_name(node));
320 }
321
322 if (rsc->next_role == RSC_ROLE_PROMOTED) {
323 pe__add_action_expected_result(mon, CRM_EX_PROMOTED);
324 }
325
326
327 if ((node == NULL) || pcmk_is_set(rsc->flags, pe_rsc_managed)) {
328 pcmk__new_ordering(rsc, start_key(rsc), NULL,
329 NULL, strdup(mon->uuid), mon,
330 pe_order_implies_then|pe_order_runnable_left,
331 rsc->cluster);
332
333 pcmk__new_ordering(rsc, reload_key(rsc), NULL,
334 NULL, strdup(mon->uuid), mon,
335 pe_order_implies_then|pe_order_runnable_left,
336 rsc->cluster);
337
338 if (rsc->next_role == RSC_ROLE_PROMOTED) {
339 pcmk__new_ordering(rsc, promote_key(rsc), NULL,
340 rsc, NULL, mon,
341 pe_order_optional|pe_order_runnable_left,
342 rsc->cluster);
343
344 } else if (rsc->role == RSC_ROLE_PROMOTED) {
345 pcmk__new_ordering(rsc, demote_key(rsc), NULL,
346 rsc, NULL, mon,
347 pe_order_optional|pe_order_runnable_left,
348 rsc->cluster);
349 }
350 }
351 }
352
353
354
355
356
357
358
359
360
361
362
363 static void
364 cancel_if_running(pe_resource_t *rsc, const pe_node_t *node, const char *key,
365 const char *name, guint interval_ms)
366 {
367 GList *possible_matches = find_actions_exact(rsc->actions, key, node);
368 pe_action_t *cancel_op = NULL;
369
370 if (possible_matches == NULL) {
371 return;
372 }
373 g_list_free(possible_matches);
374
375 cancel_op = pcmk__new_cancel_action(rsc, name, interval_ms, node);
376
377 switch (rsc->next_role) {
378 case RSC_ROLE_STARTED:
379 case RSC_ROLE_UNPROMOTED:
380
381
382
383
384
385 pcmk__new_ordering(rsc, NULL, cancel_op,
386 rsc, start_key(rsc), NULL,
387 pe_order_runnable_left, rsc->cluster);
388 break;
389 default:
390 break;
391 }
392 pe_rsc_info(rsc,
393 "Cancelling %s-interval %s action for %s on %s because "
394 "configured for " RSC_ROLE_STOPPED_S " role (not %s)",
395 pcmk__readable_interval(interval_ms), name, rsc->id,
396 pe__node_name(node), role2text(rsc->next_role));
397 }
398
399
400
401
402
403
404
405
406
407 static void
408 order_after_probes(pe_resource_t *rsc, const pe_node_t *node,
409 pe_action_t *action)
410 {
411 GList *probes = pe__resource_actions(rsc, node, RSC_STATUS, FALSE);
412
413 for (GList *iter = probes; iter != NULL; iter = iter->next) {
414 order_actions((pe_action_t *) iter->data, action,
415 pe_order_runnable_left);
416 }
417 g_list_free(probes);
418 }
419
420
421
422
423
424
425
426
427
428 static void
429 order_after_stops(pe_resource_t *rsc, const pe_node_t *node,
430 pe_action_t *action)
431 {
432 GList *stop_ops = pe__resource_actions(rsc, node, RSC_STOP, TRUE);
433
434 for (GList *iter = stop_ops; iter != NULL; iter = iter->next) {
435 pe_action_t *stop = (pe_action_t *) iter->data;
436
437 if (!pcmk_is_set(stop->flags, pe_action_optional)
438 && !pcmk_is_set(action->flags, pe_action_optional)
439 && !pcmk_is_set(rsc->flags, pe_rsc_managed)) {
440 pe_rsc_trace(rsc, "%s optional on %s: unmanaged",
441 action->uuid, pe__node_name(node));
442 pe__set_action_flags(action, pe_action_optional);
443 }
444
445 if (!pcmk_is_set(stop->flags, pe_action_runnable)) {
446 crm_debug("%s unrunnable on %s: stop is unrunnable",
447 action->uuid, pe__node_name(node));
448 pe__clear_action_flags(action, pe_action_runnable);
449 }
450
451 if (pcmk_is_set(rsc->flags, pe_rsc_managed)) {
452 pcmk__new_ordering(rsc, stop_key(rsc), stop,
453 NULL, NULL, action,
454 pe_order_implies_then|pe_order_runnable_left,
455 rsc->cluster);
456 }
457 }
458 g_list_free(stop_ops);
459 }
460
461
462
463
464
465
466
467
468
469 static void
470 recurring_op_for_inactive(pe_resource_t *rsc, const pe_node_t *node,
471 const struct op_history *op)
472 {
473 GList *possible_matches = NULL;
474
475
476 if (op->role != RSC_ROLE_STOPPED) {
477 return;
478 }
479
480 if (!pcmk_is_set(rsc->flags, pe_rsc_unique)) {
481 crm_notice("Ignoring %s (recurring monitors for " RSC_ROLE_STOPPED_S
482 " role are not supported for anonymous clones)", op->id);
483 return;
484 }
485
486 pe_rsc_trace(rsc, "Creating recurring action %s for %s on nodes "
487 "where it should not be running", op->id, rsc->id);
488
489 for (GList *iter = rsc->cluster->nodes; iter != NULL; iter = iter->next) {
490 pe_node_t *stop_node = (pe_node_t *) iter->data;
491
492 bool is_optional = true;
493 pe_action_t *stopped_mon = NULL;
494
495
496 if ((node != NULL)
497 && pcmk__str_eq(stop_node->details->uname, node->details->uname,
498 pcmk__str_casei)) {
499 cancel_if_running(rsc, node, op->key, op->name, op->interval_ms);
500 continue;
501 }
502
503
504 possible_matches = find_actions_exact(rsc->actions, op->key, stop_node);
505 is_optional = (possible_matches != NULL);
506 g_list_free(possible_matches);
507
508 pe_rsc_trace(rsc,
509 "Creating %s recurring action %s for %s (%s "
510 RSC_ROLE_STOPPED_S " on %s)",
511 (is_optional? "optional" : "mandatory"),
512 op->key, op->id, rsc->id, pe__node_name(stop_node));
513
514 stopped_mon = custom_action(rsc, strdup(op->key), op->name, stop_node,
515 is_optional, TRUE, rsc->cluster);
516
517 pe__add_action_expected_result(stopped_mon, CRM_EX_NOT_RUNNING);
518
519 if (pcmk_is_set(rsc->flags, pe_rsc_managed)) {
520 order_after_probes(rsc, stop_node, stopped_mon);
521 }
522
523
524
525
526 order_after_stops(rsc, stop_node, stopped_mon);
527
528 if (!stop_node->details->online || stop_node->details->unclean) {
529 pe_rsc_debug(rsc, "%s unrunnable on %s: node unavailable)",
530 stopped_mon->uuid, pe__node_name(stop_node));
531 pe__clear_action_flags(stopped_mon, pe_action_runnable);
532 }
533
534 if (pcmk_is_set(stopped_mon->flags, pe_action_runnable)
535 && !pcmk_is_set(stopped_mon->flags, pe_action_optional)) {
536 crm_notice("Start recurring %s-interval %s for "
537 RSC_ROLE_STOPPED_S " %s on %s",
538 pcmk__readable_interval(op->interval_ms),
539 stopped_mon->task, rsc->id, pe__node_name(stop_node));
540 }
541 }
542 }
543
544
545
546
547
548
549
550 void
551 pcmk__create_recurring_actions(pe_resource_t *rsc)
552 {
553 pe_action_t *start = NULL;
554
555 if (pcmk_is_set(rsc->flags, pe_rsc_block)) {
556 pe_rsc_trace(rsc, "Skipping recurring actions for blocked resource %s",
557 rsc->id);
558 return;
559 }
560
561 if (pcmk_is_set(rsc->flags, pe_rsc_maintenance)) {
562 pe_rsc_trace(rsc, "Skipping recurring actions for %s "
563 "in maintenance mode", rsc->id);
564 return;
565 }
566
567 if (rsc->allocated_to == NULL) {
568
569
570 } else if (rsc->allocated_to->details->maintenance) {
571 pe_rsc_trace(rsc,
572 "Skipping recurring actions for %s on %s "
573 "in maintenance mode",
574 rsc->id, pe__node_name(rsc->allocated_to));
575
576 } else if ((rsc->next_role != RSC_ROLE_STOPPED)
577 || !pcmk_is_set(rsc->flags, pe_rsc_managed)) {
578
579 start = start_action(rsc, rsc->allocated_to, TRUE);
580 }
581
582 pe_rsc_trace(rsc, "Creating any recurring actions needed for %s", rsc->id);
583
584 for (xmlNode *op = first_named_child(rsc->ops_xml, "op");
585 op != NULL; op = crm_next_same_xml(op)) {
586
587 struct op_history op_history = { NULL, };
588
589 if (!is_recurring_history(rsc, op, &op_history)) {
590 continue;
591 }
592
593 if (start != NULL) {
594 recurring_op_for_active(rsc, start, rsc->allocated_to, &op_history);
595 }
596 recurring_op_for_inactive(rsc, rsc->allocated_to, &op_history);
597
598 free(op_history.key);
599 }
600 }
601
602
603
604
605
606
607
608
609
610
611
612
613 pe_action_t *
614 pcmk__new_cancel_action(pe_resource_t *rsc, const char *task, guint interval_ms,
615 const pe_node_t *node)
616 {
617 pe_action_t *cancel_op = NULL;
618 char *key = NULL;
619 char *interval_ms_s = NULL;
620
621 CRM_ASSERT((rsc != NULL) && (task != NULL) && (node != NULL));
622
623
624 key = pcmk__op_key(rsc->id, task, interval_ms);
625
626 cancel_op = custom_action(rsc, key, RSC_CANCEL, node, FALSE, TRUE,
627 rsc->cluster);
628
629 pcmk__str_update(&cancel_op->task, RSC_CANCEL);
630 pcmk__str_update(&cancel_op->cancel_task, task);
631
632 interval_ms_s = crm_strdup_printf("%u", interval_ms);
633 add_hash_param(cancel_op->meta, XML_LRM_ATTR_TASK, task);
634 add_hash_param(cancel_op->meta, XML_LRM_ATTR_INTERVAL_MS, interval_ms_s);
635 free(interval_ms_s);
636
637 return cancel_op;
638 }
639
640
641
642
643
644
645
646
647
648
649
650
651 void
652 pcmk__schedule_cancel(pe_resource_t *rsc, const char *call_id, const char *task,
653 guint interval_ms, const pe_node_t *node,
654 const char *reason)
655 {
656 pe_action_t *cancel = NULL;
657
658 CRM_CHECK((rsc != NULL) && (task != NULL)
659 && (node != NULL) && (reason != NULL),
660 return);
661
662 crm_info("Recurring %s-interval %s for %s will be stopped on %s: %s",
663 pcmk__readable_interval(interval_ms), task, rsc->id,
664 pe__node_name(node), reason);
665 cancel = pcmk__new_cancel_action(rsc, task, interval_ms, node);
666 add_hash_param(cancel->meta, XML_LRM_ATTR_CALLID, call_id);
667
668
669 pcmk__new_ordering(rsc, stop_key(rsc), NULL, rsc, NULL, cancel,
670 pe_order_optional, rsc->cluster);
671 }
672
673
674
675
676
677
678
679
680
681
682 void
683 pcmk__reschedule_recurring(pe_resource_t *rsc, const char *task,
684 guint interval_ms, pe_node_t *node)
685 {
686 pe_action_t *op = NULL;
687
688 trigger_unfencing(rsc, node, "Device parameters changed (reschedule)",
689 NULL, rsc->cluster);
690 op = custom_action(rsc, pcmk__op_key(rsc->id, task, interval_ms),
691 task, node, TRUE, TRUE, rsc->cluster);
692 pe__set_action_flags(op, pe_action_reschedule);
693 }
694
695
696
697
698
699
700
701
702
703 bool
704 pcmk__action_is_recurring(const pe_action_t *action)
705 {
706 guint interval_ms = 0;
707
708 if (pcmk__guint_from_hash(action->meta,
709 XML_LRM_ATTR_INTERVAL_MS, 0,
710 &interval_ms) != pcmk_rc_ok) {
711 return false;
712 }
713 return (interval_ms > 0);
714 }