pacemaker  2.1.8-3980678f03
Scalable High-Availability cluster resource manager
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 
17 #include "libpacemaker_private.h"
18 
27 static void
28 add_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 
45 void
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 
153 void
154 pcmk__abort_dangling_migration(void *data, void *user_data)
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 
183 bool
185 {
186  CRM_CHECK(rsc != NULL, return false);
187 
188  if (!pcmk_is_set(rsc->flags, pcmk_rsc_migratable)) {
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 
240 static char *
241 task_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 
263 void
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 */
298  pcmk__new_ordering(order->rsc1,
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  */
316  pcmk__new_ordering(order->rsc1,
317  pcmk__op_key(order->rsc1->id,
318  PCMK_ACTION_START, 0),
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  */
338  pcmk__new_ordering(order->rsc1,
339  pcmk__op_key(order->rsc1->id, PCMK_ACTION_STOP, 0),
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) {
348  pcmk__new_ordering(order->rsc1,
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 */
365  pcmk__new_ordering(order->rsc1,
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 */
382  pcmk__new_ordering(order->rsc1,
383  pcmk__op_key(order->rsc1->id,
384  PCMK_ACTION_DEMOTE, 0),
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) {
392  pcmk__new_ordering(order->rsc1,
393  pcmk__op_key(order->rsc1->id,
394  PCMK_ACTION_DEMOTE, 0),
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 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:245
enum rsc_start_requirement needs
Definition: actions.h:351
pcmk_scheduler_t * cluster
Definition: resources.h:408
G_GNUC_INTERNAL void pcmk__schedule_cleanup(pcmk_resource_t *rsc, const pcmk_node_t *node, bool optional)
char data[0]
Definition: cpg.c:58
#define PCMK_META_RECORD_PENDING
Definition: options.h:104
pcmk_node_t * partial_migration_target
Definition: resources.h:450
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 stop_action(rsc, node, optional)
Definition: internal.h:214
#define pcmk__rsc_trace(rsc, fmt, args...)
If &#39;first&#39; is unrunnable, &#39;then&#39; becomes a real, unmigratable action.
#define pcmk__insert_meta(obj, name, value)
#define PCMK_ACTION_MONITOR
Definition: actions.h:60
#define PCMK_ACTION_MIGRATE_TO
Definition: actions.h:59
void pcmk__create_migration_actions(pcmk_resource_t *rsc, const pcmk_node_t *current)
#define pcmk__set_relation_flags(ar_flags, flags_to_set)
const char * action
Definition: pcmk_fence.c:30
#define PCMK__META_MIGRATE_TARGET
#define PCMK_ACTION_DEMOTE
Definition: actions.h:49
Actions are ordered (optionally, if no other flags are set)
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:98
struct pe_node_shared_s * details
Definition: nodes.h:167
#define PCMK_ACTION_START
Definition: actions.h:72
bool pcmk__rsc_can_migrate(const pcmk_resource_t *rsc, const pcmk_node_t *current)
unsigned long long flags
Definition: resources.h:428
const char * uname
Definition: nodes.h:73
Wrappers for and extensions to libxml2.
#define PCMK_ACTION_STOP
Definition: actions.h:75
#define PCMK_VALUE_TRUE
Definition: options.h:215
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
#define pcmk__str_copy(str)
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.
Definition: pe_actions.c:1129
const char * target
Definition: pcmk_fence.c:29
gboolean is_remote_node
Definition: resources.h:431
#define start_action(rsc, node, optional)
Definition: internal.h:220
void pcmk__order_migration_equivalents(pcmk__action_relation_t *order)
Relation applies only if &#39;first&#39; cannot be part of a live migration.
#define PCMK_ACTION_MIGRATE_FROM
Definition: actions.h:58
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: actions.c:250
pcmk_node_t * allocated_to
Definition: resources.h:447
gboolean is_parent(pcmk_resource_t *child, pcmk_resource_t *rsc)
Definition: complex.c:990
#define PCMK_ACTION_PROMOTE
Definition: actions.h:66
#define pcmk__set_action_flags(action, flags_to_set)
#define PCMK__META_MIGRATE_SOURCE
unsigned long long flags
Definition: scheduler.h:211
gboolean unclean
Definition: nodes.h:91
uint64_t flags
Definition: remote.c:215
void pcmk__abort_dangling_migration(void *data, void *user_data)