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;
openSUSE Build Service is sponsored by