1 /*
2 * Copyright 2004-2023 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 <stdbool.h>
13
14 #include <crm/msg_xml.h>
15 #include <pacemaker-internal.h>
16
17 #include "libpacemaker_private.h"
18
19 /*!
20 * \internal
21 * \brief Add migration source and target meta-attributes to an action
22 *
23 * \param[in,out] action Action to add meta-attributes to
24 * \param[in] source Node to add as migration source
25 * \param[in] target Node to add as migration target
26 */
27 static void
28 add_migration_meta(pcmk_action_t *action, const pcmk_node_t *source,
29 const pcmk_node_t *target)
30 {
31 add_hash_param(action->meta, XML_LRM_ATTR_MIGRATE_SOURCE,
32 source->details->uname);
33
34 add_hash_param(action->meta, XML_LRM_ATTR_MIGRATE_TARGET,
35 target->details->uname);
36 }
37
38 /*!
39 * \internal
40 * \brief Create internal migration actions for a migrateable resource
41 *
42 * \param[in,out] rsc Resource to create migration actions for
43 * \param[in] current Node that resource is originally active on
44 */
45 void
46 pcmk__create_migration_actions(pcmk_resource_t *rsc, const pcmk_node_t *current)
47 {
48 pcmk_action_t *migrate_to = NULL;
49 pcmk_action_t *migrate_from = NULL;
50 pcmk_action_t *start = NULL;
51 pcmk_action_t *stop = NULL;
52
53 pe_rsc_trace(rsc, "Creating actions to %smigrate %s from %s to %s",
54 ((rsc->partial_migration_target == NULL)? "" : "partially "),
55 rsc->id, pe__node_name(current),
56 pe__node_name(rsc->allocated_to));
57 start = start_action(rsc, rsc->allocated_to, TRUE);
58 stop = stop_action(rsc, current, TRUE);
59
60 if (rsc->partial_migration_target == NULL) {
61 migrate_to = custom_action(rsc, pcmk__op_key(rsc->id,
62 PCMK_ACTION_MIGRATE_TO, 0),
63 PCMK_ACTION_MIGRATE_TO, current, TRUE,
64 rsc->cluster);
65 }
66 migrate_from = custom_action(rsc, pcmk__op_key(rsc->id,
67 PCMK_ACTION_MIGRATE_FROM, 0),
68 PCMK_ACTION_MIGRATE_FROM, rsc->allocated_to,
69 TRUE, rsc->cluster);
70
71 pe__set_action_flags(start, pcmk_action_migratable);
72 pe__set_action_flags(stop, pcmk_action_migratable);
73
74 // This is easier than trying to delete it from the graph
75 pe__set_action_flags(start, pcmk_action_pseudo);
76
77 if (rsc->partial_migration_target == NULL) {
78 pe__set_action_flags(migrate_from, pcmk_action_migratable);
79 pe__set_action_flags(migrate_to, pcmk_action_migratable);
80 migrate_to->needs = start->needs;
81
82 // Probe -> migrate_to -> migrate_from
83 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MONITOR, 0),
84 NULL,
85 rsc,
86 pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_TO, 0),
87 NULL, pcmk__ar_ordered, rsc->cluster);
88 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_TO, 0),
89 NULL,
90 rsc,
91 pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_FROM, 0),
92 NULL,
93 pcmk__ar_ordered|pcmk__ar_unmigratable_then_blocks,
94 rsc->cluster);
95 } else {
96 pe__set_action_flags(migrate_from, pcmk_action_migratable);
97 migrate_from->needs = start->needs;
98
99 // Probe -> migrate_from (migrate_to already completed)
100 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MONITOR, 0),
101 NULL,
102 rsc,
103 pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_FROM, 0),
104 NULL, pcmk__ar_ordered, rsc->cluster);
105 }
106
107 // migrate_from before stop or start
108 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_FROM, 0),
109 NULL,
110 rsc, pcmk__op_key(rsc->id, PCMK_ACTION_STOP, 0),
111 NULL,
112 pcmk__ar_ordered|pcmk__ar_unmigratable_then_blocks,
113 rsc->cluster);
114 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_FROM, 0),
115 NULL,
116 rsc, pcmk__op_key(rsc->id, PCMK_ACTION_START, 0),
117 NULL,
118 pcmk__ar_ordered
119 |pcmk__ar_unmigratable_then_blocks
120 |pcmk__ar_first_else_then,
121 rsc->cluster);
122
123 if (migrate_to != NULL) {
124 add_migration_meta(migrate_to, current, rsc->allocated_to);
125
126 if (!rsc->is_remote_node) {
127 /* migrate_to takes place on the source node, but can affect the
128 * target node depending on how the agent is written. Because of
129 * this, pending migrate_to actions must be recorded in the CIB,
130 * in case the source node loses membership while the migrate_to
131 * action is still in flight.
132 *
133 * However we know Pacemaker Remote connection resources don't
134 * require this, so we skip this for them. (Although it wouldn't
135 * hurt, and now that record-pending defaults to true, skipping it
136 * matters even less.)
137 */
138 add_hash_param(migrate_to->meta, XML_OP_ATTR_PENDING, "true");
139 }
140 }
141
142 add_migration_meta(migrate_from, current, rsc->allocated_to);
143 }
144
145 /*!
146 * \internal
147 * \brief Abort a dangling migration by scheduling a stop (and possibly cleanup)
148 *
149 * \param[in] data Source node of dangling migration
150 * \param[in,out] user_data Resource involved in dangling migration
151 */
152 void
153 pcmk__abort_dangling_migration(void *data, void *user_data)
154 {
155 const pcmk_node_t *dangling_source = (const pcmk_node_t *) data;
156 pcmk_resource_t *rsc = (pcmk_resource_t *) user_data;
157
158 pcmk_action_t *stop = NULL;
159 bool cleanup = pcmk_is_set(rsc->cluster->flags,
160 pcmk_sched_remove_after_stop);
161
162 pe_rsc_trace(rsc,
163 "Scheduling stop%s for %s on %s due to dangling migration",
164 (cleanup? " and cleanup" : ""), rsc->id,
165 pe__node_name(dangling_source));
166 stop = stop_action(rsc, dangling_source, FALSE);
167 pe__set_action_flags(stop, pcmk_action_migration_abort);
168 if (cleanup) {
169 pcmk__schedule_cleanup(rsc, dangling_source, false);
170 }
171 }
172
173 /*!
174 * \internal
175 * \brief Check whether a resource can migrate
176 *
177 * \param[in] rsc Resource to check
178 * \param[in] node Resource's current node
179 *
180 * \return true if \p rsc can migrate, otherwise false
181 */
182 bool
183 pcmk__rsc_can_migrate(const pcmk_resource_t *rsc, const pcmk_node_t *current)
184 {
185 CRM_CHECK(rsc != NULL, return false);
186
187 if (!pcmk_is_set(rsc->flags, pcmk_rsc_migratable)) {
188 pe_rsc_trace(rsc, "%s cannot migrate because "
189 "the configuration does not allow it",
190 rsc->id);
191 return false;
192 }
193
194 if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
195 pe_rsc_trace(rsc, "%s cannot migrate because it is not managed",
196 rsc->id);
197 return false;
198 }
199
200 if (pcmk_is_set(rsc->flags, pcmk_rsc_failed)) {
201 pe_rsc_trace(rsc, "%s cannot migrate because it is failed",
202 rsc->id);
203 return false;
204 }
205
206 if (pcmk_is_set(rsc->flags, pcmk_rsc_start_pending)) {
207 pe_rsc_trace(rsc, "%s cannot migrate because it has a start pending",
208 rsc->id);
209 return false;
210 }
211
212 if ((current == NULL) || current->details->unclean) {
213 pe_rsc_trace(rsc, "%s cannot migrate because "
214 "its current node (%s) is unclean",
215 rsc->id, pe__node_name(current));
216 return false;
217 }
218
219 if ((rsc->allocated_to == NULL) || rsc->allocated_to->details->unclean) {
220 pe_rsc_trace(rsc, "%s cannot migrate because "
221 "its next node (%s) is unclean",
222 rsc->id, pe__node_name(rsc->allocated_to));
223 return false;
224 }
225
226 return true;
227 }
228
229 /*!
230 * \internal
231 * \brief Get an action name from an action or operation key
232 *
233 * \param[in] action If not NULL, get action name from here
234 * \param[in] key If not NULL, get action name from here
235 *
236 * \return Newly allocated copy of action name (or NULL if none available)
237 */
238 static char *
239 task_from_action_or_key(const pcmk_action_t *action, const char *key)
240 {
241 char *res = NULL;
242
243 if (action != NULL) {
244 res = strdup(action->task);
245 CRM_ASSERT(res != NULL);
246 } else if (key != NULL) {
247 parse_op_key(key, NULL, &res, NULL);
248 }
249 return res;
250 }
251
252 /*!
253 * \internal
254 * \brief Order migration actions equivalent to a given ordering
255 *
256 * Orderings involving start, stop, demote, and promote actions must be honored
257 * during a migration as well, so duplicate any such ordering for the
258 * corresponding migration actions.
259 *
260 * \param[in,out] order Ordering constraint to check
261 */
262 void
263 pcmk__order_migration_equivalents(pe__ordering_t *order)
264 {
265 char *first_task = NULL;
266 char *then_task = NULL;
267 bool then_migratable;
268 bool first_migratable;
269
270 // Only orderings between unrelated resources are relevant
271 if ((order->lh_rsc == NULL) || (order->rh_rsc == NULL)
272 || (order->lh_rsc == order->rh_rsc)
273 || is_parent(order->lh_rsc, order->rh_rsc)
274 || is_parent(order->rh_rsc, order->lh_rsc)) {
275 return;
276 }
277
278 // Only orderings involving at least one migratable resource are relevant
279 first_migratable = pcmk_is_set(order->lh_rsc->flags, pcmk_rsc_migratable);
280 then_migratable = pcmk_is_set(order->rh_rsc->flags, pcmk_rsc_migratable);
281 if (!first_migratable && !then_migratable) {
282 return;
283 }
284
285 // Check which actions are involved
286 first_task = task_from_action_or_key(order->lh_action,
287 order->lh_action_task);
288 then_task = task_from_action_or_key(order->rh_action,
289 order->rh_action_task);
290
291 if (pcmk__str_eq(first_task, PCMK_ACTION_START, pcmk__str_none)
292 && pcmk__str_eq(then_task, PCMK_ACTION_START, pcmk__str_none)) {
293
294 uint32_t flags = pcmk__ar_ordered;
295
296 if (first_migratable && then_migratable) {
297 /* A start then B start
298 * -> A migrate_from then B migrate_to */
299 pcmk__new_ordering(order->lh_rsc,
300 pcmk__op_key(order->lh_rsc->id,
301 PCMK_ACTION_MIGRATE_FROM, 0),
302 NULL, order->rh_rsc,
303 pcmk__op_key(order->rh_rsc->id,
304 PCMK_ACTION_MIGRATE_TO, 0),
305 NULL, flags, order->lh_rsc->cluster);
306 }
307
308 if (then_migratable) {
309 if (first_migratable) {
310 pe__set_order_flags(flags, pcmk__ar_if_first_unmigratable);
311 }
312
313 /* A start then B start
314 * -> A start then B migrate_to (if start is not part of a
315 * migration)
316 */
317 pcmk__new_ordering(order->lh_rsc,
318 pcmk__op_key(order->lh_rsc->id,
319 PCMK_ACTION_START, 0),
320 NULL, order->rh_rsc,
321 pcmk__op_key(order->rh_rsc->id,
322 PCMK_ACTION_MIGRATE_TO, 0),
323 NULL, flags, order->lh_rsc->cluster);
324 }
325
326 } else if (then_migratable
327 && pcmk__str_eq(first_task, PCMK_ACTION_STOP, pcmk__str_none)
328 && pcmk__str_eq(then_task, PCMK_ACTION_STOP, pcmk__str_none)) {
329
330 uint32_t flags = pcmk__ar_ordered;
331
332 if (first_migratable) {
333 pe__set_order_flags(flags, pcmk__ar_if_first_unmigratable);
334 }
335
336 /* For an ordering "stop A then stop B", if A is moving via restart, and
337 * B is migrating, enforce that B's migrate_to occurs after A's stop.
338 */
339 pcmk__new_ordering(order->lh_rsc,
340 pcmk__op_key(order->lh_rsc->id, PCMK_ACTION_STOP, 0),
341 NULL,
342 order->rh_rsc,
343 pcmk__op_key(order->rh_rsc->id,
344 PCMK_ACTION_MIGRATE_TO, 0),
345 NULL, flags, order->lh_rsc->cluster);
346
347 // Also order B's migrate_from after A's stop during partial migrations
348 if (order->rh_rsc->partial_migration_target) {
349 pcmk__new_ordering(order->lh_rsc,
350 pcmk__op_key(order->lh_rsc->id, PCMK_ACTION_STOP,
351 0),
352 NULL, order->rh_rsc,
353 pcmk__op_key(order->rh_rsc->id,
354 PCMK_ACTION_MIGRATE_FROM, 0),
355 NULL, flags, order->lh_rsc->cluster);
356 }
357
358 } else if (pcmk__str_eq(first_task, PCMK_ACTION_PROMOTE, pcmk__str_none)
359 && pcmk__str_eq(then_task, PCMK_ACTION_START, pcmk__str_none)) {
360
361 uint32_t flags = pcmk__ar_ordered;
362
363 if (then_migratable) {
364 /* A promote then B start
365 * -> A promote then B migrate_to */
366 pcmk__new_ordering(order->lh_rsc,
367 pcmk__op_key(order->lh_rsc->id,
368 PCMK_ACTION_PROMOTE, 0),
369 NULL, order->rh_rsc,
370 pcmk__op_key(order->rh_rsc->id,
371 PCMK_ACTION_MIGRATE_TO, 0),
372 NULL, flags, order->lh_rsc->cluster);
373 }
374
375 } else if (pcmk__str_eq(first_task, PCMK_ACTION_DEMOTE, pcmk__str_none)
376 && pcmk__str_eq(then_task, PCMK_ACTION_STOP, pcmk__str_none)) {
377
378 uint32_t flags = pcmk__ar_ordered;
379
380 if (then_migratable) {
381 /* A demote then B stop
382 * -> A demote then B migrate_to */
383 pcmk__new_ordering(order->lh_rsc,
384 pcmk__op_key(order->lh_rsc->id,
385 PCMK_ACTION_DEMOTE, 0),
386 NULL, order->rh_rsc,
387 pcmk__op_key(order->rh_rsc->id,
388 PCMK_ACTION_MIGRATE_TO, 0),
389 NULL, flags, order->lh_rsc->cluster);
390
391 // Order B migrate_from after A demote during partial migrations
392 if (order->rh_rsc->partial_migration_target) {
393 pcmk__new_ordering(order->lh_rsc,
394 pcmk__op_key(order->lh_rsc->id,
395 PCMK_ACTION_DEMOTE, 0),
396 NULL, order->rh_rsc,
397 pcmk__op_key(order->rh_rsc->id,
398 PCMK_ACTION_MIGRATE_FROM, 0),
399 NULL, flags, order->lh_rsc->cluster);
400 }
401 }
402 }
403
404 free(first_task);
405 free(then_task);
406 }
407