1 /*
2 * Copyright 2004-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_ACTIONS_INTERNAL__H
11 #define PCMK__CRM_COMMON_ACTIONS_INTERNAL__H
12
13 #include <stdbool.h> // bool
14 #include <stdint.h> // uint32_t, UINT32_C()
15 #include <glib.h> // guint, GList, GHashTable
16 #include <libxml/tree.h> // xmlNode
17
18 #include <crm/common/actions.h> // PCMK_ACTION_MONITOR
19 #include <crm/common/roles.h> // enum rsc_role_e
20 #include <crm/common/scheduler_types.h> // pcmk_resource_t, pcmk_node_t
21 #include <crm/common/strings_internal.h> // pcmk__str_eq()
22
23 #include <crm/common/strings_internal.h> // pcmk__str_any_of()
24
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28
29 //! printf-style format to create operation key from resource, action, interval
30 #define PCMK__OP_FMT "%s_%s_%u"
31
32 /*!
33 * \internal
34 * \brief Set action flags for an action
35 *
36 * \param[in,out] action Action to set flags for
37 * \param[in] flags_to_set Group of enum pcmk__action_flags to set
38 */
39 #define pcmk__set_action_flags(action, flags_to_set) do { \
40 (action)->flags = pcmk__set_flags_as(__func__, __LINE__, \
41 LOG_TRACE, \
42 "Action", (action)->uuid, \
43 (action)->flags, \
44 (flags_to_set), \
45 #flags_to_set); \
46 } while (0)
47
48 /*!
49 * \internal
50 * \brief Clear action flags for an action
51 *
52 * \param[in,out] action Action to clear flags for
53 * \param[in] flags_to_clear Group of enum pcmk__action_flags to clear
54 */
55 #define pcmk__clear_action_flags(action, flags_to_clear) do { \
56 (action)->flags = pcmk__clear_flags_as(__func__, __LINE__, \
57 LOG_TRACE, \
58 "Action", (action)->uuid, \
59 (action)->flags, \
60 (flags_to_clear), \
61 #flags_to_clear); \
62 } while (0)
63
64 /*!
65 * \internal
66 * \brief Set action flags for a flag group
67 *
68 * \param[in,out] action_flags Flag group to set flags for
69 * \param[in] action_name Name of action being modified (for logging)
70 * \param[in] to_set Group of enum pcmk__action_flags to set
71 */
72 #define pcmk__set_raw_action_flags(action_flags, action_name, to_set) do { \
73 action_flags = pcmk__set_flags_as(__func__, __LINE__, \
74 LOG_TRACE, "Action", action_name, \
75 (action_flags), \
76 (to_set), #to_set); \
77 } while (0)
78
79 /*!
80 * \internal
81 * \brief Clear action flags for a flag group
82 *
83 * \param[in,out] action_flags Flag group to clear flags for
84 * \param[in] action_name Name of action being modified (for logging)
85 * \param[in] to_clear Group of enum pcmk__action_flags to clear
86 */
87 #define pcmk__clear_raw_action_flags(action_flags, action_name, to_clear) \
88 do { \
89 action_flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, \
90 "Action", action_name, \
91 (action_flags), \
92 (to_clear), #to_clear); \
93 } while (0)
94
95 // Possible actions (including some pseudo-actions)
96 enum pcmk__action_type {
97 pcmk__action_unspecified = 0, // Unspecified or unknown action
98 pcmk__action_monitor, // Monitor
99
100 // Each "completed" action must be the regular action plus 1
101
102 pcmk__action_stop, // Stop
103 pcmk__action_stopped, // Stop completed
104
105 pcmk__action_start, // Start
106 pcmk__action_started, // Start completed
107
108 pcmk__action_notify, // Notify
109 pcmk__action_notified, // Notify completed
110
111 pcmk__action_promote, // Promote
112 pcmk__action_promoted, // Promoted
113
114 pcmk__action_demote, // Demote
115 pcmk__action_demoted, // Demoted
116
117 pcmk__action_shutdown, // Shut down node
118 pcmk__action_fence, // Fence node
119 };
120
121 // Action scheduling flags
122 enum pcmk__action_flags {
123 // No action flags set (compare with equality rather than bit set)
124 pcmk__no_action_flags = 0,
125
126 // Whether action does not require invoking an agent
127 pcmk__action_pseudo = (UINT32_C(1) << 0),
128
129 // Whether action is runnable
130 pcmk__action_runnable = (UINT32_C(1) << 1),
131
132 // Whether action should not be executed
133 pcmk__action_optional = (UINT32_C(1) << 2),
134
135 // Whether action should be added to transition graph even if optional
136 pcmk__action_always_in_graph = (UINT32_C(1) << 3),
137
138 // Whether operation-specific instance attributes have been unpacked yet
139 pcmk__action_attrs_evaluated = (UINT32_C(1) << 4),
140
141 // Whether action is allowed to be part of a live migration
142 pcmk__action_migratable = (UINT32_C(1) << 7),
143
144 // Whether action has been added to transition graph
145 pcmk__action_added_to_graph = (UINT32_C(1) << 8),
146
147 // Whether action is a stop to abort a dangling migration
148 pcmk__action_migration_abort = (UINT32_C(1) << 11),
149
150 // Whether action is recurring monitor that must be rescheduled if active
151 pcmk__action_reschedule = (UINT32_C(1) << 13),
152
153 // Whether action has already been processed by a recursive procedure
154 pcmk__action_detect_loop = (UINT32_C(1) << 14),
155
156 // Whether action's inputs have been de-duplicated yet
157 pcmk__action_inputs_deduplicated = (UINT32_C(1) << 15),
158
159 // Whether action can be executed on DC rather than own node
160 pcmk__action_on_dc = (UINT32_C(1) << 16),
161 };
162
163 /* Possible responses to a resource action failure
164 *
165 * The order is significant; the values are in order of increasing severity so
166 * that they can be compared with less than and greater than.
167 */
168 enum pcmk__on_fail {
169 pcmk__on_fail_ignore, // Act as if failure didn't happen
170 pcmk__on_fail_demote, // Demote if promotable, else stop
171 pcmk__on_fail_restart, // Restart resource
172
173 /* Fence the remote node created by the resource if fencing is enabled,
174 * otherwise attempt to restart the resource (used internally for some
175 * remote connection failures).
176 */
177 pcmk__on_fail_reset_remote,
178
179 pcmk__on_fail_restart_container, // Restart resource's container
180 pcmk__on_fail_ban, // Ban resource from current node
181 pcmk__on_fail_block, // Treat resource as unmanaged
182 pcmk__on_fail_stop, // Stop resource and leave stopped
183 pcmk__on_fail_standby_node, // Put resource's node in standby
184 pcmk__on_fail_fence_node, // Fence resource's node
185 };
186
187 // What resource needs before it can be recovered from a failed node
188 enum pcmk__requires {
189 pcmk__requires_nothing = 0, // Resource can be recovered immediately
190 pcmk__requires_quorum = 1, // Resource can be recovered if quorate
191 pcmk__requires_fencing = 2, // Resource can be recovered after fencing
192 };
193
194 // Implementation of pcmk_action_t
195 struct pcmk__action {
196 int id; // Counter to identify action
197
198 /*
199 * When the controller aborts a transition graph, it sets an abort priority.
200 * If this priority is higher, the action will still be executed anyway.
201 * Pseudo-actions are always allowed, so this is irrelevant for them.
202 */
203 int priority;
204
205 pcmk_resource_t *rsc; // Resource to apply action to, if any
206 pcmk_node_t *node; // Copy of node to execute action on, if any
207 xmlNode *op_entry; // Action XML configuration, if any
208 char *task; // Action name
209 char *uuid; // Action key
210 char *cancel_task; // If task is "cancel", the action being cancelled
211 char *reason; // Readable description of why action is needed
212 uint32_t flags; // Group of enum pcmk__action_flags
213 enum pcmk__requires needs; // Prerequisite for recovery
214 enum pcmk__on_fail on_fail; // Response to failure
215 enum rsc_role_e fail_role; // Resource role if action fails
216 GHashTable *meta; // Meta-attributes relevant to action
217 GHashTable *extra; // Action-specific instance attributes
218 pcmk_scheduler_t *scheduler; // Scheduler data this action is part of
219
220 /* Current count of runnable instance actions for "first" action in an
221 * ordering dependency with pcmk__ar_min_runnable set.
222 */
223 int runnable_before;
224
225 /*
226 * Number of instance actions for "first" action in an ordering dependency
227 * with pcmk__ar_min_runnable set that must be runnable before this action
228 * can be runnable.
229 */
230 int required_runnable_before;
231
232 // Actions in a relation with this one (as pcmk__related_action_t *)
233 GList *actions_before;
234 GList *actions_after;
235 };
236
237 void pcmk__free_action(gpointer user_data);
238 char *pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms);
239 char *pcmk__notify_key(const char *rsc_id, const char *notify_type,
240 const char *op_type);
241 char *pcmk__transition_key(int transition_id, int action_id, int target_rc,
242 const char *node);
243 void pcmk__filter_op_for_digest(xmlNode *param_set);
244 bool pcmk__is_fencing_action(const char *action);
245 enum pcmk__action_type pcmk__parse_action(const char *action_name);
246 const char *pcmk__action_text(enum pcmk__action_type action);
247 const char *pcmk__on_fail_text(enum pcmk__on_fail on_fail);
248
249
250 /*!
251 * \internal
252 * \brief Get a human-friendly action name
253 *
254 * \param[in] action_name Actual action name
255 * \param[in] interval_ms Action interval (in milliseconds)
256 *
257 * \return Action name suitable for display
258 */
259 static inline const char *
260 pcmk__readable_action(const char *action_name, guint interval_ms) {
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
261 if ((interval_ms == 0)
262 && pcmk__str_eq(action_name, PCMK_ACTION_MONITOR, pcmk__str_none)) {
263 return "probe";
264 }
265 return action_name;
266 }
267
268 /*!
269 * \internal
270 * \brief Check whether an action raises a resource's role
271 *
272 * \param[in] action Action to check
273 *
274 * \return \c true if \p action is "start", "promote", or "migrate_from"
275 */
276 static inline bool
277 pcmk__is_up_action(const char *action)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
278 {
279 return pcmk__str_any_of(action, PCMK_ACTION_START, PCMK_ACTION_PROMOTE,
280 PCMK_ACTION_MIGRATE_FROM, NULL);
281 }
282
283 /*!
284 * \internal
285 * \brief Check whether an action lowers a resource's role
286 *
287 * \param[in] action Action to check
288 *
289 * \return \c true if \p action is "stop", "demote", or "migrate_to"
290 */
291 static inline bool
292 pcmk__is_down_action(const char *action)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
293 {
294 return pcmk__str_any_of(action, PCMK_ACTION_STOP, PCMK_ACTION_DEMOTE,
295 PCMK_ACTION_MIGRATE_TO, NULL);
296 }
297
298 #ifdef __cplusplus
299 }
300 #endif
301
302 #endif // PCMK__CRM_COMMON_ACTIONS_INTERNAL__H