pacemaker 3.0.1-16e74fc4da
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->priv->name);
33
35 target->priv->name);
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 const pcmk_node_t *target_node = rsc->priv->partial_migration_target;
53
54 pcmk__rsc_trace(rsc, "Creating actions to %smigrate %s from %s to %s",
55 ((target_node == NULL)? "" : "partially "),
56 rsc->id, pcmk__node_name(current),
57 pcmk__node_name(rsc->priv->assigned_node));
58 start = start_action(rsc, rsc->priv->assigned_node, TRUE);
59 stop = stop_action(rsc, current, TRUE);
60
61 if (target_node == NULL) {
62 migrate_to = custom_action(rsc, pcmk__op_key(rsc->id,
64 PCMK_ACTION_MIGRATE_TO, current, TRUE,
65 rsc->priv->scheduler);
66 }
67 migrate_from = custom_action(rsc, pcmk__op_key(rsc->id,
70 rsc->priv->assigned_node, TRUE,
71 rsc->priv->scheduler);
72
75
76 // This is easier than trying to delete it from the graph
78
79 if (target_node == NULL) {
82 migrate_to->needs = start->needs;
83
84 // Probe -> migrate_to -> migrate_from
86 NULL,
87 rsc,
89 NULL, pcmk__ar_ordered, rsc->priv->scheduler);
91 NULL,
92 rsc,
94 NULL,
96 rsc->priv->scheduler);
97 } else {
99 migrate_from->needs = start->needs;
100
101 // Probe -> migrate_from (migrate_to already completed)
103 NULL,
104 rsc,
106 NULL, pcmk__ar_ordered, rsc->priv->scheduler);
107 }
108
109 // migrate_from before stop or start
111 NULL,
112 rsc, pcmk__op_key(rsc->id, PCMK_ACTION_STOP, 0),
113 NULL,
115 rsc->priv->scheduler);
117 NULL,
118 rsc, pcmk__op_key(rsc->id, PCMK_ACTION_START, 0),
119 NULL,
123 rsc->priv->scheduler);
124
125 if (migrate_to != NULL) {
126 add_migration_meta(migrate_to, current, rsc->priv->assigned_node);
127
129 /* migrate_to takes place on the source node, but can affect the
130 * target node depending on how the agent is written. Because of
131 * this, pending migrate_to actions must be recorded in the CIB,
132 * in case the source node loses membership while the migrate_to
133 * action is still in flight.
134 *
135 * However we know Pacemaker Remote connection resources don't
136 * require this, so we skip this for them. (Although it wouldn't
137 * hurt, and now that PCMK_META_RECORD_PENDING defaults to true,
138 * skipping it matters even less.)
139 */
140 pcmk__insert_meta(migrate_to,
142 }
143 }
144
145 add_migration_meta(migrate_from, current, rsc->priv->assigned_node);
146}
147
155void
157{
158 const pcmk_node_t *dangling_source = (const pcmk_node_t *) data;
159 pcmk_resource_t *rsc = (pcmk_resource_t *) user_data;
160
161 pcmk_action_t *stop = NULL;
162
163 pcmk__rsc_trace(rsc,
164 "Scheduling stop for %s on %s due to dangling migration",
165 rsc->id, pcmk__node_name(dangling_source));
166 stop = stop_action(rsc, dangling_source, FALSE);
168}
169
179bool
181{
182 CRM_CHECK(rsc != NULL, return false);
183
185 pcmk__rsc_trace(rsc,
186 "%s cannot migrate because "
187 "the configuration does not allow it", rsc->id);
188 return false;
189 }
190
191 if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
192 pcmk__rsc_trace(rsc, "%s cannot migrate because it is not managed",
193 rsc->id);
194 return false;
195 }
196
198 pcmk__rsc_trace(rsc, "%s cannot migrate because it is failed", rsc->id);
199 return false;
200 }
201
203 pcmk__rsc_trace(rsc, "%s cannot migrate because it has a start pending",
204 rsc->id);
205 return false;
206 }
207
208 if ((current == NULL) || current->details->unclean) {
209 pcmk__rsc_trace(rsc,
210 "%s cannot migrate because "
211 "its current node (%s) is unclean",
212 rsc->id, pcmk__node_name(current));
213 return false;
214 }
215
216 if ((rsc->priv->assigned_node == NULL)
217 || rsc->priv->assigned_node->details->unclean) {
218
219 pcmk__rsc_trace(rsc,
220 "%s cannot migrate because "
221 "its next node (%s) is unclean",
222 rsc->id, pcmk__node_name(rsc->priv->assigned_node));
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 = pcmk__str_copy(action->task);
245 } else if (key != NULL) {
246 parse_op_key(key, NULL, &res, NULL);
247 }
248 return res;
249}
250
261void
263{
264 char *first_task = NULL;
265 char *then_task = NULL;
266 bool then_migratable;
267 bool first_migratable;
268
269 // Only orderings between unrelated resources are relevant
270 if ((order->rsc1 == NULL) || (order->rsc2 == NULL)
271 || (order->rsc1 == order->rsc2)
272 || is_parent(order->rsc1, order->rsc2)
273 || is_parent(order->rsc2, order->rsc1)) {
274 return;
275 }
276
277 // Only orderings involving at least one migratable resource are relevant
278 first_migratable = pcmk_is_set(order->rsc1->flags, pcmk__rsc_migratable);
279 then_migratable = pcmk_is_set(order->rsc2->flags, pcmk__rsc_migratable);
280 if (!first_migratable && !then_migratable) {
281 return;
282 }
283
284 // Check which actions are involved
285 first_task = task_from_action_or_key(order->action1, order->task1);
286 then_task = task_from_action_or_key(order->action2, order->task2);
287
288 if (pcmk__str_eq(first_task, PCMK_ACTION_START, pcmk__str_none)
289 && pcmk__str_eq(then_task, PCMK_ACTION_START, pcmk__str_none)) {
290
291 uint32_t flags = pcmk__ar_ordered;
292
293 if (first_migratable && then_migratable) {
294 /* A start then B start
295 * -> A migrate_from then B migrate_to */
297 pcmk__op_key(order->rsc1->id,
299 NULL, order->rsc2,
300 pcmk__op_key(order->rsc2->id,
302 NULL, flags, order->rsc1->priv->scheduler);
303 }
304
305 if (then_migratable) {
306 if (first_migratable) {
308 }
309
310 /* A start then B start
311 * -> A start then B migrate_to (if start is not part of a
312 * migration)
313 */
315 pcmk__op_key(order->rsc1->id,
317 NULL, order->rsc2,
318 pcmk__op_key(order->rsc2->id,
320 NULL, flags, order->rsc1->priv->scheduler);
321 }
322
323 } else if (then_migratable
324 && pcmk__str_eq(first_task, PCMK_ACTION_STOP, pcmk__str_none)
325 && pcmk__str_eq(then_task, PCMK_ACTION_STOP, pcmk__str_none)) {
326
327 uint32_t flags = pcmk__ar_ordered;
328
329 if (first_migratable) {
331 }
332
333 /* For an ordering "stop A then stop B", if A is moving via restart, and
334 * B is migrating, enforce that B's migrate_to occurs after A's stop.
335 */
338 NULL,
339 order->rsc2,
340 pcmk__op_key(order->rsc2->id,
342 NULL, flags, order->rsc1->priv->scheduler);
343
344 // Also order B's migrate_from after A's stop during partial migrations
345 if (order->rsc2->priv->partial_migration_target != NULL) {
348 0),
349 NULL, order->rsc2,
350 pcmk__op_key(order->rsc2->id,
352 NULL, flags, order->rsc1->priv->scheduler);
353 }
354
355 } else if (pcmk__str_eq(first_task, PCMK_ACTION_PROMOTE, pcmk__str_none)
356 && pcmk__str_eq(then_task, PCMK_ACTION_START, pcmk__str_none)) {
357
358 uint32_t flags = pcmk__ar_ordered;
359
360 if (then_migratable) {
361 /* A promote then B start
362 * -> A promote then B migrate_to */
364 pcmk__op_key(order->rsc1->id,
366 NULL, order->rsc2,
367 pcmk__op_key(order->rsc2->id,
369 NULL, flags, order->rsc1->priv->scheduler);
370 }
371
372 } else if (pcmk__str_eq(first_task, PCMK_ACTION_DEMOTE, pcmk__str_none)
373 && pcmk__str_eq(then_task, PCMK_ACTION_STOP, pcmk__str_none)) {
374
375 uint32_t flags = pcmk__ar_ordered;
376
377 if (then_migratable) {
378 /* A demote then B stop
379 * -> A demote then B migrate_to */
381 pcmk__op_key(order->rsc1->id,
383 NULL, order->rsc2,
384 pcmk__op_key(order->rsc2->id,
386 NULL, flags, order->rsc1->priv->scheduler);
387
388 // Order B migrate_from after A demote during partial migrations
389 if (order->rsc2->priv->partial_migration_target != NULL) {
391 pcmk__op_key(order->rsc1->id,
393 NULL, order->rsc2,
394 pcmk__op_key(order->rsc2->id,
396 NULL, flags,
397 order->rsc1->priv->scheduler);
398 }
399 }
400 }
401
402 free(first_task);
403 free(then_task);
404}
@ 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:278
#define PCMK_ACTION_STOP
Definition actions.h:66
#define PCMK_ACTION_PROMOTE
Definition actions.h:57
#define PCMK_ACTION_START
Definition actions.h:63
#define PCMK_ACTION_MIGRATE_FROM
Definition actions.h:49
#define PCMK_ACTION_MIGRATE_TO
Definition actions.h:50
#define PCMK_ACTION_MONITOR
Definition actions.h:51
#define PCMK_ACTION_DEMOTE
Definition actions.h:40
@ pcmk__action_migration_abort
@ pcmk__action_migratable
@ pcmk__action_pseudo
#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:225
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:80
gboolean is_parent(pcmk_resource_t *child, pcmk_resource_t *rsc)
Definition complex.c:982
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)
#define CRM_CHECK(expr, failure_action)
Definition logging.h:213
#define pcmk__insert_meta(obj, name, value)
#define PCMK_META_RECORD_PENDING
Definition options.h:105
#define PCMK_VALUE_TRUE
Definition options.h:219
#define PCMK__META_MIGRATE_SOURCE
#define PCMK__META_MIGRATE_TARGET
const char * action
Definition pcmk_fence.c:32
const char * target
Definition pcmk_fence.c:31
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:204
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:200
@ pcmk__rsc_migratable
@ pcmk__rsc_managed
@ pcmk__rsc_is_remote_connection
@ pcmk__rsc_start_pending
@ pcmk__rsc_failed
#define pcmk__rsc_trace(rsc, fmt, args...)
@ pcmk__str_none
#define pcmk__str_copy(str)
enum pcmk__requires needs
gboolean unclean
Definition nodes.h:58
pcmk_node_t * partial_migration_target
pcmk_scheduler_t * scheduler
unsigned long long flags
Definition resources.h:69
pcmk__resource_private_t * priv
Definition resources.h:61
pcmk__node_private_t * priv
Definition nodes.h:85
struct pcmk__node_details * details
Definition nodes.h:82
Wrappers for and extensions to libxml2.