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