diff --git a/lib/pacemaker/pcmk_sched_allocate.c b/lib/pacemaker/pcmk_sched_allocate.c index e0e59cf..a958082 100644 --- a/lib/pacemaker/pcmk_sched_allocate.c +++ b/lib/pacemaker/pcmk_sched_allocate.c @@ -1015,8 +1015,23 @@ apply_shutdown_lock(pe_resource_t *rsc, pe_working_set_t *data_set) return; } + if (rsc->lock_node != NULL) { + // The lock was obtained from resource history + + if (rsc->running_on != NULL) { + /* The resource was started elsewhere even though it is now + * considered locked. This shouldn't be possible, but as a + * failsafe, we don't want to disturb the resource now. + */ + pe_rsc_info(rsc, + "Cancelling shutdown lock because %s is already active", + rsc->id); + rsc->lock_node = NULL; + rsc->lock_time = 0; + } + // Only a resource active on exactly one node can be locked - if (pcmk__list_of_1(rsc->running_on)) { + } else if (pcmk__list_of_1(rsc->running_on)) { pe_node_t *node = rsc->running_on->data; if (node->details->shutdown) { diff --git a/lib/pacemaker/pcmk_sched_graph.c b/lib/pacemaker/pcmk_sched_graph.c index 31f6758..bc9866e 100644 --- a/lib/pacemaker/pcmk_sched_graph.c +++ b/lib/pacemaker/pcmk_sched_graph.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2019 the Pacemaker project contributors + * Copyright 2004-2020 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -992,6 +992,26 @@ add_downed_nodes(xmlNode *xml, const action_t *action, } } +static bool +should_lock_action(pe_action_t *action) +{ + // Only actions taking place on resource's lock node are locked + if ((action->rsc->lock_node == NULL) || (action->node == NULL) + || (action->node->details != action->rsc->lock_node->details)) { + return false; + } + + /* During shutdown, only stops are locked (otherwise, another action such as + * a demote would cause the controller to clear the lock) + */ + if (action->node->details->shutdown && action->task + && strcmp(action->task, RSC_STOP)) { + return false; + } + + return true; +} + static xmlNode * action2xml(action_t * action, gboolean as_input, pe_working_set_t *data_set) { @@ -1101,6 +1121,14 @@ action2xml(action_t * action, gboolean as_input, pe_working_set_t *data_set) XML_ATTR_TYPE }; + /* If a resource is locked to a node via shutdown-lock, mark its actions + * so the controller can preserve the lock when the action completes. + */ + if (should_lock_action(action)) { + crm_xml_add_ll(action_xml, XML_CONFIG_ATTR_SHUTDOWN_LOCK, + (long long) action->rsc->lock_time); + } + // List affected resource rsc_xml = create_xml_node(action_xml, diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c index f1fef0e..4e9e9a3 100644 --- a/lib/pengine/unpack.c +++ b/lib/pengine/unpack.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -1059,7 +1060,8 @@ unpack_node_loop(xmlNode * status, bool fence, pe_working_set_t * data_set) crm_trace("Checking node %s/%s/%s status %d/%d/%d", id, rsc->id, rsc->container->id, fence, rsc->role, RSC_ROLE_STARTED); } else if (!pe__is_guest_node(this_node) - && rsc->role == RSC_ROLE_STARTED) { + && ((rsc->role == RSC_ROLE_STARTED) + || is_set(data_set->flags, pe_flag_shutdown_lock))) { check = TRUE; crm_trace("Checking node %s/%s status %d/%d/%d", id, rsc->id, fence, rsc->role, RSC_ROLE_STARTED); } @@ -1075,6 +1077,9 @@ unpack_node_loop(xmlNode * status, bool fence, pe_working_set_t * data_set) } else if (fence) { process = TRUE; + + } else if (is_set(data_set->flags, pe_flag_shutdown_lock)) { + process = TRUE; } if(process) { @@ -2197,6 +2202,28 @@ calculate_active_ops(GListPtr sorted_op_list, int *start_index, int *stop_index) } } +// If resource history entry has shutdown lock, remember lock node and time +static void +unpack_shutdown_lock(xmlNode *rsc_entry, pe_resource_t *rsc, pe_node_t *node, + pe_working_set_t *data_set) +{ + time_t lock_time = 0; // When lock started (i.e. node shutdown time) + + if ((crm_element_value_epoch(rsc_entry, XML_CONFIG_ATTR_SHUTDOWN_LOCK, + &lock_time) == pcmk_ok) && (lock_time != 0)) { + + if ((data_set->shutdown_lock > 0) + && (get_effective_time(data_set) + > (lock_time + data_set->shutdown_lock))) { + pe_rsc_info(rsc, "Shutdown lock for %s on %s expired", + rsc->id, node->details->uname); + } else { + rsc->lock_node = node; + rsc->lock_time = lock_time; + } + } +} + static resource_t * unpack_lrm_rsc_state(node_t * node, xmlNode * rsc_entry, pe_working_set_t * data_set) { @@ -2233,18 +2260,30 @@ unpack_lrm_rsc_state(node_t * node, xmlNode * rsc_entry, pe_working_set_t * data } } - if (op_list == NULL) { - /* if there are no operations, there is nothing to do */ - return NULL; + if (is_not_set(data_set->flags, pe_flag_shutdown_lock)) { + if (op_list == NULL) { + // If there are no operations, there is nothing to do + return NULL; + } } /* find the resource */ rsc = unpack_find_resource(data_set, node, rsc_id, rsc_entry); if (rsc == NULL) { - rsc = process_orphan_resource(rsc_entry, node, data_set); + if (op_list == NULL) { + // If there are no operations, there is nothing to do + return NULL; + } else { + rsc = process_orphan_resource(rsc_entry, node, data_set); + } } CRM_ASSERT(rsc != NULL); + // Check whether the resource is "shutdown-locked" to this node + if (is_set(data_set->flags, pe_flag_shutdown_lock)) { + unpack_shutdown_lock(rsc_entry, rsc, node, data_set); + } + /* process operations */ saved_role = rsc->role; on_fail = action_fail_ignore;