pacemaker 2.1.8-2.1.8
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-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 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/common/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 pcmk__rsc_trace(rsc, "Creating actions to %smigrate %s from %s to %s",
54 ((rsc->partial_migration_target == NULL)? "" : "partially "),
55 rsc->id, pcmk__node_name(current),
56 pcmk__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 PCMK_META_RECORD_PENDING defaults to true,
136 * skipping it matters even less.)
137 */
138 pcmk__insert_meta(migrate_to,
140 }
141 }
142
143 add_migration_meta(migrate_from, current, rsc->allocated_to);
144}
145
153void
155{
156 const pcmk_node_t *dangling_source = (const pcmk_node_t *) data;
157 pcmk_resource_t *rsc = (pcmk_resource_t *) user_data;
158
159 pcmk_action_t *stop = NULL;
160 bool cleanup = pcmk_is_set(rsc->cluster->flags,
162
163 pcmk__rsc_trace(rsc,
164 "Scheduling stop%s for %s on %s due to dangling migration",
165 (cleanup? " and cleanup" : ""), rsc->id,
166 pcmk__node_name(dangling_source));
167 stop = stop_action(rsc, dangling_source, FALSE);
169 if (cleanup) {
170 pcmk__schedule_cleanup(rsc, dangling_source, false);
171 }
172}
173
183bool
185{
186 CRM_CHECK(rsc != NULL, return false);
187
189 pcmk__rsc_trace(rsc,
190 "%s cannot migrate because "
191 "the configuration does not allow it", rsc->id);
192 return false;
193 }
194
195 if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
196 pcmk__rsc_trace(rsc, "%s cannot migrate because it is not managed",
197 rsc->id);
198 return false;
199 }
200
201 if (pcmk_is_set(rsc->flags, pcmk_rsc_failed)) {
202 pcmk__rsc_trace(rsc, "%s cannot migrate because it is failed", rsc->id);
203 return false;
204 }
205
207 pcmk__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 pcmk__rsc_trace(rsc,
214 "%s cannot migrate because "
215 "its current node (%s) is unclean",
216 rsc->id, pcmk__node_name(current));
217 return false;
218 }
219
220 if ((rsc->allocated_to == NULL) || rsc->allocated_to->details->unclean) {
221 pcmk__rsc_trace(rsc,
222 "%s cannot migrate because "
223 "its next node (%s) is unclean",
224 rsc->id, pcmk__node_name(rsc->allocated_to));
225 return false;
226 }
227
228 return true;
229}
230
240static char *
241task_from_action_or_key(const pcmk_action_t *action, const char *key)
242{
243 char *res = NULL;
244
245 if (action != NULL) {
246 res = pcmk__str_copy(action->task);
247 } else if (key != NULL) {
248 parse_op_key(key, NULL, &res, NULL);
249 }
250 return res;
251}
252
263void
265{
266 char *first_task = NULL;
267 char *then_task = NULL;
268 bool then_migratable;
269 bool first_migratable;
270
271 // Only orderings between unrelated resources are relevant
272 if ((order->rsc1 == NULL) || (order->rsc2 == NULL)
273 || (order->rsc1 == order->rsc2)
274 || is_parent(order->rsc1, order->rsc2)
275 || is_parent(order->rsc2, order->rsc1)) {
276 return;
277 }
278
279 // Only orderings involving at least one migratable resource are relevant
280 first_migratable = pcmk_is_set(order->rsc1->flags, pcmk_rsc_migratable);
281 then_migratable = pcmk_is_set(order->rsc2->flags, pcmk_rsc_migratable);
282 if (!first_migratable && !then_migratable) {
283 return;
284 }
285
286 // Check which actions are involved
287 first_task = task_from_action_or_key(order->action1, order->task1);
288 then_task = task_from_action_or_key(order->action2, order->task2);
289
290 if (pcmk__str_eq(first_task, PCMK_ACTION_START, pcmk__str_none)
291 && pcmk__str_eq(then_task, PCMK_ACTION_START, pcmk__str_none)) {
292
293 uint32_t flags = pcmk__ar_ordered;
294
295 if (first_migratable && then_migratable) {
296 /* A start then B start
297 * -> A migrate_from then B migrate_to */
299 pcmk__op_key(order->rsc1->id,
301 NULL, order->rsc2,
302 pcmk__op_key(order->rsc2->id,
304 NULL, flags, order->rsc1->cluster);
305 }
306
307 if (then_migratable) {
308 if (first_migratable) {
310 }
311
312 /* A start then B start
313 * -> A start then B migrate_to (if start is not part of a
314 * migration)
315 */
317 pcmk__op_key(order->rsc1->id,
319 NULL, order->rsc2,
320 pcmk__op_key(order->rsc2->id,
322 NULL, flags, order->rsc1->cluster);
323 }
324
325 } else if (then_migratable
326 && pcmk__str_eq(first_task, PCMK_ACTION_STOP, pcmk__str_none)
327 && pcmk__str_eq(then_task, PCMK_ACTION_STOP, pcmk__str_none)) {
328
329 uint32_t flags = pcmk__ar_ordered;
330
331 if (first_migratable) {
333 }
334
335 /* For an ordering "stop A then stop B", if A is moving via restart, and
336 * B is migrating, enforce that B's migrate_to occurs after A's stop.
337 */
340 NULL,
341 order->rsc2,
342 pcmk__op_key(order->rsc2->id,
344 NULL, flags, order->rsc1->cluster);
345
346 // Also order B's migrate_from after A's stop during partial migrations
347 if (order->rsc2->partial_migration_target != NULL) {
350 0),
351 NULL, order->rsc2,
352 pcmk__op_key(order->rsc2->id,
354 NULL, flags, order->rsc1->cluster);
355 }
356
357 } else if (pcmk__str_eq(first_task, PCMK_ACTION_PROMOTE, pcmk__str_none)
358 && pcmk__str_eq(then_task, PCMK_ACTION_START, pcmk__str_none)) {
359
360 uint32_t flags = pcmk__ar_ordered;
361
362 if (then_migratable) {
363 /* A promote then B start
364 * -> A promote then B migrate_to */
366 pcmk__op_key(order->rsc1->id,
368 NULL, order->rsc2,
369 pcmk__op_key(order->rsc2->id,
371 NULL, flags, order->rsc1->cluster);
372 }
373
374 } else if (pcmk__str_eq(first_task, PCMK_ACTION_DEMOTE, pcmk__str_none)
375 && pcmk__str_eq(then_task, PCMK_ACTION_STOP, pcmk__str_none)) {
376
377 uint32_t flags = pcmk__ar_ordered;
378
379 if (then_migratable) {
380 /* A demote then B stop
381 * -> A demote then B migrate_to */
383 pcmk__op_key(order->rsc1->id,
385 NULL, order->rsc2,
386 pcmk__op_key(order->rsc2->id,
388 NULL, flags, order->rsc1->cluster);
389
390 // Order B migrate_from after A demote during partial migrations
391 if (order->rsc2->partial_migration_target != NULL) {
393 pcmk__op_key(order->rsc1->id,
395 NULL, order->rsc2,
396 pcmk__op_key(order->rsc2->id,
398 NULL, flags, order->rsc1->cluster);
399 }
400 }
401 }
402
403 free(first_task);
404 free(then_task);
405}
@ 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)
#define pcmk__set_relation_flags(ar_flags, flags_to_set)
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition actions.c:250
#define PCMK_ACTION_STOP
Definition actions.h:75
#define PCMK_ACTION_PROMOTE
Definition actions.h:66
#define PCMK_ACTION_START
Definition actions.h:72
#define PCMK_ACTION_MIGRATE_FROM
Definition actions.h:58
@ pcmk_action_migratable
Definition actions.h:219
@ pcmk_action_pseudo
Definition actions.h:204
@ pcmk_action_migration_abort
Definition actions.h:225
#define PCMK_ACTION_MIGRATE_TO
Definition actions.h:59
#define PCMK_ACTION_MONITOR
Definition actions.h:60
#define PCMK_ACTION_DEMOTE
Definition actions.h:49
#define pcmk__set_action_flags(action, flags_to_set)
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:196
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:98
gboolean is_parent(pcmk_resource_t *child, pcmk_resource_t *rsc)
Definition complex.c:990
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:245
#define pcmk__insert_meta(obj, name, value)
#define PCMK_META_RECORD_PENDING
Definition options.h:104
#define PCMK_VALUE_TRUE
Definition options.h:215
#define PCMK__META_MIGRATE_SOURCE
#define PCMK__META_MIGRATE_TARGET
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(pcmk__action_relation_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:220
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:214
@ pcmk_rsc_migratable
Definition resources.h:157
@ pcmk_rsc_start_pending
Definition resources.h:142
@ pcmk_rsc_managed
Definition resources.h:88
@ pcmk_rsc_failed
Definition resources.h:133
@ pcmk_sched_remove_after_stop
Definition scheduler.h:127
#define pcmk__rsc_trace(rsc, fmt, args...)
@ pcmk__str_none
#define pcmk__str_copy(str)
enum rsc_start_requirement needs
Definition actions.h:351
struct pe_node_shared_s * details
Definition nodes.h:167
const char * uname
Definition nodes.h:73
gboolean unclean
Definition nodes.h:91
pcmk_node_t * partial_migration_target
Definition resources.h:450
pcmk_scheduler_t * cluster
Definition resources.h:408
gboolean is_remote_node
Definition resources.h:431
pcmk_node_t * allocated_to
Definition resources.h:447
unsigned long long flags
Definition resources.h:428
unsigned long long flags
Definition scheduler.h:211
Wrappers for and extensions to libxml2.