LCOV - code coverage report
Current view: top level - pacemaker - pcmk_sched_migration.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 147 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 6 0.0 %

          Line data    Source code
       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             : 
      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           0 : add_migration_meta(pcmk_action_t *action, const pcmk_node_t *source,
      29             :                    const pcmk_node_t *target)
      30             : {
      31           0 :     pcmk__insert_meta(action, PCMK__META_MIGRATE_SOURCE,
      32             :                       source->details->uname);
      33             : 
      34           0 :     pcmk__insert_meta(action, PCMK__META_MIGRATE_TARGET,
      35             :                       target->details->uname);
      36           0 : }
      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           0 : pcmk__create_migration_actions(pcmk_resource_t *rsc, const pcmk_node_t *current)
      47             : {
      48           0 :     pcmk_action_t *migrate_to = NULL;
      49           0 :     pcmk_action_t *migrate_from = NULL;
      50           0 :     pcmk_action_t *start = NULL;
      51           0 :     pcmk_action_t *stop = NULL;
      52             : 
      53           0 :     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           0 :     start = start_action(rsc, rsc->allocated_to, TRUE);
      58           0 :     stop = stop_action(rsc, current, TRUE);
      59             : 
      60           0 :     if (rsc->partial_migration_target == NULL) {
      61           0 :         migrate_to = custom_action(rsc, pcmk__op_key(rsc->id,
      62             :                                                      PCMK_ACTION_MIGRATE_TO, 0),
      63             :                                    PCMK_ACTION_MIGRATE_TO, current, TRUE,
      64             :                                    rsc->cluster);
      65             :     }
      66           0 :     migrate_from = custom_action(rsc, pcmk__op_key(rsc->id,
      67             :                                                    PCMK_ACTION_MIGRATE_FROM, 0),
      68           0 :                                  PCMK_ACTION_MIGRATE_FROM, rsc->allocated_to,
      69             :                                  TRUE, rsc->cluster);
      70             : 
      71           0 :     pcmk__set_action_flags(start, pcmk_action_migratable);
      72           0 :     pcmk__set_action_flags(stop, pcmk_action_migratable);
      73             : 
      74             :     // This is easier than trying to delete it from the graph
      75           0 :     pcmk__set_action_flags(start, pcmk_action_pseudo);
      76             : 
      77           0 :     if (rsc->partial_migration_target == NULL) {
      78           0 :         pcmk__set_action_flags(migrate_from, pcmk_action_migratable);
      79           0 :         pcmk__set_action_flags(migrate_to, pcmk_action_migratable);
      80           0 :         migrate_to->needs = start->needs;
      81             : 
      82             :         // Probe -> migrate_to -> migrate_from
      83           0 :         pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MONITOR, 0),
      84             :                            NULL,
      85             :                            rsc,
      86           0 :                            pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_TO, 0),
      87             :                            NULL, pcmk__ar_ordered, rsc->cluster);
      88           0 :         pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_TO, 0),
      89             :                            NULL,
      90             :                            rsc,
      91           0 :                            pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_FROM, 0),
      92             :                            NULL,
      93             :                            pcmk__ar_ordered|pcmk__ar_unmigratable_then_blocks,
      94             :                            rsc->cluster);
      95             :     } else {
      96           0 :         pcmk__set_action_flags(migrate_from, pcmk_action_migratable);
      97           0 :         migrate_from->needs = start->needs;
      98             : 
      99             :         // Probe -> migrate_from (migrate_to already completed)
     100           0 :         pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MONITOR, 0),
     101             :                            NULL,
     102             :                            rsc,
     103           0 :                            pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_FROM, 0),
     104             :                            NULL, pcmk__ar_ordered, rsc->cluster);
     105             :     }
     106             : 
     107             :     // migrate_from before stop or start
     108           0 :     pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_FROM, 0),
     109             :                        NULL,
     110           0 :                        rsc, pcmk__op_key(rsc->id, PCMK_ACTION_STOP, 0),
     111             :                        NULL,
     112             :                        pcmk__ar_ordered|pcmk__ar_unmigratable_then_blocks,
     113             :                        rsc->cluster);
     114           0 :     pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_FROM, 0),
     115             :                        NULL,
     116           0 :                        rsc, pcmk__op_key(rsc->id, PCMK_ACTION_START, 0),
     117             :                        NULL,
     118             :                        pcmk__ar_ordered
     119             :                        |pcmk__ar_unmigratable_then_blocks
     120             :                        |pcmk__ar_first_else_then,
     121             :                        rsc->cluster);
     122             : 
     123           0 :     if (migrate_to != NULL) {
     124           0 :         add_migration_meta(migrate_to, current, rsc->allocated_to);
     125             : 
     126           0 :         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           0 :             pcmk__insert_meta(migrate_to,
     139             :                               PCMK_META_RECORD_PENDING, PCMK_VALUE_TRUE);
     140             :         }
     141             :     }
     142             : 
     143           0 :     add_migration_meta(migrate_from, current, rsc->allocated_to);
     144           0 : }
     145             : 
     146             : /*!
     147             :  * \internal
     148             :  * \brief Abort a dangling migration by scheduling a stop (and possibly cleanup)
     149             :  *
     150             :  * \param[in]     data       Source node of dangling migration
     151             :  * \param[in,out] user_data  Resource involved in dangling migration
     152             :  */
     153             : void
     154           0 : pcmk__abort_dangling_migration(void *data, void *user_data)
     155             : {
     156           0 :     const pcmk_node_t *dangling_source = (const pcmk_node_t *) data;
     157           0 :     pcmk_resource_t *rsc = (pcmk_resource_t *) user_data;
     158             : 
     159           0 :     pcmk_action_t *stop = NULL;
     160           0 :     bool cleanup = pcmk_is_set(rsc->cluster->flags,
     161             :                                pcmk_sched_remove_after_stop);
     162             : 
     163           0 :     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           0 :     stop = stop_action(rsc, dangling_source, FALSE);
     168           0 :     pcmk__set_action_flags(stop, pcmk_action_migration_abort);
     169           0 :     if (cleanup) {
     170           0 :         pcmk__schedule_cleanup(rsc, dangling_source, false);
     171             :     }
     172           0 : }
     173             : 
     174             : /*!
     175             :  * \internal
     176             :  * \brief Check whether a resource can migrate
     177             :  *
     178             :  * \param[in] rsc   Resource to check
     179             :  * \param[in] node  Resource's current node
     180             :  *
     181             :  * \return true if \p rsc can migrate, otherwise false
     182             :  */
     183             : bool
     184           0 : pcmk__rsc_can_migrate(const pcmk_resource_t *rsc, const pcmk_node_t *current)
     185             : {
     186           0 :     CRM_CHECK(rsc != NULL, return false);
     187             : 
     188           0 :     if (!pcmk_is_set(rsc->flags, pcmk_rsc_migratable)) {
     189           0 :         pcmk__rsc_trace(rsc,
     190             :                         "%s cannot migrate because "
     191             :                         "the configuration does not allow it", rsc->id);
     192           0 :         return false;
     193             :     }
     194             : 
     195           0 :     if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
     196           0 :         pcmk__rsc_trace(rsc, "%s cannot migrate because it is not managed",
     197             :                         rsc->id);
     198           0 :         return false;
     199             :     }
     200             : 
     201           0 :     if (pcmk_is_set(rsc->flags, pcmk_rsc_failed)) {
     202           0 :         pcmk__rsc_trace(rsc, "%s cannot migrate because it is failed", rsc->id);
     203           0 :         return false;
     204             :     }
     205             : 
     206           0 :     if (pcmk_is_set(rsc->flags, pcmk_rsc_start_pending)) {
     207           0 :         pcmk__rsc_trace(rsc, "%s cannot migrate because it has a start pending",
     208             :                         rsc->id);
     209           0 :         return false;
     210             :     }
     211             : 
     212           0 :     if ((current == NULL) || current->details->unclean) {
     213           0 :         pcmk__rsc_trace(rsc,
     214             :                         "%s cannot migrate because "
     215             :                         "its current node (%s) is unclean",
     216             :                         rsc->id, pcmk__node_name(current));
     217           0 :         return false;
     218             :     }
     219             : 
     220           0 :     if ((rsc->allocated_to == NULL) || rsc->allocated_to->details->unclean) {
     221           0 :         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           0 :         return false;
     226             :     }
     227             : 
     228           0 :     return true;
     229             : }
     230             : 
     231             : /*!
     232             :  * \internal
     233             :  * \brief Get an action name from an action or operation key
     234             :  *
     235             :  * \param[in] action  If not NULL, get action name from here
     236             :  * \param[in] key     If not NULL, get action name from here
     237             :  *
     238             :  * \return Newly allocated copy of action name (or NULL if none available)
     239             :  */
     240             : static char *
     241           0 : task_from_action_or_key(const pcmk_action_t *action, const char *key)
     242             : {
     243           0 :     char *res = NULL;
     244             : 
     245           0 :     if (action != NULL) {
     246           0 :         res = pcmk__str_copy(action->task);
     247           0 :     } else if (key != NULL) {
     248           0 :         parse_op_key(key, NULL, &res, NULL);
     249             :     }
     250           0 :     return res;
     251             : }
     252             : 
     253             : /*!
     254             :  * \internal
     255             :  * \brief Order migration actions equivalent to a given ordering
     256             :  *
     257             :  * Orderings involving start, stop, demote, and promote actions must be honored
     258             :  * during a migration as well, so duplicate any such ordering for the
     259             :  * corresponding migration actions.
     260             :  *
     261             :  * \param[in,out] order     Ordering constraint to check
     262             :  */
     263             : void
     264           0 : pcmk__order_migration_equivalents(pcmk__action_relation_t *order)
     265             : {
     266           0 :     char *first_task = NULL;
     267           0 :     char *then_task = NULL;
     268             :     bool then_migratable;
     269             :     bool first_migratable;
     270             : 
     271             :     // Only orderings between unrelated resources are relevant
     272           0 :     if ((order->rsc1 == NULL) || (order->rsc2 == NULL)
     273           0 :         || (order->rsc1 == order->rsc2)
     274           0 :         || is_parent(order->rsc1, order->rsc2)
     275           0 :         || is_parent(order->rsc2, order->rsc1)) {
     276           0 :         return;
     277             :     }
     278             : 
     279             :     // Only orderings involving at least one migratable resource are relevant
     280           0 :     first_migratable = pcmk_is_set(order->rsc1->flags, pcmk_rsc_migratable);
     281           0 :     then_migratable = pcmk_is_set(order->rsc2->flags, pcmk_rsc_migratable);
     282           0 :     if (!first_migratable && !then_migratable) {
     283           0 :         return;
     284             :     }
     285             : 
     286             :     // Check which actions are involved
     287           0 :     first_task = task_from_action_or_key(order->action1, order->task1);
     288           0 :     then_task = task_from_action_or_key(order->action2, order->task2);
     289             : 
     290           0 :     if (pcmk__str_eq(first_task, PCMK_ACTION_START, pcmk__str_none)
     291           0 :         && pcmk__str_eq(then_task, PCMK_ACTION_START, pcmk__str_none)) {
     292             : 
     293           0 :         uint32_t flags = pcmk__ar_ordered;
     294             : 
     295           0 :         if (first_migratable && then_migratable) {
     296             :             /* A start then B start
     297             :              * -> A migrate_from then B migrate_to */
     298           0 :             pcmk__new_ordering(order->rsc1,
     299           0 :                                pcmk__op_key(order->rsc1->id,
     300             :                                             PCMK_ACTION_MIGRATE_FROM, 0),
     301             :                                NULL, order->rsc2,
     302           0 :                                pcmk__op_key(order->rsc2->id,
     303             :                                             PCMK_ACTION_MIGRATE_TO, 0),
     304           0 :                                NULL, flags, order->rsc1->cluster);
     305             :         }
     306             : 
     307           0 :         if (then_migratable) {
     308           0 :             if (first_migratable) {
     309           0 :                 pcmk__set_relation_flags(flags, pcmk__ar_if_first_unmigratable);
     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           0 :             pcmk__new_ordering(order->rsc1,
     317           0 :                                pcmk__op_key(order->rsc1->id,
     318             :                                             PCMK_ACTION_START, 0),
     319             :                                NULL, order->rsc2,
     320           0 :                                pcmk__op_key(order->rsc2->id,
     321             :                                             PCMK_ACTION_MIGRATE_TO, 0),
     322           0 :                                NULL, flags, order->rsc1->cluster);
     323             :         }
     324             : 
     325           0 :     } else if (then_migratable
     326           0 :                && pcmk__str_eq(first_task, PCMK_ACTION_STOP, pcmk__str_none)
     327           0 :                && pcmk__str_eq(then_task, PCMK_ACTION_STOP, pcmk__str_none)) {
     328             : 
     329           0 :         uint32_t flags = pcmk__ar_ordered;
     330             : 
     331           0 :         if (first_migratable) {
     332           0 :             pcmk__set_relation_flags(flags, pcmk__ar_if_first_unmigratable);
     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           0 :         pcmk__new_ordering(order->rsc1,
     339           0 :                            pcmk__op_key(order->rsc1->id, PCMK_ACTION_STOP, 0),
     340             :                            NULL,
     341             :                            order->rsc2,
     342           0 :                            pcmk__op_key(order->rsc2->id,
     343             :                                         PCMK_ACTION_MIGRATE_TO, 0),
     344           0 :                            NULL, flags, order->rsc1->cluster);
     345             : 
     346             :         // Also order B's migrate_from after A's stop during partial migrations
     347           0 :         if (order->rsc2->partial_migration_target != NULL) {
     348           0 :             pcmk__new_ordering(order->rsc1,
     349           0 :                                pcmk__op_key(order->rsc1->id, PCMK_ACTION_STOP,
     350             :                                             0),
     351             :                                NULL, order->rsc2,
     352           0 :                                pcmk__op_key(order->rsc2->id,
     353             :                                             PCMK_ACTION_MIGRATE_FROM, 0),
     354           0 :                                NULL, flags, order->rsc1->cluster);
     355             :         }
     356             : 
     357           0 :     } else if (pcmk__str_eq(first_task, PCMK_ACTION_PROMOTE, pcmk__str_none)
     358           0 :                && pcmk__str_eq(then_task, PCMK_ACTION_START, pcmk__str_none)) {
     359             : 
     360           0 :         uint32_t flags = pcmk__ar_ordered;
     361             : 
     362           0 :         if (then_migratable) {
     363             :             /* A promote then B start
     364             :              * -> A promote then B migrate_to */
     365           0 :             pcmk__new_ordering(order->rsc1,
     366           0 :                                pcmk__op_key(order->rsc1->id,
     367             :                                             PCMK_ACTION_PROMOTE, 0),
     368             :                                NULL, order->rsc2,
     369           0 :                                pcmk__op_key(order->rsc2->id,
     370             :                                             PCMK_ACTION_MIGRATE_TO, 0),
     371           0 :                                NULL, flags, order->rsc1->cluster);
     372             :         }
     373             : 
     374           0 :     } else if (pcmk__str_eq(first_task, PCMK_ACTION_DEMOTE, pcmk__str_none)
     375           0 :                && pcmk__str_eq(then_task, PCMK_ACTION_STOP, pcmk__str_none)) {
     376             : 
     377           0 :         uint32_t flags = pcmk__ar_ordered;
     378             : 
     379           0 :         if (then_migratable) {
     380             :             /* A demote then B stop
     381             :              * -> A demote then B migrate_to */
     382           0 :             pcmk__new_ordering(order->rsc1,
     383           0 :                                pcmk__op_key(order->rsc1->id,
     384             :                                             PCMK_ACTION_DEMOTE, 0),
     385             :                                NULL, order->rsc2,
     386           0 :                                pcmk__op_key(order->rsc2->id,
     387             :                                             PCMK_ACTION_MIGRATE_TO, 0),
     388           0 :                                NULL, flags, order->rsc1->cluster);
     389             : 
     390             :             // Order B migrate_from after A demote during partial migrations
     391           0 :             if (order->rsc2->partial_migration_target != NULL) {
     392           0 :                 pcmk__new_ordering(order->rsc1,
     393           0 :                                    pcmk__op_key(order->rsc1->id,
     394             :                                                 PCMK_ACTION_DEMOTE, 0),
     395             :                                    NULL, order->rsc2,
     396           0 :                                    pcmk__op_key(order->rsc2->id,
     397             :                                                 PCMK_ACTION_MIGRATE_FROM, 0),
     398           0 :                                    NULL, flags, order->rsc1->cluster);
     399             :             }
     400             :         }
     401             :     }
     402             : 
     403           0 :     free(first_task);
     404           0 :     free(then_task);
     405             : }

Generated by: LCOV version 1.14