Blame SOURCES/020-rhbz1872376.patch

23c78e
From 08ce507927ff497b0e8f125050f67d59c74d674c Mon Sep 17 00:00:00 2001
23c78e
From: Ken Gaillot <kgaillot@redhat.com>
23c78e
Date: Thu, 19 Nov 2020 15:52:14 -0600
23c78e
Subject: [PATCH 01/12] Refactor: libpe_rules: functionize value-source
23c78e
 expansion
23c78e
23c78e
... for readability
23c78e
---
23c78e
 lib/pengine/rules.c | 61 +++++++++++++++++++++++++++++++----------------------
23c78e
 1 file changed, 36 insertions(+), 25 deletions(-)
23c78e
23c78e
diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c
23c78e
index e5d452f..aa5d6ab 100644
23c78e
--- a/lib/pengine/rules.c
23c78e
+++ b/lib/pengine/rules.c
23c78e
@@ -1027,6 +1027,36 @@ accept_attr_expr(const char *l_val, const char *r_val, const char *type,
23c78e
 
23c78e
 /*!
23c78e
  * \internal
23c78e
+ * \brief Get correct value according to value-source
23c78e
+ *
23c78e
+ * \param[in] value         value given in rule expression
23c78e
+ * \param[in] value_source  value-source given in rule expressions
23c78e
+ * \param[in] match_data    If not NULL, resource back-references and params
23c78e
+ */
23c78e
+static const char *
23c78e
+expand_value_source(const char *value, const char *value_source,
23c78e
+                    pe_match_data_t *match_data)
23c78e
+{
23c78e
+    GHashTable *table = NULL;
23c78e
+
23c78e
+    if (pcmk__str_eq(value_source, "param", pcmk__str_casei)) {
23c78e
+        table = match_data->params;
23c78e
+
23c78e
+    } else if (pcmk__str_eq(value_source, "meta", pcmk__str_casei)) {
23c78e
+        table = match_data->meta;
23c78e
+
23c78e
+    } else { // literal
23c78e
+        return value;
23c78e
+    }
23c78e
+
23c78e
+    if ((table == NULL) || pcmk__str_empty(value)) {
23c78e
+        return NULL;
23c78e
+    }
23c78e
+    return (const char *) g_hash_table_lookup(table, value);
23c78e
+}
23c78e
+
23c78e
+/*!
23c78e
+ * \internal
23c78e
  * \brief Evaluate a node attribute expression based on #uname, #id, #kind,
23c78e
  *        or a generic node attribute
23c78e
  *
23c78e
@@ -1040,8 +1070,6 @@ pe__eval_attr_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
23c78e
 {
23c78e
     gboolean attr_allocated = FALSE;
23c78e
     const char *h_val = NULL;
23c78e
-    GHashTable *table = NULL;
23c78e
-    bool literal = true;
23c78e
 
23c78e
     const char *op = NULL;
23c78e
     const char *type = NULL;
23c78e
@@ -1061,36 +1089,19 @@ pe__eval_attr_expr(xmlNodePtr expr, pe_rule_eval_data_t *rule_data)
23c78e
         return FALSE;
23c78e
     }
23c78e
 
23c78e
-    if (rule_data->match_data) {
23c78e
-        if (rule_data->match_data->re) {
23c78e
+    if (rule_data->match_data != NULL) {
23c78e
+        // Expand any regular expression submatches (%0-%9) in attribute name
23c78e
+        if (rule_data->match_data->re != NULL) {
23c78e
             char *resolved_attr = pe_expand_re_matches(attr, rule_data->match_data->re);
23c78e
 
23c78e
-            if (resolved_attr) {
23c78e
+            if (resolved_attr != NULL) {
23c78e
                 attr = (const char *) resolved_attr;
23c78e
                 attr_allocated = TRUE;
23c78e
             }
23c78e
         }
23c78e
 
23c78e
-        if (pcmk__str_eq(value_source, "param", pcmk__str_casei)) {
23c78e
-            literal = false;
23c78e
-            table = rule_data->match_data->params;
23c78e
-        } else if (pcmk__str_eq(value_source, "meta", pcmk__str_casei)) {
23c78e
-            literal = false;
23c78e
-            table = rule_data->match_data->meta;
23c78e
-        }
23c78e
-    }
23c78e
-
23c78e
-    if (!literal) {
23c78e
-        const char *param_name = value;
23c78e
-        const char *param_value = NULL;
23c78e
-
23c78e
-        value = NULL;
23c78e
-        if ((table != NULL) && !pcmk__str_empty(param_name)) {
23c78e
-            param_value = (const char *)g_hash_table_lookup(table, param_name);
23c78e
-            if (param_value != NULL) {
23c78e
-                value = param_value;
23c78e
-            }
23c78e
-        }
23c78e
+        // Get value appropriate to value-source
23c78e
+        value = expand_value_source(value, value_source, rule_data->match_data);
23c78e
     }
23c78e
 
23c78e
     if (rule_data->node_hash != NULL) {
23c78e
-- 
23c78e
1.8.3.1
23c78e
23c78e
23c78e
From 8864e8596cc44fa275f68d58fea9b7d3d5236106 Mon Sep 17 00:00:00 2001
23c78e
From: Ken Gaillot <kgaillot@redhat.com>
23c78e
Date: Thu, 19 Nov 2020 11:59:05 -0600
23c78e
Subject: [PATCH 02/12] Refactor: libcrmcommon: expose "first XML attribute"
23c78e
 function
23c78e
23c78e
... for future reuse. Also, rename to reflect that only XML element nodes may
23c78e
have attributes.
23c78e
---
23c78e
 include/crm/common/xml_internal.h | 14 +++++++
23c78e
 lib/common/crmcommon_private.h    |  6 ---
23c78e
 lib/common/nvpair.c               |  4 +-
23c78e
 lib/common/patchset.c             | 20 +++++-----
23c78e
 lib/common/xml.c                  | 81 +++++++++++++++++----------------------
23c78e
 5 files changed, 61 insertions(+), 64 deletions(-)
23c78e
23c78e
diff --git a/include/crm/common/xml_internal.h b/include/crm/common/xml_internal.h
23c78e
index 13157c6..b2ff529 100644
23c78e
--- a/include/crm/common/xml_internal.h
23c78e
+++ b/include/crm/common/xml_internal.h
23c78e
@@ -255,4 +255,18 @@ void
23c78e
 pcmk__xe_set_props(xmlNodePtr node, ...)
23c78e
 G_GNUC_NULL_TERMINATED;
23c78e
 
23c78e
+/*!
23c78e
+ * \internal
23c78e
+ * \brief Get first attribute of an XML element
23c78e
+ *
23c78e
+ * \param[in] xe  XML element to check
23c78e
+ *
23c78e
+ * \return First attribute of \p xe (or NULL if \p xe is NULL or has none)
23c78e
+ */
23c78e
+static inline xmlAttr *
23c78e
+pcmk__xe_first_attr(const xmlNode *xe)
23c78e
+{
23c78e
+    return (xe == NULL)? NULL : xe->properties;
23c78e
+}
23c78e
+
23c78e
 #endif // PCMK__XML_INTERNAL__H
23c78e
diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h
23c78e
index 1654cba..c2f334d 100644
23c78e
--- a/lib/common/crmcommon_private.h
23c78e
+++ b/lib/common/crmcommon_private.h
23c78e
@@ -141,12 +141,6 @@ void pcmk__mark_xml_attr_dirty(xmlAttr *a);
23c78e
 G_GNUC_INTERNAL
23c78e
 bool pcmk__xa_filterable(const char *name);
23c78e
 
23c78e
-static inline xmlAttr *
23c78e
-pcmk__first_xml_attr(const xmlNode *xml)
23c78e
-{
23c78e
-    return xml? xml->properties : NULL;
23c78e
-}
23c78e
-
23c78e
 static inline const char *
23c78e
 pcmk__xml_attr_value(const xmlAttr *attr)
23c78e
 {
23c78e
diff --git a/lib/common/nvpair.c b/lib/common/nvpair.c
23c78e
index 0ed7a7d..9bd87af 100644
23c78e
--- a/lib/common/nvpair.c
23c78e
+++ b/lib/common/nvpair.c
23c78e
@@ -163,7 +163,7 @@ pcmk_xml_attrs2nvpairs(xmlNode *xml)
23c78e
 {
23c78e
     GSList *result = NULL;
23c78e
 
23c78e
-    for (xmlAttrPtr iter = pcmk__first_xml_attr(xml); iter != NULL;
23c78e
+    for (xmlAttrPtr iter = pcmk__xe_first_attr(xml); iter != NULL;
23c78e
          iter = iter->next) {
23c78e
 
23c78e
         result = pcmk_prepend_nvpair(result,
23c78e
@@ -925,7 +925,7 @@ xml2list(xmlNode *parent)
23c78e
 
23c78e
     crm_log_xml_trace(nvpair_list, "Unpacking");
23c78e
 
23c78e
-    for (pIter = pcmk__first_xml_attr(nvpair_list); pIter != NULL;
23c78e
+    for (pIter = pcmk__xe_first_attr(nvpair_list); pIter != NULL;
23c78e
          pIter = pIter->next) {
23c78e
 
23c78e
         const char *p_name = (const char *)pIter->name;
23c78e
diff --git a/lib/common/patchset.c b/lib/common/patchset.c
23c78e
index f3dab03..15cbe07 100644
23c78e
--- a/lib/common/patchset.c
23c78e
+++ b/lib/common/patchset.c
23c78e
@@ -112,7 +112,7 @@ add_xml_changes_to_patchset(xmlNode *xml, xmlNode *patchset)
23c78e
     }
23c78e
 
23c78e
     // Check each of the XML node's attributes for changes
23c78e
-    for (pIter = pcmk__first_xml_attr(xml); pIter != NULL;
23c78e
+    for (pIter = pcmk__xe_first_attr(xml); pIter != NULL;
23c78e
          pIter = pIter->next) {
23c78e
         xmlNode *attr = NULL;
23c78e
 
23c78e
@@ -156,7 +156,7 @@ add_xml_changes_to_patchset(xmlNode *xml, xmlNode *patchset)
23c78e
         change = create_xml_node(change->parent, XML_DIFF_RESULT);
23c78e
         result = create_xml_node(change, (const char *)xml->name);
23c78e
 
23c78e
-        for (pIter = pcmk__first_xml_attr(xml); pIter != NULL;
23c78e
+        for (pIter = pcmk__xe_first_attr(xml); pIter != NULL;
23c78e
              pIter = pIter->next) {
23c78e
             p = pIter->_private;
23c78e
             if (!pcmk_is_set(p->flags, xpf_deleted)) {
23c78e
@@ -677,7 +677,7 @@ process_v1_removals(xmlNode *target, xmlNode *patch)
23c78e
         return;
23c78e
     }
23c78e
 
23c78e
-    for (xIter = pcmk__first_xml_attr(patch); xIter != NULL;
23c78e
+    for (xIter = pcmk__xe_first_attr(patch); xIter != NULL;
23c78e
          xIter = xIter->next) {
23c78e
         const char *p_name = (const char *)xIter->name;
23c78e
 
23c78e
@@ -745,7 +745,7 @@ process_v1_additions(xmlNode *parent, xmlNode *target, xmlNode *patch)
23c78e
               return);
23c78e
     CRM_CHECK(pcmk__str_eq(ID(target), ID(patch), pcmk__str_casei), return);
23c78e
 
23c78e
-    for (xIter = pcmk__first_xml_attr(patch); xIter != NULL;
23c78e
+    for (xIter = pcmk__xe_first_attr(patch); xIter != NULL;
23c78e
          xIter = xIter->next) {
23c78e
         const char *p_name = (const char *) xIter->name;
23c78e
         const char *p_value = crm_element_value(patch, p_name);
23c78e
@@ -1204,7 +1204,7 @@ apply_v2_patchset(xmlNode *xml, xmlNode *patchset)
23c78e
             free_xml(match);
23c78e
 
23c78e
         } else if (strcmp(op, "modify") == 0) {
23c78e
-            xmlAttr *pIter = pcmk__first_xml_attr(match);
23c78e
+            xmlAttr *pIter = pcmk__xe_first_attr(match);
23c78e
             xmlNode *attrs = NULL;
23c78e
 
23c78e
             attrs = pcmk__xml_first_child(first_named_child(change,
23c78e
@@ -1220,7 +1220,7 @@ apply_v2_patchset(xmlNode *xml, xmlNode *patchset)
23c78e
                 xml_remove_prop(match, name);
23c78e
             }
23c78e
 
23c78e
-            for (pIter = pcmk__first_xml_attr(attrs); pIter != NULL;
23c78e
+            for (pIter = pcmk__xe_first_attr(attrs); pIter != NULL;
23c78e
                  pIter = pIter->next) {
23c78e
                 const char *name = (const char *) pIter->name;
23c78e
                 const char *value = crm_element_value(attrs, name);
23c78e
@@ -1553,7 +1553,7 @@ subtract_xml_object(xmlNode *parent, xmlNode *left, xmlNode *right,
23c78e
     } else if (full) {
23c78e
         xmlAttrPtr pIter = NULL;
23c78e
 
23c78e
-        for (pIter = pcmk__first_xml_attr(left); pIter != NULL;
23c78e
+        for (pIter = pcmk__xe_first_attr(left); pIter != NULL;
23c78e
              pIter = pIter->next) {
23c78e
             const char *p_name = (const char *)pIter->name;
23c78e
             const char *p_value = pcmk__xml_attr_value(pIter);
23c78e
@@ -1566,7 +1566,7 @@ subtract_xml_object(xmlNode *parent, xmlNode *left, xmlNode *right,
23c78e
     }
23c78e
 
23c78e
     // Changes to name/value pairs
23c78e
-    for (xIter = pcmk__first_xml_attr(left); xIter != NULL;
23c78e
+    for (xIter = pcmk__xe_first_attr(left); xIter != NULL;
23c78e
          xIter = xIter->next) {
23c78e
         const char *prop_name = (const char *) xIter->name;
23c78e
         xmlAttrPtr right_attr = NULL;
23c78e
@@ -1594,7 +1594,7 @@ subtract_xml_object(xmlNode *parent, xmlNode *left, xmlNode *right,
23c78e
             if (full) {
23c78e
                 xmlAttrPtr pIter = NULL;
23c78e
 
23c78e
-                for (pIter = pcmk__first_xml_attr(left); pIter != NULL;
23c78e
+                for (pIter = pcmk__xe_first_attr(left); pIter != NULL;
23c78e
                      pIter = pIter->next) {
23c78e
                     const char *p_name = (const char *) pIter->name;
23c78e
                     const char *p_value = pcmk__xml_attr_value(pIter);
23c78e
@@ -1624,7 +1624,7 @@ subtract_xml_object(xmlNode *parent, xmlNode *left, xmlNode *right,
23c78e
 
23c78e
                     crm_trace("Changes detected to %s in <%s id=%s>", prop_name,
23c78e
                               crm_element_name(left), id);
23c78e
-                    for (pIter = pcmk__first_xml_attr(left); pIter != NULL;
23c78e
+                    for (pIter = pcmk__xe_first_attr(left); pIter != NULL;
23c78e
                          pIter = pIter->next) {
23c78e
                         const char *p_name = (const char *) pIter->name;
23c78e
                         const char *p_value = pcmk__xml_attr_value(pIter);
23c78e
diff --git a/lib/common/xml.c b/lib/common/xml.c
23c78e
index abb120c..f2f48e9 100644
23c78e
--- a/lib/common/xml.c
23c78e
+++ b/lib/common/xml.c
23c78e
@@ -337,7 +337,7 @@ accept_attr_deletions(xmlNode *xml)
23c78e
     xml_private_t *p = xml->_private;
23c78e
 
23c78e
     p->flags = xpf_none;
23c78e
-    pIter = pcmk__first_xml_attr(xml);
23c78e
+    pIter = pcmk__xe_first_attr(xml);
23c78e
 
23c78e
     while (pIter != NULL) {
23c78e
         const xmlChar *name = pIter->name;
23c78e
@@ -528,11 +528,9 @@ copy_in_properties(xmlNode * target, xmlNode * src)
23c78e
         crm_err("No node to copy properties into");
23c78e
 
23c78e
     } else {
23c78e
-        xmlAttrPtr pIter = NULL;
23c78e
-
23c78e
-        for (pIter = pcmk__first_xml_attr(src); pIter != NULL; pIter = pIter->next) {
23c78e
-            const char *p_name = (const char *)pIter->name;
23c78e
-            const char *p_value = pcmk__xml_attr_value(pIter);
23c78e
+        for (xmlAttrPtr a = pcmk__xe_first_attr(src); a != NULL; a = a->next) {
23c78e
+            const char *p_name = (const char *) a->name;
23c78e
+            const char *p_value = pcmk__xml_attr_value(a);
23c78e
 
23c78e
             expand_plus_plus(target, p_name, p_value);
23c78e
         }
23c78e
@@ -546,11 +544,10 @@ fix_plus_plus_recursive(xmlNode * target)
23c78e
 {
23c78e
     /* TODO: Remove recursion and use xpath searches for value++ */
23c78e
     xmlNode *child = NULL;
23c78e
-    xmlAttrPtr pIter = NULL;
23c78e
 
23c78e
-    for (pIter = pcmk__first_xml_attr(target); pIter != NULL; pIter = pIter->next) {
23c78e
-        const char *p_name = (const char *)pIter->name;
23c78e
-        const char *p_value = pcmk__xml_attr_value(pIter);
23c78e
+    for (xmlAttrPtr a = pcmk__xe_first_attr(target); a != NULL; a = a->next) {
23c78e
+        const char *p_name = (const char *) a->name;
23c78e
+        const char *p_value = pcmk__xml_attr_value(a);
23c78e
 
23c78e
         expand_plus_plus(target, p_name, p_value);
23c78e
     }
23c78e
@@ -1429,7 +1426,6 @@ pcmk__xe_log(int log_level, const char *file, const char *function, int line,
23c78e
     const char *hidden = NULL;
23c78e
 
23c78e
     xmlNode *child = NULL;
23c78e
-    xmlAttrPtr pIter = NULL;
23c78e
 
23c78e
     if ((data == NULL) || (log_level == LOG_NEVER)) {
23c78e
         return;
23c78e
@@ -1449,10 +1445,12 @@ pcmk__xe_log(int log_level, const char *file, const char *function, int line,
23c78e
             buffer_print(buffer, max, offset, "<%s", name);
23c78e
 
23c78e
             hidden = crm_element_value(data, "hidden");
23c78e
-            for (pIter = pcmk__first_xml_attr(data); pIter != NULL; pIter = pIter->next) {
23c78e
-                xml_private_t *p = pIter->_private;
23c78e
-                const char *p_name = (const char *)pIter->name;
23c78e
-                const char *p_value = pcmk__xml_attr_value(pIter);
23c78e
+            for (xmlAttrPtr a = pcmk__xe_first_attr(data); a != NULL;
23c78e
+                 a = a->next) {
23c78e
+
23c78e
+                xml_private_t *p = a->_private;
23c78e
+                const char *p_name = (const char *) a->name;
23c78e
+                const char *p_value = pcmk__xml_attr_value(a);
23c78e
                 char *p_copy = NULL;
23c78e
 
23c78e
                 if (pcmk_is_set(p->flags, xpf_deleted)) {
23c78e
@@ -1526,7 +1524,6 @@ log_xml_changes(int log_level, const char *file, const char *function, int line,
23c78e
     xml_private_t *p;
23c78e
     char *prefix_m = NULL;
23c78e
     xmlNode *child = NULL;
23c78e
-    xmlAttrPtr pIter = NULL;
23c78e
 
23c78e
     if ((data == NULL) || (log_level == LOG_NEVER)) {
23c78e
         return;
23c78e
@@ -1566,10 +1563,10 @@ log_xml_changes(int log_level, const char *file, const char *function, int line,
23c78e
         pcmk__xe_log(log_level, file, function, line, flags, data, depth,
23c78e
                      options|xml_log_option_open);
23c78e
 
23c78e
-        for (pIter = pcmk__first_xml_attr(data); pIter != NULL; pIter = pIter->next) {
23c78e
-            const char *aname = (const char*)pIter->name;
23c78e
+        for (xmlAttrPtr a = pcmk__xe_first_attr(data); a != NULL; a = a->next) {
23c78e
+            const char *aname = (const char*) a->name;
23c78e
 
23c78e
-            p = pIter->_private;
23c78e
+            p = a->_private;
23c78e
             if (pcmk_is_set(p->flags, xpf_deleted)) {
23c78e
                 const char *value = crm_element_value(data, aname);
23c78e
                 flags = prefix_del;
23c78e
@@ -1684,11 +1681,9 @@ log_data_element(int log_level, const char *file, const char *function, int line
23c78e
 static void
23c78e
 dump_filtered_xml(xmlNode * data, int options, char **buffer, int *offset, int *max)
23c78e
 {
23c78e
-    xmlAttrPtr xIter = NULL;
23c78e
-
23c78e
-    for (xIter = pcmk__first_xml_attr(data); xIter != NULL; xIter = xIter->next) {
23c78e
-        if (!pcmk__xa_filterable((const char *) (xIter->name))) {
23c78e
-            dump_xml_attr(xIter, options, buffer, offset, max);
23c78e
+    for (xmlAttrPtr a = pcmk__xe_first_attr(data); a != NULL; a = a->next) {
23c78e
+        if (!pcmk__xa_filterable((const char *) (a->name))) {
23c78e
+            dump_xml_attr(a, options, buffer, offset, max);
23c78e
         }
23c78e
     }
23c78e
 }
23c78e
@@ -1722,10 +1717,8 @@ dump_xml_element(xmlNode * data, int options, char **buffer, int *offset, int *m
23c78e
         dump_filtered_xml(data, options, buffer, offset, max);
23c78e
 
23c78e
     } else {
23c78e
-        xmlAttrPtr xIter = NULL;
23c78e
-
23c78e
-        for (xIter = pcmk__first_xml_attr(data); xIter != NULL; xIter = xIter->next) {
23c78e
-            dump_xml_attr(xIter, options, buffer, offset, max);
23c78e
+        for (xmlAttrPtr a = pcmk__xe_first_attr(data); a != NULL; a = a->next) {
23c78e
+            dump_xml_attr(a, options, buffer, offset, max);
23c78e
         }
23c78e
     }
23c78e
 
23c78e
@@ -2062,7 +2055,7 @@ save_xml_to_file(xmlNode * xml, const char *desc, const char *filename)
23c78e
 static void
23c78e
 set_attrs_flag(xmlNode *xml, enum xml_private_flags flag)
23c78e
 {
23c78e
-    for (xmlAttr *attr = pcmk__first_xml_attr(xml); attr; attr = attr->next) {
23c78e
+    for (xmlAttr *attr = pcmk__xe_first_attr(xml); attr; attr = attr->next) {
23c78e
         pcmk__set_xml_flags((xml_private_t *) (attr->_private), flag);
23c78e
     }
23c78e
 }
23c78e
@@ -2152,7 +2145,7 @@ mark_attr_moved(xmlNode *new_xml, const char *element, xmlAttr *old_attr,
23c78e
 static void
23c78e
 xml_diff_old_attrs(xmlNode *old_xml, xmlNode *new_xml)
23c78e
 {
23c78e
-    xmlAttr *attr_iter = pcmk__first_xml_attr(old_xml);
23c78e
+    xmlAttr *attr_iter = pcmk__xe_first_attr(old_xml);
23c78e
 
23c78e
     while (attr_iter != NULL) {
23c78e
         xmlAttr *old_attr = attr_iter;
23c78e
@@ -2194,7 +2187,7 @@ xml_diff_old_attrs(xmlNode *old_xml, xmlNode *new_xml)
23c78e
 static void
23c78e
 mark_created_attrs(xmlNode *new_xml)
23c78e
 {
23c78e
-    xmlAttr *attr_iter = pcmk__first_xml_attr(new_xml);
23c78e
+    xmlAttr *attr_iter = pcmk__xe_first_attr(new_xml);
23c78e
 
23c78e
     while (attr_iter != NULL) {
23c78e
         xmlAttr *new_attr = attr_iter;
23c78e
@@ -2371,7 +2364,6 @@ gboolean
23c78e
 can_prune_leaf(xmlNode * xml_node)
23c78e
 {
23c78e
     xmlNode *cIter = NULL;
23c78e
-    xmlAttrPtr pIter = NULL;
23c78e
     gboolean can_prune = TRUE;
23c78e
     const char *name = crm_element_name(xml_node);
23c78e
 
23c78e
@@ -2380,8 +2372,8 @@ can_prune_leaf(xmlNode * xml_node)
23c78e
         return FALSE;
23c78e
     }
23c78e
 
23c78e
-    for (pIter = pcmk__first_xml_attr(xml_node); pIter != NULL; pIter = pIter->next) {
23c78e
-        const char *p_name = (const char *)pIter->name;
23c78e
+    for (xmlAttrPtr a = pcmk__xe_first_attr(xml_node); a != NULL; a = a->next) {
23c78e
+        const char *p_name = (const char *) a->name;
23c78e
 
23c78e
         if (strcmp(p_name, XML_ATTR_ID) == 0) {
23c78e
             continue;
23c78e
@@ -2558,15 +2550,13 @@ pcmk__xml_update(xmlNode *parent, xmlNode *target, xmlNode *update,
23c78e
 
23c78e
     } else {
23c78e
         /* No need for expand_plus_plus(), just raw speed */
23c78e
-        xmlAttrPtr pIter = NULL;
23c78e
-
23c78e
-        for (pIter = pcmk__first_xml_attr(update); pIter != NULL; pIter = pIter->next) {
23c78e
-            const char *p_name = (const char *)pIter->name;
23c78e
-            const char *p_value = pcmk__xml_attr_value(pIter);
23c78e
+        for (xmlAttrPtr a = pcmk__xe_first_attr(update); a != NULL;
23c78e
+             a = a->next) {
23c78e
+            const char *p_value = pcmk__xml_attr_value(a);
23c78e
 
23c78e
             /* Remove it first so the ordering of the update is preserved */
23c78e
-            xmlUnsetProp(target, (pcmkXmlStr) p_name);
23c78e
-            xmlSetProp(target, (pcmkXmlStr) p_name, (pcmkXmlStr) p_value);
23c78e
+            xmlUnsetProp(target, a->name);
23c78e
+            xmlSetProp(target, a->name, (pcmkXmlStr) p_value);
23c78e
         }
23c78e
     }
23c78e
 
23c78e
@@ -2681,11 +2671,10 @@ replace_xml_child(xmlNode * parent, xmlNode * child, xmlNode * update, gboolean
23c78e
         can_delete = FALSE;
23c78e
     }
23c78e
     if (can_delete && delete_only) {
23c78e
-        xmlAttrPtr pIter = NULL;
23c78e
-
23c78e
-        for (pIter = pcmk__first_xml_attr(update); pIter != NULL; pIter = pIter->next) {
23c78e
-            const char *p_name = (const char *)pIter->name;
23c78e
-            const char *p_value = pcmk__xml_attr_value(pIter);
23c78e
+        for (xmlAttrPtr a = pcmk__xe_first_attr(update); a != NULL;
23c78e
+             a = a->next) {
23c78e
+            const char *p_name = (const char *) a->name;
23c78e
+            const char *p_value = pcmk__xml_attr_value(a);
23c78e
 
23c78e
             right_val = crm_element_value(child, p_name);
23c78e
             if (!pcmk__str_eq(p_value, right_val, pcmk__str_casei)) {
23c78e
-- 
23c78e
1.8.3.1
23c78e
23c78e
23c78e
From 68e35a6f715f26a8a3b033cc91875f6f7001f106 Mon Sep 17 00:00:00 2001
23c78e
From: Ken Gaillot <kgaillot@redhat.com>
23c78e
Date: Thu, 19 Nov 2020 10:31:36 -0600
23c78e
Subject: [PATCH 03/12] Refactor: libcrmcommon: new internal function for
23c78e
 removing XML attributes
23c78e
23c78e
---
23c78e
 include/crm/common/xml_internal.h |  4 ++++
23c78e
 lib/common/xml.c                  | 34 ++++++++++++++++++++++++++++++++++
23c78e
 2 files changed, 38 insertions(+)
23c78e
23c78e
diff --git a/include/crm/common/xml_internal.h b/include/crm/common/xml_internal.h
23c78e
index b2ff529..1e80bc6 100644
23c78e
--- a/include/crm/common/xml_internal.h
23c78e
+++ b/include/crm/common/xml_internal.h
23c78e
@@ -136,6 +136,10 @@ const char *pcmk__xe_add_last_written(xmlNode *xe);
23c78e
 xmlNode *pcmk__xe_match(xmlNode *parent, const char *node_name,
23c78e
                         const char *attr_n, const char *attr_v);
23c78e
 
23c78e
+void pcmk__xe_remove_matching_attrs(xmlNode *element,
23c78e
+                                    bool (*match)(xmlAttrPtr, void *),
23c78e
+                                    void *user_data);
23c78e
+
23c78e
 /*!
23c78e
  * \internal
23c78e
  * \brief Get the root directory to scan XML artefacts of given kind for
23c78e
diff --git a/lib/common/xml.c b/lib/common/xml.c
23c78e
index f2f48e9..39c5e53 100644
23c78e
--- a/lib/common/xml.c
23c78e
+++ b/lib/common/xml.c
23c78e
@@ -618,6 +618,40 @@ expand_plus_plus(xmlNode * target, const char *name, const char *value)
23c78e
     return;
23c78e
 }
23c78e
 
23c78e
+/*!
23c78e
+ * \internal
23c78e
+ * \brief Remove an XML element's attributes that match some criteria
23c78e
+ *
23c78e
+ * \param[in,out] element    XML element to modify
23c78e
+ * \param[in]     match      If not NULL, only remove attributes for which
23c78e
+ *                           this function returns true
23c78e
+ * \param[in]     user_data  Data to pass to \p match
23c78e
+ */
23c78e
+void
23c78e
+pcmk__xe_remove_matching_attrs(xmlNode *element,
23c78e
+                               bool (*match)(xmlAttrPtr, void *),
23c78e
+                               void *user_data)
23c78e
+{
23c78e
+    xmlAttrPtr next = NULL;
23c78e
+
23c78e
+    for (xmlAttrPtr a = pcmk__xe_first_attr(element); a != NULL; a = next) {
23c78e
+        next = a->next; // Grab now because attribute might get removed
23c78e
+        if ((match == NULL) || match(a, user_data)) {
23c78e
+            if (!pcmk__check_acl(element, NULL, xpf_acl_write)) {
23c78e
+                crm_trace("ACLs prevent removal of %s attribute from %s element",
23c78e
+                          (const char *) a->name, (const char *) element->name);
23c78e
+
23c78e
+            } else if (pcmk__tracking_xml_changes(element, false)) {
23c78e
+                // Leave (marked for removal) until after diff is calculated
23c78e
+                set_parent_flag(element, xpf_dirty);
23c78e
+                pcmk__set_xml_flags((xml_private_t *) a->_private, xpf_deleted);
23c78e
+            } else {
23c78e
+                xmlRemoveProp(a);
23c78e
+            }
23c78e
+        }
23c78e
+    }
23c78e
+}
23c78e
+
23c78e
 xmlDoc *
23c78e
 getDocPtr(xmlNode * node)
23c78e
 {
23c78e
-- 
23c78e
1.8.3.1
23c78e
23c78e
23c78e
From a6e1804156dfd1f6c3bc1ffbf888fbd6421aa464 Mon Sep 17 00:00:00 2001
23c78e
From: Ken Gaillot <kgaillot@redhat.com>
23c78e
Date: Thu, 19 Nov 2020 11:10:52 -0600
23c78e
Subject: [PATCH 04/12] Refactor: libcrmcommon,libpe_status: use new attribute
23c78e
 removing function
23c78e
23c78e
... where appropriate, for readability and efficiency
23c78e
---
23c78e
 lib/common/operations.c | 64 ++++++++++++++++++-------------------
23c78e
 lib/common/patchset.c   | 29 +++++++----------
23c78e
 lib/common/xml.c        | 39 +++++++++++------------
23c78e
 lib/pengine/pe_digest.c | 84 ++++++++++++++++++++++++++-----------------------
23c78e
 4 files changed, 105 insertions(+), 111 deletions(-)
23c78e
23c78e
diff --git a/lib/common/operations.c b/lib/common/operations.c
23c78e
index 7e6bf5a..f3a11be 100644
23c78e
--- a/lib/common/operations.c
23c78e
+++ b/lib/common/operations.c
23c78e
@@ -24,6 +24,7 @@
23c78e
 #include <crm/lrmd.h>
23c78e
 #include <crm/msg_xml.h>
23c78e
 #include <crm/common/xml.h>
23c78e
+#include <crm/common/xml_internal.h>
23c78e
 #include <crm/common/util.h>
23c78e
 
23c78e
 static regex_t *notify_migrate_re = NULL;
23c78e
@@ -361,6 +362,24 @@ decode_transition_key(const char *key, char **uuid, int *transition_id, int *act
23c78e
     return TRUE;
23c78e
 }
23c78e
 
23c78e
+#define CRM_META_LEN (sizeof(CRM_META) - 1)
23c78e
+
23c78e
+// Return true if a is an attribute that should be filtered
23c78e
+static bool
23c78e
+should_filter_for_digest(xmlAttrPtr a, void *user_data)
23c78e
+{
23c78e
+    // @TODO CRM_META check should be case-sensitive
23c78e
+    return (strncasecmp((const char *) a->name, CRM_META, CRM_META_LEN) == 0)
23c78e
+           || pcmk__str_any_of((const char *) a->name,
23c78e
+                               XML_ATTR_ID,
23c78e
+                               XML_ATTR_CRM_VERSION,
23c78e
+                               XML_LRM_ATTR_OP_DIGEST,
23c78e
+                               XML_LRM_ATTR_TARGET,
23c78e
+                               XML_LRM_ATTR_TARGET_UUID,
23c78e
+                               "pcmk_external_ip",
23c78e
+                               NULL);
23c78e
+}
23c78e
+
23c78e
 /*!
23c78e
  * \internal
23c78e
  * \brief Remove XML attributes not needed for operation digest
23c78e
@@ -374,52 +393,31 @@ pcmk__filter_op_for_digest(xmlNode *param_set)
23c78e
     char *timeout = NULL;
23c78e
     guint interval_ms = 0;
23c78e
 
23c78e
-    const char *attr_filter[] = {
23c78e
-        XML_ATTR_ID,
23c78e
-        XML_ATTR_CRM_VERSION,
23c78e
-        XML_LRM_ATTR_OP_DIGEST,
23c78e
-        XML_LRM_ATTR_TARGET,
23c78e
-        XML_LRM_ATTR_TARGET_UUID,
23c78e
-        "pcmk_external_ip"
23c78e
-    };
23c78e
-
23c78e
-    const int meta_len = strlen(CRM_META);
23c78e
-
23c78e
     if (param_set == NULL) {
23c78e
         return;
23c78e
     }
23c78e
 
23c78e
-    // Remove the specific attributes listed in attr_filter
23c78e
-    for (int lpc = 0; lpc < DIMOF(attr_filter); lpc++) {
23c78e
-        xml_remove_prop(param_set, attr_filter[lpc]);
23c78e
-    }
23c78e
-
23c78e
+    /* Timeout is useful for recurring operation digests, so grab it before
23c78e
+     * removing meta-attributes
23c78e
+     */
23c78e
     key = crm_meta_name(XML_LRM_ATTR_INTERVAL_MS);
23c78e
     if (crm_element_value_ms(param_set, key, &interval_ms) != pcmk_ok) {
23c78e
         interval_ms = 0;
23c78e
     }
23c78e
     free(key);
23c78e
-
23c78e
-    key = crm_meta_name(XML_ATTR_TIMEOUT);
23c78e
-    timeout = crm_element_value_copy(param_set, key);
23c78e
-
23c78e
-    // Remove all CRM_meta_* attributes
23c78e
-    for (xmlAttrPtr xIter = param_set->properties; xIter != NULL; ) {
23c78e
-        const char *prop_name = (const char *) (xIter->name);
23c78e
-
23c78e
-        xIter = xIter->next;
23c78e
-
23c78e
-        // @TODO Why is this case-insensitive?
23c78e
-        if (strncasecmp(prop_name, CRM_META, meta_len) == 0) {
23c78e
-            xml_remove_prop(param_set, prop_name);
23c78e
-        }
23c78e
+    key = NULL;
23c78e
+    if (interval_ms != 0) {
23c78e
+        key = crm_meta_name(XML_ATTR_TIMEOUT);
23c78e
+        timeout = crm_element_value_copy(param_set, key);
23c78e
     }
23c78e
 
23c78e
-    if ((interval_ms != 0) && (timeout != NULL)) {
23c78e
-        // Add the timeout back, it's useful for recurring operation digests
23c78e
+    // Remove all CRM_meta_* attributes and certain other attributes
23c78e
+    pcmk__xe_remove_matching_attrs(param_set, should_filter_for_digest, NULL);
23c78e
+
23c78e
+    // Add timeout back for recurring operation digests
23c78e
+    if (timeout != NULL) {
23c78e
         crm_xml_add(param_set, key, timeout);
23c78e
     }
23c78e
-
23c78e
     free(timeout);
23c78e
     free(key);
23c78e
 }
23c78e
diff --git a/lib/common/patchset.c b/lib/common/patchset.c
23c78e
index 15cbe07..fae7046 100644
23c78e
--- a/lib/common/patchset.c
23c78e
+++ b/lib/common/patchset.c
23c78e
@@ -638,13 +638,19 @@ xml_log_patchset(uint8_t log_level, const char *function, xmlNode *patchset)
23c78e
     }
23c78e
 }
23c78e
 
23c78e
+// Return true if attribute name is not "id"
23c78e
+static bool
23c78e
+not_id(xmlAttrPtr attr, void *user_data)
23c78e
+{
23c78e
+    return strcmp((const char *) attr->name, XML_ATTR_ID) != 0;
23c78e
+}
23c78e
+
23c78e
 // Apply the removals section of an v1 patchset to an XML node
23c78e
 static void
23c78e
 process_v1_removals(xmlNode *target, xmlNode *patch)
23c78e
 {
23c78e
     xmlNode *patch_child = NULL;
23c78e
     xmlNode *cIter = NULL;
23c78e
-    xmlAttrPtr xIter = NULL;
23c78e
 
23c78e
     char *id = NULL;
23c78e
     const char *name = NULL;
23c78e
@@ -677,15 +683,8 @@ process_v1_removals(xmlNode *target, xmlNode *patch)
23c78e
         return;
23c78e
     }
23c78e
 
23c78e
-    for (xIter = pcmk__xe_first_attr(patch); xIter != NULL;
23c78e
-         xIter = xIter->next) {
23c78e
-        const char *p_name = (const char *)xIter->name;
23c78e
-
23c78e
-        // Removing then restoring id would change ordering of properties
23c78e
-        if (!pcmk__str_eq(p_name, XML_ATTR_ID, pcmk__str_casei)) {
23c78e
-            xml_remove_prop(target, p_name);
23c78e
-        }
23c78e
-    }
23c78e
+    // Removing then restoring id would change ordering of properties
23c78e
+    pcmk__xe_remove_matching_attrs(patch, not_id, NULL);
23c78e
 
23c78e
     // Changes to child objects
23c78e
     cIter = pcmk__xml_first_child(target);
23c78e
@@ -1204,7 +1203,6 @@ apply_v2_patchset(xmlNode *xml, xmlNode *patchset)
23c78e
             free_xml(match);
23c78e
 
23c78e
         } else if (strcmp(op, "modify") == 0) {
23c78e
-            xmlAttr *pIter = pcmk__xe_first_attr(match);
23c78e
             xmlNode *attrs = NULL;
23c78e
 
23c78e
             attrs = pcmk__xml_first_child(first_named_child(change,
23c78e
@@ -1213,14 +1211,9 @@ apply_v2_patchset(xmlNode *xml, xmlNode *patchset)
23c78e
                 rc = ENOMSG;
23c78e
                 continue;
23c78e
             }
23c78e
-            while (pIter != NULL) {
23c78e
-                const char *name = (const char *)pIter->name;
23c78e
-
23c78e
-                pIter = pIter->next;
23c78e
-                xml_remove_prop(match, name);
23c78e
-            }
23c78e
+            pcmk__xe_remove_matching_attrs(match, NULL, NULL); // Remove all
23c78e
 
23c78e
-            for (pIter = pcmk__xe_first_attr(attrs); pIter != NULL;
23c78e
+            for (xmlAttrPtr pIter = pcmk__xe_first_attr(attrs); pIter != NULL;
23c78e
                  pIter = pIter->next) {
23c78e
                 const char *name = (const char *) pIter->name;
23c78e
                 const char *value = crm_element_value(attrs, name);
23c78e
diff --git a/lib/common/xml.c b/lib/common/xml.c
23c78e
index 39c5e53..869ed51 100644
23c78e
--- a/lib/common/xml.c
23c78e
+++ b/lib/common/xml.c
23c78e
@@ -328,32 +328,31 @@ pcmk__xml_position(xmlNode *xml, enum xml_private_flags ignore_if_set)
23c78e
     return position;
23c78e
 }
23c78e
 
23c78e
-// Remove all attributes marked as deleted from an XML node
23c78e
-static void
23c78e
-accept_attr_deletions(xmlNode *xml)
23c78e
+// This also clears attribute's flags if not marked as deleted
23c78e
+static bool
23c78e
+marked_as_deleted(xmlAttrPtr a, void *user_data)
23c78e
 {
23c78e
-    xmlNode *cIter = NULL;
23c78e
-    xmlAttr *pIter = NULL;
23c78e
-    xml_private_t *p = xml->_private;
23c78e
+    xml_private_t *p = a->_private;
23c78e
 
23c78e
+    if (pcmk_is_set(p->flags, xpf_deleted)) {
23c78e
+        return true;
23c78e
+    }
23c78e
     p->flags = xpf_none;
23c78e
-    pIter = pcmk__xe_first_attr(xml);
23c78e
-
23c78e
-    while (pIter != NULL) {
23c78e
-        const xmlChar *name = pIter->name;
23c78e
-
23c78e
-        p = pIter->_private;
23c78e
-        pIter = pIter->next;
23c78e
+    return false;
23c78e
+}
23c78e
 
23c78e
-        if(p->flags & xpf_deleted) {
23c78e
-            xml_remove_prop(xml, (const char *)name);
23c78e
+// Remove all attributes marked as deleted from an XML node
23c78e
+static void
23c78e
+accept_attr_deletions(xmlNode *xml)
23c78e
+{
23c78e
+    // Clear XML node's flags
23c78e
+    ((xml_private_t *) xml->_private)->flags = xpf_none;
23c78e
 
23c78e
-        } else {
23c78e
-            p->flags = xpf_none;
23c78e
-        }
23c78e
-    }
23c78e
+    // Remove this XML node's attributes that were marked as deleted
23c78e
+    pcmk__xe_remove_matching_attrs(xml, marked_as_deleted, NULL);
23c78e
 
23c78e
-    for (cIter = pcmk__xml_first_child(xml); cIter != NULL;
23c78e
+    // Recursively do the same for this XML node's children
23c78e
+    for (xmlNodePtr cIter = pcmk__xml_first_child(xml); cIter != NULL;
23c78e
          cIter = pcmk__xml_next(cIter)) {
23c78e
         accept_attr_deletions(cIter);
23c78e
     }
23c78e
diff --git a/lib/pengine/pe_digest.c b/lib/pengine/pe_digest.c
23c78e
index dd6b753..e8cb108 100644
23c78e
--- a/lib/pengine/pe_digest.c
23c78e
+++ b/lib/pengine/pe_digest.c
23c78e
@@ -15,6 +15,7 @@
23c78e
 #include <crm/crm.h>
23c78e
 #include <crm/msg_xml.h>
23c78e
 #include <crm/common/xml.h>
23c78e
+#include <crm/common/xml_internal.h>
23c78e
 #include <crm/pengine/internal.h>
23c78e
 #include "pe_status_private.h"
23c78e
 
23c78e
@@ -45,40 +46,36 @@ pe__free_digests(gpointer ptr)
23c78e
     }
23c78e
 }
23c78e
 
23c78e
-/*!
23c78e
- * \internal
23c78e
- * \brief Remove named attributes from an XML element
23c78e
- *
23c78e
- * \param[in,out] param_set     XML to be filtered
23c78e
- * \param[in]     param_string  Space-separated list of attribute names
23c78e
- * \param[in]     need_present  Whether to remove attributes that match,
23c78e
- *                              or those that don't match
23c78e
- */
23c78e
-static void
23c78e
-filter_parameters(xmlNode *param_set, const char *param_string,
23c78e
-                  bool need_present)
23c78e
+// Return true if XML attribute name is substring of a given string
23c78e
+static bool
23c78e
+attr_in_string(xmlAttrPtr a, void *user_data)
23c78e
 {
23c78e
-    if ((param_set == NULL) || (param_string == NULL)) {
23c78e
-        return;
23c78e
-    }
23c78e
-    for (xmlAttrPtr xIter = param_set->properties; xIter; ) {
23c78e
-        const char *prop_name = (const char *) xIter->name;
23c78e
-        char *name = crm_strdup_printf(" %s ", prop_name);
23c78e
-        char *match = strstr(param_string, name);
23c78e
-
23c78e
-        free(name);
23c78e
+    bool filter = false;
23c78e
+    char *name = crm_strdup_printf(" %s ", (const char *) a->name);
23c78e
 
23c78e
-        //  Do now, because current entry might get removed below
23c78e
-        xIter = xIter->next;
23c78e
+    if (strstr((const char *) user_data, name) == NULL) {
23c78e
+        crm_trace("Filtering %s (not found in '%s')",
23c78e
+                  (const char *) a->name, (const char *) user_data);
23c78e
+        filter = true;
23c78e
+    }
23c78e
+    free(name);
23c78e
+    return filter;
23c78e
+}
23c78e
 
23c78e
-        if ((need_present && (match == NULL))
23c78e
-            || (!need_present && (match != NULL))) {
23c78e
+// Return true if XML attribute name is not substring of a given string
23c78e
+static bool
23c78e
+attr_not_in_string(xmlAttrPtr a, void *user_data)
23c78e
+{
23c78e
+    bool filter = false;
23c78e
+    char *name = crm_strdup_printf(" %s ", (const char *) a->name);
23c78e
 
23c78e
-            crm_trace("Filtering %s (%sfound in '%s')",
23c78e
-                      prop_name, (need_present? "not " : ""), param_string);
23c78e
-            xml_remove_prop(param_set, prop_name);
23c78e
-        }
23c78e
+    if (strstr((const char *) user_data, name) != NULL) {
23c78e
+        crm_trace("Filtering %s (found in '%s')",
23c78e
+                  (const char *) a->name, (const char *) user_data);
23c78e
+        filter = true;
23c78e
     }
23c78e
+    free(name);
23c78e
+    return filter;
23c78e
 }
23c78e
 
23c78e
 #if ENABLE_VERSIONED_ATTRS
23c78e
@@ -177,6 +174,13 @@ calculate_main_digest(op_digest_cache_t *data, pe_resource_t *rsc,
23c78e
                                                        op_version);
23c78e
 }
23c78e
 
23c78e
+// Return true if XML attribute name is a Pacemaker-defined fencing parameter
23c78e
+static bool
23c78e
+is_fence_param(xmlAttrPtr attr, void *user_data)
23c78e
+{
23c78e
+    return pcmk_stonith_param((const char *) attr->name);
23c78e
+}
23c78e
+
23c78e
 /*!
23c78e
  * \internal
23c78e
  * \brief Add secure digest to a digest cache entry
23c78e
@@ -209,8 +213,12 @@ calculate_secure_digest(op_digest_cache_t *data, pe_resource_t *rsc,
23c78e
     if (overrides != NULL) {
23c78e
         g_hash_table_foreach(overrides, hash2field, data->params_secure);
23c78e
     }
23c78e
+
23c78e
     g_hash_table_foreach(rsc->parameters, hash2field, data->params_secure);
23c78e
-    filter_parameters(data->params_secure, secure_list, FALSE);
23c78e
+    if (secure_list != NULL) {
23c78e
+        pcmk__xe_remove_matching_attrs(data->params_secure, attr_not_in_string,
23c78e
+                                       (void *) secure_list);
23c78e
+    }
23c78e
     if (pcmk_is_set(pcmk_get_ra_caps(class),
23c78e
                     pcmk_ra_cap_fence_params)) {
23c78e
         /* For stonith resources, Pacemaker adds special parameters,
23c78e
@@ -218,15 +226,8 @@ calculate_secure_digest(op_digest_cache_t *data, pe_resource_t *rsc,
23c78e
          * controller will not hash them. That means we have to filter
23c78e
          * them out before calculating our hash for comparison.
23c78e
          */
23c78e
-        for (xmlAttrPtr iter = data->params_secure->properties;
23c78e
-             iter != NULL; ) {
23c78e
-            const char *prop_name = (const char *) iter->name;
23c78e
-
23c78e
-            iter = iter->next; // Grab next now in case we remove current
23c78e
-            if (pcmk_stonith_param(prop_name)) {
23c78e
-                xml_remove_prop(data->params_secure, prop_name);
23c78e
-            }
23c78e
-        }
23c78e
+        pcmk__xe_remove_matching_attrs(data->params_secure, is_fence_param,
23c78e
+                                       NULL);
23c78e
     }
23c78e
     data->digest_secure_calc = calculate_operation_digest(data->params_secure,
23c78e
                                                           op_version);
23c78e
@@ -264,7 +265,10 @@ calculate_restart_digest(op_digest_cache_t *data, xmlNode *xml_op,
23c78e
 
23c78e
     // Then filter out reloadable parameters, if any
23c78e
     value = crm_element_value(xml_op, XML_LRM_ATTR_OP_RESTART);
23c78e
-    filter_parameters(data->params_restart, value, TRUE);
23c78e
+    if (value != NULL) {
23c78e
+        pcmk__xe_remove_matching_attrs(data->params_restart, attr_in_string,
23c78e
+                                       (void *) value);
23c78e
+    }
23c78e
 
23c78e
     value = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
23c78e
     data->digest_restart_calc = calculate_operation_digest(data->params_restart,
23c78e
-- 
23c78e
1.8.3.1
23c78e
23c78e
23c78e
From 579875b70c2399f6cbf15d7afd210a2d4e2ed9df Mon Sep 17 00:00:00 2001
23c78e
From: Ken Gaillot <kgaillot@redhat.com>
23c78e
Date: Thu, 19 Nov 2020 11:47:20 -0600
23c78e
Subject: [PATCH 05/12] Refactor: libcrmcommon,libpe_status: use "first XML
23c78e
 attribute" function
23c78e
23c78e
... where appropriate. It checks for NULL, so that doesn't need to be
23c78e
duplicated.
23c78e
---
23c78e
 lib/common/patchset.c | 11 +++--------
23c78e
 lib/pengine/complex.c | 12 ++++--------
23c78e
 2 files changed, 7 insertions(+), 16 deletions(-)
23c78e
23c78e
diff --git a/lib/common/patchset.c b/lib/common/patchset.c
23c78e
index fae7046..46d136a 100644
23c78e
--- a/lib/common/patchset.c
23c78e
+++ b/lib/common/patchset.c
23c78e
@@ -279,15 +279,10 @@ xml_repair_v1_diff(xmlNode *last, xmlNode *next, xmlNode *local_diff,
23c78e
         crm_xml_add(diff_child, vfields[lpc], value);
23c78e
     }
23c78e
 
23c78e
-    if (next) {
23c78e
-        xmlAttrPtr xIter = NULL;
23c78e
+    for (xmlAttrPtr a = pcmk__xe_first_attr(next); a != NULL; a = a->next) {
23c78e
+        const char *p_value = crm_element_value(next, (const char *) a->name);
23c78e
 
23c78e
-        for (xIter = next->properties; xIter; xIter = xIter->next) {
23c78e
-            const char *p_name = (const char *) xIter->name;
23c78e
-            const char *p_value = crm_element_value(next, p_name);
23c78e
-
23c78e
-            xmlSetProp(cib, (pcmkXmlStr) p_name, (pcmkXmlStr) p_value);
23c78e
-        }
23c78e
+        xmlSetProp(cib, a->name, (pcmkXmlStr) p_value);
23c78e
     }
23c78e
 
23c78e
     crm_log_xml_explicit(local_diff, "Repaired-diff");
23c78e
diff --git a/lib/pengine/complex.c b/lib/pengine/complex.c
23c78e
index a087e5e..5f484ad 100644
23c78e
--- a/lib/pengine/complex.c
23c78e
+++ b/lib/pengine/complex.c
23c78e
@@ -159,15 +159,11 @@ get_meta_attributes(GHashTable * meta_hash, pe_resource_t * rsc,
23c78e
         rule_data.node_hash = node->details->attrs;
23c78e
     }
23c78e
 
23c78e
-    if (rsc->xml) {
23c78e
-        xmlAttrPtr xIter = NULL;
23c78e
+    for (xmlAttrPtr a = pcmk__xe_first_attr(rsc->xml); a != NULL; a = a->next) {
23c78e
+        const char *prop_name = (const char *) a->name;
23c78e
+        const char *prop_value = crm_element_value(rsc->xml, prop_name);
23c78e
 
23c78e
-        for (xIter = rsc->xml->properties; xIter; xIter = xIter->next) {
23c78e
-            const char *prop_name = (const char *)xIter->name;
23c78e
-            const char *prop_value = crm_element_value(rsc->xml, prop_name);
23c78e
-
23c78e
-            add_hash_param(meta_hash, prop_name, prop_value);
23c78e
-        }
23c78e
+        add_hash_param(meta_hash, prop_name, prop_value);
23c78e
     }
23c78e
 
23c78e
     pe__unpack_dataset_nvpairs(rsc->xml, XML_TAG_META_SETS, &rule_data,
23c78e
-- 
23c78e
1.8.3.1
23c78e
23c78e
23c78e
From a30d60e6344129e03fcab9cd8c9523bf24951a92 Mon Sep 17 00:00:00 2001
23c78e
From: Ken Gaillot <kgaillot@redhat.com>
23c78e
Date: Thu, 19 Nov 2020 13:37:37 -0600
23c78e
Subject: [PATCH 06/12] Low: libcrmcommon: compare CRM_meta_ properly
23c78e
23c78e
Previously, when filtering XML attributes for digests, we would filter
23c78e
attributes starting with "CRM_meta" case-insensitively. Now, compare
23c78e
against "CRM_meta_" case-sensitively.
23c78e
23c78e
This could potentially cause resource restarts after upgrading to a version
23c78e
with this commit, for any resource that has instance attributes that start with
23c78e
something like "crm_meta" -- a highly unlikely scenario.
23c78e
---
23c78e
 lib/common/operations.c | 6 +++---
23c78e
 1 file changed, 3 insertions(+), 3 deletions(-)
23c78e
23c78e
diff --git a/lib/common/operations.c b/lib/common/operations.c
23c78e
index f3a11be..421aaac 100644
23c78e
--- a/lib/common/operations.c
23c78e
+++ b/lib/common/operations.c
23c78e
@@ -362,14 +362,14 @@ decode_transition_key(const char *key, char **uuid, int *transition_id, int *act
23c78e
     return TRUE;
23c78e
 }
23c78e
 
23c78e
-#define CRM_META_LEN (sizeof(CRM_META) - 1)
23c78e
+// String length of CRM_META"_"
23c78e
+#define CRM_META_LEN sizeof(CRM_META)
23c78e
 
23c78e
 // Return true if a is an attribute that should be filtered
23c78e
 static bool
23c78e
 should_filter_for_digest(xmlAttrPtr a, void *user_data)
23c78e
 {
23c78e
-    // @TODO CRM_META check should be case-sensitive
23c78e
-    return (strncasecmp((const char *) a->name, CRM_META, CRM_META_LEN) == 0)
23c78e
+    return (strncmp((const char *) a->name, CRM_META "_", CRM_META_LEN) == 0)
23c78e
            || pcmk__str_any_of((const char *) a->name,
23c78e
                                XML_ATTR_ID,
23c78e
                                XML_ATTR_CRM_VERSION,
23c78e
-- 
23c78e
1.8.3.1
23c78e
23c78e
23c78e
From cb81616eaf53e7029a0c196ffab6203d60389386 Mon Sep 17 00:00:00 2001
23c78e
From: Ken Gaillot <kgaillot@redhat.com>
23c78e
Date: Mon, 23 Nov 2020 11:04:08 -0600
23c78e
Subject: [PATCH 07/12] Low: scheduler: filter non-private parameters properly
23c78e
 for digest
23c78e
23c78e
Do the same filtering for non-private parameter digests as for all-parameter
23c78e
digests. This matters when a filterable parameter is specified in overrides.
23c78e
---
23c78e
 lib/pengine/pe_digest.c | 1 +
23c78e
 1 file changed, 1 insertion(+)
23c78e
23c78e
diff --git a/lib/pengine/pe_digest.c b/lib/pengine/pe_digest.c
23c78e
index e8cb108..03aa3bc 100644
23c78e
--- a/lib/pengine/pe_digest.c
23c78e
+++ b/lib/pengine/pe_digest.c
23c78e
@@ -229,6 +229,7 @@ calculate_secure_digest(op_digest_cache_t *data, pe_resource_t *rsc,
23c78e
         pcmk__xe_remove_matching_attrs(data->params_secure, is_fence_param,
23c78e
                                        NULL);
23c78e
     }
23c78e
+    pcmk__filter_op_for_digest(data->params_secure);
23c78e
     data->digest_secure_calc = calculate_operation_digest(data->params_secure,
23c78e
                                                           op_version);
23c78e
 }
23c78e
-- 
23c78e
1.8.3.1
23c78e
23c78e
23c78e
From fe4aee37ceca64fd8a512e7cae57bae0745c7ace Mon Sep 17 00:00:00 2001
23c78e
From: Ken Gaillot <kgaillot@redhat.com>
23c78e
Date: Mon, 23 Nov 2020 17:17:59 -0600
23c78e
Subject: [PATCH 08/12] Refactor: scheduler: pull interval from digest
23c78e
 overrides if appropriate
23c78e
23c78e
When calculating an operation digest, we previously used an operation key
23c78e
provided by the caller, along with a table of parameter overrides. However, if
23c78e
CRM_meta_interval is one of the overrides, that should be used in the operation
23c78e
key instead of the caller-provided key.
23c78e
23c78e
Now, the caller passes in a pointer to the interval, and if it's overridden,
23c78e
pe__calculate_digests() will use the overridden value and reset the caller's
23c78e
interval to it.
23c78e
23c78e
As of this commit, no caller passes overrides, so it has no effect, but it will
23c78e
be useful for an upcoming feature.
23c78e
---
23c78e
 include/crm/pengine/internal.h |   2 +-
23c78e
 lib/pengine/pe_digest.c        | 117 +++++++++++++++++++++++++----------------
23c78e
 2 files changed, 73 insertions(+), 46 deletions(-)
23c78e
23c78e
diff --git a/include/crm/pengine/internal.h b/include/crm/pengine/internal.h
23c78e
index a4f8086..1e5aee1 100644
23c78e
--- a/include/crm/pengine/internal.h
23c78e
+++ b/include/crm/pengine/internal.h
23c78e
@@ -503,7 +503,7 @@ typedef struct op_digest_cache_s {
23c78e
 } op_digest_cache_t;
23c78e
 
23c78e
 op_digest_cache_t *pe__calculate_digests(pe_resource_t *rsc, const char *task,
23c78e
-                                         const char *key, pe_node_t *node,
23c78e
+                                         guint *interval_ms, pe_node_t *node,
23c78e
                                          xmlNode *xml_op, GHashTable *overrides,
23c78e
                                          bool calc_secure,
23c78e
                                          pe_working_set_t *data_set);
23c78e
diff --git a/lib/pengine/pe_digest.c b/lib/pengine/pe_digest.c
23c78e
index 03aa3bc..b608f22 100644
23c78e
--- a/lib/pengine/pe_digest.c
23c78e
+++ b/lib/pengine/pe_digest.c
23c78e
@@ -121,19 +121,19 @@ append_all_versioned_params(pe_resource_t *rsc, pe_node_t *node,
23c78e
  * \internal
23c78e
  * \brief Add digest of all parameters to a digest cache entry
23c78e
  *
23c78e
- * \param[out] data        Digest cache entry to modify
23c78e
- * \param[in]  rsc         Resource that action was for
23c78e
- * \param[in]  node        Node action was performed on
23c78e
- * \param[in]  task        Name of action performed
23c78e
- * \param[in]  key         Action's task key
23c78e
- * \param[in]  xml_op      XML of operation in CIB status (if available)
23c78e
- * \param[in]  op_version  CRM feature set to use for digest calculation
23c78e
- * \param[in]  overrides   Key/value hash table to override resource parameters
23c78e
- * \param[in]  data_set    Cluster working set
23c78e
+ * \param[out]    data         Digest cache entry to modify
23c78e
+ * \param[in]     rsc          Resource that action was for
23c78e
+ * \param[in]     node         Node action was performed on
23c78e
+ * \param[in]     task         Name of action performed
23c78e
+ * \param[in,out] interval_ms  Action's interval (will be reset if in overrides)
23c78e
+ * \param[in]     xml_op       XML of operation in CIB status (if available)
23c78e
+ * \param[in]     op_version   CRM feature set to use for digest calculation
23c78e
+ * \param[in]     overrides    Key/value table to override resource parameters
23c78e
+ * \param[in]     data_set     Cluster working set
23c78e
  */
23c78e
 static void
23c78e
 calculate_main_digest(op_digest_cache_t *data, pe_resource_t *rsc,
23c78e
-                      pe_node_t *node, const char *task, const char *key,
23c78e
+                      pe_node_t *node, const char *task, guint *interval_ms,
23c78e
                       xmlNode *xml_op, const char *op_version,
23c78e
                       GHashTable *overrides, pe_working_set_t *data_set)
23c78e
 {
23c78e
@@ -153,7 +153,24 @@ calculate_main_digest(op_digest_cache_t *data, pe_resource_t *rsc,
23c78e
                   rsc->id, node->details->uname);
23c78e
     }
23c78e
 
23c78e
-    action = custom_action(rsc, strdup(key), task, node, TRUE, FALSE, data_set);
23c78e
+    // If interval was overridden, reset it
23c78e
+    if (overrides != NULL) {
23c78e
+        const char *interval_s = g_hash_table_lookup(overrides, CRM_META "_"
23c78e
+                                                     XML_LRM_ATTR_INTERVAL);
23c78e
+
23c78e
+        if (interval_s != NULL) {
23c78e
+            long long value_ll;
23c78e
+
23c78e
+            errno = 0;
23c78e
+            value_ll = crm_parse_ll(interval_s, NULL);
23c78e
+            if ((errno == 0) && (value_ll >= 0) && (value_ll <= G_MAXUINT)) {
23c78e
+                *interval_ms = (guint) value_ll;
23c78e
+            }
23c78e
+        }
23c78e
+    }
23c78e
+
23c78e
+    action = custom_action(rsc, pcmk__op_key(rsc->id, task, *interval_ms),
23c78e
+                           task, node, TRUE, FALSE, data_set);
23c78e
     if (overrides != NULL) {
23c78e
         g_hash_table_foreach(overrides, hash2field, data->params_all);
23c78e
     }
23c78e
@@ -280,21 +297,21 @@ calculate_restart_digest(op_digest_cache_t *data, xmlNode *xml_op,
23c78e
  * \internal
23c78e
  * \brief Create a new digest cache entry with calculated digests
23c78e
  *
23c78e
- * \param[in] rsc          Resource that action was for
23c78e
- * \param[in] task         Name of action performed
23c78e
- * \param[in] key          Action's task key
23c78e
- * \param[in] node         Node action was performed on
23c78e
- * \param[in] xml_op       XML of operation in CIB status (if available)
23c78e
- * \param[in] overrides    Key/value hash table to override resource parameters
23c78e
- * \param[in] calc_secure  Whether to calculate secure digest
23c78e
- * \param[in] data_set     Cluster working set
23c78e
+ * \param[in]     rsc          Resource that action was for
23c78e
+ * \param[in]     task         Name of action performed
23c78e
+ * \param[in,out] interval_ms  Action's interval (will be reset if in overrides)
23c78e
+ * \param[in]     node         Node action was performed on
23c78e
+ * \param[in]     xml_op       XML of operation in CIB status (if available)
23c78e
+ * \param[in]     overrides    Key/value table to override resource parameters
23c78e
+ * \param[in]     calc_secure  Whether to calculate secure digest
23c78e
+ * \param[in]     data_set     Cluster working set
23c78e
  *
23c78e
  * \return Pointer to new digest cache entry (or NULL on memory error)
23c78e
  * \note It is the caller's responsibility to free the result using
23c78e
  *       pe__free_digests().
23c78e
  */
23c78e
 op_digest_cache_t *
23c78e
-pe__calculate_digests(pe_resource_t *rsc, const char *task, const char *key,
23c78e
+pe__calculate_digests(pe_resource_t *rsc, const char *task, guint *interval_ms,
23c78e
                       pe_node_t *node, xmlNode *xml_op, GHashTable *overrides,
23c78e
                       bool calc_secure, pe_working_set_t *data_set)
23c78e
 {
23c78e
@@ -307,8 +324,9 @@ pe__calculate_digests(pe_resource_t *rsc, const char *task, const char *key,
23c78e
     if (xml_op != NULL) {
23c78e
         op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
23c78e
     }
23c78e
-    calculate_main_digest(data, rsc, node, task, key, xml_op, op_version,
23c78e
-                          overrides, data_set);
23c78e
+
23c78e
+    calculate_main_digest(data, rsc, node, task, interval_ms, xml_op,
23c78e
+                          op_version, overrides, data_set);
23c78e
     if (calc_secure) {
23c78e
         calculate_secure_digest(data, rsc, xml_op, op_version, overrides);
23c78e
     }
23c78e
@@ -322,7 +340,7 @@ pe__calculate_digests(pe_resource_t *rsc, const char *task, const char *key,
23c78e
  *
23c78e
  * \param[in] rsc          Resource that action was for
23c78e
  * \param[in] task         Name of action performed
23c78e
- * \param[in] key          Action's task key
23c78e
+ * \param[in] interval_ms  Action's interval
23c78e
  * \param[in] node         Node action was performed on
23c78e
  * \param[in] xml_op       XML of operation in CIB status (if available)
23c78e
  * \param[in] calc_secure  Whether to calculate secure digest
23c78e
@@ -331,29 +349,40 @@ pe__calculate_digests(pe_resource_t *rsc, const char *task, const char *key,
23c78e
  * \return Pointer to node's digest cache entry
23c78e
  */
23c78e
 static op_digest_cache_t *
23c78e
-rsc_action_digest(pe_resource_t *rsc, const char *task, const char *key,
23c78e
+rsc_action_digest(pe_resource_t *rsc, const char *task, guint interval_ms,
23c78e
                   pe_node_t *node, xmlNode *xml_op, bool calc_secure,
23c78e
                   pe_working_set_t *data_set)
23c78e
 {
23c78e
     op_digest_cache_t *data = NULL;
23c78e
+    char *key = pcmk__op_key(rsc->id, task, interval_ms);
23c78e
 
23c78e
     data = g_hash_table_lookup(node->details->digest_cache, key);
23c78e
     if (data == NULL) {
23c78e
-        data = pe__calculate_digests(rsc, task, key, node, xml_op, NULL,
23c78e
-                                     calc_secure, data_set);
23c78e
+        data = pe__calculate_digests(rsc, task, &interval_ms, node, xml_op,
23c78e
+                                     NULL, calc_secure, data_set);
23c78e
         CRM_ASSERT(data != NULL);
23c78e
         g_hash_table_insert(node->details->digest_cache, strdup(key), data);
23c78e
     }
23c78e
+    free(key);
23c78e
     return data;
23c78e
 }
23c78e
 
23c78e
+/*!
23c78e
+ * \internal
23c78e
+ * \brief Calculate operation digests and compare against an XML history entry
23c78e
+ *
23c78e
+ * \param[in] rsc       Resource to check
23c78e
+ * \param[in] xml_op    Resource history XML
23c78e
+ * \param[in] node      Node to use for digest calculation
23c78e
+ * \param[in] data_set  Cluster working set
23c78e
+ *
23c78e
+ * \return Pointer to node's digest cache entry, with comparison result set
23c78e
+ */
23c78e
 op_digest_cache_t *
23c78e
 rsc_action_digest_cmp(pe_resource_t * rsc, xmlNode * xml_op, pe_node_t * node,
23c78e
                       pe_working_set_t * data_set)
23c78e
 {
23c78e
     op_digest_cache_t *data = NULL;
23c78e
-
23c78e
-    char *key = NULL;
23c78e
     guint interval_ms = 0;
23c78e
 
23c78e
     const char *op_version;
23c78e
@@ -368,17 +397,18 @@ rsc_action_digest_cmp(pe_resource_t * rsc, xmlNode * xml_op, pe_node_t * node,
23c78e
     digest_restart = crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST);
23c78e
 
23c78e
     crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
23c78e
-    key = pcmk__op_key(rsc->id, task, interval_ms);
23c78e
-    data = rsc_action_digest(rsc, task, key, node, xml_op,
23c78e
+    data = rsc_action_digest(rsc, task, interval_ms, node, xml_op,
23c78e
                              pcmk_is_set(data_set->flags, pe_flag_sanitized),
23c78e
                              data_set);
23c78e
 
23c78e
     data->rc = RSC_DIGEST_MATCH;
23c78e
     if (digest_restart && data->digest_restart_calc && strcmp(data->digest_restart_calc, digest_restart) != 0) {
23c78e
-        pe_rsc_info(rsc, "Parameters to %s on %s changed: was %s vs. now %s (restart:%s) %s",
23c78e
-                 key, node->details->uname,
23c78e
-                 crm_str(digest_restart), data->digest_restart_calc,
23c78e
-                 op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
23c78e
+        pe_rsc_info(rsc, "Parameters to %ums-interval %s action for %s on %s "
23c78e
+                         "changed: hash was %s vs. now %s (restart:%s) %s",
23c78e
+                    interval_ms, task, rsc->id, node->details->uname,
23c78e
+                    crm_str(digest_restart), data->digest_restart_calc,
23c78e
+                    op_version,
23c78e
+                    crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
23c78e
         data->rc = RSC_DIGEST_RESTART;
23c78e
 
23c78e
     } else if (digest_all == NULL) {
23c78e
@@ -386,15 +416,15 @@ rsc_action_digest_cmp(pe_resource_t * rsc, xmlNode * xml_op, pe_node_t * node,
23c78e
         data->rc = RSC_DIGEST_UNKNOWN;
23c78e
 
23c78e
     } else if (strcmp(digest_all, data->digest_all_calc) != 0) {
23c78e
-        pe_rsc_info(rsc, "Parameters to %s on %s changed: was %s vs. now %s (%s:%s) %s",
23c78e
-                 key, node->details->uname,
23c78e
-                 crm_str(digest_all), data->digest_all_calc,
23c78e
-                 (interval_ms > 0)? "reschedule" : "reload",
23c78e
-                 op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
23c78e
+        pe_rsc_info(rsc, "Parameters to %ums-interval %s action for %s on %s "
23c78e
+                         "changed: hash was %s vs. now %s (%s:%s) %s",
23c78e
+                    interval_ms, task, rsc->id, node->details->uname,
23c78e
+                    crm_str(digest_all), data->digest_all_calc,
23c78e
+                    (interval_ms > 0)? "reschedule" : "reload",
23c78e
+                    op_version,
23c78e
+                    crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
23c78e
         data->rc = RSC_DIGEST_ALL;
23c78e
     }
23c78e
-
23c78e
-    free(key);
23c78e
     return data;
23c78e
 }
23c78e
 
23c78e
@@ -483,12 +513,9 @@ pe__compare_fencing_digest(pe_resource_t *rsc, const char *agent,
23c78e
     const char *node_summary = NULL;
23c78e
 
23c78e
     // Calculate device's current parameter digests
23c78e
-    char *key = pcmk__op_key(rsc->id, STONITH_DIGEST_TASK, 0);
23c78e
-    op_digest_cache_t *data = rsc_action_digest(rsc, STONITH_DIGEST_TASK, key,
23c78e
+    op_digest_cache_t *data = rsc_action_digest(rsc, STONITH_DIGEST_TASK, 0U,
23c78e
                                                 node, NULL, TRUE, data_set);
23c78e
 
23c78e
-    free(key);
23c78e
-
23c78e
     // Check whether node has special unfencing summary node attribute
23c78e
     node_summary = pe_node_attribute_raw(node, CRM_ATTR_DIGESTS_ALL);
23c78e
     if (node_summary == NULL) {
23c78e
-- 
23c78e
1.8.3.1
23c78e
23c78e
23c78e
From bf20b166b6e7dcf87edd398f2edfc384cb640886 Mon Sep 17 00:00:00 2001
23c78e
From: Ken Gaillot <kgaillot@redhat.com>
23c78e
Date: Mon, 23 Nov 2020 17:48:34 -0600
23c78e
Subject: [PATCH 09/12] Low: scheduler: don't include timeout in secure digests
23c78e
23c78e
... to match what the controller does
23c78e
---
23c78e
 lib/pengine/pe_digest.c | 11 +++++++++++
23c78e
 1 file changed, 11 insertions(+)
23c78e
23c78e
diff --git a/lib/pengine/pe_digest.c b/lib/pengine/pe_digest.c
23c78e
index b608f22..f55c896 100644
23c78e
--- a/lib/pengine/pe_digest.c
23c78e
+++ b/lib/pengine/pe_digest.c
23c78e
@@ -247,6 +247,17 @@ calculate_secure_digest(op_digest_cache_t *data, pe_resource_t *rsc,
23c78e
                                        NULL);
23c78e
     }
23c78e
     pcmk__filter_op_for_digest(data->params_secure);
23c78e
+
23c78e
+    /* CRM_meta_timeout *should* be part of a digest for recurring operations.
23c78e
+     * However, currently the controller does not add timeout to secure digests,
23c78e
+     * because it only includes parameters declared by the resource agent.
23c78e
+     * Remove any timeout that made it this far, to match.
23c78e
+     *
23c78e
+     * @TODO Update the controller to add the timeout (which will require
23c78e
+     * bumping the feature set and checking that here).
23c78e
+     */
23c78e
+    xml_remove_prop(data->params_secure, CRM_META "_" XML_ATTR_TIMEOUT);
23c78e
+
23c78e
     data->digest_secure_calc = calculate_operation_digest(data->params_secure,
23c78e
                                                           op_version);
23c78e
 }
23c78e
-- 
23c78e
1.8.3.1
23c78e
23c78e
23c78e
From a956e32a536942b0fc1f2f058e441b3faf2abdd3 Mon Sep 17 00:00:00 2001
23c78e
From: Ken Gaillot <kgaillot@redhat.com>
23c78e
Date: Thu, 7 Jan 2021 12:08:56 -0600
23c78e
Subject: [PATCH 10/12] Low: scheduler: treat NULL and empty string the same in
23c78e
 literal attribute comparisons
23c78e
23c78e
Previously, expand_value_source() returned NULL if the value was the empty
23c78e
string ("") only when value-source was "param" or "meta". If value-source was
23c78e
literal, it would return the empty string.
23c78e
23c78e
This behavior shouldn't depend on value-source, so it now returns NULL when a
23c78e
literal value is the empty string.
23c78e
23c78e
This could change the behavior for "defined"/"not_defined" checks, and
23c78e
comparisons against another NULL or empty string value (NULL compares less than
23c78e
empty strings). But the consistency seems worth it.
23c78e
23c78e
(Another question not addressed here is whether NULL and empty string should
23c78e
compare as equal.)
23c78e
---
23c78e
 lib/pengine/rules.c | 9 ++++++---
23c78e
 1 file changed, 6 insertions(+), 3 deletions(-)
23c78e
23c78e
diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c
23c78e
index aa5d6ab..d69f449 100644
23c78e
--- a/lib/pengine/rules.c
23c78e
+++ b/lib/pengine/rules.c
23c78e
@@ -1,5 +1,5 @@
23c78e
 /*
23c78e
- * Copyright 2004-2020 the Pacemaker project contributors
23c78e
+ * Copyright 2004-2021 the Pacemaker project contributors
23c78e
  *
23c78e
  * The version control history for this file may have further details.
23c78e
  *
23c78e
@@ -1039,7 +1039,10 @@ expand_value_source(const char *value, const char *value_source,
23c78e
 {
23c78e
     GHashTable *table = NULL;
23c78e
 
23c78e
-    if (pcmk__str_eq(value_source, "param", pcmk__str_casei)) {
23c78e
+    if (pcmk__str_empty(value)) {
23c78e
+        return NULL; // value_source is irrelevant
23c78e
+
23c78e
+    } else if (pcmk__str_eq(value_source, "param", pcmk__str_casei)) {
23c78e
         table = match_data->params;
23c78e
 
23c78e
     } else if (pcmk__str_eq(value_source, "meta", pcmk__str_casei)) {
23c78e
@@ -1049,7 +1052,7 @@ expand_value_source(const char *value, const char *value_source,
23c78e
         return value;
23c78e
     }
23c78e
 
23c78e
-    if ((table == NULL) || pcmk__str_empty(value)) {
23c78e
+    if (table == NULL) {
23c78e
         return NULL;
23c78e
     }
23c78e
     return (const char *) g_hash_table_lookup(table, value);
23c78e
-- 
23c78e
1.8.3.1
23c78e
23c78e
23c78e
From 2d7cd78340b47045b5987002c9b2d221ccb01ee9 Mon Sep 17 00:00:00 2001
23c78e
From: Ken Gaillot <kgaillot@redhat.com>
23c78e
Date: Thu, 7 Jan 2021 13:01:29 -0600
23c78e
Subject: [PATCH 11/12] Refactor: libcrmcommon: bail early if ACLs block
23c78e
 attribute removal
23c78e
23c78e
... for efficiency and fewer trace messages
23c78e
---
23c78e
 lib/common/xml.c | 9 ++++++---
23c78e
 1 file changed, 6 insertions(+), 3 deletions(-)
23c78e
23c78e
diff --git a/lib/common/xml.c b/lib/common/xml.c
23c78e
index 869ed51..8b71911 100644
23c78e
--- a/lib/common/xml.c
23c78e
+++ b/lib/common/xml.c
23c78e
@@ -1,5 +1,5 @@
23c78e
 /*
23c78e
- * Copyright 2004-2020 the Pacemaker project contributors
23c78e
+ * Copyright 2004-2021 the Pacemaker project contributors
23c78e
  *
23c78e
  * The version control history for this file may have further details.
23c78e
  *
23c78e
@@ -637,10 +637,13 @@ pcmk__xe_remove_matching_attrs(xmlNode *element,
23c78e
         next = a->next; // Grab now because attribute might get removed
23c78e
         if ((match == NULL) || match(a, user_data)) {
23c78e
             if (!pcmk__check_acl(element, NULL, xpf_acl_write)) {
23c78e
-                crm_trace("ACLs prevent removal of %s attribute from %s element",
23c78e
+                crm_trace("ACLs prevent removal of attributes (%s and "
23c78e
+                          "possibly others) from %s element",
23c78e
                           (const char *) a->name, (const char *) element->name);
23c78e
+                return; // ACLs apply to element, not particular attributes
23c78e
+            }
23c78e
 
23c78e
-            } else if (pcmk__tracking_xml_changes(element, false)) {
23c78e
+            if (pcmk__tracking_xml_changes(element, false)) {
23c78e
                 // Leave (marked for removal) until after diff is calculated
23c78e
                 set_parent_flag(element, xpf_dirty);
23c78e
                 pcmk__set_xml_flags((xml_private_t *) a->_private, xpf_deleted);
23c78e
-- 
23c78e
1.8.3.1
23c78e
23c78e
23c78e
From 459f7a58424b05b7c586906d904129a6408d6206 Mon Sep 17 00:00:00 2001
23c78e
From: Ken Gaillot <kgaillot@redhat.com>
23c78e
Date: Thu, 7 Jan 2021 13:30:40 -0600
23c78e
Subject: [PATCH 12/12] Refactor: libcrmcommon: drop a constant
23c78e
23c78e
It was only used once, and the code is actually more readable without it
23c78e
---
23c78e
 lib/common/operations.c | 26 +++++++++++++-------------
23c78e
 1 file changed, 13 insertions(+), 13 deletions(-)
23c78e
23c78e
diff --git a/lib/common/operations.c b/lib/common/operations.c
23c78e
index 421aaac..420f078 100644
23c78e
--- a/lib/common/operations.c
23c78e
+++ b/lib/common/operations.c
23c78e
@@ -1,5 +1,5 @@
23c78e
 /*
23c78e
- * Copyright 2004-2020 the Pacemaker project contributors
23c78e
+ * Copyright 2004-2021 the Pacemaker project contributors
23c78e
  *
23c78e
  * The version control history for this file may have further details.
23c78e
  *
23c78e
@@ -362,22 +362,22 @@ decode_transition_key(const char *key, char **uuid, int *transition_id, int *act
23c78e
     return TRUE;
23c78e
 }
23c78e
 
23c78e
-// String length of CRM_META"_"
23c78e
-#define CRM_META_LEN sizeof(CRM_META)
23c78e
-
23c78e
 // Return true if a is an attribute that should be filtered
23c78e
 static bool
23c78e
 should_filter_for_digest(xmlAttrPtr a, void *user_data)
23c78e
 {
23c78e
-    return (strncmp((const char *) a->name, CRM_META "_", CRM_META_LEN) == 0)
23c78e
-           || pcmk__str_any_of((const char *) a->name,
23c78e
-                               XML_ATTR_ID,
23c78e
-                               XML_ATTR_CRM_VERSION,
23c78e
-                               XML_LRM_ATTR_OP_DIGEST,
23c78e
-                               XML_LRM_ATTR_TARGET,
23c78e
-                               XML_LRM_ATTR_TARGET_UUID,
23c78e
-                               "pcmk_external_ip",
23c78e
-                               NULL);
23c78e
+    if (strncmp((const char *) a->name, CRM_META "_",
23c78e
+                sizeof(CRM_META " ") - 1) == 0) {
23c78e
+        return true;
23c78e
+    }
23c78e
+    return pcmk__str_any_of((const char *) a->name,
23c78e
+                            XML_ATTR_ID,
23c78e
+                            XML_ATTR_CRM_VERSION,
23c78e
+                            XML_LRM_ATTR_OP_DIGEST,
23c78e
+                            XML_LRM_ATTR_TARGET,
23c78e
+                            XML_LRM_ATTR_TARGET_UUID,
23c78e
+                            "pcmk_external_ip",
23c78e
+                            NULL);
23c78e
 }
23c78e
 
23c78e
 /*!
23c78e
-- 
23c78e
1.8.3.1
23c78e