c563b9
From df587aaec07b4a08364d4024b3d0c73e6dede562 Mon Sep 17 00:00:00 2001
c563b9
From: Ken Gaillot <kgaillot@redhat.com>
c563b9
Date: Mon, 9 Nov 2020 14:55:42 -0600
c563b9
Subject: [PATCH 1/9] Refactor: scheduler: simplify XML attribute filtering
c563b9
 function
c563b9
c563b9
---
c563b9
 lib/pengine/pe_digest.c | 52 ++++++++++++++++++++++++++-----------------------
c563b9
 1 file changed, 28 insertions(+), 24 deletions(-)
c563b9
c563b9
diff --git a/lib/pengine/pe_digest.c b/lib/pengine/pe_digest.c
c563b9
index 5bcd22b..1e119f9 100644
c563b9
--- a/lib/pengine/pe_digest.c
c563b9
+++ b/lib/pengine/pe_digest.c
c563b9
@@ -45,30 +45,38 @@ pe__free_digests(gpointer ptr)
c563b9
     }
c563b9
 }
c563b9
 
c563b9
+/*!
c563b9
+ * \internal
c563b9
+ * \brief Remove named attributes from an XML element
c563b9
+ *
c563b9
+ * \param[in,out] param_set     XML to be filtered
c563b9
+ * \param[in]     param_string  Space-separated list of attribute names
c563b9
+ * \param[in]     need_present  Whether to remove attributes that match,
c563b9
+ *                              or those that don't match
c563b9
+ */
c563b9
 static void
c563b9
-filter_parameters(xmlNode * param_set, const char *param_string, bool need_present)
c563b9
+filter_parameters(xmlNode *param_set, const char *param_string,
c563b9
+                  bool need_present)
c563b9
 {
c563b9
-    if (param_set && param_string) {
c563b9
-        xmlAttrPtr xIter = param_set->properties;
c563b9
-
c563b9
-        while (xIter) {
c563b9
-            const char *prop_name = (const char *)xIter->name;
c563b9
-            char *name = crm_strdup_printf(" %s ", prop_name);
c563b9
-            char *match = strstr(param_string, name);
c563b9
+    if ((param_set == NULL) || (param_string == NULL)) {
c563b9
+        return;
c563b9
+    }
c563b9
+    for (xmlAttrPtr xIter = param_set->properties; xIter; ) {
c563b9
+        const char *prop_name = (const char *) xIter->name;
c563b9
+        char *name = crm_strdup_printf(" %s ", prop_name);
c563b9
+        char *match = strstr(param_string, name);
c563b9
 
c563b9
-            free(name);
c563b9
+        free(name);
c563b9
 
c563b9
-            //  Do now, because current entry might get removed below
c563b9
-            xIter = xIter->next;
c563b9
+        //  Do now, because current entry might get removed below
c563b9
+        xIter = xIter->next;
c563b9
 
c563b9
-            if (need_present && match == NULL) {
c563b9
-                crm_trace("%s not found in %s", prop_name, param_string);
c563b9
-                xml_remove_prop(param_set, prop_name);
c563b9
+        if ((need_present && (match == NULL))
c563b9
+            || (!need_present && (match != NULL))) {
c563b9
 
c563b9
-            } else if (need_present == FALSE && match) {
c563b9
-                crm_trace("%s found in %s", prop_name, param_string);
c563b9
-                xml_remove_prop(param_set, prop_name);
c563b9
-            }
c563b9
+            crm_trace("Filtering %s (%sfound in '%s')",
c563b9
+                      prop_name, (need_present? "not " : ""), param_string);
c563b9
+            xml_remove_prop(param_set, prop_name);
c563b9
         }
c563b9
     }
c563b9
 }
c563b9
@@ -203,9 +211,7 @@ calculate_secure_digest(op_digest_cache_t *data, pe_resource_t *rsc,
c563b9
         g_hash_table_foreach(overrides, hash2field, data->params_secure);
c563b9
     }
c563b9
     g_hash_table_foreach(rsc->parameters, hash2field, data->params_secure);
c563b9
-    if (secure_list != NULL) {
c563b9
-        filter_parameters(data->params_secure, secure_list, FALSE);
c563b9
-    }
c563b9
+    filter_parameters(data->params_secure, secure_list, FALSE);
c563b9
     if (pcmk_is_set(pcmk_get_ra_caps(class),
c563b9
                     pcmk_ra_cap_fence_params)) {
c563b9
         /* For stonith resources, Pacemaker adds special parameters,
c563b9
@@ -259,9 +265,7 @@ calculate_restart_digest(op_digest_cache_t *data, xmlNode *xml_op,
c563b9
 
c563b9
     // Then filter out reloadable parameters, if any
c563b9
     value = crm_element_value(xml_op, XML_LRM_ATTR_OP_RESTART);
c563b9
-    if (value != NULL) {
c563b9
-        filter_parameters(data->params_restart, value, TRUE);
c563b9
-    }
c563b9
+    filter_parameters(data->params_restart, value, TRUE);
c563b9
 
c563b9
     value = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
c563b9
     data->digest_restart_calc = calculate_operation_digest(data->params_restart,
c563b9
-- 
c563b9
1.8.3.1
c563b9
c563b9
c563b9
From f030af8771601d46947ac9276538c46c6c296504 Mon Sep 17 00:00:00 2001
c563b9
From: Ken Gaillot <kgaillot@redhat.com>
c563b9
Date: Mon, 9 Nov 2020 18:37:37 -0600
c563b9
Subject: [PATCH 2/9] Refactor: scheduler: remember whether action is probe
c563b9
 when unpacking
c563b9
c563b9
... to reduce code duplication and improve readability
c563b9
---
c563b9
 lib/pengine/utils.c | 8 ++++----
c563b9
 1 file changed, 4 insertions(+), 4 deletions(-)
c563b9
c563b9
diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c
c563b9
index 04110be..b0922fa 100644
c563b9
--- a/lib/pengine/utils.c
c563b9
+++ b/lib/pengine/utils.c
c563b9
@@ -995,6 +995,8 @@ unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * contai
c563b9
 {
c563b9
     int timeout_ms = 0;
c563b9
     const char *value = NULL;
c563b9
+    bool is_probe = pcmk__str_eq(action->task, RSC_STATUS, pcmk__str_casei)
c563b9
+                    && (interval_ms == 0);
c563b9
 #if ENABLE_VERSIONED_ATTRS
c563b9
     pe_rsc_action_details_t *rsc_details = NULL;
c563b9
 #endif
c563b9
@@ -1026,8 +1028,7 @@ unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * contai
c563b9
                                action->meta, NULL, FALSE, data_set);
c563b9
 
c563b9
     // Determine probe default timeout differently
c563b9
-    if (pcmk__str_eq(action->task, RSC_STATUS, pcmk__str_casei)
c563b9
-            && (interval_ms == 0)) {
c563b9
+    if (is_probe) {
c563b9
         xmlNode *min_interval_mon = find_min_interval_mon(action->rsc, FALSE);
c563b9
 
c563b9
         if (min_interval_mon) {
c563b9
@@ -1099,8 +1100,7 @@ unpack_operation(pe_action_t * action, xmlNode * xml_obj, pe_resource_t * contai
c563b9
     if (pcmk_is_set(pcmk_get_ra_caps(rsc_rule_data.standard),
c563b9
                     pcmk_ra_cap_fence_params)
c563b9
             && (pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)
c563b9
-                    || (pcmk__str_eq(action->task, RSC_STATUS, pcmk__str_casei)
c563b9
-                            && (interval_ms == 0)))
c563b9
+                || is_probe)
c563b9
             && action->rsc->parameters) {
c563b9
 
c563b9
         value = g_hash_table_lookup(action->rsc->parameters,
c563b9
-- 
c563b9
1.8.3.1
c563b9
c563b9
c563b9
From 9de547849697cd6a3581db3f83b04f68d0405d9d Mon Sep 17 00:00:00 2001
c563b9
From: Ken Gaillot <kgaillot@redhat.com>
c563b9
Date: Tue, 10 Nov 2020 15:15:01 -0600
c563b9
Subject: [PATCH 3/9] Refactor: scheduler: don't include originally unpacked
c563b9
 resource parameters in digest
c563b9
c563b9
Previously, when calculating an operation digest, calculate_main_digest() would
c563b9
grab the following, in order of highest to lowest precedence:
c563b9
c563b9
* instance attributes evaluated for the appropriate node
c563b9
* instance attributes specified with the operation
c563b9
* instance attributes as originally unpacked (without evaluating for any node)
c563b9
* resource meta-attributes
c563b9
c563b9
Adding the originally unpacked instance attributes was redundant, since
c563b9
node-evaluated instance attributes would always be a superset of those and
c563b9
would take precedence.
c563b9
---
c563b9
 lib/pengine/pe_digest.c | 1 -
c563b9
 1 file changed, 1 deletion(-)
c563b9
c563b9
diff --git a/lib/pengine/pe_digest.c b/lib/pengine/pe_digest.c
c563b9
index 1e119f9..dd6b753 100644
c563b9
--- a/lib/pengine/pe_digest.c
c563b9
+++ b/lib/pengine/pe_digest.c
c563b9
@@ -162,7 +162,6 @@ calculate_main_digest(op_digest_cache_t *data, pe_resource_t *rsc,
c563b9
     }
c563b9
     g_hash_table_foreach(local_rsc_params, hash2field, data->params_all);
c563b9
     g_hash_table_foreach(action->extra, hash2field, data->params_all);
c563b9
-    g_hash_table_foreach(rsc->parameters, hash2field, data->params_all);
c563b9
     g_hash_table_foreach(action->meta, hash2metafield, data->params_all);
c563b9
 
c563b9
 #if ENABLE_VERSIONED_ATTRS
c563b9
-- 
c563b9
1.8.3.1
c563b9
c563b9
c563b9
From e9921b2ab3e9eeab6227d97cc12b85fa04dfd187 Mon Sep 17 00:00:00 2001
c563b9
From: Ken Gaillot <kgaillot@redhat.com>
c563b9
Date: Fri, 13 Nov 2020 09:27:12 -0600
c563b9
Subject: [PATCH 4/9] Refactor: scheduler: reuse existing function to check for
c563b9
 remote in XML
c563b9
c563b9
... to reduce code duplication and improve readability
c563b9
---
c563b9
 lib/pengine/bundle.c | 21 +++------------------
c563b9
 1 file changed, 3 insertions(+), 18 deletions(-)
c563b9
c563b9
diff --git a/lib/pengine/bundle.c b/lib/pengine/bundle.c
c563b9
index 76730c7..4f6eac3 100644
c563b9
--- a/lib/pengine/bundle.c
c563b9
+++ b/lib/pengine/bundle.c
c563b9
@@ -959,28 +959,13 @@ pe__bundle_needs_remote_name(pe_resource_t *rsc)
c563b9
     const char *value;
c563b9
 
c563b9
     if (rsc == NULL) {
c563b9
-        return FALSE;
c563b9
+        return false;
c563b9
     }
c563b9
 
c563b9
     value = g_hash_table_lookup(rsc->parameters, XML_RSC_ATTR_REMOTE_RA_ADDR);
c563b9
-    if (!pcmk__str_eq(value, "#uname", pcmk__str_casei)) {
c563b9
-        return FALSE;
c563b9
 
c563b9
-    } else {
c563b9
-        const char *match[3][2] = {
c563b9
-            { XML_ATTR_TYPE,           "remote"                },
c563b9
-            { XML_AGENT_ATTR_CLASS,    PCMK_RESOURCE_CLASS_OCF },
c563b9
-            { XML_AGENT_ATTR_PROVIDER, "pacemaker"             },
c563b9
-        };
c563b9
-
c563b9
-        for (int m = 0; m < 3; m++) {
c563b9
-            value = crm_element_value(rsc->xml, match[m][0]);
c563b9
-            if (!pcmk__str_eq(value, match[m][1], pcmk__str_casei)) {
c563b9
-                return FALSE;
c563b9
-            }
c563b9
-        }
c563b9
-    }
c563b9
-    return TRUE;
c563b9
+    return pcmk__str_eq(value, "#uname", pcmk__str_casei)
c563b9
+           && xml_contains_remote_node(rsc->xml);
c563b9
 }
c563b9
 
c563b9
 const char *
c563b9
-- 
c563b9
1.8.3.1
c563b9
c563b9
c563b9
From 0f220e1cd25ec095492ac4b346452520f4b71cf1 Mon Sep 17 00:00:00 2001
c563b9
From: Ken Gaillot <kgaillot@redhat.com>
c563b9
Date: Wed, 11 Nov 2020 15:29:46 -0600
c563b9
Subject: [PATCH 5/9] Refactor: scheduler: remove dead code
c563b9
c563b9
Several internal expression-testing functions were unused. While they might
c563b9
have had some potential future value, the abundance of similarly named
c563b9
functions made debugging difficult. Comment blocks were added to the functions
c563b9
they wrapped, which should add similar value.
c563b9
c563b9
Also, we had an internal wrapper for pe__eval_date_expr() that was used
c563b9
only in crm_rule, so it was moved there.
c563b9
---
c563b9
 include/crm/pengine/rules_internal.h |  10 +--
c563b9
 lib/pengine/rules.c                  | 130 +++++++++++------------------------
c563b9
 tools/crm_rule.c                     |  27 +++++++-
c563b9
 3 files changed, 66 insertions(+), 101 deletions(-)
c563b9
c563b9
diff --git a/include/crm/pengine/rules_internal.h b/include/crm/pengine/rules_internal.h
c563b9
index f60263a..7380826 100644
c563b9
--- a/include/crm/pengine/rules_internal.h
c563b9
+++ b/include/crm/pengine/rules_internal.h
c563b9
@@ -1,5 +1,5 @@
c563b9
 /*
c563b9
- * Copyright 2015-2019 the Pacemaker project contributors
c563b9
+ * Copyright 2015-2020 the Pacemaker project contributors
c563b9
  *
c563b9
  * The version control history for this file may have further details.
c563b9
  *
c563b9
@@ -28,14 +28,6 @@ gboolean pe__eval_op_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data);
c563b9
 gboolean pe__eval_role_expr(xmlNode *expr, pe_rule_eval_data_t *rule_data);
c563b9
 gboolean pe__eval_rsc_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data);
c563b9
 
c563b9
-int pe_eval_date_expression(xmlNode *time_expr,
c563b9
-                            crm_time_t *now,
c563b9
-                            crm_time_t *next_change);
c563b9
-gboolean pe_test_date_expression(xmlNode *time_expr, crm_time_t *now,
c563b9
-                                 crm_time_t *next_change);
c563b9
 int pe_cron_range_satisfied(crm_time_t * now, xmlNode * cron_spec);
c563b9
-gboolean pe_test_attr_expression(xmlNode *expr, GHashTable *hash, crm_time_t *now,
c563b9
-                                 pe_match_data_t *match_data);
c563b9
-gboolean pe_test_role_expression(xmlNode * expr, enum rsc_role_e role, crm_time_t * now);
c563b9
 
c563b9
 #endif
c563b9
diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c
c563b9
index 28562aa..be30e67 100644
c563b9
--- a/lib/pengine/rules.c
c563b9
+++ b/lib/pengine/rules.c
c563b9
@@ -140,37 +140,6 @@ find_expression_type(xmlNode * expr)
c563b9
     return attr_expr;
c563b9
 }
c563b9
 
c563b9
-gboolean
c563b9
-pe_test_role_expression(xmlNode *expr, enum rsc_role_e role, crm_time_t *now)
c563b9
-{
c563b9
-    pe_rule_eval_data_t rule_data = {
c563b9
-        .node_hash = NULL,
c563b9
-        .role = role,
c563b9
-        .now = now,
c563b9
-        .match_data = NULL,
c563b9
-        .rsc_data = NULL,
c563b9
-        .op_data = NULL
c563b9
-    };
c563b9
-
c563b9
-    return pe__eval_role_expr(expr, &rule_data);
c563b9
-}
c563b9
-
c563b9
-gboolean
c563b9
-pe_test_attr_expression(xmlNode *expr, GHashTable *hash, crm_time_t *now,
c563b9
-                        pe_match_data_t *match_data)
c563b9
-{
c563b9
-    pe_rule_eval_data_t rule_data = {
c563b9
-        .node_hash = hash,
c563b9
-        .role = RSC_ROLE_UNKNOWN,
c563b9
-        .now = now,
c563b9
-        .match_data = match_data,
c563b9
-        .rsc_data = NULL,
c563b9
-        .op_data = NULL
c563b9
-    };
c563b9
-
c563b9
-    return pe__eval_attr_expr(expr, &rule_data);
c563b9
-}
c563b9
-
c563b9
 /* As per the nethack rules:
c563b9
  *
c563b9
  * moon period = 29.53058 days ~= 30, year = 365.2422 days
c563b9
@@ -331,38 +300,6 @@ pe_parse_xml_duration(crm_time_t * start, xmlNode * duration_spec)
c563b9
     return end;
c563b9
 }
c563b9
 
c563b9
-/*!
c563b9
- * \internal
c563b9
- * \brief Test a date expression (pass/fail) for a specific time
c563b9
- *
c563b9
- * \param[in]  time_expr    date_expression XML
c563b9
- * \param[in]  now          Time for which to evaluate expression
c563b9
- * \param[out] next_change  If not NULL, set to when evaluation will change
c563b9
- *
c563b9
- * \return TRUE if date expression is in effect at given time, FALSE otherwise
c563b9
- */
c563b9
-gboolean
c563b9
-pe_test_date_expression(xmlNode *expr, crm_time_t *now, crm_time_t *next_change)
c563b9
-{
c563b9
-    pe_rule_eval_data_t rule_data = {
c563b9
-        .node_hash = NULL,
c563b9
-        .role = RSC_ROLE_UNKNOWN,
c563b9
-        .now = now,
c563b9
-        .match_data = NULL,
c563b9
-        .rsc_data = NULL,
c563b9
-        .op_data = NULL
c563b9
-    };
c563b9
-
c563b9
-    switch (pe__eval_date_expr(expr, &rule_data, next_change)) {
c563b9
-        case pcmk_rc_within_range:
c563b9
-        case pcmk_rc_ok:
c563b9
-            return TRUE;
c563b9
-
c563b9
-        default:
c563b9
-            return FALSE;
c563b9
-    }
c563b9
-}
c563b9
-
c563b9
 // Set next_change to t if t is earlier
c563b9
 static void
c563b9
 crm_time_set_if_earlier(crm_time_t *next_change, crm_time_t *t)
c563b9
@@ -375,31 +312,6 @@ crm_time_set_if_earlier(crm_time_t *next_change, crm_time_t *t)
c563b9
     }
c563b9
 }
c563b9
 
c563b9
-/*!
c563b9
- * \internal
c563b9
- * \brief Evaluate a date expression for a specific time
c563b9
- *
c563b9
- * \param[in]  time_expr    date_expression XML
c563b9
- * \param[in]  now          Time for which to evaluate expression
c563b9
- * \param[out] next_change  If not NULL, set to when evaluation will change
c563b9
- *
c563b9
- * \return Standard Pacemaker return code
c563b9
- */
c563b9
-int
c563b9
-pe_eval_date_expression(xmlNode *expr, crm_time_t *now, crm_time_t *next_change)
c563b9
-{
c563b9
-    pe_rule_eval_data_t rule_data = {
c563b9
-        .node_hash = NULL,
c563b9
-        .role = RSC_ROLE_UNKNOWN,
c563b9
-        .now = now,
c563b9
-        .match_data = NULL,
c563b9
-        .rsc_data = NULL,
c563b9
-        .op_data = NULL
c563b9
-    };
c563b9
-
c563b9
-    return pe__eval_date_expr(expr, &rule_data, next_change);
c563b9
-}
c563b9
-
c563b9
 // Information about a block of nvpair elements
c563b9
 typedef struct sorted_set_s {
c563b9
     int score;                  // This block's score for sorting
c563b9
@@ -908,7 +820,16 @@ pe_eval_subexpr(xmlNode *expr, pe_rule_eval_data_t *rule_data, crm_time_t *next_
c563b9
             break;
c563b9
 
c563b9
         case time_expr:
c563b9
-            accept = pe_test_date_expression(expr, rule_data->now, next_change);
c563b9
+            switch (pe__eval_date_expr(expr, rule_data, next_change)) {
c563b9
+                case pcmk_rc_within_range:
c563b9
+                case pcmk_rc_ok:
c563b9
+                    accept = TRUE;
c563b9
+                    break;
c563b9
+
c563b9
+                default:
c563b9
+                    accept = FALSE;
c563b9
+                    break;
c563b9
+            }
c563b9
             break;
c563b9
 
c563b9
         case role_expr:
c563b9
@@ -1104,6 +1025,16 @@ accept_attr_expr(const char *l_val, const char *r_val, const char *type,
c563b9
     return false;   // Should never reach this point
c563b9
 }
c563b9
 
c563b9
+/*!
c563b9
+ * \internal
c563b9
+ * \brief Evaluate a node attribute expression based on #uname, #id, #kind,
c563b9
+ *        or a generic node attribute
c563b9
+ *
c563b9
+ * \param[in] expr       XML of rule expression
c563b9
+ * \param[in] rule_data  The match_data and node_hash members are used
c563b9
+ *
c563b9
+ * \return TRUE if rule_data satisfies the expression, FALSE otherwise
c563b9
+ */
c563b9
 gboolean
c563b9
 pe__eval_attr_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
c563b9
 {
c563b9
@@ -1169,8 +1100,16 @@ pe__eval_attr_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
c563b9
     return accept_attr_expr(h_val, value, type, op);
c563b9
 }
c563b9
 
c563b9
-
c563b9
-
c563b9
+/*!
c563b9
+ * \internal
c563b9
+ * \brief Evaluate a date_expression
c563b9
+ *
c563b9
+ * \param[in]  expr         XML of rule expression
c563b9
+ * \param[in]  rule_data    Only the now member is used
c563b9
+ * \param[out] next_change  If not NULL, set to when evaluation will change
c563b9
+ *
c563b9
+ * \return Standard Pacemaker return code
c563b9
+ */
c563b9
 int
c563b9
 pe__eval_date_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data, crm_time_t *next_change)
c563b9
 {
c563b9
@@ -1285,6 +1224,15 @@ pe__eval_op_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data) {
c563b9
     return TRUE;
c563b9
 }
c563b9
 
c563b9
+/*!
c563b9
+ * \internal
c563b9
+ * \brief Evaluate a node attribute expression based on #role
c563b9
+ *
c563b9
+ * \param[in] expr       XML of rule expression
c563b9
+ * \param[in] rule_data  Only the role member is used
c563b9
+ *
c563b9
+ * \return TRUE if rule_data->role satisfies the expression, FALSE otherwise
c563b9
+ */
c563b9
 gboolean
c563b9
 pe__eval_role_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
c563b9
 {
c563b9
diff --git a/tools/crm_rule.c b/tools/crm_rule.c
c563b9
index 0e44828..2871f3d 100644
c563b9
--- a/tools/crm_rule.c
c563b9
+++ b/tools/crm_rule.c
c563b9
@@ -75,6 +75,31 @@ mode_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **e
c563b9
     return TRUE;
c563b9
 }
c563b9
 
c563b9
+/*!
c563b9
+ * \internal
c563b9
+ * \brief Evaluate a date expression for a specific time
c563b9
+ *
c563b9
+ * \param[in]  time_expr    date_expression XML
c563b9
+ * \param[in]  now          Time for which to evaluate expression
c563b9
+ * \param[out] next_change  If not NULL, set to when evaluation will change
c563b9
+ *
c563b9
+ * \return Standard Pacemaker return code
c563b9
+ */
c563b9
+static int
c563b9
+eval_date_expression(xmlNode *expr, crm_time_t *now, crm_time_t *next_change)
c563b9
+{
c563b9
+    pe_rule_eval_data_t rule_data = {
c563b9
+        .node_hash = NULL,
c563b9
+        .role = RSC_ROLE_UNKNOWN,
c563b9
+        .now = now,
c563b9
+        .match_data = NULL,
c563b9
+        .rsc_data = NULL,
c563b9
+        .op_data = NULL
c563b9
+    };
c563b9
+
c563b9
+    return pe__eval_date_expr(expr, &rule_data, next_change);
c563b9
+}
c563b9
+
c563b9
 static int
c563b9
 crm_rule_check(pe_working_set_t *data_set, const char *rule_id, crm_time_t *effective_date)
c563b9
 {
c563b9
@@ -156,7 +181,7 @@ crm_rule_check(pe_working_set_t *data_set, const char *rule_id, crm_time_t *effe
c563b9
     CRM_ASSERT(match != NULL);
c563b9
     CRM_ASSERT(find_expression_type(match) == time_expr);
c563b9
 
c563b9
-    rc = pe_eval_date_expression(match, effective_date, NULL);
c563b9
+    rc = eval_date_expression(match, effective_date, NULL);
c563b9
 
c563b9
     if (rc == pcmk_rc_within_range) {
c563b9
         printf("Rule %s is still in effect\n", rule_id);
c563b9
-- 
c563b9
1.8.3.1
c563b9
c563b9
c563b9
From 91a6ec4bec86de7389fcd64cb27e315da760f0dd Mon Sep 17 00:00:00 2001
c563b9
From: Ken Gaillot <kgaillot@redhat.com>
c563b9
Date: Wed, 11 Nov 2020 16:44:57 -0600
c563b9
Subject: [PATCH 6/9] Refactor: scheduler: make constraint unpacking function
c563b9
 static
c563b9
c563b9
... for linker efficiency and readability. Also change the return type to void
c563b9
since it was ignored (and the same for some related functions).
c563b9
---
c563b9
 include/pcmki/pcmki_sched_allocate.h   |  4 +--
c563b9
 lib/pacemaker/pcmk_sched_constraints.c | 46 ++++++++++++++++------------------
c563b9
 2 files changed, 23 insertions(+), 27 deletions(-)
c563b9
c563b9
diff --git a/include/pcmki/pcmki_sched_allocate.h b/include/pcmki/pcmki_sched_allocate.h
c563b9
index efc0da6..a7f8c11 100644
c563b9
--- a/include/pcmki/pcmki_sched_allocate.h
c563b9
+++ b/include/pcmki/pcmki_sched_allocate.h
c563b9
@@ -1,5 +1,5 @@
c563b9
 /*
c563b9
- * Copyright 2004-2019 the Pacemaker project contributors
c563b9
+ * Copyright 2004-2020 the Pacemaker project contributors
c563b9
  *
c563b9
  * The version control history for this file may have further details.
c563b9
  *
c563b9
@@ -143,8 +143,6 @@ extern gboolean unpack_rsc_order(xmlNode * xml_obj, pe_working_set_t * data_set)
c563b9
 
c563b9
 extern gboolean unpack_rsc_colocation(xmlNode * xml_obj, pe_working_set_t * data_set);
c563b9
 
c563b9
-extern gboolean unpack_location(xmlNode * xml_obj, pe_working_set_t * data_set);
c563b9
-
c563b9
 extern gboolean unpack_rsc_ticket(xmlNode * xml_obj, pe_working_set_t * data_set);
c563b9
 
c563b9
 void LogNodeActions(pe_working_set_t * data_set, gboolean terminal);
c563b9
diff --git a/lib/pacemaker/pcmk_sched_constraints.c b/lib/pacemaker/pcmk_sched_constraints.c
c563b9
index 6ed2d8c..121754d 100644
c563b9
--- a/lib/pacemaker/pcmk_sched_constraints.c
c563b9
+++ b/lib/pacemaker/pcmk_sched_constraints.c
c563b9
@@ -48,6 +48,7 @@ static pe__location_t *generate_location_rule(pe_resource_t *rsc,
c563b9
                                               crm_time_t *next_change,
c563b9
                                               pe_working_set_t *data_set,
c563b9
                                               pe_match_data_t *match_data);
c563b9
+static void unpack_location(xmlNode *xml_obj, pe_working_set_t *data_set);
c563b9
 
c563b9
 static bool
c563b9
 evaluate_lifetime(xmlNode *lifetime, pe_working_set_t *data_set)
c563b9
@@ -709,11 +710,13 @@ tag_to_set(xmlNode * xml_obj, xmlNode ** rsc_set, const char * attr,
c563b9
     return TRUE;
c563b9
 }
c563b9
 
c563b9
-static gboolean unpack_rsc_location(xmlNode * xml_obj, pe_resource_t * rsc_lh, const char * role,
c563b9
-                             const char * score, pe_working_set_t * data_set, pe_match_data_t * match_data);
c563b9
+static void unpack_rsc_location(xmlNode *xml_obj, pe_resource_t *rsc_lh,
c563b9
+                                const char *role, const char *score,
c563b9
+                                pe_working_set_t *data_set,
c563b9
+                                pe_match_data_t *match_data);
c563b9
 
c563b9
-static gboolean
c563b9
-unpack_simple_location(xmlNode * xml_obj, pe_working_set_t * data_set)
c563b9
+static void
c563b9
+unpack_simple_location(xmlNode *xml_obj, pe_working_set_t *data_set)
c563b9
 {
c563b9
     const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
c563b9
     const char *value = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
c563b9
@@ -721,7 +724,7 @@ unpack_simple_location(xmlNode * xml_obj, pe_working_set_t * data_set)
c563b9
     if(value) {
c563b9
         pe_resource_t *rsc_lh = pe_find_constraint_resource(data_set->resources, value);
c563b9
 
c563b9
-        return unpack_rsc_location(xml_obj, rsc_lh, NULL, NULL, data_set, NULL);
c563b9
+        unpack_rsc_location(xml_obj, rsc_lh, NULL, NULL, data_set, NULL);
c563b9
     }
c563b9
 
c563b9
     value = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE_PATTERN);
c563b9
@@ -741,7 +744,7 @@ unpack_simple_location(xmlNode * xml_obj, pe_working_set_t * data_set)
c563b9
                              " has invalid value '%s'", id, value);
c563b9
             regfree(r_patt);
c563b9
             free(r_patt);
c563b9
-            return FALSE;
c563b9
+            return;
c563b9
         }
c563b9
 
c563b9
         for (rIter = data_set->resources; rIter; rIter = rIter->next) {
c563b9
@@ -787,13 +790,12 @@ unpack_simple_location(xmlNode * xml_obj, pe_working_set_t * data_set)
c563b9
         regfree(r_patt);
c563b9
         free(r_patt);
c563b9
     }
c563b9
-
c563b9
-    return FALSE;
c563b9
 }
c563b9
 
c563b9
-static gboolean
c563b9
-unpack_rsc_location(xmlNode * xml_obj, pe_resource_t * rsc_lh, const char * role,
c563b9
-                    const char * score, pe_working_set_t * data_set, pe_match_data_t * match_data)
c563b9
+static void
c563b9
+unpack_rsc_location(xmlNode *xml_obj, pe_resource_t *rsc_lh, const char *role,
c563b9
+                    const char *score, pe_working_set_t *data_set,
c563b9
+                    pe_match_data_t *match_data)
c563b9
 {
c563b9
     pe__location_t *location = NULL;
c563b9
     const char *id_lh = crm_element_value(xml_obj, XML_LOC_ATTR_SOURCE);
c563b9
@@ -804,7 +806,7 @@ unpack_rsc_location(xmlNode * xml_obj, pe_resource_t * rsc_lh, const char * role
c563b9
     if (rsc_lh == NULL) {
c563b9
         pcmk__config_warn("Ignoring constraint '%s' because resource '%s' "
c563b9
                           "does not exist", id, id_lh);
c563b9
-        return FALSE;
c563b9
+        return;
c563b9
     }
c563b9
 
c563b9
     if (score == NULL) {
c563b9
@@ -816,7 +818,7 @@ unpack_rsc_location(xmlNode * xml_obj, pe_resource_t * rsc_lh, const char * role
c563b9
         pe_node_t *match = pe_find_node(data_set->nodes, node);
c563b9
 
c563b9
         if (!match) {
c563b9
-            return FALSE;
c563b9
+            return;
c563b9
         }
c563b9
         location = rsc2node_new(id, rsc_lh, score_i, discovery, match, data_set);
c563b9
 
c563b9
@@ -850,7 +852,7 @@ unpack_rsc_location(xmlNode * xml_obj, pe_resource_t * rsc_lh, const char * role
c563b9
             pe__update_recheck_time(t, data_set);
c563b9
         }
c563b9
         crm_time_free(next_change);
c563b9
-        return TRUE;
c563b9
+        return;
c563b9
     }
c563b9
 
c563b9
     if (role == NULL) {
c563b9
@@ -860,7 +862,7 @@ unpack_rsc_location(xmlNode * xml_obj, pe_resource_t * rsc_lh, const char * role
c563b9
     if (location && role) {
c563b9
         if (text2role(role) == RSC_ROLE_UNKNOWN) {
c563b9
             pe_err("Invalid constraint %s: Bad role %s", id, role);
c563b9
-            return FALSE;
c563b9
+            return;
c563b9
 
c563b9
         } else {
c563b9
             enum rsc_role_e r = text2role(role);
c563b9
@@ -877,8 +879,6 @@ unpack_rsc_location(xmlNode * xml_obj, pe_resource_t * rsc_lh, const char * role
c563b9
             }
c563b9
         }
c563b9
     }
c563b9
-
c563b9
-    return TRUE;
c563b9
 }
c563b9
 
c563b9
 static gboolean
c563b9
@@ -992,8 +992,8 @@ unpack_location_set(xmlNode * location, xmlNode * set, pe_working_set_t * data_s
c563b9
     return TRUE;
c563b9
 }
c563b9
 
c563b9
-gboolean
c563b9
-unpack_location(xmlNode * xml_obj, pe_working_set_t * data_set)
c563b9
+static void
c563b9
+unpack_location(xmlNode *xml_obj, pe_working_set_t *data_set)
c563b9
 {
c563b9
     xmlNode *set = NULL;
c563b9
     gboolean any_sets = FALSE;
c563b9
@@ -1002,7 +1002,7 @@ unpack_location(xmlNode * xml_obj, pe_working_set_t * data_set)
c563b9
     xmlNode *expanded_xml = NULL;
c563b9
 
c563b9
     if (unpack_location_tags(xml_obj, &expanded_xml, data_set) == FALSE) {
c563b9
-        return FALSE;
c563b9
+        return;
c563b9
     }
c563b9
 
c563b9
     if (expanded_xml) {
c563b9
@@ -1020,7 +1020,7 @@ unpack_location(xmlNode * xml_obj, pe_working_set_t * data_set)
c563b9
                 if (expanded_xml) {
c563b9
                     free_xml(expanded_xml);
c563b9
                 }
c563b9
-                return FALSE;
c563b9
+                return;
c563b9
             }
c563b9
         }
c563b9
     }
c563b9
@@ -1031,10 +1031,8 @@ unpack_location(xmlNode * xml_obj, pe_working_set_t * data_set)
c563b9
     }
c563b9
 
c563b9
     if (any_sets == FALSE) {
c563b9
-        return unpack_simple_location(xml_obj, data_set);
c563b9
+        unpack_simple_location(xml_obj, data_set);
c563b9
     }
c563b9
-
c563b9
-    return TRUE;
c563b9
 }
c563b9
 
c563b9
 static int
c563b9
-- 
c563b9
1.8.3.1
c563b9
c563b9
c563b9
From df842adafca8ba56ddb5b448490ffef54ea785d4 Mon Sep 17 00:00:00 2001
c563b9
From: Ken Gaillot <kgaillot@redhat.com>
c563b9
Date: Fri, 13 Nov 2020 09:19:51 -0600
c563b9
Subject: [PATCH 7/9] Refactor: scheduler: trivial refactoring of nvpair
c563b9
 evaluation
c563b9
c563b9
... for readability
c563b9
---
c563b9
 lib/pengine/rules.c | 15 +++++++--------
c563b9
 1 file changed, 7 insertions(+), 8 deletions(-)
c563b9
c563b9
diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c
c563b9
index be30e67..86e7899 100644
c563b9
--- a/lib/pengine/rules.c
c563b9
+++ b/lib/pengine/rules.c
c563b9
@@ -529,20 +529,19 @@ static GList *
c563b9
 make_pairs(xmlNode *top, xmlNode *xml_obj, const char *set_name,
c563b9
            const char *always_first)
c563b9
 {
c563b9
-    GListPtr unsorted = NULL;
c563b9
-    const char *score = NULL;
c563b9
-    sorted_set_t *pair = NULL;
c563b9
-    xmlNode *attr_set = NULL;
c563b9
+    GList *unsorted = NULL;
c563b9
 
c563b9
     if (xml_obj == NULL) {
c563b9
         return NULL;
c563b9
     }
c563b9
-    for (attr_set = pcmk__xe_first_child(xml_obj); attr_set != NULL;
c563b9
+    for (xmlNode *attr_set = pcmk__xe_first_child(xml_obj); attr_set != NULL;
c563b9
          attr_set = pcmk__xe_next(attr_set)) {
c563b9
 
c563b9
-        /* Uncertain if set_name == NULL check is strictly necessary here */
c563b9
-        if (pcmk__str_eq(set_name, (const char *)attr_set->name, pcmk__str_null_matches)) {
c563b9
-            pair = NULL;
c563b9
+        if (pcmk__str_eq(set_name, (const char *) attr_set->name,
c563b9
+                         pcmk__str_null_matches)) {
c563b9
+            const char *score = NULL;
c563b9
+            sorted_set_t *pair = NULL;
c563b9
+
c563b9
             attr_set = expand_idref(attr_set, top);
c563b9
             if (attr_set == NULL) {
c563b9
                 continue;
c563b9
-- 
c563b9
1.8.3.1
c563b9
c563b9
c563b9
From 373c224ac1c41bd47a928a7523744c6c678a6543 Mon Sep 17 00:00:00 2001
c563b9
From: Ken Gaillot <kgaillot@redhat.com>
c563b9
Date: Fri, 13 Nov 2020 09:21:35 -0600
c563b9
Subject: [PATCH 8/9] Low: scheduler: correctly skip dangling id-ref
c563b9
c563b9
When evaluating XML nvpair blocks, make_pairs() previously reused the
c563b9
"for" loop variable when expanding id-ref's. However if the id-ref was dangling
c563b9
(only possible if schema enforcement is turned off), this would make it NULL
c563b9
and thus exiting the loop instead of continuing.
c563b9
---
c563b9
 lib/pengine/rules.c | 11 ++++++-----
c563b9
 1 file changed, 6 insertions(+), 5 deletions(-)
c563b9
c563b9
diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c
c563b9
index 86e7899..1bd807f 100644
c563b9
--- a/lib/pengine/rules.c
c563b9
+++ b/lib/pengine/rules.c
c563b9
@@ -541,18 +541,19 @@ make_pairs(xmlNode *top, xmlNode *xml_obj, const char *set_name,
c563b9
                          pcmk__str_null_matches)) {
c563b9
             const char *score = NULL;
c563b9
             sorted_set_t *pair = NULL;
c563b9
+            xmlNode *expanded_attr_set = expand_idref(attr_set, top);
c563b9
 
c563b9
-            attr_set = expand_idref(attr_set, top);
c563b9
-            if (attr_set == NULL) {
c563b9
+            if (expanded_attr_set == NULL) {
c563b9
+                // Schema (if not "none") prevents this
c563b9
                 continue;
c563b9
             }
c563b9
 
c563b9
             pair = calloc(1, sizeof(sorted_set_t));
c563b9
-            pair->name = ID(attr_set);
c563b9
+            pair->name = ID(expanded_attr_set);
c563b9
             pair->special_name = always_first;
c563b9
-            pair->attr_set = attr_set;
c563b9
+            pair->attr_set = expanded_attr_set;
c563b9
 
c563b9
-            score = crm_element_value(attr_set, XML_RULE_ATTR_SCORE);
c563b9
+            score = crm_element_value(expanded_attr_set, XML_RULE_ATTR_SCORE);
c563b9
             pair->score = char2score(score);
c563b9
 
c563b9
             unsorted = g_list_prepend(unsorted, pair);
c563b9
-- 
c563b9
1.8.3.1
c563b9
c563b9
c563b9
From b59717751c168ec745bedbcc5696bee11036d931 Mon Sep 17 00:00:00 2001
c563b9
From: Ken Gaillot <kgaillot@redhat.com>
c563b9
Date: Thu, 12 Nov 2020 14:37:27 -0600
c563b9
Subject: [PATCH 9/9] Low: scheduler: treat missing parameter as NULL in rules
c563b9
 with value-source
c563b9
c563b9
Previously, if value-source were set to "param" or "meta", and an affected
c563b9
resource did not have the specified parameter, the parameter name would wrongly
c563b9
be used as the value to compare against. Now, use NULL as the value to compare
c563b9
against.
c563b9
---
c563b9
 lib/pengine/rules.c | 11 ++++++++---
c563b9
 1 file changed, 8 insertions(+), 3 deletions(-)
c563b9
c563b9
diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c
c563b9
index 1bd807f..e5d452f 100644
c563b9
--- a/lib/pengine/rules.c
c563b9
+++ b/lib/pengine/rules.c
c563b9
@@ -1041,6 +1041,7 @@ pe__eval_attr_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
c563b9
     gboolean attr_allocated = FALSE;
c563b9
     const char *h_val = NULL;
c563b9
     GHashTable *table = NULL;
c563b9
+    bool literal = true;
c563b9
 
c563b9
     const char *op = NULL;
c563b9
     const char *type = NULL;
c563b9
@@ -1071,18 +1072,22 @@ pe__eval_attr_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
c563b9
         }
c563b9
 
c563b9
         if (pcmk__str_eq(value_source, "param", pcmk__str_casei)) {
c563b9
+            literal = false;
c563b9
             table = rule_data->match_data->params;
c563b9
         } else if (pcmk__str_eq(value_source, "meta", pcmk__str_casei)) {
c563b9
+            literal = false;
c563b9
             table = rule_data->match_data->meta;
c563b9
         }
c563b9
     }
c563b9
 
c563b9
-    if (table) {
c563b9
+    if (!literal) {
c563b9
         const char *param_name = value;
c563b9
         const char *param_value = NULL;
c563b9
 
c563b9
-        if (param_name && param_name[0]) {
c563b9
-            if ((param_value = (const char *)g_hash_table_lookup(table, param_name))) {
c563b9
+        value = NULL;
c563b9
+        if ((table != NULL) && !pcmk__str_empty(param_name)) {
c563b9
+            param_value = (const char *)g_hash_table_lookup(table, param_name);
c563b9
+            if (param_value != NULL) {
c563b9
                 value = param_value;
c563b9
             }
c563b9
         }
c563b9
-- 
c563b9
1.8.3.1
c563b9