pacemaker  2.1.5-b7adf64e51
Scalable High-Availability cluster resource manager
pcmk_sched_actions.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2022 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU General Public License version 2
7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
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 <pacemaker-internal.h>
18 #include "libpacemaker_private.h"
19 
30 static enum pe_action_flags
31 action_flags_for_ordering(pe_action_t *action, pe_node_t *node)
32 {
33  bool runnable = false;
35 
36  // For non-resource actions, return the action flags
37  if (action->rsc == NULL) {
38  return action->flags;
39  }
40 
41  /* For non-clone resources, or a clone action not assigned to a node,
42  * return the flags as determined by the resource method without a node
43  * specified.
44  */
45  flags = action->rsc->cmds->action_flags(action, NULL);
46  if ((node == NULL) || !pe_rsc_is_clone(action->rsc)) {
47  return flags;
48  }
49 
50  /* Otherwise (i.e., for clone resource actions on a specific node), first
51  * remember whether the non-node-specific action is runnable.
52  */
54 
55  // Then recheck the resource method with the node
56  flags = action->rsc->cmds->action_flags(action, node);
57 
58  /* For clones in ordering constraints, the node-specific "runnable" doesn't
59  * matter, just the non-node-specific setting (i.e., is the action runnable
60  * anywhere).
61  *
62  * This applies only to runnable, and only for ordering constraints. This
63  * function shouldn't be used for other types of constraints without
64  * changes. Not very satisfying, but it's logical and appears to work well.
65  */
66  if (runnable && !pcmk_is_set(flags, pe_action_runnable)) {
69  }
70  return flags;
71 }
72 
91 static char *
92 action_uuid_for_ordering(const char *first_uuid, pe_resource_t *first_rsc)
93 {
94  guint interval_ms = 0;
95  char *uuid = NULL;
96  char *rid = NULL;
97  char *first_task_str = NULL;
98  enum action_tasks first_task = no_action;
99  enum action_tasks remapped_task = no_action;
100 
101  // Only non-notify actions for collective resources need remapping
102  if ((strstr(first_uuid, "notify") != NULL)
103  || (first_rsc->variant < pe_group)) {
104  goto done;
105  }
106 
107  // Only non-recurring actions need remapping
108  CRM_ASSERT(parse_op_key(first_uuid, &rid, &first_task_str, &interval_ms));
109  if (interval_ms > 0) {
110  goto done;
111  }
112 
113  first_task = text2task(first_task_str);
114  switch (first_task) {
115  case stop_rsc:
116  case start_rsc:
117  case action_notify:
118  case action_promote:
119  case action_demote:
120  remapped_task = first_task + 1;
121  break;
122  case stopped_rsc:
123  case started_rsc:
124  case action_notified:
125  case action_promoted:
126  case action_demoted:
127  remapped_task = first_task;
128  break;
129  case monitor_rsc:
130  case shutdown_crm:
131  case stonith_node:
132  break;
133  default:
134  crm_err("Unknown action '%s' in ordering", first_task_str);
135  break;
136  }
137 
138  if (remapped_task != no_action) {
139  /* If a (clone) resource has notifications enabled, we want to order
140  * relative to when all notifications have been sent for the remapped
141  * task. Only outermost resources or those in bundles have
142  * notifications.
143  */
144  if (pcmk_is_set(first_rsc->flags, pe_rsc_notify)
145  && ((first_rsc->parent == NULL)
146  || (pe_rsc_is_clone(first_rsc)
147  && (first_rsc->parent->variant == pe_container)))) {
148  uuid = pcmk__notify_key(rid, "confirmed-post",
149  task2text(remapped_task));
150  } else {
151  uuid = pcmk__op_key(rid, task2text(remapped_task), 0);
152  }
153  pe_rsc_trace(first_rsc,
154  "Remapped action UUID %s to %s for ordering purposes",
155  first_uuid, uuid);
156  }
157 
158 done:
159  if (uuid == NULL) {
160  uuid = strdup(first_uuid);
161  CRM_ASSERT(uuid != NULL);
162  }
163  free(first_task_str);
164  free(rid);
165  return uuid;
166 }
167 
184 static pe_action_t *
185 action_for_ordering(pe_action_t *action)
186 {
188  pe_resource_t *rsc = action->rsc;
189 
190  if ((rsc != NULL) && (rsc->variant >= pe_group) && (action->uuid != NULL)) {
191  char *uuid = action_uuid_for_ordering(action->uuid, rsc);
192 
193  result = find_first_action(rsc->actions, uuid, NULL, NULL);
194  if (result == NULL) {
195  crm_warn("Not remapping %s to %s because %s does not have "
196  "remapped action", action->uuid, uuid, rsc->id);
197  result = action;
198  }
199  free(uuid);
200  }
201  return result;
202 }
203 
217 static uint32_t
218 update_action_for_ordering_flags(pe_action_t *first, pe_action_t *then,
219  enum pe_action_flags first_flags,
220  enum pe_action_flags then_flags,
221  pe_action_wrapper_t *order,
223 {
224  uint32_t changed = pcmk__updated_none;
225 
226  /* The node will only be used for clones. If interleaved, node will be NULL,
227  * otherwise the ordering scope will be limited to the node. Normally, the
228  * whole 'then' clone should restart if 'first' is restarted, so then->node
229  * is needed.
230  */
231  pe_node_t *node = then->node;
232 
234  /* For unfencing, only instances of 'then' on the same node as 'first'
235  * (the unfencing operation) should restart, so reset node to
236  * first->node, at which point this case is handled like a normal
237  * pe_order_implies_then.
238  */
241  node = first->node;
242  pe_rsc_trace(then->rsc,
243  "%s then %s: mapped pe_order_implies_then_on_node to "
244  "pe_order_implies_then on %s",
245  first->uuid, then->uuid, pe__node_name(node));
246  }
247 
248  if (pcmk_is_set(order->type, pe_order_implies_then)) {
249  if (then->rsc != NULL) {
250  changed |= then->rsc->cmds->update_ordered_actions(first, then,
251  node,
252  first_flags & pe_action_optional,
255  data_set);
256  } else if (!pcmk_is_set(first_flags, pe_action_optional)
257  && pcmk_is_set(then->flags, pe_action_optional)) {
260  }
261  pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_implies_then",
262  first->uuid, then->uuid,
263  (changed? "changed" : "unchanged"));
264  }
265 
266  if (pcmk_is_set(order->type, pe_order_restart) && (then->rsc != NULL)) {
268 
269  changed |= then->rsc->cmds->update_ordered_actions(first, then, node,
270  first_flags, restart,
272  data_set);
273  pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_restart",
274  first->uuid, then->uuid,
275  (changed? "changed" : "unchanged"));
276  }
277 
278  if (pcmk_is_set(order->type, pe_order_implies_first)) {
279  if (first->rsc != NULL) {
280  changed |= first->rsc->cmds->update_ordered_actions(first, then,
281  node,
282  first_flags,
285  data_set);
286  } else if (!pcmk_is_set(first_flags, pe_action_optional)
287  && pcmk_is_set(first->flags, pe_action_runnable)) {
290  }
291  pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_implies_first",
292  first->uuid, then->uuid,
293  (changed? "changed" : "unchanged"));
294  }
295 
297  if (then->rsc != NULL) {
298  changed |= then->rsc->cmds->update_ordered_actions(first, then,
299  node,
300  first_flags & pe_action_optional,
303  data_set);
304  }
305  pe_rsc_trace(then->rsc,
306  "%s then %s: %s after pe_order_promoted_implies_first",
307  first->uuid, then->uuid,
308  (changed? "changed" : "unchanged"));
309  }
310 
311  if (pcmk_is_set(order->type, pe_order_one_or_more)) {
312  if (then->rsc != NULL) {
313  changed |= then->rsc->cmds->update_ordered_actions(first, then,
314  node,
315  first_flags,
318  data_set);
319 
320  } else if (pcmk_is_set(first_flags, pe_action_runnable)) {
321  // We have another runnable instance of "first"
322  then->runnable_before++;
323 
324  /* Mark "then" as runnable if it requires a certain number of
325  * "before" instances to be runnable, and they now are.
326  */
327  if ((then->runnable_before >= then->required_runnable_before)
328  && !pcmk_is_set(then->flags, pe_action_runnable)) {
329 
332  }
333  }
334  pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_one_or_more",
335  first->uuid, then->uuid,
336  (changed? "changed" : "unchanged"));
337  }
338 
339  if (pcmk_is_set(order->type, pe_order_probe) && (then->rsc != NULL)) {
340  if (!pcmk_is_set(first_flags, pe_action_runnable)
341  && (first->rsc->running_on != NULL)) {
342 
343  pe_rsc_trace(then->rsc,
344  "%s then %s: ignoring because first is stopping",
345  first->uuid, then->uuid);
346  order->type = pe_order_none;
347  } else {
348  changed |= then->rsc->cmds->update_ordered_actions(first, then,
349  node,
350  first_flags,
353  data_set);
354  }
355  pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_probe",
356  first->uuid, then->uuid,
357  (changed? "changed" : "unchanged"));
358  }
359 
360  if (pcmk_is_set(order->type, pe_order_runnable_left)) {
361  if (then->rsc != NULL) {
362  changed |= then->rsc->cmds->update_ordered_actions(first, then,
363  node,
364  first_flags,
367  data_set);
368 
369  } else if (!pcmk_is_set(first_flags, pe_action_runnable)
370  && pcmk_is_set(then->flags, pe_action_runnable)) {
371 
374  }
375  pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_runnable_left",
376  first->uuid, then->uuid,
377  (changed? "changed" : "unchanged"));
378  }
379 
381  if (then->rsc != NULL) {
382  changed |= then->rsc->cmds->update_ordered_actions(first, then,
383  node,
384  first_flags,
387  data_set);
388  }
389  pe_rsc_trace(then->rsc, "%s then %s: %s after "
390  "pe_order_implies_first_migratable",
391  first->uuid, then->uuid,
392  (changed? "changed" : "unchanged"));
393  }
394 
395  if (pcmk_is_set(order->type, pe_order_pseudo_left)) {
396  if (then->rsc != NULL) {
397  changed |= then->rsc->cmds->update_ordered_actions(first, then,
398  node,
399  first_flags,
402  data_set);
403  }
404  pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_pseudo_left",
405  first->uuid, then->uuid,
406  (changed? "changed" : "unchanged"));
407  }
408 
409  if (pcmk_is_set(order->type, pe_order_optional)) {
410  if (then->rsc != NULL) {
411  changed |= then->rsc->cmds->update_ordered_actions(first, then,
412  node,
413  first_flags,
416  data_set);
417  }
418  pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_optional",
419  first->uuid, then->uuid,
420  (changed? "changed" : "unchanged"));
421  }
422 
423  if (pcmk_is_set(order->type, pe_order_asymmetrical)) {
424  if (then->rsc != NULL) {
425  changed |= then->rsc->cmds->update_ordered_actions(first, then,
426  node,
427  first_flags,
430  data_set);
431  }
432  pe_rsc_trace(then->rsc, "%s then %s: %s after pe_order_asymmetrical",
433  first->uuid, then->uuid,
434  (changed? "changed" : "unchanged"));
435  }
436 
439  && !pcmk_is_set(first_flags, pe_action_optional)) {
440 
441  pe_rsc_trace(then->rsc, "%s will be in graph because %s is required",
442  then->uuid, first->uuid);
444  // Don't bother marking 'then' as changed just for this
445  }
446 
448  && !pcmk_is_set(then_flags, pe_action_optional)) {
449 
450  pe_rsc_trace(then->rsc, "%s will be in graph because %s is required",
451  first->uuid, then->uuid);
453  // Don't bother marking 'first' as changed just for this
454  }
455 
456  if (pcmk_any_flags_set(order->type, pe_order_implies_then
459  && (first->rsc != NULL)
460  && !pcmk_is_set(first->rsc->flags, pe_rsc_managed)
461  && pcmk_is_set(first->rsc->flags, pe_rsc_block)
463  && pcmk__str_eq(first->task, RSC_STOP, pcmk__str_casei)) {
464 
465  if (pcmk_is_set(then->flags, pe_action_runnable)) {
468  }
469  pe_rsc_trace(then->rsc, "%s then %s: %s after checking whether first "
470  "is blocked, unmanaged, unrunnable stop",
471  first->uuid, then->uuid,
472  (changed? "changed" : "unchanged"));
473  }
474 
475  return changed;
476 }
477 
478 // Convenience macros for logging action properties
479 
480 #define action_type_str(flags) \
481  (pcmk_is_set((flags), pe_action_pseudo)? "pseudo-action" : "action")
482 
483 #define action_optional_str(flags) \
484  (pcmk_is_set((flags), pe_action_optional)? "optional" : "required")
485 
486 #define action_runnable_str(flags) \
487  (pcmk_is_set((flags), pe_action_runnable)? "runnable" : "unrunnable")
488 
489 #define action_node_str(a) \
490  (((a)->node == NULL)? "no node" : (a)->node->details->uname)
491 
499 void
501 {
502  GList *lpc = NULL;
503  uint32_t changed = pcmk__updated_none;
504  int last_flags = then->flags;
505 
506  pe_rsc_trace(then->rsc, "Updating %s %s (%s %s) on %s",
507  action_type_str(then->flags), then->uuid,
508  action_optional_str(then->flags),
510 
512  /* Initialize current known "runnable before" actions. As
513  * update_action_for_ordering_flags() is called for each of then's
514  * before actions, this number will increment as runnable 'first'
515  * actions are encountered.
516  */
517  then->runnable_before = 0;
518 
519  if (then->required_runnable_before == 0) {
520  /* @COMPAT This ordering constraint uses the deprecated
521  * "require-all=false" attribute. Treat it like "clone-min=1".
522  */
523  then->required_runnable_before = 1;
524  }
525 
526  /* The pe_order_one_or_more clause of update_action_for_ordering_flags()
527  * (called below) will reset runnable if appropriate.
528  */
530  }
531 
532  for (lpc = then->actions_before; lpc != NULL; lpc = lpc->next) {
533  pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc->data;
534  pe_action_t *first = other->action;
535 
536  pe_node_t *then_node = then->node;
537  pe_node_t *first_node = first->node;
538 
539  if ((first->rsc != NULL)
540  && (first->rsc->variant == pe_group)
541  && pcmk__str_eq(first->task, RSC_START, pcmk__str_casei)) {
542 
543  first_node = first->rsc->fns->location(first->rsc, NULL, FALSE);
544  if (first_node != NULL) {
545  pe_rsc_trace(first->rsc, "Found %s for 'first' %s",
546  pe__node_name(first_node), first->uuid);
547  }
548  }
549 
550  if ((then->rsc != NULL)
551  && (then->rsc->variant == pe_group)
552  && pcmk__str_eq(then->task, RSC_START, pcmk__str_casei)) {
553 
554  then_node = then->rsc->fns->location(then->rsc, NULL, FALSE);
555  if (then_node != NULL) {
556  pe_rsc_trace(then->rsc, "Found %s for 'then' %s",
557  pe__node_name(then_node), then->uuid);
558  }
559  }
560 
561  // Disable constraint if it only applies when on same node, but isn't
562  if (pcmk_is_set(other->type, pe_order_same_node)
563  && (first_node != NULL) && (then_node != NULL)
564  && (first_node->details != then_node->details)) {
565 
566  pe_rsc_trace(then->rsc,
567  "Disabled ordering %s on %s then %s on %s: not same node",
568  other->action->uuid, pe__node_name(first_node),
569  then->uuid, pe__node_name(then_node));
570  other->type = pe_order_none;
571  continue;
572  }
573 
575 
576  if ((first->rsc != NULL)
578  && !pcmk_is_set(then->flags, pe_action_optional)) {
579 
580  /* 'then' is required, so we must abandon 'first'
581  * (e.g. a required stop cancels any agent reload).
582  */
584  if (!strcmp(first->task, CRMD_ACTION_RELOAD_AGENT)) {
586  }
587  }
588 
589  if ((first->rsc != NULL) && (then->rsc != NULL)
590  && (first->rsc != then->rsc) && !is_parent(then->rsc, first->rsc)) {
591  first = action_for_ordering(first);
592  }
593  if (first != other->action) {
594  pe_rsc_trace(then->rsc, "Ordering %s after %s instead of %s",
595  then->uuid, first->uuid, other->action->uuid);
596  }
597 
598  pe_rsc_trace(then->rsc,
599  "%s (%#.6x) then %s (%#.6x): type=%#.6x node=%s",
600  first->uuid, first->flags, then->uuid, then->flags,
601  other->type, action_node_str(first));
602 
603  if (first == other->action) {
604  /* 'first' was not remapped (e.g. from 'start' to 'running'), which
605  * could mean it is a non-resource action, a primitive resource
606  * action, or already expanded.
607  */
608  enum pe_action_flags first_flags, then_flags;
609 
610  first_flags = action_flags_for_ordering(first, then_node);
611  then_flags = action_flags_for_ordering(then, first_node);
612 
613  changed |= update_action_for_ordering_flags(first, then,
614  first_flags, then_flags,
615  other, data_set);
616 
617  /* 'first' was for a complex resource (clone, group, etc),
618  * create a new dependency if necessary
619  */
620  } else if (order_actions(first, then, other->type)) {
621  /* This was the first time 'first' and 'then' were associated,
622  * start again to get the new actions_before list
623  */
625  pe_rsc_trace(then->rsc,
626  "Disabled ordering %s then %s in favor of %s then %s",
627  other->action->uuid, then->uuid, first->uuid,
628  then->uuid);
629  other->type = pe_order_none;
630  }
631 
632 
633  if (pcmk_is_set(changed, pcmk__updated_first)) {
634  crm_trace("Re-processing %s and its 'after' actions "
635  "because it changed", first->uuid);
636  for (GList *lpc2 = first->actions_after; lpc2 != NULL;
637  lpc2 = lpc2->next) {
638  pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc2->data;
639 
641  }
643  }
644  }
645 
647  if (last_flags == then->flags) {
649  } else {
651  }
652  }
653 
654  if (pcmk_is_set(changed, pcmk__updated_then)) {
655  crm_trace("Re-processing %s and its 'after' actions because it changed",
656  then->uuid);
657  if (pcmk_is_set(last_flags, pe_action_runnable)
658  && !pcmk_is_set(then->flags, pe_action_runnable)) {
660  }
662  for (lpc = then->actions_after; lpc != NULL; lpc = lpc->next) {
663  pe_action_wrapper_t *other = (pe_action_wrapper_t *) lpc->data;
664 
666  }
667  }
668 }
669 
670 static inline bool
671 is_primitive_action(pe_action_t *action)
672 {
673  return action && action->rsc && (action->rsc->variant == pe_native);
674 }
675 
684 #define clear_action_flag_because(action, flag, reason) do { \
685  if (pcmk_is_set((action)->flags, (flag))) { \
686  pe__clear_action_flags(action, flag); \
687  if ((action)->rsc != (reason)->rsc) { \
688  char *reason_text = pe__action2reason((reason), (flag)); \
689  pe_action_set_reason((action), reason_text, \
690  ((flag) == pe_action_migrate_runnable)); \
691  free(reason_text); \
692  } \
693  } \
694  } while (0)
695 
703 static void
704 handle_asymmetric_ordering(pe_action_t *first, pe_action_t *then)
705 {
706  enum rsc_role_e then_rsc_role = RSC_ROLE_UNKNOWN;
707  GList *then_on = NULL;
708 
709  if (then->rsc == NULL) {
710  // Asymmetric orderings only matter if there's a resource involved
711  return;
712  }
713 
714  then_rsc_role = then->rsc->fns->state(then->rsc, TRUE);
715  then_on = then->rsc->running_on;
716 
717  if ((then_rsc_role == RSC_ROLE_STOPPED)
718  && pcmk__str_eq(then->task, RSC_STOP, pcmk__str_none)) {
719  /* Nothing needs to be done for asymmetric ordering if 'then' is
720  * supposed to be stopped after 'first' but is already stopped.
721  */
722  return;
723  }
724 
725  if ((then_rsc_role >= RSC_ROLE_STARTED)
727  && (then->node != NULL)
728  && pcmk__list_of_1(then_on)
729  && (then->node->details == ((pe_node_t *) then_on->data)->details)
730  && pcmk__str_eq(then->task, RSC_START, pcmk__str_none)) {
731  /* Nothing needs to be done for asymmetric ordering if 'then' is
732  * supposed to be started after 'first' but is already started --
733  * unless the start is mandatory, which indicates the resource is
734  * restarting and the ordering is still needed.
735  */
736  return;
737  }
738 
739  if (!pcmk_is_set(first->flags, pe_action_runnable)) {
740  // 'First' can't run, so 'then' can't either
743  }
744 }
745 
757 static void
758 handle_restart_ordering(pe_action_t *first, pe_action_t *then, uint32_t filter)
759 {
760  const char *reason = NULL;
761 
762  CRM_ASSERT(is_primitive_action(first));
763  CRM_ASSERT(is_primitive_action(then));
764 
765  // We need to update the action in two cases:
766 
767  // ... if 'then' is required
768  if (pcmk_is_set(filter, pe_action_optional)
769  && !pcmk_is_set(then->flags, pe_action_optional)) {
770  reason = "restart";
771  }
772 
773  /* ... if 'then' is unrunnable action on same resource (if a resource
774  * should restart but can't start, we still want to stop)
775  */
776  if (pcmk_is_set(filter, pe_action_runnable)
778  && pcmk_is_set(then->rsc->flags, pe_rsc_managed)
779  && (first->rsc == then->rsc)) {
780  reason = "stop";
781  }
782 
783  if (reason == NULL) {
784  return;
785  }
786 
787  pe_rsc_trace(first->rsc, "Handling %s -> %s for %s",
788  first->uuid, then->uuid, reason);
789 
790  // Make 'first' required if it is runnable
791  if (pcmk_is_set(first->flags, pe_action_runnable)) {
793  }
794 
795  // Make 'first' required if 'then' is required
796  if (!pcmk_is_set(then->flags, pe_action_optional)) {
798  }
799 
800  // Make 'first' unmigratable if 'then' is unmigratable
803  }
804 
805  // Make 'then' unrunnable if 'first' is required but unrunnable
806  if (!pcmk_is_set(first->flags, pe_action_optional)
807  && !pcmk_is_set(first->flags, pe_action_runnable)) {
809  }
810 }
811 
834 uint32_t
836  const pe_node_t *node, uint32_t flags,
837  uint32_t filter, uint32_t type,
839 {
840  uint32_t changed = pcmk__updated_none;
841  uint32_t then_flags = then->flags;
842  uint32_t first_flags = first->flags;
843 
845  handle_asymmetric_ordering(first, then);
846  }
847 
849  && !pcmk_is_set(then_flags, pe_action_optional)) {
850  // Then is required, and implies first should be, too
851 
852  if (pcmk_is_set(filter, pe_action_optional)
854  && pcmk_is_set(first_flags, pe_action_optional)) {
856  }
857 
861  }
862  }
863 
865  && (then->rsc != NULL) && (then->rsc->role == RSC_ROLE_PROMOTED)
866  && pcmk_is_set(filter, pe_action_optional)
867  && !pcmk_is_set(then->flags, pe_action_optional)) {
868 
870 
874  then);
875  }
876  }
877 
879  && pcmk_is_set(filter, pe_action_optional)) {
880 
881  if (!pcmk_all_flags_set(then->flags,
884  }
885 
886  if (!pcmk_is_set(then->flags, pe_action_optional)) {
888  }
889  }
890 
892  && pcmk_is_set(filter, pe_action_optional)
893  && !pcmk_is_set(first->flags, pe_action_runnable)) {
894 
897  }
898 
900  && pcmk_is_set(filter, pe_action_runnable)
903 
906  }
907 
909  && pcmk_is_set(filter, pe_action_optional)
913 
915  }
916 
918  handle_restart_ordering(first, then, filter);
919  }
920 
921  if (then_flags != then->flags) {
923  pe_rsc_trace(then->rsc,
924  "%s on %s: flags are now %#.6x (was %#.6x) "
925  "because of 'first' %s (%#.6x)",
926  then->uuid, pe__node_name(then->node),
927  then->flags, then_flags, first->uuid, first->flags);
928 
929  if ((then->rsc != NULL) && (then->rsc->parent != NULL)) {
930  // Required to handle "X_stop then X_start" for cloned groups
932  }
933  }
934 
935  if (first_flags != first->flags) {
937  pe_rsc_trace(first->rsc,
938  "%s on %s: flags are now %#.6x (was %#.6x) "
939  "because of 'then' %s (%#.6x)",
940  first->uuid, pe__node_name(first->node),
941  first->flags, first_flags, then->uuid, then->flags);
942  }
943 
944  return changed;
945 }
946 
955 void
956 pcmk__log_action(const char *pre_text, pe_action_t *action, bool details)
957 {
958  const char *node_uname = NULL;
959  const char *node_uuid = NULL;
960  const char *desc = NULL;
961 
962  CRM_CHECK(action != NULL, return);
963 
964  if (!pcmk_is_set(action->flags, pe_action_pseudo)) {
965  if (action->node != NULL) {
966  node_uname = action->node->details->uname;
967  node_uuid = action->node->details->id;
968  } else {
969  node_uname = "<none>";
970  }
971  }
972 
973  switch (text2task(action->task)) {
974  case stonith_node:
975  case shutdown_crm:
976  if (pcmk_is_set(action->flags, pe_action_pseudo)) {
977  desc = "Pseudo ";
978  } else if (pcmk_is_set(action->flags, pe_action_optional)) {
979  desc = "Optional ";
980  } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
981  desc = "!!Non-Startable!! ";
982  } else if (pcmk_is_set(action->flags, pe_action_processed)) {
983  desc = "";
984  } else {
985  desc = "(Provisional) ";
986  }
987  crm_trace("%s%s%sAction %d: %s%s%s%s%s%s",
988  ((pre_text == NULL)? "" : pre_text),
989  ((pre_text == NULL)? "" : ": "),
990  desc, action->id, action->uuid,
991  (node_uname? "\ton " : ""), (node_uname? node_uname : ""),
992  (node_uuid? "\t\t(" : ""), (node_uuid? node_uuid : ""),
993  (node_uuid? ")" : ""));
994  break;
995  default:
996  if (pcmk_is_set(action->flags, pe_action_optional)) {
997  desc = "Optional ";
998  } else if (pcmk_is_set(action->flags, pe_action_pseudo)) {
999  desc = "Pseudo ";
1000  } else if (!pcmk_is_set(action->flags, pe_action_runnable)) {
1001  desc = "!!Non-Startable!! ";
1002  } else if (pcmk_is_set(action->flags, pe_action_processed)) {
1003  desc = "";
1004  } else {
1005  desc = "(Provisional) ";
1006  }
1007  crm_trace("%s%s%sAction %d: %s %s%s%s%s%s%s",
1008  ((pre_text == NULL)? "" : pre_text),
1009  ((pre_text == NULL)? "" : ": "),
1010  desc, action->id, action->uuid,
1011  (action->rsc? action->rsc->id : "<none>"),
1012  (node_uname? "\ton " : ""), (node_uname? node_uname : ""),
1013  (node_uuid? "\t\t(" : ""), (node_uuid? node_uuid : ""),
1014  (node_uuid? ")" : ""));
1015  break;
1016  }
1017 
1018  if (details) {
1019  GList *iter = NULL;
1020 
1021  crm_trace("\t\t====== Preceding Actions");
1022  for (iter = action->actions_before; iter != NULL; iter = iter->next) {
1023  pe_action_wrapper_t *other = (pe_action_wrapper_t *) iter->data;
1024 
1025  pcmk__log_action("\t\t", other->action, false);
1026  }
1027  crm_trace("\t\t====== Subsequent Actions");
1028  for (iter = action->actions_after; iter != NULL; iter = iter->next) {
1029  pe_action_wrapper_t *other = (pe_action_wrapper_t *) iter->data;
1030 
1031  pcmk__log_action("\t\t", other->action, false);
1032  }
1033  crm_trace("\t\t====== End");
1034 
1035  } else {
1036  crm_trace("\t\t(before=%d, after=%d)",
1037  g_list_length(action->actions_before),
1038  g_list_length(action->actions_after));
1039  }
1040 }
1041 
1050 pe_action_t *
1052 {
1053  char *shutdown_id = NULL;
1054  pe_action_t *shutdown_op = NULL;
1055 
1056  CRM_ASSERT(node != NULL);
1057 
1058  shutdown_id = crm_strdup_printf("%s-%s", CRM_OP_SHUTDOWN,
1059  node->details->uname);
1060 
1061  shutdown_op = custom_action(NULL, shutdown_id, CRM_OP_SHUTDOWN, node, FALSE,
1062  TRUE, node->details->data_set);
1063 
1064  pcmk__order_stops_before_shutdown(node, shutdown_op);
1066  return shutdown_op;
1067 }
1068 
1080 static void
1081 add_op_digest_to_xml(lrmd_event_data_t *op, xmlNode *update)
1082 {
1083  char *digest = NULL;
1084  xmlNode *args_xml = NULL;
1085 
1086  if (op->params == NULL) {
1087  return;
1088  }
1089  args_xml = create_xml_node(NULL, XML_TAG_PARAMS);
1090  g_hash_table_foreach(op->params, hash2field, args_xml);
1091  pcmk__filter_op_for_digest(args_xml);
1092  digest = calculate_operation_digest(args_xml, NULL);
1093  crm_xml_add(update, XML_LRM_ATTR_OP_DIGEST, digest);
1094  free_xml(args_xml);
1095  free(digest);
1096 }
1097 
1098 #define FAKE_TE_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
1099 
1113 xmlNode *
1115  const char *caller_version, int target_rc,
1116  const char *node, const char *origin)
1117 {
1118  char *key = NULL;
1119  char *magic = NULL;
1120  char *op_id = NULL;
1121  char *op_id_additional = NULL;
1122  char *local_user_data = NULL;
1123  const char *exit_reason = NULL;
1124 
1125  xmlNode *xml_op = NULL;
1126  const char *task = NULL;
1127 
1128  CRM_CHECK(op != NULL, return NULL);
1129  crm_trace("Creating history XML for %s-interval %s action for %s on %s "
1130  "(DC version: %s, origin: %s)",
1132  ((node == NULL)? "no node" : node), caller_version, origin);
1133 
1134  task = op->op_type;
1135 
1136  /* Record a successful agent reload as a start, and a failed one as a
1137  * monitor, to make life easier for the scheduler when determining the
1138  * current state.
1139  *
1140  * @COMPAT We should check "reload" here only if the operation was for a
1141  * pre-OCF-1.1 resource agent, but we don't know that here, and we should
1142  * only ever get results for actions scheduled by us, so we can reasonably
1143  * assume any "reload" is actually a pre-1.1 agent reload.
1144  */
1146  NULL)) {
1147  if (op->op_status == PCMK_EXEC_DONE) {
1148  task = CRMD_ACTION_START;
1149  } else {
1150  task = CRMD_ACTION_STATUS;
1151  }
1152  }
1153 
1154  key = pcmk__op_key(op->rsc_id, task, op->interval_ms);
1155  if (pcmk__str_eq(task, CRMD_ACTION_NOTIFY, pcmk__str_none)) {
1156  const char *n_type = crm_meta_value(op->params, "notify_type");
1157  const char *n_task = crm_meta_value(op->params, "notify_operation");
1158 
1159  CRM_LOG_ASSERT(n_type != NULL);
1160  CRM_LOG_ASSERT(n_task != NULL);
1161  op_id = pcmk__notify_key(op->rsc_id, n_type, n_task);
1162 
1163  if (op->op_status != PCMK_EXEC_PENDING) {
1164  /* Ignore notify errors.
1165  *
1166  * @TODO It might be better to keep the correct result here, and
1167  * ignore it in process_graph_event().
1168  */
1170  }
1171 
1172  /* Migration history is preserved separately, which usually matters for
1173  * multiple nodes and is important for future cluster transitions.
1174  */
1176  CRMD_ACTION_MIGRATED, NULL)) {
1177  op_id = strdup(key);
1178 
1179  } else if (did_rsc_op_fail(op, target_rc)) {
1180  op_id = pcmk__op_key(op->rsc_id, "last_failure", 0);
1181  if (op->interval_ms == 0) {
1182  // Ensure 'last' gets updated, in case record-pending is true
1183  op_id_additional = pcmk__op_key(op->rsc_id, "last", 0);
1184  }
1185  exit_reason = op->exit_reason;
1186 
1187  } else if (op->interval_ms > 0) {
1188  op_id = strdup(key);
1189 
1190  } else {
1191  op_id = pcmk__op_key(op->rsc_id, "last", 0);
1192  }
1193 
1194  again:
1196  if (xml_op == NULL) {
1198  }
1199 
1200  if (op->user_data == NULL) {
1201  crm_debug("Generating fake transition key for: " PCMK__OP_FMT
1202  " %d from %s", op->rsc_id, op->op_type, op->interval_ms,
1203  op->call_id, origin);
1204  local_user_data = pcmk__transition_key(-1, op->call_id, target_rc,
1205  FAKE_TE_ID);
1206  op->user_data = local_user_data;
1207  }
1208 
1209  if (magic == NULL) {
1210  magic = crm_strdup_printf("%d:%d;%s", op->op_status, op->rc,
1211  (const char *) op->user_data);
1212  }
1213 
1214  crm_xml_add(xml_op, XML_ATTR_ID, op_id);
1215  crm_xml_add(xml_op, XML_LRM_ATTR_TASK_KEY, key);
1216  crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task);
1217  crm_xml_add(xml_op, XML_ATTR_ORIGIN, origin);
1218  crm_xml_add(xml_op, XML_ATTR_CRM_VERSION, caller_version);
1220  crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, magic);
1221  crm_xml_add(xml_op, XML_LRM_ATTR_EXIT_REASON, exit_reason == NULL ? "" : exit_reason);
1222  crm_xml_add(xml_op, XML_LRM_ATTR_TARGET, node); /* For context during triage */
1223 
1225  crm_xml_add_int(xml_op, XML_LRM_ATTR_RC, op->rc);
1228 
1229  if (compare_version("2.1", caller_version) <= 0) {
1230  if (op->t_run || op->t_rcchange || op->exec_time || op->queue_time) {
1231  crm_trace("Timing data (" PCMK__OP_FMT
1232  "): last=%u change=%u exec=%u queue=%u",
1233  op->rsc_id, op->op_type, op->interval_ms,
1234  op->t_run, op->t_rcchange, op->exec_time, op->queue_time);
1235 
1236  if ((op->interval_ms != 0) && (op->t_rcchange != 0)) {
1237  // Recurring ops may have changed rc after initial run
1239  (long long) op->t_rcchange);
1240  } else {
1242  (long long) op->t_run);
1243  }
1244 
1247  }
1248  }
1249 
1251  /*
1252  * Record migrate_source and migrate_target always for migrate ops.
1253  */
1254  const char *name = XML_LRM_ATTR_MIGRATE_SOURCE;
1255 
1256  crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1257 
1259  crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1260  }
1261 
1262  add_op_digest_to_xml(op, xml_op);
1263 
1264  if (op_id_additional) {
1265  free(op_id);
1266  op_id = op_id_additional;
1267  op_id_additional = NULL;
1268  goto again;
1269  }
1270 
1271  if (local_user_data) {
1272  free(local_user_data);
1273  op->user_data = NULL;
1274  }
1275  free(magic);
1276  free(op_id);
1277  free(key);
1278  return xml_op;
1279 }
1280 
1295 bool
1297 {
1298  // Only resource actions taking place on resource's lock node are locked
1299  if ((action == NULL) || (action->rsc == NULL)
1300  || (action->rsc->lock_node == NULL) || (action->node == NULL)
1301  || (action->node->details != action->rsc->lock_node->details)) {
1302  return false;
1303  }
1304 
1305  /* During shutdown, only stops are locked (otherwise, another action such as
1306  * a demote would cause the controller to clear the lock)
1307  */
1308  if (action->node->details->shutdown && (action->task != NULL)
1309  && (strcmp(action->task, RSC_STOP) != 0)) {
1310  return false;
1311  }
1312 
1313  return true;
1314 }
1315 
1316 /* lowest to highest */
1317 static gint
1318 sort_action_id(gconstpointer a, gconstpointer b)
1319 {
1320  const pe_action_wrapper_t *action_wrapper2 = (const pe_action_wrapper_t *)a;
1321  const pe_action_wrapper_t *action_wrapper1 = (const pe_action_wrapper_t *)b;
1322 
1323  if (a == NULL) {
1324  return 1;
1325  }
1326  if (b == NULL) {
1327  return -1;
1328  }
1329  if (action_wrapper1->action->id < action_wrapper2->action->id) {
1330  return 1;
1331  }
1332  if (action_wrapper1->action->id > action_wrapper2->action->id) {
1333  return -1;
1334  }
1335  return 0;
1336 }
1337 
1344 void
1346 {
1347  GList *item = NULL;
1348  GList *next = NULL;
1349  pe_action_wrapper_t *last_input = NULL;
1350 
1351  action->actions_before = g_list_sort(action->actions_before,
1352  sort_action_id);
1353  for (item = action->actions_before; item != NULL; item = next) {
1354  pe_action_wrapper_t *input = (pe_action_wrapper_t *) item->data;
1355 
1356  next = item->next;
1357  if ((last_input != NULL)
1358  && (input->action->id == last_input->action->id)) {
1359  crm_trace("Input %s (%d) duplicate skipped for action %s (%d)",
1360  input->action->uuid, input->action->id,
1361  action->uuid, action->id);
1362 
1363  /* For the purposes of scheduling, the ordering flags no longer
1364  * matter, but crm_simulate looks at certain ones when creating a
1365  * dot graph. Combining the flags is sufficient for that purpose.
1366  */
1367  last_input->type |= input->type;
1368  if (input->state == pe_link_dumped) {
1369  last_input->state = pe_link_dumped;
1370  }
1371 
1372  free(item->data);
1373  action->actions_before = g_list_delete_link(action->actions_before,
1374  item);
1375  } else {
1376  last_input = input;
1377  input->state = pe_link_not_dumped;
1378  }
1379  }
1380 }
1381 
1388 void
1390 {
1391  pcmk__output_t *out = data_set->priv;
1392 
1393  // Output node (non-resource) actions
1394  for (GList *iter = data_set->actions; iter != NULL; iter = iter->next) {
1395  char *node_name = NULL;
1396  char *task = NULL;
1397  pe_action_t *action = (pe_action_t *) iter->data;
1398 
1399  if (action->rsc != NULL) {
1400  continue; // Resource actions will be output later
1401 
1402  } else if (pcmk_is_set(action->flags, pe_action_optional)) {
1403  continue; // This action was not scheduled
1404  }
1405 
1406  if (pcmk__str_eq(action->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
1407  task = strdup("Shutdown");
1408 
1409  } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
1410  const char *op = g_hash_table_lookup(action->meta, "stonith_action");
1411 
1412  task = crm_strdup_printf("Fence (%s)", op);
1413 
1414  } else {
1415  continue; // Don't display other node action types
1416  }
1417 
1418  if (pe__is_guest_node(action->node)) {
1419  node_name = crm_strdup_printf("%s (resource: %s)",
1420  pe__node_name(action->node),
1421  action->node->details->remote_rsc->container->id);
1422  } else if (action->node != NULL) {
1423  node_name = crm_strdup_printf("%s", pe__node_name(action->node));
1424  }
1425 
1426  out->message(out, "node-action", task, node_name, action->reason);
1427 
1428  free(node_name);
1429  free(task);
1430  }
1431 
1432  // Output resource actions
1433  for (GList *iter = data_set->resources; iter != NULL; iter = iter->next) {
1434  pe_resource_t *rsc = (pe_resource_t *) iter->data;
1435 
1436  rsc->cmds->output_actions(rsc);
1437  }
1438 }
1439 
1450 static bool
1451 action_in_config(pe_resource_t *rsc, const char *task, guint interval_ms)
1452 {
1453  char *key = pcmk__op_key(rsc->id, task, interval_ms);
1454  bool config = (find_rsc_op_entry(rsc, key) != NULL);
1455 
1456  free(key);
1457  return config;
1458 }
1459 
1469 static const char *
1470 task_for_digest(const char *task, guint interval_ms)
1471 {
1472  /* Certain actions need to be compared against the parameters used to start
1473  * the resource.
1474  */
1475  if ((interval_ms == 0)
1477  task = RSC_START;
1478  }
1479  return task;
1480 }
1481 
1499 static bool
1500 only_sanitized_changed(xmlNode *xml_op, const op_digest_cache_t *digest_data,
1502 {
1503  const char *digest_secure = NULL;
1504 
1506  // The scheduler is not being run as a simulation
1507  return false;
1508  }
1509 
1510  digest_secure = crm_element_value(xml_op, XML_LRM_ATTR_SECURE_DIGEST);
1511 
1512  return (digest_data->rc != RSC_DIGEST_MATCH) && (digest_secure != NULL)
1513  && (digest_data->digest_secure_calc != NULL)
1514  && (strcmp(digest_data->digest_secure_calc, digest_secure) == 0);
1515 }
1516 
1526 static void
1527 force_restart(pe_resource_t *rsc, const char *task, guint interval_ms,
1528  pe_node_t *node)
1529 {
1530  char *key = pcmk__op_key(rsc->id, task, interval_ms);
1531  pe_action_t *required = custom_action(rsc, key, task, NULL, FALSE, TRUE,
1532  rsc->cluster);
1533 
1534  pe_action_set_reason(required, "resource definition change", true);
1535  trigger_unfencing(rsc, node, "Device parameters changed", NULL,
1536  rsc->cluster);
1537 }
1538 
1546 static void
1547 schedule_reload(pe_resource_t *rsc, pe_node_t *node)
1548 {
1549  pe_action_t *reload = NULL;
1550 
1551  // For collective resources, just call recursively for children
1552  if (rsc->variant > pe_native) {
1553  g_list_foreach(rsc->children, (GFunc) schedule_reload, node);
1554  return;
1555  }
1556 
1557  // Skip the reload in certain situations
1558  if ((node == NULL)
1559  || !pcmk_is_set(rsc->flags, pe_rsc_managed)
1560  || pcmk_is_set(rsc->flags, pe_rsc_failed)) {
1561  pe_rsc_trace(rsc, "Skip reload of %s:%s%s %s",
1562  rsc->id,
1563  pcmk_is_set(rsc->flags, pe_rsc_managed)? "" : " unmanaged",
1564  pcmk_is_set(rsc->flags, pe_rsc_failed)? " failed" : "",
1565  (node == NULL)? "inactive" : node->details->uname);
1566  return;
1567  }
1568 
1569  /* If a resource's configuration changed while a start was pending,
1570  * force a full restart instead of a reload.
1571  */
1572  if (pcmk_is_set(rsc->flags, pe_rsc_start_pending)) {
1573  pe_rsc_trace(rsc, "%s: preventing agent reload because start pending",
1574  rsc->id);
1575  custom_action(rsc, stop_key(rsc), CRMD_ACTION_STOP, node, FALSE, TRUE,
1576  rsc->cluster);
1577  return;
1578  }
1579 
1580  // Schedule the reload
1582  reload = custom_action(rsc, reload_key(rsc), CRMD_ACTION_RELOAD_AGENT, node,
1583  FALSE, TRUE, rsc->cluster);
1584  pe_action_set_reason(reload, "resource definition change", FALSE);
1585 
1586  // Set orderings so that a required stop or demote cancels the reload
1587  pcmk__new_ordering(NULL, NULL, reload, rsc, stop_key(rsc), NULL,
1589  rsc->cluster);
1590  pcmk__new_ordering(NULL, NULL, reload, rsc, demote_key(rsc), NULL,
1592  rsc->cluster);
1593 }
1594 
1609 bool
1611 {
1612  guint interval_ms = 0;
1613  const char *task = NULL;
1614  const op_digest_cache_t *digest_data = NULL;
1615 
1616  CRM_CHECK((rsc != NULL) && (node != NULL) && (xml_op != NULL),
1617  return false);
1618 
1619  task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
1620  CRM_CHECK(task != NULL, return false);
1621 
1622  crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
1623 
1624  // If this is a recurring action, check whether it has been orphaned
1625  if (interval_ms > 0) {
1626  if (action_in_config(rsc, task, interval_ms)) {
1627  pe_rsc_trace(rsc, "%s-interval %s for %s on %s is in configuration",
1628  pcmk__readable_interval(interval_ms), task, rsc->id,
1629  pe__node_name(node));
1630  } else if (pcmk_is_set(rsc->cluster->flags,
1634  task, interval_ms, node, "orphan");
1635  return true;
1636  } else {
1637  pe_rsc_debug(rsc, "%s-interval %s for %s on %s is orphaned",
1638  pcmk__readable_interval(interval_ms), task, rsc->id,
1639  pe__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  pe__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  pe__node_name(node),
1660  }
1661  return false;
1662  }
1663 
1664  switch (digest_data->rc) {
1665  case RSC_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 RSC_DIGEST_ALL:
1671  case RSC_DIGEST_UNKNOWN:
1672  // Changes that can potentially be handled by an agent reload
1673 
1674  if (interval_ms > 0) {
1675  /* Recurring actions aren't reloaded per se, they are just
1676  * re-scheduled so the next run uses the new parameters.
1677  * The old instance will be cancelled automatically.
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  XML_LRM_ATTR_RESTART_DIGEST) != NULL) {
1684  // Agent supports reload, so use it
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(rsc, node);
1690 
1691  } else {
1692  pe_rsc_trace(rsc,
1693  "Restarting %s because agent doesn't support reload",
1694  rsc->id);
1695  crm_log_xml_debug(digest_data->params_restart,
1696  "params:restart");
1697  force_restart(rsc, task, interval_ms, node);
1698  }
1699  return true;
1700 
1701  default:
1702  break;
1703  }
1704  return false;
1705 }
1706 
1716 static GList *
1717 rsc_history_as_list(pe_resource_t *rsc, xmlNode *rsc_entry,
1718  int *start_index, int *stop_index)
1719 {
1720  GList *ops = NULL;
1721 
1722  for (xmlNode *rsc_op = first_named_child(rsc_entry, XML_LRM_TAG_RSC_OP);
1723  rsc_op != NULL; rsc_op = crm_next_same_xml(rsc_op)) {
1724  ops = g_list_prepend(ops, rsc_op);
1725  }
1726  ops = g_list_sort(ops, sort_op_by_callid);
1727  calculate_active_ops(ops, start_index, stop_index);
1728  return ops;
1729 }
1730 
1745 static void
1746 process_rsc_history(xmlNode *rsc_entry, pe_resource_t *rsc, pe_node_t *node)
1747 {
1748  int offset = -1;
1749  int stop_index = 0;
1750  int start_index = 0;
1751  GList *sorted_op_list = NULL;
1752 
1753  if (pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
1754  if (pe_rsc_is_anon_clone(uber_parent(rsc))) {
1755  pe_rsc_trace(rsc,
1756  "Skipping configuration check "
1757  "for orphaned clone instance %s",
1758  rsc->id);
1759  } else {
1760  pe_rsc_trace(rsc,
1761  "Skipping configuration check and scheduling clean-up "
1762  "for orphaned resource %s", rsc->id);
1763  pcmk__schedule_cleanup(rsc, node, false);
1764  }
1765  return;
1766  }
1767 
1768  if (pe_find_node_id(rsc->running_on, node->details->id) == NULL) {
1769  if (pcmk__rsc_agent_changed(rsc, node, rsc_entry, false)) {
1770  pcmk__schedule_cleanup(rsc, node, false);
1771  }
1772  pe_rsc_trace(rsc,
1773  "Skipping configuration check for %s "
1774  "because no longer active on %s",
1775  rsc->id, pe__node_name(node));
1776  return;
1777  }
1778 
1779  pe_rsc_trace(rsc, "Checking for configuration changes for %s on %s",
1780  rsc->id, pe__node_name(node));
1781 
1782  if (pcmk__rsc_agent_changed(rsc, node, rsc_entry, true)) {
1783  pcmk__schedule_cleanup(rsc, node, false);
1784  }
1785 
1786  sorted_op_list = rsc_history_as_list(rsc, rsc_entry, &start_index,
1787  &stop_index);
1788  if (start_index < stop_index) {
1789  return; // Resource is stopped
1790  }
1791 
1792  for (GList *iter = sorted_op_list; iter != NULL; iter = iter->next) {
1793  xmlNode *rsc_op = (xmlNode *) iter->data;
1794  const char *task = NULL;
1795  guint interval_ms = 0;
1796 
1797  if (++offset < start_index) {
1798  // Skip actions that happened before a start
1799  continue;
1800  }
1801 
1802  task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
1803  crm_element_value_ms(rsc_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
1804 
1805  if ((interval_ms > 0)
1807  || node->details->maintenance)) {
1808  // Maintenance mode cancels recurring operations
1811  task, interval_ms, node, "maintenance mode");
1812 
1813  } else if ((interval_ms > 0)
1815  RSC_PROMOTE, RSC_MIGRATED, NULL)) {
1816  /* If a resource operation failed, and the operation's definition
1817  * has changed, clear any fail count so they can be retried fresh.
1818  */
1819 
1820  if (pe__bundle_needs_remote_name(rsc, rsc->cluster)) {
1821  /* We haven't allocated resources to nodes yet, so if the
1822  * REMOTE_CONTAINER_HACK is used, we may calculate the digest
1823  * based on the literal "#uname" value rather than the properly
1824  * substituted value. That would mistakenly make the action
1825  * definition appear to have been changed. Defer the check until
1826  * later in this case.
1827  */
1828  pe__add_param_check(rsc_op, rsc, node, pe_check_active,
1829  rsc->cluster);
1830 
1831  } else if (pcmk__check_action_config(rsc, node, rsc_op)
1832  && (pe_get_failcount(node, rsc, NULL, pe_fc_effective,
1833  NULL, rsc->cluster) != 0)) {
1834  pe__clear_failcount(rsc, node, "action definition changed",
1835  rsc->cluster);
1836  }
1837  }
1838  }
1839  g_list_free(sorted_op_list);
1840 }
1841 
1856 static void
1857 process_node_history(pe_node_t *node, xmlNode *lrm_rscs, pe_working_set_t *data_set)
1858 {
1859  crm_trace("Processing node history for %s", pe__node_name(node));
1860  for (xmlNode *rsc_entry = first_named_child(lrm_rscs, XML_LRM_TAG_RESOURCE);
1861  rsc_entry != NULL; rsc_entry = crm_next_same_xml(rsc_entry)) {
1862 
1863  if (xml_has_children(rsc_entry)) {
1864  GList *result = pcmk__rscs_matching_id(ID(rsc_entry), data_set);
1865 
1866  for (GList *iter = result; iter != NULL; iter = iter->next) {
1867  pe_resource_t *rsc = (pe_resource_t *) iter->data;
1868 
1869  if (rsc->variant == pe_native) {
1870  process_rsc_history(rsc_entry, rsc, node);
1871  }
1872  }
1873  g_list_free(result);
1874  }
1875  }
1876 }
1877 
1878 // XPath to find a node's resource history
1879 #define XPATH_NODE_HISTORY "/" XML_TAG_CIB "/" XML_CIB_TAG_STATUS \
1880  "/" XML_CIB_TAG_STATE "[@" XML_ATTR_UNAME "='%s']" \
1881  "/" XML_CIB_TAG_LRM "/" XML_LRM_TAG_RESOURCES
1882 
1895 void
1897 {
1898  crm_trace("Check resource and action configuration for changes");
1899 
1900  /* Rather than iterate through the status section, iterate through the nodes
1901  * and search for the appropriate status subsection for each. This skips
1902  * orphaned nodes and lets us eliminate some cases before searching the XML.
1903  */
1904  for (GList *iter = data_set->nodes; iter != NULL; iter = iter->next) {
1905  pe_node_t *node = (pe_node_t *) iter->data;
1906 
1907  /* Don't bother checking actions for a node that can't run actions ...
1908  * unless it's in maintenance mode, in which case we still need to
1909  * cancel any existing recurring monitors.
1910  */
1911  if (node->details->maintenance
1912  || pcmk__node_available(node, false, false)) {
1913 
1914  char *xpath = NULL;
1915  xmlNode *history = NULL;
1916 
1918  history = get_xpath_object(xpath, data_set->input, LOG_NEVER);
1919  free(xpath);
1920 
1921  process_node_history(node, history, data_set);
1922  }
1923  }
1924 }
enum pe_link_state state
Definition: pe_types.h:529
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define XML_RSC_OP_LAST_CHANGE
Definition: msg_xml.h:320
void pcmk__output_actions(pe_working_set_t *data_set)
xmlNode * find_rsc_op_entry(const pe_resource_t *rsc, const char *key)
Definition: pe_actions.c:145
const char * task2text(enum action_tasks task)
Definition: common.c:401
#define RSC_STOP
Definition: crm.h:202
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: operations.c:185
#define CRMD_ACTION_MIGRATED
Definition: crm.h:172
#define pe_flag_stop_action_orphans
Definition: pe_types.h:105
#define pe_rsc_debug(rsc, fmt, args...)
Definition: internal.h:46
G_GNUC_INTERNAL void pcmk__schedule_cleanup(pe_resource_t *rsc, const pe_node_t *node, bool optional)
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:86
const char * user_data
Definition: lrmd.h:225
gboolean is_parent(pe_resource_t *child, pe_resource_t *rsc)
Definition: complex.c:895
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition: nvpair.c:770
int runnable_before
Definition: pe_types.h:438
xmlNode * pcmk__xe_match(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml.c:520
const char * rsc_id
Definition: lrmd.h:221
#define CRM_OP_FENCE
Definition: crm.h:144
const char * crm_xml_add_ms(xmlNode *node, const char *name, guint ms)
Create an XML attribute with specified name and unsigned value.
Definition: nvpair.c:441
#define XML_ATTR_TRANSITION_MAGIC
Definition: msg_xml.h:412
void pe__add_param_check(xmlNode *rsc_op, pe_resource_t *rsc, pe_node_t *node, enum pe_check_parameters, pe_working_set_t *data_set)
Definition: remote.c:220
const char * name
Definition: cib.c:24
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:928
int(* message)(pcmk__output_t *out, const char *message_id,...)
#define clear_action_flag_because(action, flag, reason)
enum rsc_role_e role
Definition: pe_types.h:377
GList * children
Definition: pe_types.h:384
resource_alloc_functions_t * cmds
Definition: pe_types.h:341
unsigned int queue_time
Definition: lrmd.h:251
Internal tracking for transition graph creation.
Definition: pe_types.h:468
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2930
void pcmk__update_action_for_orderings(pe_action_t *then, pe_working_set_t *data_set)
pe_resource_t * rsc
Definition: pe_types.h:406
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition: nvpair.c:419
#define reload_key(rsc)
Definition: internal.h:419
pe_action_t * find_first_action(const GList *input, const char *uuid, const char *task, const pe_node_t *on_node)
Definition: pe_actions.c:1296
#define CRMD_ACTION_NOTIFY
Definition: crm.h:185
#define XML_RSC_OP_T_EXEC
Definition: msg_xml.h:322
#define pe_rsc_notify
Definition: pe_types.h:261
const char * crm_meta_value(GHashTable *hash, const char *field)
Definition: utils.c:490
resource_object_functions_t * fns
Definition: pe_types.h:340
#define XML_LRM_TAG_RESOURCE
Definition: msg_xml.h:267
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:323
#define XML_LRM_ATTR_OP_DIGEST
Definition: msg_xml.h:313
bool pe__bundle_needs_remote_name(pe_resource_t *rsc, pe_working_set_t *data_set)
Definition: bundle.c:690
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
Definition: pe_actions.c:1627
unsigned int t_rcchange
Definition: lrmd.h:247
xmlNode * pcmk__create_history_xml(xmlNode *parent, lrmd_event_data_t *op, const char *caller_version, int target_rc, const char *node, const char *origin)
void pcmk__filter_op_for_digest(xmlNode *param_set)
Definition: operations.c:390
enum action_tasks text2task(const char *task)
Definition: common.c:353
GList * actions
Definition: pe_types.h:171
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:211
int(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
xmlNode * params_restart
Definition: internal.h:520
enum crm_ais_msg_types type
Definition: cpg.c:48
#define demote_key(rsc)
Definition: internal.h:440
enum ocf_exitcode rc
Definition: lrmd.h:239
#define RSC_START
Definition: crm.h:199
pe_action_t * action
Definition: pe_types.h:530
#define XML_RSC_OP_T_QUEUE
Definition: msg_xml.h:323
#define LOG_NEVER
Definition: logging.h:47
G_GNUC_INTERNAL GList * pcmk__rscs_matching_id(const char *id, pe_working_set_t *data_set)
#define pe__set_raw_action_flags(action_flags, action_name, flags_to_set)
Definition: internal.h:104
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:214
pe_working_set_t * data_set
Cluster that this node is part of.
Definition: pe_types.h:245
bool pcmk__action_locks_rsc_to_node(const pe_action_t *action)
const char * action
Definition: pcmk_fence.c:30
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:74
GList * resources
Definition: pe_types.h:165
void trigger_unfencing(pe_resource_t *rsc, pe_node_t *node, const char *reason, pe_action_t *dependency, pe_working_set_t *data_set)
Definition: utils.c:604
unsigned int exec_time
Definition: lrmd.h:249
GList * nodes
Definition: pe_types.h:164
#define XML_ATTR_ORIGIN
Definition: msg_xml.h:129
#define CRMD_ACTION_START
Definition: crm.h:174
#define XML_LRM_ATTR_TASK_KEY
Definition: msg_xml.h:301
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:300
void pcmk__deduplicate_action_inputs(pe_action_t *action)
uint32_t pcmk__update_ordered_actions(pe_action_t *first, pe_action_t *then, const pe_node_t *node, uint32_t flags, uint32_t filter, uint32_t type, pe_working_set_t *data_set)
pe_node_t *(* location)(const pe_resource_t *, GList **, int)
Definition: pe_types.h:55
#define CRMD_ACTION_STOP
Definition: crm.h:177
void * params
Definition: lrmd.h:258
char * calculate_operation_digest(xmlNode *local_cib, const char *version)
Calculate and return digest of XML operation.
Definition: digest.c:153
#define crm_warn(fmt, args...)
Definition: logging.h:360
#define CRMD_ACTION_RELOAD_AGENT
Definition: crm.h:170
void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
Definition: pe_actions.c:1447
const char * exit_reason
Definition: lrmd.h:266
pe_action_flags
Definition: pe_types.h:298
#define action_type_str(flags)
char * pcmk__notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: operations.c:229
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition: nvpair.c:610
#define action_node_str(a)
#define pe_rsc_failed
Definition: pe_types.h:276
#define crm_debug(fmt, args...)
Definition: logging.h:364
G_GNUC_INTERNAL bool pcmk__node_available(const pe_node_t *node, bool consider_score, bool consider_guest)
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition: complex.c:912
#define pe_flag_sanitized
Definition: pe_types.h:121
#define pe__clear_order_flags(order_flags, flags_to_clear)
Definition: internal.h:145
#define XML_ATTR_ID
Definition: msg_xml.h:134
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:517
#define XML_BOOLEAN_TRUE
Definition: msg_xml.h:146
bool pe__is_guest_node(const pe_node_t *node)
Definition: remote.c:33
#define stop_key(rsc)
Definition: internal.h:414
#define pe_rsc_start_pending
Definition: pe_types.h:278
char * task
Definition: pe_types.h:410
GList * actions_after
Definition: pe_types.h:444
#define pe__clear_action_flags(action, flags_to_clear)
Definition: internal.h:95
void pcmk__log_action(const char *pre_text, pe_action_t *action, bool details)
#define crm_trace(fmt, args...)
Definition: logging.h:365
enum rsc_digest_cmp_val rc
Definition: internal.h:517
char * digest_secure_calc
Definition: internal.h:522
void calculate_active_ops(GList *sorted_op_list, int *start_index, int *stop_index)
Definition: unpack.c:2290
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
GHashTable * meta
Definition: pe_types.h:420
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
struct pe_node_shared_s * details
Definition: pe_types.h:252
#define crm_log_xml_debug(xml, text)
Definition: logging.h:372
pe_node_t * node
Definition: pe_types.h:407
bool pcmk__is_daemon
Definition: logging.c:47
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition: utils.c:474
unsigned long long flags
Definition: pe_types.h:355
const char * uname
Definition: pe_types.h:216
pe_working_set_t * data_set
#define XML_ATTR_TE_NOWAIT
Definition: msg_xml.h:415
void(* output_actions)(pe_resource_t *rsc)
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:749
Action completed, result is known.
Definition: results.h:312
GList * actions
Definition: pe_types.h:366
G_GNUC_INTERNAL void pcmk__new_ordering(pe_resource_t *first_rsc, char *first_task, pe_action_t *first_action, pe_resource_t *then_rsc, char *then_task, pe_action_t *then_action, uint32_t flags, pe_working_set_t *data_set)
#define pcmk__clear_updated_flags(au_flags, action, flags_to_clear)
#define XML_LRM_ATTR_MIGRATE_TARGET
Definition: msg_xml.h:326
#define XML_LRM_ATTR_EXIT_REASON
Definition: msg_xml.h:318
char * uuid
Definition: pe_types.h:411
#define XML_LRM_ATTR_RESTART_DIGEST
Definition: msg_xml.h:316
void free_xml(xmlNode *child)
Definition: xml.c:885
enum pe_obj_types variant
Definition: pe_types.h:338
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:952
gboolean xml_has_children(const xmlNode *root)
Definition: xml.c:2136
xmlNode * input
Definition: pe_types.h:144
xmlNode * params_all
Definition: internal.h:518
#define CRM_OP_SHUTDOWN
Definition: crm.h:143
G_GNUC_INTERNAL void pcmk__reschedule_recurring(pe_resource_t *rsc, const char *task, guint interval_ms, pe_node_t *node)
G_GNUC_INTERNAL void pcmk__order_stops_before_shutdown(pe_node_t *node, pe_action_t *shutdown_op)
const char * id
Definition: pe_types.h:215
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition: operations.c:45
const char * op_type
Definition: lrmd.h:223
#define CRMD_ACTION_RELOAD
Definition: crm.h:169
const char * crm_xml_add_ll(xmlNode *node, const char *name, long long value)
Create an XML attribute with specified name and long long int value.
Definition: nvpair.c:469
void pcmk__handle_rsc_config_changes(pe_working_set_t *data_set)
unsigned int t_run
Definition: lrmd.h:245
pe_node_t * pe_find_node_id(GList *node_list, const char *id)
Definition: status.c:427
#define XML_ATTR_TRANSITION_KEY
Definition: msg_xml.h:413
#define XML_LRM_ATTR_SECURE_DIGEST
Definition: msg_xml.h:317
#define action_runnable_str(flags)
enum rsc_role_e(* state)(const pe_resource_t *, gboolean)
Definition: pe_types.h:54
#define action_optional_str(flags)
G_GNUC_INTERNAL bool pcmk__rsc_agent_changed(pe_resource_t *rsc, pe_node_t *node, const xmlNode *rsc_entry, bool active_on_node)
pcmk__action_result_t result
Definition: pcmk_fence.c:35
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:504
gboolean did_rsc_op_fail(lrmd_event_data_t *event, int target_rc)
Definition: operations.c:437
#define XPATH_NODE_HISTORY
#define pcmk__set_updated_flags(au_flags, action, flags_to_set)
#define crm_err(fmt, args...)
Definition: logging.h:359
#define CRM_ASSERT(expr)
Definition: results.h:42
#define RSC_STATUS
Definition: crm.h:213
Success.
Definition: results.h:164
pe_action_t * pe__clear_failcount(pe_resource_t *rsc, pe_node_t *node, const char *reason, pe_working_set_t *data_set)
Schedule a controller operation to clear a fail count.
Definition: failcounts.c:360
op_digest_cache_t * rsc_action_digest_cmp(pe_resource_t *rsc, xmlNode *xml_op, pe_node_t *node, pe_working_set_t *data_set)
Definition: pe_digest.c:380
void lrmd__set_result(lrmd_event_data_t *event, enum ocf_exitcode rc, int op_status, const char *exit_reason)
Definition: lrmd_client.c:2472
#define pe_rsc_reload
Definition: pe_types.h:272
#define RSC_PROMOTE
Definition: crm.h:205
xmlNode * input
This structure contains everything that makes up a single output formatter.
int compare_version(const char *version1, const char *version2)
Definition: utils.c:189
#define XML_LRM_ATTR_INTERVAL_MS
Definition: msg_xml.h:298
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:312
#define CRMD_ACTION_MIGRATE
Definition: crm.h:171
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:80
#define XML_LRM_ATTR_OPSTATUS
Definition: msg_xml.h:310
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:118
char * pcmk__transition_key(int transition_id, int action_id, int target_rc, const char *node)
Definition: operations.c:296
G_GNUC_INTERNAL void pcmk__schedule_cancel(pe_resource_t *rsc, const char *call_id, const char *task, guint interval_ms, const pe_node_t *node, const char *reason)
rsc_role_e
Possible roles that a resource can be in.
Definition: common.h:92
GList * running_on
Definition: pe_types.h:373
#define pe_rsc_block
Definition: pe_types.h:258
enum pe_action_flags flags
Definition: pe_types.h:415
gboolean maintenance
Definition: pe_types.h:229
#define XML_LRM_ATTR_RC
Definition: msg_xml.h:311
#define pe_rsc_maintenance
Definition: pe_types.h:290
pe_working_set_t * cluster
Definition: pe_types.h:335
Action is in progress.
Definition: results.h:311
const char * pcmk__readable_interval(guint interval_ms)
Definition: iso8601.c:1765
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:302
#define XML_LRM_TAG_RSC_OP
Definition: msg_xml.h:268
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:47
#define pe__set_order_flags(order_flags, flags_to_set)
Definition: internal.h:138
#define ID(x)
Definition: msg_xml.h:468
unsigned long long flags
Definition: pe_types.h:153
#define FAKE_TE_ID
const char * parent
Definition: cib.c:25
uint32_t(* update_ordered_actions)(pe_action_t *first, pe_action_t *then, const pe_node_t *node, uint32_t flags, uint32_t filter, uint32_t type, pe_working_set_t *data_set)
#define PCMK__OP_FMT
Definition: internal.h:168
#define XML_LRM_ATTR_MIGRATE_SOURCE
Definition: msg_xml.h:325
G_GNUC_INTERNAL void pcmk__block_colocation_dependents(pe_action_t *action, pe_working_set_t *data_set)
pe_action_t * custom_action(pe_resource_t *rsc, char *key, const char *task, const pe_node_t *on_node, gboolean optional, gboolean foo, pe_working_set_t *data_set)
Create or update an action object.
Definition: pe_actions.c:940
enum pe_ordering type
Definition: pe_types.h:528
pe_action_t * pcmk__new_shutdown_action(pe_node_t *node)
#define XML_TAG_PARAMS
Definition: msg_xml.h:212
#define pe_rsc_managed
Definition: pe_types.h:257
#define pe_rsc_orphan
Definition: pe_types.h:256
bool pcmk__check_action_config(pe_resource_t *rsc, pe_node_t *node, xmlNode *xml_op)
uint64_t flags
Definition: remote.c:215
GList * actions_before
Definition: pe_types.h:443
int pe_get_failcount(pe_node_t *node, pe_resource_t *rsc, time_t *last_failure, uint32_t flags, xmlNode *xml_op, pe_working_set_t *data_set)
Definition: failcounts.c:251
int required_runnable_before
Definition: pe_types.h:441
action_tasks
Definition: common.h:61
pe_resource_t * parent
Definition: pe_types.h:336
guint interval_ms
Definition: lrmd.h:232
char * id
Definition: pe_types.h:329
#define RSC_MIGRATED
Definition: crm.h:197
#define CRMD_ACTION_STATUS
Definition: crm.h:188
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2956