From f5d88938955f63935058b7cc2d706a12e6ea1121 Mon Sep 17 00:00:00 2001 From: Ken Gaillot Date: Fri, 6 Dec 2019 11:57:59 -0600 Subject: [PATCH 07/18] Low: scheduler: respect shutdown locks when placing active resources Use new pe_resource_t members to indicate that a resource is locked to a particular node. For active resources (i.e. in the transition where the node is scheduled for shutdown), these are connected by checking each lockable resource for whether it is running on a single clean node that is shutting down. When applying constraints, place -INFINITY location constraints for locked resources on all nodes other than the lock node. (Inactive resources -- i.e. in later transitions after the node is shut down -- are not yet locked.) --- include/crm/pengine/pe_types.h | 2 + lib/pacemaker/pcmk_sched_allocate.c | 87 +++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/include/crm/pengine/pe_types.h b/include/crm/pengine/pe_types.h index 8a735a3..123d8ef 100644 --- a/include/crm/pengine/pe_types.h +++ b/include/crm/pengine/pe_types.h @@ -354,6 +354,8 @@ struct pe_resource_s { GListPtr fillers; pe_node_t *pending_node; // Node on which pending_task is happening + pe_node_t *lock_node; // Resource is shutdown-locked to this node + time_t lock_time; // When shutdown lock started #if ENABLE_VERSIONED_ATTRS xmlNode *versioned_parameters; diff --git a/lib/pacemaker/pcmk_sched_allocate.c b/lib/pacemaker/pcmk_sched_allocate.c index fc2f4cf..0314f1b 100644 --- a/lib/pacemaker/pcmk_sched_allocate.c +++ b/lib/pacemaker/pcmk_sched_allocate.c @@ -977,6 +977,87 @@ rsc_discover_filter(resource_t *rsc, node_t *node) } } +static time_t +shutdown_time(pe_node_t *node, pe_working_set_t *data_set) +{ + const char *shutdown = pe_node_attribute_raw(node, XML_CIB_ATTR_SHUTDOWN); + time_t result = 0; + + if (shutdown) { + errno = 0; + result = (time_t) crm_int_helper(shutdown, NULL); + if (errno != 0) { + result = 0; + } + } + return result? result : get_effective_time(data_set); +} + +static void +apply_shutdown_lock(pe_resource_t *rsc, pe_working_set_t *data_set) +{ + const char *class; + + // Only primitives and (uncloned) groups may be locked + if (rsc->variant == pe_group) { + for (GList *item = rsc->children; item != NULL; + item = item->next) { + apply_shutdown_lock((pe_resource_t *) item->data, data_set); + } + } else if (rsc->variant != pe_native) { + return; + } + + // Fence devices and remote connections can't be locked + class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); + if ((class == NULL) || !strcmp(class, PCMK_RESOURCE_CLASS_STONITH) + || pe__resource_is_remote_conn(rsc, data_set)) { + return; + } + + // Only a resource active on exactly one node can be locked + if (pcmk__list_of_1(rsc->running_on)) { + pe_node_t *node = rsc->running_on->data; + + if (node->details->shutdown) { + if (node->details->unclean) { + pe_rsc_debug(rsc, "Not locking %s to unclean %s for shutdown", + rsc->id, node->details->uname); + } else { + rsc->lock_node = node; + rsc->lock_time = shutdown_time(node, data_set); + } + } + } + + if (rsc->lock_node == NULL) { + // No lock needed + return; + } + + if (data_set->shutdown_lock > 0) { + time_t lock_expiration = rsc->lock_time + data_set->shutdown_lock; + + pe_rsc_info(rsc, "Locking %s to %s due to shutdown (expires @%lld)", + rsc->id, rsc->lock_node->details->uname, + (long long) lock_expiration); + pe__update_recheck_time(++lock_expiration, data_set); + } else { + pe_rsc_info(rsc, "Locking %s to %s due to shutdown", + rsc->id, rsc->lock_node->details->uname); + } + + // If resource is locked to one node, ban it from all other nodes + for (GList *item = data_set->nodes; item != NULL; item = item->next) { + pe_node_t *node = item->data; + + if (strcmp(node->details->uname, rsc->lock_node->details->uname)) { + resource_location(rsc, node, -CRM_SCORE_INFINITY, + XML_CONFIG_ATTR_SHUTDOWN_LOCK, data_set); + } + } +} + /* * Count how many valid nodes we have (so we know the maximum number of * colors we can resolve). @@ -988,6 +1069,12 @@ stage2(pe_working_set_t * data_set) { GListPtr gIter = NULL; + if (is_set(data_set->flags, pe_flag_shutdown_lock)) { + for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) { + apply_shutdown_lock((pe_resource_t *) gIter->data, data_set); + } + } + for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) { node_t *node = (node_t *) gIter->data; -- 1.8.3.1