Blame SOURCES/020-rhbz1872376.patch

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