1 /*
2 * Copyright 2023-2024 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 Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10 #ifndef PCMK__CRM_COMMON_ACTION_RELATION_INTERNAL__H
11 #define PCMK__CRM_COMMON_ACTION_RELATION_INTERNAL__H
12
13 #include <stdbool.h> // bool
14 #include <stdint.h> // uint32_t
15 #include <crm/common/scheduler_types.h> // pcmk_resource_t, pcmk_action_t
16
17 #ifdef __cplusplus
18 extern "C" {
19 #endif
20
21 // Flags to indicate the relationship between two actions
22 enum pcmk__action_relation_flags {
23 //! No relation (compare with equality rather than bit set)
24 pcmk__ar_none = 0U,
25
26 //! Actions are ordered (optionally, if no other flags are set)
27 pcmk__ar_ordered = (1U << 0),
28
29 //! Relation applies only if 'first' cannot be part of a live migration
30 pcmk__ar_if_first_unmigratable = (1U << 1),
31
32 /*!
33 * If 'then' is required, 'first' becomes required (and becomes unmigratable
34 * if 'then' is); also, if 'first' is a stop of a blocked resource, 'then'
35 * becomes unrunnable
36 */
37 pcmk__ar_then_implies_first = (1U << 4),
38
39 /*!
40 * If 'first' is required, 'then' becomes required; if 'first' is a stop of
41 * a blocked resource, 'then' becomes unrunnable
42 */
43 pcmk__ar_first_implies_then = (1U << 5),
44
45 /*!
46 * If 'then' is required and for a promoted instance, 'first' becomes
47 * required (and becomes unmigratable if 'then' is)
48 */
49 pcmk__ar_promoted_then_implies_first = (1U << 6),
50
51 /*!
52 * 'first' is runnable only if 'then' is both runnable and migratable,
53 * and 'first' becomes required if 'then' is
54 */
55 pcmk__ar_unmigratable_then_blocks = (1U << 7),
56
57 //! 'then' is runnable (and migratable) only if 'first' is runnable
58 pcmk__ar_unrunnable_first_blocks = (1U << 8),
59
60 //! If 'first' is unrunnable, 'then' becomes a real, unmigratable action
61 pcmk__ar_first_else_then = (1U << 9),
62
63 //! If 'first' is required, 'then' action for instance on same node is
64 pcmk__ar_first_implies_same_node_then = (1U << 10),
65
66 /*!
67 * Disable relation if 'first' is unrunnable and for an active resource,
68 * otherwise order actions and make 'then' unrunnable if 'first' is.
69 *
70 * This is used to order a bundle replica's start of its container before a
71 * probe of its remote connection resource, in case the connection uses the
72 * REMOTE_CONTAINER_HACK to replace the connection address with where the
73 * container is running.
74 */
75 pcmk__ar_nested_remote_probe = (1U << 11),
76
77 /*!
78 * If 'first' is for a blocked resource, make 'then' unrunnable.
79 *
80 * If 'then' is required, make 'first' required, make 'first' unmigratable
81 * if 'then' is unmigratable, and make 'then' unrunnable if 'first' is
82 * unrunnable.
83 *
84 * If 'then' is unrunnable and for the same resource as 'first', make
85 * 'first' required if it is runnable, and make 'first' unmigratable if
86 * 'then' is unmigratable.
87 *
88 * This is used for "stop then start primitive" (restarts) and
89 * "stop group member then stop previous member".
90 */
91 pcmk__ar_intermediate_stop = (1U << 12),
92
93 /*!
94 * The actions must be serialized if in the same transition but can be in
95 * either order. (In practice, we always arrange them as 'first' then
96 * 'then', so they end up being essentially the same as optional orderings.)
97 *
98 * @TODO Handle more intelligently -- for example, we could schedule the
99 * action with the fewest inputs first, so we're more likely to execute at
100 * least one if there is a failure during the transition. Or, we could
101 * prefer certain action types over others, or base it on resource priority.
102 */
103 pcmk__ar_serialize = (1U << 14),
104
105 //! Relation applies only if actions are on same node
106 pcmk__ar_if_on_same_node = (1U << 15),
107
108 //! If 'then' is required, 'first' must be added to the transition graph
109 pcmk__ar_then_implies_first_graphed = (1U << 16),
110
111 //! If 'first' is required and runnable, 'then' must be in graph
112 pcmk__ar_first_implies_then_graphed = (1U << 17),
113
114 //! User-configured asymmetric ordering
115 pcmk__ar_asymmetric = (1U << 20),
116
117 //! Actions are ordered if on same node (or migration target for migrate_to)
118 pcmk__ar_if_on_same_node_or_target = (1U << 21),
119
120 //! 'then' action is runnable if certain number of 'first' instances are
121 pcmk__ar_min_runnable = (1U << 22),
122
123 //! Ordering applies only if 'first' is required and on same node as 'then'
124 pcmk__ar_if_required_on_same_node = (1U << 23),
125
126 //! Ordering applies even if 'first' runs on guest node created by 'then'
127 pcmk__ar_guest_allowed = (1U << 24),
128
129 //! If 'then' action becomes required, 'first' becomes optional
130 pcmk__ar_then_cancels_first = (1U << 25),
131 };
132
133 /* Action relation object
134 *
135 * The most common type of relation is an ordering, in which case action1 etc.
136 * refers to the "first" action, and action2 etc. refers to the "then" action.
137 */
138 typedef struct {
139 int id; // Counter to identify relation
140 uint32_t flags; // Group of enum pcmk__action_relation_flags
141 pcmk_resource_t *rsc1; // Resource for first action, if any
142 pcmk_action_t *action1; // First action in relation
143 char *task1; // Action name or key for first action
144 pcmk_resource_t *rsc2; // Resource for second action, if any
145 pcmk_action_t *action2; // Second action in relation
146 char *task2; // Action name or key for second action
147 } pcmk__action_relation_t;
148
149 // Action sequenced relative to another action
150 typedef struct pcmk__related_action {
151 pcmk_action_t *action; // Action to be sequenced
152 uint32_t flags; // Group of enum pcmk__action_relation_flags
153 bool graphed; // Whether action has been added to graph yet
154 } pcmk__related_action_t;
155
156 /*!
157 * \internal
158 * \brief Set action relation flags
159 *
160 * \param[in,out] ar_flags Flag group to modify
161 * \param[in] flags_to_set enum pcmk__action_relation_flags to set
162 */
163 #define pcmk__set_relation_flags(ar_flags, flags_to_set) do { \
164 ar_flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, \
165 "Action relation", "constraint", \
166 ar_flags, (flags_to_set), \
167 #flags_to_set); \
168 } while (0)
169
170 /*!
171 * \internal
172 * \brief Clear action relation flags
173 *
174 * \param[in,out] ar_flags Flag group to modify
175 * \param[in] flags_to_clear enum pcmk__action_relation_flags to clear
176 */
177 #define pcmk__clear_relation_flags(ar_flags, flags_to_clear) do { \
178 ar_flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, \
179 "Action relation", "constraint", \
180 ar_flags, (flags_to_clear), \
181 #flags_to_clear); \
182 } while (0)
183
184 #ifdef __cplusplus
185 }
186 #endif
187
188 #endif // PCMK__CRM_COMMON_ACTION_RELATION_INTERNAL__H