Blame SOURCES/020-rhbz1872376.patch

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