root/lib/pacemaker/pcmk_sched_migration.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. add_migration_meta
  2. pcmk__create_migration_actions
  3. pcmk__abort_dangling_migration
  4. pcmk__rsc_can_migrate
  5. task_from_action_or_key
  6. pcmk__order_migration_equivalents

   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 
  19 /*!
  20  * \internal
  21  * \brief Add migration source and target meta-attributes to an action
  22  *
  23  * \param[in,out] action  Action to add meta-attributes to
  24  * \param[in]     source  Node to add as migration source
  25  * \param[in]     target  Node to add as migration target
  26  */
  27 static void
  28 add_migration_meta(pe_action_t *action, const pe_node_t *source,
     /* [previous][next][first][last][top][bottom][index][help] */
  29                    const pe_node_t *target)
  30 {
  31     add_hash_param(action->meta, XML_LRM_ATTR_MIGRATE_SOURCE,
  32                    source->details->uname);
  33 
  34     add_hash_param(action->meta, XML_LRM_ATTR_MIGRATE_TARGET,
  35                    target->details->uname);
  36 }
  37 
  38 /*!
  39  * \internal
  40  * \brief Create internal migration actions for a migrateable resource
  41  *
  42  * \param[in,out] rsc      Resource to create migration actions for
  43  * \param[in]     current  Node that resource is originally active on
  44  */
  45 void
  46 pcmk__create_migration_actions(pe_resource_t *rsc, const pe_node_t *current)
     /* [previous][next][first][last][top][bottom][index][help] */
  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 
  72         pe__set_action_flags(start, pe_action_migrate_runnable);
  73         pe__set_action_flags(stop, pe_action_migrate_runnable);
  74 
  75         // This is easier than trying to delete it from the graph
  76         pe__set_action_flags(start, pe_action_pseudo);
  77 
  78         if (rsc->partial_migration_target == NULL) {
  79             pe__set_action_flags(migrate_from, pe_action_migrate_runnable);
  80 
  81             if (migrate_to != NULL) {
  82                 pe__set_action_flags(migrate_to, pe_action_migrate_runnable);
  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,
  93                                pe_order_optional|pe_order_implies_first_migratable,
  94                                rsc->cluster);
  95         } else {
  96             pe__set_action_flags(migrate_from, pe_action_migrate_runnable);
  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,
 108                            pe_order_optional|pe_order_implies_first_migratable,
 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,
 112                            pe_order_optional|pe_order_implies_first_migratable|pe_order_pseudo_left,
 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 
 140 /*!
 141  * \internal
 142  * \brief Abort a dangling migration by scheduling a stop (and possibly cleanup)
 143  *
 144  * \param[in]     data       Source node of dangling migration
 145  * \param[in,out] user_data  Resource involved in dangling migration
 146  */
 147 void
 148 pcmk__abort_dangling_migration(void *data, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 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);
 161     pe__set_action_flags(stop, pe_action_dangle);
 162     if (cleanup) {
 163         pcmk__schedule_cleanup(rsc, dangling_source, false);
 164     }
 165 }
 166 
 167 /*!
 168  * \internal
 169  * \brief Check whether a resource can migrate
 170  *
 171  * \param[in] rsc   Resource to check
 172  * \param[in] node  Resource's current node
 173  *
 174  * \return true if \p rsc can migrate, otherwise false
 175  */
 176 bool
 177 pcmk__rsc_can_migrate(const pe_resource_t *rsc, const pe_node_t *current)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 
 200     if (pcmk_is_set(rsc->flags, pe_rsc_start_pending)) {
 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 
 223 /*!
 224  * \internal
 225  * \brief Get an action name from an action or operation key
 226  *
 227  * \param[in] action  If not NULL, get action name from here
 228  * \param[in] key     If not NULL, get action name from here
 229  *
 230  * \return Newly allocated copy of action name (or NULL if none available)
 231  */
 232 static char *
 233 task_from_action_or_key(const pe_action_t *action, const char *key)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 
 246 /*!
 247  * \internal
 248  * \brief Order migration actions equivalent to a given ordering
 249  *
 250  * Orderings involving start, stop, demote, and promote actions must be honored
 251  * during a migration as well, so duplicate any such ordering for the
 252  * corresponding migration actions.
 253  *
 254  * \param[in,out] order     Ordering constraint to check
 255  */
 256 void
 257 pcmk__order_migration_equivalents(pe__ordering_t *order)
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
 302                 pe__set_order_flags(flags, pe_order_apply_first_non_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) {
 323             pe__set_order_flags(flags, pe_order_apply_first_non_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 }

/* [previous][next][first][last][top][bottom][index][help] */