Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4511872
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
18 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment