pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
pcmk_sched_migration.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 <stdbool.h>
13
14#include <crm/msg_xml.h>
15#include <pacemaker-internal.h>
16
18
27static void
28add_migration_meta(pe_action_t *action, const pe_node_t *source,
29 const pe_node_t *target)
30{
32 source->details->uname);
33
35 target->details->uname);
36}
37
45void
47{
48 pe_action_t *migrate_to = NULL;
49 pe_action_t *migrate_from = NULL;
50 pe_action_t *start = NULL;
51 pe_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, RSC_MIGRATE, 0),
62 RSC_MIGRATE, current, TRUE, TRUE,
63 rsc->cluster);
64 }
65 migrate_from = custom_action(rsc, pcmk__op_key(rsc->id, RSC_MIGRATED, 0),
66 RSC_MIGRATED, rsc->allocated_to, TRUE, TRUE,
67 rsc->cluster);
68
69 if ((migrate_from != NULL)
70 && ((migrate_to != NULL) || (rsc->partial_migration_target != NULL))) {
71
74
75 // This is easier than trying to delete it from the graph
77
78 if (rsc->partial_migration_target == NULL) {
80
81 if (migrate_to != NULL) {
83 migrate_to->needs = start->needs;
84 }
85
86 // Probe -> migrate_to -> migrate_from
87 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, RSC_STATUS, 0), NULL,
88 rsc, pcmk__op_key(rsc->id, RSC_MIGRATE, 0),
89 NULL, pe_order_optional, rsc->cluster);
90 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, RSC_MIGRATE, 0), NULL,
91 rsc, pcmk__op_key(rsc->id, RSC_MIGRATED, 0),
92 NULL,
94 rsc->cluster);
95 } else {
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, RSC_STATUS, 0), NULL,
101 rsc, pcmk__op_key(rsc->id, RSC_MIGRATED, 0),
102 NULL, pe_order_optional, rsc->cluster);
103 }
104
105 // migrate_from before stop or start
106 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, RSC_MIGRATED, 0), NULL,
107 rsc, pcmk__op_key(rsc->id, RSC_STOP, 0), NULL,
109 rsc->cluster);
110 pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, RSC_MIGRATED, 0), NULL,
111 rsc, pcmk__op_key(rsc->id, RSC_START, 0), NULL,
113 rsc->cluster);
114 }
115
116 if (migrate_to != NULL) {
117 add_migration_meta(migrate_to, current, rsc->allocated_to);
118
119 if (!rsc->is_remote_node) {
120 /* migrate_to takes place on the source node, but can affect the
121 * target node depending on how the agent is written. Because of
122 * this, pending migrate_to actions must be recorded in the CIB,
123 * in case the source node loses membership while the migrate_to
124 * action is still in flight.
125 *
126 * However we know Pacemaker Remote connection resources don't
127 * require this, so we skip this for them. (Although it wouldn't
128 * hurt, and now that record-pending defaults to true, skipping it
129 * matters even less.)
130 */
131 add_hash_param(migrate_to->meta, XML_OP_ATTR_PENDING, "true");
132 }
133 }
134
135 if (migrate_from != NULL) {
136 add_migration_meta(migrate_from, current, rsc->allocated_to);
137 }
138}
139
147void
149{
150 const pe_node_t *dangling_source = (const pe_node_t *) data;
151 pe_resource_t *rsc = (pe_resource_t *) user_data;
152
153 pe_action_t *stop = NULL;
154 bool cleanup = pcmk_is_set(rsc->cluster->flags, pe_flag_remove_after_stop);
155
156 pe_rsc_trace(rsc,
157 "Scheduling stop%s for %s on %s due to dangling migration",
158 (cleanup? " and cleanup" : ""), rsc->id,
159 pe__node_name(dangling_source));
160 stop = stop_action(rsc, dangling_source, FALSE);
162 if (cleanup) {
163 pcmk__schedule_cleanup(rsc, dangling_source, false);
164 }
165}
166
176bool
178{
179 CRM_CHECK(rsc != NULL, return false);
180
182 pe_rsc_trace(rsc, "%s cannot migrate because "
183 "the configuration does not allow it",
184 rsc->id);
185 return false;
186 }
187
188 if (!pcmk_is_set(rsc->flags, pe_rsc_managed)) {
189 pe_rsc_trace(rsc, "%s cannot migrate because it is not managed",
190 rsc->id);
191 return false;
192 }
193
194 if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
195 pe_rsc_trace(rsc, "%s cannot migrate because it is failed",
196 rsc->id);
197 return false;
198 }
199
201 pe_rsc_trace(rsc, "%s cannot migrate because it has a start pending",
202 rsc->id);
203 return false;
204 }
205
206 if ((current == NULL) || current->details->unclean) {
207 pe_rsc_trace(rsc, "%s cannot migrate because "
208 "its current node (%s) is unclean",
209 rsc->id, pe__node_name(current));
210 return false;
211 }
212
213 if ((rsc->allocated_to == NULL) || rsc->allocated_to->details->unclean) {
214 pe_rsc_trace(rsc, "%s cannot migrate because "
215 "its next node (%s) is unclean",
216 rsc->id, pe__node_name(rsc->allocated_to));
217 return false;
218 }
219
220 return true;
221}
222
232static char *
233task_from_action_or_key(const pe_action_t *action, const char *key)
234{
235 char *res = NULL;
236
237 if (action != NULL) {
238 res = strdup(action->task);
239 CRM_ASSERT(res != NULL);
240 } else if (key != NULL) {
241 parse_op_key(key, NULL, &res, NULL);
242 }
243 return res;
244}
245
256void
258{
259 char *first_task = NULL;
260 char *then_task = NULL;
261 bool then_migratable;
262 bool first_migratable;
263
264 // Only orderings between unrelated resources are relevant
265 if ((order->lh_rsc == NULL) || (order->rh_rsc == NULL)
266 || (order->lh_rsc == order->rh_rsc)
267 || is_parent(order->lh_rsc, order->rh_rsc)
268 || is_parent(order->rh_rsc, order->lh_rsc)) {
269 return;
270 }
271
272 // Only orderings involving at least one migratable resource are relevant
273 first_migratable = pcmk_is_set(order->lh_rsc->flags, pe_rsc_allow_migrate);
274 then_migratable = pcmk_is_set(order->rh_rsc->flags, pe_rsc_allow_migrate);
275 if (!first_migratable && !then_migratable) {
276 return;
277 }
278
279 // Check which actions are involved
280 first_task = task_from_action_or_key(order->lh_action,
281 order->lh_action_task);
282 then_task = task_from_action_or_key(order->rh_action,
283 order->rh_action_task);
284
285 if (pcmk__str_eq(first_task, RSC_START, pcmk__str_none)
286 && pcmk__str_eq(then_task, RSC_START, pcmk__str_none)) {
287
288 uint32_t flags = pe_order_optional;
289
290 if (first_migratable && then_migratable) {
291 /* A start then B start
292 * -> A migrate_from then B migrate_to */
294 pcmk__op_key(order->lh_rsc->id, RSC_MIGRATED, 0),
295 NULL, order->rh_rsc,
296 pcmk__op_key(order->rh_rsc->id, RSC_MIGRATE, 0),
297 NULL, flags, order->lh_rsc->cluster);
298 }
299
300 if (then_migratable) {
301 if (first_migratable) {
303 }
304
305 /* A start then B start
306 * -> A start then B migrate_to (if start is not part of a
307 * migration)
308 */
310 pcmk__op_key(order->lh_rsc->id, RSC_START, 0),
311 NULL, order->rh_rsc,
312 pcmk__op_key(order->rh_rsc->id, RSC_MIGRATE, 0),
313 NULL, flags, order->lh_rsc->cluster);
314 }
315
316 } else if (then_migratable
317 && pcmk__str_eq(first_task, RSC_STOP, pcmk__str_none)
318 && pcmk__str_eq(then_task, RSC_STOP, pcmk__str_none)) {
319
320 uint32_t flags = pe_order_optional;
321
322 if (first_migratable) {
324 }
325
326 /* For an ordering "stop A then stop B", if A is moving via restart, and
327 * B is migrating, enforce that B's migrate_to occurs after A's stop.
328 */
330 pcmk__op_key(order->lh_rsc->id, RSC_STOP, 0), NULL,
331 order->rh_rsc,
332 pcmk__op_key(order->rh_rsc->id, RSC_MIGRATE, 0),
333 NULL, flags, order->lh_rsc->cluster);
334
335 // Also order B's migrate_from after A's stop during partial migrations
336 if (order->rh_rsc->partial_migration_target) {
338 pcmk__op_key(order->lh_rsc->id, RSC_STOP, 0),
339 NULL, order->rh_rsc,
340 pcmk__op_key(order->rh_rsc->id, RSC_MIGRATED, 0),
341 NULL, flags, order->lh_rsc->cluster);
342 }
343
344 } else if (pcmk__str_eq(first_task, RSC_PROMOTE, pcmk__str_none)
345 && pcmk__str_eq(then_task, RSC_START, pcmk__str_none)) {
346
347 uint32_t flags = pe_order_optional;
348
349 if (then_migratable) {
350 /* A promote then B start
351 * -> A promote then B migrate_to */
353 pcmk__op_key(order->lh_rsc->id, RSC_PROMOTE, 0),
354 NULL, order->rh_rsc,
355 pcmk__op_key(order->rh_rsc->id, RSC_MIGRATE, 0),
356 NULL, flags, order->lh_rsc->cluster);
357 }
358
359 } else if (pcmk__str_eq(first_task, RSC_DEMOTE, pcmk__str_none)
360 && pcmk__str_eq(then_task, RSC_STOP, pcmk__str_none)) {
361
362 uint32_t flags = pe_order_optional;
363
364 if (then_migratable) {
365 /* A demote then B stop
366 * -> A demote then B migrate_to */
368 pcmk__op_key(order->lh_rsc->id, RSC_DEMOTE, 0),
369 NULL, order->rh_rsc,
370 pcmk__op_key(order->rh_rsc->id, RSC_MIGRATE, 0),
371 NULL, flags, order->lh_rsc->cluster);
372
373 // Also order B migrate_from after A demote during partial migrations
374 if (order->rh_rsc->partial_migration_target) {
376 pcmk__op_key(order->lh_rsc->id, RSC_DEMOTE, 0),
377 NULL, order->rh_rsc,
378 pcmk__op_key(order->rh_rsc->id, RSC_MIGRATED, 0),
379 NULL, flags, order->lh_rsc->cluster);
380 }
381 }
382 }
383
384 free(first_task);
385 free(then_task);
386}
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
uint64_t flags
Definition: remote.c:3
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: operations.c:185
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
gboolean is_parent(pe_resource_t *child, pe_resource_t *rsc)
Definition: complex.c:895
char data[0]
Definition: cpg.c:10
#define RSC_PROMOTE
Definition: crm.h:205
#define RSC_DEMOTE
Definition: crm.h:207
#define RSC_START
Definition: crm.h:199
#define RSC_STOP
Definition: crm.h:202
#define RSC_STATUS
Definition: crm.h:213
#define RSC_MIGRATE
Definition: crm.h:196
#define RSC_MIGRATED
Definition: crm.h:197
G_GNUC_INTERNAL void pcmk__schedule_cleanup(pe_resource_t *rsc, const pe_node_t *node, bool optional)
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 CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define XML_LRM_ATTR_MIGRATE_SOURCE
Definition: msg_xml.h:325
#define XML_LRM_ATTR_MIGRATE_TARGET
Definition: msg_xml.h:326
#define XML_OP_ATTR_PENDING
Definition: msg_xml.h:261
const char * action
Definition: pcmk_fence.c:30
const char * target
Definition: pcmk_fence.c:29
void pcmk__abort_dangling_migration(void *data, void *user_data)
void pcmk__order_migration_equivalents(pe__ordering_t *order)
void pcmk__create_migration_actions(pe_resource_t *rsc, const pe_node_t *current)
bool pcmk__rsc_can_migrate(const pe_resource_t *rsc, const pe_node_t *current)
#define pe_rsc_managed
Definition: pe_types.h:257
@ pe_order_pseudo_left
Definition: pe_types.h:493
@ pe_order_implies_first_migratable
Definition: pe_types.h:489
@ pe_order_optional
Definition: pe_types.h:481
@ pe_order_apply_first_non_migratable
Definition: pe_types.h:482
#define pe_rsc_allow_migrate
Definition: pe_types.h:287
@ pe_action_dangle
Definition: pe_types.h:313
@ pe_action_pseudo
Definition: pe_types.h:299
@ pe_action_migrate_runnable
Definition: pe_types.h:306
#define pe_flag_remove_after_stop
Definition: pe_types.h:111
#define pe_rsc_failed
Definition: pe_types.h:276
#define pe_rsc_start_pending
Definition: pe_types.h:278
#define start_action(rsc, node, optional)
Definition: internal.h:421
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
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:47
#define stop_action(rsc, node, optional)
Definition: internal.h:415
#define pe__set_order_flags(order_flags, flags_to_set)
Definition: internal.h:138
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:86
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:504
#define CRM_ASSERT(expr)
Definition: results.h:42
@ pcmk__str_none
pe_action_t * rh_action
Definition: internal.h:205
pe_resource_t * rh_rsc
Definition: internal.h:204
pe_resource_t * lh_rsc
Definition: internal.h:199
pe_action_t * lh_action
Definition: internal.h:200
enum rsc_start_requirement needs
Definition: pe_types.h:416
GHashTable * meta
Definition: pe_types.h:420
struct pe_node_shared_s * details
Definition: pe_types.h:252
const char * uname
Definition: pe_types.h:216
gboolean unclean
Definition: pe_types.h:224
pe_working_set_t * cluster
Definition: pe_types.h:335
gboolean is_remote_node
Definition: pe_types.h:358
char * id
Definition: pe_types.h:329
pe_node_t * allocated_to
Definition: pe_types.h:370
unsigned long long flags
Definition: pe_types.h:355
pe_node_t * partial_migration_target
Definition: pe_types.h:371
unsigned long long flags
Definition: pe_types.h:153