File pacemaker#3409-0002-Low-tools-use-better-value-for-crm_resource-force-ti.patch of Package pacemaker
From 3e3513e579b30625a6f5040ae3d8681f23768567 Mon Sep 17 00:00:00 2001
From: Ken Gaillot <kgaillot@redhat.com>
Date: Thu, 14 Mar 2024 16:57:10 -0500
Subject: [PATCH 2/3] Low: tools: use better value for crm_resource --force-*
timeout
This drops the pe_get_configured_timeout() function, because it duplicated what
other functions already do, but poorly. It did not handle rsc_expression and
op_expression in rules, did not default to the minimum-interval monitor timeout
for probes, etc.
Also, use guint for the timeout, since that's how it's eventually used.
---
include/crm/pengine/internal.h | 3 --
lib/pengine/pe_actions.c | 49 ------------------
tools/crm_resource.c | 11 ++--
tools/crm_resource.h | 9 ++--
tools/crm_resource_runtime.c | 91 +++++++++++++++++++++++-----------
5 files changed, 73 insertions(+), 90 deletions(-)
Index: pacemaker-2.1.7+20231219.0f7f88312/include/crm/pengine/internal.h
===================================================================
--- pacemaker-2.1.7+20231219.0f7f88312.orig/include/crm/pengine/internal.h
+++ pacemaker-2.1.7+20231219.0f7f88312/include/crm/pengine/internal.h
@@ -396,9 +396,6 @@ pcmk_action_t *custom_action(pcmk_resour
rsc, demote_key(rsc), PCMK_ACTION_DEMOTE, node, \
optional, rsc->cluster)
-extern int pe_get_configured_timeout(pcmk_resource_t *rsc, const char *action,
- pcmk_scheduler_t *scheduler);
-
pcmk_action_t *find_first_action(const GList *input, const char *uuid,
const char *task, const pcmk_node_t *on_node);
Index: pacemaker-2.1.7+20231219.0f7f88312/lib/pengine/pe_actions.c
===================================================================
--- pacemaker-2.1.7+20231219.0f7f88312.orig/lib/pengine/pe_actions.c
+++ pacemaker-2.1.7+20231219.0f7f88312/lib/pengine/pe_actions.c
@@ -1400,55 +1400,6 @@ pe_free_action(pcmk_action_t *action)
free(action);
}
-int
-pe_get_configured_timeout(pcmk_resource_t *rsc, const char *action,
- pcmk_scheduler_t *scheduler)
-{
- xmlNode *child = NULL;
- GHashTable *action_meta = NULL;
- const char *timeout_spec = NULL;
- int timeout_ms = 0;
-
- pe_rule_eval_data_t rule_data = {
- .node_hash = NULL,
- .role = pcmk_role_unknown,
- .now = scheduler->now,
- .match_data = NULL,
- .rsc_data = NULL,
- .op_data = NULL
- };
-
- for (child = first_named_child(rsc->ops_xml, XML_ATTR_OP);
- child != NULL; child = crm_next_same_xml(child)) {
- if (pcmk__str_eq(action, crm_element_value(child, XML_NVPAIR_ATTR_NAME),
- pcmk__str_casei)) {
- timeout_spec = crm_element_value(child, XML_ATTR_TIMEOUT);
- break;
- }
- }
-
- if (timeout_spec == NULL && scheduler->op_defaults) {
- action_meta = pcmk__strkey_table(free, free);
- pe__unpack_dataset_nvpairs(scheduler->op_defaults, XML_TAG_META_SETS,
- &rule_data, action_meta, NULL, FALSE,
- scheduler);
- timeout_spec = g_hash_table_lookup(action_meta, XML_ATTR_TIMEOUT);
- }
-
- // @TODO check meta-attributes
- // @TODO maybe use min-interval monitor timeout as default for monitors
-
- timeout_ms = crm_get_msec(timeout_spec);
- if (timeout_ms < 0) {
- timeout_ms = PCMK_DEFAULT_ACTION_TIMEOUT_MS;
- }
-
- if (action_meta != NULL) {
- g_hash_table_destroy(action_meta);
- }
- return timeout_ms;
-}
-
enum action_tasks
get_complex_task(const pcmk_resource_t *rsc, const char *name)
{
Index: pacemaker-2.1.7+20231219.0f7f88312/tools/crm_resource.c
===================================================================
--- pacemaker-2.1.7+20231219.0f7f88312.orig/tools/crm_resource.c
+++ pacemaker-2.1.7+20231219.0f7f88312/tools/crm_resource.c
@@ -97,7 +97,7 @@ struct {
char *prop_name; // Attribute name
gchar *prop_set; // --set-name (attribute block XML ID)
gchar *prop_value; // --parameter-value (attribute value)
- int timeout_ms; // Parsed from --timeout value
+ guint timeout_ms; // Parsed from --timeout value
char *agent_spec; // Standard and/or provider and/or agent
gchar *xml_file; // Value of (deprecated) --xml-file
int check_level; // Optional value of --validate or --force-check
@@ -897,7 +897,15 @@ set_prop_cb(const gchar *option_name, co
gboolean
timeout_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
- options.timeout_ms = crm_get_msec(optarg);
+ long long timeout_ms = crm_get_msec(optarg);
+
+ if (timeout_ms < 0) {
+ // @COMPAT When we can break backward compatibilty, return FALSE
+ crm_warn("Ignoring invalid timeout '%s'", optarg);
+ options.timeout_ms = 0U;
+ } else {
+ options.timeout_ms = (guint) QB_MIN(timeout_ms, UINT_MAX);
+ }
return TRUE;
}
Index: pacemaker-2.1.7+20231219.0f7f88312/tools/crm_resource.h
===================================================================
--- pacemaker-2.1.7+20231219.0f7f88312.orig/tools/crm_resource.h
+++ pacemaker-2.1.7+20231219.0f7f88312/tools/crm_resource.h
@@ -89,7 +89,7 @@ int cli_cleanup_all(pcmk_ipc_api_t *cont
pcmk_scheduler_t *scheduler);
int cli_resource_restart(pcmk__output_t *out, pcmk_resource_t *rsc,
const pcmk_node_t *node, const char *move_lifetime,
- int timeout_ms, cib_t *cib, int cib_options,
+ guint timeout_ms, cib_t *cib, int cib_options,
gboolean promoted_role_only, gboolean force);
int cli_resource_move(const pcmk_resource_t *rsc, const char *rsc_id,
const char *host_name, const char *move_lifetime,
@@ -99,12 +99,13 @@ crm_exit_t cli_resource_execute_from_par
const char *rsc_class, const char *rsc_prov,
const char *rsc_type, const char *rsc_action,
GHashTable *params, GHashTable *override_hash,
- int timeout_ms, int resource_verbose,
+ guint timeout_ms,
+ int resource_verbose,
gboolean force, int check_level);
crm_exit_t cli_resource_execute(pcmk_resource_t *rsc,
const char *requested_name,
const char *rsc_action, GHashTable *override_hash,
- int timeout_ms, cib_t *cib,
+ guint timeout_ms, cib_t *cib,
pcmk_scheduler_t *scheduler,
int resource_verbose, gboolean force, int check_level);
@@ -121,7 +122,7 @@ int cli_resource_delete_attribute(pcmk_r
cib_t *cib, int cib_options, gboolean force);
int update_scheduler_input(pcmk_scheduler_t *scheduler, xmlNode **xml);
-int wait_till_stable(pcmk__output_t *out, int timeout_ms, cib_t * cib);
+int wait_till_stable(pcmk__output_t *out, guint timeout_ms, cib_t * cib);
bool resource_is_running_on(pcmk_resource_t *rsc, const char *host);
Index: pacemaker-2.1.7+20231219.0f7f88312/tools/crm_resource_runtime.c
===================================================================
--- pacemaker-2.1.7+20231219.0f7f88312.orig/tools/crm_resource_runtime.c
+++ pacemaker-2.1.7+20231219.0f7f88312/tools/crm_resource_runtime.c
@@ -9,12 +9,18 @@
#include <crm_internal.h>
-#include <crm_resource.h>
+#include <stdio.h>
+#include <limits.h>
+#include <glib.h>
+#include <libxml/tree.h>
+
#include <crm/common/ipc_attrd_internal.h>
#include <crm/common/ipc_controld.h>
#include <crm/common/lists_internal.h>
#include <crm/services_internal.h>
+#include <crm_resource.h>
+
static GList *
build_node_info_list(const pcmk_resource_t *rsc)
{
@@ -1325,11 +1331,11 @@ update_dataset(cib_t *cib, pcmk_schedule
*
* \return Maximum stop timeout for \p rsc (in milliseconds)
*/
-static int
+static guint
max_rsc_stop_timeout(pcmk_resource_t *rsc)
{
long long result_ll;
- int max_delay = 0;
+ guint max_delay = 0;
xmlNode *config = NULL;
GHashTable *meta = NULL;
@@ -1341,7 +1347,7 @@ max_rsc_stop_timeout(pcmk_resource_t *rs
if (rsc->children != NULL) {
for (GList *iter = rsc->children; iter; iter = iter->next) {
pcmk_resource_t *child = iter->data;
- int delay = max_rsc_stop_timeout(child);
+ guint delay = max_rsc_stop_timeout(child);
if (delay > max_delay) {
pe_rsc_trace(rsc,
@@ -1363,9 +1369,8 @@ max_rsc_stop_timeout(pcmk_resource_t *rs
*/
meta = pcmk__unpack_action_meta(rsc, NULL, PCMK_ACTION_STOP, 0, config);
if ((pcmk__scan_ll(g_hash_table_lookup(meta, XML_ATTR_TIMEOUT),
- &result_ll, -1LL) == pcmk_rc_ok)
- && (result_ll >= 0) && (result_ll <= INT_MAX)) {
- max_delay = (int) result_ll;
+ &result_ll, -1LL) == pcmk_rc_ok) && (result_ll >= 0)) {
+ max_delay = (guint) QB_MIN(result_ll, UINT_MAX);
}
g_hash_table_destroy(meta);
@@ -1387,16 +1392,16 @@ max_rsc_stop_timeout(pcmk_resource_t *rs
* throttling, or any demotions needed. It checks the stop timeout, even
* if the resources in question are actually being started.
*/
-static int
+static guint
wait_time_estimate(pcmk_scheduler_t *scheduler, const GList *resources)
{
- int max_delay = 0;
+ guint max_delay = 0U;
// Find maximum stop timeout in milliseconds
for (const GList *item = resources; item != NULL; item = item->next) {
pcmk_resource_t *rsc = pe_find_resource(scheduler->resources,
(const char *) item->data);
- int delay = max_rsc_stop_timeout(rsc);
+ guint delay = max_rsc_stop_timeout(rsc);
if (delay > max_delay) {
pe_rsc_trace(rsc,
@@ -1406,7 +1411,7 @@ wait_time_estimate(pcmk_scheduler_t *sch
}
}
- return (max_delay / 1000) + 5;
+ return (max_delay / 1000U) + 5U;
}
#define waiting_for_starts(d, r, h) ((d != NULL) || \
@@ -1438,15 +1443,15 @@ wait_time_estimate(pcmk_scheduler_t *sch
int
cli_resource_restart(pcmk__output_t *out, pcmk_resource_t *rsc,
const pcmk_node_t *node, const char *move_lifetime,
- int timeout_ms, cib_t *cib, int cib_options,
+ guint timeout_ms, cib_t *cib, int cib_options,
gboolean promoted_role_only, gboolean force)
{
int rc = pcmk_rc_ok;
int lpc = 0;
int before = 0;
- int step_timeout_s = 0;
- int sleep_interval = 2;
- int timeout = timeout_ms / 1000;
+ guint step_timeout_s = 0;
+ guint sleep_interval = 2U;
+ guint timeout = timeout_ms / 1000U;
bool stop_via_ban = false;
char *rsc_id = NULL;
@@ -1616,7 +1621,7 @@ cli_resource_restart(pcmk__output_t *out
sleep(sleep_interval);
if(timeout) {
timeout -= sleep_interval;
- crm_trace("%ds remaining", timeout);
+ crm_trace("%us remaining", timeout);
}
rc = update_dataset(cib, scheduler, FALSE);
if(rc != pcmk_rc_ok) {
@@ -1839,17 +1844,22 @@ print_pending_actions(pcmk__output_t *ou
* \return Standard Pacemaker return code
*/
int
-wait_till_stable(pcmk__output_t *out, int timeout_ms, cib_t * cib)
+wait_till_stable(pcmk__output_t *out, guint timeout_ms, cib_t * cib)
{
pcmk_scheduler_t *scheduler = NULL;
xmlXPathObjectPtr search;
int rc = pcmk_rc_ok;
bool pending_unknown_state_resources;
- int timeout_s = timeout_ms? ((timeout_ms + 999) / 1000) : WAIT_DEFAULT_TIMEOUT_S;
- time_t expire_time = time(NULL) + timeout_s;
+ time_t expire_time = time(NULL);
time_t time_diff;
bool printed_version_warning = out->is_quiet(out); // i.e. don't print if quiet
+ if (timeout_ms == 0) {
+ expire_time += WAIT_DEFAULT_TIMEOUT_S;
+ } else {
+ expire_time += (timeout_ms + 999) / 1000;
+ }
+
scheduler = pe_new_working_set();
if (scheduler == NULL) {
return ENOMEM;
@@ -1943,11 +1953,11 @@ get_action(const char *rsc_action) {
* \param[in] verbosity Verbosity level
*/
static void
-set_agent_environment(GHashTable *params, int timeout_ms, int check_level,
+set_agent_environment(GHashTable *params, guint timeout_ms, int check_level,
int verbosity)
{
g_hash_table_insert(params, strdup("CRM_meta_timeout"),
- crm_strdup_printf("%d", timeout_ms));
+ crm_strdup_printf("%u", timeout_ms));
g_hash_table_insert(params, strdup(XML_ATTR_CRM_VERSION),
strdup(CRM_FEATURE_SET));
@@ -1999,8 +2009,8 @@ cli_resource_execute_from_params(pcmk__o
const char *rsc_class, const char *rsc_prov,
const char *rsc_type, const char *rsc_action,
GHashTable *params, GHashTable *override_hash,
- int timeout_ms, int resource_verbose, gboolean force,
- int check_level)
+ guint timeout_ms, int resource_verbose,
+ gboolean force, int check_level)
{
const char *class = rsc_class;
const char *action = get_action(rsc_action);
@@ -2008,7 +2018,7 @@ cli_resource_execute_from_params(pcmk__o
svc_action_t *op = NULL;
// If no timeout was provided, use the same default as the cluster
- if (timeout_ms == 0) {
+ if (timeout_ms == 0U) {
timeout_ms = PCMK_DEFAULT_ACTION_TIMEOUT_MS;
}
@@ -2017,7 +2027,8 @@ cli_resource_execute_from_params(pcmk__o
op = services__create_resource_action(rsc_name? rsc_name : "test",
rsc_class, rsc_prov, rsc_type, action,
- 0, timeout_ms, params, 0);
+ 0, QB_MIN(timeout_ms, INT_MAX),
+ params, 0);
if (op == NULL) {
out->err(out, "Could not execute %s using %s%s%s:%s: %s",
action, rsc_class, (rsc_prov? ":" : ""),
@@ -2060,10 +2071,33 @@ done:
return exit_code;
}
+/*!
+ * \internal
+ * \brief Get the timeout the cluster would use for an action
+ *
+ * \param[in] rsc Resource that action is for
+ * \param[in] action Name of action
+ */
+static guint
+get_action_timeout(pcmk_resource_t *rsc, const char *action)
+{
+ long long timeout_ms = -1LL;
+ xmlNode *op = pcmk__find_action_config(rsc, action, 0, true);
+ GHashTable *meta = pcmk__unpack_action_meta(rsc, NULL, action, 0, op);
+
+ if ((pcmk__scan_ll(g_hash_table_lookup(meta, XML_ATTR_TIMEOUT),
+ &timeout_ms, -1LL) != pcmk_rc_ok)
+ || (timeout_ms <= 0LL)) {
+ timeout_ms = PCMK_DEFAULT_ACTION_TIMEOUT_MS;
+ }
+ g_hash_table_destroy(meta);
+ return (guint) QB_MIN(timeout_ms, UINT_MAX);
+}
+
crm_exit_t
cli_resource_execute(pcmk_resource_t *rsc, const char *requested_name,
const char *rsc_action, GHashTable *override_hash,
- int timeout_ms, cib_t *cib, pcmk_scheduler_t *scheduler,
+ guint timeout_ms, cib_t *cib, pcmk_scheduler_t *scheduler,
int resource_verbose, gboolean force, int check_level)
{
pcmk__output_t *out = scheduler->priv;
@@ -2110,9 +2144,8 @@ cli_resource_execute(pcmk_resource_t *rs
params = generate_resource_params(rsc, NULL /* @TODO use local node */,
scheduler);
- if (timeout_ms == 0) {
- timeout_ms = pe_get_configured_timeout(rsc, get_action(rsc_action),
- scheduler);
+ if (timeout_ms == 0U) {
+ timeout_ms = get_action_timeout(rsc, get_action(rsc_action));
}
rid = pe_rsc_is_anon_clone(rsc->parent)? requested_name : rsc->id;