a216ed
From a32b6e14ba51fefbda2d4a699cf1c48dd3a1bb5a Mon Sep 17 00:00:00 2001
a216ed
From: Chris Lumens <clumens@redhat.com>
a216ed
Date: Thu, 7 Jan 2021 11:37:51 -0500
a216ed
Subject: [PATCH 01/10] Fix: tools: Don't pass stonith history to
a216ed
 print_simple_status.
a216ed
a216ed
It's not being used.
a216ed
---
a216ed
 tools/crm_mon.c | 7 +++----
a216ed
 1 file changed, 3 insertions(+), 4 deletions(-)
a216ed
a216ed
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
a216ed
index 4555516..729f6a1 100644
a216ed
--- a/tools/crm_mon.c
a216ed
+++ b/tools/crm_mon.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
@@ -1451,14 +1451,13 @@ main(int argc, char **argv)
a216ed
  * \brief Print one-line status suitable for use with monitoring software
a216ed
  *
a216ed
  * \param[in] data_set  Working set of CIB state
a216ed
- * \param[in] history   List of stonith actions
a216ed
  *
a216ed
  * \note This function's output (and the return code when the program exits)
a216ed
  *       should conform to https://www.monitoring-plugins.org/doc/guidelines.html
a216ed
  */
a216ed
 static void
a216ed
 print_simple_status(pcmk__output_t *out, pe_working_set_t * data_set,
a216ed
-                    stonith_history_t *history, unsigned int mon_ops)
a216ed
+                    unsigned int mon_ops)
a216ed
 {
a216ed
     GListPtr gIter = NULL;
a216ed
     int nodes_online = 0;
a216ed
@@ -2012,7 +2011,7 @@ mon_refresh_display(gpointer user_data)
a216ed
             break;
a216ed
 
a216ed
         case mon_output_monitor:
a216ed
-            print_simple_status(out, mon_data_set, stonith_history, options.mon_ops);
a216ed
+            print_simple_status(out, mon_data_set, options.mon_ops);
a216ed
             if (pcmk_is_set(options.mon_ops, mon_op_has_warnings)) {
a216ed
                 clean_up(MON_STATUS_WARN);
a216ed
                 return FALSE;
a216ed
-- 
a216ed
1.8.3.1
a216ed
a216ed
a216ed
From 8b9c47089c70295bc0529671ba5991c6d831e14b Mon Sep 17 00:00:00 2001
a216ed
From: Chris Lumens <clumens@redhat.com>
a216ed
Date: Thu, 7 Jan 2021 13:17:04 -0500
a216ed
Subject: [PATCH 02/10] Refactor: tools: Don't pass output_format to
a216ed
 mon_refresh_display.
a216ed
a216ed
output_format is a global variable.
a216ed
---
a216ed
 tools/crm_mon.c | 2 +-
a216ed
 1 file changed, 1 insertion(+), 1 deletion(-)
a216ed
a216ed
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
a216ed
index 729f6a1..b801560 100644
a216ed
--- a/tools/crm_mon.c
a216ed
+++ b/tools/crm_mon.c
a216ed
@@ -827,7 +827,7 @@ cib_connect(gboolean full)
a216ed
 
a216ed
         rc = cib->cmds->query(cib, NULL, &current_cib, cib_scope_local | cib_sync_call);
a216ed
         if (rc == pcmk_ok) {
a216ed
-            mon_refresh_display(&output_format);
a216ed
+            mon_refresh_display(NULL);
a216ed
         }
a216ed
 
a216ed
         if (rc == pcmk_ok && full) {
a216ed
-- 
a216ed
1.8.3.1
a216ed
a216ed
a216ed
From a1b14ad96f12746167da8588dc086b20e6f6d1d6 Mon Sep 17 00:00:00 2001
a216ed
From: Chris Lumens <clumens@redhat.com>
a216ed
Date: Thu, 7 Jan 2021 13:20:14 -0500
a216ed
Subject: [PATCH 03/10] Refactor: tools: Remove unnecessary checks for cib !=
a216ed
 NULL.
a216ed
a216ed
cib is guaranteed to not be NULL at these points, so there's no need to
a216ed
do an additional check.  This code was leftover from a previous
a216ed
reorganization that changed when the cib variable gets initialized.
a216ed
---
a216ed
 tools/crm_mon.c | 41 +++++++++++++++++++----------------------
a216ed
 1 file changed, 19 insertions(+), 22 deletions(-)
a216ed
a216ed
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
a216ed
index b801560..1eedd38 100644
a216ed
--- a/tools/crm_mon.c
a216ed
+++ b/tools/crm_mon.c
a216ed
@@ -1346,7 +1346,7 @@ main(int argc, char **argv)
a216ed
 
a216ed
     /* Extra sanity checks when in CGI mode */
a216ed
     if (output_format == mon_output_cgi) {
a216ed
-        if (cib && cib->variant == cib_file) {
a216ed
+        if (cib->variant == cib_file) {
a216ed
             g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_USAGE, "CGI mode used with CIB file");
a216ed
             return clean_up(CRM_EX_USAGE);
a216ed
         } else if (options.external_agent != NULL) {
a216ed
@@ -1370,33 +1370,30 @@ main(int argc, char **argv)
a216ed
 
a216ed
     crm_info("Starting %s", crm_system_name);
a216ed
 
a216ed
-    if (cib) {
a216ed
-
a216ed
-        do {
a216ed
-            if (!pcmk_is_set(options.mon_ops, mon_op_one_shot)) {
a216ed
-                print_as(output_format ,"Waiting until cluster is available on this node ...\n");
a216ed
-            }
a216ed
-            rc = cib_connect(!pcmk_is_set(options.mon_ops, mon_op_one_shot));
a216ed
+    do {
a216ed
+        if (!pcmk_is_set(options.mon_ops, mon_op_one_shot)) {
a216ed
+            print_as(output_format ,"Waiting until cluster is available on this node ...\n");
a216ed
+        }
a216ed
+        rc = cib_connect(!pcmk_is_set(options.mon_ops, mon_op_one_shot));
a216ed
 
a216ed
-            if (pcmk_is_set(options.mon_ops, mon_op_one_shot)) {
a216ed
-                break;
a216ed
+        if (pcmk_is_set(options.mon_ops, mon_op_one_shot)) {
a216ed
+            break;
a216ed
 
a216ed
-            } else if (rc != pcmk_ok) {
a216ed
-                sleep(options.reconnect_msec / 1000);
a216ed
+        } else if (rc != pcmk_ok) {
a216ed
+            sleep(options.reconnect_msec / 1000);
a216ed
 #if CURSES_ENABLED
a216ed
-                if (output_format == mon_output_console) {
a216ed
-                    clear();
a216ed
-                    refresh();
a216ed
-                }
a216ed
+            if (output_format == mon_output_console) {
a216ed
+                clear();
a216ed
+                refresh();
a216ed
+            }
a216ed
 #endif
a216ed
-            } else {
a216ed
-                if (output_format == mon_output_html && out->dest != stdout) {
a216ed
-                    printf("Writing html to %s ...\n", args->output_dest);
a216ed
-                }
a216ed
+        } else {
a216ed
+            if (output_format == mon_output_html && out->dest != stdout) {
a216ed
+                printf("Writing html to %s ...\n", args->output_dest);
a216ed
             }
a216ed
+        }
a216ed
 
a216ed
-        } while (rc == -ENOTCONN);
a216ed
-    }
a216ed
+    } while (rc == -ENOTCONN);
a216ed
 
a216ed
     if (rc != pcmk_ok) {
a216ed
         if (output_format == mon_output_monitor) {
a216ed
-- 
a216ed
1.8.3.1
a216ed
a216ed
a216ed
From fe5284a12765e775905bdfe58711c5733a063132 Mon Sep 17 00:00:00 2001
a216ed
From: Chris Lumens <clumens@redhat.com>
a216ed
Date: Thu, 7 Jan 2021 14:15:40 -0500
a216ed
Subject: [PATCH 04/10] Fix: tools: mon_refresh_display should return an int.
a216ed
a216ed
While GSourceFunc is defined as returning a boolean, our public API
a216ed
mainloop function expect the dispatch function to return an int.  So
a216ed
change mon_refresh_display to do so.
a216ed
---
a216ed
 tools/crm_mon.c | 12 ++++++------
a216ed
 1 file changed, 6 insertions(+), 6 deletions(-)
a216ed
a216ed
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
a216ed
index 1eedd38..8657a89 100644
a216ed
--- a/tools/crm_mon.c
a216ed
+++ b/tools/crm_mon.c
a216ed
@@ -125,7 +125,7 @@ struct {
a216ed
 static void clean_up_connections(void);
a216ed
 static crm_exit_t clean_up(crm_exit_t exit_code);
a216ed
 static void crm_diff_update(const char *event, xmlNode * msg);
a216ed
-static gboolean mon_refresh_display(gpointer user_data);
a216ed
+static int mon_refresh_display(gpointer user_data);
a216ed
 static int cib_connect(gboolean full);
a216ed
 static void mon_st_callback_event(stonith_t * st, stonith_event_t * e);
a216ed
 static void mon_st_callback_display(stonith_t * st, stonith_event_t * e);
a216ed
@@ -1925,7 +1925,7 @@ crm_diff_update(const char *event, xmlNode * msg)
a216ed
     kick_refresh(cib_updated);
a216ed
 }
a216ed
 
a216ed
-static gboolean
a216ed
+static int
a216ed
 mon_refresh_display(gpointer user_data)
a216ed
 {
a216ed
     xmlNode *cib_copy = copy_xml(current_cib);
a216ed
@@ -1940,7 +1940,7 @@ mon_refresh_display(gpointer user_data)
a216ed
         }
a216ed
         out->err(out, "Upgrade failed: %s", pcmk_strerror(-pcmk_err_schema_validation));
a216ed
         clean_up(CRM_EX_CONFIG);
a216ed
-        return FALSE;
a216ed
+        return 0;
a216ed
     }
a216ed
 
a216ed
     /* get the stonith-history if there is evidence we need it
a216ed
@@ -1966,7 +1966,7 @@ mon_refresh_display(gpointer user_data)
a216ed
         }
a216ed
         free_xml(cib_copy);
a216ed
         out->err(out, "Reading stonith-history failed");
a216ed
-        return FALSE;
a216ed
+        return 0;
a216ed
     }
a216ed
 
a216ed
     if (mon_data_set == NULL) {
a216ed
@@ -1995,7 +1995,7 @@ mon_refresh_display(gpointer user_data)
a216ed
                                   options.only_node, options.only_rsc) != 0) {
a216ed
                 g_set_error(&error, PCMK__EXITC_ERROR, CRM_EX_CANTCREAT, "Critical: Unable to output html file");
a216ed
                 clean_up(CRM_EX_CANTCREAT);
a216ed
-                return FALSE;
a216ed
+                return 0;
a216ed
             }
a216ed
             break;
a216ed
 
a216ed
@@ -2044,7 +2044,7 @@ mon_refresh_display(gpointer user_data)
a216ed
     stonith_history_free(stonith_history);
a216ed
     stonith_history = NULL;
a216ed
     pe_reset_working_set(mon_data_set);
a216ed
-    return TRUE;
a216ed
+    return 1;
a216ed
 }
a216ed
 
a216ed
 static void
a216ed
-- 
a216ed
1.8.3.1
a216ed
a216ed
a216ed
From 7f88a5a428ed73fb5161096ece2517abe1119f06 Mon Sep 17 00:00:00 2001
a216ed
From: Chris Lumens <clumens@redhat.com>
a216ed
Date: Thu, 7 Jan 2021 16:59:02 -0500
a216ed
Subject: [PATCH 05/10] Refactor: tools: Change a conditional in cib_connect.
a216ed
a216ed
This allows unindenting everything that occurs inside that conditional,
a216ed
which I think makes it a little bit easier to understand what is going
a216ed
on.
a216ed
---
a216ed
 tools/crm_mon.c | 86 +++++++++++++++++++++++++++++----------------------------
a216ed
 1 file changed, 44 insertions(+), 42 deletions(-)
a216ed
a216ed
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
a216ed
index 8657a89..b8ba56b 100644
a216ed
--- a/tools/crm_mon.c
a216ed
+++ b/tools/crm_mon.c
a216ed
@@ -804,55 +804,57 @@ cib_connect(gboolean full)
a216ed
         }
a216ed
     }
a216ed
 
a216ed
-    if (cib->state != cib_connected_query && cib->state != cib_connected_command) {
a216ed
-        crm_trace("Connecting to the CIB");
a216ed
-
a216ed
-        /* Hack: the CIB signon will print the prompt for a password if needed,
a216ed
-         * but to stderr. If we're in curses, show it on the screen instead.
a216ed
-         *
a216ed
-         * @TODO Add a password prompt (maybe including input) function to
a216ed
-         *       pcmk__output_t and use it in libcib.
a216ed
-         */
a216ed
-        if ((output_format == mon_output_console) && need_pass && (cib->variant == cib_remote)) {
a216ed
-            need_pass = FALSE;
a216ed
-            print_as(output_format, "Password:");
a216ed
-        }
a216ed
+    if (cib->state == cib_connected_query || cib->state == cib_connected_command) {
a216ed
+        return rc;
a216ed
+    }
a216ed
 
a216ed
-        rc = cib->cmds->signon(cib, crm_system_name, cib_query);
a216ed
-        if (rc != pcmk_ok) {
a216ed
-            out->err(out, "Could not connect to the CIB: %s",
a216ed
-                     pcmk_strerror(rc));
a216ed
-            return rc;
a216ed
-        }
a216ed
+    crm_trace("Connecting to the CIB");
a216ed
 
a216ed
-        rc = cib->cmds->query(cib, NULL, &current_cib, cib_scope_local | cib_sync_call);
a216ed
-        if (rc == pcmk_ok) {
a216ed
-            mon_refresh_display(NULL);
a216ed
-        }
a216ed
+    /* Hack: the CIB signon will print the prompt for a password if needed,
a216ed
+     * but to stderr. If we're in curses, show it on the screen instead.
a216ed
+     *
a216ed
+     * @TODO Add a password prompt (maybe including input) function to
a216ed
+     *       pcmk__output_t and use it in libcib.
a216ed
+     */
a216ed
+    if ((output_format == mon_output_console) && need_pass && (cib->variant == cib_remote)) {
a216ed
+        need_pass = FALSE;
a216ed
+        print_as(output_format, "Password:");
a216ed
+    }
a216ed
 
a216ed
-        if (rc == pcmk_ok && full) {
a216ed
-            if (rc == pcmk_ok) {
a216ed
-                rc = cib->cmds->set_connection_dnotify(cib, mon_cib_connection_destroy_regular);
a216ed
-                if (rc == -EPROTONOSUPPORT) {
a216ed
-                    print_as
a216ed
-                        (output_format, "Notification setup not supported, won't be able to reconnect after failure");
a216ed
-                    if (output_format == mon_output_console) {
a216ed
-                        sleep(2);
a216ed
-                    }
a216ed
-                    rc = pcmk_ok;
a216ed
-                }
a216ed
+    rc = cib->cmds->signon(cib, crm_system_name, cib_query);
a216ed
+    if (rc != pcmk_ok) {
a216ed
+        out->err(out, "Could not connect to the CIB: %s",
a216ed
+                 pcmk_strerror(rc));
a216ed
+        return rc;
a216ed
+    }
a216ed
 
a216ed
-            }
a216ed
+    rc = cib->cmds->query(cib, NULL, &current_cib, cib_scope_local | cib_sync_call);
a216ed
+    if (rc == pcmk_ok) {
a216ed
+        mon_refresh_display(NULL);
a216ed
+    }
a216ed
 
a216ed
-            if (rc == pcmk_ok) {
a216ed
-                cib->cmds->del_notify_callback(cib, T_CIB_DIFF_NOTIFY, crm_diff_update);
a216ed
-                rc = cib->cmds->add_notify_callback(cib, T_CIB_DIFF_NOTIFY, crm_diff_update);
a216ed
+    if (rc == pcmk_ok && full) {
a216ed
+        if (rc == pcmk_ok) {
a216ed
+            rc = cib->cmds->set_connection_dnotify(cib, mon_cib_connection_destroy_regular);
a216ed
+            if (rc == -EPROTONOSUPPORT) {
a216ed
+                print_as
a216ed
+                    (output_format, "Notification setup not supported, won't be able to reconnect after failure");
a216ed
+                if (output_format == mon_output_console) {
a216ed
+                    sleep(2);
a216ed
+                }
a216ed
+                rc = pcmk_ok;
a216ed
             }
a216ed
 
a216ed
-            if (rc != pcmk_ok) {
a216ed
-                out->err(out, "Notification setup failed, could not monitor CIB actions");
a216ed
-                clean_up_connections();
a216ed
-            }
a216ed
+        }
a216ed
+
a216ed
+        if (rc == pcmk_ok) {
a216ed
+            cib->cmds->del_notify_callback(cib, T_CIB_DIFF_NOTIFY, crm_diff_update);
a216ed
+            rc = cib->cmds->add_notify_callback(cib, T_CIB_DIFF_NOTIFY, crm_diff_update);
a216ed
+        }
a216ed
+
a216ed
+        if (rc != pcmk_ok) {
a216ed
+            out->err(out, "Notification setup failed, could not monitor CIB actions");
a216ed
+            clean_up_connections();
a216ed
         }
a216ed
     }
a216ed
     return rc;
a216ed
-- 
a216ed
1.8.3.1
a216ed
a216ed
a216ed
From 178ba17e4ee62bef28f8e71cad2c002f823661b5 Mon Sep 17 00:00:00 2001
a216ed
From: Chris Lumens <clumens@redhat.com>
a216ed
Date: Thu, 7 Jan 2021 17:37:36 -0500
a216ed
Subject: [PATCH 06/10] Refactor: tools: Remove an unnecessary conditional in
a216ed
 cib_connect.
a216ed
a216ed
---
a216ed
 tools/crm_mon.c | 17 +++++++----------
a216ed
 1 file changed, 7 insertions(+), 10 deletions(-)
a216ed
a216ed
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
a216ed
index b8ba56b..36249e8 100644
a216ed
--- a/tools/crm_mon.c
a216ed
+++ b/tools/crm_mon.c
a216ed
@@ -834,17 +834,14 @@ cib_connect(gboolean full)
a216ed
     }
a216ed
 
a216ed
     if (rc == pcmk_ok && full) {
a216ed
-        if (rc == pcmk_ok) {
a216ed
-            rc = cib->cmds->set_connection_dnotify(cib, mon_cib_connection_destroy_regular);
a216ed
-            if (rc == -EPROTONOSUPPORT) {
a216ed
-                print_as
a216ed
-                    (output_format, "Notification setup not supported, won't be able to reconnect after failure");
a216ed
-                if (output_format == mon_output_console) {
a216ed
-                    sleep(2);
a216ed
-                }
a216ed
-                rc = pcmk_ok;
a216ed
+        rc = cib->cmds->set_connection_dnotify(cib, mon_cib_connection_destroy_regular);
a216ed
+        if (rc == -EPROTONOSUPPORT) {
a216ed
+            print_as
a216ed
+                (output_format, "Notification setup not supported, won't be able to reconnect after failure");
a216ed
+            if (output_format == mon_output_console) {
a216ed
+                sleep(2);
a216ed
             }
a216ed
-
a216ed
+            rc = pcmk_ok;
a216ed
         }
a216ed
 
a216ed
         if (rc == pcmk_ok) {
a216ed
-- 
a216ed
1.8.3.1
a216ed
a216ed
a216ed
From 33bac5886417afc5c7bbf56f4d31e0e36f8ae947 Mon Sep 17 00:00:00 2001
a216ed
From: Chris Lumens <clumens@redhat.com>
a216ed
Date: Fri, 8 Jan 2021 10:00:50 -0500
a216ed
Subject: [PATCH 07/10] Refactor: tools: Simplify another conditional in
a216ed
 crm_mon.
a216ed
a216ed
---
a216ed
 tools/crm_mon.c | 6 ++----
a216ed
 1 file changed, 2 insertions(+), 4 deletions(-)
a216ed
a216ed
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
a216ed
index 36249e8..8b47bbc 100644
a216ed
--- a/tools/crm_mon.c
a216ed
+++ b/tools/crm_mon.c
a216ed
@@ -1386,10 +1386,8 @@ main(int argc, char **argv)
a216ed
                 refresh();
a216ed
             }
a216ed
 #endif
a216ed
-        } else {
a216ed
-            if (output_format == mon_output_html && out->dest != stdout) {
a216ed
-                printf("Writing html to %s ...\n", args->output_dest);
a216ed
-            }
a216ed
+        } else if (output_format == mon_output_html && out->dest != stdout) {
a216ed
+            printf("Writing html to %s ...\n", args->output_dest);
a216ed
         }
a216ed
 
a216ed
     } while (rc == -ENOTCONN);
a216ed
-- 
a216ed
1.8.3.1
a216ed
a216ed
a216ed
From 40bc8b3147e7ebef4318211fa69973a8b5d32e79 Mon Sep 17 00:00:00 2001
a216ed
From: Chris Lumens <clumens@redhat.com>
a216ed
Date: Fri, 8 Jan 2021 12:12:37 -0500
a216ed
Subject: [PATCH 08/10] Refactor: libcrmcommon,tools,daemons: Put common xpath
a216ed
 code in one place.
a216ed
a216ed
---
a216ed
 configure.ac                                      |  1 +
a216ed
 daemons/controld/controld_te_callbacks.c          | 26 +++-----------
a216ed
 include/crm/common/xml_internal.h                 | 14 +++++++-
a216ed
 lib/common/tests/Makefile.am                      |  2 +-
a216ed
 lib/common/tests/xpath/Makefile.am                | 29 +++++++++++++++
a216ed
 lib/common/tests/xpath/pcmk__xpath_node_id_test.c | 43 +++++++++++++++++++++++
a216ed
 lib/common/xpath.c                                | 34 +++++++++++++++++-
a216ed
 tools/crm_mon.c                                   | 25 ++-----------
a216ed
 8 files changed, 127 insertions(+), 47 deletions(-)
a216ed
 create mode 100644 lib/common/tests/xpath/Makefile.am
a216ed
 create mode 100644 lib/common/tests/xpath/pcmk__xpath_node_id_test.c
a216ed
a216ed
diff --git a/configure.ac b/configure.ac
a216ed
index 5959116..ce0f1fe 100644
a216ed
--- a/configure.ac
a216ed
+++ b/configure.ac
a216ed
@@ -1920,6 +1920,7 @@ AC_CONFIG_FILES(Makefile                                            \
a216ed
                 lib/common/tests/operations/Makefile                \
a216ed
                 lib/common/tests/strings/Makefile                   \
a216ed
                 lib/common/tests/utils/Makefile                     \
a216ed
+                lib/common/tests/xpath/Makefile                     \
a216ed
                 lib/cluster/Makefile                                \
a216ed
                 lib/cib/Makefile                                    \
a216ed
                 lib/gnu/Makefile                                    \
a216ed
diff --git a/daemons/controld/controld_te_callbacks.c b/daemons/controld/controld_te_callbacks.c
a216ed
index 66fc645..4e3e4e6 100644
a216ed
--- a/daemons/controld/controld_te_callbacks.c
a216ed
+++ b/daemons/controld/controld_te_callbacks.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
@@ -276,24 +276,6 @@ process_resource_updates(const char *node, xmlNode *xml, xmlNode *change,
a216ed
     }
a216ed
 }
a216ed
 
a216ed
-#define NODE_PATT "/lrm[@id="
a216ed
-static char *get_node_from_xpath(const char *xpath) 
a216ed
-{
a216ed
-    char *nodeid = NULL;
a216ed
-    char *tmp = strstr(xpath, NODE_PATT);
a216ed
-
a216ed
-    if(tmp) {
a216ed
-        tmp += strlen(NODE_PATT);
a216ed
-        tmp += 1;
a216ed
-
a216ed
-        nodeid = strdup(tmp);
a216ed
-        tmp = strstr(nodeid, "\'");
a216ed
-        CRM_ASSERT(tmp);
a216ed
-        tmp[0] = 0;
a216ed
-    }
a216ed
-    return nodeid;
a216ed
-}
a216ed
-
a216ed
 static char *extract_node_uuid(const char *xpath) 
a216ed
 {
a216ed
     char *mutable_path = strdup(xpath);
a216ed
@@ -522,19 +504,19 @@ te_update_diff_v2(xmlNode *diff)
a216ed
             process_resource_updates(ID(match), match, change, op, xpath);
a216ed
 
a216ed
         } else if (strcmp(name, XML_LRM_TAG_RESOURCES) == 0) {
a216ed
-            char *local_node = get_node_from_xpath(xpath);
a216ed
+            char *local_node = pcmk__xpath_node_id(xpath, "lrm");
a216ed
 
a216ed
             process_resource_updates(local_node, match, change, op, xpath);
a216ed
             free(local_node);
a216ed
 
a216ed
         } else if (strcmp(name, XML_LRM_TAG_RESOURCE) == 0) {
a216ed
-            char *local_node = get_node_from_xpath(xpath);
a216ed
+            char *local_node = pcmk__xpath_node_id(xpath, "lrm");
a216ed
 
a216ed
             process_lrm_resource_diff(match, local_node);
a216ed
             free(local_node);
a216ed
 
a216ed
         } else if (strcmp(name, XML_LRM_TAG_RSC_OP) == 0) {
a216ed
-            char *local_node = get_node_from_xpath(xpath);
a216ed
+            char *local_node = pcmk__xpath_node_id(xpath, "lrm");
a216ed
 
a216ed
             process_graph_event(match, local_node);
a216ed
             free(local_node);
a216ed
diff --git a/include/crm/common/xml_internal.h b/include/crm/common/xml_internal.h
a216ed
index 1e80bc6..d8694ee 100644
a216ed
--- a/include/crm/common/xml_internal.h
a216ed
+++ b/include/crm/common/xml_internal.h
a216ed
@@ -1,5 +1,5 @@
a216ed
 /*
a216ed
- * Copyright 2017-2020 the Pacemaker project contributors
a216ed
+ * Copyright 2017-2021 the Pacemaker project contributors
a216ed
  *
a216ed
  * The version control history for this file may have further details.
a216ed
  *
a216ed
@@ -273,4 +273,16 @@ pcmk__xe_first_attr(const xmlNode *xe)
a216ed
     return (xe == NULL)? NULL : xe->properties;
a216ed
 }
a216ed
 
a216ed
+/*!
a216ed
+ * \internal
a216ed
+ * \brief Extract the ID attribute from an XML element
a216ed
+ *
a216ed
+ * \param[in] xpath String to search
a216ed
+ * \param[in] node  Node to get the ID for
a216ed
+ *
a216ed
+ * \return ID attribute of \p node in xpath string \p xpath
a216ed
+ */
a216ed
+char *
a216ed
+pcmk__xpath_node_id(const char *xpath, const char *node);
a216ed
+
a216ed
 #endif // PCMK__XML_INTERNAL__H
a216ed
diff --git a/lib/common/tests/Makefile.am b/lib/common/tests/Makefile.am
a216ed
index 2c33cc5..4c6e8b4 100644
a216ed
--- a/lib/common/tests/Makefile.am
a216ed
+++ b/lib/common/tests/Makefile.am
a216ed
@@ -1 +1 @@
a216ed
-SUBDIRS = agents cmdline flags operations strings utils
a216ed
+SUBDIRS = agents cmdline flags operations strings utils xpath
a216ed
diff --git a/lib/common/tests/xpath/Makefile.am b/lib/common/tests/xpath/Makefile.am
a216ed
new file mode 100644
a216ed
index 0000000..7a53683
a216ed
--- /dev/null
a216ed
+++ b/lib/common/tests/xpath/Makefile.am
a216ed
@@ -0,0 +1,29 @@
a216ed
+#
a216ed
+# Copyright 2021 the Pacemaker project contributors
a216ed
+#
a216ed
+# The version control history for this file may have further details.
a216ed
+#
a216ed
+# This source code is licensed under the GNU General Public License version 2
a216ed
+# or later (GPLv2+) WITHOUT ANY WARRANTY.
a216ed
+#
a216ed
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
a216ed
+LDADD = $(top_builddir)/lib/common/libcrmcommon.la
a216ed
+
a216ed
+include $(top_srcdir)/mk/glib-tap.mk
a216ed
+
a216ed
+# Add each test program here.  Each test should be written as a little standalone
a216ed
+# program using the glib unit testing functions.  See the documentation for more
a216ed
+# information.
a216ed
+#
a216ed
+# https://developer.gnome.org/glib/unstable/glib-Testing.html
a216ed
+#
a216ed
+# Add "_test" to the end of all test program names to simplify .gitignore.
a216ed
+test_programs =	pcmk__xpath_node_id_test
a216ed
+
a216ed
+# If any extra data needs to be added to the source distribution, add it to the
a216ed
+# following list.
a216ed
+dist_test_data =
a216ed
+
a216ed
+# If any extra data needs to be used by tests but should not be added to the
a216ed
+# source distribution, add it to the following list.
a216ed
+test_data =
a216ed
diff --git a/lib/common/tests/xpath/pcmk__xpath_node_id_test.c b/lib/common/tests/xpath/pcmk__xpath_node_id_test.c
a216ed
new file mode 100644
a216ed
index 0000000..f6b5c10
a216ed
--- /dev/null
a216ed
+++ b/lib/common/tests/xpath/pcmk__xpath_node_id_test.c
a216ed
@@ -0,0 +1,43 @@
a216ed
+/*
a216ed
+ * Copyright 2021 the Pacemaker project contributors
a216ed
+ *
a216ed
+ * The version control history for this file may have further details.
a216ed
+ *
a216ed
+ * This source code is licensed under the GNU Lesser General Public License
a216ed
+ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
a216ed
+ */
a216ed
+
a216ed
+#include <crm_internal.h>
a216ed
+#include <crm/common/xml_internal.h>
a216ed
+
a216ed
+static void
a216ed
+empty_input(void) {
a216ed
+    g_assert_null(pcmk__xpath_node_id(NULL, "lrm"));
a216ed
+    g_assert_null(pcmk__xpath_node_id("", "lrm"));
a216ed
+    g_assert_null(pcmk__xpath_node_id("/blah/blah", NULL));
a216ed
+    g_assert_null(pcmk__xpath_node_id("/blah/blah", ""));
a216ed
+    g_assert_null(pcmk__xpath_node_id(NULL, NULL));
a216ed
+}
a216ed
+
a216ed
+static void
a216ed
+not_present(void) {
a216ed
+    g_assert_null(pcmk__xpath_node_id("/some/xpath/string[@id='xyz']", "lrm"));
a216ed
+    g_assert_null(pcmk__xpath_node_id("/some/xpath/containing[@id='lrm']", "lrm"));
a216ed
+}
a216ed
+
a216ed
+static void
a216ed
+present(void) {
a216ed
+    g_assert_cmpint(strcmp(pcmk__xpath_node_id("/some/xpath/containing/lrm[@id='xyz']", "lrm"), "xyz"), ==, 0);
a216ed
+    g_assert_cmpint(strcmp(pcmk__xpath_node_id("/some/other/lrm[@id='xyz']/xpath", "lrm"), "xyz"), ==, 0);
a216ed
+}
a216ed
+
a216ed
+int
a216ed
+main(int argc, char **argv)
a216ed
+{
a216ed
+    g_test_init(&argc, &argv, NULL);
a216ed
+
a216ed
+    g_test_add_func("/common/xpath/node_id/empty_input", empty_input);
a216ed
+    g_test_add_func("/common/xpath/node_id/not_present", not_present);
a216ed
+    g_test_add_func("/common/xpath/node_id/present", present);
a216ed
+    return g_test_run();
a216ed
+}
a216ed
diff --git a/lib/common/xpath.c b/lib/common/xpath.c
a216ed
index 6fa4941..7851a7c 100644
a216ed
--- a/lib/common/xpath.c
a216ed
+++ b/lib/common/xpath.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
@@ -11,6 +11,7 @@
a216ed
 #include <stdio.h>
a216ed
 #include <string.h>
a216ed
 #include <crm/msg_xml.h>
a216ed
+#include <crm/common/xml_internal.h>
a216ed
 #include "crmcommon_private.h"
a216ed
 
a216ed
 /*
a216ed
@@ -297,3 +298,34 @@ xml_get_path(xmlNode *xml)
a216ed
     }
a216ed
     return NULL;
a216ed
 }
a216ed
+
a216ed
+char *
a216ed
+pcmk__xpath_node_id(const char *xpath, const char *node)
a216ed
+{
a216ed
+    char *retval = NULL;
a216ed
+    char *patt = NULL;
a216ed
+    char *start = NULL;
a216ed
+    char *end = NULL;
a216ed
+
a216ed
+    if (node == NULL || xpath == NULL) {
a216ed
+        return retval;
a216ed
+    }
a216ed
+
a216ed
+    patt = crm_strdup_printf("/%s[@id=", node);
a216ed
+    start = strstr(xpath, patt);
a216ed
+
a216ed
+    if (!start) {
a216ed
+        free(patt);
a216ed
+        return retval;
a216ed
+    }
a216ed
+
a216ed
+    start += strlen(patt);
a216ed
+    start++;
a216ed
+
a216ed
+    end = strstr(start, "\'");
a216ed
+    CRM_ASSERT(end);
a216ed
+    retval = strndup(start, end-start);
a216ed
+
a216ed
+    free(patt);
a216ed
+    return retval;
a216ed
+}
a216ed
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
a216ed
index 8b47bbc..ff1b86b 100644
a216ed
--- a/tools/crm_mon.c
a216ed
+++ b/tools/crm_mon.c
a216ed
@@ -1719,25 +1719,6 @@ mon_trigger_refresh(gpointer user_data)
a216ed
     return FALSE;
a216ed
 }
a216ed
 
a216ed
-#define NODE_PATT "/lrm[@id="
a216ed
-static char *
a216ed
-get_node_from_xpath(const char *xpath)
a216ed
-{
a216ed
-    char *nodeid = NULL;
a216ed
-    char *tmp = strstr(xpath, NODE_PATT);
a216ed
-
a216ed
-    if(tmp) {
a216ed
-        tmp += strlen(NODE_PATT);
a216ed
-        tmp += 1;
a216ed
-
a216ed
-        nodeid = strdup(tmp);
a216ed
-        tmp = strstr(nodeid, "\'");
a216ed
-        CRM_ASSERT(tmp);
a216ed
-        tmp[0] = 0;
a216ed
-    }
a216ed
-    return nodeid;
a216ed
-}
a216ed
-
a216ed
 static void
a216ed
 crm_diff_update_v2(const char *event, xmlNode * msg)
a216ed
 {
a216ed
@@ -1822,19 +1803,19 @@ crm_diff_update_v2(const char *event, xmlNode * msg)
a216ed
             handle_rsc_op(match, node);
a216ed
 
a216ed
         } else if(strcmp(name, XML_LRM_TAG_RESOURCES) == 0) {
a216ed
-            char *local_node = get_node_from_xpath(xpath);
a216ed
+            char *local_node = pcmk__xpath_node_id(xpath, "lrm");
a216ed
 
a216ed
             handle_rsc_op(match, local_node);
a216ed
             free(local_node);
a216ed
 
a216ed
         } else if(strcmp(name, XML_LRM_TAG_RESOURCE) == 0) {
a216ed
-            char *local_node = get_node_from_xpath(xpath);
a216ed
+            char *local_node = pcmk__xpath_node_id(xpath, "lrm");
a216ed
 
a216ed
             handle_rsc_op(match, local_node);
a216ed
             free(local_node);
a216ed
 
a216ed
         } else if(strcmp(name, XML_LRM_TAG_RSC_OP) == 0) {
a216ed
-            char *local_node = get_node_from_xpath(xpath);
a216ed
+            char *local_node = pcmk__xpath_node_id(xpath, "lrm");
a216ed
 
a216ed
             handle_rsc_op(match, local_node);
a216ed
             free(local_node);
a216ed
-- 
a216ed
1.8.3.1
a216ed
a216ed
a216ed
From b0126373d8b2a739ec5b985a7e1f530e850618d3 Mon Sep 17 00:00:00 2001
a216ed
From: Chris Lumens <clumens@redhat.com>
a216ed
Date: Mon, 11 Jan 2021 10:20:11 -0500
a216ed
Subject: [PATCH 09/10] Refactor: libpacemaker: Move reduce_stonith_history
a216ed
 into the library.
a216ed
a216ed
And also rename it to pcmk__reduce_fence_history.  I don't see anywhere
a216ed
else that could use this function at the moment, but it seems too
a216ed
generic to keep in crm_mon.
a216ed
---
a216ed
 include/pcmki/pcmki_fence.h | 16 +++++++++++++-
a216ed
 lib/pacemaker/pcmk_fence.c  | 45 ++++++++++++++++++++++++++++++++++++++-
a216ed
 tools/crm_mon.c             | 52 +--------------------------------------------
a216ed
 3 files changed, 60 insertions(+), 53 deletions(-)
a216ed
a216ed
diff --git a/include/pcmki/pcmki_fence.h b/include/pcmki/pcmki_fence.h
a216ed
index 241d030..d4cef68 100644
a216ed
--- a/include/pcmki/pcmki_fence.h
a216ed
+++ b/include/pcmki/pcmki_fence.h
a216ed
@@ -1,5 +1,5 @@
a216ed
 /*
a216ed
- * Copyright 2019-2020 the Pacemaker project contributors
a216ed
+ * Copyright 2019-2021 the Pacemaker project contributors
a216ed
  *
a216ed
  * The version control history for this file may have further details.
a216ed
  *
a216ed
@@ -219,4 +219,18 @@ int pcmk__fence_validate(pcmk__output_t *out, stonith_t *st, const char *agent,
a216ed
                          const char *id, stonith_key_value_t *params,
a216ed
                          unsigned int timeout);
a216ed
 
a216ed
+/**
a216ed
+ * \brief Reduce the STONITH history
a216ed
+ *
a216ed
+ * STONITH history is reduced as follows:
a216ed
+ *  - The last successful action of every action-type and target is kept
a216ed
+ *  - For failed actions, who failed is kept
a216ed
+ *  - All actions in progress are kept
a216ed
+ *
a216ed
+ * \param[in] history List of STONITH actions
a216ed
+ *
a216ed
+ * \return The reduced history
a216ed
+ */
a216ed
+stonith_history_t *
a216ed
+pcmk__reduce_fence_history(stonith_history_t *history);
a216ed
 #endif
a216ed
diff --git a/lib/pacemaker/pcmk_fence.c b/lib/pacemaker/pcmk_fence.c
a216ed
index d591379..34540cc 100644
a216ed
--- a/lib/pacemaker/pcmk_fence.c
a216ed
+++ b/lib/pacemaker/pcmk_fence.c
a216ed
@@ -1,5 +1,5 @@
a216ed
 /*
a216ed
- * Copyright 2009-2020 the Pacemaker project contributors
a216ed
+ * Copyright 2009-2021 the Pacemaker project contributors
a216ed
  *
a216ed
  * The version control history for this file may have further details.
a216ed
  *
a216ed
@@ -520,3 +520,46 @@ pcmk_fence_validate(xmlNodePtr *xml, stonith_t *st, const char *agent,
a216ed
     return rc;
a216ed
 }
a216ed
 #endif
a216ed
+
a216ed
+stonith_history_t *
a216ed
+pcmk__reduce_fence_history(stonith_history_t *history)
a216ed
+{
a216ed
+    stonith_history_t *new, *hp, *np;
a216ed
+
a216ed
+    if (!history) {
a216ed
+        return history;
a216ed
+    }
a216ed
+
a216ed
+    new = history;
a216ed
+    hp = new->next;
a216ed
+    new->next = NULL;
a216ed
+
a216ed
+    while (hp) {
a216ed
+        stonith_history_t *hp_next = hp->next;
a216ed
+
a216ed
+        hp->next = NULL;
a216ed
+
a216ed
+        for (np = new; ; np = np->next) {
a216ed
+            if ((hp->state == st_done) || (hp->state == st_failed)) {
a216ed
+                /* action not in progress */
a216ed
+                if (pcmk__str_eq(hp->target, np->target, pcmk__str_casei) &&
a216ed
+                    pcmk__str_eq(hp->action, np->action, pcmk__str_casei) &&
a216ed
+                    (hp->state == np->state) &&
a216ed
+                    ((hp->state == st_done) ||
a216ed
+                     pcmk__str_eq(hp->delegate, np->delegate, pcmk__str_casei))) {
a216ed
+                        /* purge older hp */
a216ed
+                        stonith_history_free(hp);
a216ed
+                        break;
a216ed
+                }
a216ed
+            }
a216ed
+
a216ed
+            if (!np->next) {
a216ed
+                np->next = hp;
a216ed
+                break;
a216ed
+            }
a216ed
+        }
a216ed
+        hp = hp_next;
a216ed
+    }
a216ed
+
a216ed
+    return new;
a216ed
+}
a216ed
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
a216ed
index ff1b86b..2179f53 100644
a216ed
--- a/tools/crm_mon.c
a216ed
+++ b/tools/crm_mon.c
a216ed
@@ -1520,56 +1520,6 @@ print_simple_status(pcmk__output_t *out, pe_working_set_t * data_set,
a216ed
     /* coverity[leaked_storage] False positive */
a216ed
 }
a216ed
 
a216ed
-/*!
a216ed
- * \internal
a216ed
- * \brief Reduce the stonith-history
a216ed
- *        for successful actions we keep the last of every action-type & target
a216ed
- *        for failed actions we record as well who had failed
a216ed
- *        for actions in progress we keep full track
a216ed
- *
a216ed
- * \param[in] history    List of stonith actions
a216ed
- *
a216ed
- */
a216ed
-static stonith_history_t *
a216ed
-reduce_stonith_history(stonith_history_t *history)
a216ed
-{
a216ed
-    stonith_history_t *new = history, *hp, *np;
a216ed
-
a216ed
-    if (new) {
a216ed
-        hp = new->next;
a216ed
-        new->next = NULL;
a216ed
-
a216ed
-        while (hp) {
a216ed
-            stonith_history_t *hp_next = hp->next;
a216ed
-
a216ed
-            hp->next = NULL;
a216ed
-
a216ed
-            for (np = new; ; np = np->next) {
a216ed
-                if ((hp->state == st_done) || (hp->state == st_failed)) {
a216ed
-                    /* action not in progress */
a216ed
-                    if (pcmk__str_eq(hp->target, np->target, pcmk__str_casei) &&
a216ed
-                        pcmk__str_eq(hp->action, np->action, pcmk__str_casei) &&
a216ed
-                        (hp->state == np->state) &&
a216ed
-                        ((hp->state == st_done) ||
a216ed
-                         pcmk__str_eq(hp->delegate, np->delegate, pcmk__str_casei))) {
a216ed
-                            /* purge older hp */
a216ed
-                            stonith_history_free(hp);
a216ed
-                            break;
a216ed
-                    }
a216ed
-                }
a216ed
-
a216ed
-                if (!np->next) {
a216ed
-                    np->next = hp;
a216ed
-                    break;
a216ed
-                }
a216ed
-            }
a216ed
-            hp = hp_next;
a216ed
-        }
a216ed
-    }
a216ed
-
a216ed
-    return new;
a216ed
-}
a216ed
-
a216ed
 static int
a216ed
 send_custom_trap(const char *node, const char *rsc, const char *task, int target_rc, int rc,
a216ed
                  int status, const char *desc)
a216ed
@@ -1935,7 +1885,7 @@ mon_refresh_display(gpointer user_data)
a216ed
                 if (!pcmk_is_set(options.mon_ops, mon_op_fence_full_history)
a216ed
                     && (output_format != mon_output_xml)) {
a216ed
 
a216ed
-                    stonith_history = reduce_stonith_history(stonith_history);
a216ed
+                    stonith_history = pcmk__reduce_fence_history(stonith_history);
a216ed
                 }
a216ed
                 break; /* all other cases are errors */
a216ed
             }
a216ed
-- 
a216ed
1.8.3.1
a216ed
a216ed
a216ed
From af3f1368bc76eb498c2c96b3eda9324b579c9380 Mon Sep 17 00:00:00 2001
a216ed
From: Chris Lumens <clumens@redhat.com>
a216ed
Date: Tue, 12 Jan 2021 15:46:55 -0500
a216ed
Subject: [PATCH 10/10] Low: tools: Adjust fencing shown indicator in crm_mon.
a216ed
a216ed
If any of the various fencing flags are set, but not all of them, no '*'
a216ed
will be shown next to the fencing line in the interactive change screen.
a216ed
This makes it seem like fencing should not be shown, and hitting 'm'
a216ed
should toggle the fencing display on.  However, that's not the case and
a216ed
hitting 'm' will actually toggle fencing off.  Hitting it again will
a216ed
toggle it on and the '*' will appear.
a216ed
a216ed
This is confusing, so just display the '*' if any fencing flag is set.
a216ed
---
a216ed
 tools/crm_mon.c | 5 ++++-
a216ed
 1 file changed, 4 insertions(+), 1 deletion(-)
a216ed
a216ed
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
a216ed
index 2179f53..8ec97bb 100644
a216ed
--- a/tools/crm_mon.c
a216ed
+++ b/tools/crm_mon.c
a216ed
@@ -984,7 +984,10 @@ detect_user_input(GIOChannel *channel, GIOCondition condition, gpointer user_dat
a216ed
         print_option_help(out, 'R', pcmk_is_set(options.mon_ops, mon_op_print_clone_detail));
a216ed
         print_option_help(out, 'b', pcmk_is_set(options.mon_ops, mon_op_print_brief));
a216ed
         print_option_help(out, 'j', pcmk_is_set(options.mon_ops, mon_op_print_pending));
a216ed
-        print_option_help(out, 'm', pcmk_is_set(show, mon_show_fencing_all));
a216ed
+        print_option_help(out, 'm', pcmk_any_flags_set(show,
a216ed
+                                                       mon_show_fence_failed
a216ed
+                                                      |mon_show_fence_pending
a216ed
+                                                      |mon_show_fence_worked));
a216ed
         out->info(out, "%s", "\nToggle fields via field letter, type any other key to return");
a216ed
     }
a216ed
 
a216ed
-- 
a216ed
1.8.3.1
a216ed