pacemaker 2.1.7-2.1.7
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_sched_migration.c
Go to the documentation of this file.
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
18
27static void
28add_migration_meta(pcmk_action_t *action, const pcmk_node_t *source,
29 const pcmk_node_t *target)
30{
32 source->details->uname);
33
35 target->details->uname);
36}
37
45void
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,
63 PCMK_ACTION_MIGRATE_TO, current, TRUE,
64 rsc->cluster);
65 }
66 migrate_from = custom_action(rsc, pcmk__op_key(rsc->id,
69 TRUE, rsc->cluster);
70
73
74 // This is easier than trying to delete it from the graph
76
77 if (rsc->partial_migration_target == NULL) {
80 migrate_to->needs = start->needs;
81
82 // Probe -> migrate_to -> migrate_from
84 NULL,
85 rsc,
87 NULL, pcmk__ar_ordered, rsc->cluster);
89 NULL,
90 rsc,
92 NULL,
94 rsc->cluster);
95 } else {
97 migrate_from->needs = start->needs;
98
99 // Probe -> migrate_from (migrate_to already completed)
101 NULL,
102 rsc,
104 NULL, pcmk__ar_ordered, rsc->cluster);
105 }
106
107 // migrate_from before stop or start
109 NULL,
110 rsc, pcmk__op_key(rsc->id, PCMK_ACTION_STOP, 0),
111 NULL,
113 rsc->cluster);
115 NULL,
116 rsc, pcmk__op_key(rsc->id, PCMK_ACTION_START, 0),
117 NULL,
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
152void
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,
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);
168 if (cleanup) {
169 pcmk__schedule_cleanup(rsc, dangling_source, false);
170 }
171}
172
182bool
184{
185 CRM_CHECK(rsc != NULL, return false);
186
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
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
238static char *
239task_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
262void
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 */
300 pcmk__op_key(order->lh_rsc->id,
302 NULL, order->rh_rsc,
303 pcmk__op_key(order->rh_rsc->id,
305 NULL, flags, order->lh_rsc->cluster);
306 }
307
308 if (then_migratable) {
309 if (first_migratable) {
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 */
318 pcmk__op_key(order->lh_rsc->id,
320 NULL, order->rh_rsc,
321 pcmk__op_key(order->rh_rsc->id,
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) {
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 */
341 NULL,
342 order->rh_rsc,
343 pcmk__op_key(order->rh_rsc->id,
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) {
351 0),
352 NULL, order->rh_rsc,
353 pcmk__op_key(order->rh_rsc->id,
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 */
367 pcmk__op_key(order->lh_rsc->id,
369 NULL, order->rh_rsc,
370 pcmk__op_key(order->rh_rsc->id,
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 */
384 pcmk__op_key(order->lh_rsc->id,
386 NULL, order->rh_rsc,
387 pcmk__op_key(order->rh_rsc->id,
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) {
394 pcmk__op_key(order->lh_rsc->id,
396 NULL, order->rh_rsc,
397 pcmk__op_key(order->rh_rsc->id,
399 NULL, flags, order->lh_rsc->cluster);
400 }
401 }
402 }
403
404 free(first_task);
405 free(then_task);
406}
@ pcmk__ar_first_else_then
If 'first' is unrunnable, 'then' becomes a real, unmigratable action.
@ pcmk__ar_if_first_unmigratable
Relation applies only if 'first' cannot be part of a live migration.
@ pcmk__ar_unmigratable_then_blocks
@ pcmk__ar_ordered
Actions are ordered (optionally, if no other flags are set)
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition actions.c:96
#define PCMK_ACTION_STOP
Definition actions.h:74
#define PCMK_ACTION_PROMOTE
Definition actions.h:65
#define PCMK_ACTION_START
Definition actions.h:71
#define PCMK_ACTION_MIGRATE_FROM
Definition actions.h:57
@ pcmk_action_migratable
Whether action is allowed to be part of a live migration.
Definition actions.h:253
@ pcmk_action_pseudo
Whether action does not require invoking an agent.
Definition actions.h:238
@ pcmk_action_migration_abort
Whether action is a stop to abort a dangling migration.
Definition actions.h:259
#define PCMK_ACTION_MIGRATE_TO
Definition actions.h:58
#define PCMK_ACTION_MONITOR
Definition actions.h:59
#define PCMK_ACTION_DEMOTE
Definition actions.h:49
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition actions.c:42
uint64_t flags
Definition remote.c:3
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:99
gboolean is_parent(pcmk_resource_t *child, pcmk_resource_t *rsc)
Definition complex.c:919
char data[0]
Definition cpg.c:10
G_GNUC_INTERNAL void pcmk__new_ordering(pcmk_resource_t *first_rsc, char *first_task, pcmk_action_t *first_action, pcmk_resource_t *then_rsc, char *then_task, pcmk_action_t *then_action, uint32_t flags, pcmk_scheduler_t *sched)
G_GNUC_INTERNAL void pcmk__schedule_cleanup(pcmk_resource_t *rsc, const pcmk_node_t *node, bool optional)
#define CRM_CHECK(expr, failure_action)
Definition logging.h:238
#define XML_LRM_ATTR_MIGRATE_SOURCE
Definition msg_xml.h:330
#define XML_LRM_ATTR_MIGRATE_TARGET
Definition msg_xml.h:331
#define XML_OP_ATTR_PENDING
Definition msg_xml.h:272
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__create_migration_actions(pcmk_resource_t *rsc, const pcmk_node_t *current)
void pcmk__order_migration_equivalents(pe__ordering_t *order)
bool pcmk__rsc_can_migrate(const pcmk_resource_t *rsc, const pcmk_node_t *current)
#define start_action(rsc, node, optional)
Definition internal.h:385
#define pe_rsc_trace(rsc, fmt, args...)
Definition internal.h:37
pcmk_action_t * custom_action(pcmk_resource_t *rsc, char *key, const char *task, const pcmk_node_t *on_node, gboolean optional, pcmk_scheduler_t *scheduler)
Create or update an action object.
#define stop_action(rsc, node, optional)
Definition internal.h:379
#define pe__set_order_flags(order_flags, flags_to_set)
Definition internal.h:128
#define pe__set_action_flags(action, flags_to_set)
Definition internal.h:76
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition common.c:508
@ pcmk_rsc_migratable
Whether resource is allowed to live-migrate.
Definition resources.h:172
@ pcmk_rsc_start_pending
Whether resource has pending start action in history.
Definition resources.h:160
@ pcmk_rsc_managed
Whether resource is managed.
Definition resources.h:106
@ pcmk_rsc_failed
Whether resource is considered failed.
Definition resources.h:151
#define CRM_ASSERT(expr)
Definition results.h:42
@ pcmk_sched_remove_after_stop
Definition scheduler.h:113
@ pcmk__str_none
pcmk_resource_t * lh_rsc
Definition internal.h:171
pcmk_action_t * lh_action
Definition internal.h:172
pcmk_resource_t * rh_rsc
Definition internal.h:176
pcmk_action_t * rh_action
Definition internal.h:177
Implementation of pcmk_action_t.
Definition actions.h:390
enum rsc_start_requirement needs
Prerequisite for recovery.
Definition actions.h:411
GHashTable * meta
Meta-attributes relevant to action.
Definition actions.h:414
Implementation of pcmk_node_t.
Definition nodes.h:130
struct pe_node_shared_s * details
Basic node information.
Definition nodes.h:134
const char * uname
Node name in cluster.
Definition nodes.h:68
gboolean unclean
Whether node requires fencing.
Definition nodes.h:76
Implementation of pcmk_resource_t.
Definition resources.h:399
pcmk_node_t * partial_migration_target
The destination node, if migrate_to completed but migrate_from has not.
Definition resources.h:454
pcmk_scheduler_t * cluster
Cluster that resource is part of.
Definition resources.h:412
gboolean is_remote_node
Whether this is a remote connection.
Definition resources.h:432
char * id
Resource ID in configuration.
Definition resources.h:400
pcmk_node_t * allocated_to
Node resource is assigned to.
Definition resources.h:451
unsigned long long flags
Group of enum pcmk_rsc_flags.
Definition resources.h:429
unsigned long long flags
Group of enum pcmk_scheduler_flags.
Definition scheduler.h:183