pacemaker  2.1.5-b7adf64e51
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 
17 #include "libpacemaker_private.h"
18 
27 static void
28 add_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 
45 void
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 
147 void
148 pcmk__abort_dangling_migration(void *data, void *user_data)
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 
176 bool
177 pcmk__rsc_can_migrate(const pe_resource_t *rsc, const pe_node_t *current)
178 {
179  CRM_CHECK(rsc != NULL, return false);
180 
181  if (!pcmk_is_set(rsc->flags, pe_rsc_allow_migrate)) {
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 
232 static char *
233 task_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 
256 void
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 */
293  pcmk__new_ordering(order->lh_rsc,
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  */
309  pcmk__new_ordering(order->lh_rsc,
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  */
329  pcmk__new_ordering(order->lh_rsc,
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) {
337  pcmk__new_ordering(order->lh_rsc,
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 */
352  pcmk__new_ordering(order->lh_rsc,
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 */
367  pcmk__new_ordering(order->lh_rsc,
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) {
375  pcmk__new_ordering(order->lh_rsc,
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 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
pe_action_t * lh_action
Definition: internal.h:200
enum rsc_start_requirement needs
Definition: pe_types.h:416
#define RSC_STOP
Definition: crm.h:202
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition: operations.c:185
void pcmk__order_migration_equivalents(pe__ordering_t *order)
char data[0]
Definition: cpg.c:55
G_GNUC_INTERNAL void pcmk__schedule_cleanup(pe_resource_t *rsc, const pe_node_t *node, bool optional)
#define pe__set_action_flags(action, flags_to_set)
Definition: internal.h:86
gboolean is_parent(pe_resource_t *child, pe_resource_t *rsc)
Definition: complex.c:895
#define stop_action(rsc, node, optional)
Definition: internal.h:415
#define pe_flag_remove_after_stop
Definition: pe_types.h:111
void pcmk__create_migration_actions(pe_resource_t *rsc, const pe_node_t *current)
pe_action_t * rh_action
Definition: internal.h:205
pe_node_t * partial_migration_target
Definition: pe_types.h:371
#define RSC_START
Definition: crm.h:199
pe_node_t * allocated_to
Definition: pe_types.h:370
#define RSC_MIGRATE
Definition: crm.h:196
const char * action
Definition: pcmk_fence.c:30
#define pe_rsc_allow_migrate
Definition: pe_types.h:287
#define pe_rsc_failed
Definition: pe_types.h:276
#define pe_rsc_start_pending
Definition: pe_types.h:278
GHashTable * meta
Definition: pe_types.h:420
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
struct pe_node_shared_s * details
Definition: pe_types.h:252
unsigned long long flags
Definition: pe_types.h:355
const char * uname
Definition: pe_types.h:216
pe_resource_t * lh_rsc
Definition: internal.h:199
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 XML_LRM_ATTR_MIGRATE_TARGET
Definition: msg_xml.h:326
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
const char * target
Definition: pcmk_fence.c:29
gboolean is_remote_node
Definition: pe_types.h:358
bool pcmk__rsc_can_migrate(const pe_resource_t *rsc, const pe_node_t *current)
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:504
#define start_action(rsc, node, optional)
Definition: internal.h:421
#define CRM_ASSERT(expr)
Definition: results.h:42
#define RSC_STATUS
Definition: crm.h:213
#define RSC_PROMOTE
Definition: crm.h:205
pe_working_set_t * cluster
Definition: pe_types.h:335
#define XML_OP_ATTR_PENDING
Definition: msg_xml.h:261
pe_resource_t * rh_rsc
Definition: internal.h:204
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:47
#define pe__set_order_flags(order_flags, flags_to_set)
Definition: internal.h:138
unsigned long long flags
Definition: pe_types.h:153
#define XML_LRM_ATTR_MIGRATE_SOURCE
Definition: msg_xml.h:325
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
gboolean unclean
Definition: pe_types.h:224
#define pe_rsc_managed
Definition: pe_types.h:257
uint64_t flags
Definition: remote.c:215
void pcmk__abort_dangling_migration(void *data, void *user_data)
#define RSC_DEMOTE
Definition: crm.h:207
char * id
Definition: pe_types.h:329
#define RSC_MIGRATED
Definition: crm.h:197