Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/lib/pacemaker/pcmk_sched_migration.c b/lib/pacemaker/pcmk_sched_migration.c
index fba4d98b9f..93de19fc30 100644
--- a/lib/pacemaker/pcmk_sched_migration.c
+++ b/lib/pacemaker/pcmk_sched_migration.c
@@ -1,420 +1,408 @@
/*
* Copyright 2004-2023 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <stdbool.h>
#include <crm/msg_xml.h>
#include <pacemaker-internal.h>
#include "libpacemaker_private.h"
/*!
* \internal
* \brief Add migration source and target meta-attributes to an action
*
* \param[in,out] action Action to add meta-attributes to
* \param[in] source Node to add as migration source
* \param[in] target Node to add as migration target
*/
static void
add_migration_meta(pe_action_t *action, const pe_node_t *source,
const pe_node_t *target)
{
add_hash_param(action->meta, XML_LRM_ATTR_MIGRATE_SOURCE,
source->details->uname);
add_hash_param(action->meta, XML_LRM_ATTR_MIGRATE_TARGET,
target->details->uname);
}
/*!
* \internal
* \brief Create internal migration actions for a migrateable resource
*
* \param[in,out] rsc Resource to create migration actions for
* \param[in] current Node that resource is originally active on
*/
void
pcmk__create_migration_actions(pe_resource_t *rsc, const pe_node_t *current)
{
pe_action_t *migrate_to = NULL;
pe_action_t *migrate_from = NULL;
pe_action_t *start = NULL;
pe_action_t *stop = NULL;
pe_rsc_trace(rsc, "Creating actions to %smigrate %s from %s to %s",
((rsc->partial_migration_target == NULL)? "" : "partially "),
rsc->id, pe__node_name(current),
pe__node_name(rsc->allocated_to));
start = start_action(rsc, rsc->allocated_to, TRUE);
stop = stop_action(rsc, current, TRUE);
if (rsc->partial_migration_target == NULL) {
migrate_to = custom_action(rsc, pcmk__op_key(rsc->id,
PCMK_ACTION_MIGRATE_TO, 0),
PCMK_ACTION_MIGRATE_TO, current, TRUE, TRUE,
rsc->cluster);
}
migrate_from = custom_action(rsc, pcmk__op_key(rsc->id,
PCMK_ACTION_MIGRATE_FROM, 0),
PCMK_ACTION_MIGRATE_FROM, rsc->allocated_to,
TRUE, TRUE,
rsc->cluster);
- if ((migrate_from != NULL)
- && ((migrate_to != NULL) || (rsc->partial_migration_target != NULL))) {
+ pe__set_action_flags(start, pcmk_action_migratable);
+ pe__set_action_flags(stop, pcmk_action_migratable);
- pe__set_action_flags(start, pcmk_action_migratable);
- pe__set_action_flags(stop, pcmk_action_migratable);
+ // This is easier than trying to delete it from the graph
+ pe__set_action_flags(start, pcmk_action_pseudo);
- // This is easier than trying to delete it from the graph
- pe__set_action_flags(start, pcmk_action_pseudo);
-
- if (rsc->partial_migration_target == NULL) {
- pe__set_action_flags(migrate_from, pcmk_action_migratable);
-
- if (migrate_to != NULL) {
- pe__set_action_flags(migrate_to, pcmk_action_migratable);
- migrate_to->needs = start->needs;
- }
-
- // Probe -> migrate_to -> migrate_from
- pcmk__new_ordering(rsc,
- pcmk__op_key(rsc->id, PCMK_ACTION_MONITOR, 0),
- NULL, rsc,
- pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_TO, 0),
- NULL, pe_order_optional, rsc->cluster);
- pcmk__new_ordering(rsc,
- pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_TO, 0),
- NULL, rsc,
- pcmk__op_key(rsc->id,
- PCMK_ACTION_MIGRATE_FROM, 0),
- NULL,
- pe_order_optional
- |pe_order_implies_first_migratable,
- rsc->cluster);
- } else {
- pe__set_action_flags(migrate_from, pcmk_action_migratable);
- migrate_from->needs = start->needs;
-
- // Probe -> migrate_from (migrate_to already completed)
- pcmk__new_ordering(rsc,
- pcmk__op_key(rsc->id, PCMK_ACTION_MONITOR, 0),
- NULL, rsc,
- pcmk__op_key(rsc->id,
- PCMK_ACTION_MIGRATE_FROM, 0),
- NULL, pe_order_optional, rsc->cluster);
- }
+ if (rsc->partial_migration_target == NULL) {
+ pe__set_action_flags(migrate_from, pcmk_action_migratable);
+ pe__set_action_flags(migrate_to, pcmk_action_migratable);
+ migrate_to->needs = start->needs;
- // migrate_from before stop or start
- pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_FROM,
- 0),
+ // Probe -> migrate_to -> migrate_from
+ pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MONITOR, 0),
NULL,
- rsc, pcmk__op_key(rsc->id, PCMK_ACTION_STOP, 0),
+ rsc,
+ pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_TO, 0),
+ NULL, pe_order_optional, rsc->cluster);
+ pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_TO, 0),
NULL,
- pe_order_optional|pe_order_implies_first_migratable,
- rsc->cluster);
- pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_FROM,
- 0),
+ rsc,
+ pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_FROM, 0),
NULL,
- rsc, pcmk__op_key(rsc->id, PCMK_ACTION_START, 0),
- NULL, pe_order_optional
- |pe_order_implies_first_migratable
- |pe_order_pseudo_left,
+ pe_order_optional
+ |pe_order_implies_first_migratable,
rsc->cluster);
+ } else {
+ pe__set_action_flags(migrate_from, pcmk_action_migratable);
+ migrate_from->needs = start->needs;
+
+ // Probe -> migrate_from (migrate_to already completed)
+ pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MONITOR, 0),
+ NULL,
+ rsc,
+ pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_FROM, 0),
+ NULL, pe_order_optional, rsc->cluster);
}
+ // migrate_from before stop or start
+ pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_FROM, 0),
+ NULL,
+ rsc, pcmk__op_key(rsc->id, PCMK_ACTION_STOP, 0),
+ NULL,
+ pe_order_optional|pe_order_implies_first_migratable,
+ rsc->cluster);
+ pcmk__new_ordering(rsc, pcmk__op_key(rsc->id, PCMK_ACTION_MIGRATE_FROM, 0),
+ NULL,
+ rsc, pcmk__op_key(rsc->id, PCMK_ACTION_START, 0),
+ NULL,
+ pe_order_optional
+ |pe_order_implies_first_migratable
+ |pe_order_pseudo_left,
+ rsc->cluster);
+
if (migrate_to != NULL) {
add_migration_meta(migrate_to, current, rsc->allocated_to);
if (!rsc->is_remote_node) {
/* migrate_to takes place on the source node, but can affect the
* target node depending on how the agent is written. Because of
* this, pending migrate_to actions must be recorded in the CIB,
* in case the source node loses membership while the migrate_to
* action is still in flight.
*
* However we know Pacemaker Remote connection resources don't
* require this, so we skip this for them. (Although it wouldn't
* hurt, and now that record-pending defaults to true, skipping it
* matters even less.)
*/
add_hash_param(migrate_to->meta, XML_OP_ATTR_PENDING, "true");
}
}
- if (migrate_from != NULL) {
- add_migration_meta(migrate_from, current, rsc->allocated_to);
- }
+ add_migration_meta(migrate_from, current, rsc->allocated_to);
}
/*!
* \internal
* \brief Abort a dangling migration by scheduling a stop (and possibly cleanup)
*
* \param[in] data Source node of dangling migration
* \param[in,out] user_data Resource involved in dangling migration
*/
void
pcmk__abort_dangling_migration(void *data, void *user_data)
{
const pe_node_t *dangling_source = (const pe_node_t *) data;
pe_resource_t *rsc = (pe_resource_t *) user_data;
pe_action_t *stop = NULL;
bool cleanup = pcmk_is_set(rsc->cluster->flags,
pcmk_sched_remove_after_stop);
pe_rsc_trace(rsc,
"Scheduling stop%s for %s on %s due to dangling migration",
(cleanup? " and cleanup" : ""), rsc->id,
pe__node_name(dangling_source));
stop = stop_action(rsc, dangling_source, FALSE);
pe__set_action_flags(stop, pcmk_action_migration_abort);
if (cleanup) {
pcmk__schedule_cleanup(rsc, dangling_source, false);
}
}
/*!
* \internal
* \brief Check whether a resource can migrate
*
* \param[in] rsc Resource to check
* \param[in] node Resource's current node
*
* \return true if \p rsc can migrate, otherwise false
*/
bool
pcmk__rsc_can_migrate(const pe_resource_t *rsc, const pe_node_t *current)
{
CRM_CHECK(rsc != NULL, return false);
if (!pcmk_is_set(rsc->flags, pcmk_rsc_migratable)) {
pe_rsc_trace(rsc, "%s cannot migrate because "
"the configuration does not allow it",
rsc->id);
return false;
}
if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
pe_rsc_trace(rsc, "%s cannot migrate because it is not managed",
rsc->id);
return false;
}
if (pcmk_is_set(rsc->flags, pcmk_rsc_failed)) {
pe_rsc_trace(rsc, "%s cannot migrate because it is failed",
rsc->id);
return false;
}
if (pcmk_is_set(rsc->flags, pcmk_rsc_start_pending)) {
pe_rsc_trace(rsc, "%s cannot migrate because it has a start pending",
rsc->id);
return false;
}
if ((current == NULL) || current->details->unclean) {
pe_rsc_trace(rsc, "%s cannot migrate because "
"its current node (%s) is unclean",
rsc->id, pe__node_name(current));
return false;
}
if ((rsc->allocated_to == NULL) || rsc->allocated_to->details->unclean) {
pe_rsc_trace(rsc, "%s cannot migrate because "
"its next node (%s) is unclean",
rsc->id, pe__node_name(rsc->allocated_to));
return false;
}
return true;
}
/*!
* \internal
* \brief Get an action name from an action or operation key
*
* \param[in] action If not NULL, get action name from here
* \param[in] key If not NULL, get action name from here
*
* \return Newly allocated copy of action name (or NULL if none available)
*/
static char *
task_from_action_or_key(const pe_action_t *action, const char *key)
{
char *res = NULL;
if (action != NULL) {
res = strdup(action->task);
CRM_ASSERT(res != NULL);
} else if (key != NULL) {
parse_op_key(key, NULL, &res, NULL);
}
return res;
}
/*!
* \internal
* \brief Order migration actions equivalent to a given ordering
*
* Orderings involving start, stop, demote, and promote actions must be honored
* during a migration as well, so duplicate any such ordering for the
* corresponding migration actions.
*
* \param[in,out] order Ordering constraint to check
*/
void
pcmk__order_migration_equivalents(pe__ordering_t *order)
{
char *first_task = NULL;
char *then_task = NULL;
bool then_migratable;
bool first_migratable;
// Only orderings between unrelated resources are relevant
if ((order->lh_rsc == NULL) || (order->rh_rsc == NULL)
|| (order->lh_rsc == order->rh_rsc)
|| is_parent(order->lh_rsc, order->rh_rsc)
|| is_parent(order->rh_rsc, order->lh_rsc)) {
return;
}
// Only orderings involving at least one migratable resource are relevant
first_migratable = pcmk_is_set(order->lh_rsc->flags, pcmk_rsc_migratable);
then_migratable = pcmk_is_set(order->rh_rsc->flags, pcmk_rsc_migratable);
if (!first_migratable && !then_migratable) {
return;
}
// Check which actions are involved
first_task = task_from_action_or_key(order->lh_action,
order->lh_action_task);
then_task = task_from_action_or_key(order->rh_action,
order->rh_action_task);
if (pcmk__str_eq(first_task, PCMK_ACTION_START, pcmk__str_none)
&& pcmk__str_eq(then_task, PCMK_ACTION_START, pcmk__str_none)) {
uint32_t flags = pe_order_optional;
if (first_migratable && then_migratable) {
/* A start then B start
* -> A migrate_from then B migrate_to */
pcmk__new_ordering(order->lh_rsc,
pcmk__op_key(order->lh_rsc->id,
PCMK_ACTION_MIGRATE_FROM, 0),
NULL, order->rh_rsc,
pcmk__op_key(order->rh_rsc->id,
PCMK_ACTION_MIGRATE_TO, 0),
NULL, flags, order->lh_rsc->cluster);
}
if (then_migratable) {
if (first_migratable) {
pe__set_order_flags(flags, pe_order_apply_first_non_migratable);
}
/* A start then B start
* -> A start then B migrate_to (if start is not part of a
* migration)
*/
pcmk__new_ordering(order->lh_rsc,
pcmk__op_key(order->lh_rsc->id,
PCMK_ACTION_START, 0),
NULL, order->rh_rsc,
pcmk__op_key(order->rh_rsc->id,
PCMK_ACTION_MIGRATE_TO, 0),
NULL, flags, order->lh_rsc->cluster);
}
} else if (then_migratable
&& pcmk__str_eq(first_task, PCMK_ACTION_STOP, pcmk__str_none)
&& pcmk__str_eq(then_task, PCMK_ACTION_STOP, pcmk__str_none)) {
uint32_t flags = pe_order_optional;
if (first_migratable) {
pe__set_order_flags(flags, pe_order_apply_first_non_migratable);
}
/* For an ordering "stop A then stop B", if A is moving via restart, and
* B is migrating, enforce that B's migrate_to occurs after A's stop.
*/
pcmk__new_ordering(order->lh_rsc,
pcmk__op_key(order->lh_rsc->id, PCMK_ACTION_STOP, 0),
NULL,
order->rh_rsc,
pcmk__op_key(order->rh_rsc->id,
PCMK_ACTION_MIGRATE_TO, 0),
NULL, flags, order->lh_rsc->cluster);
// Also order B's migrate_from after A's stop during partial migrations
if (order->rh_rsc->partial_migration_target) {
pcmk__new_ordering(order->lh_rsc,
pcmk__op_key(order->lh_rsc->id, PCMK_ACTION_STOP,
0),
NULL, order->rh_rsc,
pcmk__op_key(order->rh_rsc->id,
PCMK_ACTION_MIGRATE_FROM, 0),
NULL, flags, order->lh_rsc->cluster);
}
} else if (pcmk__str_eq(first_task, PCMK_ACTION_PROMOTE, pcmk__str_none)
&& pcmk__str_eq(then_task, PCMK_ACTION_START, pcmk__str_none)) {
uint32_t flags = pe_order_optional;
if (then_migratable) {
/* A promote then B start
* -> A promote then B migrate_to */
pcmk__new_ordering(order->lh_rsc,
pcmk__op_key(order->lh_rsc->id,
PCMK_ACTION_PROMOTE, 0),
NULL, order->rh_rsc,
pcmk__op_key(order->rh_rsc->id,
PCMK_ACTION_MIGRATE_TO, 0),
NULL, flags, order->lh_rsc->cluster);
}
} else if (pcmk__str_eq(first_task, PCMK_ACTION_DEMOTE, pcmk__str_none)
&& pcmk__str_eq(then_task, PCMK_ACTION_STOP, pcmk__str_none)) {
uint32_t flags = pe_order_optional;
if (then_migratable) {
/* A demote then B stop
* -> A demote then B migrate_to */
pcmk__new_ordering(order->lh_rsc,
pcmk__op_key(order->lh_rsc->id,
PCMK_ACTION_DEMOTE, 0),
NULL, order->rh_rsc,
pcmk__op_key(order->rh_rsc->id,
PCMK_ACTION_MIGRATE_TO, 0),
NULL, flags, order->lh_rsc->cluster);
// Order B migrate_from after A demote during partial migrations
if (order->rh_rsc->partial_migration_target) {
pcmk__new_ordering(order->lh_rsc,
pcmk__op_key(order->lh_rsc->id,
PCMK_ACTION_DEMOTE, 0),
NULL, order->rh_rsc,
pcmk__op_key(order->rh_rsc->id,
PCMK_ACTION_MIGRATE_FROM, 0),
NULL, flags, order->lh_rsc->cluster);
}
}
}
free(first_task);
free(then_task);
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Jun 25, 3:04 AM (20 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1951947
Default Alt Text
(18 KB)

Event Timeline