diff --git a/.gitignore b/.gitignore
index bcfcb86..f6ff383 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
 SOURCES/nagios-agents-metadata-105ab8a.tar.gz
-SOURCES/pacemaker-f14e36f.tar.gz
+SOURCES/pacemaker-63d2d79.tar.gz
diff --git a/.pacemaker.metadata b/.pacemaker.metadata
index ec07f17..1c989ca 100644
--- a/.pacemaker.metadata
+++ b/.pacemaker.metadata
@@ -1,2 +1,2 @@
 ea6c0a27fd0ae8ce02f84a11f08a0d79377041c3 SOURCES/nagios-agents-metadata-105ab8a.tar.gz
-1affd72b4a9a8190e5e87761b16c32935120e65c SOURCES/pacemaker-f14e36f.tar.gz
+b5dc327aef72008613540d55289020d4e18d36da SOURCES/pacemaker-63d2d79.tar.gz
diff --git a/SOURCES/01-rollup.patch b/SOURCES/01-rollup.patch
deleted file mode 100644
index b06cebe..0000000
--- a/SOURCES/01-rollup.patch
+++ /dev/null
@@ -1,11661 +0,0 @@
-From c46477fe38bdede01a070183052e5fa76f3631ef Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
-Date: Thu, 6 Jun 2019 14:47:40 +0200
-Subject: [PATCH 01/96] Maint: introduce mock/experimental skeletons, now for
- cib (based) daemon
-
-[this is a rebase from 2.0, occurrences of "based" mean "cib", but they
-are not changed everywhere, especially not in the name of the mocked
-daemon, for easy comparability amongst the branches]
-
-This is meant for multiple purposes (non-exhaustive):
-
-- simulating scenarios that are rather hard to achieve in practice
-  (overwhelming number of nodes or artificially capped resources)
-
-- robustness testing (will other daemons survive intermittently, yet
-  frequently missing responses to the based queries?  to what extent
-  do they rely on some causality relations like notify-after-write?
-  what if a chance of continuously changed CIB contents causing
-  troubles?)
-
-- anything not fitting the former two categories
-
-Another option would be to start from a full-fledged daemon, cutting it
-to pieces self-contained, patchable pieces, but since in case of based,
-it has grown rather organically as a monolith, it would be substantially
-more hassle than start grab the most vital pieces and start with a clean
-room.  The aim is to keep additional functionality on top of said
-skeleton, and let the additional functionality stay apart in opt-in
-loosly coupled modules.  We shall see how this works out.
----
- maint/mocked/Makefile |  42 +++++++
- maint/mocked/based.c  | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++
- maint/mocked/based.h  |  47 ++++++++
- 4 files changed, 418 insertions(+)
- create mode 100644 maint/mocked/Makefile
- create mode 100644 maint/mocked/based.c
- create mode 100644 maint/mocked/based.h
-
-diff --git a/maint/mocked/Makefile b/maint/mocked/Makefile
-new file mode 100644
-index 0000000..05b3cb4
---- /dev/null
-+++ b/maint/mocked/Makefile
-@@ -0,0 +1,42 @@
-+#
-+# Copyright 2019 the Pacemaker project contributors
-+#
-+# The version control history for this file may have further details.
-+#
-+# Copying and distribution of this file, with or without modification,
-+# are permitted in any medium without royalty provided the copyright
-+# notice and this notice are preserved.  This file is offered as-is,
-+# without any warranty.
-+#
-+
-+#BASED_LDFLAGS = $$(pkgconf -libs glib-2.0) \
-+#	$$(pkgconf -libs libxml-2.0) \
-+#	$$(pkgconf -libs libqb) \
-+#	$$(pkgconf -libs pacemaker)
-+BASED_LDFLAGS = $$(pkgconf -libs glib-2.0) \
-+	$$(pkgconf -libs libxml-2.0) \
-+	$$(pkgconf -libs libqb) \
-+	-Wl,-rpath=$(CURDIR)/../../lib/common/.libs \
-+	  -L../../lib/common/.libs -lcrmcommon \
-+	  -L../../lib/pacemaker/.libs -lpacemaker
-+
-+BASED_CPPFLAGS = $$(pkgconf -cflags glib-2.0) \
-+	$$(pkgconf -cflags libxml-2.0) \
-+	$$(pkgconf -cflags libqb) \
-+	-DCS_USES_LIBQB \
-+	-I ../.. -I ../../include -g
-+
-+PROGRAMS = based
-+
-+BASED_OBJECTS = based.o
-+
-+all: ${PROGRAMS}
-+
-+based: $(BASED_OBJECTS)
-+	$(CC) $(BASED_LDFLAGS) $^ -o $@
-+
-+$(BASED_OBJECTS): %.o: %.c
-+	$(CC) $(BASED_CPPFLAGS) $(BASED_LDFLAGS) -c $< -o $@
-+
-+clean:
-+	rm ${PROGRAMS} $(BASED_OBJECTS)
-diff --git a/maint/mocked/based.c b/maint/mocked/based.c
-new file mode 100644
-index 0000000..451a384
---- /dev/null
-+++ b/maint/mocked/based.c
-@@ -0,0 +1,328 @@
-+/*
-+ * Copyright 2019 the Pacemaker project contributors
-+ *
-+ * The version control history for this file may have further details.
-+ *
-+ * Licensed under the GNU General Public License version 2 or later (GPLv2+).
-+ */
-+
-+/*
-+ * Clean room attempt (admittedly with lot of code borrowed or inspired from
-+ * the full-blown daemon), minimalistic implementation of based daemon, with
-+ * only important aspects being implemented at the moment.
-+ *
-+ * Hopefully easy to adapt for variety of purposes.
-+ *
-+ * NOTE: currently, only cib_rw API end-point is opened, future refinements
-+ *       as new modules are added should conditionalize per what the module
-+ *       indicates in the context (which is intentionally very loose data glue
-+ *       between the skeleton and modules themselves (like CGI variables so
-+ *       to say, but more structurally predestined so as to avoid complexities
-+ *       of hash table lookups etc.)
-+ */
-+
-+#include <crm_internal.h>
-+#if 0
-+#include "crm/common/ipcs.h"  /* crm_client_t */
-+#include "crm/common/xml.h"  /* crm_xml_add */
-+#endif
-+#include "crm/cib/internal.h"  /* T_CIB */
-+#include "crm/msg_xml.h"  /* F_SUBTYPE */
-+#include "cib/callbacks.h"  /* cib_notify_diff */
-+
-+#include <qb/qbipcs.h>  /* qb_ipcs_connection_t */
-+
-+#include "based.h"
-+
-+
-+/* direct global access violated in one case only
-+   - mock_based_ipc_accept adds a reference to it to crm_cient_t->userdata */
-+mock_based_context_t mock_based_context;
-+
-+
-+/* see based/based_callbacks.c:cib_ipc_accept */
-+static int32_t
-+mock_based_ipc_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid)
-+{
-+    int32_t ret = 0;
-+    crm_client_t *cib_client;
-+
-+    crm_trace("Connection %p", c);
-+    if ((cib_client = crm_client_new(c, uid, gid)) == NULL) {
-+        ret = -EIO;
-+    }
-+
-+    cib_client->userdata = &mock_based_context;
-+
-+    return ret;
-+}
-+
-+/* see based/based_callbacks.c:cib_ipc_created */
-+static void
-+mock_based_ipc_created(qb_ipcs_connection_t *c)
-+{
-+    crm_trace("Connection %p", c);
-+}
-+
-+/* see based/based_callbacks.c:cib_ipc_closed */
-+static int32_t
-+mock_based_ipc_closed(qb_ipcs_connection_t *c)
-+{
-+    crm_client_t *client = crm_client_get(c);
-+
-+    if (client != NULL) {
-+        crm_trace("Connection %p", c);
-+        crm_client_destroy(client);
-+    }
-+
-+    return 0;
-+}
-+
-+/* see based/based_callbacks.c:cib_ipc_destroy */
-+static void
-+mock_based_ipc_destroy(qb_ipcs_connection_t *c)
-+{
-+    crm_trace("Connection %p", c);
-+    mock_based_ipc_closed(c);
-+}
-+
-+/* see based/based_callbacks.c:cib_process_command (and more) */
-+static void
-+mock_based_handle_query(crm_client_t *cib_client, uint32_t flags,
-+                        const xmlNode *op_request)
-+{
-+    xmlNode *reply, *cib;
-+    const char cib_str[] =
-+#if 0
-+"<cib/>";
-+#else
-+"<cib validate-with='pacemaker-1.2' admin_epoch='0' epoch='0' num_updates='0'>"\
-+"  <configuration>"\
-+"    <crm_config/>"\
-+"    <nodes/>"\
-+"    <resources/>"\
-+"    <constraints/>"\
-+"  </configuration>"\
-+"  <status/>"\
-+"</cib>";
-+#endif
-+    cib = xmlReadMemory(cib_str, sizeof(cib_str), "file:///tmp/foo", NULL, 0)->children;
-+
-+    reply = create_xml_node(NULL, "cib-reply");
-+    crm_xml_add(reply, F_TYPE, T_CIB);
-+    crm_xml_add(reply, F_CIB_OPERATION,
-+                crm_element_value(op_request, F_CIB_OPERATION));
-+    crm_xml_add(reply, F_CIB_CALLID,
-+                crm_element_value(op_request, F_CIB_CALLID));
-+    crm_xml_add(reply, F_CIB_CLIENTID,
-+                crm_element_value(op_request, F_CIB_CLIENTID));
-+    crm_xml_add_int(reply, F_CIB_CALLOPTS, flags);
-+    crm_xml_add_int(reply, F_CIB_RC, pcmk_ok);
-+
-+    if (cib != NULL) {
-+        crm_trace("Attaching reply output");
-+        add_message_xml(reply, F_CIB_CALLDATA, cib);
-+    }
-+
-+    crm_ipcs_send(cib_client, cib_client->request_id, reply,
-+                  (flags & cib_sync_call) ? crm_ipc_flags_none
-+                                          : crm_ipc_server_event);
-+
-+    free_xml(reply);
-+    free_xml(cib);
-+}
-+
-+/* see based/based_callbacks.c:cib_common_callback_worker */
-+static void
-+mock_based_common_callback_worker(uint32_t id, uint32_t flags,
-+                                  xmlNode *op_request, crm_client_t *cib_client)
-+{
-+    const char *op = crm_element_value(op_request, F_CIB_OPERATION);
-+
-+    if (!strcmp(op, CRM_OP_REGISTER)) {
-+        if (flags & crm_ipc_client_response) {
-+            xmlNode *ack = create_xml_node(NULL, __FUNCTION__);
-+            crm_xml_add(ack, F_CIB_OPERATION, CRM_OP_REGISTER);
-+            crm_xml_add(ack, F_CIB_CLIENTID, cib_client->id);
-+            crm_ipcs_send(cib_client, id, ack, flags);
-+            cib_client->request_id = 0;
-+            free_xml(ack);
-+        }
-+
-+    } else if (!strcmp(op, T_CIB_NOTIFY)) {
-+        int on_off = 0;
-+        const char *type = crm_element_value(op_request, F_CIB_NOTIFY_TYPE);
-+        crm_element_value_int(op_request, F_CIB_NOTIFY_ACTIVATE, &on_off);
-+
-+        crm_debug("Setting %s callbacks for %s (%s): %s",
-+                  type, cib_client->name, cib_client->id, on_off ? "on" : "off");
-+
-+        if (!strcmp(type, T_CIB_DIFF_NOTIFY) && on_off) {
-+            cib_client->options |= cib_notify_diff;
-+        }
-+
-+        if (flags & crm_ipc_client_response) {
-+            crm_ipcs_send_ack(cib_client, id, flags, "ack", __FUNCTION__, __LINE__);
-+        }
-+
-+    } else if (!strcmp(op, CIB_OP_QUERY)) {
-+        mock_based_handle_query(cib_client, flags, op_request);
-+
-+    } else {
-+        crm_notice("Discarded request %s", op);
-+    }
-+}
-+
-+/* see based/based_callbacks.c:cib_ipc_dispatch_rw */
-+static int32_t
-+mock_based_dispatch_command(qb_ipcs_connection_t *c, void *data, size_t size)
-+{
-+    uint32_t id = 0, flags = 0;
-+    int call_options = 0;
-+    crm_client_t *cib_client = crm_client_get(c);
-+    xmlNode *op_request = crm_ipcs_recv(cib_client, data, size, &id, &flags);
-+
-+    crm_notice("Got connection %p", c);
-+    assert(op_request != NULL);
-+
-+    if (cib_client == NULL || op_request == NULL) {
-+        if (op_request == NULL) {
-+            crm_trace("Invalid message from %p", c);
-+            crm_ipcs_send_ack(cib_client, id, flags, "nack", __FUNCTION__, __LINE__);
-+        }
-+        return 0;
-+    }
-+
-+    crm_element_value_int(op_request, F_CIB_CALLOPTS, &call_options);
-+    if (call_options & cib_sync_call) {
-+        assert(flags & crm_ipc_client_response);
-+        cib_client->request_id = id;  /* reply only to last in-flight request */
-+    }
-+
-+    assert(cib_client->name == NULL);
-+    crm_element_value_int(op_request, F_CIB_CALLOPTS, &call_options);
-+    crm_xml_add(op_request, F_CIB_CLIENTID, cib_client->id);
-+    crm_xml_add(op_request, F_CIB_CLIENTNAME, cib_client->name);
-+
-+    mock_based_common_callback_worker(id, flags, op_request, cib_client);
-+    free_xml(op_request);
-+
-+    return 0;
-+}
-+
-+/* * */
-+
-+size_t mock_based_register_module(module_t mod) {
-+    module_t *module;
-+    size_t ret = mock_based_context.modules_cnt++;
-+
-+    mock_based_context.modules = realloc(mock_based_context.modules,
-+                                         sizeof(*mock_based_context.modules)
-+                                          * mock_based_context.modules_cnt);
-+    if (mock_based_context.modules == NULL
-+            || (module = malloc(sizeof(module_t))) == NULL) {
-+        abort();
-+    }
-+
-+    memcpy(module, &mod, sizeof(mod));
-+    mock_based_context.modules[mock_based_context.modules_cnt - 1] = module;
-+
-+    return ret;
-+}
-+
-+static int
-+mock_based_options(mock_based_context_t *ctxt,
-+                   bool usage, int argc, const char *argv[])
-+{
-+    const char **args2argv;
-+    char *s;
-+    int ret = 0;
-+
-+    if (argc <= 1) {
-+        const char *help_argv[] = {argv[0], "-h"};
-+        return mock_based_options(ctxt, false, 2, (const char **) &help_argv);
-+    }
-+
-+    for (size_t i = 1; i < argc; i++) {
-+        if (argv[i][0] == '-' && argv[i][1] != '-' && argv[i][1] != '\0') {
-+            if (usage) {
-+                printf("\t-%c\t", argv[i][1]);
-+            }
-+            switch(argv[i][1]) {
-+            case 'h':
-+                if (usage) {
-+                    printf("show this help message\n");
-+                    ret = 1;
-+
-+                } else {
-+                    if ((args2argv
-+                            = malloc((ctxt->modules_cnt + 2) * sizeof(*args2argv))) == NULL
-+                        || (s
-+                            = malloc((ctxt->modules_cnt * 2 + 2) * sizeof(*s))) == NULL) {
-+                        return -1;
-+                    }
-+                    s[0] = 'h';
-+                    args2argv[ctxt->modules_cnt + 1] = (char[]){'-', 'h', '\0'};
-+                    for (size_t c = ctxt->modules_cnt; c > 0; c--) {
-+                        args2argv[c] = (char[]){'-', ctxt->modules[c - 1]->shortopt, '\0'};
-+                        s[(ctxt->modules_cnt - i) + 1] = '|';
-+                        s[(ctxt->modules_cnt - i) + 2] = ctxt->modules[c - 1]->shortopt;
-+                    }
-+                    s[ctxt->modules_cnt * 2 + 1] = '\0';
-+                    printf("Usage: %s [-{%s}]\n", argv[0], s);
-+                    (void) mock_based_options(ctxt, true, 2 + ctxt->modules_cnt, args2argv);
-+                    free(args2argv);
-+                    free(s);
-+                }
-+                return ret;
-+            default:
-+                for (size_t c = ctxt->modules_cnt; c > 0; c--) {
-+                    if (ctxt->modules[c - 1]->shortopt == argv[i][1]) {
-+                        ret = ctxt->modules[c - 1]->hooks.argparse(ctxt, usage, argc - i, &argv[i]);
-+                        if (ret < 0) {
-+                            break;
-+                        } else if (ret > 1) {
-+                            i += (ret - 1);
-+                        }
-+                    }
-+                }
-+                if (ret == 0) {
-+                    printf("uknown option \"%s\"\n", argv[i]);
-+                }
-+                break;
-+            }
-+        }
-+    }
-+    return ret;
-+}
-+
-+int main(int argc, char *argv[])
-+{
-+    mock_based_context_t *ctxt = &mock_based_context;
-+
-+    if (mock_based_options(ctxt, false, argc, (const char **) argv) > 0) {
-+        struct qb_ipcs_service_handlers cib_ipc_callbacks = {
-+            .connection_accept = mock_based_ipc_accept,
-+            .connection_created = mock_based_ipc_created,
-+            .msg_process = mock_based_dispatch_command,
-+            .connection_closed = mock_based_ipc_closed,
-+            .connection_destroyed = mock_based_ipc_destroy,
-+        };
-+        crm_log_preinit(NULL, argc, argv);
-+        crm_log_init(NULL, LOG_DEBUG, false, true, argc, argv, false);
-+        qb_ipcs_service_t *ipcs_command =
-+            mainloop_add_ipc_server(cib_channel_rw, QB_IPC_NATIVE,
-+                                    &cib_ipc_callbacks);
-+        g_main_loop_run(g_main_loop_new(NULL, false));
-+        qb_ipcs_destroy(ipcs_command);
-+    }
-+
-+    for (size_t c = ctxt->modules_cnt; c > 0; c--) {
-+        if (ctxt->modules[c - 1]->hooks.destroy != NULL) {
-+            ctxt->modules[c - 1]->hooks.destroy(ctxt->modules[c - 1]);
-+        }
-+        free(mock_based_context.modules[c - 1]);
-+    }
-+
-+    free(mock_based_context.modules);
-+}
-diff --git a/maint/mocked/based.h b/maint/mocked/based.h
-new file mode 100644
-index 0000000..04d8eed
---- /dev/null
-+++ b/maint/mocked/based.h
-@@ -0,0 +1,47 @@
-+/*
-+ * Copyright 2019 the Pacemaker project contributors
-+ *
-+ * The version control history for this file may have further details.
-+ *
-+ * Licensed under the GNU General Public License version 2 or later (GPLv2+).
-+ */
-+
-+#pragma once
-+
-+#include <stdlib.h>  /* size_t */
-+#include <stdbool.h>  /* bool */
-+
-+#include <crm/common/ipcs.h>  /* crm_client_t */
-+
-+
-+struct module_s;
-+
-+typedef struct mock_based_context_s {
-+    size_t modules_cnt;
-+    struct module_s** modules;
-+} mock_based_context_t;
-+
-+
-+typedef int (*mock_based_argparse_hook)(mock_based_context_t *,
-+                                        bool, int,
-+                                        const char *[]);
-+
-+typedef void (*mock_based_destroy_hook)(struct module_s *);
-+
-+/* specialized callbacks... */
-+
-+typedef struct mock_based_hooks_s {
-+    /* generic ones */
-+    mock_based_argparse_hook argparse;
-+    mock_based_destroy_hook destroy;
-+
-+    /* specialized callbacks... */
-+} mock_based_hooks_t;
-+
-+typedef struct module_s {
-+    char shortopt;
-+    mock_based_hooks_t hooks;
-+    void *priv;
-+} module_t;
-+
-+size_t mock_based_register_module(module_t mod);
--- 
-1.8.3.1
-
-
-From 1498a811283a00623c4410c7e9abbd8b9ff3fe53 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
-Date: Wed, 15 May 2019 18:23:56 +0200
-Subject: [PATCH 02/96] Maint: mocked/based: add based-notifyfenced module
-
-[this is a rebase from 2.0, occurrences of "based" mean "cib", just as
-"fenced" means "stonithd" in this context , but these are not changed
-everywhere, especially not in the name of the mocked daemon + modules,
-for easy comparability amongst the branches]
-
-This is to demonstrate how the current arrangement at _other_
-daemons (fenced in particular, as the name may suggest) is sometimes
-insufficient (see the following fix for fenced daemon) regarding
-liveness requirements, since high-rate stream of notifications from
-pacemaker-based can effectively block any progress regarding their
-own native services they provide (starving their own clients out).
-
-It would be rather difficult to achieve the same triggering
-circumstances artificially in vanilla settings, especially when
-constrained at number-of-nodes/resources dimension (bothersome
-artificial-messaging-load-through-configuration) -- leveraging the
-skeleton from the previous commit, we can now emulate the same just
-with a single node under test and with next to zero configuration
--- just configure a single node cluster through corosync.conf, start
-corosync, run "./based -N" (preferably as hacluster:haclient), only
-then pacemaker-fenced and try to communicate with it (e.g. via
-stonith_admin) -- see the in-line comment wrt. how to use this module.
-
-Note that this first module has some parts ifdef'd out since it's
-intented also as a template for writing additional modules -- you'll:
-
-- copy based-notifyspam.c as based-mymodule.c, and edit it, so that...
-
-- OPTCHAR is a new, unique short option character
-  (preferably uppercase, leaving lower-cased letters reserved as
-  action modifiers, cf. xml/regression.sh)
-
-- drop everything unneeded except for mock_based_MOD_argparse_hook
-  and mock_based_MOD_init, configure the callbacks there respectively
-
-- should the new hook mounting place be needed, declare new hook
-  prototype in based.h, append such respective member
-  to the struct mock_based_hooks_s there, locate the corresponding
-  location for its application in based.c and apply it here
-  (follow the example of hooks.cib_notify)
-
-- add the respective "BASED_OBJECTS += based-MOD.o" to Makefile
-
-- test...
----
- maint/mocked/Makefile             |   3 +
- maint/mocked/based-notifyfenced.c | 247 ++++++++++++++++++++++++++++++++++++++
- maint/mocked/based.c              |   8 ++
- maint/mocked/based.h              |   2 +
- 4 files changed, 260 insertions(+)
- create mode 100644 maint/mocked/based-notifyfenced.c
-
-diff --git a/maint/mocked/Makefile b/maint/mocked/Makefile
-index 05b3cb4..5e3a1a8 100644
---- a/maint/mocked/Makefile
-+++ b/maint/mocked/Makefile
-@@ -30,6 +30,9 @@ PROGRAMS = based
- 
- BASED_OBJECTS = based.o
- 
-+# include or not the modules as you wish
-+BASED_OBJECTS += based-notifyfenced.o
-+
- all: ${PROGRAMS}
- 
- based: $(BASED_OBJECTS)
-diff --git a/maint/mocked/based-notifyfenced.c b/maint/mocked/based-notifyfenced.c
-new file mode 100644
-index 0000000..90cad48
---- /dev/null
-+++ b/maint/mocked/based-notifyfenced.c
-@@ -0,0 +1,247 @@
-+/*
-+ * Copyright 2019 the Pacemaker project contributors
-+ *
-+ * The version control history for this file may have further details.
-+ *
-+ * Licensed under the GNU General Public License version 2 or later (GPLv2+).
-+ */
-+
-+/*
-+ * Intended demo use case:
-+ *
-+ * - as root, start corosync
-+ * - start "./based -N"; hint:
-+ *   su -s /bin/sh -c './based -N' hacluster
-+ * - start stonithd; hint:
-+ *   su -c 'env PCMK_logpriority=crit ../../fencing/stonithd'
-+ * - wait a bit (5 < seconds < 20)
-+ * - as haclient group (or root), run "stonith_admin --list-registered"
-+ * - observe whether such invocation is blocked or not
-+ */
-+
-+
-+#include <stdio.h>  /* printf, perror */
-+
-+#include "crm/cib.h"  /* cib_zero_copy */
-+#include "crm/cib/internal.h"  /* CIB_OP_CREATE */
-+#include "crm/msg_xml.h"  /* F_SUBTYPE */
-+#include "cib/callbacks.h"  /* cib_notify_diff */
-+
-+#include "based.h"
-+
-+
-+#define OPTCHAR 'N'
-+static size_t module_handle;
-+
-+
-+struct cib_notification_s {
-+    xmlNode *msg;
-+    struct iovec *iov;
-+    int32_t iov_size;
-+};
-+
-+/* see based/based_notify.c:cib_notify_send_one */
-+static bool
-+mock_based_cib_notify_send_one(crm_client_t *client, xmlNode *xml)
-+{
-+    const char *type = NULL;
-+    bool do_send = false;
-+
-+    struct iovec *iov;
-+    ssize_t rc = crm_ipc_prepare(0, xml, &iov, 0);
-+    struct cib_notification_s update = {
-+        .msg = xml,
-+        .iov = iov,
-+        .iov_size = rc,
-+    };
-+
-+    CRM_CHECK(client != NULL, return true);
-+    if (client->ipcs == NULL && client->remote == NULL) {
-+        crm_warn("Skipping client with NULL channel");
-+        return FALSE;
-+    }
-+
-+    type = crm_element_value(update.msg, F_SUBTYPE);
-+    CRM_LOG_ASSERT(type != NULL);
-+    if (is_set(client->options, cib_notify_diff)
-+            && safe_str_eq(type, T_CIB_DIFF_NOTIFY)) {
-+
-+        if (crm_ipcs_sendv(client, update.iov, crm_ipc_server_event) < 0)
-+            crm_warn("Notification of client %s/%s failed", client->name, client->id);
-+
-+    }
-+    if (iov) {
-+        free(iov[0].iov_base);
-+        free(iov[1].iov_base);
-+        free(iov);
-+    }
-+
-+    return FALSE;
-+}
-+
-+/* see based/based_notify.c:do_cib_notify + cib_notify_send */
-+void
-+do_cib_notify(crm_client_t *cib_client, int options, const char *op,
-+              xmlNode *update, int result, xmlNode *result_data,
-+              const char *msg_type)
-+{
-+    xmlNode *update_msg = NULL;
-+    const char *id = NULL;
-+
-+    update_msg = create_xml_node(NULL, "notify");
-+
-+
-+    crm_xml_add(update_msg, F_TYPE, T_CIB_NOTIFY);
-+    crm_xml_add(update_msg, F_SUBTYPE, msg_type);
-+    crm_xml_add(update_msg, F_CIB_OPERATION, op);
-+    crm_xml_add_int(update_msg, F_CIB_RC, result);
-+
-+    if (result_data != NULL) {
-+        id = crm_element_value(result_data, XML_ATTR_ID);
-+        if (id != NULL)
-+            crm_xml_add(update_msg, F_CIB_OBJID, id);
-+    }
-+
-+    if (update != NULL) {
-+        crm_trace("Setting type to update->name: %s", crm_element_name(update));
-+        crm_xml_add(update_msg, F_CIB_OBJTYPE, crm_element_name(update));
-+
-+    } else if (result_data != NULL) {
-+        crm_trace("Setting type to new_obj->name: %s", crm_element_name(result_data));
-+        crm_xml_add(update_msg, F_CIB_OBJTYPE, crm_element_name(result_data));
-+
-+    } else {
-+        crm_trace("Not Setting type");
-+    }
-+
-+#if 0
-+    attach_cib_generation(update_msg, "cib_generation", the_cib);
-+#endif
-+
-+    if (update != NULL) {
-+        add_message_xml(update_msg, F_CIB_UPDATE, update);
-+    }
-+    if (result_data != NULL) {
-+        add_message_xml(update_msg, F_CIB_UPDATE_RESULT, result_data);
-+    }
-+
-+    mock_based_cib_notify_send_one(cib_client, update_msg);
-+    free_xml(update_msg);
-+}
-+
-+static gboolean
-+mock_based_notifyfencedmer_callback_worker(gpointer data)
-+{
-+    crm_client_t *cib_client = (crm_client_t *) data;
-+
-+    xmlNode *result_data;
-+    xmlNode *input, *update;
-+    int options;
-+    char update_str[4096];
-+
-+    options |= cib_zero_copy;
-+
-+
-+    input = create_xml_node(NULL, "cib");
-+
-+    /* spam it */
-+#if 0
-+    for (size_t i = 0; i < SIZE_MAX - 1; i++) {
-+#else
-+    for (size_t i = 0; i < 10000; i++) {
-+#endif
-+        /* NOTE: we need to trigger fenced attention, add new fence device */
-+        snprintf(update_str, sizeof(update_str),
-+"<diff crm_feature_set='3.1.0' format='1'>\n"
-+"  <diff-removed admin_epoch='%1$llu' epoch='%1$llu' num_updates='%1$llu'>\n"
-+"    <cib admin_epoch='%1$llu' epoch='%1$llu' num_updates='%1$llu'/>\n"
-+"  </diff-removed>\n"
-+"  <diff-added admin_epoch='%2$llu' epoch='%2$llu' num_updates='%2$llu'>\n"
-+"    <cib validate-with='pacemaker-1.2' admin_epoch='%2$llu' epoch='%2$llu' num_updates='%2$llu'>\n"
-+"      <configuration>\n"
-+"        <resources>\n"
-+"          <primitive id='FENCEDEV-fence-dummy-%2$llu' class='stonith' type='__apparently_bogus__' __crm_diff_marker__='added:top'/>\n"
-+"        </resources>\n"
-+"      </configuration>\n"
-+"    </cib>\n"
-+"  </diff-added>\n"
-+"</diff>\n", i, i+1);
-+        update = xmlReadMemory(update_str, sizeof(update_str),
-+                               "file:///tmp/update", NULL, 0)->children;
-+        do_cib_notify(cib_client, options, CIB_OP_CREATE, input, pcmk_ok,
-+                      update, T_CIB_DIFF_NOTIFY);
-+        free_xml(update);
-+    };
-+
-+    free_xml(input);
-+}
-+
-+static void
-+mock_based_notifyfenced_cib_notify_hook(crm_client_t *cib_client)
-+{
-+
-+    /* MOCK: client asked for upcoming diff's, let's
-+             spam it a bit after a while... */
-+    crm_info("Going to spam %s (%s) in 5 seconds...",
-+             cib_client->name, cib_client->id);
-+    mainloop_timer_start(mainloop_timer_add("spammer", 5000, FALSE,
-+                         mock_based_notifyfencedmer_callback_worker,
-+                         cib_client));
-+}
-+
-+/* * */
-+
-+static int
-+mock_based_notifyfenced_argparse_hook(struct mock_based_context_s *ctxt,
-+                                    bool usage, int argc_to_go,
-+                                    const char *argv_to_go[])
-+{
-+    const char *opt = *argv_to_go;
-+restart:
-+    switch(*opt) {
-+    case '-':
-+        if (opt == *argv_to_go) {
-+            opt++;
-+            goto restart;
-+        }
-+        break;
-+    case OPTCHAR:
-+        if (usage) {
-+            printf("spam the \"cib diff\" notification client"
-+                   " (targeting pacemaker-fenced in particular)\n");
-+
-+        } else {
-+#if 0
-+            ctxt->modules[module_handle]->priv =
-+                malloc(sizeof(mock_based_notifyfenced_priv_t));
-+            if (ctxt->modules[module_handle]->priv == NULL) {
-+                perror("malloc");
-+                return -1;
-+            }
-+#endif
-+        }
-+        return 1;
-+    }
-+    return 0;
-+}
-+
-+#if 0
-+static void
-+mock_based_notifyfenced_destroy_hook(module_t *mod) {
-+    free(mod->priv);
-+}
-+#endif
-+
-+__attribute__((__constructor__))
-+void
-+mock_based_notifyfenced_init(void) {
-+    module_handle = mock_based_register_module((module_t){
-+        .shortopt = OPTCHAR,
-+        .hooks = {
-+            .argparse = mock_based_notifyfenced_argparse_hook,
-+            //.destroy = mock_based_notifyfenced_destroy_hook,
-+            /* specialized hooks */
-+            .cib_notify = mock_based_notifyfenced_cib_notify_hook,
-+        }
-+    });
-+}
-diff --git a/maint/mocked/based.c b/maint/mocked/based.c
-index 451a384..d340274 100644
---- a/maint/mocked/based.c
-+++ b/maint/mocked/based.c
-@@ -138,6 +138,7 @@ mock_based_common_callback_worker(uint32_t id, uint32_t flags,
-                                   xmlNode *op_request, crm_client_t *cib_client)
- {
-     const char *op = crm_element_value(op_request, F_CIB_OPERATION);
-+    mock_based_context_t *ctxt;
- 
-     if (!strcmp(op, CRM_OP_REGISTER)) {
-         if (flags & crm_ipc_client_response) {
-@@ -161,6 +162,13 @@ mock_based_common_callback_worker(uint32_t id, uint32_t flags,
-             cib_client->options |= cib_notify_diff;
-         }
- 
-+        ctxt = (mock_based_context_t *) cib_client->userdata;
-+        for (size_t c = ctxt->modules_cnt; c > 0; c--) {
-+            if (ctxt->modules[c - 1]->hooks.cib_notify != NULL) {
-+                ctxt->modules[c - 1]->hooks.cib_notify(cib_client);
-+            }
-+        }
-+
-         if (flags & crm_ipc_client_response) {
-             crm_ipcs_send_ack(cib_client, id, flags, "ack", __FUNCTION__, __LINE__);
-         }
-diff --git a/maint/mocked/based.h b/maint/mocked/based.h
-index 04d8eed..dcebf0e 100644
---- a/maint/mocked/based.h
-+++ b/maint/mocked/based.h
-@@ -29,6 +29,7 @@ typedef int (*mock_based_argparse_hook)(mock_based_context_t *,
- typedef void (*mock_based_destroy_hook)(struct module_s *);
- 
- /* specialized callbacks... */
-+typedef void (*mock_based_cib_notify_hook)(crm_client_t *);
- 
- typedef struct mock_based_hooks_s {
-     /* generic ones */
-@@ -36,6 +37,7 @@ typedef struct mock_based_hooks_s {
-     mock_based_destroy_hook destroy;
- 
-     /* specialized callbacks... */
-+    mock_based_cib_notify_hook cib_notify;
- } mock_based_hooks_t;
- 
- typedef struct module_s {
--- 
-1.8.3.1
-
-
-From eee76118f2a557a79bda0214ea5c0974a7cd40c2 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
-Date: Wed, 29 Aug 2018 15:49:58 +0200
-Subject: [PATCH 03/96] Low: mainloop: make it possible to specify server's
- priority in mainloop
-
----
- include/crm/common/mainloop.h | 24 +++++++++++++
- lib/common/mainloop.c         | 82 +++++++++++++++++++++++++++++++++++++++++--
- 2 files changed, 103 insertions(+), 3 deletions(-)
-
-diff --git a/include/crm/common/mainloop.h b/include/crm/common/mainloop.h
-index eab31ac..e00da48 100644
---- a/include/crm/common/mainloop.h
-+++ b/include/crm/common/mainloop.h
-@@ -67,6 +67,30 @@ struct ipc_client_callbacks {
- qb_ipcs_service_t *mainloop_add_ipc_server(const char *name, enum qb_ipc_type type,
-                                            struct qb_ipcs_service_handlers *callbacks);
- 
-+/*!
-+ * \brief Start server-side API end-point, hooked into the internal event loop
-+ *
-+ * \param[in] name    name of the IPC end-point ("address" for the client)
-+ * \param[in] type    selects libqb's IPC back-end (or use #QB_IPC_NATIVE)
-+ * \param[in] callbacks  defines libqb's IPC service-level handlers
-+ * \param[in] priority  priority relative to other events handled in the
-+ *                      abstract handling loop, use #QB_LOOP_MED when unsure
-+ *
-+ * \return libqb's opaque handle to the created service abstraction
-+ *
-+ * \note For portability concerns, do not use this function if you keep
-+ *       \p priority as #QB_LOOP_MED, stick with #mainloop_add_ipc_server
-+ *       (with exactly such semantics) instead (once you link with this new
-+ *       symbol employed, you can't downgrade the library freely anymore).
-+ *
-+ * \note The intended effect will only get fully reflected when run-time
-+ *       linked to patched libqb: https://github.com/ClusterLabs/libqb/pull/352
-+ */
-+qb_ipcs_service_t *mainloop_add_ipc_server_with_prio(const char *name,
-+                                                    enum qb_ipc_type type,
-+                                                    struct qb_ipcs_service_handlers *callbacks,
-+                                                    enum qb_loop_priority prio);
-+
- void mainloop_del_ipc_server(qb_ipcs_service_t * server);
- 
- mainloop_io_t *mainloop_add_ipc_client(const char *name, int priority, size_t max_size,
-diff --git a/lib/common/mainloop.c b/lib/common/mainloop.c
-index 60726cb..9bdd026 100644
---- a/lib/common/mainloop.c
-+++ b/lib/common/mainloop.c
-@@ -456,6 +456,65 @@ gio_poll_destroy(gpointer data)
-     }
- }
- 
-+/*!
-+ * \internal
-+ * \brief Convert libqb's poll priority into GLib's one
-+ *
-+ * \param[in] prio  libqb's poll priority (#QB_LOOP_MED assumed as fallback)
-+ *
-+ * \return  best matching GLib's priority
-+ */
-+static gint
-+conv_prio_libqb2glib(enum qb_loop_priority prio)
-+{
-+    gint ret = G_PRIORITY_DEFAULT;
-+    switch (prio) {
-+        case QB_LOOP_LOW:
-+            ret = G_PRIORITY_LOW;
-+            break;
-+        case QB_LOOP_HIGH:
-+            ret = G_PRIORITY_HIGH;
-+            break;
-+        default:
-+            crm_trace("Invalid libqb's loop priority %d, assuming QB_LOOP_MED",
-+                      prio);
-+            /* fall-through */
-+        case QB_LOOP_MED:
-+            break;
-+    }
-+    return ret;
-+}
-+
-+/*!
-+ * \internal
-+ * \brief Convert libqb's poll priority to rate limiting spec
-+ *
-+ * \param[in] prio  libqb's poll priority (#QB_LOOP_MED assumed as fallback)
-+ *
-+ * \return  best matching rate limiting spec
-+ */
-+static enum qb_ipcs_rate_limit
-+conv_libqb_prio2ratelimit(enum qb_loop_priority prio)
-+{
-+    /* this is an inversion of what libqb's qb_ipcs_request_rate_limit does */
-+    enum qb_ipcs_rate_limit ret = QB_IPCS_RATE_NORMAL;
-+    switch (prio) {
-+        case QB_LOOP_LOW:
-+            ret = QB_IPCS_RATE_SLOW;
-+            break;
-+        case QB_LOOP_HIGH:
-+            ret = QB_IPCS_RATE_FAST;
-+            break;
-+        default:
-+            crm_trace("Invalid libqb's loop priority %d, assuming QB_LOOP_MED",
-+                      prio);
-+            /* fall-through */
-+        case QB_LOOP_MED:
-+            break;
-+    }
-+    return ret;
-+}
-+
- static int32_t
- gio_poll_dispatch_update(enum qb_loop_priority p, int32_t fd, int32_t evts,
-                          void *data, qb_ipcs_dispatch_fn_t fn, int32_t add)
-@@ -502,8 +561,8 @@ gio_poll_dispatch_update(enum qb_loop_priority p, int32_t fd, int32_t evts,
-     adaptor->p = p;
-     adaptor->is_used++;
-     adaptor->source =
--        g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, evts, gio_read_socket, adaptor,
--                            gio_poll_destroy);
-+        g_io_add_watch_full(channel, conv_prio_libqb2glib(p), evts,
-+                            gio_read_socket, adaptor, gio_poll_destroy);
- 
-     /* Now that mainloop now holds a reference to channel,
-      * thanks to g_io_add_watch_full(), drop ours from g_io_channel_unix_new().
-@@ -587,7 +646,15 @@ pick_ipc_type(enum qb_ipc_type requested)
- 
- qb_ipcs_service_t *
- mainloop_add_ipc_server(const char *name, enum qb_ipc_type type,
--                        struct qb_ipcs_service_handlers * callbacks)
-+                        struct qb_ipcs_service_handlers *callbacks)
-+{
-+    return mainloop_add_ipc_server_with_prio(name, type, callbacks, QB_LOOP_MED);
-+}
-+
-+qb_ipcs_service_t *
-+mainloop_add_ipc_server_with_prio(const char *name, enum qb_ipc_type type,
-+                                  struct qb_ipcs_service_handlers *callbacks,
-+                                  enum qb_loop_priority prio)
- {
-     int rc = 0;
-     qb_ipcs_service_t *server = NULL;
-@@ -599,6 +666,15 @@ mainloop_add_ipc_server(const char *name, enum qb_ipc_type type,
-     crm_client_init();
-     server = qb_ipcs_create(name, 0, pick_ipc_type(type), callbacks);
- 
-+    if (server == NULL) {
-+        crm_err("Could not create %s IPC server: %s (%d)", name, pcmk_strerror(rc), rc);
-+        return NULL;
-+    }
-+
-+    if (prio != QB_LOOP_MED) {
-+        qb_ipcs_request_rate_limit(server, conv_libqb_prio2ratelimit(prio));
-+    }
-+
- #ifdef HAVE_IPCS_GET_BUFFER_SIZE
-     /* All clients should use at least ipc_buffer_max as their buffer size */
-     qb_ipcs_enforce_buffer_size(server, crm_ipc_default_buffer_size());
--- 
-1.8.3.1
-
-
-From 428a9c873b661947af1e142ec8fa9fcf85328dcd Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
-Date: Wed, 29 Aug 2018 15:50:57 +0200
-Subject: [PATCH 04/96] High: stonith-ng's function cannot be blocked with CIB
- updates forever
-
-In the high-load (or high-rate-config-change) scenarios,
-pacemaker-fenced would be unable to provide service when basically DoS'd
-with CIB update notifications.  Try to reconcile that with elevated
-priority of the server's proper listening interface in the mainloop, at
-worst, it will try to fence with slightly outdated config, but appears
-to be less bad than not carrying the execution at all, for instance.
-Other daemons might be considered as well.
-
-Prerequisites:
-- https://github.com/ClusterLabs/libqb/pull/352
-  (libqb used to contain a bug due to which one particular step in the
-  initial-client-connection-accepting-at-the-server procedure that would
-  be carried out with hard-coded (and hence possibly lower than competing
-  events') priority, which backfires exactly in this case (once the
-  pacemaker part is fixed -- by the means of elevating priority for
-  the API end-point of fenced so that it won't get consistently
-  overridden with a non-socket-based event source/trigger)
-
-How to verify:
-- mocked/based -N (see commit adding that module to mocked based daemon)
----
- lib/common/utils.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/lib/common/utils.c b/lib/common/utils.c
-index f3f60ed..b87454e 100644
---- a/lib/common/utils.c
-+++ b/lib/common/utils.c
-@@ -1223,7 +1223,8 @@ attrd_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers
- void
- stonith_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
- {
--    *ipcs = mainloop_add_ipc_server("stonith-ng", QB_IPC_NATIVE, cb);
-+    *ipcs = mainloop_add_ipc_server_with_prio("stonith-ng", QB_IPC_NATIVE, cb,
-+                                              QB_LOOP_HIGH);
- 
-     if (*ipcs == NULL) {
-         crm_err("Failed to create stonith-ng servers: exiting and inhibiting respawn.");
--- 
-1.8.3.1
-
-
-From 75f507e6432e414c78938fc83d18493a998c98b6 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
-Date: Wed, 5 Jun 2019 15:12:23 +0200
-Subject: [PATCH 05/96] Doc: Pacemaker Development: intro of mocked daemons
-
-Partly as a documentation for ourselves.
----
- doc/Pacemaker_Development/en-US/Ch-Hacking.txt     | 52 ++++++++++++++++++++++
- .../en-US/Pacemaker_Development.xml                | 11 ++---
- .../en-US/Revision_History.xml                     | 13 ++++++
- 3 files changed, 71 insertions(+), 5 deletions(-)
- create mode 100644 doc/Pacemaker_Development/en-US/Ch-Hacking.txt
-
-diff --git a/doc/Pacemaker_Development/en-US/Ch-Hacking.txt b/doc/Pacemaker_Development/en-US/Ch-Hacking.txt
-new file mode 100644
-index 0000000..d8d8173
---- /dev/null
-+++ b/doc/Pacemaker_Development/en-US/Ch-Hacking.txt
-@@ -0,0 +1,52 @@
-+:compat-mode: legacy
-+= Advanced Hacking on the Project =
-+
-+anchor:ch-hacking[Chapter 4. Hacking on Pacemaker]
-+
-+[id="hacking-foreword"]
-+== Foreword ==
-+
-+This chapter aims to be a gentle introduction (or perhaps, rather
-+a summarization of advanced techniques we developed for backreferences)
-+to how deal with the Pacemaker internals effectively.
-+for instance, how to:
-+
-+* verify various interesting interaction-based properties
-+
-+or simply put, all that is in the interest of the core contributors
-+on the project to know, master, and (preferably) also evolve
-+-- way beyond what is in the presumed repertoire of a generic
-+contributor role, which is detailed in other chapters of this guide.
-+
-+Therefore, if you think you will not benefit from any such details
-+in the scope of this chapter, feel free to skip it.
-+
-+== Working with mocked daemons ==
-+
-+Since the Pacemaker run-time consists of multiple co-operating daemons
-+as detailed elsewhere, tracking down the interaction details amongst
-+them can be rather cumbersome.  Since rebuilding existing daemons in
-+a more modular way as opposed to clusters of mutually dependent
-+functions, we elected to grow separate bare-bones counterparts built
-+evolutionary as skeletons just to get the basic (long-term stabilized)
-+communication with typical daemon clients going, and to add new modules
-+in their outer circles (plus minimalistic hook support at those cores)
-+on a demand-driven basis.
-+
-+The code for these is located at `maint/mocked`; for instance,
-+`based-notifyfenced.c` module of `based.c` skeleton mocking
-+`pacemaker-based` daemon was exactly to fulfill investigation helper
-+role (the case at hand was also an impulse to kick off this very
-+sort of maintenance support material, to begin with).
-+
-+Non-trivial knowledge of Pacemaker internals and other skills are
-+needed to use such devised helpers, but given the other way around,
-+some sorts of investigation may be even heftier, it may be the least
-+effort choice.  And when that's the case, advanced contributors are
-+expected to contribute their own extensions they used to validate
-+the reproducibility/actual correctness of the fix along the actual
-+code modifications.  This way, the rest of the development teams is
-+not required to deal with elaborate preconditions, be at guess, or
-+even forced to use a blind faith regarding the causes, consequences
-+and validity regarding the raised issues/fixes, for the greater
-+benefit of all.
-diff --git a/doc/Pacemaker_Development/en-US/Pacemaker_Development.xml b/doc/Pacemaker_Development/en-US/Pacemaker_Development.xml
-index 854d77a..6641d3b 100644
---- a/doc/Pacemaker_Development/en-US/Pacemaker_Development.xml
-+++ b/doc/Pacemaker_Development/en-US/Pacemaker_Development.xml
-@@ -4,10 +4,11 @@
- %BOOK_ENTITIES;
- ]>
- <book>
--    <xi:include href="Book_Info.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
--    <xi:include href="Ch-FAQ.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
--    <xi:include href="Ch-Coding.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
--    <xi:include href="Ch-Python.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
--    <xi:include href="Revision_History.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
-+    <xi:include href="Book_Info.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
-+    <xi:include href="Ch-FAQ.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
-+    <xi:include href="Ch-Coding.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
-+    <xi:include href="Ch-Python.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
-+    <xi:include href="Ch-Hacking.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
-+    <xi:include href="Revision_History.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
-     <index></index>
- </book>
-diff --git a/doc/Pacemaker_Development/en-US/Revision_History.xml b/doc/Pacemaker_Development/en-US/Revision_History.xml
-index fd29d52..10ae102 100644
---- a/doc/Pacemaker_Development/en-US/Revision_History.xml
-+++ b/doc/Pacemaker_Development/en-US/Revision_History.xml
-@@ -35,6 +35,19 @@
-         </revdescription>
-       </revision>
- 
-+      <revision>
-+        <revnumber>1-2</revnumber>
-+        <date>Fri 17 May 2019</date>
-+        <author>
-+          <firstname>Jan</firstname><surname>Pokorný</surname>
-+          <email>poki@redhat.com</email>
-+        </author>
-+        <revdescription>
-+          <simplelist><member>Start capturing hacking howto
-+                              for advanced contributors</member></simplelist>
-+        </revdescription>
-+      </revision>
-+
-     </revhistory>
-   </simpara>
- </appendix>
--- 
-1.8.3.1
-
-
-From 96244e2c9bb4f32dc38bd4fa1c091c9f0d5bbf57 Mon Sep 17 00:00:00 2001
-From: "Gao,Yan" <ygao@suse.com>
-Date: Fri, 26 Apr 2019 11:52:59 +0200
-Subject: [PATCH 06/96] Fix: libcrmcommon: correctly apply XML diffs with
- multiple move/create changes
-
-Given a resource group:
-```
-<group id="dummies">
-  <primitive id="dummy0"/>
-  <primitive id="dummy1"/>
-  <primitive id="dummy2"/>
-  <primitive id="dummy3"/>
-  <primitive id="dummy4"/>
-</group>
-```
-
-, if we'd like to change it to:
-```
-<group id="dummies">
-  <primitive id="dummy3"/>
-  <primitive id="dummy4"/>
-  <primitive id="dummy2"/>
-  <primitive id="dummy0"/>
-  <primitive id="dummy1"/>
-</group>
-```
-
-, the generated XML diff would be like:
-```
-<diff format="2">
-  <change operation="move" path="//primitive[@id=dummy3]" position="0"/>
-  <change operation="move" path="//primitive[@id=dummy4]" position="1"/>
-  <change operation="move" path="//primitive[@id=dummy0]" position="3"/>
-  <change operation="move" path="//primitive[@id=dummy1]" position="4"/>
-</diff>
-```
-
-Previously after applying the XML diff, the resulting XML would be a mess:
-```
-<group id="dummies">
-  <primitive id="dummy3"/>
-  <primitive id="dummy4"/>
-  <primitive id="dummy0"/>
-  <primitive id="dummy2"/>
-  <primitive id="dummy1"/>
-</group>
-```
-It's because the positions of the already moved XML objects could be
-affected by the later moved objects.
-
-This commit fixes it by temporarily putting "move" objects after the
-last sibling and also delaying the adding of any "create" objects, then
-placing them to the target positions in the right order.
----
- lib/common/xml.c | 126 ++++++++++++++++++++++++++++++++++++++++++-------------
- 1 file changed, 97 insertions(+), 29 deletions(-)
-
-diff --git a/lib/common/xml.c b/lib/common/xml.c
-index 6728247..f7d6c70 100644
---- a/lib/common/xml.c
-+++ b/lib/common/xml.c
-@@ -1467,11 +1467,40 @@ __xml_find_path(xmlNode *top, const char *key, int target_position)
-     return target;
- }
- 
-+typedef struct xml_change_obj_s {
-+    xmlNode *change;
-+    xmlNode *match;
-+} xml_change_obj_t;
-+
-+static gint
-+sort_change_obj_by_position(gconstpointer a, gconstpointer b)
-+{
-+    const xml_change_obj_t *change_obj_a = a;
-+    const xml_change_obj_t *change_obj_b = b;
-+    int position_a = -1;
-+    int position_b = -1;
-+
-+    crm_element_value_int(change_obj_a->change, XML_DIFF_POSITION, &position_a);
-+    crm_element_value_int(change_obj_b->change, XML_DIFF_POSITION, &position_b);
-+
-+    if (position_a < position_b) {
-+        return -1;
-+
-+    } else if (position_a > position_b) {
-+        return 1;
-+    }
-+
-+    return 0;
-+}
-+
- static int
- xml_apply_patchset_v2(xmlNode *xml, xmlNode *patchset)
- {
-     int rc = pcmk_ok;
-     xmlNode *change = NULL;
-+    GListPtr change_objs = NULL;
-+    GListPtr gIter = NULL;
-+
-     for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) {
-         xmlNode *match = NULL;
-         const char *op = crm_element_value(change, XML_DIFF_OP);
-@@ -1483,6 +1512,7 @@ xml_apply_patchset_v2(xmlNode *xml, xmlNode *patchset)
-             continue;
-         }
- 
-+        // "delete" changes for XML comments are generated with "position"
-         if(strcmp(op, "delete") == 0) {
-             crm_element_value_int(change, XML_DIFF_POSITION, &position);
-         }
-@@ -1502,7 +1532,71 @@ xml_apply_patchset_v2(xmlNode *xml, xmlNode *patchset)
-             rc = -pcmk_err_diff_failed;
-             continue;
- 
--        } else if(strcmp(op, "create") == 0) {
-+        } else if (strcmp(op, "create") == 0 || strcmp(op, "move") == 0) {
-+            // Delay the adding of a "create" object
-+            xml_change_obj_t *change_obj = calloc(1, sizeof(xml_change_obj_t));
-+
-+            CRM_ASSERT(change_obj != NULL);
-+
-+            change_obj->change = change;
-+            change_obj->match = match;
-+
-+            change_objs = g_list_append(change_objs, change_obj);
-+
-+            if (strcmp(op, "move") == 0) {
-+                // Temporarily put the "move" object after the last sibling
-+                if (match->parent != NULL && match->parent->last != NULL) {
-+                    xmlAddNextSibling(match->parent->last, match);
-+                }
-+            }
-+
-+        } else if(strcmp(op, "delete") == 0) {
-+            free_xml(match);
-+
-+        } else if(strcmp(op, "modify") == 0) {
-+            xmlAttr *pIter = pcmk__first_xml_attr(match);
-+            xmlNode *attrs = __xml_first_child(first_named_child(change, XML_DIFF_RESULT));
-+
-+            if(attrs == NULL) {
-+                rc = -ENOMSG;
-+                continue;
-+            }
-+            while(pIter != NULL) {
-+                const char *name = (const char *)pIter->name;
-+
-+                pIter = pIter->next;
-+                xml_remove_prop(match, name);
-+            }
-+
-+            for (pIter = pcmk__first_xml_attr(attrs); pIter != NULL; pIter = pIter->next) {
-+                const char *name = (const char *)pIter->name;
-+                const char *value = crm_element_value(attrs, name);
-+
-+                crm_xml_add(match, name, value);
-+            }
-+
-+        } else {
-+            crm_err("Unknown operation: %s", op);
-+        }
-+    }
-+
-+    // Changes should be generated in the right order. Double checking.
-+    change_objs = g_list_sort(change_objs, sort_change_obj_by_position);
-+
-+    for (gIter = change_objs; gIter; gIter = gIter->next) {
-+        xml_change_obj_t *change_obj = gIter->data;
-+        xmlNode *match = change_obj->match;
-+        const char *op = NULL;
-+        const char *xpath = NULL;
-+
-+        change = change_obj->change;
-+
-+        op = crm_element_value(change, XML_DIFF_OP);
-+        xpath = crm_element_value(change, XML_DIFF_PATH);
-+
-+        crm_trace("Continue performing %s on %s with %p", op, xpath, match);
-+
-+        if(strcmp(op, "create") == 0) {
-             int position = 0;
-             xmlNode *child = NULL;
-             xmlNode *match_child = NULL;
-@@ -1570,36 +1664,10 @@ xml_apply_patchset_v2(xmlNode *xml, xmlNode *patchset)
-                         match->name, ID(match), __xml_offset(match), position, match->prev);
-                 rc = -pcmk_err_diff_failed;
-             }
--
--        } else if(strcmp(op, "delete") == 0) {
--            free_xml(match);
--
--        } else if(strcmp(op, "modify") == 0) {
--            xmlAttr *pIter = pcmk__first_xml_attr(match);
--            xmlNode *attrs = __xml_first_child(first_named_child(change, XML_DIFF_RESULT));
--
--            if(attrs == NULL) {
--                rc = -ENOMSG;
--                continue;
--            }
--            while(pIter != NULL) {
--                const char *name = (const char *)pIter->name;
--
--                pIter = pIter->next;
--                xml_remove_prop(match, name);
--            }
--
--            for (pIter = pcmk__first_xml_attr(attrs); pIter != NULL; pIter = pIter->next) {
--                const char *name = (const char *)pIter->name;
--                const char *value = crm_element_value(attrs, name);
--
--                crm_xml_add(match, name, value);
--            }
--
--        } else {
--            crm_err("Unknown operation: %s", op);
-         }
-     }
-+
-+    g_list_free_full(change_objs, free);
-     return rc;
- }
- 
--- 
-1.8.3.1
-
-
-From a3de5c611febf265880c17a8b49267eaa968c741 Mon Sep 17 00:00:00 2001
-From: "Gao,Yan" <ygao@suse.com>
-Date: Tue, 30 Apr 2019 00:15:03 +0200
-Subject: [PATCH 07/96] Fix: libcrmcommon: avoid possible use-of-NULL when
- applying XML diffs
-
----
- lib/common/xml.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/lib/common/xml.c b/lib/common/xml.c
-index f7d6c70..5f52600 100644
---- a/lib/common/xml.c
-+++ b/lib/common/xml.c
-@@ -1507,11 +1507,12 @@ xml_apply_patchset_v2(xmlNode *xml, xmlNode *patchset)
-         const char *xpath = crm_element_value(change, XML_DIFF_PATH);
-         int position = -1;
- 
--        crm_trace("Processing %s %s", change->name, op);
-         if(op == NULL) {
-             continue;
-         }
- 
-+        crm_trace("Processing %s %s", change->name, op);
-+
-         // "delete" changes for XML comments are generated with "position"
-         if(strcmp(op, "delete") == 0) {
-             crm_element_value_int(change, XML_DIFF_POSITION, &position);
--- 
-1.8.3.1
-
-
-From f40dad3645bfee99ad6b2bafbe69242171c44cf3 Mon Sep 17 00:00:00 2001
-From: "Gao,Yan" <ygao@suse.com>
-Date: Tue, 30 Apr 2019 00:19:46 +0200
-Subject: [PATCH 08/96] Fix: libcrmcommon: return error when applying XML diffs
- containing unknown operations
-
----
- lib/common/xml.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/lib/common/xml.c b/lib/common/xml.c
-index 5f52600..91c0edb 100644
---- a/lib/common/xml.c
-+++ b/lib/common/xml.c
-@@ -1578,6 +1578,7 @@ xml_apply_patchset_v2(xmlNode *xml, xmlNode *patchset)
- 
-         } else {
-             crm_err("Unknown operation: %s", op);
-+            rc = -pcmk_err_diff_failed;
-         }
-     }
- 
--- 
-1.8.3.1
-
-
-From 3a8c61bc744a3f59d097403231a4f3f3c39a990c Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Fri, 22 Mar 2019 17:49:30 -0500
-Subject: [PATCH 09/96] Log: controller: improve failed recurring action
- messages
-
-Recurring action status changes can be reported in any later transition, not
-just the one they were initially scheduled in. Previously, they would be logged
-as an "Old event". Now, distinguish this situation.
----
- crmd/te_events.c | 34 +++++++++++++++++++---------------
- 1 file changed, 19 insertions(+), 15 deletions(-)
-
-diff --git a/crmd/te_events.c b/crmd/te_events.c
-index 1f7a34c..eb1a8ca 100644
---- a/crmd/te_events.c
-+++ b/crmd/te_events.c
-@@ -1,19 +1,10 @@
- /*
-- * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
-+ * Copyright 2004-2019 the Pacemaker project contributors
-  *
-- * This program is free software; you can redistribute it and/or
-- * modify it under the terms of the GNU General Public
-- * License as published by the Free Software Foundation; either
-- * version 2 of the License, or (at your option) any later version.
-+ * The version control history for this file may have further details.
-  *
-- * This software is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-- * General Public License for more details.
-- *
-- * You should have received a copy of the GNU General Public
-- * License along with this library; if not, write to the Free Software
-- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-+ * This source code is licensed under the GNU General Public License version 2
-+ * or later (GPLv2+) WITHOUT ANY WARRANTY.
-  */
- 
- #include <crm_internal.h>
-@@ -495,8 +486,21 @@ process_graph_event(xmlNode *event, const char *event_node)
-         abort_transition(INFINITY, tg_restart, "Foreign event", event);
- 
-     } else if (transition_graph->id != transition_num) {
--        desc = "arrived really late";
--        abort_transition(INFINITY, tg_restart, "Old event", event);
-+        int interval_ms = 0;
-+
-+        if (parse_op_key(id, NULL, NULL, &interval_ms)
-+            && (interval_ms != 0)) {
-+            /* Recurring actions have the transition number they were first
-+             * scheduled in.
-+             */
-+            desc = "arrived after initial scheduling";
-+            abort_transition(INFINITY, tg_restart, "Change in recurring result",
-+                             event);
-+
-+        } else {
-+            desc = "arrived really late";
-+            abort_transition(INFINITY, tg_restart, "Old event", event);
-+        }
- 
-     } else if (transition_graph->complete) {
-         desc = "arrived late";
--- 
-1.8.3.1
-
-
-From dac669b390cfb1be265c71cb588fa0a67ecdd929 Mon Sep 17 00:00:00 2001
-From: "Gao,Yan" <ygao@suse.com>
-Date: Thu, 9 May 2019 13:24:35 +0200
-Subject: [PATCH 10/96] Fix: controller: confirm cancel of failed monitors
-
-Usually after a monitor has been cancelled from executor, contoller
-erases the corresponding lrm_rsc_op from the cib, and DC will confirm
-the cancel action by process_op_deletion() according to the cib diff.
-
-But if a monitor has failed, the lrm_rsc_op will be recorded as
-"last_failure". When cancelling it, the lrm_rsc_op won't get erased from
-the cib given the logic on purpose in erase_lrm_history_by_op(). So that
-the cancel action won't have a chance to get confirmed by DC with
-process_op_deletion().
-
-Previously cluster transition would get stuck waiting for the remaining
-action timer to time out.
-
-This commit fixes the issue by directly acknowledging the cancel action
-in this case and enabling DC to be able to confirm it.
-
-This also moves get_node_id() function into controld_utils.c for common
-use.
-
-Producer:
-```
- # Insert a 10s sleep in the monitor action of RA
- # /usr/lib/ocf/resource.d/pacemaker/Stateful:
-
-  stateful_monitor() {
- +    sleep 10
-      stateful_check_state "master"
-
- # Add a promotable clone resource:
-
- crm configure primitive stateful ocf:pacemaker:Stateful \
-         op monitor interval=5 role=Master \
-         op monitor interval=10 role=Slave
- crm configure clone p-clone stateful \
-         meta promotable=true
-
- # Wait for the resource instance to be started, promoted to be master,
- # and monitor for master role to complete.
-
- # Set is-managed=false for the promotable clone:
- crm_resource --meta -p is-managed -v false -r p-clone
-
- # Change the status of the master instance to be slave and immediately
- # enforce refresh of it:
- echo slave > /var/run/Stateful-stateful.state; crm_resource --refresh -r stateful --force
-
- # Wait for probe to complete, and then monitor for slave role to be
- # issued:
- sleep 15
-
- # While the monitor for slave role is still in progress, change the
- # status to be master again:
- echo master > /var/run/Stateful-stateful.state
-
- # The monitor for slave role returns error. Cluster issues monitor for
- # master role instead and tries to cancel the failed one for slave role.
- # But cluster transition gets stuck. Depending on the monitor timeout
- # configured for the slave role plus cluster-delay, only after that
- # controller eventually says:
-
- pacemaker-controld[21205] error: Node opensuse150 did not send cancel result (via controller) within 20000ms (action timeout plus cluster-delay)
- pacemaker-controld[21205] error: [Action    1]: In-flight rsc op stateful_monitor_10000            on opensuse150 (priority: 0, waiting: none)
- pacemaker-controld[21205] notice: Transition 6 aborted: Action lost
-
-```
----
- crmd/crmd_utils.h   |  2 ++
- crmd/lrm.c          | 38 ++++++++++++++++++++++++++++++++++++++
- crmd/te_callbacks.c | 21 ++-------------------
- crmd/te_events.c    | 32 ++++++++++++++++++++++++++++++++
- crmd/tengine.h      |  1 +
- crmd/utils.c        | 13 +++++++++++++
- 6 files changed, 88 insertions(+), 19 deletions(-)
-
-diff --git a/crmd/crmd_utils.h b/crmd/crmd_utils.h
-index d49642f..a754487 100644
---- a/crmd/crmd_utils.h
-+++ b/crmd/crmd_utils.h
-@@ -112,6 +112,8 @@ void crmd_peer_down(crm_node_t *peer, bool full);
- unsigned int cib_op_timeout(void);
- bool controld_action_is_recordable(const char *action);
- 
-+const char *get_node_id(xmlNode *lrm_rsc_op);
-+
- /* Convenience macro for registering a CIB callback
-  * (assumes that data can be freed with free())
-  */
-diff --git a/crmd/lrm.c b/crmd/lrm.c
-index 1c9a276..776c02b 100644
---- a/crmd/lrm.c
-+++ b/crmd/lrm.c
-@@ -2487,6 +2487,30 @@ unescape_newlines(const char *string)
-     return ret;
- }
- 
-+static bool
-+did_lrm_rsc_op_fail(lrm_state_t *lrm_state, const char * rsc_id,
-+                    const char * op_type, guint interval_ms)
-+{
-+    rsc_history_t *entry = NULL;
-+
-+    CRM_CHECK(lrm_state != NULL, return FALSE);
-+    CRM_CHECK(rsc_id != NULL, return FALSE);
-+    CRM_CHECK(op_type != NULL, return FALSE);
-+
-+    entry = g_hash_table_lookup(lrm_state->resource_history, rsc_id);
-+    if (entry == NULL || entry->failed == NULL) {
-+        return FALSE;
-+    }
-+
-+    if (crm_str_eq(entry->failed->rsc_id, rsc_id, TRUE)
-+        && safe_str_eq(entry->failed->op_type, op_type)
-+        && entry->failed->interval == interval_ms) {
-+        return TRUE;
-+    }
-+
-+    return FALSE;
-+}
-+
- void
- process_lrm_event(lrm_state_t *lrm_state, lrmd_event_data_t *op,
-                   struct recurring_op_s *pending, xmlNode *action_xml)
-@@ -2616,6 +2640,20 @@ process_lrm_event(lrm_state_t *lrm_state, lrmd_event_data_t *op,
-             erase_lrm_history_by_op(lrm_state, op);
-         }
- 
-+        /* If the recurring operation had failed, the lrm_rsc_op is recorded as
-+         * "last_failure" which won't get erased from the cib given the logic on
-+         * purpose in erase_lrm_history_by_op(). So that the cancel action won't
-+         * have a chance to get confirmed by DC with process_op_deletion().
-+         * Cluster transition would get stuck waiting for the remaining action
-+         * timer to time out.
-+         *
-+         * Directly acknowledge the cancel operation in this case.
-+         */
-+        if (did_lrm_rsc_op_fail(lrm_state, pending->rsc_id,
-+                                pending->op_type, pending->interval)) {
-+            need_direct_ack = TRUE;
-+        }
-+
-     } else if (op->rsc_deleted) {
-         /* This recurring operation was cancelled (but not by us, and the
-          * executor does not have resource information, likely due to resource
-diff --git a/crmd/te_callbacks.c b/crmd/te_callbacks.c
-index 087f3e1..9faf932 100644
---- a/crmd/te_callbacks.c
-+++ b/crmd/te_callbacks.c
-@@ -42,19 +42,6 @@ static unsigned long int stonith_max_attempts = 10;
- /* #define rsc_op_template "//"XML_TAG_DIFF_ADDED"//"XML_TAG_CIB"//"XML_CIB_TAG_STATE"[@uname='%s']"//"XML_LRM_TAG_RSC_OP"[@id='%s]" */
- #define rsc_op_template "//"XML_TAG_DIFF_ADDED"//"XML_TAG_CIB"//"XML_LRM_TAG_RSC_OP"[@id='%s']"
- 
--static const char *
--get_node_id(xmlNode * rsc_op)
--{
--    xmlNode *node = rsc_op;
--
--    while (node != NULL && safe_str_neq(XML_CIB_TAG_STATE, TYPE(node))) {
--        node = node->parent;
--    }
--
--    CRM_CHECK(node != NULL, return NULL);
--    return ID(node);
--}
--
- void
- update_stonith_max_attempts(const char* value)
- {
-@@ -384,12 +371,8 @@ process_op_deletion(const char *xpath, xmlNode *change)
-     node_uuid = extract_node_uuid(xpath);
-     cancel = get_cancel_action(key, node_uuid);
-     if (cancel) {
--        crm_info("Cancellation of %s on %s confirmed (%d)",
--                 key, node_uuid, cancel->id);
--        stop_te_timer(cancel->timer);
--        te_action_confirmed(cancel);
--        update_graph(transition_graph, cancel);
--        trigger_graph();
-+        confirm_cancel_action(cancel);
-+
-     } else {
-         abort_transition(INFINITY, tg_restart, "Resource operation removal",
-                          change);
-diff --git a/crmd/te_events.c b/crmd/te_events.c
-index eb1a8ca..b398739 100644
---- a/crmd/te_events.c
-+++ b/crmd/te_events.c
-@@ -373,6 +373,27 @@ get_cancel_action(const char *id, const char *node)
-     return NULL;
- }
- 
-+void
-+confirm_cancel_action(crm_action_t *cancel)
-+{
-+    const char *op_key = NULL;
-+    const char *node_name = NULL;
-+
-+    CRM_ASSERT(cancel != NULL);
-+
-+    op_key = crm_element_value(cancel->xml, XML_LRM_ATTR_TASK_KEY);
-+    node_name = crm_element_value(cancel->xml, XML_LRM_ATTR_TARGET);
-+
-+    stop_te_timer(cancel->timer);
-+    te_action_confirmed(cancel);
-+    update_graph(transition_graph, cancel);
-+
-+    crm_info("Cancellation of %s on %s confirmed (action %d)",
-+             op_key, node_name, cancel->id);
-+
-+    trigger_graph();
-+}
-+
- /* downed nodes are listed like: <downed> <node id="UUID1" /> ... </downed> */
- #define XPATH_DOWNED "//" XML_GRAPH_TAG_DOWNED \
-                      "/" XML_CIB_TAG_NODE "[@" XML_ATTR_UUID "='%s']"
-@@ -493,6 +514,17 @@ process_graph_event(xmlNode *event, const char *event_node)
-             /* Recurring actions have the transition number they were first
-              * scheduled in.
-              */
-+
-+            if (status == PCMK_LRM_OP_CANCELLED) {
-+                const char *node_id = get_node_id(event);
-+
-+                action = get_cancel_action(id, node_id);
-+                if (action) {
-+                    confirm_cancel_action(action);
-+                }
-+                goto bail;
-+            }
-+
-             desc = "arrived after initial scheduling";
-             abort_transition(INFINITY, tg_restart, "Change in recurring result",
-                              event);
-diff --git a/crmd/tengine.h b/crmd/tengine.h
-index b5141a0..1a9b2d2 100644
---- a/crmd/tengine.h
-+++ b/crmd/tengine.h
-@@ -35,6 +35,7 @@ void execute_stonith_cleanup(void);
- /* tengine */
- extern crm_action_t *match_down_event(const char *target, bool quiet);
- extern crm_action_t *get_cancel_action(const char *id, const char *node);
-+void confirm_cancel_action(crm_action_t *cancel);
- 
- void controld_record_action_timeout(crm_action_t *action);
- extern gboolean fail_incompletable_actions(crm_graph_t * graph, const char *down_node);
-diff --git a/crmd/utils.c b/crmd/utils.c
-index 08abc6e..761f5a7 100644
---- a/crmd/utils.c
-+++ b/crmd/utils.c
-@@ -1054,3 +1054,16 @@ cib_op_timeout()
-     }
-     return calculated_timeout;
- }
-+
-+const char *
-+get_node_id(xmlNode *lrm_rsc_op)
-+{
-+    xmlNode *node = lrm_rsc_op;
-+
-+    while (node != NULL && safe_str_neq(XML_CIB_TAG_STATE, TYPE(node))) {
-+        node = node->parent;
-+    }
-+
-+    CRM_CHECK(node != NULL, return NULL);
-+    return ID(node);
-+}
--- 
-1.8.3.1
-
-
-From a81ca9625e8d1ccd7f79fbe464b9f4221e8671f2 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 9 May 2019 20:26:08 -0500
-Subject: [PATCH 11/96] Refactor: libpe_status: functionize unfencing digest
- code more
-
-... for readability, reusability, and avoiding unnecessary function calls or
-memory allocation.
----
- lib/pengine/utils.c | 159 ++++++++++++++++++++++++++++++++++++++--------------
- 1 file changed, 118 insertions(+), 41 deletions(-)
-
-diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c
-index d09b0d8..b6a31d1 100644
---- a/lib/pengine/utils.c
-+++ b/lib/pengine/utils.c
-@@ -2091,57 +2091,134 @@ rsc_action_digest_cmp(resource_t * rsc, xmlNode * xml_op, node_t * node,
-     return data;
- }
- 
-+/*!
-+ * \internal
-+ * \brief Create an unfencing summary for use in special node attribute
-+ *
-+ * Create a string combining a fence device's resource ID, agent type, and
-+ * parameter digest (whether for all parameters or just non-private parameters).
-+ * This can be stored in a special node attribute, allowing us to detect changes
-+ * in either the agent type or parameters, to know whether unfencing must be
-+ * redone or can be safely skipped when the device's history is cleaned.
-+ *
-+ * \param[in] rsc_id        Fence device resource ID
-+ * \param[in] agent_type    Fence device agent
-+ * \param[in] param_digest  Fence device parameter digest
-+ *
-+ * \return Newly allocated string with unfencing digest
-+ * \note The caller is responsible for freeing the result.
-+ */
-+static inline char *
-+create_unfencing_summary(const char *rsc_id, const char *agent_type,
-+                         const char *param_digest)
-+{
-+    return crm_strdup_printf("%s:%s:%s", rsc_id, agent_type, param_digest);
-+}
-+
-+/*!
-+ * \internal
-+ * \brief Check whether a node can skip unfencing
-+ *
-+ * Check whether a fence device's current definition matches a node's
-+ * stored summary of when it was last unfenced by the device.
-+ *
-+ * \param[in] rsc_id        Fence device's resource ID
-+ * \param[in] agent         Fence device's agent type
-+ * \param[in] digest_calc   Fence device's current parameter digest
-+ * \param[in] node_summary  Value of node's special unfencing node attribute
-+ *                          (a comma-separated list of unfencing summaries for
-+ *                          all devices that have unfenced this node)
-+ *
-+ * \return TRUE if digest matches, FALSE otherwise
-+ */
-+static bool
-+unfencing_digest_matches(const char *rsc_id, const char *agent,
-+                         const char *digest_calc, const char *node_summary)
-+{
-+    bool matches = FALSE;
-+
-+    if (rsc_id && agent && digest_calc && node_summary) {
-+        char *search_secure = create_unfencing_summary(rsc_id, agent,
-+                                                       digest_calc);
-+
-+        /* The digest was calculated including the device ID and agent,
-+         * so there is no risk of collision using strstr().
-+         */
-+        matches = (strstr(node_summary, search_secure) != NULL);
-+        crm_trace("Calculated unfencing digest '%s' %sfound in '%s'",
-+                  search_secure, matches? "" : "not ", node_summary);
-+        free(search_secure);
-+    }
-+    return matches;
-+}
-+
-+/* Magic string to use as action name for digest cache entries used for
-+ * unfencing checks. This is not a real action name (i.e. "on"), so
-+ * check_action_definition() won't confuse these entries with real actions.
-+ */
- #define STONITH_DIGEST_TASK "stonith-on"
- 
-+/*!
-+ * \internal
-+ * \brief Calculate fence device digests and digest comparison result
-+ *
-+ * \param[in] rsc       Fence device resource
-+ * \param[in] agent     Fence device's agent type
-+ * \param[in] node      Node with digest cache to use
-+ * \param[in] data_set  Cluster working set
-+ *
-+ * \return Node's digest cache entry
-+ */
- static op_digest_cache_t *
--fencing_action_digest_cmp(resource_t * rsc, node_t * node, pe_working_set_t * data_set)
-+fencing_action_digest_cmp(pe_resource_t *rsc, const char *agent,
-+                          pe_node_t *node, pe_working_set_t *data_set)
- {
--    char *key = generate_op_key(rsc->id, STONITH_DIGEST_TASK, 0);
--    op_digest_cache_t *data = rsc_action_digest(rsc, STONITH_DIGEST_TASK, key, node, NULL, data_set);
-+    const char *node_summary = NULL;
- 
--    const char *digest_all = pe_node_attribute_raw(node, CRM_ATTR_DIGESTS_ALL);
--    const char *digest_secure = pe_node_attribute_raw(node, CRM_ATTR_DIGESTS_SECURE);
-+    // Calculate device's current parameter digests
-+    char *key = generate_op_key(rsc->id, STONITH_DIGEST_TASK, 0);
-+    op_digest_cache_t *data = rsc_action_digest(rsc, STONITH_DIGEST_TASK, key,
-+                                                node, NULL, data_set);
- 
--    /* No 'reloads' for fencing device changes
--     *
--     * We use the resource id + agent + digest so that we can detect
--     * changes to the agent and/or the parameters used
--     */
--    char *search_all = crm_strdup_printf("%s:%s:%s", rsc->id, (const char*)g_hash_table_lookup(rsc->meta, XML_ATTR_TYPE), data->digest_all_calc);
--    char *search_secure = crm_strdup_printf("%s:%s:%s", rsc->id, (const char*)g_hash_table_lookup(rsc->meta, XML_ATTR_TYPE), data->digest_secure_calc);
-+    free(key);
- 
--    data->rc = RSC_DIGEST_ALL;
--    if (digest_all == NULL) {
--        /* it is unknown what the previous op digest was */
-+    // Check whether node has special unfencing summary node attribute
-+    node_summary = pe_node_attribute_raw(node, CRM_ATTR_DIGESTS_ALL);
-+    if (node_summary == NULL) {
-         data->rc = RSC_DIGEST_UNKNOWN;
-+        return data;
-+    }
- 
--    } else if (strstr(digest_all, search_all)) {
-+    // Check whether full parameter digest matches
-+    if (unfencing_digest_matches(rsc->id, agent, data->digest_all_calc,
-+                                 node_summary)) {
-         data->rc = RSC_DIGEST_MATCH;
-+        return data;
-+    }
- 
--    } else if(digest_secure && data->digest_secure_calc) {
--        if(strstr(digest_secure, search_secure)) {
--            if (is_set(data_set->flags, pe_flag_stdout)) {
--                printf("Only 'private' parameters to %s for unfencing %s changed\n",
--                       rsc->id, node->details->uname);
--            }
--            data->rc = RSC_DIGEST_MATCH;
-+    // Check whether secure parameter digest matches
-+    node_summary = pe_node_attribute_raw(node, CRM_ATTR_DIGESTS_SECURE);
-+    if (unfencing_digest_matches(rsc->id, agent, data->digest_secure_calc,
-+                                 node_summary)) {
-+        data->rc = RSC_DIGEST_MATCH;
-+        if (is_set(data_set->flags, pe_flag_stdout)) {
-+            printf("Only 'private' parameters to %s for unfencing %s changed\n",
-+                   rsc->id, node->details->uname);
-         }
-+        return data;
-     }
- 
--    if (is_set(data_set->flags, pe_flag_sanitized)
--        && is_set(data_set->flags, pe_flag_stdout)
--        && (data->rc == RSC_DIGEST_ALL)
-+    // Parameters don't match
-+    data->rc = RSC_DIGEST_ALL;
-+    if (is_set(data_set->flags, (pe_flag_sanitized|pe_flag_stdout))
-         && data->digest_secure_calc) {
--        printf("Parameters to %s for unfencing %s changed, try '%s:%s:%s'\n",
--               rsc->id, node->details->uname, rsc->id,
--               (const char *) g_hash_table_lookup(rsc->meta, XML_ATTR_TYPE),
--               data->digest_secure_calc);
--    }
--
--    free(key);
--    free(search_all);
--    free(search_secure);
-+        char *digest = create_unfencing_summary(rsc->id, agent,
-+                                                data->digest_secure_calc);
- 
-+        printf("Parameters to %s for unfencing %s changed, try '%s'\n",
-+               rsc->id, node->details->uname, digest);
-+        free(digest);
-+    }
-     return data;
- }
- 
-@@ -2228,9 +2305,6 @@ pe_fence_op(node_t * node, const char *op, bool optional, const char *reason, pe
-              *
-              * We may do this for all nodes in the future, but for now
-              * the check_action_definition() based stuff works fine.
--             *
--             * Use "stonith-on" to avoid creating cache entries for
--             * operations check_action_definition() would look for.
-              */
-             long max = 1024;
-             long digests_all_offset = 0;
-@@ -2242,8 +2316,11 @@ pe_fence_op(node_t * node, const char *op, bool optional, const char *reason, pe
- 
-             for (GListPtr gIter = matches; gIter != NULL; gIter = gIter->next) {
-                 resource_t *match = gIter->data;
--                op_digest_cache_t *data = fencing_action_digest_cmp(match, node, data_set);
-+                const char *agent = g_hash_table_lookup(match->meta,
-+                                                        XML_ATTR_TYPE);
-+                op_digest_cache_t *data = NULL;
- 
-+                data = fencing_action_digest_cmp(match, agent, node, data_set);
-                 if(data->rc == RSC_DIGEST_ALL) {
-                     optional = FALSE;
-                     crm_notice("Unfencing %s (remote): because the definition of %s changed", node->details->uname, match->id);
-@@ -2254,11 +2331,11 @@ pe_fence_op(node_t * node, const char *op, bool optional, const char *reason, pe
- 
-                 digests_all_offset += snprintf(
-                     digests_all+digests_all_offset, max-digests_all_offset,
--                    "%s:%s:%s,", match->id, (const char*)g_hash_table_lookup(match->meta, XML_ATTR_TYPE), data->digest_all_calc);
-+                    "%s:%s:%s,", match->id, agent, data->digest_all_calc);
- 
-                 digests_secure_offset += snprintf(
-                     digests_secure+digests_secure_offset, max-digests_secure_offset,
--                    "%s:%s:%s,", match->id, (const char*)g_hash_table_lookup(match->meta, XML_ATTR_TYPE), data->digest_secure_calc);
-+                    "%s:%s:%s,", match->id, agent, data->digest_secure_calc);
-             }
-             g_hash_table_insert(stonith_op->meta,
-                                 strdup(XML_OP_ATTR_DIGESTS_ALL),
--- 
-1.8.3.1
-
-
-From be34a73f9cfb6abdb3e2799593cb0358c01c2521 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Fri, 10 May 2019 11:57:31 -0500
-Subject: [PATCH 12/96] Fix: libpe_status: calculate secure digests for
- unfencing ops
-
-The calculation of digests for detection of when unfencing is needed reused
-rsc_action_digest(). However that would only add secure digests when the
-pe_flag_sanitized flag was set, which is only set by crm_simulate, so secure
-digests would never be added in normal cluster operation. This led to
-node attributes like name="#digests-secure"
-value="stonith-fence_compute-fence-nova:fence_compute:(null),".
-
-Now, rsc_action_digest() takes a new argument to select whether secure digests
-are added, which is always set to TRUE when calculating unfencing digests.
----
- lib/pengine/utils.c | 27 ++++++++++++++++++++++-----
- 1 file changed, 22 insertions(+), 5 deletions(-)
-
-diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c
-index b6a31d1..f52f1c7 100644
---- a/lib/pengine/utils.c
-+++ b/lib/pengine/utils.c
-@@ -1948,9 +1948,24 @@ append_versioned_params(xmlNode *versioned_params, const char *ra_version, xmlNo
- }
- #endif
- 
-+/*!
-+ * \internal
-+ * \brief Calculate action digests and store in node's digest cache
-+ *
-+ * \param[in] rsc          Resource that action was for
-+ * \param[in] task         Name of action performed
-+ * \param[in] key          Action's task key
-+ * \param[in] node         Node action was performed on
-+ * \param[in] xml_op       XML of operation in CIB status (if available)
-+ * \param[in] calc_secure  Whether to calculate secure digest
-+ * \param[in] data_set     Cluster working set
-+ *
-+ * \return Pointer to node's digest cache entry
-+ */
- static op_digest_cache_t *
--rsc_action_digest(resource_t * rsc, const char *task, const char *key,
--                  node_t * node, xmlNode * xml_op, pe_working_set_t * data_set) 
-+rsc_action_digest(pe_resource_t *rsc, const char *task, const char *key,
-+                  pe_node_t *node, xmlNode *xml_op, bool calc_secure,
-+                  pe_working_set_t *data_set)
- {
-     op_digest_cache_t *data = NULL;
- 
-@@ -2018,7 +2033,7 @@ rsc_action_digest(resource_t * rsc, const char *task, const char *key,
- 
-         data->digest_all_calc = calculate_operation_digest(data->params_all, op_version);
- 
--        if (is_set(data_set->flags, pe_flag_sanitized)) {
-+        if (calc_secure) {
-             data->params_secure = copy_xml(data->params_all);
-             if(secure_list) {
-                 filter_parameters(data->params_secure, secure_list, FALSE);
-@@ -2064,7 +2079,9 @@ rsc_action_digest_cmp(resource_t * rsc, xmlNode * xml_op, node_t * node,
- 
-     interval = crm_parse_int(interval_s, "0");
-     key = generate_op_key(rsc->id, task, interval);
--    data = rsc_action_digest(rsc, task, key, node, xml_op, data_set);
-+    data = rsc_action_digest(rsc, task, key, node, xml_op,
-+                             is_set(data_set->flags, pe_flag_sanitized),
-+                             data_set);
- 
-     data->rc = RSC_DIGEST_MATCH;
-     if (digest_restart && data->digest_restart_calc && strcmp(data->digest_restart_calc, digest_restart) != 0) {
-@@ -2178,7 +2195,7 @@ fencing_action_digest_cmp(pe_resource_t *rsc, const char *agent,
-     // Calculate device's current parameter digests
-     char *key = generate_op_key(rsc->id, STONITH_DIGEST_TASK, 0);
-     op_digest_cache_t *data = rsc_action_digest(rsc, STONITH_DIGEST_TASK, key,
--                                                node, NULL, data_set);
-+                                                node, NULL, TRUE, data_set);
- 
-     free(key);
- 
--- 
-1.8.3.1
-
-
-From 8819c2f96f74ab4b4979df5ed04c16dd6bdad5f1 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Sat, 8 Jun 2019 16:25:04 -0500
-Subject: [PATCH 13/96] Refactor: libpe_status: add function for checking
- shutdown attribute
-
-... to reduce code duplication and allow further reuse
----
- include/crm/pengine/internal.h |  2 ++
- lib/pengine/unpack.c           |  8 ++------
- lib/pengine/utils.c            | 20 ++++++++++++++++++++
- 3 files changed, 24 insertions(+), 6 deletions(-)
-
-diff --git a/include/crm/pengine/internal.h b/include/crm/pengine/internal.h
-index c40b075..c3f9f70 100644
---- a/include/crm/pengine/internal.h
-+++ b/include/crm/pengine/internal.h
-@@ -362,4 +362,6 @@ void pe__foreach_param_check(pe_working_set_t *data_set,
-                                         enum pe_check_parameters,
-                                         pe_working_set_t*));
- void pe__free_param_checks(pe_working_set_t *data_set);
-+
-+bool pe__shutdown_requested(pe_node_t *node);
- #endif
-diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c
-index 619ccbf..cf725a1 100644
---- a/lib/pengine/unpack.c
-+++ b/lib/pengine/unpack.c
-@@ -1013,7 +1013,6 @@ unpack_handle_remote_attrs(node_t *this_node, xmlNode *state, pe_working_set_t *
-     const char *resource_discovery_enabled = NULL;
-     xmlNode *attrs = NULL;
-     resource_t *rsc = NULL;
--    const char *shutdown = NULL;
- 
-     if (crm_str_eq((const char *)state->name, XML_CIB_TAG_STATE, TRUE) == FALSE) {
-         return;
-@@ -1035,8 +1034,7 @@ unpack_handle_remote_attrs(node_t *this_node, xmlNode *state, pe_working_set_t *
-     attrs = find_xml_node(state, XML_TAG_TRANSIENT_NODEATTRS, FALSE);
-     add_node_attrs(attrs, this_node, TRUE, data_set);
- 
--    shutdown = pe_node_attribute_raw(this_node, XML_CIB_ATTR_SHUTDOWN);
--    if (shutdown != NULL && safe_str_neq("0", shutdown)) {
-+    if (pe__shutdown_requested(this_node)) {
-         crm_info("Node %s is shutting down", this_node->details->uname);
-         this_node->details->shutdown = TRUE;
-         if (rsc) {
-@@ -1512,7 +1510,6 @@ gboolean
- determine_online_status(xmlNode * node_state, node_t * this_node, pe_working_set_t * data_set)
- {
-     gboolean online = FALSE;
--    const char *shutdown = NULL;
-     const char *exp_state = crm_element_value(node_state, XML_NODE_EXPECTED);
- 
-     if (this_node == NULL) {
-@@ -1522,9 +1519,8 @@ determine_online_status(xmlNode * node_state, node_t * this_node, pe_working_set
- 
-     this_node->details->shutdown = FALSE;
-     this_node->details->expected_up = FALSE;
--    shutdown = pe_node_attribute_raw(this_node, XML_CIB_ATTR_SHUTDOWN);
- 
--    if (shutdown != NULL && safe_str_neq("0", shutdown)) {
-+    if (pe__shutdown_requested(this_node)) {
-         this_node->details->shutdown = TRUE;
- 
-     } else if (safe_str_eq(exp_state, CRMD_JOINSTATE_MEMBER)) {
-diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c
-index f52f1c7..8eac2ce 100644
---- a/lib/pengine/utils.c
-+++ b/lib/pengine/utils.c
-@@ -2522,3 +2522,23 @@ void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrit
-         }
-     }
- }
-+
-+/*!
-+ * \internal
-+ * \brief Check whether shutdown has been requested for a node
-+ *
-+ * \param[in] node  Node to check
-+ *
-+ * \return TRUE if node has shutdown attribute set and nonzero, FALSE otherwise
-+ * \note This differs from simply using node->details->shutdown in that it can
-+ *       be used before that has been determined (and in fact to determine it),
-+ *       and it can also be used to distinguish requested shutdown from implicit
-+ *       shutdown of remote nodes by virtue of their connection stopping.
-+ */
-+bool
-+pe__shutdown_requested(pe_node_t *node)
-+{
-+    const char *shutdown = pe_node_attribute_raw(node, XML_CIB_ATTR_SHUTDOWN);
-+
-+    return shutdown && strcmp(shutdown, "0");
-+}
--- 
-1.8.3.1
-
-
-From 938e99f29ed5faaeb4015247e363ddc7e77208a3 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Wed, 5 Jun 2019 16:37:26 -0500
-Subject: [PATCH 14/96] Fix: scheduler: remote state is failed if node is
- shutting down with connection failure
-
-When determining remote state, if the connection resource is failed and not
-being started again, we consider the state to be unknown if the connection has
-a reconnect interval, because we won't know whether the connection can be
-recovered until the interval expires and we re-attempt connection.
-
-However, if the node is shutting down at the time, we won't re-attempt
-connection, so consider the state failed in that case. (Note that we check the
-actual shutdown node attribute, rather than node->details->shutdown, since that
-is set for remote nodes whenever the connection is stopping.)
-
-This avoids a situation where actions that cannot succeed can be scheduled on a
-remote node that's shutting down.
----
- pengine/allocate.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/pengine/allocate.c b/pengine/allocate.c
-index 578db2f..c9877a4 100644
---- a/pengine/allocate.c
-+++ b/pengine/allocate.c
-@@ -1998,7 +1998,8 @@ get_remote_node_state(pe_node_t *node)
- 
-         if ((remote_rsc->next_role == RSC_ROLE_STOPPED)
-             && remote_rsc->remote_reconnect_interval
--            && node->details->remote_was_fenced) {
-+            && node->details->remote_was_fenced
-+            && !pe__shutdown_requested(node)) {
- 
-             /* We won't know whether the connection is recoverable until the
-              * reconnect interval expires and we reattempt connection.
--- 
-1.8.3.1
-
-
-From c20f8920634f47bbdf699d80dafd50c6a72eac8b Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Wed, 5 Jun 2019 16:43:19 -0500
-Subject: [PATCH 15/96] Fix: libpe_status: don't order implied stops relative
- to a remote connection
-
-Actions behind a remote connection are ordered relative to any start or stop of
-the remote connection. However, if the action is a stop implied due to fencing,
-it does not require the remote connection, and the ordering should not be done.
-
-This avoids a delay in the remote connection recovery if it is failed, e.g.
-previously the ordering would look like:
-
-   fence remote node -> implied stop of resource on remote -> stop connection
-
-Now, the connection stop can proceed simultaneously with the remote node
-fencing.
----
- pengine/allocate.c | 11 +++++------
- 1 file changed, 5 insertions(+), 6 deletions(-)
-
-diff --git a/pengine/allocate.c b/pengine/allocate.c
-index c9877a4..c7c68f8 100644
---- a/pengine/allocate.c
-+++ b/pengine/allocate.c
-@@ -2091,14 +2091,13 @@ apply_remote_ordering(action_t *action, pe_working_set_t *data_set)
-                                        pe_order_implies_first, data_set);
- 
-             } else if(state == remote_state_failed) {
--                /* We would only be here if the resource is
--                 * running on the remote node.  Since we have no
--                 * way to stop it, it is necessary to fence the
--                 * node.
-+                /* The resource is active on the node, but since we don't have a
-+                 * valid connection, the only way to stop the resource is by
-+                 * fencing the node. There is no need to order the stop relative
-+                 * to the remote connection, since the stop will become implied
-+                 * by the fencing.
-                  */
-                 pe_fence_node(data_set, action->node, "resources are active and the connection is unrecoverable");
--                order_action_then_stop(action, remote_rsc,
--                                       pe_order_implies_first, data_set);
- 
-             } else if(remote_rsc->next_role == RSC_ROLE_STOPPED) {
-                 /* State must be remote_state_unknown or remote_state_stopped.
--- 
-1.8.3.1
-
-
-From 26a28ee80b7fc110125eedac377dfa4c0a8e8294 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Fri, 14 Jun 2019 14:08:47 -0500
-Subject: [PATCH 16/96] Test: pengine: update regression tests for remote
- connection ordering change
-
----
- pengine/test10/remote-connection-unrecoverable.dot     | 2 --
- pengine/test10/remote-connection-unrecoverable.exp     | 6 ------
- pengine/test10/remote-connection-unrecoverable.summary | 2 +-
- pengine/test10/remote-fence-before-reconnect.dot       | 1 -
- pengine/test10/remote-fence-before-reconnect.exp       | 6 +-----
- pengine/test10/remote-fence-before-reconnect.summary   | 2 +-
- pengine/test10/remote-recover-all.dot                  | 2 --
- pengine/test10/remote-recover-all.exp                  | 6 ------
- pengine/test10/remote-recover-all.summary              | 4 ++--
- pengine/test10/remote-recover-no-resources.dot         | 1 -
- pengine/test10/remote-recover-no-resources.exp         | 3 ---
- pengine/test10/remote-recover-no-resources.summary     | 2 +-
- pengine/test10/remote-recover-unknown.dot              | 1 -
- pengine/test10/remote-recover-unknown.exp              | 3 ---
- pengine/test10/remote-recover-unknown.summary          | 2 +-
- 15 files changed, 7 insertions(+), 36 deletions(-)
-
-diff --git a/pengine/test10/remote-connection-unrecoverable.dot b/pengine/test10/remote-connection-unrecoverable.dot
-index 0360cd0..b5caca6 100644
---- a/pengine/test10/remote-connection-unrecoverable.dot
-+++ b/pengine/test10/remote-connection-unrecoverable.dot
-@@ -7,14 +7,12 @@ digraph "g" {
- "remote1_stop_0 node1" [ style=bold color="green" fontcolor="orange"]
- "rsc1_delete_0 remote1" -> "rsc1_start_0 node2" [ style = dashed]
- "rsc1_delete_0 remote1" [ style=dashed color="red" fontcolor="black"]
--"rsc1_monitor_0 node2" -> "remote1_stop_0 node1" [ style = bold]
- "rsc1_monitor_0 node2" -> "rsc1_start_0 node2" [ style = bold]
- "rsc1_monitor_0 node2" -> "rsc2-master_demote_0" [ style = bold]
- "rsc1_monitor_0 node2" [ style=bold color="green" fontcolor="black"]
- "rsc1_monitor_10000 node2" [ style=bold color="green" fontcolor="black"]
- "rsc1_start_0 node2" -> "rsc1_monitor_10000 node2" [ style = bold]
- "rsc1_start_0 node2" [ style=bold color="green" fontcolor="black"]
--"rsc1_stop_0 remote1" -> "remote1_stop_0 node1" [ style = bold]
- "rsc1_stop_0 remote1" -> "rsc1_delete_0 remote1" [ style = dashed]
- "rsc1_stop_0 remote1" -> "rsc1_start_0 node2" [ style = bold]
- "rsc1_stop_0 remote1" -> "rsc2-master_demote_0" [ style = bold]
-diff --git a/pengine/test10/remote-connection-unrecoverable.exp b/pengine/test10/remote-connection-unrecoverable.exp
-index 73fa7a1..339ad56 100644
---- a/pengine/test10/remote-connection-unrecoverable.exp
-+++ b/pengine/test10/remote-connection-unrecoverable.exp
-@@ -9,12 +9,6 @@
-       <trigger>
-         <crm_event id="1" operation="stonith" operation_key="stonith-node1-reboot" on_node="node1" on_node_uuid="1"/>
-       </trigger>
--      <trigger>
--        <pseudo_event id="6" operation="stop" operation_key="rsc1_stop_0"/>
--      </trigger>
--      <trigger>
--        <rsc_op id="8" operation="monitor" operation_key="rsc1_monitor_0" on_node="node2" on_node_uuid="2"/>
--      </trigger>
-     </inputs>
-   </synapse>
-   <synapse id="1">
-diff --git a/pengine/test10/remote-connection-unrecoverable.summary b/pengine/test10/remote-connection-unrecoverable.summary
-index efeb765..18f7dc7 100644
---- a/pengine/test10/remote-connection-unrecoverable.summary
-+++ b/pengine/test10/remote-connection-unrecoverable.summary
-@@ -24,12 +24,12 @@ Executing cluster transition:
-  * Resource action: killer          stop on node2
-  * Resource action: rsc1            monitor on node2
-  * Fencing node1 (reboot)
-+ * Pseudo action:   remote1_stop_0
-  * Fencing remote1 (reboot)
-  * Resource action: killer          start on node2
-  * Resource action: killer          monitor=60000 on node2
-  * Pseudo action:   rsc1_stop_0
-  * Pseudo action:   rsc2-master_demote_0
-- * Pseudo action:   remote1_stop_0
-  * Resource action: rsc1            start on node2
-  * Pseudo action:   rsc2_demote_0
-  * Pseudo action:   rsc2-master_demoted_0
-diff --git a/pengine/test10/remote-fence-before-reconnect.dot b/pengine/test10/remote-fence-before-reconnect.dot
-index 4ced43e..5812b7f 100644
---- a/pengine/test10/remote-fence-before-reconnect.dot
-+++ b/pengine/test10/remote-fence-before-reconnect.dot
-@@ -3,7 +3,6 @@
- "fake2_monitor_10000 c7auto1" [ style=bold color="green" fontcolor="black"]
- "fake2_start_0 c7auto1" -> "fake2_monitor_10000 c7auto1" [ style = bold]
- "fake2_start_0 c7auto1" [ style=bold color="green" fontcolor="black"]
--"fake2_stop_0 c7auto4" -> "c7auto4_stop_0 c7auto1" [ style = bold]
- "fake2_stop_0 c7auto4" -> "fake2_start_0 c7auto1" [ style = bold]
- "fake2_stop_0 c7auto4" [ style=bold color="green" fontcolor="orange"]
- "stonith 'reboot' c7auto4" -> "fake2_start_0 c7auto1" [ style = bold]
-diff --git a/pengine/test10/remote-fence-before-reconnect.exp b/pengine/test10/remote-fence-before-reconnect.exp
-index f99d9ef..f506f85 100644
---- a/pengine/test10/remote-fence-before-reconnect.exp
-+++ b/pengine/test10/remote-fence-before-reconnect.exp
-@@ -9,11 +9,7 @@
-         </downed>
-       </rsc_op>
-     </action_set>
--    <inputs>
--      <trigger>
--        <pseudo_event id="13" operation="stop" operation_key="fake2_stop_0"/>
--      </trigger>
--    </inputs>
-+    <inputs/>
-   </synapse>
-   <synapse id="1">
-     <action_set>
-diff --git a/pengine/test10/remote-fence-before-reconnect.summary b/pengine/test10/remote-fence-before-reconnect.summary
-index f61e18b..03eac20 100644
---- a/pengine/test10/remote-fence-before-reconnect.summary
-+++ b/pengine/test10/remote-fence-before-reconnect.summary
-@@ -17,9 +17,9 @@ Transition Summary:
-  * Move       fake2       ( c7auto4 -> c7auto1 )  
- 
- Executing cluster transition:
-+ * Resource action: c7auto4         stop on c7auto1
-  * Fencing c7auto4 (reboot)
-  * Pseudo action:   fake2_stop_0
-- * Resource action: c7auto4         stop on c7auto1
-  * Resource action: fake2           start on c7auto1
-  * Resource action: fake2           monitor=10000 on c7auto1
- 
-diff --git a/pengine/test10/remote-recover-all.dot b/pengine/test10/remote-recover-all.dot
-index 1f967c5..b48b04e 100644
---- a/pengine/test10/remote-recover-all.dot
-+++ b/pengine/test10/remote-recover-all.dot
-@@ -19,7 +19,6 @@ digraph "g" {
- "galera_demote_0 galera-2" -> "galera_stop_0 galera-2" [ style = bold]
- "galera_demote_0 galera-2" [ style=bold color="green" fontcolor="orange"]
- "galera_monitor_10000 galera-0" [ style=bold color="green" fontcolor="black"]
--"galera_stop_0 galera-2" -> "galera-2_stop_0 controller-1" [ style = bold]
- "galera_stop_0 galera-2" -> "galera-master_stopped_0" [ style = bold]
- "galera_stop_0 galera-2" [ style=bold color="green" fontcolor="orange"]
- "haproxy-clone_stop_0" -> "haproxy-clone_stopped_0" [ style = bold]
-@@ -60,7 +59,6 @@ digraph "g" {
- "rabbitmq_post_notify_stonith_0" -> "rabbitmq_post_notify_stonith_0 messaging-0" [ style = bold]
- "rabbitmq_post_notify_stonith_0" -> "rabbitmq_post_notify_stonith_0 messaging-2" [ style = bold]
- "rabbitmq_post_notify_stonith_0" [ style=bold color="green" fontcolor="orange"]
--"rabbitmq_stop_0 messaging-1" -> "messaging-1_stop_0 controller-1" [ style = bold]
- "rabbitmq_stop_0 messaging-1" -> "rabbitmq-clone_stopped_0" [ style = bold]
- "rabbitmq_stop_0 messaging-1" [ style=bold color="green" fontcolor="orange"]
- "redis-master_confirmed-post_notify_stopped_0" [ style=bold color="green" fontcolor="orange"]
-diff --git a/pengine/test10/remote-recover-all.exp b/pengine/test10/remote-recover-all.exp
-index 900781c..e61ad6a 100644
---- a/pengine/test10/remote-recover-all.exp
-+++ b/pengine/test10/remote-recover-all.exp
-@@ -9,9 +9,6 @@
-       <trigger>
-         <crm_event id="1" operation="stonith" operation_key="stonith-controller-1-reboot" on_node="controller-1" on_node_uuid="2"/>
-       </trigger>
--      <trigger>
--        <pseudo_event id="39" operation="stop" operation_key="rabbitmq_stop_0" internal_operation_key="rabbitmq:2_stop_0"/>
--      </trigger>
-     </inputs>
-   </synapse>
-   <synapse id="1">
-@@ -64,9 +61,6 @@
-       <trigger>
-         <crm_event id="1" operation="stonith" operation_key="stonith-controller-1-reboot" on_node="controller-1" on_node_uuid="2"/>
-       </trigger>
--      <trigger>
--        <pseudo_event id="49" operation="stop" operation_key="galera_stop_0" internal_operation_key="galera:1_stop_0"/>
--      </trigger>
-     </inputs>
-   </synapse>
-   <synapse id="5" priority="1000000">
-diff --git a/pengine/test10/remote-recover-all.summary b/pengine/test10/remote-recover-all.summary
-index 865f39a..cfeac3a 100644
---- a/pengine/test10/remote-recover-all.summary
-+++ b/pengine/test10/remote-recover-all.summary
-@@ -63,6 +63,8 @@ Executing cluster transition:
-  * Resource action: stonith-fence_ipmilan-525400b4f6bd stop on controller-0
-  * Pseudo action:   stonith-fence_ipmilan-5254005bdbb5_stop_0
-  * Fencing controller-1 (reboot)
-+ * Pseudo action:   messaging-1_stop_0
-+ * Pseudo action:   galera-2_stop_0
-  * Pseudo action:   redis_post_notify_stop_0
-  * Resource action: redis           notify on controller-0
-  * Resource action: redis           notify on controller-2
-@@ -94,7 +96,6 @@ Executing cluster transition:
-  * Resource action: stonith-fence_ipmilan-525400b4f6bd monitor=60000 on controller-0
-  * Resource action: stonith-fence_ipmilan-5254005bdbb5 start on controller-2
-  * Resource action: galera-0        monitor=20000 on controller-2
-- * Pseudo action:   galera-2_stop_0
-  * Resource action: rabbitmq        notify on messaging-2
-  * Resource action: rabbitmq        notify on messaging-0
-  * Pseudo action:   rabbitmq_notified_0
-@@ -107,7 +108,6 @@ Executing cluster transition:
-  * Resource action: ip-172.17.1.17  start on controller-2
-  * Resource action: ip-172.17.4.11  start on controller-2
-  * Resource action: stonith-fence_ipmilan-5254005bdbb5 monitor=60000 on controller-2
-- * Pseudo action:   messaging-1_stop_0
-  * Pseudo action:   redis_notified_0
-  * Resource action: ip-172.17.1.14  monitor=10000 on controller-2
-  * Resource action: ip-172.17.1.17  monitor=10000 on controller-2
-diff --git a/pengine/test10/remote-recover-no-resources.dot b/pengine/test10/remote-recover-no-resources.dot
-index a46c305..a0b1ecc 100644
---- a/pengine/test10/remote-recover-no-resources.dot
-+++ b/pengine/test10/remote-recover-no-resources.dot
-@@ -45,7 +45,6 @@ digraph "g" {
- "rabbitmq_post_notify_stonith_0" -> "rabbitmq_post_notify_stonith_0 messaging-0" [ style = bold]
- "rabbitmq_post_notify_stonith_0" -> "rabbitmq_post_notify_stonith_0 messaging-2" [ style = bold]
- "rabbitmq_post_notify_stonith_0" [ style=bold color="green" fontcolor="orange"]
--"rabbitmq_stop_0 messaging-1" -> "messaging-1_stop_0 controller-1" [ style = bold]
- "rabbitmq_stop_0 messaging-1" -> "rabbitmq-clone_stopped_0" [ style = bold]
- "rabbitmq_stop_0 messaging-1" [ style=bold color="green" fontcolor="orange"]
- "redis-master_confirmed-post_notify_stopped_0" [ style=bold color="green" fontcolor="orange"]
-diff --git a/pengine/test10/remote-recover-no-resources.exp b/pengine/test10/remote-recover-no-resources.exp
-index 4d82aa4..27f18b5 100644
---- a/pengine/test10/remote-recover-no-resources.exp
-+++ b/pengine/test10/remote-recover-no-resources.exp
-@@ -9,9 +9,6 @@
-       <trigger>
-         <crm_event id="1" operation="stonith" operation_key="stonith-controller-1-reboot" on_node="controller-1" on_node_uuid="2"/>
-       </trigger>
--      <trigger>
--        <pseudo_event id="38" operation="stop" operation_key="rabbitmq_stop_0" internal_operation_key="rabbitmq:2_stop_0"/>
--      </trigger>
-     </inputs>
-   </synapse>
-   <synapse id="1">
-diff --git a/pengine/test10/remote-recover-no-resources.summary b/pengine/test10/remote-recover-no-resources.summary
-index 9527161..c01eb87 100644
---- a/pengine/test10/remote-recover-no-resources.summary
-+++ b/pengine/test10/remote-recover-no-resources.summary
-@@ -60,6 +60,7 @@ Executing cluster transition:
-  * Resource action: stonith-fence_ipmilan-525400b4f6bd stop on controller-0
-  * Pseudo action:   stonith-fence_ipmilan-5254005bdbb5_stop_0
-  * Fencing controller-1 (reboot)
-+ * Pseudo action:   messaging-1_stop_0
-  * Pseudo action:   galera-2_stop_0
-  * Pseudo action:   redis_post_notify_stop_0
-  * Resource action: redis           notify on controller-0
-@@ -92,7 +93,6 @@ Executing cluster transition:
-  * Pseudo action:   ip-172.17.1.17_stop_0
-  * Pseudo action:   ip-172.17.4.11_stop_0
-  * Resource action: stonith-fence_ipmilan-5254005bdbb5 monitor=60000 on controller-2
-- * Pseudo action:   messaging-1_stop_0
-  * Resource action: redis           notify on controller-0
-  * Resource action: redis           notify on controller-2
-  * Pseudo action:   redis-master_confirmed-post_notify_stopped_0
-diff --git a/pengine/test10/remote-recover-unknown.dot b/pengine/test10/remote-recover-unknown.dot
-index a883eb4..1d13e50 100644
---- a/pengine/test10/remote-recover-unknown.dot
-+++ b/pengine/test10/remote-recover-unknown.dot
-@@ -46,7 +46,6 @@ digraph "g" {
- "rabbitmq_post_notify_stonith_0" -> "rabbitmq_post_notify_stonith_0 messaging-0" [ style = bold]
- "rabbitmq_post_notify_stonith_0" -> "rabbitmq_post_notify_stonith_0 messaging-2" [ style = bold]
- "rabbitmq_post_notify_stonith_0" [ style=bold color="green" fontcolor="orange"]
--"rabbitmq_stop_0 messaging-1" -> "messaging-1_stop_0 controller-1" [ style = bold]
- "rabbitmq_stop_0 messaging-1" -> "rabbitmq-clone_stopped_0" [ style = bold]
- "rabbitmq_stop_0 messaging-1" [ style=bold color="green" fontcolor="orange"]
- "redis-master_confirmed-post_notify_stopped_0" [ style=bold color="green" fontcolor="orange"]
-diff --git a/pengine/test10/remote-recover-unknown.exp b/pengine/test10/remote-recover-unknown.exp
-index 65677b4..13bd295 100644
---- a/pengine/test10/remote-recover-unknown.exp
-+++ b/pengine/test10/remote-recover-unknown.exp
-@@ -9,9 +9,6 @@
-       <trigger>
-         <crm_event id="1" operation="stonith" operation_key="stonith-controller-1-reboot" on_node="controller-1" on_node_uuid="2"/>
-       </trigger>
--      <trigger>
--        <pseudo_event id="39" operation="stop" operation_key="rabbitmq_stop_0" internal_operation_key="rabbitmq:2_stop_0"/>
--      </trigger>
-     </inputs>
-   </synapse>
-   <synapse id="1">
-diff --git a/pengine/test10/remote-recover-unknown.summary b/pengine/test10/remote-recover-unknown.summary
-index 78a60d0..64f37cb 100644
---- a/pengine/test10/remote-recover-unknown.summary
-+++ b/pengine/test10/remote-recover-unknown.summary
-@@ -61,6 +61,7 @@ Executing cluster transition:
-  * Resource action: stonith-fence_ipmilan-525400b4f6bd stop on controller-0
-  * Pseudo action:   stonith-fence_ipmilan-5254005bdbb5_stop_0
-  * Fencing controller-1 (reboot)
-+ * Pseudo action:   messaging-1_stop_0
-  * Pseudo action:   galera-2_stop_0
-  * Pseudo action:   redis_post_notify_stop_0
-  * Resource action: redis           notify on controller-0
-@@ -94,7 +95,6 @@ Executing cluster transition:
-  * Pseudo action:   ip-172.17.1.17_stop_0
-  * Pseudo action:   ip-172.17.4.11_stop_0
-  * Resource action: stonith-fence_ipmilan-5254005bdbb5 monitor=60000 on controller-2
-- * Pseudo action:   messaging-1_stop_0
-  * Resource action: redis           notify on controller-0
-  * Resource action: redis           notify on controller-2
-  * Pseudo action:   redis-master_confirmed-post_notify_stopped_0
--- 
-1.8.3.1
-
-
-From 71142273e6b5108224ecdb0082b36f533b604fad Mon Sep 17 00:00:00 2001
-From: Klaus Wenninger <klaus.wenninger@aon.at>
-Date: Mon, 8 Jul 2019 18:17:28 +0200
-Subject: [PATCH 17/96] Fix: fence-history: fail leftover pending-actions after
- stonithd-restart
-
----
- fencing/history.c  | 15 +++++++++++++++
- fencing/internal.h |  8 ++++++++
- fencing/remote.c   |  6 +++---
- 3 files changed, 26 insertions(+), 3 deletions(-)
-
-diff --git a/fencing/history.c b/fencing/history.c
-index 0f98058..c487848 100644
---- a/fencing/history.c
-+++ b/fencing/history.c
-@@ -347,6 +347,21 @@ stonith_merge_in_history_list(GHashTable *history)
- 
-         updated = TRUE;
-         g_hash_table_iter_steal(&iter);
-+
-+        if ((op->state != st_failed) &&
-+            (op->state != st_done) &&
-+            safe_str_eq(op->originator, stonith_our_uname)) {
-+            crm_warn("received pending action we are supposed to be the "
-+                     "owner but it's not in our records -> fail it");
-+            op->state = st_failed;
-+            op->completed = time(NULL);
-+            /* use -EHOSTUNREACH to not introduce a new return-code that might
-+               trigger unexpected results at other places and to prevent
-+               remote_op_done from setting the delegate if not present
-+             */
-+            stonith_bcast_result_to_peers(op, -EHOSTUNREACH);
-+        }
-+
-         g_hash_table_insert(stonith_remote_op_list, op->id, op);
-         /* we could trim the history here but if we bail
-          * out after trim we might miss more recent entries
-diff --git a/fencing/internal.h b/fencing/internal.h
-index 028137f..cd48b53 100644
---- a/fencing/internal.h
-+++ b/fencing/internal.h
-@@ -142,6 +142,14 @@ typedef struct remote_fencing_op_s {
- 
- } remote_fencing_op_t;
- 
-+/*!
-+ * \internal
-+ * \brief Broadcast the result of an operation to the peers.
-+ * \param op, Operation whose result should be broadcast
-+ * \param rc, Result of the operation
-+ */
-+void stonith_bcast_result_to_peers(remote_fencing_op_t * op, int rc);
-+
- enum st_callback_flags {
-     st_callback_unknown        = 0x0000,
-     st_callback_notify_fence   = 0x0001,
-diff --git a/fencing/remote.c b/fencing/remote.c
-index 866112f..6c5b9b8 100644
---- a/fencing/remote.c
-+++ b/fencing/remote.c
-@@ -379,8 +379,8 @@ create_op_done_notify(remote_fencing_op_t * op, int rc)
-     return notify_data;
- }
- 
--static void
--bcast_result_to_peers(remote_fencing_op_t * op, int rc)
-+void
-+stonith_bcast_result_to_peers(remote_fencing_op_t * op, int rc)
- {
-     static int count = 0;
-     xmlNode *bcast = create_xml_node(NULL, T_STONITH_REPLY);
-@@ -518,7 +518,7 @@ remote_op_done(remote_fencing_op_t * op, xmlNode * data, int rc, int dup)
-     subt = crm_element_value(data, F_SUBTYPE);
-     if (dup == FALSE && safe_str_neq(subt, "broadcast")) {
-         /* Defer notification until the bcast message arrives */
--        bcast_result_to_peers(op, rc);
-+        stonith_bcast_result_to_peers(op, rc);
-         goto remote_op_done_cleanup;
-     }
- 
--- 
-1.8.3.1
-
-
-From 89c87a604b7a318df5a6fd66d5e077362d6717aa Mon Sep 17 00:00:00 2001
-From: Klaus Wenninger <klaus.wenninger@aon.at>
-Date: Mon, 8 Jul 2019 18:49:18 +0200
-Subject: [PATCH 18/96] Fix: st_client: make safe to remove notifications from
- notifications
-
-While cycling over the notification-list just mark for deletion
-and delete afterwards.
----
- lib/fencing/st_client.c | 58 +++++++++++++++++++++++++++++++++++++++++++++----
- 1 file changed, 54 insertions(+), 4 deletions(-)
-
-diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
-index c38f356..feb8c73 100644
---- a/lib/fencing/st_client.c
-+++ b/lib/fencing/st_client.c
-@@ -77,6 +77,8 @@ typedef struct stonith_private_s {
-     mainloop_io_t *source;
-     GHashTable *stonith_op_callback_table;
-     GList *notify_list;
-+    int notify_refcnt;
-+    bool notify_deletes;
- 
-     void (*op_callback) (stonith_t * st, stonith_callback_data_t * data);
- 
-@@ -87,6 +89,7 @@ typedef struct stonith_notify_client_s {
-     const char *obj_id;         /* implement one day */
-     const char *obj_type;       /* implement one day */
-     void (*notify) (stonith_t * st, stonith_event_t * e);
-+    bool delete;
- 
- } stonith_notify_client_t;
- 
-@@ -223,6 +226,38 @@ log_action(stonith_action_t *action, pid_t pid)
-     }
- }
- 
-+/* when cycling through the list we don't want to delete items
-+   so just mark them and when we know nobody is using the list
-+   loop over it to remove the marked items
-+ */
-+static void
-+foreach_notify_entry (stonith_private_t *private,
-+                GFunc func,
-+                gpointer user_data)
-+{
-+    private->notify_refcnt++;
-+    g_list_foreach(private->notify_list, func, user_data);
-+    private->notify_refcnt--;
-+    if ((private->notify_refcnt == 0) &&
-+        private->notify_deletes) {
-+        GList *list_item = private->notify_list;
-+
-+        private->notify_deletes = FALSE;
-+        while (list_item != NULL)
-+        {
-+            stonith_notify_client_t *list_client = list_item->data;
-+            GList *next = g_list_next(list_item);
-+
-+            if (list_client->delete) {
-+                free(list_client);
-+                private->notify_list =
-+                    g_list_delete_link(private->notify_list, list_item);
-+            }
-+            list_item = next;
-+        }
-+    }
-+}
-+
- static void
- stonith_connection_destroy(gpointer user_data)
- {
-@@ -242,7 +277,7 @@ stonith_connection_destroy(gpointer user_data)
-     crm_xml_add(blob.xml, F_TYPE, T_STONITH_NOTIFY);
-     crm_xml_add(blob.xml, F_SUBTYPE, T_STONITH_NOTIFY_DISCONNECT);
- 
--    g_list_foreach(native->notify_list, stonith_send_notification, &blob);
-+    foreach_notify_entry(native, stonith_send_notification, &blob);
-     free_xml(blob.xml);
- }
- 
-@@ -1244,6 +1279,10 @@ stonithlib_GCompareFunc(gconstpointer a, gconstpointer b)
-     const stonith_notify_client_t *a_client = a;
-     const stonith_notify_client_t *b_client = b;
- 
-+    if (a_client->delete || b_client->delete) {
-+        /* make entries marked for deletion not findable */
-+        return -1;
-+    }
-     CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
-     rc = strcmp(a_client->event, b_client->event);
-     if (rc == 0) {
-@@ -1502,8 +1541,13 @@ stonith_api_del_notification(stonith_t * stonith, const char *event)
-     if (list_item != NULL) {
-         stonith_notify_client_t *list_client = list_item->data;
- 
--        private->notify_list = g_list_remove(private->notify_list, list_client);
--        free(list_client);
-+        if (private->notify_refcnt) {
-+            list_client->delete = TRUE;
-+            private->notify_deletes = TRUE;
-+        } else {
-+            private->notify_list = g_list_remove(private->notify_list, list_client);
-+            free(list_client);
-+        }
- 
-         crm_trace("Removed callback");
- 
-@@ -1807,6 +1851,10 @@ stonith_send_notification(gpointer data, gpointer user_data)
-         crm_warn("Skipping callback - NULL callback client");
-         return;
- 
-+    } else if (entry->delete) {
-+        crm_trace("Skipping callback - marked for deletion");
-+        return;
-+
-     } else if (entry->notify == NULL) {
-         crm_warn("Skipping callback - NULL callback");
-         return;
-@@ -1988,7 +2036,7 @@ stonith_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata)
-         stonith_perform_callback(st, blob.xml, 0, 0);
- 
-     } else if (safe_str_eq(type, T_STONITH_NOTIFY)) {
--        g_list_foreach(private->notify_list, stonith_send_notification, &blob);
-+        foreach_notify_entry(private, stonith_send_notification, &blob);
-     } else if (safe_str_eq(type, T_STONITH_TIMEOUT_VALUE)) {
-         int call_id = 0;
-         int timeout = 0;
-@@ -2135,6 +2183,8 @@ stonith_api_new(void)
-     private->stonith_op_callback_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
-                                                                NULL, stonith_destroy_op_callback);
-     private->notify_list = NULL;
-+    private->notify_refcnt = 0;
-+    private->notify_deletes = FALSE;
- 
-     new_stonith->call_id = 1;
-     new_stonith->state = stonith_disconnected;
--- 
-1.8.3.1
-
-
-From 4625dd976d9e9cd08e0fefa0bbe057fb91510d98 Mon Sep 17 00:00:00 2001
-From: Klaus Wenninger <klaus.wenninger@aon.at>
-Date: Mon, 8 Jul 2019 19:12:53 +0200
-Subject: [PATCH 19/96] Feature: fence-history: add notification upon
- history-synced
-
----
- fencing/history.c        |  5 +++++
- fencing/internal.h       | 11 ++++++-----
- fencing/main.c           |  3 +++
- include/crm/stonith-ng.h |  1 +
- 4 files changed, 15 insertions(+), 5 deletions(-)
-
-diff --git a/fencing/history.c b/fencing/history.c
-index c487848..4f1fc4a 100644
---- a/fencing/history.c
-+++ b/fencing/history.c
-@@ -420,6 +420,11 @@ stonith_fence_history(xmlNode *msg, xmlNode **output,
-         stonith_fence_history_cleanup(target,
-             crm_element_value(msg, F_STONITH_CALLID) != NULL);
-     } else if (options & st_opt_broadcast) {
-+        /* there is no clear sign atm for when a history sync
-+           is done so send a notification for anything
-+           that smells like history-sync
-+         */
-+        do_stonith_notify(0, T_STONITH_NOTIFY_HISTORY_SYNCED, 0, NULL);
-         if (crm_element_value(msg, F_STONITH_CALLID)) {
-             /* this is coming from the stonith-API
-             *
-diff --git a/fencing/internal.h b/fencing/internal.h
-index cd48b53..a51b0e6 100644
---- a/fencing/internal.h
-+++ b/fencing/internal.h
-@@ -151,11 +151,12 @@ typedef struct remote_fencing_op_s {
- void stonith_bcast_result_to_peers(remote_fencing_op_t * op, int rc);
- 
- enum st_callback_flags {
--    st_callback_unknown        = 0x0000,
--    st_callback_notify_fence   = 0x0001,
--    st_callback_device_add     = 0x0004,
--    st_callback_device_del     = 0x0010,
--    st_callback_notify_history = 0x0020
-+    st_callback_unknown               = 0x0000,
-+    st_callback_notify_fence          = 0x0001,
-+    st_callback_device_add            = 0x0004,
-+    st_callback_device_del            = 0x0010,
-+    st_callback_notify_history        = 0x0020,
-+    st_callback_notify_history_synced = 0x0040
- };
- 
- /*
-diff --git a/fencing/main.c b/fencing/main.c
-index 82bee86..624937e 100644
---- a/fencing/main.c
-+++ b/fencing/main.c
-@@ -301,6 +301,9 @@ get_stonith_flag(const char *name)
-     } else if (safe_str_eq(name, T_STONITH_NOTIFY_HISTORY)) {
-         return st_callback_notify_history;
- 
-+    } else if (safe_str_eq(name, T_STONITH_NOTIFY_HISTORY_SYNCED)) {
-+        return st_callback_notify_history_synced;
-+
-     }
-     return st_callback_unknown;
- }
-diff --git a/include/crm/stonith-ng.h b/include/crm/stonith-ng.h
-index 045521a..23f879b 100644
---- a/include/crm/stonith-ng.h
-+++ b/include/crm/stonith-ng.h
-@@ -35,6 +35,7 @@
- #  define T_STONITH_NOTIFY_DISCONNECT     "st_notify_disconnect"
- #  define T_STONITH_NOTIFY_FENCE          "st_notify_fence"
- #  define T_STONITH_NOTIFY_HISTORY        "st_notify_history"
-+#  define T_STONITH_NOTIFY_HISTORY_SYNCED "st_notify_history_synced"
- 
- /* *INDENT-OFF* */
- enum stonith_state {
--- 
-1.8.3.1
-
-
-From 732f069557e490a9ce1d1a5adfc74081c3e309c1 Mon Sep 17 00:00:00 2001
-From: Klaus Wenninger <klaus.wenninger@aon.at>
-Date: Mon, 8 Jul 2019 19:32:28 +0200
-Subject: [PATCH 20/96] Fix: crmd: remove-stonith-notifications upon
- connection-destroy
-
----
- crmd/te_utils.c | 11 +++++++++--
- 1 file changed, 9 insertions(+), 2 deletions(-)
-
-diff --git a/crmd/te_utils.c b/crmd/te_utils.c
-index 280fc95..f5bcb84 100644
---- a/crmd/te_utils.c
-+++ b/crmd/te_utils.c
-@@ -183,8 +183,15 @@ tengine_stonith_connection_destroy(stonith_t * st, stonith_event_t * e)
-     }
- 
-     /* cbchan will be garbage at this point, arrange for it to be reset */
--    if(stonith_api) {
--        stonith_api->state = stonith_disconnected;
-+    if (stonith_api) {
-+        /* the client API won't properly reconnect notifications
-+         * if they are still in the table - so remove them
-+         */
-+        stonith_api->cmds->remove_notification(st, T_STONITH_NOTIFY_DISCONNECT);
-+        stonith_api->cmds->remove_notification(st, T_STONITH_NOTIFY_FENCE);
-+        if (stonith_api->state != stonith_disconnected) {
-+            stonith_api->cmds->disconnect(st);
-+        }
-     }
- 
-     if (AM_I_DC) {
--- 
-1.8.3.1
-
-
-From 199d9df653e8264fb09655dd5f8f1e94533612ee Mon Sep 17 00:00:00 2001
-From: Klaus Wenninger <klaus.wenninger@aon.at>
-Date: Mon, 8 Jul 2019 19:36:02 +0200
-Subject: [PATCH 21/96] Fix: crmd: add notice-log for successful fencer-connect
-
----
- crmd/te_utils.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/crmd/te_utils.c b/crmd/te_utils.c
-index f5bcb84..2805ea9 100644
---- a/crmd/te_utils.c
-+++ b/crmd/te_utils.c
-@@ -496,7 +496,7 @@ te_connect_stonith(gpointer user_data)
-     stonith_api->cmds->register_notification(stonith_api, T_STONITH_NOTIFY_FENCE,
-                                              tengine_stonith_notify);
- 
--    crm_trace("Connected");
-+    crm_notice("Fencer successfully connected");
-     return TRUE;
- }
- 
--- 
-1.8.3.1
-
-
-From ec0bb46caba533fa03b9bf4376f0f1ac5f70d393 Mon Sep 17 00:00:00 2001
-From: Klaus Wenninger <klaus.wenninger@aon.at>
-Date: Mon, 8 Jul 2019 19:40:42 +0200
-Subject: [PATCH 22/96] Test: CTS: new pattern to identify fenced reconnected
-
-Now that we are removing notifications upon disconnect a duplicate
-notification can't be used as sign for reconnection any more.
----
- cts/patterns.py | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/cts/patterns.py b/cts/patterns.py
-index ccd753d..87b44a9 100644
---- a/cts/patterns.py
-+++ b/cts/patterns.py
-@@ -376,7 +376,7 @@ class crm_cs_v0(BasePatterns):
-             "LRMD lost STONITH connection",
-             "Connection to stonith-ng.* closed",
-             "Fencing daemon connection failed",
--            r"crmd.*:\s*warn.*:\s*Callback already present",
-+            r"pacemaker-controld.*Fencer successfully connected",
-         ]
-         self.components["stonith-ignore"] = [
-             r"pengine.*: Recover Fencing",
--- 
-1.8.3.1
-
-
-From 5141b03fe7bffd493cd26c20412bbcf3041fa495 Mon Sep 17 00:00:00 2001
-From: Klaus Wenninger <klaus.wenninger@aon.at>
-Date: Mon, 8 Jul 2019 21:15:51 +0200
-Subject: [PATCH 23/96] Fix: fence-history: resync fence-history after stonithd
- crash
-
-Setting up a 30s fallback timer to trigger history-sync if the
-sync via DC doesn't happen
----
- crmd/callbacks.c |  2 +-
- crmd/control.c   |  9 ++++++-
- crmd/te_utils.c  | 78 ++++++++++++++++++++++++++++++++++++++++++++++++--------
- crmd/tengine.h   |  3 ++-
- 4 files changed, 79 insertions(+), 13 deletions(-)
-
-diff --git a/crmd/callbacks.c b/crmd/callbacks.c
-index c51b215..7560470 100644
---- a/crmd/callbacks.c
-+++ b/crmd/callbacks.c
-@@ -212,7 +212,7 @@ peer_update_callback(enum crm_status_type type, crm_node_t * node, const void *d
-                 } else {
-                     crm_info("New peer %s we want to sync fence history with",
-                              node->uname);
--                    te_trigger_stonith_history_sync();
-+                    te_trigger_stonith_history_sync(FALSE);
-                 }
-             }
-             break;
-diff --git a/crmd/control.c b/crmd/control.c
-index 488ea88..04935c7 100644
---- a/crmd/control.c
-+++ b/crmd/control.c
-@@ -192,7 +192,12 @@ do_shutdown(long long action,
-         clear_bit(fsa_input_register, R_ST_REQUIRED);
- 
-         crm_info("Disconnecting STONITH...");
--        stonith_api->cmds->disconnect(stonith_api);
-+        if (stonith_api->state != stonith_disconnected) {
-+            stonith_api->cmds->disconnect(stonith_api);
-+        }
-+        stonith_api->cmds->remove_notification(stonith_api, T_STONITH_NOTIFY_DISCONNECT);
-+        stonith_api->cmds->remove_notification(stonith_api, T_STONITH_NOTIFY_FENCE);
-+        stonith_api->cmds->remove_notification(stonith_api, T_STONITH_NOTIFY_HISTORY_SYNCED);
-     }
- }
- 
-@@ -369,6 +374,8 @@ crmd_exit(int rc)
-     crm_timer_stop(wait_timer);
-     crm_timer_stop(recheck_timer);
- 
-+    te_cleanup_stonith_history_sync(NULL, TRUE);
-+
-     free(transition_timer); transition_timer = NULL;
-     free(integration_timer); integration_timer = NULL;
-     free(finalization_timer); finalization_timer = NULL;
-diff --git a/crmd/te_utils.c b/crmd/te_utils.c
-index 2805ea9..29b411f 100644
---- a/crmd/te_utils.c
-+++ b/crmd/te_utils.c
-@@ -33,7 +33,33 @@
- 
- crm_trigger_t *stonith_reconnect = NULL;
- static crm_trigger_t *stonith_history_sync_trigger = NULL;
--static mainloop_timer_t *stonith_history_sync_timer = NULL;
-+static mainloop_timer_t *stonith_history_sync_timer_short = NULL;
-+static mainloop_timer_t *stonith_history_sync_timer_long = NULL;
-+
-+void
-+te_cleanup_stonith_history_sync(stonith_t *st, bool free_timers)
-+{
-+    if (free_timers) {
-+        mainloop_timer_del(stonith_history_sync_timer_short);
-+        stonith_history_sync_timer_short = NULL;
-+        mainloop_timer_del(stonith_history_sync_timer_long);
-+        stonith_history_sync_timer_long = NULL;
-+    } else {
-+        mainloop_timer_stop(stonith_history_sync_timer_short);
-+        mainloop_timer_stop(stonith_history_sync_timer_long);
-+    }
-+
-+    if (st) {
-+        st->cmds->remove_notification(st, T_STONITH_NOTIFY_HISTORY_SYNCED);
-+    }
-+}
-+
-+static void
-+tengine_stonith_history_synced(stonith_t *st, stonith_event_t *st_event)
-+{
-+    te_cleanup_stonith_history_sync(st, FALSE);
-+    crm_debug("Fence-history synced - cancel all timers");
-+}
- 
- /*
-  * stonith cleanup list
-@@ -174,6 +200,8 @@ fail_incompletable_stonith(crm_graph_t * graph)
- static void
- tengine_stonith_connection_destroy(stonith_t * st, stonith_event_t * e)
- {
-+    te_cleanup_stonith_history_sync(st, FALSE);
-+
-     if (is_set(fsa_input_register, R_ST_REQUIRED)) {
-         crm_crit("Fencing daemon connection failed");
-         mainloop_set_trigger(stonith_reconnect);
-@@ -187,11 +215,12 @@ tengine_stonith_connection_destroy(stonith_t * st, stonith_event_t * e)
-         /* the client API won't properly reconnect notifications
-          * if they are still in the table - so remove them
-          */
--        stonith_api->cmds->remove_notification(st, T_STONITH_NOTIFY_DISCONNECT);
--        stonith_api->cmds->remove_notification(st, T_STONITH_NOTIFY_FENCE);
-         if (stonith_api->state != stonith_disconnected) {
-             stonith_api->cmds->disconnect(st);
-         }
-+        stonith_api->cmds->remove_notification(stonith_api, T_STONITH_NOTIFY_DISCONNECT);
-+        stonith_api->cmds->remove_notification(stonith_api, T_STONITH_NOTIFY_FENCE);
-+        stonith_api->cmds->remove_notification(stonith_api, T_STONITH_NOTIFY_HISTORY_SYNCED);
-     }
- 
-     if (AM_I_DC) {
-@@ -212,6 +241,9 @@ char *te_client_id = NULL;
- #endif
- 
- static void
-+tengine_stonith_history_synced(stonith_t *st, stonith_event_t *st_event);
-+
-+static void
- tengine_stonith_notify(stonith_t * st, stonith_event_t * st_event)
- {
-     if(te_client_id == NULL) {
-@@ -404,6 +436,7 @@ do_stonith_history_sync(gpointer user_data)
-     if (stonith_api && (stonith_api->state != stonith_disconnected)) {
-         stonith_history_t *history = NULL;
- 
-+        te_cleanup_stonith_history_sync(stonith_api, FALSE);
-         stonith_api->cmds->history(stonith_api,
-                                    st_opt_sync_call | st_opt_broadcast,
-                                    NULL, &history, 5);
-@@ -423,11 +456,18 @@ stonith_history_sync_set_trigger(gpointer user_data)
- }
- 
- void
--te_trigger_stonith_history_sync(void)
-+te_trigger_stonith_history_sync(bool long_timeout)
- {
-     /* trigger a sync in 5s to give more nodes the
-      * chance to show up so that we don't create
-      * unnecessary stonith-history-sync traffic
-+     *
-+     * the long timeout of 30s is there as a fallback
-+     * so that after a successful connection to fenced
-+     * we will wait for 30s for the DC to trigger a
-+     * history-sync
-+     * if this doesn't happen we trigger a sync locally
-+     * (e.g. fenced segfaults and is restarted by pacemakerd)
-      */
- 
-     /* as we are finally checking the stonith-connection
-@@ -441,13 +481,25 @@ te_trigger_stonith_history_sync(void)
-                                  do_stonith_history_sync, NULL);
-     }
- 
--    if(stonith_history_sync_timer == NULL) {
--        stonith_history_sync_timer =
--            mainloop_timer_add("history_sync", 5000,
--                               FALSE, stonith_history_sync_set_trigger,
--                               NULL);
-+    if (long_timeout) {
-+        if(stonith_history_sync_timer_long == NULL) {
-+            stonith_history_sync_timer_long =
-+                mainloop_timer_add("history_sync_long", 30000,
-+                                   FALSE, stonith_history_sync_set_trigger,
-+                                   NULL);
-+        }
-+        crm_info("Fence history will be synchronized cluster-wide within 30 seconds");
-+        mainloop_timer_start(stonith_history_sync_timer_long);
-+    } else {
-+        if(stonith_history_sync_timer_short == NULL) {
-+            stonith_history_sync_timer_short =
-+                mainloop_timer_add("history_sync_short", 5000,
-+                                   FALSE, stonith_history_sync_set_trigger,
-+                                   NULL);
-+        }
-+        crm_info("Fence history will be synchronized cluster-wide within 5 seconds");
-+        mainloop_timer_start(stonith_history_sync_timer_short);
-     }
--    mainloop_timer_start(stonith_history_sync_timer);
- }
- 
- gboolean
-@@ -496,6 +548,12 @@ te_connect_stonith(gpointer user_data)
-     stonith_api->cmds->register_notification(stonith_api, T_STONITH_NOTIFY_FENCE,
-                                              tengine_stonith_notify);
- 
-+    stonith_api->cmds->register_notification(stonith_api,
-+                                             T_STONITH_NOTIFY_HISTORY_SYNCED,
-+                                             tengine_stonith_history_synced);
-+
-+    te_trigger_stonith_history_sync(TRUE);
-+
-     crm_notice("Fencer successfully connected");
-     return TRUE;
- }
-diff --git a/crmd/tengine.h b/crmd/tengine.h
-index 1a9b2d2..a20760c 100644
---- a/crmd/tengine.h
-+++ b/crmd/tengine.h
-@@ -72,7 +72,8 @@ extern void abort_transition_graph(int abort_priority, enum transition_action ab
- 
- extern gboolean te_connect_stonith(gpointer user_data);
- 
--extern void te_trigger_stonith_history_sync(void);
-+extern void te_trigger_stonith_history_sync(bool long_timeout);
-+extern void te_cleanup_stonith_history_sync(stonith_t *st, bool free_timers);
- 
- extern crm_trigger_t *transition_trigger;
- extern crm_trigger_t *stonith_reconnect;
--- 
-1.8.3.1
-
-
-From 926ae820d6406885dce8ba794215002b57bce17f Mon Sep 17 00:00:00 2001
-From: Klaus Wenninger <klaus.wenninger@aon.at>
-Date: Wed, 10 Jul 2019 17:57:02 +0200
-Subject: [PATCH 24/96] Fix: st_client: cleanup token whenever setting api to
- disconnected
-
----
- lib/fencing/st_client.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
-index feb8c73..60c07d5 100644
---- a/lib/fencing/st_client.c
-+++ b/lib/fencing/st_client.c
-@@ -273,6 +273,7 @@ stonith_connection_destroy(gpointer user_data)
-     native->ipc = NULL;
-     native->source = NULL;
- 
-+    free(native->token); native->token = NULL;
-     stonith->state = stonith_disconnected;
-     crm_xml_add(blob.xml, F_TYPE, T_STONITH_NOTIFY);
-     crm_xml_add(blob.xml, F_SUBTYPE, T_STONITH_NOTIFY_DISCONNECT);
-@@ -1975,6 +1976,7 @@ stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data, xmlNod
-   done:
-     if (crm_ipc_connected(native->ipc) == FALSE) {
-         crm_err("STONITH disconnected");
-+        free(native->token); native->token = NULL;
-         stonith->state = stonith_disconnected;
-     }
- 
--- 
-1.8.3.1
-
-
-From 365c29581f0a88f106622c000e8fe4b3e9edd024 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Wed, 27 Feb 2019 15:39:59 -0600
-Subject: [PATCH 25/96] Low: executor: consider stonith resource stopped only
- if stop succeeded
-
-Previously, the executor would consider a stonith resource stopped whenever a
-stop was requested, regardless of the actual result of remove_device(). One
-could make a case for ignoring device unregistration failures, but it would be
-unusual enough result that it makes sense to draw attention to it.
----
- lrmd/lrmd.c | 9 ++++++---
- 1 file changed, 6 insertions(+), 3 deletions(-)
-
-diff --git a/lrmd/lrmd.c b/lrmd/lrmd.c
-index d6a431d..ecf0cc7 100644
---- a/lrmd/lrmd.c
-+++ b/lrmd/lrmd.c
-@@ -1057,8 +1057,12 @@ stonith_action_complete(lrmd_cmd_t * cmd, int rc)
-     } else {
-         /* command successful */
-         cmd->lrmd_op_status = PCMK_LRM_OP_DONE;
--        if (safe_str_eq(cmd->action, "start") && rsc) {
--            rsc->stonith_started = 1;
-+        if (rsc) {
-+            if (safe_str_eq(cmd->action, "start")) {
-+                rsc->stonith_started = 1;
-+            } else if (safe_str_eq(cmd->action, "stop")) {
-+                rsc->stonith_started = 0;
-+            }
-         }
-     }
- 
-@@ -1160,7 +1164,6 @@ lrmd_rsc_execute_stonith(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
-         }
-     } else if (safe_str_eq(cmd->action, "stop")) {
-         rc = stonith_api->cmds->remove_device(stonith_api, st_opt_sync_call, cmd->rsc_id);
--        rsc->stonith_started = 0;
-     } else if (safe_str_eq(cmd->action, "monitor")) {
-         if (cmd->interval) {
-             do_monitor = 1;
--- 
-1.8.3.1
-
-
-From 4e535413aaacb21aa11de3d1b48a90ed3a173825 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Wed, 10 Apr 2019 12:43:21 -0500
-Subject: [PATCH 26/96] Fix: executor: return error for stonith probes if
- stonith connection was lost
-
-Previously, stonith probes could return only PCMK_OCF_OK (if the executor had
-registered the device with the fencer) or PCMK_OCF_NOT_RUNNING (if the executor
-had unregistered or not yet registered the device).
-
-However if the stonith connection is lost, the executor doesn't know whether
-the device is still registered or not, and thus could be giving wrong
-information back to the controller.
-
-This fixes that by refactoring lrmd_rsc_t's stonith_started member from a
-boolean (0 = not started, 1 = started) to an rc code (pcmk_ok = started,
--ENODEV = not started, pcmk_err_generic = stonith connection lost).
-stonith_rc2status() will map these to PCMK_OCF_OK, PCMK_OCF_NOT_RUNNING, or
-PCMK_OCF_UNKNOWN_ERROR.
-
-This ensures that probes after the connection is lost will fail, which is
-especially important if the controller respawned at the same time as the fencer
-and so didn't receive client notification of failed monitors.
-
-This means that if the executor loses its stonith connection, probes for *all*
-stonith devices on that node will fail and require a stop on that node, which
-may be unexpected for users accustomed to the old behavior, but is more
-correct.
----
- lrmd/lrmd.c         | 15 ++++++++++++---
- lrmd/lrmd_private.h |  2 +-
- 2 files changed, 13 insertions(+), 4 deletions(-)
-
-diff --git a/lrmd/lrmd.c b/lrmd/lrmd.c
-index ecf0cc7..59751ec 100644
---- a/lrmd/lrmd.c
-+++ b/lrmd/lrmd.c
-@@ -158,6 +158,7 @@ build_rsc_from_xml(xmlNode * msg)
-     rsc->provider = crm_element_value_copy(rsc_xml, F_LRMD_PROVIDER);
-     rsc->type = crm_element_value_copy(rsc_xml, F_LRMD_TYPE);
-     rsc->work = mainloop_add_trigger(G_PRIORITY_HIGH, lrmd_rsc_dispatch, rsc);
-+    rsc->st_probe_rc = -ENODEV; // if stonith, initialize to "not running"
-     return rsc;
- }
- 
-@@ -1059,9 +1060,9 @@ stonith_action_complete(lrmd_cmd_t * cmd, int rc)
-         cmd->lrmd_op_status = PCMK_LRM_OP_DONE;
-         if (rsc) {
-             if (safe_str_eq(cmd->action, "start")) {
--                rsc->stonith_started = 1;
-+                rsc->st_probe_rc = pcmk_ok; // maps to PCMK_OCF_OK
-             } else if (safe_str_eq(cmd->action, "stop")) {
--                rsc->stonith_started = 0;
-+                rsc->st_probe_rc = -ENODEV; // maps to PCMK_OCF_NOT_RUNNING
-             }
-         }
-     }
-@@ -1094,6 +1095,14 @@ stonith_connection_failed(void)
-     g_hash_table_iter_init(&iter, rsc_list);
-     while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & rsc)) {
-         if (safe_str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH)) {
-+            /* This will cause future probes to return PCMK_OCF_UNKNOWN_ERROR
-+             * until the resource is stopped or started successfully. This is
-+             * especially important if the controller also went away (possibly
-+             * due to a cluster layer restart) and won't receive our client
-+             * notification of any monitors finalized below.
-+             */
-+            rsc->st_probe_rc = pcmk_err_generic;
-+
-             if (rsc->active) {
-                 cmd_list = g_list_append(cmd_list, rsc->active);
-             }
-@@ -1168,7 +1177,7 @@ lrmd_rsc_execute_stonith(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
-         if (cmd->interval) {
-             do_monitor = 1;
-         } else {
--            rc = rsc->stonith_started ? 0 : -ENODEV;
-+            rc = rsc->st_probe_rc;
-         }
-     }
- 
-diff --git a/lrmd/lrmd_private.h b/lrmd/lrmd_private.h
-index 4449bb0..44de453 100644
---- a/lrmd/lrmd_private.h
-+++ b/lrmd/lrmd_private.h
-@@ -54,7 +54,7 @@ typedef struct lrmd_rsc_s {
-      * that have been handed off from the pending ops list. */
-     GList *recurring_ops;
- 
--    int stonith_started;
-+    int st_probe_rc; // What value should be returned for a probe if stonith
- 
-     crm_trigger_t *work;
- } lrmd_rsc_t;
--- 
-1.8.3.1
-
-
-From 1268ce78d1be9841f5861892e4ed3d9013d38fdb Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Wed, 10 Apr 2019 12:51:48 -0500
-Subject: [PATCH 27/96] Fix: executor: don't cancel stonith monitors when
- device is not registered
-
-This essentially reverts 53532a7. Now that failed stonith connections will
-cause failures of future probes, we can properly leave the decision to cancel
-monitors to the controller. Otherwise, the controller won't know that the
-recurring action is no longer active, and could get action timeouts in some
-cases.
----
- lrmd/lrmd.c | 12 +-----------
- 1 file changed, 1 insertion(+), 11 deletions(-)
-
-diff --git a/lrmd/lrmd.c b/lrmd/lrmd.c
-index 59751ec..5d33324 100644
---- a/lrmd/lrmd.c
-+++ b/lrmd/lrmd.c
-@@ -1029,17 +1029,7 @@ stonith_action_complete(lrmd_cmd_t * cmd, int rc)
-     } else if (rc == -ENODEV && safe_str_eq(cmd->action, "monitor")) {
-         // The device is not registered with the fencer
- 
--        if (recurring) {
--            /* If we get here, the fencer somehow lost the registration of a
--             * previously active device (possibly due to crash and respawn). In
--             * that case, we need to indicate that the recurring monitor needs
--             * to be cancelled.
--             */
--            cmd->lrmd_op_status = PCMK_LRM_OP_CANCELLED;
--            recurring = FALSE;
--        } else {
--            cmd->lrmd_op_status = PCMK_LRM_OP_DONE;
--        }
-+        cmd->lrmd_op_status = PCMK_LRM_OP_ERROR;
-         cmd->exec_rc = PCMK_OCF_NOT_RUNNING;
- 
-     } else if (rc) {
--- 
-1.8.3.1
-
-
-From ffd57df21eff2e0c96966be7069152b5b57c1870 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Fri, 28 Jun 2019 15:27:56 -0500
-Subject: [PATCH 28/96] Refactor: controller: functionize access to last
- scheduler request ID
-
-This will come in handy for adding a new timer
----
- crmd/control.c    |  3 +--
- crmd/crmd_utils.h |  2 ++
- crmd/pengine.c    | 49 ++++++++++++++++++++++++++++++++++++++-----------
- crmd/te_utils.c   |  5 +----
- 4 files changed, 42 insertions(+), 17 deletions(-)
-
-diff --git a/crmd/control.c b/crmd/control.c
-index 04935c7..73a2b08 100644
---- a/crmd/control.c
-+++ b/crmd/control.c
-@@ -339,7 +339,6 @@ crmd_exit(int rc)
-     clear_bit(fsa_input_register, R_MEMBERSHIP);
-     g_list_free(fsa_message_queue); fsa_message_queue = NULL;
- 
--    free(pe_subsystem); pe_subsystem = NULL;
-     free(te_subsystem); te_subsystem = NULL;
-     free(cib_subsystem); cib_subsystem = NULL;
- 
-@@ -375,6 +374,7 @@ crmd_exit(int rc)
-     crm_timer_stop(recheck_timer);
- 
-     te_cleanup_stonith_history_sync(NULL, TRUE);
-+    controld_sched_cleanup();
- 
-     free(transition_timer); transition_timer = NULL;
-     free(integration_timer); integration_timer = NULL;
-@@ -393,7 +393,6 @@ crmd_exit(int rc)
- 
-     free(te_uuid); te_uuid = NULL;
-     free(te_client_id); te_client_id = NULL;
--    free(fsa_pe_ref); fsa_pe_ref = NULL;
-     free(failed_stop_offset); failed_stop_offset = NULL;
-     free(failed_start_offset); failed_start_offset = NULL;
- 
-diff --git a/crmd/crmd_utils.h b/crmd/crmd_utils.h
-index a754487..ce856b7 100644
---- a/crmd/crmd_utils.h
-+++ b/crmd/crmd_utils.h
-@@ -83,6 +83,8 @@ int crmd_exit(int rc);
- int crmd_fast_exit(int rc);
- gboolean stop_subsystem(struct crm_subsystem_s *centry, gboolean force_quit);
- gboolean start_subsystem(struct crm_subsystem_s *centry);
-+void controld_expect_sched_reply(xmlNode *msg);
-+void controld_sched_cleanup(void);
- 
- void fsa_dump_actions(long long action, const char *text);
- void fsa_dump_inputs(int log_level, const char *text, long long input_register);
-diff --git a/crmd/pengine.c b/crmd/pengine.c
-index 8ecb21d..b7d996a 100644
---- a/crmd/pengine.c
-+++ b/crmd/pengine.c
-@@ -1,5 +1,7 @@
- /* 
-- * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
-+ * Copyright 2004-2019 the Pacemaker project contributors
-+ *
-+ * The version control history for this file may have further details.
-  * 
-  * This program is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU General Public
-@@ -172,6 +174,36 @@ do_pe_control(long long action,
- int fsa_pe_query = 0;
- char *fsa_pe_ref = NULL;
- 
-+/*!
-+ * \internal
-+ * \brief Set the scheduler request currently being waited on
-+ *
-+ * \param[in] msg  Request to expect reply to (or NULL for none)
-+ */
-+void
-+controld_expect_sched_reply(xmlNode *msg)
-+{
-+    char *ref = NULL;
-+
-+    if (msg) {
-+        ref = crm_element_value_copy(msg, XML_ATTR_REFERENCE);
-+        CRM_ASSERT(ref != NULL);
-+    }
-+    free(fsa_pe_ref);
-+    fsa_pe_ref = ref;
-+}
-+
-+/*!
-+ * \internal
-+ * \brief Clean up all memory used by controller scheduler handling
-+ */
-+void
-+controld_sched_cleanup()
-+{
-+    free(pe_subsystem); pe_subsystem = NULL;
-+    controld_expect_sched_reply(NULL);
-+}
-+
- /*	 A_PE_INVOKE	*/
- void
- do_pe_invoke(long long action,
-@@ -216,10 +248,7 @@ do_pe_invoke(long long action,
-     crm_debug("Query %d: Requesting the current CIB: %s", fsa_pe_query,
-               fsa_state2string(fsa_state));
- 
--    /* Make sure any queued calculations are discarded */
--    free(fsa_pe_ref);
--    fsa_pe_ref = NULL;
--
-+    controld_expect_sched_reply(NULL);
-     fsa_register_cib_callback(fsa_pe_query, FALSE, NULL, do_pe_invoke_callback);
- }
- 
-@@ -335,16 +364,14 @@ do_pe_invoke_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void
- 
-     cmd = create_request(CRM_OP_PECALC, output, NULL, CRM_SYSTEM_PENGINE, CRM_SYSTEM_DC, NULL);
- 
--    free(fsa_pe_ref);
--    fsa_pe_ref = crm_element_value_copy(cmd, XML_ATTR_REFERENCE);
--
-     sent = crm_ipc_send(mainloop_get_ipc_client(pe_subsystem->source), cmd, 0, 0, NULL);
-     if (sent <= 0) {
-         crm_err("Could not contact the pengine: %d", sent);
-         register_fsa_error_adv(C_FSA_INTERNAL, I_ERROR, NULL, NULL, __FUNCTION__);
-+    } else {
-+        controld_expect_sched_reply(cmd);
-+        crm_debug("Invoking the PE: query=%d, ref=%s, seq=%llu, quorate=%d",
-+                  fsa_pe_query, fsa_pe_ref, crm_peer_seq, fsa_has_quorum);
-     }
--
--    crm_debug("Invoking the PE: query=%d, ref=%s, seq=%llu, quorate=%d",
--              fsa_pe_query, fsa_pe_ref, crm_peer_seq, fsa_has_quorum);
-     free_xml(cmd);
- }
-diff --git a/crmd/te_utils.c b/crmd/te_utils.c
-index 29b411f..14570cd 100644
---- a/crmd/te_utils.c
-+++ b/crmd/te_utils.c
-@@ -717,10 +717,7 @@ abort_transition_graph(int abort_priority, enum transition_action abort_action,
-     }
- 
-     abort_timer.aborted = TRUE;
--
--    /* Make sure any queued calculations are discarded ASAP */
--    free(fsa_pe_ref);
--    fsa_pe_ref = NULL;
-+    controld_expect_sched_reply(NULL);
- 
-     if (transition_graph->complete == FALSE) {
-         if(update_abort_priority(transition_graph, abort_priority, abort_action, abort_text)) {
--- 
-1.8.3.1
-
-
-From 61000ec5247d77ee539cc6988f826c20a6903105 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Fri, 28 Jun 2019 16:20:03 -0500
-Subject: [PATCH 29/96] Fix: controller: set timeout on scheduler responses
-
-Previously, once the DC successfully read the CIB and sent a calculation
-request to the scheduler, it wouldn't do anything further with the request,
-aside from the message handler for the scheduler's response.
-
-This meant that if the scheduler successfully accepted the request, but then
-was unable to reply (such as not getting enough CPU cycles), the controller
-would never detect anything wrong, and the cluster would be blocked.
-
-Now, the controller sets a 2-minute timer after handing off the request to the
-scheduler, and if it doesn't get a response in that time, it exits and stays
-down (if a node is elected DC but can't run the scheduler, we want to ensure it
-doesn't interfere with further elections).
----
- crmd/crmd_utils.h |  1 +
- crmd/election.c   |  1 +
- crmd/messages.c   |  2 +-
- crmd/pengine.c    | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 56 insertions(+), 1 deletion(-)
-
-diff --git a/crmd/crmd_utils.h b/crmd/crmd_utils.h
-index ce856b7..a704380 100644
---- a/crmd/crmd_utils.h
-+++ b/crmd/crmd_utils.h
-@@ -83,6 +83,7 @@ int crmd_exit(int rc);
- int crmd_fast_exit(int rc);
- gboolean stop_subsystem(struct crm_subsystem_s *centry, gboolean force_quit);
- gboolean start_subsystem(struct crm_subsystem_s *centry);
-+void controld_stop_sched_timer(void);
- void controld_expect_sched_reply(xmlNode *msg);
- void controld_sched_cleanup(void);
- 
-diff --git a/crmd/election.c b/crmd/election.c
-index cef82d0..a4313cc 100644
---- a/crmd/election.c
-+++ b/crmd/election.c
-@@ -280,6 +280,7 @@ do_dc_release(long long action,
-     if (action & A_DC_RELEASE) {
-         crm_debug("Releasing the role of DC");
-         clear_bit(fsa_input_register, R_THE_DC);
-+        controld_expect_sched_reply(NULL);
- 
-     } else if (action & A_DC_RELEASED) {
-         crm_info("DC role released");
-diff --git a/crmd/messages.c b/crmd/messages.c
-index 24ffac6..f1599ab 100644
---- a/crmd/messages.c
-+++ b/crmd/messages.c
-@@ -1000,9 +1000,9 @@ handle_response(xmlNode * stored_msg)
-         } else if (safe_str_eq(msg_ref, fsa_pe_ref)) {
-             ha_msg_input_t fsa_input;
- 
-+            controld_stop_sched_timer();
-             fsa_input.msg = stored_msg;
-             register_fsa_input_later(C_IPC_MESSAGE, I_PE_SUCCESS, &fsa_input);
--            crm_trace("Completed: %s...", fsa_pe_ref);
- 
-         } else {
-             crm_info("%s calculation %s is obsolete", op, msg_ref);
-diff --git a/crmd/pengine.c b/crmd/pengine.c
-index b7d996a..1630e7b 100644
---- a/crmd/pengine.c
-+++ b/crmd/pengine.c
-@@ -173,6 +173,45 @@ do_pe_control(long long action,
- 
- int fsa_pe_query = 0;
- char *fsa_pe_ref = NULL;
-+static mainloop_timer_t *controld_sched_timer = NULL;
-+
-+// @TODO Make this a configurable cluster option if there's demand for it
-+#define SCHED_TIMEOUT_MS (120000)
-+
-+/*!
-+ * \internal
-+ * \brief Handle a timeout waiting for scheduler reply
-+ *
-+ * \param[in] user_data  Ignored
-+ *
-+ * \return FALSE (indicating that timer should not be restarted)
-+ */
-+static gboolean
-+controld_sched_timeout(gpointer user_data)
-+{
-+    if (AM_I_DC) {
-+        /* If this node is the DC but can't communicate with the scheduler, just
-+         * exit (and likely get fenced) so this node doesn't interfere with any
-+         * further DC elections.
-+         *
-+         * @TODO We could try something less drastic first, like disconnecting
-+         * and reconnecting to the scheduler, but something is likely going
-+         * seriously wrong, so perhaps it's better to just fail as quickly as
-+         * possible.
-+         */
-+        crmd_exit(DAEMON_RESPAWN_STOP);
-+    }
-+    return FALSE;
-+}
-+
-+void
-+controld_stop_sched_timer()
-+{
-+    if (controld_sched_timer && fsa_pe_ref) {
-+        crm_trace("Stopping timer for scheduler reply %s", fsa_pe_ref);
-+    }
-+    mainloop_timer_stop(controld_sched_timer);
-+}
- 
- /*!
-  * \internal
-@@ -188,6 +227,16 @@ controld_expect_sched_reply(xmlNode *msg)
-     if (msg) {
-         ref = crm_element_value_copy(msg, XML_ATTR_REFERENCE);
-         CRM_ASSERT(ref != NULL);
-+
-+        if (controld_sched_timer == NULL) {
-+            controld_sched_timer = mainloop_timer_add("scheduler_reply_timer",
-+                                                      SCHED_TIMEOUT_MS, FALSE,
-+                                                      controld_sched_timeout,
-+                                                      NULL);
-+        }
-+        mainloop_timer_start(controld_sched_timer);
-+    } else {
-+        controld_stop_sched_timer();
-     }
-     free(fsa_pe_ref);
-     fsa_pe_ref = ref;
-@@ -200,6 +249,10 @@ controld_expect_sched_reply(xmlNode *msg)
- void
- controld_sched_cleanup()
- {
-+    if (controld_sched_timer != NULL) {
-+        mainloop_timer_del(controld_sched_timer);
-+        controld_sched_timer = NULL;
-+    }
-     free(pe_subsystem); pe_subsystem = NULL;
-     controld_expect_sched_reply(NULL);
- }
--- 
-1.8.3.1
-
-
-From ab4ddb17c9b69f182a71026ee9752eec519fb10c Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 30 May 2019 08:37:52 -0500
-Subject: [PATCH 30/96] Low: libpe_status: offer compile-time option to change
- concurrent-fencing default
-
-We most likely want to make concurrent-fencing default to true at some point.
-For now, offer that possibility via a compile-time constant, for experimenting.
----
- lib/pengine/common.c | 8 +++++++-
- lib/pengine/status.c | 3 +++
- 2 files changed, 10 insertions(+), 1 deletion(-)
-
-diff --git a/lib/pengine/common.c b/lib/pengine/common.c
-index d03a6aa..e82434a 100644
---- a/lib/pengine/common.c
-+++ b/lib/pengine/common.c
-@@ -111,7 +111,13 @@ pe_cluster_option pe_opts[] = {
- 	  "How long to wait for the STONITH action (reboot,on,off) to complete", NULL },
- 	{ XML_ATTR_HAVE_WATCHDOG, NULL, "boolean", NULL, "false", &check_boolean,
- 	  "Enable watchdog integration", "Set automatically by the cluster if SBD is detected.  User configured values are ignored." },
--	{ "concurrent-fencing", NULL, "boolean", NULL, "false", &check_boolean,
-+	{ "concurrent-fencing", NULL, "boolean", NULL,
-+#ifdef DEFAULT_CONCURRENT_FENCING_TRUE
-+      "true",
-+#else
-+      "false",
-+#endif
-+      &check_boolean,
- 	  "Allow performing fencing operations in parallel", NULL },
- 	{ "startup-fencing", "startup_fencing", "boolean", NULL, "true", &check_boolean,
- 	  "STONITH unseen nodes", "Advanced Use Only!  Not using the default is very unsafe!" },
-diff --git a/lib/pengine/status.c b/lib/pengine/status.c
-index 6810c78..fdebaa2 100644
---- a/lib/pengine/status.c
-+++ b/lib/pengine/status.c
-@@ -376,6 +376,9 @@ set_working_set_defaults(pe_working_set_t * data_set)
-     set_bit(data_set->flags, pe_flag_symmetric_cluster);
-     set_bit(data_set->flags, pe_flag_is_managed_default);
-     set_bit(data_set->flags, pe_flag_stop_action_orphans);
-+#ifdef DEFAULT_CONCURRENT_FENCING_TRUE
-+    set_bit(data_set->flags, pe_flag_concurrent_fencing);
-+#endif
- }
- 
- resource_t *
--- 
-1.8.3.1
-
-
-From deac9823e08c51a2683c127527a2b047b516f393 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 6 Jun 2019 14:18:37 -0500
-Subject: [PATCH 31/96] Test: scheduler: explicitly set concurrent-fencing in
- relevant regression tests
-
-... since concurrent-fencing's default is likely to eventually change,
-which would otherwise affect the results of these tests
----
- pengine/test10/rec-node-14.xml                     | 1 +
- pengine/test10/remote-connection-unrecoverable.xml | 1 +
- pengine/test10/remote-recover-all.xml              | 1 +
- pengine/test10/remote-recover-no-resources.xml     | 1 +
- pengine/test10/remote-recover-unknown.xml          | 1 +
- pengine/test10/stonith-4.xml                       | 1 +
- pengine/test10/suicide-needed-inquorate.xml        | 1 +
- pengine/test10/ticket-clone-21.xml                 | 1 +
- pengine/test10/ticket-clone-9.xml                  | 1 +
- 9 files changed, 9 insertions(+)
-
-diff --git a/pengine/test10/rec-node-14.xml b/pengine/test10/rec-node-14.xml
-index 456ea80..8582c17 100644
---- a/pengine/test10/rec-node-14.xml
-+++ b/pengine/test10/rec-node-14.xml
-@@ -4,6 +4,7 @@
-       <cluster_property_set id="cib-bootstrap-options">
-         <nvpair id="nvpair.id21835" name="stonith-enabled" value="true"/>
-         <nvpair id="nvpair.id21844" name="no-quorum-policy" value="ignore"/>
-+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
-       </cluster_property_set>
-     </crm_config>
-     <nodes>
-diff --git a/pengine/test10/remote-connection-unrecoverable.xml b/pengine/test10/remote-connection-unrecoverable.xml
-index 4dda833..8096e25 100644
---- a/pengine/test10/remote-connection-unrecoverable.xml
-+++ b/pengine/test10/remote-connection-unrecoverable.xml
-@@ -7,6 +7,7 @@
-         <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"/>
-         <nvpair id="cib-bootstrap-options-cluster-name" name="cluster-name" value="mycluster"/>
-         <nvpair id="cib-bootstrap-options-last-lrm-refresh" name="last-lrm-refresh" value="1459735110"/>
-+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
-       </cluster_property_set>
-     </crm_config>
-     <nodes>
-diff --git a/pengine/test10/remote-recover-all.xml b/pengine/test10/remote-recover-all.xml
-index 30d2451..f56e641 100644
---- a/pengine/test10/remote-recover-all.xml
-+++ b/pengine/test10/remote-recover-all.xml
-@@ -10,6 +10,7 @@
-         <nvpair id="cib-bootstrap-options-cluster-recheck-interval" name="cluster-recheck-interval" value="60s"/>
-         <nvpair id="cib-bootstrap-options-maintenance-mode" name="maintenance-mode" value="false"/>
-         <nvpair id="cib-bootstrap-options-last-lrm-refresh" name="last-lrm-refresh" value="1493817755"/>
-+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
-       </cluster_property_set>
-       <cluster_property_set id="redis_replication">
-         <nvpair id="redis_replication-redis_REPL_INFO" name="redis_REPL_INFO" value="controller-0"/>
-diff --git a/pengine/test10/remote-recover-no-resources.xml b/pengine/test10/remote-recover-no-resources.xml
-index d2fa0df..36f424b 100644
---- a/pengine/test10/remote-recover-no-resources.xml
-+++ b/pengine/test10/remote-recover-no-resources.xml
-@@ -10,6 +10,7 @@
-         <nvpair id="cib-bootstrap-options-cluster-recheck-interval" name="cluster-recheck-interval" value="60s"/>
-         <nvpair id="cib-bootstrap-options-maintenance-mode" name="maintenance-mode" value="false"/>
-         <nvpair id="cib-bootstrap-options-last-lrm-refresh" name="last-lrm-refresh" value="1493817755"/>
-+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
-       </cluster_property_set>
-       <cluster_property_set id="redis_replication">
-         <nvpair id="redis_replication-redis_REPL_INFO" name="redis_REPL_INFO" value="controller-0"/>
-diff --git a/pengine/test10/remote-recover-unknown.xml b/pengine/test10/remote-recover-unknown.xml
-index 3992b03..dd7807c 100644
---- a/pengine/test10/remote-recover-unknown.xml
-+++ b/pengine/test10/remote-recover-unknown.xml
-@@ -10,6 +10,7 @@
-         <nvpair id="cib-bootstrap-options-cluster-recheck-interval" name="cluster-recheck-interval" value="60s"/>
-         <nvpair id="cib-bootstrap-options-maintenance-mode" name="maintenance-mode" value="false"/>
-         <nvpair id="cib-bootstrap-options-last-lrm-refresh" name="last-lrm-refresh" value="1493817755"/>
-+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
-       </cluster_property_set>
-       <cluster_property_set id="redis_replication">
-         <nvpair id="redis_replication-redis_REPL_INFO" name="redis_REPL_INFO" value="controller-0"/>
-diff --git a/pengine/test10/stonith-4.xml b/pengine/test10/stonith-4.xml
-index f9a4d44..4f185de 100644
---- a/pengine/test10/stonith-4.xml
-+++ b/pengine/test10/stonith-4.xml
-@@ -4,6 +4,7 @@
-       <cluster_property_set id="cib-bootstrap-options">
-         <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="1.1.8-0.772.26fe3e5.git.fc17-26fe3e52d259e4726699300d27991fc1a80c556b"/>
-         <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"/>
-+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
-       </cluster_property_set>
-     </crm_config>
-     <nodes>
-diff --git a/pengine/test10/suicide-needed-inquorate.xml b/pengine/test10/suicide-needed-inquorate.xml
-index 160af00..6add7fd 100644
---- a/pengine/test10/suicide-needed-inquorate.xml
-+++ b/pengine/test10/suicide-needed-inquorate.xml
-@@ -7,6 +7,7 @@
-         <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="1.1.17-1"/>
-         <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"/>
-         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="suicide"/>
-+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
-       </cluster_property_set>
-     </crm_config>
-     <nodes>
-diff --git a/pengine/test10/ticket-clone-21.xml b/pengine/test10/ticket-clone-21.xml
-index c29d89f..4a9fce9 100644
---- a/pengine/test10/ticket-clone-21.xml
-+++ b/pengine/test10/ticket-clone-21.xml
-@@ -4,6 +4,7 @@
-       <cluster_property_set id="cib-bootstrap-options">
-         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
-         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
-+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
-       </cluster_property_set>
-     </crm_config>
-     <nodes>
-diff --git a/pengine/test10/ticket-clone-9.xml b/pengine/test10/ticket-clone-9.xml
-index 7b2a62f..c6139d3 100644
---- a/pengine/test10/ticket-clone-9.xml
-+++ b/pengine/test10/ticket-clone-9.xml
-@@ -4,6 +4,7 @@
-       <cluster_property_set id="cib-bootstrap-options">
-         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
-         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
-+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
-       </cluster_property_set>
-     </crm_config>
-     <nodes>
--- 
-1.8.3.1
-
-
-From 7c3bc762a9cede20a0193f64ca1a36f507aeeeb3 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Fri, 20 Apr 2018 13:23:10 -0500
-Subject: [PATCH 32/96] Build: libcrmcommon: configure option to specify GnuTLS
- cipher priorities
-
-Default to current behavior, i.e. "NORMAL". Spec file overrides with "@SYSTEM"
-on distros that have it.
-
-Pacemaker does not use option value as-is; it adds "+ANON-DH" for CIB remote
-commands and "+DHE-PSK:+PSK" for Pacemaker Remote connections. In the longer
-term, we could consider moving to certificate-based connections in both cases,
-but that has backward compatibility issues as well as additional administrative
-burden.
----
- configure.ac        | 9 +++++++++
- lib/common/remote.c | 4 ++--
- pacemaker.spec.in   | 4 ++++
- 3 files changed, 15 insertions(+), 2 deletions(-)
-
-diff --git a/configure.ac b/configure.ac
-index ce02777..a7084e2 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -290,6 +290,12 @@ AC_ARG_WITH(cibsecrets,
-     [ SUPPORT_CIBSECRETS=no ],
- )
- 
-+AC_ARG_WITH(gnutls-priorities,
-+    [  --with-gnutls-priorities  GnuTLS cipher priorities @<:@NORMAL@:>@ ],
-+    [ PCMK_GNUTLS_PRIORITIES="$withval" ],
-+    [ PCMK_GNUTLS_PRIORITIES="NORMAL" ],
-+)
-+
- CSPREFIX=""
- AC_ARG_WITH(ais-prefix,
-     [  --with-ais-prefix=DIR  Prefix used when Corosync was installed [$prefix]],
-@@ -453,6 +459,9 @@ if test x"${BUG_URL}" = x""; then
- fi
- AC_SUBST(BUG_URL)
- 
-+AC_DEFINE_UNQUOTED([PCMK_GNUTLS_PRIORITIES], ["$PCMK_GNUTLS_PRIORITIES"],
-+		   [GnuTLS cipher priorities])
-+
- for j in prefix exec_prefix bindir sbindir libexecdir datadir sysconfdir \
-     sharedstatedir localstatedir libdir includedir oldincludedir infodir \
-     mandir INITDIR docdir CONFIGDIR
-diff --git a/lib/common/remote.c b/lib/common/remote.c
-index 12d25fa..1e4f8d8 100644
---- a/lib/common/remote.c
-+++ b/lib/common/remote.c
-@@ -244,9 +244,9 @@ pcmk__new_tls_session(int csock, unsigned int conn_type,
- #  ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT
-     if (cred_type == GNUTLS_CRD_ANON) {
-         // http://www.manpagez.com/info/gnutls/gnutls-2.10.4/gnutls_81.php#Echo-Server-with-anonymous-authentication
--        prio = "NORMAL:+ANON-DH";
-+        prio = PCMK_GNUTLS_PRIORITIES ":+ANON-DH";
-     } else {
--        prio = "NORMAL:+DHE-PSK:+PSK";
-+        prio = PCMK_GNUTLS_PRIORITIES ":+DHE-PSK:+PSK";
-     }
- #  endif
- 
-diff --git a/pacemaker.spec.in b/pacemaker.spec.in
-index 3a26572..fd0e3c8 100644
---- a/pacemaker.spec.in
-+++ b/pacemaker.spec.in
-@@ -80,6 +80,9 @@
-   } || %{?__transaction_systemd_inhibit:1}%{!?__transaction_systemd_inhibit:0}%{nil \
-   } || %(test -f /usr/lib/os-release; test $? -ne 0; echo $?))
- 
-+%if 0%{?fedora} > 20 || 0%{?rhel} > 7
-+%global gnutls_priorities @SYSTEM
-+%endif
- 
- # Definitions for backward compatibility with older RPM versions
- 
-@@ -403,6 +406,7 @@ export LDFLAGS_HARDENED_LIB="%{?_hardening_ldflags}"
-         --without-heartbeat                        \
-         %{!?with_doc:        --with-brand=}        \
-         %{!?with_hardening:  --disable-hardening}  \
-+        %{?gnutls_priorities: --with-gnutls-priorities="%{gnutls_priorities}"} \
-         --with-initdir=%{_initrddir}               \
-         --localstatedir=%{_var}                    \
-         --with-version=%{version}-%{release}
--- 
-1.8.3.1
-
-
-From 99a83b172544102ec32585514e5808585f2ce31c Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Mon, 8 Jul 2019 17:39:12 -0500
-Subject: [PATCH 33/96] Feature: remote: allow run-time configurable TLS
- priorities
-
-This also restores compilability with GnuTLS <2.1.7 (not that anyone is still
-using that ...), unintentionally broken in 5bded36 (1.1.20).
----
- lib/common/remote.c     | 34 +++++++++++++++++++++++++++-------
- mcp/pacemaker.sysconfig |  9 +++++++++
- 2 files changed, 36 insertions(+), 7 deletions(-)
-
-diff --git a/lib/common/remote.c b/lib/common/remote.c
-index 1e4f8d8..ccd0342 100644
---- a/lib/common/remote.c
-+++ b/lib/common/remote.c
-@@ -237,17 +237,25 @@ pcmk__new_tls_session(int csock, unsigned int conn_type,
- {
-     int rc = GNUTLS_E_SUCCESS;
- #  ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT
--    const char *prio = NULL;
-+    const char *prio_base = NULL;
-+    char *prio = NULL;
- #  endif
-     gnutls_session_t *session = NULL;
- 
- #  ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT
--    if (cred_type == GNUTLS_CRD_ANON) {
--        // http://www.manpagez.com/info/gnutls/gnutls-2.10.4/gnutls_81.php#Echo-Server-with-anonymous-authentication
--        prio = PCMK_GNUTLS_PRIORITIES ":+ANON-DH";
--    } else {
--        prio = PCMK_GNUTLS_PRIORITIES ":+DHE-PSK:+PSK";
-+    /* Determine list of acceptable ciphers, etc. Pacemaker always adds the
-+     * values required for its functionality.
-+     *
-+     * For an example of anonymous authentication, see:
-+     * http://www.manpagez.com/info/gnutls/gnutls-2.10.4/gnutls_81.php#Echo-Server-with-anonymous-authentication
-+     */
-+
-+    prio_base = getenv("PCMK_tls_priorities");
-+    if (prio_base == NULL) {
-+        prio_base = PCMK_GNUTLS_PRIORITIES;
-     }
-+    prio = crm_strdup_printf("%s:%s", prio_base,
-+                             (cred_type == GNUTLS_CRD_ANON)? "+ANON-DH" : "+DHE-PSK:+PSK");
- #  endif
- 
-     session = gnutls_malloc(sizeof(gnutls_session_t));
-@@ -285,6 +293,9 @@ pcmk__new_tls_session(int csock, unsigned int conn_type,
-     if (rc != GNUTLS_E_SUCCESS) {
-         goto error;
-     }
-+#  ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT
-+    free(prio);
-+#  endif
-     return session;
- 
- error:
-@@ -292,7 +303,16 @@ error:
-             CRM_XS " rc=%d priority='%s'",
-             (cred_type == GNUTLS_CRD_ANON)? "anonymous" : "PSK",
-             (conn_type == GNUTLS_SERVER)? "server" : "client",
--            gnutls_strerror(rc), rc, prio);
-+            gnutls_strerror(rc), rc,
-+#  ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT
-+            prio
-+#  else
-+            "default"
-+#  endif
-+            );
-+#  ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT
-+    free(prio);
-+#  endif
-     if (session != NULL) {
-         gnutls_free(session);
-     }
-diff --git a/mcp/pacemaker.sysconfig b/mcp/pacemaker.sysconfig
-index a983011..0da401e 100644
---- a/mcp/pacemaker.sysconfig
-+++ b/mcp/pacemaker.sysconfig
-@@ -101,6 +101,15 @@
- # value must be the same on all nodes. The default is "3121".
- # PCMK_remote_port=3121
- 
-+# Use these GnuTLS cipher priorities for TLS connections. See:
-+#
-+#   https://gnutls.org/manual/html_node/Priority-Strings.html
-+#
-+# Pacemaker will append ":+ANON-DH" for remote CIB access (when enabled) and
-+# ":+DHE-PSK:+PSK" for Pacemaker Remote connections, as they are required for
-+# the respective functionality.
-+# PCMK_tls_priorities="NORMAL"
-+
- # Set bounds on the bit length of the prime number generated for Diffie-Hellman
- # parameters needed by TLS connections. The default is not to set any bounds.
- #
--- 
-1.8.3.1
-
-
-From bb7f4be166e4a8d9e851377aeb3b69a2a6b429a4 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Fri, 5 Jul 2019 15:34:30 -0500
-Subject: [PATCH 34/96] Low: controller: reset expected reply when
- disconnecting from scheduler
-
----
- crmd/control.c    |  7 ++++++-
- crmd/crmd_utils.h |  2 +-
- crmd/pengine.c    | 12 ++++++++----
- 3 files changed, 15 insertions(+), 6 deletions(-)
-
-diff --git a/crmd/control.c b/crmd/control.c
-index 73a2b08..4b19114 100644
---- a/crmd/control.c
-+++ b/crmd/control.c
-@@ -297,6 +297,10 @@ crmd_exit(int rc)
- 
-     if (pe_subsystem && pe_subsystem->client && pe_subsystem->client->ipcs) {
-         crm_trace("Disconnecting Policy Engine");
-+
-+        // If we aren't connected to the scheduler, we can't expect a reply
-+        controld_expect_sched_reply(NULL);
-+
-         qb_ipcs_disconnect(pe_subsystem->client->ipcs);
-     }
- 
-@@ -339,6 +343,7 @@ crmd_exit(int rc)
-     clear_bit(fsa_input_register, R_MEMBERSHIP);
-     g_list_free(fsa_message_queue); fsa_message_queue = NULL;
- 
-+    free(pe_subsystem); pe_subsystem = NULL;
-     free(te_subsystem); te_subsystem = NULL;
-     free(cib_subsystem); cib_subsystem = NULL;
- 
-@@ -374,7 +379,7 @@ crmd_exit(int rc)
-     crm_timer_stop(recheck_timer);
- 
-     te_cleanup_stonith_history_sync(NULL, TRUE);
--    controld_sched_cleanup();
-+    controld_free_sched_timer();
- 
-     free(transition_timer); transition_timer = NULL;
-     free(integration_timer); integration_timer = NULL;
-diff --git a/crmd/crmd_utils.h b/crmd/crmd_utils.h
-index a704380..955d859 100644
---- a/crmd/crmd_utils.h
-+++ b/crmd/crmd_utils.h
-@@ -84,8 +84,8 @@ int crmd_fast_exit(int rc);
- gboolean stop_subsystem(struct crm_subsystem_s *centry, gboolean force_quit);
- gboolean start_subsystem(struct crm_subsystem_s *centry);
- void controld_stop_sched_timer(void);
-+void controld_free_sched_timer(void);
- void controld_expect_sched_reply(xmlNode *msg);
--void controld_sched_cleanup(void);
- 
- void fsa_dump_actions(long long action, const char *text);
- void fsa_dump_inputs(int log_level, const char *text, long long input_register);
-diff --git a/crmd/pengine.c b/crmd/pengine.c
-index 1630e7b..3512952 100644
---- a/crmd/pengine.c
-+++ b/crmd/pengine.c
-@@ -97,6 +97,9 @@ pe_ipc_destroy(gpointer user_data)
-         crm_info("Connection to the Policy Engine released");
-     }
- 
-+    // If we aren't connected to the scheduler, we can't expect a reply
-+    controld_expect_sched_reply(NULL);
-+
-     clear_bit(fsa_input_register, pe_subsystem->flag_connected);
-     pe_subsystem->pid = -1;
-     pe_subsystem->source = NULL;
-@@ -137,6 +140,9 @@ do_pe_control(long long action,
-     };
- 
-     if (action & stop_actions) {
-+        // If we aren't connected to the scheduler, we can't expect a reply
-+        controld_expect_sched_reply(NULL);
-+
-         clear_bit(fsa_input_register, pe_subsystem->flag_required);
- 
-         mainloop_del_ipc_client(pe_subsystem->source);
-@@ -244,17 +250,15 @@ controld_expect_sched_reply(xmlNode *msg)
- 
- /*!
-  * \internal
-- * \brief Clean up all memory used by controller scheduler handling
-+ * \brief Free the scheduler reply timer
-  */
- void
--controld_sched_cleanup()
-+controld_free_sched_timer()
- {
-     if (controld_sched_timer != NULL) {
-         mainloop_timer_del(controld_sched_timer);
-         controld_sched_timer = NULL;
-     }
--    free(pe_subsystem); pe_subsystem = NULL;
--    controld_expect_sched_reply(NULL);
- }
- 
- /*	 A_PE_INVOKE	*/
--- 
-1.8.3.1
-
-
-From e2981df8681d7721d576eacd443fa3cc08c17a02 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 11 Jul 2019 13:49:11 -0500
-Subject: [PATCH 35/96] Test: CTS: update pattern for 1.1 backport
-
----
- cts/patterns.py | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/cts/patterns.py b/cts/patterns.py
-index 87b44a9..00c26ff 100644
---- a/cts/patterns.py
-+++ b/cts/patterns.py
-@@ -376,7 +376,7 @@ class crm_cs_v0(BasePatterns):
-             "LRMD lost STONITH connection",
-             "Connection to stonith-ng.* closed",
-             "Fencing daemon connection failed",
--            r"pacemaker-controld.*Fencer successfully connected",
-+            r"crmd:.*Fencer successfully connected",
-         ]
-         self.components["stonith-ignore"] = [
-             r"pengine.*: Recover Fencing",
--- 
-1.8.3.1
-
-
-From 7903d2a0ad53f4906248d26e13d5aaf7c4c824e6 Mon Sep 17 00:00:00 2001
-From: "Gao,Yan" <ygao@suse.com>
-Date: Mon, 8 Apr 2019 15:01:20 +0200
-Subject: [PATCH 36/96] Fix: scheduler: wait for probe actions to complete to
- prevent unnecessary restart/re-promote of dependent resources
-
-This addresses the issue brought up from:
-https://github.com/ClusterLabs/pacemaker/commit/faf44d811e4f5598dae085c61fdef410c8d18882#commitcomment-22262090
-
-Given an ordering chain in a transition graph like:
-
-A.probe -> A.start -> [...] -> B.start
-
-, if B was already started, it would be scheduled to restart.
-
-Previously, B would be directly stopped, which could turn out to be
-unnecessary if A was probed being already started as well. Such
-unnecessary restart could be very expensive for heavy workload.
-
-With this commit, a new order will be created:
-
-A.probe -> B.stop
-
-So that any potential restart of B will wait for A.probe to complete. In
-case that A is already started, transition will abort and restart of B
-won't need to be performed any more.
-
-Similarly for an ordering chain like:
-
-A.probe -> A.start -> [...] -> B.promote
-
-A new order will be created to prevent unnecessary re-promote:
-A.probe -> B.demote
----
- pengine/allocate.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 202 insertions(+), 2 deletions(-)
-
-diff --git a/pengine/allocate.c b/pengine/allocate.c
-index c7c68f8..d600bbf 100644
---- a/pengine/allocate.c
-+++ b/pengine/allocate.c
-@@ -2294,9 +2294,8 @@ order_first_probe_unneeded(pe_action_t * probe, pe_action_t * rh_action)
-     return FALSE;
- }
- 
--
- static void
--order_first_probes(pe_working_set_t * data_set)
-+order_first_probes_imply_stops(pe_working_set_t * data_set)
- {
-     GListPtr gIter = NULL;
- 
-@@ -2424,6 +2423,207 @@ order_first_probes(pe_working_set_t * data_set)
- }
- 
- static void
-+order_first_probe_then_restart_repromote(pe_action_t * probe,
-+                                         pe_action_t * after,
-+                                         pe_working_set_t * data_set)
-+{
-+    GListPtr gIter = NULL;
-+    bool interleave = FALSE;
-+    pe_resource_t *compatible_rsc = NULL;
-+
-+    if (probe == NULL
-+        || probe->rsc == NULL
-+        || probe->rsc->variant != pe_native) {
-+        return;
-+    }
-+
-+    if (after == NULL
-+        // Avoid running into any possible loop
-+        || is_set(after->flags, pe_action_tracking)) {
-+        return;
-+    }
-+
-+    if (safe_str_neq(probe->task, RSC_STATUS)) {
-+        return;
-+    }
-+
-+    pe_set_action_bit(after, pe_action_tracking);
-+
-+    crm_trace("Processing based on %s %s -> %s %s",
-+              probe->uuid,
-+              probe->node ? probe->node->details->uname: "",
-+              after->uuid,
-+              after->node ? after->node->details->uname : "");
-+
-+    if (after->rsc
-+        /* Better not build a dependency directly with a clone/group.
-+         * We are going to proceed through the ordering chain and build
-+         * dependencies with its children.
-+         */
-+        && after->rsc->variant == pe_native
-+        && probe->rsc != after->rsc) {
-+
-+            GListPtr then_actions = NULL;
-+            enum pe_ordering probe_order_type = pe_order_optional;
-+
-+            if (safe_str_eq(after->task, RSC_START)) {
-+                char *key = generate_op_key(after->rsc->id, RSC_STOP, 0);
-+
-+                then_actions = find_actions(after->rsc->actions, key, NULL);
-+                free(key);
-+
-+            } else if (safe_str_eq(after->task, RSC_PROMOTE)) {
-+                char *key = generate_op_key(after->rsc->id, RSC_DEMOTE, 0);
-+
-+                then_actions = find_actions(after->rsc->actions, key, NULL);
-+                free(key);
-+            }
-+
-+            for (gIter = then_actions; gIter != NULL; gIter = gIter->next) {
-+                pe_action_t *then = (pe_action_t *) gIter->data;
-+
-+                // Skip any pseudo action which for example is implied by fencing
-+                if (is_set(then->flags, pe_action_pseudo)) {
-+                    continue;
-+                }
-+
-+                order_actions(probe, then, probe_order_type);
-+            }
-+            g_list_free(then_actions);
-+    }
-+
-+    if (after->rsc
-+        && after->rsc->variant > pe_group) {
-+        const char *interleave_s = g_hash_table_lookup(after->rsc->meta,
-+                                                       XML_RSC_ATTR_INTERLEAVE);
-+
-+        interleave = crm_is_true(interleave_s);
-+
-+        if (interleave) {
-+            /* For an interleaved clone, we should build a dependency only
-+             * with the relevant clone child.
-+             */
-+            compatible_rsc = find_compatible_child(probe->rsc,
-+                                                   after->rsc,
-+                                                   RSC_ROLE_UNKNOWN,
-+                                                   FALSE);
-+        }
-+    }
-+
-+    for (gIter = after->actions_after; gIter != NULL; gIter = gIter->next) {
-+        action_wrapper_t *after_wrapper = (action_wrapper_t *) gIter->data;
-+        /* pe_order_implies_then is the reason why a required A.start
-+         * implies/enforces B.start to be required too, which is the cause of
-+         * B.restart/re-promote.
-+         *
-+         * Not sure about pe_order_implies_then_on_node though. It's now only
-+         * used for unfencing case, which tends to introduce transition
-+         * loops...
-+         */
-+
-+        if (is_not_set(after_wrapper->type, pe_order_implies_then)) {
-+            /* The order type between a group/clone and its child such as
-+             * B.start-> B_child.start is:
-+             * pe_order_implies_first_printed | pe_order_runnable_left
-+             *
-+             * Proceed through the ordering chain and build dependencies with
-+             * its children.
-+             */
-+            if (after->rsc == NULL
-+                || after->rsc->variant < pe_group
-+                || probe->rsc->parent == after->rsc
-+                || after_wrapper->action->rsc == NULL
-+                || after_wrapper->action->rsc->variant > pe_group
-+                || after->rsc != after_wrapper->action->rsc->parent) {
-+                continue;
-+            }
-+
-+            /* Proceed to the children of a group or a non-interleaved clone.
-+             * For an interleaved clone, proceed only to the relevant child.
-+             */
-+            if (after->rsc->variant > pe_group
-+                && interleave == TRUE
-+                && (compatible_rsc == NULL
-+                    || compatible_rsc != after_wrapper->action->rsc)) {
-+                continue;
-+            }
-+        }
-+
-+        crm_trace("Proceeding through %s %s -> %s %s (type=0x%.6x)",
-+                  after->uuid,
-+                  after->node ? after->node->details->uname: "",
-+                  after_wrapper->action->uuid,
-+                  after_wrapper->action->node ? after_wrapper->action->node->details->uname : "",
-+                  after_wrapper->type);
-+
-+        order_first_probe_then_restart_repromote(probe, after_wrapper->action, data_set);
-+    }
-+}
-+
-+static void clear_actions_tracking_flag(pe_working_set_t * data_set)
-+{
-+    GListPtr gIter = NULL;
-+
-+    for (gIter = data_set->actions; gIter != NULL; gIter = gIter->next) {
-+        pe_action_t *action = (pe_action_t *) gIter->data;
-+
-+        if (is_set(action->flags, pe_action_tracking)) {
-+            pe_clear_action_bit(action, pe_action_tracking);
-+        }
-+    }
-+}
-+
-+static void
-+order_first_rsc_probes(pe_resource_t * rsc, pe_working_set_t * data_set)
-+{
-+    GListPtr gIter = NULL;
-+    GListPtr probes = NULL;
-+    char *key = NULL;
-+
-+    for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
-+        pe_resource_t * child = (pe_resource_t *) gIter->data;
-+
-+        order_first_rsc_probes(child, data_set);
-+    }
-+
-+    if (rsc->variant != pe_native) {
-+        return;
-+    }
-+
-+    key = generate_op_key(rsc->id, RSC_STATUS, 0);
-+    probes = find_actions(rsc->actions, key, NULL);
-+    free(key);
-+
-+    for (gIter = probes; gIter != NULL; gIter= gIter->next) {
-+        pe_action_t *probe = (pe_action_t *) gIter->data;
-+        GListPtr aIter = NULL;
-+
-+        for (aIter = probe->actions_after; aIter != NULL; aIter = aIter->next) {
-+            action_wrapper_t *after_wrapper = (action_wrapper_t *) aIter->data;
-+
-+            order_first_probe_then_restart_repromote(probe, after_wrapper->action, data_set);
-+            clear_actions_tracking_flag(data_set);
-+        }
-+    }
-+
-+    g_list_free(probes);
-+}
-+
-+static void
-+order_first_probes(pe_working_set_t * data_set)
-+{
-+    GListPtr gIter = NULL;
-+
-+    for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
-+        pe_resource_t *rsc = (pe_resource_t *) gIter->data;
-+
-+        order_first_rsc_probes(rsc, data_set);
-+    }
-+
-+    order_first_probes_imply_stops(data_set);
-+}
-+
-+static void
- order_then_probes(pe_working_set_t * data_set)
- {
- #if 0
--- 
-1.8.3.1
-
-
-From 3228b6b4df624db4b72d40bd366433f673a8780e Mon Sep 17 00:00:00 2001
-From: "Gao,Yan" <ygao@suse.com>
-Date: Tue, 30 Apr 2019 03:47:07 +0200
-Subject: [PATCH 37/96] Test: scheduler: wait for probe actions to complete to
- prevent unnecessary restart/re-promote of dependent resources (update tests)
-
----
- .../test10/11-a-then-bm-b-move-a-clone-starting.dot |  1 +
- .../test10/11-a-then-bm-b-move-a-clone-starting.exp |  6 +++++-
- pengine/test10/bug-n-387749.dot                     |  7 +++++++
- pengine/test10/bug-n-387749.exp                     | 21 +++++++++++++++++++++
- pengine/test10/group5.dot                           |  3 +++
- pengine/test10/group5.exp                           |  9 +++++++++
- pengine/test10/group6.dot                           |  6 ++++++
- pengine/test10/group6.exp                           | 18 ++++++++++++++++++
- pengine/test10/group9.dot                           |  6 ++++++
- pengine/test10/group9.exp                           | 18 ++++++++++++++++++
- pengine/test10/order6.dot                           |  2 ++
- pengine/test10/order6.exp                           | 12 ++++++++++--
- pengine/test10/reload-becomes-restart.dot           |  1 +
- pengine/test10/reload-becomes-restart.exp           |  3 +++
- 14 files changed, 110 insertions(+), 3 deletions(-)
-
-diff --git a/pengine/test10/11-a-then-bm-b-move-a-clone-starting.dot b/pengine/test10/11-a-then-bm-b-move-a-clone-starting.dot
-index 4a89db6..4fd6a7d 100644
---- a/pengine/test10/11-a-then-bm-b-move-a-clone-starting.dot
-+++ b/pengine/test10/11-a-then-bm-b-move-a-clone-starting.dot
-@@ -12,6 +12,7 @@
- "myclone-clone_stopped_0" [ style=bold color="green" fontcolor="orange"]
- "myclone_monitor_0 f20node2" -> "myclone-clone_start_0" [ style = bold]
- "myclone_monitor_0 f20node2" -> "myclone-clone_stopped_0" [ style = bold]
-+"myclone_monitor_0 f20node2" -> "vm_stop_0 f20node1" [ style = bold]
- "myclone_monitor_0 f20node2" [ style=bold color="green" fontcolor="black"]
- "myclone_start_0 f20node2" -> "myclone-clone_running_0" [ style = bold]
- "myclone_start_0 f20node2" [ style=bold color="green" fontcolor="black"]
-diff --git a/pengine/test10/11-a-then-bm-b-move-a-clone-starting.exp b/pengine/test10/11-a-then-bm-b-move-a-clone-starting.exp
-index 4eeb086..d3ce8b7 100644
---- a/pengine/test10/11-a-then-bm-b-move-a-clone-starting.exp
-+++ b/pengine/test10/11-a-then-bm-b-move-a-clone-starting.exp
-@@ -120,6 +120,10 @@
-         <attributes CRM_meta_on_node="f20node1" CRM_meta_on_node_uuid="1" CRM_meta_timeout="20000" />
-       </rsc_op>
-     </action_set>
--    <inputs/>
-+    <inputs>
-+      <trigger>
-+        <rsc_op id="1" operation="monitor" operation_key="myclone_monitor_0" internal_operation_key="myclone:0_monitor_0" on_node="f20node2" on_node_uuid="2"/>
-+      </trigger>
-+    </inputs>
-   </synapse>
- </transition_graph>
-diff --git a/pengine/test10/bug-n-387749.dot b/pengine/test10/bug-n-387749.dot
-index 5095351..a820108 100644
---- a/pengine/test10/bug-n-387749.dot
-+++ b/pengine/test10/bug-n-387749.dot
-@@ -1,17 +1,23 @@
- digraph "g" {
- "export_home_ocfs2:0_monitor_0 power720-1" -> "export_home_ocfs2_clone_set_start_0" [ style = bold]
-+"export_home_ocfs2:0_monitor_0 power720-1" -> "resource_ipaddr1_single_stop_0 power720-2" [ style = bold]
-+"export_home_ocfs2:0_monitor_0 power720-1" -> "resource_nfsserver_single_stop_0 power720-2" [ style = bold]
- "export_home_ocfs2:0_monitor_0 power720-1" [ style=bold color="green" fontcolor="black" ]
- "export_home_ocfs2:0_post_notify_start_0 power720-1" -> "export_home_ocfs2_clone_set_confirmed-post_notify_running_0" [ style = bold]
- "export_home_ocfs2:0_post_notify_start_0 power720-1" [ style=bold color="green" fontcolor="black" ]
- "export_home_ocfs2:0_start_0 power720-1" -> "export_home_ocfs2_clone_set_running_0" [ style = bold]
- "export_home_ocfs2:0_start_0 power720-1" [ style=bold color="green" fontcolor="black" ]
- "export_home_ocfs2:1_monitor_0 power720-1" -> "export_home_ocfs2_clone_set_start_0" [ style = bold]
-+"export_home_ocfs2:1_monitor_0 power720-1" -> "resource_ipaddr1_single_stop_0 power720-2" [ style = bold]
-+"export_home_ocfs2:1_monitor_0 power720-1" -> "resource_nfsserver_single_stop_0 power720-2" [ style = bold]
- "export_home_ocfs2:1_monitor_0 power720-1" [ style=bold color="green" fontcolor="black" ]
- "export_home_ocfs2:1_post_notify_start_0 power720-2" -> "export_home_ocfs2_clone_set_confirmed-post_notify_running_0" [ style = bold]
- "export_home_ocfs2:1_post_notify_start_0 power720-2" [ style=bold color="green" fontcolor="black" ]
- "export_home_ocfs2:1_pre_notify_start_0 power720-2" -> "export_home_ocfs2_clone_set_confirmed-pre_notify_start_0" [ style = bold]
- "export_home_ocfs2:1_pre_notify_start_0 power720-2" [ style=bold color="green" fontcolor="black" ]
- "export_home_ocfs2:2_monitor_0 power720-1" -> "export_home_ocfs2_clone_set_start_0" [ style = bold]
-+"export_home_ocfs2:2_monitor_0 power720-1" -> "resource_ipaddr1_single_stop_0 power720-2" [ style = bold]
-+"export_home_ocfs2:2_monitor_0 power720-1" -> "resource_nfsserver_single_stop_0 power720-2" [ style = bold]
- "export_home_ocfs2:2_monitor_0 power720-1" [ style=bold color="green" fontcolor="black" ]
- "export_home_ocfs2_clone_set_confirmed-post_notify_running_0" -> "group_nfs_start_0" [ style = bold]
- "export_home_ocfs2_clone_set_confirmed-post_notify_running_0" [ style=bold color="green" fontcolor="orange" ]
-@@ -43,6 +49,7 @@ digraph "g" {
- "group_nfs_stopped_0" [ style=bold color="green" fontcolor="orange" ]
- "resource_ipaddr1_single_monitor_0 power720-1" -> "group_nfs_stopped_0" [ style = bold]
- "resource_ipaddr1_single_monitor_0 power720-1" -> "resource_ipaddr1_single_start_0 power720-1" [ style = bold]
-+"resource_ipaddr1_single_monitor_0 power720-1" -> "resource_nfsserver_single_stop_0 power720-2" [ style = bold]
- "resource_ipaddr1_single_monitor_0 power720-1" [ style=bold color="green" fontcolor="black" ]
- "resource_ipaddr1_single_monitor_5000 power720-1" [ style=bold color="green" fontcolor="black" ]
- "resource_ipaddr1_single_start_0 power720-1" -> "group_nfs_running_0" [ style = bold]
-diff --git a/pengine/test10/bug-n-387749.exp b/pengine/test10/bug-n-387749.exp
-index d6fe8e4..5b646bc 100644
---- a/pengine/test10/bug-n-387749.exp
-+++ b/pengine/test10/bug-n-387749.exp
-@@ -276,6 +276,15 @@
-      </action_set>
-      <inputs>
-        <trigger>
-+        <rsc_op id="3" operation="monitor" operation_key="export_home_ocfs2:0_monitor_0" on_node="power720-1" on_node_uuid="ac446085-4c9d-4d4a-a94d-5e63b6e421e3"/>
-+      </trigger>
-+      <trigger>
-+        <rsc_op id="4" operation="monitor" operation_key="export_home_ocfs2:1_monitor_0" on_node="power720-1" on_node_uuid="ac446085-4c9d-4d4a-a94d-5e63b6e421e3"/>
-+      </trigger>
-+      <trigger>
-+        <rsc_op id="5" operation="monitor" operation_key="export_home_ocfs2:2_monitor_0" on_node="power720-1" on_node_uuid="ac446085-4c9d-4d4a-a94d-5e63b6e421e3"/>
-+      </trigger>
-+      <trigger>
-         <rsc_op id="7" operation="monitor" operation_key="resource_nfsserver_single_monitor_0" on_node="power720-1" on_node_uuid="ac446085-4c9d-4d4a-a94d-5e63b6e421e3"/>
-       </trigger>
-       <trigger>
-@@ -339,6 +348,18 @@
-      </action_set>
-      <inputs>
-        <trigger>
-+        <rsc_op id="3" operation="monitor" operation_key="export_home_ocfs2:0_monitor_0" on_node="power720-1" on_node_uuid="ac446085-4c9d-4d4a-a94d-5e63b6e421e3"/>
-+      </trigger>
-+      <trigger>
-+        <rsc_op id="4" operation="monitor" operation_key="export_home_ocfs2:1_monitor_0" on_node="power720-1" on_node_uuid="ac446085-4c9d-4d4a-a94d-5e63b6e421e3"/>
-+      </trigger>
-+      <trigger>
-+        <rsc_op id="5" operation="monitor" operation_key="export_home_ocfs2:2_monitor_0" on_node="power720-1" on_node_uuid="ac446085-4c9d-4d4a-a94d-5e63b6e421e3"/>
-+      </trigger>
-+      <trigger>
-+        <rsc_op id="6" operation="monitor" operation_key="resource_ipaddr1_single_monitor_0" on_node="power720-1" on_node_uuid="ac446085-4c9d-4d4a-a94d-5e63b6e421e3"/>
-+      </trigger>
-+      <trigger>
-         <pseudo_event id="31" operation="stop" operation_key="group_nfs_stop_0"/>
-        </trigger>
-      </inputs>
-diff --git a/pengine/test10/group5.dot b/pengine/test10/group5.dot
-index 3fe0193..4776b1e 100644
---- a/pengine/test10/group5.dot
-+++ b/pengine/test10/group5.dot
-@@ -1,5 +1,7 @@
-  digraph "g" {
- "child_rsc1_monitor_0 node2" -> "child_rsc1_start_0 node2" [ style = bold]
-+"child_rsc1_monitor_0 node2" -> "child_rsc2_stop_0 node1" [ style = bold]
-+"child_rsc1_monitor_0 node2" -> "child_rsc3_stop_0 node1" [ style = bold]
- "child_rsc1_monitor_0 node2" -> "rsc2_stopped_0" [ style = bold]
- "child_rsc1_monitor_0 node2" [ style=bold color="green" fontcolor="black" ]
- "child_rsc1_start_0 node2" -> "child_rsc2_start_0 node2" [ style = bold]
-@@ -10,6 +12,7 @@
- "child_rsc1_stop_0 node1" [ style=bold color="green" fontcolor="black" ]
- "child_rsc2_monitor_0 node2" -> "child_rsc1_stop_0 node1" [ style = bold]
- "child_rsc2_monitor_0 node2" -> "child_rsc2_start_0 node2" [ style = bold]
-+"child_rsc2_monitor_0 node2" -> "child_rsc3_stop_0 node1" [ style = bold]
- "child_rsc2_monitor_0 node2" -> "rsc2_stopped_0" [ style = bold]
- "child_rsc2_monitor_0 node2" [ style=bold color="green" fontcolor="black" ]
- "child_rsc2_start_0 node2" -> "child_rsc3_start_0 node2" [ style = bold]
-diff --git a/pengine/test10/group5.exp b/pengine/test10/group5.exp
-index 4ea2b08..0f55341 100644
---- a/pengine/test10/group5.exp
-+++ b/pengine/test10/group5.exp
-@@ -196,6 +196,9 @@
-      </action_set>
-      <inputs>
-        <trigger>
-+        <rsc_op id="2" operation="monitor" operation_key="child_rsc1_monitor_0" on_node="node2" on_node_uuid="uuid2"/>
-+      </trigger>
-+      <trigger>
-         <rsc_op id="4" operation="monitor" operation_key="child_rsc3_monitor_0" on_node="node2" on_node_uuid="uuid2"/>
-       </trigger>
-       <trigger>
-@@ -246,6 +249,12 @@
-      </action_set>
-      <inputs>
-        <trigger>
-+        <rsc_op id="2" operation="monitor" operation_key="child_rsc1_monitor_0" on_node="node2" on_node_uuid="uuid2"/>
-+      </trigger>
-+      <trigger>
-+        <rsc_op id="3" operation="monitor" operation_key="child_rsc2_monitor_0" on_node="node2" on_node_uuid="uuid2"/>
-+      </trigger>
-+      <trigger>
-         <pseudo_event id="16" operation="stop" operation_key="rsc2_stop_0"/>
-        </trigger>
-      </inputs>
-diff --git a/pengine/test10/group6.dot b/pengine/test10/group6.dot
-index a563e05..536f56b 100644
---- a/pengine/test10/group6.dot
-+++ b/pengine/test10/group6.dot
-@@ -1,5 +1,7 @@
-  digraph "g" {
- "child_rsc1_monitor_0 node2" -> "child_rsc1_start_0 node2" [ style = bold]
-+"child_rsc1_monitor_0 node2" -> "child_rsc2_stop_0 node1" [ style = bold]
-+"child_rsc1_monitor_0 node2" -> "child_rsc3_stop_0 node1" [ style = bold]
- "child_rsc1_monitor_0 node2" -> "rsc1_stopped_0" [ style = bold]
- "child_rsc1_monitor_0 node2" [ style=bold color="green" fontcolor="black" ]
- "child_rsc1_start_0 node2" -> "child_rsc2_start_0 node2" [ style = bold]
-@@ -10,6 +12,7 @@
- "child_rsc1_stop_0 node1" [ style=bold color="green" fontcolor="black" ]
- "child_rsc2_monitor_0 node2" -> "child_rsc1_stop_0 node1" [ style = bold]
- "child_rsc2_monitor_0 node2" -> "child_rsc2_start_0 node2" [ style = bold]
-+"child_rsc2_monitor_0 node2" -> "child_rsc3_stop_0 node1" [ style = bold]
- "child_rsc2_monitor_0 node2" -> "rsc1_stopped_0" [ style = bold]
- "child_rsc2_monitor_0 node2" [ style=bold color="green" fontcolor="black" ]
- "child_rsc2_start_0 node2" -> "child_rsc3_start_0 node2" [ style = bold]
-@@ -30,6 +33,8 @@
- "child_rsc3_stop_0 node1" -> "rsc1_stopped_0" [ style = bold]
- "child_rsc3_stop_0 node1" [ style=bold color="green" fontcolor="black" ]
- "child_rsc4_monitor_0 node2" -> "child_rsc4_start_0 node2" [ style = bold]
-+"child_rsc4_monitor_0 node2" -> "child_rsc5_stop_0 node1" [ style = bold]
-+"child_rsc4_monitor_0 node2" -> "child_rsc6_stop_0 node1" [ style = bold]
- "child_rsc4_monitor_0 node2" -> "rsc2_stopped_0" [ style = bold]
- "child_rsc4_monitor_0 node2" [ style=bold color="green" fontcolor="black" ]
- "child_rsc4_start_0 node2" -> "child_rsc5_start_0 node2" [ style = bold]
-@@ -40,6 +45,7 @@
- "child_rsc4_stop_0 node1" [ style=bold color="green" fontcolor="black" ]
- "child_rsc5_monitor_0 node2" -> "child_rsc4_stop_0 node1" [ style = bold]
- "child_rsc5_monitor_0 node2" -> "child_rsc5_start_0 node2" [ style = bold]
-+"child_rsc5_monitor_0 node2" -> "child_rsc6_stop_0 node1" [ style = bold]
- "child_rsc5_monitor_0 node2" -> "rsc2_stopped_0" [ style = bold]
- "child_rsc5_monitor_0 node2" [ style=bold color="green" fontcolor="black" ]
- "child_rsc5_start_0 node2" -> "child_rsc6_start_0 node2" [ style = bold]
-diff --git a/pengine/test10/group6.exp b/pengine/test10/group6.exp
-index cddd6f4..097d23d 100644
---- a/pengine/test10/group6.exp
-+++ b/pengine/test10/group6.exp
-@@ -152,6 +152,9 @@
-      </action_set>
-      <inputs>
-        <trigger>
-+        <rsc_op id="1" operation="monitor" operation_key="child_rsc1_monitor_0" on_node="node2" on_node_uuid="uuid2"/>
-+      </trigger>
-+      <trigger>
-         <rsc_op id="3" operation="monitor" operation_key="child_rsc3_monitor_0" on_node="node2" on_node_uuid="uuid2"/>
-       </trigger>
-       <trigger>
-@@ -202,6 +205,12 @@
-      </action_set>
-      <inputs>
-        <trigger>
-+        <rsc_op id="1" operation="monitor" operation_key="child_rsc1_monitor_0" on_node="node2" on_node_uuid="uuid2"/>
-+      </trigger>
-+      <trigger>
-+        <rsc_op id="2" operation="monitor" operation_key="child_rsc2_monitor_0" on_node="node2" on_node_uuid="uuid2"/>
-+      </trigger>
-+      <trigger>
-         <pseudo_event id="15" operation="stop" operation_key="rsc1_stop_0"/>
-        </trigger>
-      </inputs>
-@@ -367,6 +376,9 @@
-      </action_set>
-      <inputs>
-        <trigger>
-+        <rsc_op id="4" operation="monitor" operation_key="child_rsc4_monitor_0" on_node="node2" on_node_uuid="uuid2"/>
-+      </trigger>
-+      <trigger>
-         <rsc_op id="6" operation="monitor" operation_key="child_rsc6_monitor_0" on_node="node2" on_node_uuid="uuid2"/>
-       </trigger>
-       <trigger>
-@@ -417,6 +429,12 @@
-      </action_set>
-      <inputs>
-        <trigger>
-+        <rsc_op id="4" operation="monitor" operation_key="child_rsc4_monitor_0" on_node="node2" on_node_uuid="uuid2"/>
-+      </trigger>
-+      <trigger>
-+        <rsc_op id="5" operation="monitor" operation_key="child_rsc5_monitor_0" on_node="node2" on_node_uuid="uuid2"/>
-+      </trigger>
-+      <trigger>
-         <pseudo_event id="25" operation="stop" operation_key="rsc2_stop_0"/>
-        </trigger>
-      </inputs>
-diff --git a/pengine/test10/group9.dot b/pengine/test10/group9.dot
-index 610fe93..5a93a31 100644
---- a/pengine/test10/group9.dot
-+++ b/pengine/test10/group9.dot
-@@ -26,9 +26,12 @@
- "rsc1_monitor_0 node2" [ style=bold color="green" fontcolor="black" ]
- "rsc2_monitor_0 node2" [ style=bold color="green" fontcolor="black" ]
- "rsc3_monitor_0 node2" -> "foo_stopped_0" [ style = bold]
-+"rsc3_monitor_0 node2" -> "rsc4_stop_0 node1" [ style = bold]
-+"rsc3_monitor_0 node2" -> "rsc5_stop_0 node1" [ style = bold]
- "rsc3_monitor_0 node2" [ style=bold color="green" fontcolor="black" ]
- "rsc4_monitor_0 node2" -> "foo_stopped_0" [ style = bold]
- "rsc4_monitor_0 node2" -> "rsc4_start_0 node1" [ style = bold]
-+"rsc4_monitor_0 node2" -> "rsc5_stop_0 node1" [ style = bold]
- "rsc4_monitor_0 node2" [ style=bold color="green" fontcolor="black" ]
- "rsc4_start_0 node1" -> "foo_running_0" [ style = bold]
- "rsc4_start_0 node1" -> "rsc5_start_0 node1" [ style = bold]
-@@ -48,6 +51,8 @@
- "rsc5_stop_0 node1" [ style=bold color="green" fontcolor="black" ]
- "rsc6_monitor_0 node2" -> "bar_stopped_0" [ style = bold]
- "rsc6_monitor_0 node2" -> "rsc6_start_0 node2" [ style = bold]
-+"rsc6_monitor_0 node2" -> "rsc7_stop_0 node1" [ style = bold]
-+"rsc6_monitor_0 node2" -> "rsc8_stop_0 node1" [ style = bold]
- "rsc6_monitor_0 node2" [ style=bold color="green" fontcolor="black" ]
- "rsc6_start_0 node2" -> "bar_running_0" [ style = bold]
- "rsc6_start_0 node2" -> "rsc7_start_0 node2" [ style = bold]
-@@ -58,6 +63,7 @@
- "rsc7_monitor_0 node2" -> "bar_stopped_0" [ style = bold]
- "rsc7_monitor_0 node2" -> "rsc6_stop_0 node1" [ style = bold]
- "rsc7_monitor_0 node2" -> "rsc7_start_0 node2" [ style = bold]
-+"rsc7_monitor_0 node2" -> "rsc8_stop_0 node1" [ style = bold]
- "rsc7_monitor_0 node2" [ style=bold color="green" fontcolor="black" ]
- "rsc7_start_0 node2" -> "bar_running_0" [ style = bold]
- "rsc7_start_0 node2" -> "rsc8_start_0 node2" [ style = bold]
-diff --git a/pengine/test10/group9.exp b/pengine/test10/group9.exp
-index f05c2c2..ac82825 100644
---- a/pengine/test10/group9.exp
-+++ b/pengine/test10/group9.exp
-@@ -128,6 +128,9 @@
-      </action_set>
-      <inputs>
-        <trigger>
-+        <rsc_op id="5" operation="monitor" operation_key="rsc3_monitor_0" on_node="node2" on_node_uuid="node2"/>
-+      </trigger>
-+      <trigger>
-         <rsc_op id="7" operation="monitor" operation_key="rsc5_monitor_0" on_node="node2" on_node_uuid="node2"/>
-       </trigger>
-       <trigger>
-@@ -169,6 +172,12 @@
-      </action_set>
-      <inputs>
-        <trigger>
-+        <rsc_op id="5" operation="monitor" operation_key="rsc3_monitor_0" on_node="node2" on_node_uuid="node2"/>
-+      </trigger>
-+      <trigger>
-+        <rsc_op id="6" operation="monitor" operation_key="rsc4_monitor_0" on_node="node2" on_node_uuid="node2"/>
-+      </trigger>
-+      <trigger>
-         <pseudo_event id="22" operation="stop" operation_key="foo_stop_0"/>
-        </trigger>
-      </inputs>
-@@ -340,6 +349,9 @@
-      </action_set>
-      <inputs>
-        <trigger>
-+        <rsc_op id="8" operation="monitor" operation_key="rsc6_monitor_0" on_node="node2" on_node_uuid="node2"/>
-+      </trigger>
-+      <trigger>
-         <rsc_op id="10" operation="monitor" operation_key="rsc8_monitor_0" on_node="node2" on_node_uuid="node2"/>
-       </trigger>
-       <trigger>
-@@ -381,6 +393,12 @@
-      </action_set>
-      <inputs>
-        <trigger>
-+        <rsc_op id="8" operation="monitor" operation_key="rsc6_monitor_0" on_node="node2" on_node_uuid="node2"/>
-+      </trigger>
-+      <trigger>
-+        <rsc_op id="9" operation="monitor" operation_key="rsc7_monitor_0" on_node="node2" on_node_uuid="node2"/>
-+      </trigger>
-+      <trigger>
-         <pseudo_event id="31" operation="stop" operation_key="bar_stop_0"/>
-        </trigger>
-      </inputs>
-diff --git a/pengine/test10/order6.dot b/pengine/test10/order6.dot
-index 74f1c5b..0dfd73f 100644
---- a/pengine/test10/order6.dot
-+++ b/pengine/test10/order6.dot
-@@ -1,4 +1,5 @@
-  digraph "g" {
-+"rsc1_monitor_0 node2" -> "rsc2_stop_0 node1" [ style = bold]
- "rsc1_monitor_0 node2" [ style=bold color="green" fontcolor="black" ]
- "rsc2_monitor_0 node2" -> "rsc2_start_0 node2" [ style = bold]
- "rsc2_monitor_0 node2" [ style=bold color="green" fontcolor="black" ]
-@@ -11,6 +12,7 @@
- "rsc4_start_0 node2" [ style=bold color="green" fontcolor="black" ]
- "rsc4_stop_0 node1" -> "rsc4_start_0 node2" [ style = bold]
- "rsc4_stop_0 node1" [ style=bold color="green" fontcolor="black" ]
-+"rsc5_monitor_0 node1" -> "rsc6_stop_0 node2" [ style = bold]
- "rsc5_monitor_0 node1" [ style=bold color="green" fontcolor="black" ]
- "rsc6_monitor_0 node1" -> "rsc6_start_0 node1" [ style = bold]
- "rsc6_monitor_0 node1" [ style=bold color="green" fontcolor="black" ]
-diff --git a/pengine/test10/order6.exp b/pengine/test10/order6.exp
-index 47dc227..c3d74e6 100644
---- a/pengine/test10/order6.exp
-+++ b/pengine/test10/order6.exp
-@@ -31,7 +31,11 @@
-         <attributes CRM_meta_on_node="node1" CRM_meta_on_node_uuid="uuid1" CRM_meta_timeout="20000" />
-        </rsc_op>
-      </action_set>
--    <inputs/>
-+    <inputs>
-+      <trigger>
-+        <rsc_op id="5" operation="monitor" operation_key="rsc1_monitor_0" on_node="node2" on_node_uuid="uuid2"/>
-+      </trigger>
-+    </inputs>
-    </synapse>
-    <synapse id="3">
-      <action_set>
-@@ -117,7 +121,11 @@
-         <attributes CRM_meta_on_node="node2" CRM_meta_on_node_uuid="uuid2" CRM_meta_timeout="20000" />
-        </rsc_op>
-      </action_set>
--    <inputs/>
-+    <inputs>
-+      <trigger>
-+        <rsc_op id="1" operation="monitor" operation_key="rsc5_monitor_0" on_node="node1" on_node_uuid="uuid1"/>
-+      </trigger>
-+    </inputs>
-    </synapse>
-   <synapse id="11">
-      <action_set>
-diff --git a/pengine/test10/reload-becomes-restart.dot b/pengine/test10/reload-becomes-restart.dot
-index a6616f9..36f8372 100644
---- a/pengine/test10/reload-becomes-restart.dot
-+++ b/pengine/test10/reload-becomes-restart.dot
-@@ -30,6 +30,7 @@ digraph "g" {
- "rsc1:0_start_0 node2" -> "rsc2:1_start_0 node2" [ style = bold]
- "rsc1:0_start_0 node2" [ style=bold color="green" fontcolor="black"]
- "rsc1:1_monitor_0 node1" -> "cl-rsc1_start_0" [ style = bold]
-+"rsc1:1_monitor_0 node1" -> "rsc2_stop_0 node1" [ style = bold]
- "rsc1:1_monitor_0 node1" [ style=bold color="green" fontcolor="black"]
- "rsc1:1_monitor_120000 node1" [ style=bold color="green" fontcolor="black"]
- "rsc1:1_start_0 node1" -> "cl-rsc1_running_0" [ style = bold]
-diff --git a/pengine/test10/reload-becomes-restart.exp b/pengine/test10/reload-becomes-restart.exp
-index c3e3721..224b8d2 100644
---- a/pengine/test10/reload-becomes-restart.exp
-+++ b/pengine/test10/reload-becomes-restart.exp
-@@ -177,6 +177,9 @@
-     </action_set>
-     <inputs>
-       <trigger>
-+        <rsc_op id="4" operation="monitor" operation_key="rsc1:1_monitor_0" on_node="node1" on_node_uuid="1"/>
-+      </trigger>
-+      <trigger>
-         <pseudo_event id="24" operation="stop" operation_key="cl-rsc2_stop_0"/>
-       </trigger>
-     </inputs>
--- 
-1.8.3.1
-
-
-From 95791c21987c82dd5c821569a7f029e876f9bed1 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Fri, 12 Jul 2019 11:08:23 -0500
-Subject: [PATCH 38/96] Test: CTS: update patterns for stonith probe change
-
-Since 343ae2a, ComponentFail tests that result in the fencer respawning (i.e.
-when the target is the fencer or the CIB) will return additional (expected)
-errors due to stonith probes (correctly) being considered failed.
----
- cts/CTStests.py |  8 ++++++--
- cts/patterns.py | 26 +++++++++++++++++++++++---
- 2 files changed, 29 insertions(+), 5 deletions(-)
-
-diff --git a/cts/CTStests.py b/cts/CTStests.py
-index b6cb31d..e30fe86 100644
---- a/cts/CTStests.py
-+++ b/cts/CTStests.py
-@@ -1422,14 +1422,18 @@ class ComponentFail(CTSTest):
-                 self.okerrpatterns.append(self.templates["Pat:ChildRespawn"] %(node, chosen.name))
-                 self.okerrpatterns.append(self.templates["Pat:ChildExit"])
- 
--        if chosen.name == "stonith":
--            # Ignore actions for STONITH resources
-+        # @TODO this should be a flag in the Component
-+        if chosen.name in [ "corosync", "cib", "stonith" ]:
-+            # Ignore actions for fence devices if fencer will respawn
-+            # (their registration will be lost, and probes will fail)
-             (rc, lines) = self.rsh(node, "crm_resource -c", None)
-             for line in lines:
-                 if re.search("^Resource", line):
-                     r = AuditResource(self.CM, line)
-                     if r.rclass == "stonith":
-                         self.okerrpatterns.append(self.templates["Pat:Fencing_recover"] % r.id)
-+                        self.okerrpatterns.append(self.templates["Pat:Fencing_active"] % r.id)
-+                        self.okerrpatterns.append(self.templates["Pat:Fencing_probe"] % r.id)
- 
-         # supply a copy so self.patterns doesn't end up empty
-         tmpPats = []
-diff --git a/cts/patterns.py b/cts/patterns.py
-index 00c26ff..0f9982e 100644
---- a/cts/patterns.py
-+++ b/cts/patterns.py
-@@ -59,9 +59,11 @@ class BasePatterns:
-             "Pat:They_dead"     : "node %s.*: is dead",
-             "Pat:TransitionComplete" : "Transition status: Complete: complete",
- 
--            "Pat:Fencing_start" : "(Initiating remote operation|Requesting peer fencing ).* (for|of) %s",
--            "Pat:Fencing_ok"    : r"stonith.*:\s*Operation .* of %s by .* for .*@.*: OK",
--            "Pat:Fencing_recover"    : r"pengine.*: Recover %s",
-+            "Pat:Fencing_start"   : r"(Initiating remote operation|Requesting peer fencing ).* (for|of) %s",
-+            "Pat:Fencing_ok"      : r"stonith.*:\s*Operation .* of %s by .* for .*@.*: OK",
-+            "Pat:Fencing_recover" : r"pengine.*: Recover %s",
-+            "Pat:Fencing_active"  : r"pengine.*: Resource %s is active on .* nodes",
-+            "Pat:Fencing_probe"   : r"crmd.*: Result of probe operation for %s on .*: Error",
- 
-             "Pat:RscOpOK"       : r"crmd.*:\s+Result of %s operation for %s.*: (0 \()?ok",
-             "Pat:RscRemoteOpOK" : r"crmd.*:\s+Result of %s operation for %s on %s: (0 \()?ok",
-@@ -299,6 +301,12 @@ class crm_cs_v0(BasePatterns):
-             r"error:.*STONITH connection failed",
-             r"error: Connection to stonith-ng.* (failed|closed)",
-             r"crit: Fencing daemon connection failed",
-+            # This is overbroad, but we don't have a way to say that only
-+            # certain transition errors are acceptable (if the fencer respawns,
-+            # fence devices may appear multiply active). We have to rely on
-+            # other causes of a transition error logging their own error
-+            # message, which is the usual practice.
-+            r"pengine.* Calculated transition .*/pe-error",
-             ]
- 
-         self.components["corosync"] = [
-@@ -316,6 +324,12 @@ class crm_cs_v0(BasePatterns):
-             "lrmd.*Connection to stonith-ng.* closed",
-             "lrmd.*LRMD lost STONITH connection",
-             "lrmd.*STONITH connection failed, finalizing .* pending operations",
-+            # This is overbroad, but we don't have a way to say that only
-+            # certain transition errors are acceptable (if the fencer respawns,
-+            # fence devices may appear multiply active). We have to rely on
-+            # other causes of a transition error logging their own error
-+            # message, which is the usual practice.
-+            r"pengine.* Calculated transition .*/pe-error",
-             ]
- 
-         self.components["cib"] = [
-@@ -387,6 +401,12 @@ class crm_cs_v0(BasePatterns):
-             r"error:.*Sign-in failed: triggered a retry",
-             "STONITH connection failed, finalizing .* pending operations.",
-             r"crmd.*:\s+Result of .* operation for Fencing.*Error",
-+            # This is overbroad, but we don't have a way to say that only
-+            # certain transition errors are acceptable (if the fencer respawns,
-+            # fence devices may appear multiply active). We have to rely on
-+            # other causes of a transition error logging their own error
-+            # message, which is the usual practice.
-+            r"pengine.* Calculated transition .*/pe-error",
-         ]
-         self.components["stonith-ignore"].extend(self.components["common-ignore"])
- 
--- 
-1.8.3.1
-
-
-From 49593689fbe40f02376f8d540c4cbd554f9e8e9f Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Tue, 16 Jul 2019 14:03:52 -0500
-Subject: [PATCH 39/96] Test: CTS: update execd ComponentFail ignore patterns
-
-attrd connects to execd for sending alerts, so connection failures for it are
-expected when killing execd
----
- cts/patterns.py | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/cts/patterns.py b/cts/patterns.py
-index 0f9982e..1e9f0e5 100644
---- a/cts/patterns.py
-+++ b/cts/patterns.py
-@@ -358,7 +358,9 @@ class crm_cs_v0(BasePatterns):
-                     r"crmd.*: Input I_TERMINATE .*from do_recover",
-                     "crmd.*Could not recover from internal error",
-                     ]
--        self.components["lrmd-ignore"] = []
-+        self.components["lrmd-ignore"] = [
-+            r"attrd.*Connection to lrmd (failed|closed)",
-+        ]
- 
-         self.components["crmd"] = [
- #                    "WARN: determine_online_status: Node .* is unclean",
--- 
-1.8.3.1
-
-
-From e9721446830e98f32be3082138c0a27ccbf6a452 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Tue, 23 Jul 2019 10:33:12 -0500
-Subject: [PATCH 40/96] Test: CTS: correct fencer connection pattern
-
-e2981df had a typo
----
- cts/patterns.py | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/cts/patterns.py b/cts/patterns.py
-index 1e9f0e5..cf1860a 100644
---- a/cts/patterns.py
-+++ b/cts/patterns.py
-@@ -392,7 +392,7 @@ class crm_cs_v0(BasePatterns):
-             "LRMD lost STONITH connection",
-             "Connection to stonith-ng.* closed",
-             "Fencing daemon connection failed",
--            r"crmd:.*Fencer successfully connected",
-+            r"crmd.*: Fencer successfully connected",
-         ]
-         self.components["stonith-ignore"] = [
-             r"pengine.*: Recover Fencing",
--- 
-1.8.3.1
-
-
-From 9fe68fdb8c1355e3436934eb5812af696de39dad Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Fri, 19 Jul 2019 18:49:21 -0500
-Subject: [PATCH 41/96] Fix: controller: panic local host if notified of own
- fencing
-
-Previously, we attempted to reboot, but that would always fail because the
-controller doesn't run as root, so it would fall back to exiting CRM_EX_FATAL.
-
-Now, we exit CRM_EX_PANIC, to tell pacemakerd to panic the local host, which
-is a better method of self-fencing.
-
-clbz#5386
----
- crmd/te_utils.c | 41 +++++++++++------------------------------
- 1 file changed, 11 insertions(+), 30 deletions(-)
-
-diff --git a/crmd/te_utils.c b/crmd/te_utils.c
-index 14570cd..6c7f9a0 100644
---- a/crmd/te_utils.c
-+++ b/crmd/te_utils.c
-@@ -235,11 +235,6 @@ tengine_stonith_connection_destroy(stonith_t * st, stonith_event_t * e)
- 
- char *te_client_id = NULL;
- 
--#ifdef HAVE_SYS_REBOOT_H
--#  include <unistd.h>
--#  include <sys/reboot.h>
--#endif
--
- static void
- tengine_stonith_history_synced(stonith_t *st, stonith_event_t *st_event);
- 
-@@ -271,33 +266,19 @@ tengine_stonith_notify(stonith_t * st, stonith_event_t * st_event)
-         return;
- 
-     } else if (st_event->result == pcmk_ok && crm_str_eq(st_event->target, fsa_our_uname, TRUE)) {
--        crm_crit("We were allegedly just fenced by %s for %s!",
--                 st_event->executioner ? st_event->executioner : "<anyone>", st_event->origin); /* Dumps blackbox if enabled */
--
--        qb_log_fini(); /* Try to get the above log message to disk - somehow */
--
--        /* Get out ASAP and do not come back up.
-+        /* We were notified of our own fencing. Most likely, either fencing was
-+         * misconfigured, or fabric fencing that doesn't cut cluster
-+         * communication is in use.
-          *
--         * Triggering a reboot is also not the worst idea either since
--         * the rest of the cluster thinks we're safely down
-+         * Either way, shutting down the local host is a good idea, to require
-+         * administrator intervention. Also, other nodes would otherwise likely
-+         * set our status to lost because of the fencing callback and discard
-+         * our subsequent election votes as "not part of our cluster".
-          */
--
--#ifdef RB_HALT_SYSTEM
--        reboot(RB_HALT_SYSTEM);
--#endif
--
--        /*
--         * If reboot() fails or is not supported, coming back up will
--         * probably lead to a situation where the other nodes set our
--         * status to 'lost' because of the fencing callback and will
--         * discard subsequent election votes with:
--         *
--         * Election 87 (current: 5171, owner: 103): Processed vote from east-03 (Peer is not part of our cluster)
--         *
--         * So just stay dead, something is seriously messed up anyway.
--         *
--         */
--        exit(100); /* None of our wrappers since we already called qb_log_fini() */
-+        crm_crit("We were allegedly just fenced by %s for %s!",
-+                 st_event->executioner? st_event->executioner : "the cluster",
-+                 st_event->origin); /* Dumps blackbox if enabled */
-+        pcmk_panic(__FUNCTION__);
-         return;
-     }
- 
--- 
-1.8.3.1
-
-
-From b7214e4b4229f4678e09a81f6afac15ef1690406 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Tue, 23 Jul 2019 13:49:33 -0500
-Subject: [PATCH 42/96] Low: executor: stonith probes should fail only if
- previously registered
-
-343ae2a4 made stonith probes return an error if the executor's fencer
-connection was lost. However this is broader than necessary; we only need
-errors to be returned for devices that were registered. Any that weren't
-registered can still be assumed to be not registered.
-
-There's a theoretical possibility that the fencer connection could somehow be
-severed and some other entity register a device between then and when the
-executor reconnects. But that is not a realistic scenario, whereas probing a
-fence device on a node where the fencer respawned sometime in the past is.
----
- lrmd/lrmd.c | 16 ++++++++++------
- 1 file changed, 10 insertions(+), 6 deletions(-)
-
-diff --git a/lrmd/lrmd.c b/lrmd/lrmd.c
-index 5d33324..2e8ea41 100644
---- a/lrmd/lrmd.c
-+++ b/lrmd/lrmd.c
-@@ -1085,13 +1085,17 @@ stonith_connection_failed(void)
-     g_hash_table_iter_init(&iter, rsc_list);
-     while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & rsc)) {
-         if (safe_str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH)) {
--            /* This will cause future probes to return PCMK_OCF_UNKNOWN_ERROR
--             * until the resource is stopped or started successfully. This is
--             * especially important if the controller also went away (possibly
--             * due to a cluster layer restart) and won't receive our client
--             * notification of any monitors finalized below.
-+            /* If we registered this fence device, we don't know whether the
-+             * fencer still has the registration or not. Cause future probes to
-+             * return PCMK_OCF_UNKNOWN_ERROR until the resource is stopped or
-+             * started successfully. This is especially important if the
-+             * controller also went away (possibly due to a cluster layer
-+             * restart) and won't receive our client notification of any
-+             * monitors finalized below.
-              */
--            rsc->st_probe_rc = pcmk_err_generic;
-+            if (rsc->st_probe_rc == pcmk_ok) {
-+                rsc->st_probe_rc = pcmk_err_generic;
-+            }
- 
-             if (rsc->active) {
-                 cmd_list = g_list_append(cmd_list, rsc->active);
--- 
-1.8.3.1
-
-
-From f392caf5dc9b26a0ba55474eb79e68c90baaca16 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Tue, 23 Jul 2019 14:25:32 -0500
-Subject: [PATCH 43/96] Feature: crmd: allow configurable reaction to local
- node fencing
-
-9fe68fd fixed a bug so that when the local node is notified of its own fencing,
-it correctly panics.
-
-However, some users may have been relying on the previous behavior. In
-particular, some users may configure fabric fencing because they don't
-want the node ever intentionally hard-powered off.
-
-This creates a new cluster property, fence-reaction, that controls the
-behavior ("stop" for the original behavior, "panic" for the more correct
-behavior). It defaults to "stop", to preserve the current behavior.
----
- crmd/control.c        | 10 ++++++++++
- crmd/te_utils.c       | 22 +++++++++++++++++++++-
- crmd/tengine.h        |  3 +++
- include/crm/msg_xml.h |  1 +
- 4 files changed, 35 insertions(+), 1 deletion(-)
-
-diff --git a/crmd/control.c b/crmd/control.c
-index 4b19114..32340ec 100644
---- a/crmd/control.c
-+++ b/crmd/control.c
-@@ -932,6 +932,14 @@ pe_cluster_option crmd_opts[] = {
-         },
- 	{ "node-action-limit", NULL, "integer", NULL, "0", &check_number,
-           "The maximum number of jobs that can be scheduled per node. Defaults to 2x cores"},
-+    { XML_CONFIG_ATTR_FENCE_REACTION, NULL, "string", NULL, "stop", NULL,
-+        "How a cluster node should react if notified of its own fencing",
-+        "A cluster node may receive notification of its own fencing if fencing "
-+        "is misconfigured, or if fabric fencing is in use that doesn't cut "
-+        "cluster communication. Allowed values are \"stop\" to attempt to "
-+        "immediately stop pacemaker and stay stopped, or \"panic\" to attempt "
-+        "to immediately reboot the local node, falling back to stop on failure."
-+    },
- 	{ XML_CONFIG_ATTR_ELECTION_FAIL, "election_timeout", "time", NULL, "2min", &check_timer,
-           "*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug."
-         },
-@@ -1053,6 +1061,8 @@ config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void
-         no_quorum_suicide_escalation = TRUE;
-     }
- 
-+    set_fence_reaction(crmd_pref(config_hash, XML_CONFIG_ATTR_FENCE_REACTION));
-+
-     value = crmd_pref(config_hash,"stonith-max-attempts");
-     update_stonith_max_attempts(value);
- 
-diff --git a/crmd/te_utils.c b/crmd/te_utils.c
-index 6c7f9a0..6052bc0 100644
---- a/crmd/te_utils.c
-+++ b/crmd/te_utils.c
-@@ -35,6 +35,7 @@ crm_trigger_t *stonith_reconnect = NULL;
- static crm_trigger_t *stonith_history_sync_trigger = NULL;
- static mainloop_timer_t *stonith_history_sync_timer_short = NULL;
- static mainloop_timer_t *stonith_history_sync_timer_long = NULL;
-+static bool fence_reaction_panic = FALSE;
- 
- void
- te_cleanup_stonith_history_sync(stonith_t *st, bool free_timers)
-@@ -54,6 +55,21 @@ te_cleanup_stonith_history_sync(stonith_t *st, bool free_timers)
-     }
- }
- 
-+void
-+set_fence_reaction(const char *reaction_s)
-+{
-+    if (safe_str_eq(reaction_s, "panic")) {
-+        fence_reaction_panic = TRUE;
-+
-+    } else {
-+        if (safe_str_neq(reaction_s, "stop")) {
-+            crm_warn("Invalid value '%s' for %s, using 'stop'",
-+                     reaction_s, XML_CONFIG_ATTR_FENCE_REACTION);
-+        }
-+        fence_reaction_panic = FALSE;
-+    }
-+}
-+
- static void
- tengine_stonith_history_synced(stonith_t *st, stonith_event_t *st_event)
- {
-@@ -278,7 +294,11 @@ tengine_stonith_notify(stonith_t * st, stonith_event_t * st_event)
-         crm_crit("We were allegedly just fenced by %s for %s!",
-                  st_event->executioner? st_event->executioner : "the cluster",
-                  st_event->origin); /* Dumps blackbox if enabled */
--        pcmk_panic(__FUNCTION__);
-+        if (fence_reaction_panic) {
-+            pcmk_panic(__FUNCTION__);
-+        } else {
-+            crm_exit(DAEMON_RESPAWN_STOP);
-+        }
-         return;
-     }
- 
-diff --git a/crmd/tengine.h b/crmd/tengine.h
-index a20760c..f5491a2 100644
---- a/crmd/tengine.h
-+++ b/crmd/tengine.h
-@@ -32,6 +32,9 @@ void remove_stonith_cleanup(const char *target);
- void purge_stonith_cleanup(void);
- void execute_stonith_cleanup(void);
- 
-+// reaction to notification of local node being fenced
-+void set_fence_reaction(const char *reaction_s);
-+
- /* tengine */
- extern crm_action_t *match_down_event(const char *target, bool quiet);
- extern crm_action_t *get_cancel_action(const char *id, const char *node);
-diff --git a/include/crm/msg_xml.h b/include/crm/msg_xml.h
-index 55f42c4..de99959 100644
---- a/include/crm/msg_xml.h
-+++ b/include/crm/msg_xml.h
-@@ -377,6 +377,7 @@
- #  define XML_CONFIG_ATTR_ELECTION_FAIL	"election-timeout"
- #  define XML_CONFIG_ATTR_FORCE_QUIT	"shutdown-escalation"
- #  define XML_CONFIG_ATTR_RECHECK	"cluster-recheck-interval"
-+#  define XML_CONFIG_ATTR_FENCE_REACTION	"fence-reaction"
- 
- #  define XML_ALERT_ATTR_PATH		"path"
- #  define XML_ALERT_ATTR_TIMEOUT	"timeout"
--- 
-1.8.3.1
-
-
-From 4fe2b0d9fac09a3228a558aaf5c1adadc7187217 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 25 Jul 2019 10:49:44 -0500
-Subject: [PATCH 44/96] Log: pacemakerd: backport pcmk_child_exit() log message
- changes
-
-... from 2.0's f7e5558, along with corresponding CTS changes, to make patching
-easier.
----
- cts/CM_lha.py   | 27 +++++++++++++--------------
- cts/patterns.py | 25 +++++++++++--------------
- mcp/pacemaker.c | 22 +++++++++++++---------
- 3 files changed, 37 insertions(+), 37 deletions(-)
-
-diff --git a/cts/CM_lha.py b/cts/CM_lha.py
-index 0ba4ba1..2f39063 100755
---- a/cts/CM_lha.py
-+++ b/cts/CM_lha.py
-@@ -377,9 +377,9 @@ class crm_lha(ClusterManager):
-                     "Exiting to recover from CCM connection failure",
-                     r"crmd.*: Could not recover from internal error",
-                     "crmd.*I_ERROR.*(ccm_dispatch|crmd_cib_connection_destroy)",
--                    "crmd.*exited with return code 2.",
--                    "attrd.*exited with return code 1.",
--                    "cib.*exited with return code 2.",
-+                    "crmd.*exited with status 2",
-+                    "attrd.*exited with status 1",
-+                    "cib.*exited with status 2",
- 
- # Not if it was fenced
- #                    "A new node joined the cluster",
-@@ -400,8 +400,8 @@ class crm_lha(ClusterManager):
-                     r"crmd.*: Input I_TERMINATE .*from do_recover",
-                     "crmd.*I_ERROR.*crmd_cib_connection_destroy",
-                     r"crmd.*: Could not recover from internal error",
--                    "crmd.*exited with return code 2.",
--                    "attrd.*exited with return code 1.",
-+                    "crmd.*exited with status 2",
-+                    "attrd.*exited with status 1",
-                     ], badnews_ignore = common_ignore)
- 
-         lrmd = Process(self, "lrmd", triggersreboot=self.fastfail, pats = [
-@@ -411,7 +411,7 @@ class crm_lha(ClusterManager):
-                     "State transition S_STARTING -> S_PENDING",
-                     r"crmd.*: Input I_TERMINATE .*from do_recover",
-                     r"crmd.*: Could not recover from internal error",
--                    "crmd.*exited with return code 2.",
-+                    "crmd.*exited with status 2",
-                     ], badnews_ignore = common_ignore)
- 
-         crmd = Process(self, "crmd", triggersreboot=self.fastfail, pats = [
-@@ -425,12 +425,11 @@ class crm_lha(ClusterManager):
- 
-         pengine = Process(self, "pengine", triggersreboot=self.fastfail, pats = [
-                     "State transition .* S_RECOVERY",
--                    "crmd.*exited with return code 2.",
-                     r"crmd.*: Input I_TERMINATE .*from do_recover",
-                     r"crmd.*: Could not recover from internal error",
-                     r"crmd.*CRIT.*: Connection to the Policy Engine failed",
-                     "crmd.*I_ERROR.*save_cib_contents",
--                    "crmd.*exited with return code 2.",
-+                    "crmd.*exited with status 2",
-                     ], badnews_ignore = common_ignore, dc_only=1)
- 
-         if self.Env["DoFencing"] == 1 :
-@@ -441,21 +440,21 @@ class crm_lha(ClusterManager):
- 
-         if self.fastfail == 0:
-             ccm.pats.extend([
--                "attrd .* exited with return code 1",
-+                "attrd .* exited with status 1",
-                 "(ERROR|error): Respawning client .*attrd",
--                "cib.* exited with return code 2",
-+                "cib.* exited with status 2",
-                 "(ERROR|error): Respawning client .*cib",
--                "crmd.* exited with return code 2",
-+                "crmd.* exited with status 2",
-                 "(ERROR|error): Respawning client .*crmd" 
-                 ])
-             cib.pats.extend([
--                "attrd.* exited with return code 1",
-+                "attrd.* exited with status 1",
-                 "(ERROR|error): Respawning client .*attrd",
--                "crmd.* exited with return code 2",
-+                "crmd.* exited with status 2",
-                 "(ERROR|error): Respawning client .*crmd" 
-                 ])
-             lrmd.pats.extend([
--                "crmd.* exited with return code 2",
-+                "crmd.* exited with status 2",
-                 "(ERROR|error): Respawning client .*crmd" 
-                 ])
-             pengine.pats.extend([
-diff --git a/cts/patterns.py b/cts/patterns.py
-index cf1860a..c7f0035 100644
---- a/cts/patterns.py
-+++ b/cts/patterns.py
-@@ -130,7 +130,7 @@ class crm_lha(BasePatterns):
-                 r"input=I_INTEGRATED cause=C_TIMER_POPPED",
-                 r"input=I_FINALIZED cause=C_TIMER_POPPED",
-                 r"input=I_ERROR",
--                r", exiting\.",
-+                r"(pacemakerd|lrmd|crmd):.*, exiting",
-                 r"WARN.*Ignoring HA message.*vote.*not in our membership list",
-                 r"pengine.*Attempting recovery of resource",
-                 r"is taking more than 2x its timeout",
-@@ -210,7 +210,7 @@ class crm_cs_v0(BasePatterns):
-             r"input=I_INTEGRATED cause=C_TIMER_POPPED",
-             r"input=I_FINALIZED cause=C_TIMER_POPPED",
-             r"input=I_ERROR",
--            r", exiting\.",
-+            r"(pacemakerd|lrmd|crmd):.*, exiting",
-             r"(WARN|warn).*Ignoring HA message.*vote.*not in our membership list",
-             r"pengine.*Attempting recovery of resource",
-             r"is taking more than 2x its timeout",
-@@ -224,7 +224,7 @@ class crm_cs_v0(BasePatterns):
-             r"Faking parameter digest creation",
-             r"Parameters to .* action changed:",
-             r"Parameters to .* changed",
--            r"The .* process .* terminated with signal",
-+            r"\[[0-9]+\] terminated with signal [0-9]+ \(",
-             r"Child process .* terminated with signal",
-             r"pengine:.*Recover .*\(.* -\> .*\)",
-             r"rsyslogd.* imuxsock lost .* messages from pid .* due to rate-limiting",
-@@ -281,13 +281,10 @@ class crm_cs_v0(BasePatterns):
-         
-         self.components["corosync-ignore"] = [
-             r"error:.*Connection to the CPG API failed: Library error",
--            r"The .* process .* exited",
-+            r"\[[0-9]+\] exited with status [0-9]+ \(",
-             r"pacemakerd.*error:.*Child process .* exited",
-             r"cib.*error:.*Corosync connection lost",
-             r"stonith-ng.*error:.*Corosync connection terminated",
--            r"The cib process .* exited: Invalid argument",
--            r"The attrd process .* exited: Transport endpoint is not connected",
--            r"The crmd process .* exited: Link has been severed",
-             r"error:.*Child process cib .* exited: Invalid argument",
-             r"error:.*Child process attrd .* exited: Transport endpoint is not connected",
-             r"error:.*Child process crmd .* exited: Link has been severed",
-@@ -340,8 +337,8 @@ class crm_cs_v0(BasePatterns):
-                     "Connection to cib_.* closed",
-                     r"crmd.*:.*Connection to the CIB terminated...",
-                     r"attrd.*:.*(Lost connection to CIB service|Connection to the CIB terminated)",
--                    "(Child process|The) crmd .* exited: Generic Pacemaker error",
--                    "(Child process|The) attrd .* exited: (Connection reset by peer|Transport endpoint is not connected)",
-+                    r"crmd\[[0-9]+\] exited with status 2",
-+                    r"attrd\[[0-9]+\] exited with status 1",
-                     r"crmd.*: Input I_TERMINATE .*from do_recover",
-                     "crmd.*I_ERROR.*crmd_cib_connection_destroy",
-                     "crmd.*Could not recover from internal error",
-@@ -354,7 +351,7 @@ class crm_cs_v0(BasePatterns):
-                     "Connection to lrmd failed",
-                     "Connection to lrmd.* closed",
-                     "crmd.*I_ERROR.*lrm_connection_destroy",
--                    "(Child process|The) crmd .* exited: Generic Pacemaker error",
-+                    r"crmd\[[0-9]+\] exited with status 2",
-                     r"crmd.*: Input I_TERMINATE .*from do_recover",
-                     "crmd.*Could not recover from internal error",
-                     ]
-@@ -377,7 +374,7 @@ class crm_cs_v0(BasePatterns):
-         self.components["pengine"] = [
-                     "State transition .* S_RECOVERY",
-                     "Respawning .* crmd",
--                    "(The|Child process) crmd .* exited: Generic Pacemaker error",
-+                    r"crmd\[[0-9]+\] exited with status 2",
-                     "Connection to pengine failed",
-                     "Connection to pengine.* closed",
-                     "Connection to the Policy Engine failed",
-@@ -437,8 +434,8 @@ class crm_mcp(crm_cs_v0):
-             "Pat:They_stopped" : "%s\W.*crmd.*Node %s(\[|\s).*state is now lost",
-             "Pat:They_dead"    : "crmd.*Node %s(\[|\s).*state is now lost",
- 
--            "Pat:ChildExit"    : "The .* process exited",
--            "Pat:ChildKilled"  : "%s\W.*pacemakerd.*The %s process .* terminated with signal 9",
-+            "Pat:ChildExit"    : r"\[[0-9]+\] exited with status [0-9]+ \(",
-+            "Pat:ChildKilled"  : r"%s\W.*pacemakerd.*%s\[[0-9]+\] terminated with signal 9",
-             "Pat:ChildRespawn" : "%s\W.*pacemakerd.*Respawning failed child process: %s",
- 
-             "Pat:PacemakerUp"  : "%s\W.*pacemakerd.*Starting Pacemaker",
-@@ -487,7 +484,7 @@ class crm_cman(crm_cs_v0):
-             "Pat:They_stopped" : "%s\W.*crmd.*Node %s(\[|\s).*state is now lost",
-             "Pat:They_dead"    : "crmd.*Node %s(\[|\s).*state is now lost",
- 
--            "Pat:ChildKilled"  : "%s\W.*pacemakerd.*The %s process .* terminated with signal 9",
-+            "Pat:ChildKilled"  : r"%s\W.*pacemakerd.*%s\[[0-9]+\] terminated with signal 9",
-             "Pat:ChildRespawn" : "%s\W.*pacemakerd.*Respawning failed child process: %s",
- 
-             "Pat:PacemakerUp"  : "%s\W.*pacemakerd.*Starting Pacemaker",
-diff --git a/mcp/pacemaker.c b/mcp/pacemaker.c
-index 86df216..6a67b59 100644
---- a/mcp/pacemaker.c
-+++ b/mcp/pacemaker.c
-@@ -217,27 +217,30 @@ pcmk_child_exit(mainloop_child_t * p, pid_t pid, int core, int signo, int exitco
-     pcmk_child_t *child = mainloop_child_userdata(p);
-     const char *name = mainloop_child_name(p);
- 
--    if (signo && signo == SIGKILL) {
--        crm_warn("The %s process (%d) terminated with signal %d (core=%d)", name, pid, signo, core);
--
--    } else if (signo) {
--        crm_err("The %s process (%d) terminated with signal %d (core=%d)", name, pid, signo, core);
-+    if (signo) {
-+        do_crm_log(((signo == SIGKILL)? LOG_WARNING : LOG_ERR),
-+                   "%s[%d] terminated with signal %d (core=%d)",
-+                   name, pid, signo, core);
- 
-     } else {
-         switch(exitcode) {
-             case pcmk_ok:
--                crm_info("The %s process (%d) exited: %s (%d)", name, pid, pcmk_strerror(exitcode), exitcode);
-+                crm_info("%s[%d] exited with status %d (%s)",
-+                         name, pid, exitcode, pcmk_strerror(exitcode));
-                 break;
- 
-             case DAEMON_RESPAWN_STOP:
--                crm_warn("The %s process (%d) can no longer be respawned, shutting the cluster down.", name, pid);
-+                crm_warn("Shutting cluster down because %s[%d] had fatal failure",
-+                         name, pid);
-                 child->respawn = FALSE;
-                 fatal_error = TRUE;
-                 pcmk_shutdown(SIGTERM);
-                 break;
- 
-             case pcmk_err_panic:
--                do_crm_log_always(LOG_EMERG, "The %s process (%d) instructed the machine to reset", name, pid);
-+                do_crm_log_always(LOG_EMERG,
-+                                  "%s[%d] instructed the machine to reset",
-+                                  name, pid);
-                 child->respawn = FALSE;
-                 fatal_error = TRUE;
-                 pcmk_panic(__FUNCTION__);
-@@ -245,7 +248,8 @@ pcmk_child_exit(mainloop_child_t * p, pid_t pid, int core, int signo, int exitco
-                 break;
- 
-             default:
--                crm_err("The %s process (%d) exited: %s (%d)", name, pid, pcmk_strerror(exitcode), exitcode);
-+                crm_err("%s[%d] exited with status %d (%s)",
-+                        name, pid, exitcode, pcmk_strerror(exitcode));
-                 break;
-         }
-     }
--- 
-1.8.3.1
-
-
-From 2cc1d945e53ea8a8bae38b1d8fe36b78c731bef0 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 25 Jul 2019 10:00:14 -0500
-Subject: [PATCH 45/96] Log: pacemakerd: make daemon exit detection messages
- more consistent
-
-Lost daemons may be detected via pcmk_child_exit() if the current pacemakerd
-launched the daemon, or check_active_before_startup_processes() if a previous
-pacemakerd launched it.
-
-Update the log messages in these cases to be more consistent, and update CTS
-to detect exit via either path.
----
- cts/patterns.py | 10 ++++++----
- mcp/pacemaker.c | 15 +++++----------
- 2 files changed, 11 insertions(+), 14 deletions(-)
-
-diff --git a/cts/patterns.py b/cts/patterns.py
-index c7f0035..e50daae 100644
---- a/cts/patterns.py
-+++ b/cts/patterns.py
-@@ -224,9 +224,9 @@ class crm_cs_v0(BasePatterns):
-             r"Faking parameter digest creation",
-             r"Parameters to .* action changed:",
-             r"Parameters to .* changed",
--            r"\[[0-9]+\] terminated with signal [0-9]+ \(",
-+            r"pacemakerd.*\[[0-9]+\] terminated( with signal| as IPC server|$)",
-             r"Child process .* terminated with signal",
--            r"pengine:.*Recover .*\(.* -\> .*\)",
-+            r"pengine.*Recover .*\(.* -\> .*\)",
-             r"rsyslogd.* imuxsock lost .* messages from pid .* due to rate-limiting",
-             r"Peer is not part of our cluster",
-             r"We appear to be in an election loop",
-@@ -435,7 +435,8 @@ class crm_mcp(crm_cs_v0):
-             "Pat:They_dead"    : "crmd.*Node %s(\[|\s).*state is now lost",
- 
-             "Pat:ChildExit"    : r"\[[0-9]+\] exited with status [0-9]+ \(",
--            "Pat:ChildKilled"  : r"%s\W.*pacemakerd.*%s\[[0-9]+\] terminated with signal 9",
-+            # "with signal 9" == pcmk_child_exit(), "$" == check_active_before_startup_processes()
-+            "Pat:ChildKilled"  : r"%s\W.*pacemakerd.*%s\[[0-9]+\] terminated( with signal 9|$)",
-             "Pat:ChildRespawn" : "%s\W.*pacemakerd.*Respawning failed child process: %s",
- 
-             "Pat:PacemakerUp"  : "%s\W.*pacemakerd.*Starting Pacemaker",
-@@ -484,7 +485,8 @@ class crm_cman(crm_cs_v0):
-             "Pat:They_stopped" : "%s\W.*crmd.*Node %s(\[|\s).*state is now lost",
-             "Pat:They_dead"    : "crmd.*Node %s(\[|\s).*state is now lost",
- 
--            "Pat:ChildKilled"  : r"%s\W.*pacemakerd.*%s\[[0-9]+\] terminated with signal 9",
-+            # "with signal 9" == pcmk_child_exit(), "$" == check_active_before_startup_processes()
-+            "Pat:ChildKilled"  : r"%s\W.*pacemakerd.*%s\[[0-9]+\] terminated( with signal 9|$)",
-             "Pat:ChildRespawn" : "%s\W.*pacemakerd.*Respawning failed child process: %s",
- 
-             "Pat:PacemakerUp"  : "%s\W.*pacemakerd.*Starting Pacemaker",
-diff --git a/mcp/pacemaker.c b/mcp/pacemaker.c
-index 6a67b59..1cc72af 100644
---- a/mcp/pacemaker.c
-+++ b/mcp/pacemaker.c
-@@ -897,19 +897,14 @@ check_active_before_startup_processes(gpointer user_data)
-                     case 0:
-                     case 2:  /* this very case: it was OK once already */
-                         if (pcmk_children[lpc].respawn == TRUE) {
--                            /* presumably after crash, hence critical */
--                            crm_crit("Process %s terminated (pid=%lld)%s", \
--                                     name, (long long)
--                                     PCMK__SPECIAL_PID_AS_0(pcmk_children[lpc].pid),
--                                     ret ? ", at least per IPC end-point that went AWOL"
--                                         : "");
-+                            crm_err("%s[%d] terminated%s", name,
-+                                    PCMK__SPECIAL_PID_AS_0(pcmk_children[lpc].pid),
-+                                    ret ? " as IPC server" : "");
-                         } else {
-                             /* orderly shutdown */
--                            crm_notice("Process %s terminated (pid=%lld)%s", \
--                                       name, (long long)
-+                            crm_notice("%s[%d] terminated%s", name,
-                                        PCMK__SPECIAL_PID_AS_0(pcmk_children[lpc].pid),
--                                       ret ? ", at least per IPC end-point that went AWOL"
--                                           : "");
-+                                       ret ? " as IPC server" : "");
-                         }
-                         pcmk_process_exit(&(pcmk_children[lpc]));
-                         continue;
--- 
-1.8.3.1
-
-
-From ab09f0afd0d383da60411c6a719830f415e6102a Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 25 Jul 2019 11:20:04 -0500
-Subject: [PATCH 46/96] Test: CTS: alert failures are expected when executor is
- killed
-
----
- cts/patterns.py | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/cts/patterns.py b/cts/patterns.py
-index e50daae..87418d4 100644
---- a/cts/patterns.py
-+++ b/cts/patterns.py
-@@ -357,6 +357,7 @@ class crm_cs_v0(BasePatterns):
-                     ]
-         self.components["lrmd-ignore"] = [
-             r"attrd.*Connection to lrmd (failed|closed)",
-+            r"(attrd|controld).*Could not execute alert",
-         ]
- 
-         self.components["crmd"] = [
--- 
-1.8.3.1
-
-
-From 0654ed94b44930cd2762cad361ee19b229b6bd38 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Wed, 24 Jul 2019 12:06:21 -0500
-Subject: [PATCH 47/96] Doc: controller: document the cluster-name cluster
- property
-
----
- crmd/control.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
-diff --git a/crmd/control.c b/crmd/control.c
-index 32340ec..cd4223f 100644
---- a/crmd/control.c
-+++ b/crmd/control.c
-@@ -897,6 +897,13 @@ pe_cluster_option crmd_opts[] = {
- 	{ "cluster-infrastructure", NULL, "string", NULL, "heartbeat", NULL,
-           "The messaging stack on which Pacemaker is currently running.",
-           "Used for informational and diagnostic purposes." },
-+    { "cluster-name", NULL, "string", NULL, NULL, NULL,
-+        "An arbitrary name for the cluster",
-+        "This optional value is mostly for users' convenience as desired "
-+        "in administration, but may also be used in Pacemaker configuration "
-+        "rules via the #cluster-name node attribute, and by higher-level tools "
-+        "and resource agents."
-+    },
- 	{ XML_CONFIG_ATTR_DC_DEADTIME, "dc_deadtime", "time", NULL, "20s", &check_time,
-           "How long to wait for a response from other nodes during startup.",
-           "The \"correct\" value will depend on the speed/load of your network and the type of switches used."
--- 
-1.8.3.1
-
-
-From 065fabee559a62a400709957f514f33150a91442 Mon Sep 17 00:00:00 2001
-From: aleksei-burlakov <aleksei.burlakov@suse.com>
-Date: Fri, 17 May 2019 18:13:01 +0200
-Subject: [PATCH 48/96] Low: stonith_admin --help: specify the usage of
- --cleanup
-
----
- fencing/admin.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/fencing/admin.c b/fencing/admin.c
-index 8aef093..7da43e9 100644
---- a/fencing/admin.c
-+++ b/fencing/admin.c
-@@ -58,7 +58,7 @@ static struct crm_option long_options[] = {
-         "\tBe less descriptive in output."
-     },
-     {   "cleanup", no_argument, NULL, 'c',
--        "\tCleanup wherever appropriate."
-+        "\tCleanup wherever appropriate. Requires: --history."
-     },
-     {   "broadcast", no_argument, NULL, 'b',
-         "Broadcast wherever appropriate."
--- 
-1.8.3.1
-
-
-From a87da1dc8512e210e892332326684aad60ec7ee0 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 15 Aug 2019 13:48:28 -0500
-Subject: [PATCH 49/96] Test: cts: check correct variable in bandwidth test
-
-found by static analysis (backport of 3b9dc32e from master branch)
----
- cts/CTStests.py | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/cts/CTStests.py b/cts/CTStests.py
-index e30fe86..f328170 100644
---- a/cts/CTStests.py
-+++ b/cts/CTStests.py
-@@ -1051,7 +1051,7 @@ class BandwidthTest(CTSTest):
-                 linessplit = string.split(line," ")
-                 for j in range(len(linessplit)-1):
-                     if linessplit[j] == "udp": break
--                    if linesplit[j] == "length:": break
-+                    if linessplit[j] == "length:": break
-                 try:
-                     sum = int(linessplit[j+1]) + sum
-                 except ValueError:
--- 
-1.8.3.1
-
-
-From 719c34f4b2da87970058326cb14d8488f10f90f5 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Mon, 17 Jun 2019 20:30:19 -0500
-Subject: [PATCH 50/96] Refactor: libcrmcommon: functionize freeing an XML
- subtree
-
-... to reduce code duplication, and draw a distinction between this and freeing
-the entire XML document the element is in (which free_xml() does).
----
- include/crm/common/xml.h |  1 +
- lib/common/acl.c         |  7 ++++---
- lib/common/xml.c         | 22 ++++++++++++++--------
- 3 files changed, 19 insertions(+), 11 deletions(-)
-
-diff --git a/include/crm/common/xml.h b/include/crm/common/xml.h
-index 11a03f4..a9af963 100644
---- a/include/crm/common/xml.h
-+++ b/include/crm/common/xml.h
-@@ -271,6 +271,7 @@ __xml_next_element(xmlNode * child)
-     return NULL;
- }
- 
-+void pcmk_free_xml_subtree(xmlNode *xml);
- void free_xml(xmlNode * child);
- 
- xmlNode *first_named_child(xmlNode * parent, const char *name);
-diff --git a/lib/common/acl.c b/lib/common/acl.c
-index 80b1f6f..30adad8 100644
---- a/lib/common/acl.c
-+++ b/lib/common/acl.c
-@@ -1,5 +1,7 @@
- /*
-- * Copyright 2004-2018 Andrew Beekhof <andrew@beekhof.net>
-+ * Copyright 2004-2019 the Pacemaker project contributors
-+ *
-+ * The version control history for this file may have further details.
-  *
-  * This source code is licensed under the GNU Lesser General Public License
-  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
-@@ -501,8 +503,7 @@ pcmk__post_process_acl(xmlNode *xml)
-                           crm_element_name(xml), path);
- 
-                 if (xml != xmlDocGetRootElement(xml->doc)) {
--                    xmlUnlinkNode(xml);
--                    xmlFreeNode(xml);
-+                    pcmk_free_xml_subtree(xml);
-                 }
-                 free(path);
-                 return;
-diff --git a/lib/common/xml.c b/lib/common/xml.c
-index 91c0edb..dfa2d77 100644
---- a/lib/common/xml.c
-+++ b/lib/common/xml.c
-@@ -2021,6 +2021,18 @@ xml_get_path(xmlNode *xml)
-     return NULL;
- }
- 
-+/*!
-+ * Free an XML element and all of its children, removing it from its parent
-+ *
-+ * \param[in] xml  XML element to free
-+ */
-+void
-+pcmk_free_xml_subtree(xmlNode *xml)
-+{
-+    xmlUnlinkNode(xml); // Detaches from parent and siblings
-+    xmlFreeNode(xml);   // Frees
-+}
-+
- static void
- free_xml_with_position(xmlNode * child, int position)
- {
-@@ -2075,12 +2087,7 @@ free_xml_with_position(xmlNode * child, int position)
-                     pcmk__set_xml_flag(child, xpf_dirty);
-                 }
-             }
--
--            /* Free this particular subtree
--             * Make sure to unlink it from the parent first
--             */
--            xmlUnlinkNode(child);
--            xmlFreeNode(child);
-+            pcmk_free_xml_subtree(child);
-         }
-     }
- }
-@@ -2296,8 +2303,7 @@ strip_text_nodes(xmlNode * xml)
-         switch (iter->type) {
-             case XML_TEXT_NODE:
-                 /* Remove it */
--                xmlUnlinkNode(iter);
--                xmlFreeNode(iter);
-+                pcmk_free_xml_subtree(iter);
-                 break;
- 
-             case XML_ELEMENT_NODE:
--- 
-1.8.3.1
-
-
-From 310459de07dc6b3bb6e5a851fff1f25559caee2e Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Mon, 17 Jun 2019 21:08:57 -0500
-Subject: [PATCH 51/96] Refactor: libcrmcommon: make ACL creation checks more
- efficient
-
-This does the simplest checks first, avoids doing the same check repeatedly,
-and doesn't gather information unless needed.
-
-Trace log messages are also improved, and the regression tests updated to
-match.
----
- lib/common/acl.c | 76 +++++++++++++++++++++++++++++++++++---------------------
- 1 file changed, 48 insertions(+), 28 deletions(-)
-
-diff --git a/lib/common/acl.c b/lib/common/acl.c
-index 30adad8..dea67cf 100644
---- a/lib/common/acl.c
-+++ b/lib/common/acl.c
-@@ -471,6 +471,41 @@ xml_acl_filtered_copy(const char *user, xmlNode *acl_source, xmlNode *xml,
-     return TRUE;
- }
- 
-+/*!
-+ * \internal
-+ * \brief Check whether creation of an XML element is implicitly allowed
-+ *
-+ * Check whether XML is a "scaffolding" element whose creation is implicitly
-+ * allowed regardless of ACLs (that is, it is not in the ACL section and has
-+ * no attributes other than "id").
-+ *
-+ * \param[in] xml  XML element to check
-+ *
-+ * \return TRUE if XML element is implicitly allowed, FALSE otherwise
-+ */
-+static bool
-+implicitly_allowed(xmlNode *xml)
-+{
-+    char *path = NULL;
-+
-+    for (xmlAttr *prop = xml->properties; prop != NULL; prop = prop->next) {
-+        if (strcmp((const char *) prop->name, XML_ATTR_ID) != 0) {
-+            return FALSE;
-+        }
-+    }
-+
-+    path = xml_get_path(xml);
-+    if (strstr(path, "/" XML_CIB_TAG_ACLS "/") != NULL) {
-+        free(path);
-+        return FALSE;
-+    }
-+    free(path);
-+
-+    return TRUE;
-+}
-+
-+#define display_id(xml) (ID(xml)? ID(xml) : "<unset>")
-+
- void
- pcmk__post_process_acl(xmlNode *xml)
- {
-@@ -478,38 +513,23 @@ pcmk__post_process_acl(xmlNode *xml)
-     xml_private_t *p = xml->_private;
- 
-     if (is_set(p->flags, xpf_created)) {
--        xmlAttr *xIter = NULL;
--        char *path = xml_get_path(xml);
-+        if (implicitly_allowed(xml)) {
-+            crm_trace("Creation of <%s> scaffolding with id=\"%s\""
-+                      " is implicitly allowed",
-+                      crm_element_name(xml), display_id(xml));
- 
--        /* Always allow new scaffolding (e.g. node with no attributes or only an
--         * 'id'), except in the ACLs section
--         */
--
--        for (xIter = xml->properties; xIter != NULL; xIter = xIter->next) {
--            const char *prop_name = (const char *)xIter->name;
--
--            if (!strcmp(prop_name, XML_ATTR_ID)
--                && !strstr(path, "/"XML_CIB_TAG_ACLS"/")) {
--                /* Delay the acl check */
--                continue;
-+        } else if (pcmk__check_acl(xml, NULL, xpf_acl_write)) {
-+            crm_trace("ACLs allow creation of <%s> with id=\"%s\"",
-+                      crm_element_name(xml), display_id(xml));
- 
--            } else if (pcmk__check_acl(xml, NULL, xpf_acl_write)) {
--                crm_trace("Creation of %s=%s is allowed",
--                          crm_element_name(xml), ID(xml));
--                break;
--
--            } else {
--                crm_trace("Cannot add new node %s at %s",
--                          crm_element_name(xml), path);
--
--                if (xml != xmlDocGetRootElement(xml->doc)) {
--                    pcmk_free_xml_subtree(xml);
--                }
--                free(path);
--                return;
-+        } else {
-+            crm_trace("ACLs disallow creation of <%s> with id=\"%s\"",
-+                      crm_element_name(xml), display_id(xml));
-+            if (xml != xmlDocGetRootElement(xml->doc)) {
-+                pcmk_free_xml_subtree(xml);
-             }
-+            return;
-         }
--        free(path);
-     }
- 
-     while (cIter != NULL) {
--- 
-1.8.3.1
-
-
-From fec0a2a12b099a14b7db9397fdba08d5b6c22456 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 15 Aug 2019 14:00:48 -0500
-Subject: [PATCH 52/96] Test: tools: update regression tests for ACL trace
- message changes
-
----
- tools/regression.acls.exp | 70 +++++++++++++++++++++++++----------------------
- 1 file changed, 37 insertions(+), 33 deletions(-)
-
-diff --git a/tools/regression.acls.exp b/tools/regression.acls.exp
-index 6bc6062..6508b2c 100644
---- a/tools/regression.acls.exp
-+++ b/tools/regression.acls.exp
-@@ -257,6 +257,7 @@ Error performing operation: Permission denied
- (       acl.c:NNN   )   trace: pcmk__check_acl:	Ordinary user unknownguy cannot access the CIB without any defined ACLs
- (       acl.c:NNN   )   trace: pcmk__check_acl:	Ordinary user unknownguy cannot access the CIB without any defined ACLs
- (       acl.c:NNN   )   trace: pcmk__check_acl:	Ordinary user unknownguy cannot access the CIB without any defined ACLs
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of <primitive> scaffolding with id="<unset>" is implicitly allowed
- Call failed: Permission denied
- =#=#=#= End test: unknownguy: Create a resource - Permission denied (13) =#=#=#=
- * Passed: cibadmin       - unknownguy: Create a resource
-@@ -274,7 +275,7 @@ Error performing operation: Permission denied
- * Passed: crm_attribute  - l33t-haxor: Set stonith-enabled
- =#=#=#= Begin test: l33t-haxor: Create a resource =#=#=#=
- (       acl.c:NNN   )   trace: pcmk__check_acl:	400 access denied to /cib/configuration/resources/primitive[@id='dummy']: parent
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Cannot add new node primitive at /cib/configuration/resources/primitive[@id='dummy']
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs disallow creation of <primitive> with id="dummy"
- Call failed: Permission denied
- =#=#=#= End test: l33t-haxor: Create a resource - Permission denied (13) =#=#=#=
- * Passed: cibadmin       - l33t-haxor: Create a resource
-@@ -329,7 +330,7 @@ Error setting enable-acl=false (section=crm_config, set=<null>): Permission deni
- =#=#=#= End test: niceguy: Set enable-acl - Permission denied (13) =#=#=#=
- * Passed: crm_attribute  - niceguy: Set enable-acl
- =#=#=#= Begin test: niceguy: Set stonith-enabled =#=#=#=
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of nvpair=cib-bootstrap-options-stonith-enabled is allowed
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <nvpair> with id="cib-bootstrap-options-stonith-enabled"
- =#=#=#= Current cib after: niceguy: Set stonith-enabled =#=#=#=
- <cib epoch="7" num_updates="0" admin_epoch="0">
-   <configuration>
-@@ -377,7 +378,7 @@ Error setting enable-acl=false (section=crm_config, set=<null>): Permission deni
- * Passed: crm_attribute  - niceguy: Set stonith-enabled
- =#=#=#= Begin test: niceguy: Create a resource =#=#=#=
- (       acl.c:NNN   )   trace: pcmk__check_acl:	400 access denied to /cib/configuration/resources/primitive[@id='dummy']: default
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Cannot add new node primitive at /cib/configuration/resources/primitive[@id='dummy']
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs disallow creation of <primitive> with id="dummy"
- Call failed: Permission denied
- =#=#=#= End test: niceguy: Create a resource - Permission denied (13) =#=#=#=
- * Passed: cibadmin       - niceguy: Create a resource
-@@ -536,7 +537,8 @@ Error performing operation: Permission denied
- error: unpack_resources:	Resource start-up disabled since no STONITH resources have been defined
- error: unpack_resources:	Either configure some or disable STONITH with the stonith-enabled option
- error: unpack_resources:	NOTE: Clusters with shared data need STONITH to ensure data integrity
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of nvpair=dummy-meta_attributes-target-role is allowed
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of <meta_attributes> scaffolding with id="dummy-meta_attributes" is implicitly allowed
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <nvpair> with id="dummy-meta_attributes-target-role"
- 
- Set 'dummy' option: id=dummy-meta_attributes-target-role set=dummy-meta_attributes name=target-role=Stopped
- =#=#=#= Current cib after: niceguy: Create a resource meta attribute =#=#=#=
-@@ -704,7 +706,7 @@ Deleted 'dummy' option: id=dummy-meta_attributes-target-role name=target-role
- error: unpack_resources:	Resource start-up disabled since no STONITH resources have been defined
- error: unpack_resources:	Either configure some or disable STONITH with the stonith-enabled option
- error: unpack_resources:	NOTE: Clusters with shared data need STONITH to ensure data integrity
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of nvpair=dummy-meta_attributes-target-role is allowed
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <nvpair> with id="dummy-meta_attributes-target-role"
- 
- Set 'dummy' option: id=dummy-meta_attributes-target-role set=dummy-meta_attributes name=target-role=Started
- =#=#=#= Current cib after: niceguy: Create a resource meta attribute =#=#=#=
-@@ -865,7 +867,7 @@ Call failed: Permission denied
- =#=#=#= Begin test: niceguy: Replace - create resource =#=#=#=
- (       acl.c:NNN   )   trace: pcmk__check_acl:	400 access denied to /cib[@epoch]: default
- (       acl.c:NNN   )   trace: pcmk__check_acl:	400 access denied to /cib/configuration/resources/primitive[@id='dummy2']: default
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Cannot add new node primitive at /cib/configuration/resources/primitive[@id='dummy2']
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs disallow creation of <primitive> with id="dummy2"
- Call failed: Permission denied
- =#=#=#= End test: niceguy: Replace - create resource - Permission denied (13) =#=#=#=
- * Passed: cibadmin       - niceguy: Replace - create resource
-@@ -1184,28 +1186,28 @@ Call failed: Permission denied
- 
-     !#!#!#!#! Upgrading to pacemaker-2.0 and retesting !#!#!#!#!
- =#=#=#= Begin test: root: Upgrade to pacemaker-2.0 =#=#=#=
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_permission=observer-read-1 is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_permission=observer-write-1 is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_permission=observer-write-2 is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_permission=admin-read-1 is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_permission=admin-write-1 is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_target=l33t-haxor is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of role=auto-l33t-haxor is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_role=auto-l33t-haxor is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_permission=crook-nothing is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_target=niceguy is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of role=observer is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_target=bob is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of role=admin is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_target=badidea is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of role=auto-badidea is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_role=auto-badidea is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_permission=badidea-resources is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_target=betteridea is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of role=auto-betteridea is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_role=auto-betteridea is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_permission=betteridea-nothing is allowed
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of acl_permission=betteridea-resources is allowed
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_permission> with id="observer-read-1"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_permission> with id="observer-write-1"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_permission> with id="observer-write-2"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_permission> with id="admin-read-1"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_permission> with id="admin-write-1"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_target> with id="l33t-haxor"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <role> with id="auto-l33t-haxor"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_role> with id="auto-l33t-haxor"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_permission> with id="crook-nothing"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_target> with id="niceguy"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <role> with id="observer"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_target> with id="bob"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <role> with id="admin"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_target> with id="badidea"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <role> with id="auto-badidea"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_role> with id="auto-badidea"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_permission> with id="badidea-resources"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_target> with id="betteridea"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <role> with id="auto-betteridea"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_role> with id="auto-betteridea"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_permission> with id="betteridea-nothing"
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <acl_permission> with id="betteridea-resources"
- =#=#=#= Current cib after: root: Upgrade to pacemaker-2.0 =#=#=#=
- <cib epoch="2" num_updates="0" admin_epoch="1">
-   <configuration>
-@@ -1279,6 +1281,7 @@ Error performing operation: Permission denied
- (       acl.c:NNN   )   trace: pcmk__check_acl:	Ordinary user unknownguy cannot access the CIB without any defined ACLs
- (       acl.c:NNN   )   trace: pcmk__check_acl:	Ordinary user unknownguy cannot access the CIB without any defined ACLs
- (       acl.c:NNN   )   trace: pcmk__check_acl:	Ordinary user unknownguy cannot access the CIB without any defined ACLs
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of <primitive> scaffolding with id="<unset>" is implicitly allowed
- Call failed: Permission denied
- =#=#=#= End test: unknownguy: Create a resource - Permission denied (13) =#=#=#=
- * Passed: cibadmin       - unknownguy: Create a resource
-@@ -1296,7 +1299,7 @@ Error performing operation: Permission denied
- * Passed: crm_attribute  - l33t-haxor: Set stonith-enabled
- =#=#=#= Begin test: l33t-haxor: Create a resource =#=#=#=
- (       acl.c:NNN   )   trace: pcmk__check_acl:	400 access denied to /cib/configuration/resources/primitive[@id='dummy']: parent
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Cannot add new node primitive at /cib/configuration/resources/primitive[@id='dummy']
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs disallow creation of <primitive> with id="dummy"
- Call failed: Permission denied
- =#=#=#= End test: l33t-haxor: Create a resource - Permission denied (13) =#=#=#=
- * Passed: cibadmin       - l33t-haxor: Create a resource
-@@ -1417,7 +1420,7 @@ Error setting enable-acl=false (section=crm_config, set=<null>): Permission deni
- * Passed: crm_attribute  - niceguy: Set stonith-enabled
- =#=#=#= Begin test: niceguy: Create a resource =#=#=#=
- (       acl.c:NNN   )   trace: pcmk__check_acl:	400 access denied to /cib/configuration/resources/primitive[@id='dummy']: default
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Cannot add new node primitive at /cib/configuration/resources/primitive[@id='dummy']
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs disallow creation of <primitive> with id="dummy"
- Call failed: Permission denied
- =#=#=#= End test: niceguy: Create a resource - Permission denied (13) =#=#=#=
- * Passed: cibadmin       - niceguy: Create a resource
-@@ -1603,7 +1606,8 @@ Error performing operation: Permission denied
- error: unpack_resources:	Resource start-up disabled since no STONITH resources have been defined
- error: unpack_resources:	Either configure some or disable STONITH with the stonith-enabled option
- error: unpack_resources:	NOTE: Clusters with shared data need STONITH to ensure data integrity
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of nvpair=dummy-meta_attributes-target-role is allowed
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of <meta_attributes> scaffolding with id="dummy-meta_attributes" is implicitly allowed
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <nvpair> with id="dummy-meta_attributes-target-role"
- 
- Set 'dummy' option: id=dummy-meta_attributes-target-role set=dummy-meta_attributes name=target-role=Stopped
- =#=#=#= Current cib after: niceguy: Create a resource meta attribute =#=#=#=
-@@ -1798,7 +1802,7 @@ Deleted 'dummy' option: id=dummy-meta_attributes-target-role name=target-role
- error: unpack_resources:	Resource start-up disabled since no STONITH resources have been defined
- error: unpack_resources:	Either configure some or disable STONITH with the stonith-enabled option
- error: unpack_resources:	NOTE: Clusters with shared data need STONITH to ensure data integrity
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Creation of nvpair=dummy-meta_attributes-target-role is allowed
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs allow creation of <nvpair> with id="dummy-meta_attributes-target-role"
- 
- Set 'dummy' option: id=dummy-meta_attributes-target-role set=dummy-meta_attributes name=target-role=Started
- =#=#=#= Current cib after: niceguy: Create a resource meta attribute =#=#=#=
-@@ -1977,7 +1981,7 @@ Call failed: Permission denied
- =#=#=#= Begin test: niceguy: Replace - create resource =#=#=#=
- (       acl.c:NNN   )   trace: pcmk__check_acl:	400 access denied to /cib[@epoch]: default
- (       acl.c:NNN   )   trace: pcmk__check_acl:	400 access denied to /cib/configuration/resources/primitive[@id='dummy2']: default
--(       acl.c:NNN   )   trace: pcmk__post_process_acl:	Cannot add new node primitive at /cib/configuration/resources/primitive[@id='dummy2']
-+(       acl.c:NNN   )   trace: pcmk__post_process_acl:	ACLs disallow creation of <primitive> with id="dummy2"
- Call failed: Permission denied
- =#=#=#= End test: niceguy: Replace - create resource - Permission denied (13) =#=#=#=
- * Passed: cibadmin       - niceguy: Replace - create resource
--- 
-1.8.3.1
-
-
-From ecefc149f2a7f1212e678ba2824755b2d13d848a Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Tue, 18 Jun 2019 17:00:51 -0500
-Subject: [PATCH 53/96] Low: libcrmcommon: avoid use-after-free when enforcing
- creation ACLs
-
-As detected by static analysis, pcmk__post_process_acl() can free its argument,
-yet some callers continued to use the argument afterward.
-
-The existing code apparently tried to get around this by freeing the argument
-only if it wasn't the root element of the XML document. However some callers
-do pass non-root elements.
-
-The circumstances where the use-after-free could occur seem limited enough
-that it hasn't been seen in practice.
-
-This avoids any chance of use-after-free by adding an argument indicating
-whether the argument itself should be checked, or just its children (replacing
-the root element check). All callers specify just children, except
-pcmk__post_process_acl()'s recursive calls for the children.
-
-__xml_diff_object() gets a similar argument to pass along to
-pcmk__post_process_acl().
----
- lib/common/acl.c               | 32 +++++++++++++++++++++++---------
- lib/common/crmcommon_private.h |  6 ++++--
- lib/common/xml.c               | 10 +++++-----
- 3 files changed, 32 insertions(+), 16 deletions(-)
-
-diff --git a/lib/common/acl.c b/lib/common/acl.c
-index dea67cf..72dc707 100644
---- a/lib/common/acl.c
-+++ b/lib/common/acl.c
-@@ -506,10 +506,22 @@ implicitly_allowed(xmlNode *xml)
- 
- #define display_id(xml) (ID(xml)? ID(xml) : "<unset>")
- 
-+/*!
-+ * \internal
-+ * \brief Drop XML nodes created in violation of ACLs
-+ *
-+ * Given an XML element, free all of its descendent nodes created in violation
-+ * of ACLs, with the exception of allowing "scaffolding" elements (i.e. those
-+ * that aren't in the ACL section and don't have any attributes other than
-+ * "id").
-+ *
-+ * \param[in,out] xml        XML to check
-+ * \param[in]     check_top  Whether to apply checks to argument itself
-+ *                           (if TRUE, xml might get freed)
-+ */
- void
--pcmk__post_process_acl(xmlNode *xml)
-+pcmk__post_process_acl(xmlNode *xml, bool check_top)
- {
--    xmlNode *cIter = __xml_first_child(xml);
-     xml_private_t *p = xml->_private;
- 
-     if (is_set(p->flags, xpf_created)) {
-@@ -522,20 +534,22 @@ pcmk__post_process_acl(xmlNode *xml)
-             crm_trace("ACLs allow creation of <%s> with id=\"%s\"",
-                       crm_element_name(xml), display_id(xml));
- 
--        } else {
-+        } else if (check_top) {
-             crm_trace("ACLs disallow creation of <%s> with id=\"%s\"",
-                       crm_element_name(xml), display_id(xml));
--            if (xml != xmlDocGetRootElement(xml->doc)) {
--                pcmk_free_xml_subtree(xml);
--            }
-+            pcmk_free_xml_subtree(xml);
-             return;
-+
-+        } else {
-+            crm_trace("ACLs would disallow creation of <%s> with id=\"%s\"",
-+                      crm_element_name(xml), display_id(xml));
-         }
-     }
- 
--    while (cIter != NULL) {
-+    for (xmlNode *cIter = __xml_first_child(xml); cIter != NULL; ) {
-         xmlNode *child = cIter;
-         cIter = __xml_next(cIter); /* In case it is free'd */
--        pcmk__post_process_acl(child);
-+        pcmk__post_process_acl(child, TRUE);
-     }
- }
- 
-@@ -558,7 +572,7 @@ xml_acl_disable(xmlNode *xml)
- 
-         /* Catch anything that was created but shouldn't have been */
-         pcmk__apply_acl(xml);
--        pcmk__post_process_acl(xml);
-+        pcmk__post_process_acl(xml, FALSE);
-         clear_bit(p->flags, xpf_acl_enabled);
-     }
- }
-diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h
-index 113f525..b153873 100644
---- a/lib/common/crmcommon_private.h
-+++ b/lib/common/crmcommon_private.h
-@@ -1,5 +1,7 @@
- /*
-- * Copyright 2018-2019 Andrew Beekhof <andrew@beekhof.net>
-+ * Copyright 2018-2019 the Pacemaker project contributors
-+ *
-+ * The version control history for this file may have further details.
-  *
-  * This source code is licensed under the GNU Lesser General Public License
-  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
-@@ -66,7 +68,7 @@ G_GNUC_INTERNAL
- void pcmk__apply_acl(xmlNode *xml);
- 
- G_GNUC_INTERNAL
--void pcmk__post_process_acl(xmlNode *xml);
-+void pcmk__post_process_acl(xmlNode *xml, bool check_top);
- 
- G_GNUC_INTERNAL
- void pcmk__mark_xml_attr_dirty(xmlAttr *a);
-diff --git a/lib/common/xml.c b/lib/common/xml.c
-index dfa2d77..9fd83a8 100644
---- a/lib/common/xml.c
-+++ b/lib/common/xml.c
-@@ -3368,7 +3368,7 @@ apply_xml_diff(xmlNode * old, xmlNode * diff, xmlNode ** new)
- }
- 
- static void
--__xml_diff_object(xmlNode * old, xmlNode * new)
-+__xml_diff_object(xmlNode * old, xmlNode * new, bool check_top)
- {
-     xmlNode *cIter = NULL;
-     xmlAttr *pIter = NULL;
-@@ -3376,7 +3376,7 @@ __xml_diff_object(xmlNode * old, xmlNode * new)
-     CRM_CHECK(new != NULL, return);
-     if(old == NULL) {
-         crm_node_created(new);
--        pcmk__post_process_acl(new); // Check creation is allowed
-+        pcmk__post_process_acl(new, check_top); // Check creation is allowed
-         return;
- 
-     } else {
-@@ -3483,7 +3483,7 @@ __xml_diff_object(xmlNode * old, xmlNode * new)
- 
-         cIter = __xml_next(cIter);
-         if(new_child) {
--            __xml_diff_object(old_child, new_child);
-+            __xml_diff_object(old_child, new_child, TRUE);
- 
-         } else {
-             /* Create then free (which will check the acls if necessary) */
-@@ -3511,7 +3511,7 @@ __xml_diff_object(xmlNode * old, xmlNode * new)
-         if(old_child == NULL) {
-             xml_private_t *p = new_child->_private;
-             p->flags |= xpf_skip;
--            __xml_diff_object(old_child, new_child);
-+            __xml_diff_object(old_child, new_child, TRUE);
- 
-         } else {
-             /* Check for movement, we already checked for differences */
-@@ -3554,7 +3554,7 @@ xml_calculate_changes(xmlNode * old, xmlNode * new)
-         xml_track_changes(new, NULL, NULL, FALSE);
-     }
- 
--    __xml_diff_object(old, new);
-+    __xml_diff_object(old, new, FALSE);
- }
- 
- xmlNode *
--- 
-1.8.3.1
-
-
-From b24cd86fa98fa042d40e6f0820c36d12e14ff3ed Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 15 Aug 2019 14:13:32 -0500
-Subject: [PATCH 54/96] Fix: extra: handle run-as-user properly in ClusterMon
-
-7b303943 improperly searched for the crm_mon process when the user option was
-set (regression since 1.1.16)
----
- extra/resources/ClusterMon | 18 ++++++++++++++----
- 1 file changed, 14 insertions(+), 4 deletions(-)
-
-diff --git a/extra/resources/ClusterMon b/extra/resources/ClusterMon
-index 0604a26..0f4eb55 100755
---- a/extra/resources/ClusterMon
-+++ b/extra/resources/ClusterMon
-@@ -152,14 +152,24 @@ ClusterMon_stop() {
- }
- 
- ClusterMon_monitor() {
-+    local USERARG=""
-+    local header
-+    local pid
-+
-     if [ -f $OCF_RESKEY_pidfile ]; then
- 	pid=`cat $OCF_RESKEY_pidfile`
- 	if [ ! -z $pid ]; then
--	    str=$(echo "su - $OCF_RESKEY_user -c \"$CMON_CMD\"" | tr 'crmon, \t' 'xxxxxxxx')
--	    ps -o "args=${str}" -p $pid 2>/dev/null | \
-+            if [ -n "$OCF_RESKEY_user" ]; then
-+                USERARG="-u $OCF_RESKEY_user"
-+            fi
-+
-+            # Use column header wide as command, to ensure it's shown in full
-+            header=$(echo $CMON_CMD | tr 'crmon, \t' 'xxxxxxxx')
-+
-+            ps $USERARG -o "args=${header}" -p $pid 2>/dev/null | \
- 		grep -qE "[c]rm_mon.*${OCF_RESKEY_pidfile}"
--	    rc=$?
--	    case $rc in
-+
-+            case $? in
- 		0) exit $OCF_SUCCESS;;
- 		1) exit $OCF_NOT_RUNNING;;
- 		*) exit $OCF_ERR_GENERIC;;
--- 
-1.8.3.1
-
-
-From cdf23bd35084a13a02a394cada2d5baae857f47f Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 18 Jul 2019 20:36:16 -0500
-Subject: [PATCH 55/96] Fix: extra: calculate #health_disk correctly in SysInfo
-
-Previously, if SysInfo monitored multiple disks, the status of the last disk in
-the list was used as the value of #health_disk. Now, #health_disk matches the
-documentation in setting #health_disk red if any disk in the list is low on
-space.
----
- extra/resources/SysInfo | 10 ++++------
- 1 file changed, 4 insertions(+), 6 deletions(-)
-
-diff --git a/extra/resources/SysInfo b/extra/resources/SysInfo
-index 7d1c0a3..4441026 100755
---- a/extra/resources/SysInfo
-+++ b/extra/resources/SysInfo
-@@ -157,6 +157,7 @@ UpdateStat() {
- }
- 
- SysInfoStats() {
-+    local DISK_STATUS="green"
- 
-     UpdateStat arch "`uname -m`"
-     UpdateStat os "`uname -s`-`uname -r`"
-@@ -241,15 +242,12 @@ SysInfoStats() {
- 	    disk_label=`echo $disk | sed -e 's#^/$#root#;s#^/*##;s#/#_#g'`
- 	    disk_free=`SysInfo_hdd_units $disk_free`
- 	    UpdateStat ${disk_label}_free $disk_free
--	    if [ -n "$MIN_FREE" ]; then
--		if [ $disk_free -le $MIN_FREE ]; then
--		    UpdateStat "#health_disk" "red"
--		else
--		    UpdateStat "#health_disk" "green"
--		fi
-+            if [ -n "$MIN_FREE" ] && [ $disk_free -le $MIN_FREE ]; then
-+                DISK_STATUS="red"
- 	    fi
- 	fi
-     done
-+    UpdateStat "#health_disk" "$DISK_STATUS"
- }
- 
- SysInfo_megabytes() {
--- 
-1.8.3.1
-
-
-From dd8c31f794eb3cbbc37bf1abd6a2ec90374b7c36 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 15 Aug 2019 14:43:09 -0500
-Subject: [PATCH 56/96] Test: cts-cli: add test for crm_diff
-
----
- tools/Makefile.am          |  8 ++++--
- tools/crm_diff_new.xml     | 54 +++++++++++++++++++++++++++++++++++++
- tools/crm_diff_old.xml     | 54 +++++++++++++++++++++++++++++++++++++
- tools/regression.sh        |  5 ++++
- tools/regression.tools.exp | 67 ++++++++++++++++++++++++++++++++++++++++++++--
- 5 files changed, 184 insertions(+), 4 deletions(-)
- create mode 100644 tools/crm_diff_new.xml
- create mode 100644 tools/crm_diff_old.xml
-
-diff --git a/tools/Makefile.am b/tools/Makefile.am
-index 3548035..d8c3215 100644
---- a/tools/Makefile.am
-+++ b/tools/Makefile.am
-@@ -42,8 +42,12 @@ sbin_PROGRAMS		= crm_simulate crmadmin cibadmin crm_node crm_attribute crm_resou
- 
- testdir			= $(datadir)/$(PACKAGE)/tests/cli
- test_SCRIPTS		= regression.sh
--test_DATA               = regression.dates.exp regression.tools.exp regression.acls.exp \
--			  regression.validity.exp
-+test_DATA		= regression.dates.exp		\
-+			  regression.tools.exp		\
-+			  regression.acls.exp		\
-+			  regression.validity.exp	\
-+			  crm_diff_new.xml		\
-+			  crm_diff_old.xml
- 
- if BUILD_HEARTBEAT_SUPPORT
- sbin_PROGRAMS           += crm_uuid
-diff --git a/tools/crm_diff_new.xml b/tools/crm_diff_new.xml
-new file mode 100644
-index 0000000..7c2ec22
---- /dev/null
-+++ b/tools/crm_diff_new.xml
-@@ -0,0 +1,54 @@
-+<cib crm_feature_set="3.0.14" validate-with="pacemaker-2.10" epoch="1" num_updates="0" admin_epoch="0">
-+  <configuration>
-+    <crm_config>
-+      <cluster_property_set id="cib-bootstrap-options">
-+        <!-- test: move attribute "value" before "name" -->
-+        <nvpair id="cib-bootstrap-options-cluster-name" value="mycluster" name="cluster-name" />
-+        <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="1" />
-+      </cluster_property_set>
-+    </crm_config>
-+    <nodes>
-+      <node id="1" uname="node1"/>
-+      <node id="2" uname="node2"/>
-+      <node id="3" uname="node3"/>
-+      <!-- test: add element for node4 -->
-+      <node id="4" uname="node4"/>
-+    </nodes>
-+    <!-- test: add a new comment below this one -->
-+    <!-- hello world -->
-+    <resources>
-+      <!-- test: modify this comment to say something different -->
-+      <primitive id="Fencing" class="stonith" type="fence_xvm">
-+        <meta_attributes id="Fencing-meta">
-+          <nvpair id="Fencing-migration-threshold" name="migration-threshold" value="5"/>
-+        </meta_attributes>
-+        <instance_attributes id="Fencing-params">
-+          <nvpair id="Fencing-key_file" name="key_file" value="/etc/pacemaker/fence_xvm.key"/>
-+          <nvpair id="Fencing-multicast_address" name="multicast_address" value="239.255.100.100"/>
-+          <!-- test: modify attribute value to add node4 -->
-+          <nvpair id="Fencing-pcmk_host_list" name="pcmk_host_list" value="node1 node2 node3 node4"/>
-+        </instance_attributes>
-+        <operations>
-+          <!-- test: add attribute timeout="120s" -->
-+          <op id="Fencing-monitor-120s" interval="120s" timeout="120s" name="monitor" />
-+          <op id="Fencing-stop-0" interval="0" name="stop" timeout="60s"/>
-+          <!-- test: delete element Fencing-start-0 -->
-+        </operations>
-+      </primitive>
-+      <primitive id="dummy" class="ocf" type="pacemaker" provider="Dummy">
-+        <instance_attributes id="dummy-params">
-+          <!-- test: move element dummy-fake below dummy-op_sleep -->
-+          <nvpair id="dummy-op_sleep" name="op_sleep" value="3"/>
-+          <nvpair id="dummy-fake" name="fake" value="0"/>
-+        </instance_attributes>
-+        <operations>
-+          <!-- test: delete attribute timeout -->
-+          <op id="dummy-monitor-5s" interval="5s" name="monitor"/>
-+        </operations>
-+      </primitive>
-+    </resources>
-+    <constraints/>
-+    <!-- test: move this comment to end of configuration -->
-+  </configuration>
-+  <status/>
-+</cib>
-diff --git a/tools/crm_diff_old.xml b/tools/crm_diff_old.xml
-new file mode 100644
-index 0000000..8a92edd
---- /dev/null
-+++ b/tools/crm_diff_old.xml
-@@ -0,0 +1,54 @@
-+<cib crm_feature_set="3.0.14" validate-with="pacemaker-2.10" epoch="1" num_updates="0" admin_epoch="0">
-+  <configuration>
-+    <!-- test: move this comment to end of configuration -->
-+    <crm_config>
-+      <cluster_property_set id="cib-bootstrap-options">
-+        <!-- test: move attribute "value" before "name" -->
-+        <nvpair id="cib-bootstrap-options-cluster-name" name="cluster-name" value="mycluster" />
-+        <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="1" />
-+      </cluster_property_set>
-+    </crm_config>
-+    <!-- test: delete this comment -->
-+    <nodes>
-+      <node id="1" uname="node1"/>
-+      <node id="2" uname="node2"/>
-+      <node id="3" uname="node3"/>
-+      <!-- test: add element for node4 -->
-+    </nodes>
-+    <!-- test: add a new comment below this one -->
-+    <resources>
-+      <!-- test: modify this comment -->
-+      <primitive id="Fencing" class="stonith" type="fence_xvm">
-+        <meta_attributes id="Fencing-meta">
-+          <nvpair id="Fencing-migration-threshold" name="migration-threshold" value="5"/>
-+        </meta_attributes>
-+        <instance_attributes id="Fencing-params">
-+          <nvpair id="Fencing-key_file" name="key_file" value="/etc/pacemaker/fence_xvm.key"/>
-+          <nvpair id="Fencing-multicast_address" name="multicast_address" value="239.255.100.100"/>
-+          <!-- test: modify attribute value to add node4 -->
-+          <nvpair id="Fencing-pcmk_host_list" name="pcmk_host_list" value="node1 node2 node3"/>
-+        </instance_attributes>
-+        <operations>
-+          <!-- test: add attribute timeout="120s" -->
-+          <op id="Fencing-monitor-120s" interval="120s" name="monitor" />
-+          <op id="Fencing-stop-0" interval="0" name="stop" timeout="60s"/>
-+          <!-- test: delete element Fencing-start-0 -->
-+          <op id="Fencing-start-0" interval="0" name="start" timeout="60s"/>
-+        </operations>
-+      </primitive>
-+      <primitive id="dummy" class="ocf" type="pacemaker" provider="Dummy">
-+        <instance_attributes id="dummy-params">
-+          <!-- test: move element dummy-fake below dummy-op_sleep -->
-+          <nvpair id="dummy-fake" name="fake" value="0"/>
-+          <nvpair id="dummy-op_sleep" name="op_sleep" value="3"/>
-+        </instance_attributes>
-+        <operations>
-+          <!-- test: delete attribute timeout -->
-+          <op id="dummy-monitor-5s" interval="5s" timeout="10s" name="monitor"/>
-+        </operations>
-+      </primitive>
-+    </resources>
-+    <constraints/>
-+  </configuration>
-+  <status/>
-+</cib>
-diff --git a/tools/regression.sh b/tools/regression.sh
-index 3680f13..2765595 100755
---- a/tools/regression.sh
-+++ b/tools/regression.sh
-@@ -9,6 +9,7 @@ verbose=0
- tests="dates tools acls validity"
- 
- CRM_EX_OK=0
-+CRM_EX_ERROR=1
- 
- function test_assert() {
-     target=$1; shift
-@@ -388,6 +389,10 @@ function test_tools() {
-     test_assert $CRM_EX_OK
- 
-     rm -f /tmp/$$.existing.xml /tmp/$$.resources.xml
-+
-+    desc="Create an XML patchset"
-+    cmd="crm_diff -o $test_home/crm_diff_old.xml -n $test_home/crm_diff_new.xml"
-+    test_assert $CRM_EX_ERROR 0
- }
- 
- function test_dates() {
-diff --git a/tools/regression.tools.exp b/tools/regression.tools.exp
-index 5be42c8..900544a 100644
---- a/tools/regression.tools.exp
-+++ b/tools/regression.tools.exp
-@@ -3074,8 +3074,8 @@ Migration will take effect until:
- * Passed: crm_resource   - Try to move a resource previously moved with a lifetime
- =#=#=#= Begin test: Ban dummy from node1 for a short time =#=#=#=
- WARNING: Creating rsc_location constraint 'cli-ban-dummy-on-node1' with a score of -INFINITY for resource dummy on node1.
--       This will prevent dummy from running on node1 until the constraint is removed using the clear option or by editing the CIB with an appropriate tool
--       This will be the case even if node1 is the last node in the cluster
-+	This will prevent dummy from running on node1 until the constraint is removed using the clear option or by editing the CIB with an appropriate tool
-+	This will be the case even if node1 is the last node in the cluster
- Migration will take effect until:
- =#=#=#= Current cib after: Ban dummy from node1 for a short time =#=#=#=
- <cib epoch="46" num_updates="0" admin_epoch="1">
-@@ -3174,3 +3174,66 @@ Migration will take effect until:
- </cib>
- =#=#=#= End test: Remove expired constraints - OK (0) =#=#=#=
- * Passed: crm_resource   - Remove expired constraints
-+=#=#=#= Begin test: Create an XML patchset =#=#=#=
-+<diff format="2">
-+  <version>
-+    <source admin_epoch="0" epoch="1" num_updates="0"/>
-+    <target admin_epoch="0" epoch="1" num_updates="0"/>
-+  </version>
-+  <change operation="delete" path="/cib/configuration/comment" position="0"/>
-+  <change operation="delete" path="/cib/configuration/comment" position="1"/>
-+  <change operation="delete" path="/cib/configuration/resources/comment" position="0"/>
-+  <change operation="delete" path="/cib/configuration/resources/primitive[@id=&apos;Fencing&apos;]/operations/op[@id=&apos;Fencing-start-0&apos;]"/>
-+  <change operation="modify" path="/cib/configuration/crm_config/cluster_property_set[@id=&apos;cib-bootstrap-options&apos;]/nvpair[@id=&apos;cib-bootstrap-options-cluster-name&apos;]">
-+    <change-list>
-+      <change-attr name="value" operation="set" value="mycluster"/>
-+      <change-attr name="name" operation="set" value="cluster-name"/>
-+    </change-list>
-+    <change-result>
-+      <nvpair id="cib-bootstrap-options-cluster-name" value="mycluster" name="cluster-name"/>
-+    </change-result>
-+  </change>
-+  <change operation="create" path="/cib/configuration/nodes" position="4">
-+    <node id="4" uname="node4"/>
-+  </change>
-+  <change operation="create" path="/cib/configuration" position="3">
-+    <!-- hello world -->
-+  </change>
-+  <change operation="create" path="/cib/configuration/resources" position="0">
-+    <!-- test: modify this comment to say something different -->
-+  </change>
-+  <change operation="modify" path="/cib/configuration/resources/primitive[@id=&apos;Fencing&apos;]/instance_attributes[@id=&apos;Fencing-params&apos;]/nvpair[@id=&apos;Fencing-pcmk_host_list&apos;]">
-+    <change-list>
-+      <change-attr name="value" operation="set" value="node1 node2 node3 node4"/>
-+    </change-list>
-+    <change-result>
-+      <nvpair id="Fencing-pcmk_host_list" name="pcmk_host_list" value="node1 node2 node3 node4"/>
-+    </change-result>
-+  </change>
-+  <change operation="modify" path="/cib/configuration/resources/primitive[@id=&apos;Fencing&apos;]/operations/op[@id=&apos;Fencing-monitor-120s&apos;]">
-+    <change-list>
-+      <change-attr name="timeout" operation="set" value="120s"/>
-+      <change-attr name="name" operation="set" value="monitor"/>
-+    </change-list>
-+    <change-result>
-+      <op id="Fencing-monitor-120s" interval="120s" timeout="120s" name="monitor"/>
-+    </change-result>
-+  </change>
-+  <change operation="move" path="/cib/configuration/resources/primitive[@id=&apos;dummy&apos;]/instance_attributes[@id=&apos;dummy-params&apos;]/nvpair[@id=&apos;dummy-op_sleep&apos;]" position="1"/>
-+  <change operation="move" path="/cib/configuration/resources/primitive[@id=&apos;dummy&apos;]/instance_attributes[@id=&apos;dummy-params&apos;]/nvpair[@id=&apos;dummy-fake&apos;]" position="2"/>
-+  <change operation="modify" path="/cib/configuration/resources/primitive[@id=&apos;dummy&apos;]/operations/op[@id=&apos;dummy-monitor-5s&apos;]">
-+    <change-list>
-+      <change-attr name="name" operation="set" value="monitor"/>
-+      <change-attr name="timeout" operation="unset"/>
-+    </change-list>
-+    <change-result>
-+      <op id="dummy-monitor-5s" interval="5s" name="monitor"/>
-+    </change-result>
-+  </change>
-+  <change operation="create" path="/cib/configuration" position="6">
-+    <!-- test: move this comment to end of configuration -->
-+  </change>
-+</diff>
-+
-+=#=#=#= End test: Create an XML patchset - Operation not permitted (1) =#=#=#=
-+* Passed: crm_diff       - Create an XML patchset
--- 
-1.8.3.1
-
-
-From d542a0579095471a5e3e21d7de2918051ab95ef1 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 15 Aug 2019 15:04:24 -0500
-Subject: [PATCH 57/96] Refactor: libcrmcommon: add assertion
-
-not really needed, but will hopefully make static analysis happy
----
- lib/common/xml.c | 15 ++++++++-------
- 1 file changed, 8 insertions(+), 7 deletions(-)
-
-diff --git a/lib/common/xml.c b/lib/common/xml.c
-index 9fd83a8..ae4cc6a 100644
---- a/lib/common/xml.c
-+++ b/lib/common/xml.c
-@@ -3372,22 +3372,23 @@ __xml_diff_object(xmlNode * old, xmlNode * new, bool check_top)
- {
-     xmlNode *cIter = NULL;
-     xmlAttr *pIter = NULL;
-+    xml_private_t *p = NULL;
- 
-     CRM_CHECK(new != NULL, return);
-     if(old == NULL) {
-         crm_node_created(new);
-         pcmk__post_process_acl(new, check_top); // Check creation is allowed
-         return;
-+    }
- 
--    } else {
--        xml_private_t *p = new->_private;
-+    p = new->_private;
-+    CRM_CHECK(p != NULL, return);
- 
--        if(p->flags & xpf_processed) {
--            /* Avoid re-comparing nodes */
--            return;
--        }
--        p->flags |= xpf_processed;
-+    if(p->flags & xpf_processed) {
-+        /* Avoid re-comparing nodes */
-+        return;
-     }
-+    p->flags |= xpf_processed;
- 
-     for (pIter = pcmk__first_xml_attr(new); pIter != NULL; pIter = pIter->next) {
-         xml_private_t *p = pIter->_private;
--- 
-1.8.3.1
-
-
-From 01f56916870c72f054829b2276111729fc9e52de Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Mon, 12 Aug 2019 13:18:24 -0500
-Subject: [PATCH 58/96] Log: pacemakerd: log a better warning if unable to
- create /var/run/crm
-
-also makes static analysis happy
----
- mcp/pacemaker.c | 8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/mcp/pacemaker.c b/mcp/pacemaker.c
-index 1cc72af..dbe6220 100644
---- a/mcp/pacemaker.c
-+++ b/mcp/pacemaker.c
-@@ -1346,8 +1346,12 @@ main(int argc, char **argv)
-         crm_exit(ENOKEY);
-     }
- 
--    mkdir(CRM_STATE_DIR, 0750);
--    mcp_chown(CRM_STATE_DIR, pcmk_uid, pcmk_gid);
-+    // Used by some resource agents
-+    if ((mkdir(CRM_STATE_DIR, 0750) < 0) && (errno != EEXIST)) {
-+        crm_warn("Could not create " CRM_STATE_DIR ": %s", pcmk_strerror(errno));
-+    } else {
-+        mcp_chown(CRM_STATE_DIR, pcmk_uid, pcmk_gid);
-+    }
- 
-     /* Used to store core/blackbox/pengine/cib files in */
-     crm_build_path(CRM_PACEMAKER_DIR, 0750);
--- 
-1.8.3.1
-
-
-From b7b7e5ca6df11a9a21b9b61352741f4c3d9f5bf6 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Mon, 12 Aug 2019 13:29:44 -0500
-Subject: [PATCH 59/96] Log: pacemakerd: tweak messages for checking for
- existing instance
-
-and silence a static analysis warning about unused return value
----
- mcp/pacemaker.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/mcp/pacemaker.c b/mcp/pacemaker.c
-index dbe6220..6ec25be 100644
---- a/mcp/pacemaker.c
-+++ b/mcp/pacemaker.c
-@@ -1280,12 +1280,12 @@ main(int argc, char **argv)
-     /* Restore the original facility so that mcp_read_config() does the right thing */
-     set_daemon_option("logfacility", facility);
- 
--    crm_debug("Checking for old instances of %s", CRM_SYSTEM_MCP);
-+    crm_debug("Checking for existing Pacemaker instance");
-     old_instance = crm_ipc_new(CRM_SYSTEM_MCP, 0);
--    crm_ipc_connect(old_instance);
-+    (void) crm_ipc_connect(old_instance);
- 
-     if (shutdown) {
--        crm_debug("Terminating previous instance");
-+        crm_debug("Shutting down existing Pacemaker instance by request");
-         while (crm_ipc_connected(old_instance)) {
-             xmlNode *cmd =
-                 create_request(CRM_OP_QUIT, NULL, NULL, CRM_SYSTEM_MCP, CRM_SYSTEM_MCP, NULL);
-@@ -1303,7 +1303,7 @@ main(int argc, char **argv)
-     } else if (crm_ipc_connected(old_instance)) {
-         crm_ipc_close(old_instance);
-         crm_ipc_destroy(old_instance);
--        crm_err("Pacemaker is already active, aborting startup");
-+        crm_err("Aborting start-up because active Pacemaker instance found");
-         crm_exit(DAEMON_RESPAWN_STOP);
-     }
- 
--- 
-1.8.3.1
-
-
-From e32a3350ade774c1f10e397c994bfeb96e459a73 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Mon, 12 Aug 2019 13:41:43 -0500
-Subject: [PATCH 60/96] Refactor: controller: avoid memcpy() for two characters
-
-makes static analysis happy (which complained about copying 2 characters of a
-3-character literal)
----
- crmd/lrm.c | 6 +++++-
- 1 file changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/crmd/lrm.c b/crmd/lrm.c
-index 776c02b..437840f 100644
---- a/crmd/lrm.c
-+++ b/crmd/lrm.c
-@@ -2480,7 +2480,11 @@ unescape_newlines(const char *string)
-     ret = strdup(string);
-     pch = strstr(ret, escaped_newline);
-     while (pch != NULL) {
--        memcpy(pch, "\n ", 2);
-+        /* Replace newline escape pattern with actual newline (and a space so we
-+         * don't have to shuffle the rest of the buffer)
-+         */
-+        pch[0] = '\n';
-+        pch[1] = ' ';
-         pch = strstr(pch, escaped_newline);
-     }
- 
--- 
-1.8.3.1
-
-
-From e47691249062f46c7e2719994871717e5d42fb8f Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Mon, 12 Aug 2019 19:40:31 -0500
-Subject: [PATCH 61/96] Refactor: libcrmcommon: use constant for all uses of
- XML parse options
-
-Mainly so we can comment an issue with it.
----
- lib/common/xml.c | 31 ++++++++++++++++++-------------
- 1 file changed, 18 insertions(+), 13 deletions(-)
-
-diff --git a/lib/common/xml.c b/lib/common/xml.c
-index ae4cc6a..26cd78d 100644
---- a/lib/common/xml.c
-+++ b/lib/common/xml.c
-@@ -44,6 +44,17 @@
- #define XML_BUFFER_SIZE	4096
- #define XML_PARSER_DEBUG 0
- 
-+/* @TODO XML_PARSE_RECOVER allows some XML errors to be silently worked around
-+ * by libxml2, which is potentially ambiguous and dangerous. We should drop it
-+ * when we can break backward compatibility with configurations that might be
-+ * relying on it (i.e. pacemaker 3.0.0).
-+ *
-+ * It might be a good idea to have a transitional period where we first try
-+ * parsing without XML_PARSE_RECOVER, and if that fails, try parsing again with
-+ * it, logging a warning if it succeeds.
-+ */
-+#define PCMK__XML_PARSE_OPTS    (XML_PARSE_NOBLANKS | XML_PARSE_RECOVER)
-+
- typedef struct {
-     int found;
-     const char *string;
-@@ -2154,14 +2165,10 @@ string2xml(const char *input)
-     ctxt = xmlNewParserCtxt();
-     CRM_CHECK(ctxt != NULL, return NULL);
- 
--    /* xmlCtxtUseOptions(ctxt, XML_PARSE_NOBLANKS|XML_PARSE_RECOVER); */
--
-     xmlCtxtResetLastError(ctxt);
-     xmlSetGenericErrorFunc(ctxt, crm_xml_err);
--    /* initGenericErrorDefaultFunc(crm_xml_err); */
--    output =
--        xmlCtxtReadDoc(ctxt, (const xmlChar *)input, NULL, NULL,
--                       XML_PARSE_NOBLANKS | XML_PARSE_RECOVER);
-+    output = xmlCtxtReadDoc(ctxt, (const xmlChar *) input, NULL, NULL,
-+                            PCMK__XML_PARSE_OPTS);
-     if (output) {
-         xml = xmlDocGetRootElement(output);
-     }
-@@ -2328,17 +2335,13 @@ filename2xml(const char *filename)
-     gboolean uncompressed = TRUE;
-     xmlParserCtxtPtr ctxt = NULL;
-     xmlErrorPtr last_error = NULL;
--    static int xml_options = XML_PARSE_NOBLANKS | XML_PARSE_RECOVER;
- 
-     /* create a parser context */
-     ctxt = xmlNewParserCtxt();
-     CRM_CHECK(ctxt != NULL, return NULL);
- 
--    /* xmlCtxtUseOptions(ctxt, XML_PARSE_NOBLANKS|XML_PARSE_RECOVER); */
--
-     xmlCtxtResetLastError(ctxt);
-     xmlSetGenericErrorFunc(ctxt, crm_xml_err);
--    /* initGenericErrorDefaultFunc(crm_xml_err); */
- 
-     if (filename) {
-         uncompressed = !crm_ends_with_ext(filename, ".bz2");
-@@ -2346,15 +2349,17 @@ filename2xml(const char *filename)
- 
-     if (filename == NULL) {
-         /* STDIN_FILENO == fileno(stdin) */
--        output = xmlCtxtReadFd(ctxt, STDIN_FILENO, "unknown.xml", NULL, xml_options);
-+        output = xmlCtxtReadFd(ctxt, STDIN_FILENO, "unknown.xml", NULL,
-+                               PCMK__XML_PARSE_OPTS);
- 
-     } else if (uncompressed) {
--        output = xmlCtxtReadFile(ctxt, filename, NULL, xml_options);
-+        output = xmlCtxtReadFile(ctxt, filename, NULL, PCMK__XML_PARSE_OPTS);
- 
-     } else {
-         char *input = decompress_file(filename);
- 
--        output = xmlCtxtReadDoc(ctxt, (const xmlChar *)input, NULL, NULL, xml_options);
-+        output = xmlCtxtReadDoc(ctxt, (const xmlChar *) input, NULL, NULL,
-+                                PCMK__XML_PARSE_OPTS);
-         free(input);
-     }
- 
--- 
-1.8.3.1
-
-
-From ff79b7755d6debd12329632e5a14f8dd1e827e96 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Tue, 13 Aug 2019 16:32:47 -0500
-Subject: [PATCH 62/96] Refactor: tools: avoid use-of-NULL false positives in
- stonith_admin
-
-to make static analysis happy
----
- fencing/admin.c | 46 ++++++++++++++++++++++++++++++----------------
- 1 file changed, 30 insertions(+), 16 deletions(-)
-
-diff --git a/fencing/admin.c b/fencing/admin.c
-index 7da43e9..5fedb7b 100644
---- a/fencing/admin.c
-+++ b/fencing/admin.c
-@@ -312,9 +312,15 @@ handle_level(stonith_t *st, char *target, int fence_level,
-     char *node = NULL;
-     char *pattern = NULL;
-     char *name = NULL;
--    char *value = strchr(target, '=');
-+    char *value = NULL;
-+
-+    if (target == NULL) {
-+        // Not really possible, but makes static analysis happy
-+        return -EINVAL;
-+    }
- 
-     /* Determine if targeting by attribute, node name pattern or node name */
-+    value = strchr(target, '=');
-     if (value != NULL)  {
-         name = target;
-         *value++ = '\0';
-@@ -453,6 +459,28 @@ validate(stonith_t *st, const char *agent, const char *id,
-     return rc;
- }
- 
-+static void
-+show_last_fenced(int as_nodeid, const char *target)
-+{
-+    time_t when = 0;
-+
-+    if (target == NULL) {
-+        // Not really possible, but makes static analysis happy
-+        return;
-+    }
-+    if (as_nodeid) {
-+        uint32_t nodeid = atol(target);
-+        when = stonith_api_time(nodeid, NULL, FALSE);
-+    } else {
-+        when = stonith_api_time(0, target, FALSE);
-+    }
-+    if(when) {
-+        printf("Node %s last kicked at: %s\n", target, ctime(&when));
-+    } else {
-+        printf("Node %s has never been kicked\n", target);
-+    }
-+}
-+
- int
- main(int argc, char **argv)
- {
-@@ -741,21 +769,7 @@ main(int argc, char **argv)
-             rc = mainloop_fencing(st, target, "on", timeout, tolerance);
-             break;
-         case 'h':
--            {
--                time_t when = 0;
--
--                if(as_nodeid) {
--                    uint32_t nodeid = atol(target);
--                    when = stonith_api_time(nodeid, NULL, FALSE);
--                } else {
--                    when = stonith_api_time(0, target, FALSE);
--                }
--                if(when) {
--                    printf("Node %s last kicked at: %s\n", target, ctime(&when));
--                } else {
--                    printf("Node %s has never been kicked\n", target);
--                }
--            }
-+            show_last_fenced(as_nodeid, target);
-             break;
-         case 'H':
-             rc = handle_history(st, target, timeout, quiet,
--- 
-1.8.3.1
-
-
-From 9fe5ad7d746ed60e304fa5420f434fa7750289ca Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Tue, 13 Aug 2019 16:59:13 -0500
-Subject: [PATCH 63/96] Low: libcrmcommon: handle pcmk_strerror(INT_MIN)
-
-not realistic, but makes static analysis happy
----
- lib/common/logging.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/lib/common/logging.c b/lib/common/logging.c
-index b8b0f6f..c392468 100644
---- a/lib/common/logging.c
-+++ b/lib/common/logging.c
-@@ -1149,7 +1149,9 @@ pcmk_strerror(int rc)
- 
-     if (error == 0) {
-         return "OK";
--    } else if (error < PCMK_ERROR_OFFSET) {
-+
-+    // Of course error > 0 ... unless someone passed INT_MIN as rc
-+    } else if ((error > 0) && (error < PCMK_ERROR_OFFSET)) {
-         return strerror(error);
-     }
- 
--- 
-1.8.3.1
-
-
-From 8201550e12973ace36684156d14262f34386cfb7 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 15 Aug 2019 15:33:18 -0500
-Subject: [PATCH 64/96] Build: GNUmakefile: improve coverity targets
-
-Most importantly, add the ability to specify the coverity aggressiveness level,
-and put outputs in the build directory. Otherwise mostly refactoring for
-best practices.
-
-The public coverity instance changed its upload process, so we can't do a
-simple curl anymore. We haven't been using it anyway, so just echo what needs
-to be done for that case.
----
- GNUmakefile | 95 ++++++++++++++++++++++++++++++++++++++++++-------------------
- 1 file changed, 65 insertions(+), 30 deletions(-)
-
-diff --git a/GNUmakefile b/GNUmakefile
-index a084150..0822890 100644
---- a/GNUmakefile
-+++ b/GNUmakefile
-@@ -122,6 +122,11 @@ rpmbuild-with = \
- init:
- 	./autogen.sh init
- 
-+.PHONY: init-if-needed
-+init-if-needed:
-+	test -e configure || ./autogen.sh
-+	test -e Makefile || ./configure
-+
- export:
- 	rm -f $(PACKAGE)-dirty.tar.* $(PACKAGE)-tip.tar.* $(PACKAGE)-HEAD.tar.*
- 	if [ ! -f $(TARFILE) ]; then						\
-@@ -265,37 +270,67 @@ rc:
- dirty:
- 	make TAG=dirty mock
- 
--COVERITY_DIR	 = $(shell pwd)/coverity-$(TAG)
--COVFILE          = $(PACKAGE)-coverity-$(TAG).tgz
--COVHOST		?= scan5.coverity.com
--COVPASS		?= password
- 
--# Public coverity
--coverity:
--	test -e configure || ./autogen.sh
--	test -e Makefile || ./configure
--	make core-clean
--	rm -rf $(COVERITY_DIR)
--	cov-build --dir $(COVERITY_DIR) make core
--	tar czf $(COVFILE) --transform=s@.*$(TAG)@cov-int@ $(COVERITY_DIR)
--	@echo "Uploading to public Coverity instance..."
--	curl --form file=@$(COVFILE) --form project=$(PACKAGE) --form password=$(COVPASS) --form email=andrew@beekhof.net http://$(COVHOST)/cgi-bin/upload.py
--	rm -rf $(COVFILE) $(COVERITY_DIR)
--
--coverity-corp:
--	test -e configure || ./autogen.sh
--	test -e Makefile || ./configure
--	make core-clean
--	rm -rf $(COVERITY_DIR)
--	cov-build --dir $(COVERITY_DIR) make core
--	@echo "Waiting for a corporate Coverity license..."
--	cov-analyze --dir $(COVERITY_DIR) --wait-for-license
--	cov-format-errors --dir $(COVERITY_DIR) --emacs-style > $(TAG).coverity
--	cov-format-errors --dir $(COVERITY_DIR)
--	rsync $(RSYNC_OPTS) "$(COVERITY_DIR)/c/output/errors/" "$(RSYNC_DEST)/coverity/$(PACKAGE)/$(TAG)"
--	make core-clean
--#	cov-commit-defects --host $(COVHOST) --dir $(COVERITY_DIR) --stream $(PACKAGE) --user auto --password $(COVPASS)
--	rm -rf $(COVERITY_DIR)
-+## Static analysis via coverity
-+
-+# Aggressiveness (low, medium, or high)
-+COVLEVEL	?= low
-+
-+# Generated outputs
-+COVERITY_DIR	= $(builddir)/coverity-$(TAG)
-+COVTAR		= $(builddir)/$(PACKAGE)-coverity-$(TAG).tgz
-+COVEMACS	= $(builddir)/$(TAG).coverity
-+COVHTML		= $(COVERITY_DIR)/output/errors
-+
-+# Coverity outputs are phony so they get rebuilt every invocation
-+
-+.PHONY: $(COVERITY_DIR)
-+$(COVERITY_DIR): init-if-needed core-clean coverity-clean
-+	$(AM_V_GEN)cov-build --dir "$@" $(MAKE) $(AM_MAKEFLAGS) core
-+
-+.PHONY: $(COVTAR)
-+$(COVTAR): $(COVERITY_DIR)
-+	$(AM_V_GEN)tar czf "$@" --transform="s@.*$(TAG)@cov-int@" "$<"
-+
-+# emacs/html output assume $(COVERITY_DIR) has been built (don't want rebuild)
-+
-+.PHONY: $(COVEMACS)
-+$(COVEMACS):
-+	$(AM_V_GEN)cov-format-errors --dir "$(COVERITY_DIR)" --emacs-style > "$@"
-+
-+.PHONY: $(COVHTML)
-+$(COVHTML):
-+	$(AM_V_GEN)cov-format-errors --dir "$(COVERITY_DIR)" --html-output "$@"
-+
-+# Public coverity instance
-+.PHONY: coverity
-+coverity: $(COVTAR)
-+	@echo "Now go to https://scan.coverity.com/users/sign_in and upload:"
-+	@echo "  $(COVTAR)"
-+	@echo "then make core-clean coverity-clean"
-+
-+# Licensed coverity instance
-+
-+.PHONY: coverity-analyze
-+coverity-analyze: $(COVERITY_DIR)
-+	@echo ""
-+	@echo "Analyzing (waiting for coverity license if necessary) ..."
-+	cov-analyze --dir "$<" --wait-for-license --security		\
-+		--aggressiveness-level "$(COVLEVEL)"
-+
-+.PHONY: coverity-corp
-+coverity-corp: coverity-analyze $(COVEMACS) $(COVHTML) core-clean
-+	@echo "Done. See:"
-+	@echo "  file://$(abs_builddir)/$(COVERITY_DIR)/output/errors/index.html"
-+	@echo "When no longer needed, make coverity-clean"
-+
-+# Remove all outputs regardless of tag
-+.PHONY: coverity-clean
-+coverity-clean:
-+	-rm -rf "$(builddir)"/coverity-*			\
-+		"$(builddir)"/$(PACKAGE)-coverity-*.tgz		\
-+		"$(builddir)"/*.coverity
-+
- 
- global: clean-generic
- 	gtags -q
--- 
-1.8.3.1
-
-
-From 6659ba3cf69f95e0cd724b55a29c926010b68df8 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 15 Aug 2019 15:50:46 -0500
-Subject: [PATCH 66/96] Build: GNUmakefile: don't depend on prerequisite order
- for coverity target
-
----
- GNUmakefile | 30 +++++++++++++++++-------------
- 1 file changed, 17 insertions(+), 13 deletions(-)
-
-diff --git a/GNUmakefile b/GNUmakefile
-index 0822890..b2d5a28 100644
---- a/GNUmakefile
-+++ b/GNUmakefile
-@@ -288,21 +288,12 @@ COVHTML		= $(COVERITY_DIR)/output/errors
- $(COVERITY_DIR): init-if-needed core-clean coverity-clean
- 	$(AM_V_GEN)cov-build --dir "$@" $(MAKE) $(AM_MAKEFLAGS) core
- 
-+# Public coverity instance
-+
- .PHONY: $(COVTAR)
- $(COVTAR): $(COVERITY_DIR)
- 	$(AM_V_GEN)tar czf "$@" --transform="s@.*$(TAG)@cov-int@" "$<"
- 
--# emacs/html output assume $(COVERITY_DIR) has been built (don't want rebuild)
--
--.PHONY: $(COVEMACS)
--$(COVEMACS):
--	$(AM_V_GEN)cov-format-errors --dir "$(COVERITY_DIR)" --emacs-style > "$@"
--
--.PHONY: $(COVHTML)
--$(COVHTML):
--	$(AM_V_GEN)cov-format-errors --dir "$(COVERITY_DIR)" --html-output "$@"
--
--# Public coverity instance
- .PHONY: coverity
- coverity: $(COVTAR)
- 	@echo "Now go to https://scan.coverity.com/users/sign_in and upload:"
-@@ -310,6 +301,10 @@ coverity: $(COVTAR)
- 	@echo "then make core-clean coverity-clean"
- 
- # Licensed coverity instance
-+#
-+# The prerequisites are a little hacky; rather than actually required, some
-+# of them are designed so that things execute in the proper order (which is
-+# not the same as GNU make's order-only prerequisites).
- 
- .PHONY: coverity-analyze
- coverity-analyze: $(COVERITY_DIR)
-@@ -318,10 +313,19 @@ coverity-analyze: $(COVERITY_DIR)
- 	cov-analyze --dir "$<" --wait-for-license --security		\
- 		--aggressiveness-level "$(COVLEVEL)"
- 
-+.PHONY: $(COVEMACS)
-+$(COVEMACS): coverity-analyze
-+	$(AM_V_GEN)cov-format-errors --dir "$(COVERITY_DIR)" --emacs-style > "$@"
-+
-+.PHONY: $(COVHTML)
-+$(COVHTML): $(COVEMACS)
-+	$(AM_V_GEN)cov-format-errors --dir "$(COVERITY_DIR)" --html-output "$@"
-+
- .PHONY: coverity-corp
--coverity-corp: coverity-analyze $(COVEMACS) $(COVHTML) core-clean
-+coverity-corp: $(COVHTML)
-+	$(MAKE) $(AM_MAKEFLAGS) core-clean
- 	@echo "Done. See:"
--	@echo "  file://$(abs_builddir)/$(COVERITY_DIR)/output/errors/index.html"
-+	@echo "  file://$(abs_builddir)/$(COVHTML)/index.html"
- 	@echo "When no longer needed, make coverity-clean"
- 
- # Remove all outputs regardless of tag
--- 
-1.8.3.1
-
-
-From 0158f59b11b3e14f86258265a491f81d83cc6fcf Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 15 Aug 2019 17:38:41 -0500
-Subject: [PATCH 67/96] Fix: all: restrict XML children loops to XML elements
- where appropriate
-
-__xml_first_child() and __xml_next() are intended to be used in "for" loops
-where all XML node types (elements, comments, etc.) are desired.
-
-__xml_first_child_element() and __xml_next_element() are intended when
-only element children are desired.
-
-Previously, many element-only loops properly used __xml_next_element() but
-started with __xml_first_child(). In most cases, this would (by lucky
-circumstance) work without harm. However, there were cases where a comment as
-the first child of an element would case problems (for example,
-unpack_resources() would log a configuration error).
-
-Now, __xml_first_child_element() is always used in such cases.
-
-Additionally, there were some loops using __xml_first_child()/__xml_next() that
-clearly were expecting only elements. These have been converted to
-__xml_first_child_element()/__xml_next_element().
-
-Many more cases exist where __xml_first_child()/__xml_next() is used with IPC
-messages and patchsets. This commit does not convert those, though that would
-probably be a good idea for the future.
----
- lib/common/acl.c           |  12 ++---
- lib/common/xml.c           |   7 +--
- lib/pengine/clone.c        |   2 +-
- lib/pengine/complex.c      |  10 ++--
- lib/pengine/group.c        |   6 ++-
- lib/pengine/rules.c        |  51 ++++++++++---------
- lib/pengine/rules_alerts.c |   4 +-
- lib/pengine/unpack.c       |  61 ++++++++++++++++-------
- lib/pengine/utils.c        |  14 ++++--
- pengine/allocate.c         |  10 ++--
- pengine/constraints.c      | 120 +++++++++++++++++++++++++++++++++------------
- pengine/native.c           |  11 +++--
- tools/crm_mon.c            |  19 ++++---
- tools/crm_resource_print.c |   4 +-
- tools/crmadmin.c           |   4 +-
- tools/fake_transition.c    |   4 +-
- 16 files changed, 226 insertions(+), 113 deletions(-)
-
-diff --git a/lib/common/acl.c b/lib/common/acl.c
-index 72dc707..b5c20bb 100644
---- a/lib/common/acl.c
-+++ b/lib/common/acl.c
-@@ -131,8 +131,8 @@ __xml_acl_parse_entry(xmlNode *acl_top, xmlNode *acl_entry, GList *acls)
- {
-     xmlNode *child = NULL;
- 
--    for (child = __xml_first_child(acl_entry); child;
--         child = __xml_next(child)) {
-+    for (child = __xml_first_child_element(acl_entry); child;
-+         child = __xml_next_element(child)) {
-         const char *tag = crm_element_name(child);
-         const char *kind = crm_element_value(child, XML_ACL_ATTR_KIND);
- 
-@@ -151,8 +151,8 @@ __xml_acl_parse_entry(xmlNode *acl_top, xmlNode *acl_entry, GList *acls)
-             if (ref_role) {
-                 xmlNode *role = NULL;
- 
--                for (role = __xml_first_child(acl_top); role;
--                     role = __xml_next(role)) {
-+                for (role = __xml_first_child_element(acl_top); role;
-+                     role = __xml_next_element(role)) {
-                     if (!strcmp(XML_ACL_TAG_ROLE, (const char *) role->name)) {
-                         const char *role_id = crm_element_value(role,
-                                                                 XML_ATTR_ID);
-@@ -306,8 +306,8 @@ pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user)
-         if (acls) {
-             xmlNode *child = NULL;
- 
--            for (child = __xml_first_child(acls); child;
--                 child = __xml_next(child)) {
-+            for (child = __xml_first_child_element(acls); child;
-+                 child = __xml_next_element(child)) {
-                 const char *tag = crm_element_name(child);
- 
-                 if (!strcmp(tag, XML_ACL_TAG_USER)
-diff --git a/lib/common/xml.c b/lib/common/xml.c
-index 26cd78d..2c4238d 100644
---- a/lib/common/xml.c
-+++ b/lib/common/xml.c
-@@ -4242,7 +4242,8 @@ first_named_child(xmlNode * parent, const char *name)
- {
-     xmlNode *match = NULL;
- 
--    for (match = __xml_first_child(parent); match != NULL; match = __xml_next(match)) {
-+    for (match = __xml_first_child_element(parent); match != NULL;
-+         match = __xml_next_element(match)) {
-         /*
-          * name == NULL gives first child regardless of name; this is
-          * semantically incorrect in this function, but may be necessary
-@@ -4265,14 +4266,14 @@ first_named_child(xmlNode * parent, const char *name)
- xmlNode *
- crm_next_same_xml(xmlNode *sibling)
- {
--    xmlNode *match = __xml_next(sibling);
-+    xmlNode *match = __xml_next_element(sibling);
-     const char *name = crm_element_name(sibling);
- 
-     while (match != NULL) {
-         if (!strcmp(crm_element_name(match), name)) {
-             return match;
-         }
--        match = __xml_next(match);
-+        match = __xml_next_element(match);
-     }
-     return NULL;
- }
-diff --git a/lib/pengine/clone.c b/lib/pengine/clone.c
-index 88015a9..07a383c 100644
---- a/lib/pengine/clone.c
-+++ b/lib/pengine/clone.c
-@@ -172,7 +172,7 @@ clone_unpack(resource_t * rsc, pe_working_set_t * data_set)
-                  is_set(rsc->flags, pe_rsc_unique) ? "true" : "false");
- 
-     // Clones may contain a single group or primitive
--    for (a_child = __xml_first_child(xml_obj); a_child != NULL;
-+    for (a_child = __xml_first_child_element(xml_obj); a_child != NULL;
-          a_child = __xml_next_element(a_child)) {
- 
-         if (crm_str_eq((const char *)a_child->name, XML_CIB_TAG_RESOURCE, TRUE)
-diff --git a/lib/pengine/complex.c b/lib/pengine/complex.c
-index cdd409a..42492c9 100644
---- a/lib/pengine/complex.c
-+++ b/lib/pengine/complex.c
-@@ -282,7 +282,7 @@ unpack_template(xmlNode * xml_obj, xmlNode ** expanded_xml, pe_working_set_t * d
- 
-     template_ops = find_xml_node(new_xml, "operations", FALSE);
- 
--    for (child_xml = __xml_first_child(xml_obj); child_xml != NULL;
-+    for (child_xml = __xml_first_child_element(xml_obj); child_xml != NULL;
-          child_xml = __xml_next_element(child_xml)) {
-         xmlNode *new_child = NULL;
- 
-@@ -298,13 +298,17 @@ unpack_template(xmlNode * xml_obj, xmlNode ** expanded_xml, pe_working_set_t * d
-         GHashTable *rsc_ops_hash =
-             g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, NULL);
- 
--        for (op = __xml_first_child(rsc_ops); op != NULL; op = __xml_next_element(op)) {
-+        for (op = __xml_first_child_element(rsc_ops); op != NULL;
-+             op = __xml_next_element(op)) {
-+
-             char *key = template_op_key(op);
- 
-             g_hash_table_insert(rsc_ops_hash, key, op);
-         }
- 
--        for (op = __xml_first_child(template_ops); op != NULL; op = __xml_next_element(op)) {
-+        for (op = __xml_first_child_element(template_ops); op != NULL;
-+             op = __xml_next_element(op)) {
-+
-             char *key = template_op_key(op);
- 
-             if (g_hash_table_lookup(rsc_ops_hash, key) == NULL) {
-diff --git a/lib/pengine/group.c b/lib/pengine/group.c
-index 258c6b5..72f066e 100644
---- a/lib/pengine/group.c
-+++ b/lib/pengine/group.c
-@@ -1,5 +1,7 @@
- /*
-- * Copyright 2004-2018 Andrew Beekhof <andrew@beekhof.net>
-+ * Copyright 2004-2019 the Pacemaker project contributors
-+ *
-+ * The version control history for this file may have further details.
-  *
-  * This source code is licensed under the GNU Lesser General Public License
-  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
-@@ -46,7 +48,7 @@ group_unpack(resource_t * rsc, pe_working_set_t * data_set)
- 
-     clone_id = crm_element_value(rsc->xml, XML_RSC_ATTR_INCARNATION);
- 
--    for (xml_native_rsc = __xml_first_child(xml_obj); xml_native_rsc != NULL;
-+    for (xml_native_rsc = __xml_first_child_element(xml_obj); xml_native_rsc != NULL;
-          xml_native_rsc = __xml_next_element(xml_native_rsc)) {
-         if (crm_str_eq((const char *)xml_native_rsc->name, XML_CIB_TAG_RESOURCE, TRUE)) {
-             resource_t *new_rsc = NULL;
-diff --git a/lib/pengine/rules.c b/lib/pengine/rules.c
-index 2d948b9..523ed15 100644
---- a/lib/pengine/rules.c
-+++ b/lib/pengine/rules.c
-@@ -1,19 +1,10 @@
--/* 
-- * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
-- * 
-- * This library is free software; you can redistribute it and/or
-- * modify it under the terms of the GNU Lesser General Public
-- * License as published by the Free Software Foundation; either
-- * version 2.1 of the License, or (at your option) any later version.
-- * 
-- * This library is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-- * Lesser General Public License for more details.
-- * 
-- * You should have received a copy of the GNU Lesser General Public
-- * License along with this library; if not, write to the Free Software
-- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-+/*
-+ * Copyright 2004-2019 the Pacemaker project contributors
-+ *
-+ * The version control history for this file may have further details.
-+ *
-+ * This source code is licensed under the GNU Lesser General Public License
-+ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
-  */
- 
- #include <crm_internal.h>
-@@ -46,7 +37,9 @@ test_ruleset(xmlNode * ruleset, GHashTable * node_hash, crm_time_t * now)
-     gboolean ruleset_default = TRUE;
-     xmlNode *rule = NULL;
- 
--    for (rule = __xml_first_child(ruleset); rule != NULL; rule = __xml_next_element(rule)) {
-+    for (rule = __xml_first_child_element(ruleset); rule != NULL;
-+         rule = __xml_next_element(rule)) {
-+
-         if (crm_str_eq((const char *)rule->name, XML_TAG_RULE, TRUE)) {
-             ruleset_default = FALSE;
-             if (test_rule(rule, node_hash, RSC_ROLE_UNKNOWN, now)) {
-@@ -93,7 +86,9 @@ pe_test_rule_full(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role,
-     }
- 
-     crm_trace("Testing rule %s", ID(rule));
--    for (expr = __xml_first_child(rule); expr != NULL; expr = __xml_next_element(expr)) {
-+    for (expr = __xml_first_child_element(rule); expr != NULL;
-+         expr = __xml_next_element(expr)) {
-+
-         test = pe_test_expression_full(expr, node_hash, role, now, match_data);
-         empty = FALSE;
- 
-@@ -722,7 +717,9 @@ populate_hash(xmlNode * nvpair_list, GHashTable * hash, gboolean overwrite, xmlN
-         list = list->children;
-     }
- 
--    for (an_attr = __xml_first_child(list); an_attr != NULL; an_attr = __xml_next_element(an_attr)) {
-+    for (an_attr = __xml_first_child_element(list); an_attr != NULL;
-+         an_attr = __xml_next_element(an_attr)) {
-+
-         if (crm_str_eq((const char *)an_attr->name, XML_CIB_TAG_NVPAIR, TRUE)) {
-             xmlNode *ref_nvpair = expand_idref(an_attr, top);
- 
-@@ -769,9 +766,13 @@ get_versioned_rule(xmlNode * attr_set)
-     xmlNode * rule = NULL;
-     xmlNode * expr = NULL;
- 
--    for (rule = __xml_first_child(attr_set); rule != NULL; rule = __xml_next_element(rule)) {
-+    for (rule = __xml_first_child_element(attr_set); rule != NULL;
-+         rule = __xml_next_element(rule)) {
-+
-         if (crm_str_eq((const char *)rule->name, XML_TAG_RULE, TRUE)) {
--            for (expr = __xml_first_child(rule); expr != NULL; expr = __xml_next_element(expr)) {
-+            for (expr = __xml_first_child_element(rule); expr != NULL;
-+                 expr = __xml_next_element(expr)) {
-+
-                 if (find_expression_type(expr) == version_expr) {
-                     return rule;
-                 }
-@@ -801,7 +802,7 @@ add_versioned_attributes(xmlNode * attr_set, xmlNode * versioned_attrs)
-         return;
-     }
- 
--    expr = __xml_first_child(rule);
-+    expr = __xml_first_child_element(rule);
-     while (expr != NULL) {
-         if (find_expression_type(expr) != version_expr) {
-             xmlNode *node = expr;
-@@ -879,7 +880,9 @@ make_pairs_and_populate_data(xmlNode * top, xmlNode * xml_obj, const char *set_n
-     }
- 
-     crm_trace("Checking for attributes");
--    for (attr_set = __xml_first_child(xml_obj); attr_set != NULL; attr_set = __xml_next_element(attr_set)) {
-+    for (attr_set = __xml_first_child_element(xml_obj); attr_set != NULL;
-+         attr_set = __xml_next_element(attr_set)) {
-+
-         /* Uncertain if set_name == NULL check is strictly necessary here */
-         if (set_name == NULL || crm_str_eq((const char *)attr_set->name, set_name, TRUE)) {
-             pair = NULL;
-@@ -1011,7 +1014,7 @@ pe_unpack_versioned_parameters(xmlNode *versioned_params, const char *ra_version
- 
-     if (versioned_params && ra_version) {
-         GHashTable *node_hash = crm_str_table_new();
--        xmlNode *attr_set = __xml_first_child(versioned_params);
-+        xmlNode *attr_set = __xml_first_child_element(versioned_params);
- 
-         if (attr_set) {
-             g_hash_table_insert(node_hash, strdup(CRM_ATTR_RA_VERSION),
-diff --git a/lib/pengine/rules_alerts.c b/lib/pengine/rules_alerts.c
-index e2bab58..00be330 100644
---- a/lib/pengine/rules_alerts.c
-+++ b/lib/pengine/rules_alerts.c
-@@ -127,8 +127,8 @@ unpack_alert_filter(xmlNode *basenode, crm_alert_entry_t *entry)
-     xmlNode *event_type = NULL;
-     uint32_t flags = crm_alert_none;
- 
--    for (event_type = __xml_first_child(select); event_type != NULL;
--         event_type = __xml_next(event_type)) {
-+    for (event_type = __xml_first_child_element(select); event_type != NULL;
-+         event_type = __xml_next_element(event_type)) {
- 
-         const char *tagname = crm_element_name(event_type);
- 
-diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c
-index cf725a1..4282a7c 100644
---- a/lib/pengine/unpack.c
-+++ b/lib/pengine/unpack.c
-@@ -430,7 +430,9 @@ remote_id_conflict(const char *remote_name, pe_working_set_t *data)
- #else
-     if (data->name_check == NULL) {
-         data->name_check = g_hash_table_new(crm_str_hash, g_str_equal);
--        for (xml_rsc = __xml_first_child(parent); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+        for (xml_rsc = __xml_first_child_element(parent); xml_rsc != NULL;
-+             xml_rsc = __xml_next_element(xml_rsc)) {
-+
-             const char *id = ID(xml_rsc);
- 
-             /* avoiding heap allocation here because we know the duration of this hashtable allows us to */
-@@ -464,12 +466,14 @@ expand_remote_rsc_meta(xmlNode *xml_obj, xmlNode *parent, pe_working_set_t *data
-     const char *remote_allow_migrate=NULL;
-     const char *container_managed = NULL;
- 
--    for (attr_set = __xml_first_child(xml_obj); attr_set != NULL; attr_set = __xml_next_element(attr_set)) {
-+    for (attr_set = __xml_first_child_element(xml_obj); attr_set != NULL;
-+         attr_set = __xml_next_element(attr_set)) {
-         if (safe_str_neq((const char *)attr_set->name, XML_TAG_META_SETS)) {
-             continue;
-         }
- 
--        for (attr = __xml_first_child(attr_set); attr != NULL; attr = __xml_next_element(attr)) {
-+        for (attr = __xml_first_child_element(attr_set); attr != NULL;
-+             attr = __xml_next_element(attr)) {
-             const char *value = crm_element_value(attr, XML_NVPAIR_ATTR_VALUE);
-             const char *name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
- 
-@@ -538,7 +542,9 @@ unpack_nodes(xmlNode * xml_nodes, pe_working_set_t * data_set)
-     const char *type = NULL;
-     const char *score = NULL;
- 
--    for (xml_obj = __xml_first_child(xml_nodes); xml_obj != NULL; xml_obj = __xml_next_element(xml_obj)) {
-+    for (xml_obj = __xml_first_child_element(xml_nodes); xml_obj != NULL;
-+         xml_obj = __xml_next_element(xml_obj)) {
-+
-         if (crm_str_eq((const char *)xml_obj->name, XML_CIB_TAG_NODE, TRUE)) {
-             new_node = NULL;
- 
-@@ -620,7 +626,9 @@ unpack_remote_nodes(xmlNode * xml_resources, pe_working_set_t * data_set)
-     xmlNode *xml_obj = NULL;
- 
-     /* generate remote nodes from resource config before unpacking resources */
--    for (xml_obj = __xml_first_child(xml_resources); xml_obj != NULL; xml_obj = __xml_next_element(xml_obj)) {
-+    for (xml_obj = __xml_first_child_element(xml_resources); xml_obj != NULL;
-+         xml_obj = __xml_next_element(xml_obj)) {
-+
-         const char *new_node_id = NULL;
- 
-         /* first check if this is a bare metal remote node. Bare metal remote nodes
-@@ -659,7 +667,8 @@ unpack_remote_nodes(xmlNode * xml_resources, pe_working_set_t * data_set)
-         } else if (crm_str_eq((const char *)xml_obj->name, XML_CIB_TAG_GROUP, TRUE)) {
-             xmlNode *xml_obj2 = NULL;
-             /* search through a group to see if any of the primitive contain a remote node. */
--            for (xml_obj2 = __xml_first_child(xml_obj); xml_obj2 != NULL; xml_obj2 = __xml_next_element(xml_obj2)) {
-+            for (xml_obj2 = __xml_first_child_element(xml_obj); xml_obj2 != NULL;
-+                 xml_obj2 = __xml_next_element(xml_obj2)) {
- 
-                 new_node_id = expand_remote_rsc_meta(xml_obj2, xml_resources, data_set);
- 
-@@ -750,7 +759,9 @@ unpack_resources(xmlNode * xml_resources, pe_working_set_t * data_set)
-         g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str,
-                               destroy_tag);
- 
--    for (xml_obj = __xml_first_child(xml_resources); xml_obj != NULL; xml_obj = __xml_next_element(xml_obj)) {
-+    for (xml_obj = __xml_first_child_element(xml_resources); xml_obj != NULL;
-+         xml_obj = __xml_next_element(xml_obj)) {
-+
-         resource_t *new_rsc = NULL;
- 
-         if (crm_str_eq((const char *)xml_obj->name, XML_CIB_TAG_RSC_TEMPLATE, TRUE)) {
-@@ -808,7 +819,9 @@ unpack_tags(xmlNode * xml_tags, pe_working_set_t * data_set)
-     data_set->tags =
-         g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, destroy_tag);
- 
--    for (xml_tag = __xml_first_child(xml_tags); xml_tag != NULL; xml_tag = __xml_next_element(xml_tag)) {
-+    for (xml_tag = __xml_first_child_element(xml_tags); xml_tag != NULL;
-+         xml_tag = __xml_next_element(xml_tag)) {
-+
-         xmlNode *xml_obj_ref = NULL;
-         const char *tag_id = ID(xml_tag);
- 
-@@ -822,7 +835,9 @@ unpack_tags(xmlNode * xml_tags, pe_working_set_t * data_set)
-             continue;
-         }
- 
--        for (xml_obj_ref = __xml_first_child(xml_tag); xml_obj_ref != NULL; xml_obj_ref = __xml_next_element(xml_obj_ref)) {
-+        for (xml_obj_ref = __xml_first_child_element(xml_tag); xml_obj_ref != NULL;
-+             xml_obj_ref = __xml_next_element(xml_obj_ref)) {
-+
-             const char *obj_ref = ID(xml_obj_ref);
- 
-             if (crm_str_eq((const char *)xml_obj_ref->name, XML_CIB_TAG_OBJ_REF, TRUE) == FALSE) {
-@@ -916,7 +931,9 @@ unpack_tickets_state(xmlNode * xml_tickets, pe_working_set_t * data_set)
- {
-     xmlNode *xml_obj = NULL;
- 
--    for (xml_obj = __xml_first_child(xml_tickets); xml_obj != NULL; xml_obj = __xml_next_element(xml_obj)) {
-+    for (xml_obj = __xml_first_child_element(xml_tickets); xml_obj != NULL;
-+         xml_obj = __xml_next_element(xml_obj)) {
-+
-         if (crm_str_eq((const char *)xml_obj->name, XML_CIB_TAG_TICKET_STATE, TRUE) == FALSE) {
-             continue;
-         }
-@@ -1075,7 +1092,9 @@ unpack_node_loop(xmlNode * status, bool fence, pe_working_set_t * data_set)
-     bool changed = false;
-     xmlNode *lrm_rsc = NULL;
- 
--    for (xmlNode *state = __xml_first_child(status); state != NULL; state = __xml_next_element(state)) {
-+    for (xmlNode *state = __xml_first_child_element(status); state != NULL;
-+         state = __xml_next_element(state)) {
-+
-         const char *id = NULL;
-         const char *uname = NULL;
-         node_t *this_node = NULL;
-@@ -1174,7 +1193,9 @@ unpack_status(xmlNode * status, pe_working_set_t * data_set)
-             g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, destroy_ticket);
-     }
- 
--    for (state = __xml_first_child(status); state != NULL; state = __xml_next_element(state)) {
-+    for (state = __xml_first_child_element(status); state != NULL;
-+         state = __xml_next_element(state)) {
-+
-         if (crm_str_eq((const char *)state->name, XML_CIB_TAG_TICKETS, TRUE)) {
-             xmlNode *xml_tickets = state;
-             GHashTable *state_hash = NULL;
-@@ -2285,7 +2306,8 @@ unpack_lrm_rsc_state(node_t * node, xmlNode * rsc_entry, pe_working_set_t * data
-     op_list = NULL;
-     sorted_op_list = NULL;
- 
--    for (rsc_op = __xml_first_child(rsc_entry); rsc_op != NULL; rsc_op = __xml_next_element(rsc_op)) {
-+    for (rsc_op = __xml_first_child_element(rsc_entry); rsc_op != NULL;
-+         rsc_op = __xml_next_element(rsc_op)) {
-         if (crm_str_eq((const char *)rsc_op->name, XML_LRM_TAG_RSC_OP, TRUE)) {
-             op_list = g_list_prepend(op_list, rsc_op);
-         }
-@@ -2354,8 +2376,8 @@ static void
- handle_orphaned_container_fillers(xmlNode * lrm_rsc_list, pe_working_set_t * data_set)
- {
-     xmlNode *rsc_entry = NULL;
--    for (rsc_entry = __xml_first_child(lrm_rsc_list); rsc_entry != NULL;
--        rsc_entry = __xml_next_element(rsc_entry)) {
-+    for (rsc_entry = __xml_first_child_element(lrm_rsc_list); rsc_entry != NULL;
-+         rsc_entry = __xml_next_element(rsc_entry)) {
- 
-         resource_t *rsc;
-         resource_t *container;
-@@ -2400,7 +2422,7 @@ unpack_lrm_resources(node_t * node, xmlNode * lrm_rsc_list, pe_working_set_t * d
- 
-     crm_trace("Unpacking resources on %s", node->details->uname);
- 
--    for (rsc_entry = __xml_first_child(lrm_rsc_list); rsc_entry != NULL;
-+    for (rsc_entry = __xml_first_child_element(lrm_rsc_list); rsc_entry != NULL;
-          rsc_entry = __xml_next_element(rsc_entry)) {
- 
-         if (crm_str_eq((const char *)rsc_entry->name, XML_LRM_TAG_RESOURCE, TRUE)) {
-@@ -3490,7 +3512,8 @@ extract_operations(const char *node, const char *rsc, xmlNode * rsc_entry, gbool
-     op_list = NULL;
-     sorted_op_list = NULL;
- 
--    for (rsc_op = __xml_first_child(rsc_entry); rsc_op != NULL; rsc_op = __xml_next_element(rsc_op)) {
-+    for (rsc_op = __xml_first_child_element(rsc_entry);
-+         rsc_op != NULL; rsc_op = __xml_next_element(rsc_op)) {
-         if (crm_str_eq((const char *)rsc_op->name, XML_LRM_TAG_RSC_OP, TRUE)) {
-             crm_xml_add(rsc_op, "resource", rsc);
-             crm_xml_add(rsc_op, XML_ATTR_UNAME, node);
-@@ -3548,7 +3571,7 @@ find_operations(const char *rsc, const char *node, gboolean active_filter,
- 
-     xmlNode *node_state = NULL;
- 
--    for (node_state = __xml_first_child(status); node_state != NULL;
-+    for (node_state = __xml_first_child_element(status); node_state != NULL;
-          node_state = __xml_next_element(node_state)) {
- 
-         if (crm_str_eq((const char *)node_state->name, XML_CIB_TAG_STATE, TRUE)) {
-@@ -3580,7 +3603,7 @@ find_operations(const char *rsc, const char *node, gboolean active_filter,
-                 tmp = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE);
-                 tmp = find_xml_node(tmp, XML_LRM_TAG_RESOURCES, FALSE);
- 
--                for (lrm_rsc = __xml_first_child(tmp); lrm_rsc != NULL;
-+                for (lrm_rsc = __xml_first_child_element(tmp); lrm_rsc != NULL;
-                      lrm_rsc = __xml_next_element(lrm_rsc)) {
-                     if (crm_str_eq((const char *)lrm_rsc->name, XML_LRM_TAG_RESOURCE, TRUE)) {
- 
-diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c
-index 8eac2ce..67c1c3d 100644
---- a/lib/pengine/utils.c
-+++ b/lib/pengine/utils.c
-@@ -646,7 +646,7 @@ unpack_operation_on_fail(action_t * action)
- 
-         CRM_CHECK(action->rsc != NULL, return NULL);
- 
--        for (operation = __xml_first_child(action->rsc->ops_xml);
-+        for (operation = __xml_first_child_element(action->rsc->ops_xml);
-              operation && !value; operation = __xml_next_element(operation)) {
- 
-             if (!crm_str_eq((const char *)operation->name, "op", TRUE)) {
-@@ -685,7 +685,7 @@ find_min_interval_mon(resource_t * rsc, gboolean include_disabled)
-     xmlNode *op = NULL;
-     xmlNode *operation = NULL;
- 
--    for (operation = __xml_first_child(rsc->ops_xml); operation != NULL;
-+    for (operation = __xml_first_child_element(rsc->ops_xml); operation != NULL;
-          operation = __xml_next_element(operation)) {
- 
-         if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
-@@ -873,8 +873,12 @@ unpack_versioned_meta(xmlNode *versioned_meta, xmlNode *xml_obj, unsigned long l
-     xmlNode *attrs = NULL;
-     xmlNode *attr = NULL;
- 
--    for (attrs = __xml_first_child(versioned_meta); attrs != NULL; attrs = __xml_next_element(attrs)) {
--        for (attr = __xml_first_child(attrs); attr != NULL; attr = __xml_next_element(attr)) {
-+    for (attrs = __xml_first_child_element(versioned_meta); attrs != NULL;
-+         attrs = __xml_next_element(attrs)) {
-+
-+        for (attr = __xml_first_child_element(attrs); attr != NULL;
-+             attr = __xml_next_element(attr)) {
-+
-             const char *name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
-             const char *value = crm_element_value(attr, XML_NVPAIR_ATTR_VALUE);
- 
-@@ -1233,7 +1237,7 @@ find_rsc_op_entry_helper(resource_t * rsc, const char *key, gboolean include_dis
-     xmlNode *operation = NULL;
- 
-   retry:
--    for (operation = __xml_first_child(rsc->ops_xml); operation != NULL;
-+    for (operation = __xml_first_child_element(rsc->ops_xml); operation != NULL;
-          operation = __xml_next_element(operation)) {
-         if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
-             name = crm_element_value(operation, "name");
-diff --git a/pengine/allocate.c b/pengine/allocate.c
-index d600bbf..28f58b3 100644
---- a/pengine/allocate.c
-+++ b/pengine/allocate.c
-@@ -465,7 +465,9 @@ check_actions_for(xmlNode * rsc_entry, resource_t * rsc, node_t * node, pe_worki
-         DeleteRsc(rsc, node, FALSE, data_set);
-     }
- 
--    for (rsc_op = __xml_first_child(rsc_entry); rsc_op != NULL; rsc_op = __xml_next_element(rsc_op)) {
-+    for (rsc_op = __xml_first_child_element(rsc_entry); rsc_op != NULL;
-+         rsc_op = __xml_next_element(rsc_op)) {
-+
-         if (crm_str_eq((const char *)rsc_op->name, XML_LRM_TAG_RSC_OP, TRUE)) {
-             op_list = g_list_prepend(op_list, rsc_op);
-         }
-@@ -596,7 +598,7 @@ check_actions(pe_working_set_t * data_set)
- 
-     xmlNode *node_state = NULL;
- 
--    for (node_state = __xml_first_child(status); node_state != NULL;
-+    for (node_state = __xml_first_child_element(status); node_state != NULL;
-          node_state = __xml_next_element(node_state)) {
-         if (crm_str_eq((const char *)node_state->name, XML_CIB_TAG_STATE, TRUE)) {
-             id = crm_element_value(node_state, XML_ATTR_ID);
-@@ -619,8 +621,10 @@ check_actions(pe_working_set_t * data_set)
-             if (node->details->online || is_set(data_set->flags, pe_flag_stonith_enabled)) {
-                 xmlNode *rsc_entry = NULL;
- 
--                for (rsc_entry = __xml_first_child(lrm_rscs); rsc_entry != NULL;
-+                for (rsc_entry = __xml_first_child_element(lrm_rscs);
-+                     rsc_entry != NULL;
-                      rsc_entry = __xml_next_element(rsc_entry)) {
-+
-                     if (crm_str_eq((const char *)rsc_entry->name, XML_LRM_TAG_RESOURCE, TRUE)) {
- 
-                         if (xml_has_children(rsc_entry)) {
-diff --git a/pengine/constraints.c b/pengine/constraints.c
-index 6bf5adf..776eee1 100644
---- a/pengine/constraints.c
-+++ b/pengine/constraints.c
-@@ -1,5 +1,7 @@
- /*
-- * Copyright 2004-2018 Andrew Beekhof <andrew@beekhof.net>
-+ * Copyright 2004-2019 the Pacemaker project contributors
-+ *
-+ * The version control history for this file may have further details.
-  *
-  * This source code is licensed under the GNU General Public License version 2
-  * or later (GPLv2+) WITHOUT ANY WARRANTY.
-@@ -53,7 +55,7 @@ unpack_constraints(xmlNode * xml_constraints, pe_working_set_t * data_set)
-     xmlNode *xml_obj = NULL;
-     xmlNode *lifetime = NULL;
- 
--    for (xml_obj = __xml_first_child(xml_constraints); xml_obj != NULL;
-+    for (xml_obj = __xml_first_child_element(xml_constraints); xml_obj != NULL;
-          xml_obj = __xml_next_element(xml_obj)) {
-         const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
-         const char *tag = crm_element_name(xml_obj);
-@@ -489,7 +491,9 @@ expand_tags_in_sets(xmlNode * xml_obj, xmlNode ** expanded_xml, pe_working_set_t
-     new_xml = copy_xml(xml_obj);
-     cons_id = ID(new_xml);
- 
--    for (set = __xml_first_child(new_xml); set != NULL; set = __xml_next_element(set)) {
-+    for (set = __xml_first_child_element(new_xml); set != NULL;
-+         set = __xml_next_element(set)) {
-+
-         xmlNode *xml_rsc = NULL;
-         GListPtr tag_refs = NULL;
-         GListPtr gIter = NULL;
-@@ -498,7 +502,9 @@ expand_tags_in_sets(xmlNode * xml_obj, xmlNode ** expanded_xml, pe_working_set_t
-             continue;
-         }
- 
--        for (xml_rsc = __xml_first_child(set); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+        for (xml_rsc = __xml_first_child_element(set); xml_rsc != NULL;
-+             xml_rsc = __xml_next_element(xml_rsc)) {
-+
-             resource_t *rsc = NULL;
-             tag_t *tag = NULL;
-             const char *id = ID(xml_rsc);
-@@ -783,7 +789,7 @@ unpack_rsc_location(xmlNode * xml_obj, resource_t * rsc_lh, const char * role,
-     } else {
-         xmlNode *rule_xml = NULL;
- 
--        for (rule_xml = __xml_first_child(xml_obj); rule_xml != NULL;
-+        for (rule_xml = __xml_first_child_element(xml_obj); rule_xml != NULL;
-              rule_xml = __xml_next_element(rule_xml)) {
-             if (crm_str_eq((const char *)rule_xml->name, XML_TAG_RULE, TRUE)) {
-                 empty = FALSE;
-@@ -927,7 +933,9 @@ unpack_location_set(xmlNode * location, xmlNode * set, pe_working_set_t * data_s
-     role = crm_element_value(set, "role");
-     local_score = crm_element_value(set, XML_RULE_ATTR_SCORE);
- 
--    for (xml_rsc = __xml_first_child(set); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+    for (xml_rsc = __xml_first_child_element(set); xml_rsc != NULL;
-+         xml_rsc = __xml_next_element(xml_rsc)) {
-+
-         if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-             EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
-             unpack_rsc_location(location, resource, role, local_score, data_set, NULL);
-@@ -955,7 +963,9 @@ unpack_location(xmlNode * xml_obj, pe_working_set_t * data_set)
-         xml_obj = expanded_xml;
-     }
- 
--    for (set = __xml_first_child(xml_obj); set != NULL; set = __xml_next_element(set)) {
-+    for (set = __xml_first_child_element(xml_obj); set != NULL;
-+         set = __xml_next_element(set)) {
-+
-         if (crm_str_eq((const char *)set->name, XML_CONS_TAG_RSC_SET, TRUE)) {
-             any_sets = TRUE;
-             set = expand_idref(set, data_set->input);
-@@ -1628,7 +1638,9 @@ unpack_order_set(xmlNode * set, enum pe_order_kind parent_kind, resource_t ** rs
-         flags = get_asymmetrical_flags(local_kind);
-     }
- 
--    for (xml_rsc = __xml_first_child(set); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+    for (xml_rsc = __xml_first_child_element(set); xml_rsc != NULL;
-+         xml_rsc = __xml_next_element(xml_rsc)) {
-+
-         if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-             EXPAND_CONSTRAINT_IDREF(id, resource, ID(xml_rsc));
-             resources = g_list_append(resources, resource);
-@@ -1805,7 +1817,9 @@ order_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, enum pe_order_kin
-         free(task);
-         update_action_flags(unordered_action, pe_action_requires_any, __FUNCTION__, __LINE__);
- 
--        for (xml_rsc = __xml_first_child(set1); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+        for (xml_rsc = __xml_first_child_element(set1); xml_rsc != NULL;
-+             xml_rsc = __xml_next_element(xml_rsc)) {
-+
-             if (!crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                 continue;
-             }
-@@ -1818,7 +1832,9 @@ order_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, enum pe_order_kin
-                                 NULL, NULL, unordered_action,
-                                 pe_order_one_or_more | pe_order_implies_then_printed, data_set);
-         }
--        for (xml_rsc_2 = __xml_first_child(set2); xml_rsc_2 != NULL; xml_rsc_2 = __xml_next_element(xml_rsc_2)) {
-+        for (xml_rsc_2 = __xml_first_child_element(set2); xml_rsc_2 != NULL;
-+             xml_rsc_2 = __xml_next_element(xml_rsc_2)) {
-+
-             if (!crm_str_eq((const char *)xml_rsc_2->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                 continue;
-             }
-@@ -1840,7 +1856,9 @@ order_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, enum pe_order_kin
-             /* get the last one */
-             const char *rid = NULL;
- 
--            for (xml_rsc = __xml_first_child(set1); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+            for (xml_rsc = __xml_first_child_element(set1); xml_rsc != NULL;
-+                 xml_rsc = __xml_next_element(xml_rsc)) {
-+
-                 if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                     rid = ID(xml_rsc);
-                 }
-@@ -1849,7 +1867,9 @@ order_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, enum pe_order_kin
- 
-         } else {
-             /* get the first one */
--            for (xml_rsc = __xml_first_child(set1); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+            for (xml_rsc = __xml_first_child_element(set1); xml_rsc != NULL;
-+                 xml_rsc = __xml_next_element(xml_rsc)) {
-+
-                 if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                     EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
-                     break;
-@@ -1861,7 +1881,9 @@ order_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, enum pe_order_kin
-     if (crm_is_true(sequential_2)) {
-         if (invert == FALSE) {
-             /* get the first one */
--            for (xml_rsc = __xml_first_child(set2); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+            for (xml_rsc = __xml_first_child_element(set2); xml_rsc != NULL;
-+                 xml_rsc = __xml_next_element(xml_rsc)) {
-+
-                 if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                     EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc));
-                     break;
-@@ -1872,7 +1894,9 @@ order_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, enum pe_order_kin
-             /* get the last one */
-             const char *rid = NULL;
- 
--            for (xml_rsc = __xml_first_child(set2); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+            for (xml_rsc = __xml_first_child_element(set2); xml_rsc != NULL;
-+                 xml_rsc = __xml_next_element(xml_rsc)) {
-+
-                 if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                     rid = ID(xml_rsc);
-                 }
-@@ -1885,7 +1909,9 @@ order_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, enum pe_order_kin
-         new_rsc_order(rsc_1, action_1, rsc_2, action_2, flags, data_set);
- 
-     } else if (rsc_1 != NULL) {
--        for (xml_rsc = __xml_first_child(set2); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+        for (xml_rsc = __xml_first_child_element(set2); xml_rsc != NULL;
-+             xml_rsc = __xml_next_element(xml_rsc)) {
-+
-             if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc));
-                 new_rsc_order(rsc_1, action_1, rsc_2, action_2, flags, data_set);
-@@ -1895,7 +1921,9 @@ order_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, enum pe_order_kin
-     } else if (rsc_2 != NULL) {
-         xmlNode *xml_rsc = NULL;
- 
--        for (xml_rsc = __xml_first_child(set1); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+        for (xml_rsc = __xml_first_child_element(set1); xml_rsc != NULL;
-+             xml_rsc = __xml_next_element(xml_rsc)) {
-+
-             if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
-                 new_rsc_order(rsc_1, action_1, rsc_2, action_2, flags, data_set);
-@@ -1903,14 +1931,18 @@ order_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, enum pe_order_kin
-         }
- 
-     } else {
--        for (xml_rsc = __xml_first_child(set1); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+        for (xml_rsc = __xml_first_child_element(set1); xml_rsc != NULL;
-+             xml_rsc = __xml_next_element(xml_rsc)) {
-+
-             if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                 xmlNode *xml_rsc_2 = NULL;
- 
-                 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
- 
--                for (xml_rsc_2 = __xml_first_child(set2); xml_rsc_2 != NULL;
-+                for (xml_rsc_2 = __xml_first_child_element(set2);
-+                     xml_rsc_2 != NULL;
-                      xml_rsc_2 = __xml_next_element(xml_rsc_2)) {
-+
-                     if (crm_str_eq((const char *)xml_rsc_2->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                         EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc_2));
-                         new_rsc_order(rsc_1, action_1, rsc_2, action_2, flags, data_set);
-@@ -2078,7 +2110,9 @@ unpack_rsc_order(xmlNode * xml_obj, pe_working_set_t * data_set)
-         return FALSE;
-     }
- 
--    for (set = __xml_first_child(xml_obj); set != NULL; set = __xml_next_element(set)) {
-+    for (set = __xml_first_child_element(xml_obj); set != NULL;
-+         set = __xml_next_element(set)) {
-+
-         if (crm_str_eq((const char *)set->name, XML_CONS_TAG_RSC_SET, TRUE)) {
-             any_sets = TRUE;
-             set = expand_idref(set, data_set->input);
-@@ -2183,7 +2217,9 @@ unpack_colocation_set(xmlNode * set, int score, pe_working_set_t * data_set)
-         return TRUE;
- 
-     } else if (local_score >= 0 && safe_str_eq(ordering, "group")) {
--        for (xml_rsc = __xml_first_child(set); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+        for (xml_rsc = __xml_first_child_element(set); xml_rsc != NULL;
-+             xml_rsc = __xml_next_element(xml_rsc)) {
-+
-             if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
-                 if (with != NULL) {
-@@ -2197,7 +2233,9 @@ unpack_colocation_set(xmlNode * set, int score, pe_working_set_t * data_set)
-         }
-     } else if (local_score >= 0) {
-         resource_t *last = NULL;
--        for (xml_rsc = __xml_first_child(set); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+        for (xml_rsc = __xml_first_child_element(set); xml_rsc != NULL;
-+             xml_rsc = __xml_next_element(xml_rsc)) {
-+
-             if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
-                 if (last != NULL) {
-@@ -2216,14 +2254,18 @@ unpack_colocation_set(xmlNode * set, int score, pe_working_set_t * data_set)
-          * (i.e. that no one in the set can run with anyone else in the set)
-          */
- 
--        for (xml_rsc = __xml_first_child(set); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+        for (xml_rsc = __xml_first_child_element(set); xml_rsc != NULL;
-+             xml_rsc = __xml_next_element(xml_rsc)) {
-+
-             if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                 xmlNode *xml_rsc_with = NULL;
- 
-                 EXPAND_CONSTRAINT_IDREF(set_id, resource, ID(xml_rsc));
- 
--                for (xml_rsc_with = __xml_first_child(set); xml_rsc_with != NULL;
-+                for (xml_rsc_with = __xml_first_child_element(set);
-+                     xml_rsc_with != NULL;
-                      xml_rsc_with = __xml_next_element(xml_rsc_with)) {
-+
-                     if (crm_str_eq((const char *)xml_rsc_with->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                         if (safe_str_eq(resource->id, ID(xml_rsc_with))) {
-                             break;
-@@ -2258,7 +2300,9 @@ colocate_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, int score,
- 
-     if (sequential_1 == NULL || crm_is_true(sequential_1)) {
-         /* get the first one */
--        for (xml_rsc = __xml_first_child(set1); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+        for (xml_rsc = __xml_first_child_element(set1); xml_rsc != NULL;
-+             xml_rsc = __xml_next_element(xml_rsc)) {
-+
-             if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
-                 break;
-@@ -2270,7 +2314,9 @@ colocate_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, int score,
-         /* get the last one */
-         const char *rid = NULL;
- 
--        for (xml_rsc = __xml_first_child(set2); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+        for (xml_rsc = __xml_first_child_element(set2); xml_rsc != NULL;
-+             xml_rsc = __xml_next_element(xml_rsc)) {
-+
-             if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                 rid = ID(xml_rsc);
-             }
-@@ -2282,7 +2328,9 @@ colocate_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, int score,
-         rsc_colocation_new(id, NULL, score, rsc_1, rsc_2, role_1, role_2, data_set);
- 
-     } else if (rsc_1 != NULL) {
--        for (xml_rsc = __xml_first_child(set2); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+        for (xml_rsc = __xml_first_child_element(set2); xml_rsc != NULL;
-+             xml_rsc = __xml_next_element(xml_rsc)) {
-+
-             if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                 EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc));
-                 rsc_colocation_new(id, NULL, score, rsc_1, rsc_2, role_1, role_2, data_set);
-@@ -2290,7 +2338,9 @@ colocate_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, int score,
-         }
- 
-     } else if (rsc_2 != NULL) {
--        for (xml_rsc = __xml_first_child(set1); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+        for (xml_rsc = __xml_first_child_element(set1); xml_rsc != NULL;
-+             xml_rsc = __xml_next_element(xml_rsc)) {
-+
-             if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
-                 rsc_colocation_new(id, NULL, score, rsc_1, rsc_2, role_1, role_2, data_set);
-@@ -2298,14 +2348,18 @@ colocate_rsc_sets(const char *id, xmlNode * set1, xmlNode * set2, int score,
-         }
- 
-     } else {
--        for (xml_rsc = __xml_first_child(set1); xml_rsc != NULL; xml_rsc = __xml_next_element(xml_rsc)) {
-+        for (xml_rsc = __xml_first_child_element(set1); xml_rsc != NULL;
-+             xml_rsc = __xml_next_element(xml_rsc)) {
-+
-             if (crm_str_eq((const char *)xml_rsc->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                 xmlNode *xml_rsc_2 = NULL;
- 
-                 EXPAND_CONSTRAINT_IDREF(id, rsc_1, ID(xml_rsc));
- 
--                for (xml_rsc_2 = __xml_first_child(set2); xml_rsc_2 != NULL;
-+                for (xml_rsc_2 = __xml_first_child_element(set2);
-+                     xml_rsc_2 != NULL;
-                      xml_rsc_2 = __xml_next_element(xml_rsc_2)) {
-+
-                     if (crm_str_eq((const char *)xml_rsc_2->name, XML_TAG_RESOURCE_REF, TRUE)) {
-                         EXPAND_CONSTRAINT_IDREF(id, rsc_2, ID(xml_rsc_2));
-                         rsc_colocation_new(id, NULL, score, rsc_1, rsc_2, role_1, role_2, data_set);
-@@ -2537,7 +2591,9 @@ unpack_rsc_colocation(xmlNode * xml_obj, pe_working_set_t * data_set)
-         return FALSE;
-     }
- 
--    for (set = __xml_first_child(xml_obj); set != NULL; set = __xml_next_element(set)) {
-+    for (set = __xml_first_child_element(xml_obj); set != NULL;
-+         set = __xml_next_element(set)) {
-+
-         if (crm_str_eq((const char *)set->name, XML_CONS_TAG_RSC_SET, TRUE)) {
-             any_sets = TRUE;
-             set = expand_idref(set, data_set->input);
-@@ -2885,7 +2941,9 @@ unpack_rsc_ticket(xmlNode * xml_obj, pe_working_set_t * data_set)
-         return FALSE;
-     }
- 
--    for (set = __xml_first_child(xml_obj); set != NULL; set = __xml_next_element(set)) {
-+    for (set = __xml_first_child_element(xml_obj); set != NULL;
-+         set = __xml_next_element(set)) {
-+
-         if (crm_str_eq((const char *)set->name, XML_CONS_TAG_RSC_SET, TRUE)) {
-             any_sets = TRUE;
-             set = expand_idref(set, data_set->input);
-diff --git a/pengine/native.c b/pengine/native.c
-index 747cb10..10f1264 100644
---- a/pengine/native.c
-+++ b/pengine/native.c
-@@ -606,8 +606,9 @@ is_op_dup(resource_t * rsc, const char *name, const char *interval)
-     xmlNode *operation = NULL;
- 
-     CRM_ASSERT(rsc);
--    for (operation = __xml_first_child(rsc->ops_xml); operation != NULL;
-+    for (operation = __xml_first_child_element(rsc->ops_xml); operation != NULL;
-          operation = __xml_next_element(operation)) {
-+
-         if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
-             value = crm_element_value(operation, "name");
-             if (safe_str_neq(value, name)) {
-@@ -840,8 +841,10 @@ Recurring(resource_t * rsc, action_t * start, node_t * node, pe_working_set_t *
-         (node == NULL || node->details->maintenance == FALSE)) {
-         xmlNode *operation = NULL;
- 
--        for (operation = __xml_first_child(rsc->ops_xml); operation != NULL;
-+        for (operation = __xml_first_child_element(rsc->ops_xml);
-+             operation != NULL;
-              operation = __xml_next_element(operation)) {
-+
-             if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
-                 RecurringOp(rsc, start, node, operation, data_set);
-             }
-@@ -1064,8 +1067,10 @@ Recurring_Stopped(resource_t * rsc, action_t * start, node_t * node, pe_working_
-         (node == NULL || node->details->maintenance == FALSE)) {
-         xmlNode *operation = NULL;
- 
--        for (operation = __xml_first_child(rsc->ops_xml); operation != NULL;
-+        for (operation = __xml_first_child_element(rsc->ops_xml);
-+             operation != NULL;
-              operation = __xml_next_element(operation)) {
-+
-             if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
-                 RecurringOp_Stopped(rsc, start, node, operation, data_set);
-             }
-diff --git a/tools/crm_mon.c b/tools/crm_mon.c
-index 82e691e..ee9a3ef 100644
---- a/tools/crm_mon.c
-+++ b/tools/crm_mon.c
-@@ -1685,7 +1685,8 @@ print_rsc_history(FILE *stream, pe_working_set_t *data_set, node_t *node,
-     }
- 
-     /* Create a list of this resource's operations */
--    for (rsc_op = __xml_first_child(rsc_entry); rsc_op != NULL; rsc_op = __xml_next(rsc_op)) {
-+    for (rsc_op = __xml_first_child_element(rsc_entry); rsc_op != NULL;
-+         rsc_op = __xml_next_element(rsc_op)) {
-         if (crm_str_eq((const char *)rsc_op->name, XML_LRM_TAG_RSC_OP, TRUE)) {
-             op_list = g_list_append(op_list, rsc_op);
-         }
-@@ -1753,8 +1754,8 @@ print_node_history(FILE *stream, pe_working_set_t *data_set,
-         lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE);
- 
-         /* Print history of each of the node's resources */
--        for (rsc_entry = __xml_first_child(lrm_rsc); rsc_entry != NULL;
--             rsc_entry = __xml_next(rsc_entry)) {
-+        for (rsc_entry = __xml_first_child_element(lrm_rsc); rsc_entry != NULL;
-+             rsc_entry = __xml_next_element(rsc_entry)) {
- 
-             if (crm_str_eq((const char *)rsc_entry->name, XML_LRM_TAG_RESOURCE, TRUE)) {
-                 print_rsc_history(stream, data_set, node, rsc_entry, operations);
-@@ -1974,8 +1975,8 @@ print_node_summary(FILE *stream, pe_working_set_t * data_set, gboolean operation
-     }
- 
-     /* Print each node in the CIB status */
--    for (node_state = __xml_first_child(cib_status); node_state != NULL;
--         node_state = __xml_next(node_state)) {
-+    for (node_state = __xml_first_child_element(cib_status); node_state != NULL;
-+         node_state = __xml_next_element(node_state)) {
-         if (crm_str_eq((const char *)node_state->name, XML_CIB_TAG_STATE, TRUE)) {
-             print_node_history(stream, data_set, node_state, operations);
-         }
-@@ -4590,7 +4591,9 @@ static void crm_diff_update_v2(const char *event, xmlNode * msg)
-             xmlNode *state = NULL;
-             xmlNode *status = first_named_child(match, XML_CIB_TAG_STATUS);
- 
--            for (state = __xml_first_child(status); state != NULL; state = __xml_next(state)) {
-+            for (state = __xml_first_child_element(status); state != NULL;
-+                 state = __xml_next_element(state)) {
-+
-                 node = crm_element_value(state, XML_ATTR_UNAME);
-                 if (node == NULL) {
-                     node = ID(state);
-@@ -4601,7 +4604,9 @@ static void crm_diff_update_v2(const char *event, xmlNode * msg)
-         } else if(strcmp(name, XML_CIB_TAG_STATUS) == 0) {
-             xmlNode *state = NULL;
- 
--            for (state = __xml_first_child(match); state != NULL; state = __xml_next(state)) {
-+            for (state = __xml_first_child_element(match); state != NULL;
-+                 state = __xml_next_element(state)) {
-+
-                 node = crm_element_value(state, XML_ATTR_UNAME);
-                 if (node == NULL) {
-                     node = ID(state);
-diff --git a/tools/crm_resource_print.c b/tools/crm_resource_print.c
-index c4f96cd..906ea75 100644
---- a/tools/crm_resource_print.c
-+++ b/tools/crm_resource_print.c
-@@ -29,8 +29,8 @@ cli_resource_print_cts_constraints(pe_working_set_t * data_set)
-     xmlNode *lifetime = NULL;
-     xmlNode *cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, data_set->input);
- 
--    for (xml_obj = __xml_first_child(cib_constraints); xml_obj != NULL;
--         xml_obj = __xml_next(xml_obj)) {
-+    for (xml_obj = __xml_first_child_element(cib_constraints); xml_obj != NULL;
-+         xml_obj = __xml_next_element(xml_obj)) {
-         const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
- 
-         if (id == NULL) {
-diff --git a/tools/crmadmin.c b/tools/crmadmin.c
-index 920c262..c91807f 100644
---- a/tools/crmadmin.c
-+++ b/tools/crmadmin.c
-@@ -546,7 +546,9 @@ do_find_node_list(xmlNode * xml_node)
-     xmlNode *node = NULL;
-     xmlNode *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node);
- 
--    for (node = __xml_first_child(nodes); node != NULL; node = __xml_next(node)) {
-+    for (node = __xml_first_child_element(nodes); node != NULL;
-+         node = __xml_next_element(node)) {
-+
-         if (crm_str_eq((const char *)node->name, XML_CIB_TAG_NODE, TRUE)) {
- 
-             if (BASH_EXPORT) {
-diff --git a/tools/fake_transition.c b/tools/fake_transition.c
-index 5741fed..3cdd1f1 100644
---- a/tools/fake_transition.c
-+++ b/tools/fake_transition.c
-@@ -160,7 +160,9 @@ create_op(xmlNode * cib_resource, const char *task, int interval, int outcome)
-     op->t_rcchange = op->t_run;
- 
-     op->call_id = 0;
--    for (xop = __xml_first_child(cib_resource); xop != NULL; xop = __xml_next(xop)) {
-+    for (xop = __xml_first_child_element(cib_resource); xop != NULL;
-+         xop = __xml_next_element(xop)) {
-+
-         int tmp = 0;
- 
-         crm_element_value_int(xop, XML_LRM_ATTR_CALLID, &tmp);
--- 
-1.8.3.1
-
-
-From b05f992627cf468c815370010b5f9e2e58d122d5 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Mon, 29 Jul 2019 11:52:51 -0500
-Subject: [PATCH 68/96] Build: include,doc: ensure non-installed files are
- listed in makefiles
-
-This is especially important for headers, so they are distributed with
-"make dist" for building.
----
- cts/Makefile.am                |  2 ++
- include/Makefile.am            | 20 ++++++--------------
- include/crm/Makefile.am        |  2 ++
- include/crm/common/Makefile.am |  6 ++----
- 4 files changed, 12 insertions(+), 18 deletions(-)
-
-diff --git a/cts/Makefile.am b/cts/Makefile.am
-index bf56215..f3f169c 100644
---- a/cts/Makefile.am
-+++ b/cts/Makefile.am
-@@ -22,6 +22,8 @@ MAINTAINERCLEANFILES    = Makefile.in
- CLEANFILES      = LSBDummy HBDummy
- 
- EXTRA_DIST      = $(cts_SCRIPTS) $(cts_DATA)
-+noinst_SCRIPTS		= cluster_test		\
-+			  OCFIPraTest.py
- 
- ctsdir		= $(datadir)/$(PACKAGE)/tests/cts
- ctslibdir	= $(pyexecdir)/cts
-diff --git a/include/Makefile.am b/include/Makefile.am
-index f7f5714..e6444ea 100644
---- a/include/Makefile.am
-+++ b/include/Makefile.am
-@@ -1,24 +1,16 @@
- #
- # Copyright (C) 2004-2009 Andrew Beekhof
- #
--# This program is free software; you can redistribute it and/or
--# modify it under the terms of the GNU General Public License
--# as published by the Free Software Foundation; either version 2
--# of the License, or (at your option) any later version.
--# 
--# This program is distributed in the hope that it will be useful,
--# but WITHOUT ANY WARRANTY; without even the implied warranty of
--# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--# GNU General Public License for more details.
--# 
--# You should have received a copy of the GNU General Public License
--# along with this program; if not, write to the Free Software
--# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-+# This source code is licensed under the GNU General Public License version 2
-+# or later (GPLv2+) WITHOUT ANY WARRANTY.
- #
- 
- MAINTAINERCLEANFILES    = Makefile.in config.h.in
- 
--noinst_HEADERS	        = portability.h config.h crm_internal.h
-+noinst_HEADERS	        = config.h 			\
-+			  crm_internal.h		\
-+			  doxygen.h			\
-+			  portability.h
- pkginclude_HEADERS	= crm_config.h
- 
- SUBDIRS                 =  crm
-diff --git a/include/crm/Makefile.am b/include/crm/Makefile.am
-index 951d483..1226537 100644
---- a/include/crm/Makefile.am
-+++ b/include/crm/Makefile.am
-@@ -23,4 +23,6 @@ header_HEADERS		= attrd.h cib.h cluster.h compatibility.h crm.h \
- 			  error.h lrmd.h msg_xml.h services.h stonith-ng.h \
- 			  transition.h
- 
-+noinst_HEADERS		= lrmd_alerts_internal.h
-+
- SUBDIRS                 = common pengine cib fencing cluster
-diff --git a/include/crm/common/Makefile.am b/include/crm/common/Makefile.am
-index aacb6ff..7ed2360 100644
---- a/include/crm/common/Makefile.am
-+++ b/include/crm/common/Makefile.am
-@@ -13,8 +13,6 @@ headerdir=$(pkgincludedir)/crm/common
- 
- header_HEADERS = xml.h ipc.h util.h iso8601.h mainloop.h logging.h \
- 		 nvpair.h
--noinst_HEADERS = ipcs.h internal.h remote_internal.h xml_internal.h \
-+noinst_HEADERS = cib_secrets.h ipcs.h internal.h alerts_internal.h \
-+		 iso8601_internal.h remote_internal.h xml_internal.h \
- 		 ipc_internal.h
--if BUILD_CIBSECRETS
--noinst_HEADERS += cib_secrets.h
--endif
--- 
-1.8.3.1
-
-
-From af96be2dd205fecee505ee9c86d21ed6123c466e Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Wed, 26 Jun 2019 16:44:30 -0500
-Subject: [PATCH 69/96] Build: libpe_status,libpe_rules: make sure pkg-config
- files are built
-
----
- lib/Makefile.am | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/lib/Makefile.am b/lib/Makefile.am
-index d73bf2e..b00db48 100644
---- a/lib/Makefile.am
-+++ b/lib/Makefile.am
-@@ -25,9 +25,9 @@ target_LIBS		= $(LIBS:%=pacemaker-%.pc)
- 
- target_PACKAGE		= pacemaker.pc
- 
--all-local: $(target_LIBS) $(target_PACKAGE)
-+all-local: $(target_LIBS) $(target_PACKAGE) pacemaker-pe_rules.pc pacemaker-pe_status.pc
- 
--install-exec-local: $(target_LIBS) $(target_PACKAGE)
-+install-exec-local: $(target_LIBS) $(target_PACKAGE) pacemaker-pe_rules.pc pacemaker-pe_status.pc
- 	$(INSTALL) -d $(DESTDIR)/$(libdir)/pkgconfig
- 	$(INSTALL) -m 644 $(target_LIBS) $(target_PACKAGE) $(DESTDIR)/$(libdir)/pkgconfig
- 
--- 
-1.8.3.1
-
-
-From 941de1727bd07c2cc3f30f1f5508370896a8de53 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 22 Aug 2019 13:06:39 -0500
-Subject: [PATCH 70/96] Build: lib: reorganize makefile
-
-... for readability and simplicity. This takes care of a minor issue where not
-all installed files were uninstalled.
----
- lib/Makefile.am | 19 +++++++++----------
- 1 file changed, 9 insertions(+), 10 deletions(-)
-
-diff --git a/lib/Makefile.am b/lib/Makefile.am
-index b00db48..617008a 100644
---- a/lib/Makefile.am
-+++ b/lib/Makefile.am
-@@ -17,26 +17,25 @@
- #
- MAINTAINERCLEANFILES    = Makefile.in
- 
--EXTRA_DIST		= pacemaker.pc.in $(target_LIBS:%=%.in)
--
- LIBS			= cib lrmd service pengine fencing cluster
- 
--target_LIBS		= $(LIBS:%=pacemaker-%.pc)
-+PC_FILES		= $(LIBS:%=pacemaker-%.pc)	\
-+			  pacemaker.pc
- 
--target_PACKAGE		= pacemaker.pc
-+EXTRA_DIST		= $(PC_FILES:%=%.in)
- 
--all-local: $(target_LIBS) $(target_PACKAGE) pacemaker-pe_rules.pc pacemaker-pe_status.pc
-+all-local: $(PC_FILES)
- 
--install-exec-local: $(target_LIBS) $(target_PACKAGE) pacemaker-pe_rules.pc pacemaker-pe_status.pc
-+install-exec-local: $(PC_FILES)
- 	$(INSTALL) -d $(DESTDIR)/$(libdir)/pkgconfig
--	$(INSTALL) -m 644 $(target_LIBS) $(target_PACKAGE) $(DESTDIR)/$(libdir)/pkgconfig
-+	$(INSTALL) -m 644 $(PC_FILES) $(DESTDIR)/$(libdir)/pkgconfig
- 
- uninstall-local:
--	cd $(DESTDIR)/$(libdir)/pkgconfig && rm -f $(target_LIBS) $(target_PACKAGE)
--	rmdir $(DESTDIR)/$(libdir)/pkgconfig 2> /dev/null || :
-+	-cd $(DESTDIR)/$(libdir)/pkgconfig && rm -f $(PC_FILES)
-+	-rmdir $(DESTDIR)/$(libdir)/pkgconfig 2> /dev/null
- 
- clean-local:
--	rm -f *.pc
-+	rm -f $(PC_FILES)
- 
- ## Subdirectories...
- SUBDIRS	= gnu common pengine transition cib services fencing lrmd cluster
--- 
-1.8.3.1
-
-
-From 021dadf515c547a82dd00ad33dded91f9f8dac10 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Tue, 9 Jan 2018 18:27:09 -0600
-Subject: [PATCH 71/96] Build: www: update makefiles for website restructuring
-
----
- GNUmakefile                                | 10 +++++-----
- abi-check                                  |  7 +++++--
- doc/Makefile.am                            |  6 +++---
- doc/Pacemaker_Explained/en-US/Ch-Intro.txt |  4 +++-
- 4 files changed, 16 insertions(+), 11 deletions(-)
-
-diff --git a/GNUmakefile b/GNUmakefile
-index b2d5a28..352903f 100644
---- a/GNUmakefile
-+++ b/GNUmakefile
-@@ -341,17 +341,17 @@ global: clean-generic
- 
- global-upload: global
- 	htags -sanhIT
--	rsync $(RSYNC_OPTS) HTML/ "$(RSYNC_DEST)/global/$(PACKAGE)/$(TAG)"
-+	rsync $(RSYNC_OPTS) HTML/ "$(RSYNC_DEST)/$(PACKAGE)/global/$(TAG)/"
- 
- %.8.html: %.8
- 	echo groff -mandoc `man -w ./$<` -T html > $@
- 	groff -mandoc `man -w ./$<` -T html > $@
--	rsync $(RSYNC_OPTS) "$@" "$(RSYNC_DEST)/man/$(PACKAGE)/"
-+	rsync $(RSYNC_OPTS) "$@" "$(RSYNC_DEST)/$(PACKAGE)/man/"
- 
- %.7.html: %.7
- 	echo groff -mandoc `man -w ./$<` -T html > $@
- 	groff -mandoc `man -w ./$<` -T html > $@
--	rsync $(RSYNC_OPTS) "$@" "$(RSYNC_DEST)/man/$(PACKAGE)/"
-+	rsync $(RSYNC_OPTS) "$@" "$(RSYNC_DEST)/$(PACKAGE)/man/"
- 
- manhtml-upload: all
- 	find . -name "[a-z]*.[78]" -exec make \{\}.html \;
-@@ -360,12 +360,12 @@ doxygen: Doxyfile
- 	doxygen Doxyfile
- 
- doxygen-upload: doxygen
--	rsync $(RSYNC_OPTS) doc/api/html/ "$(RSYNC_DEST)/doxygen/$(PACKAGE)/$(TAG)"
-+	rsync $(RSYNC_OPTS) doc/api/html/ "$(RSYNC_DEST)/$(PACKAGE)/doxygen/$(TAG)/"
- 
- abi:
- 	./abi-check pacemaker $(LAST_RELEASE) $(TAG)
- abi-www:
--	./abi-check -u pacemaker $(LAST_RELEASE) $(TAG)
-+	export RSYNC_DEST=$(RSYNC_DEST); ./abi-check -u pacemaker $(LAST_RELEASE) $(TAG)
- 
- www:	manhtml-upload global-upload doxygen-upload
- 	make RSYNC_DEST=$(RSYNC_DEST) -C doc www
-diff --git a/abi-check b/abi-check
-index d28192b..18002c8 100755
---- a/abi-check
-+++ b/abi-check
-@@ -1,6 +1,9 @@
- #!/bin/bash
--UPLOAD=0
- 
-+# toplevel rsync destination for www targets (without trailing slash)
-+: ${RSYNC_DEST:=root@www.clusterlabs.org:/var/www/html}
-+
-+UPLOAD=0
- if [ $1 = "-u" ]; then
-     UPLOAD=1; shift
- fi
-@@ -98,6 +101,6 @@ if [ $# = 2 ]; then
- 	-d2 abi_dumps/${PACKAGE}/${PACKAGE}_${V2}.abi.tar.gz
- 
-     if [ $UPLOAD = 1 -a -d compat_reports/pacemaker/${V1}_to_${V2} ]; then
--	rsync -azxlSD --progress compat_reports/pacemaker/${V1}_to_${V2} root@www.clusterlabs.org:/var/www/html/abi/pacemaker/
-+        rsync -azxlSD --progress compat_reports/pacemaker/${V1}_to_${V2} ${RSYNC_DEST}/${PACKAGE}/abi/
-     fi
- fi
-diff --git a/doc/Makefile.am b/doc/Makefile.am
-index 8b04007..98ae680 100644
---- a/doc/Makefile.am
-+++ b/doc/Makefile.am
-@@ -29,7 +29,7 @@ docbook		=	Clusters_from_Scratch		\
- doc_DATA	= $(ascii) $(generated_docs)
- 
- # toplevel rsync destination for www targets (without trailing slash)
--RSYNC_DEST      ?= root@www.clusterlabs.org:/var/www/html/
-+RSYNC_DEST      ?= root@www.clusterlabs.org:/var/www/html
- 
- # recursive, preserve symlinks/permissions/times, verbose, compress,
- # don't cross filesystems, sparse, show progress
-@@ -294,7 +294,7 @@ pdf:
- 
- www: clean-local $(generated_docs) $(ascii)
- 	make www-cli
--	rsync $(RSYNC_OPTS) $(generated_docs) $(ascii) $(asciiman) "$(RSYNC_DEST)/doc/"
-+	rsync $(RSYNC_OPTS) $(generated_docs) $(ascii) $(asciiman) "$(RSYNC_DEST)/$(PACKAGE)/doc/"
- 
- www-pcs: www-cli
- 
-@@ -313,7 +313,7 @@ if BUILD_DOCBOOK
- 			mv $$book/publish/$$lang/Pacemaker/$(PACKAGE_SERIES)-$(ASCIIDOC_CLI_TYPE)/epub/$$book/Pacemaker-1.1{-$(ASCIIDOC_CLI_TYPE),}-$$book-$$lang.epub;	\
- 			mv $$book/publish/$$lang/Pacemaker/$(PACKAGE_SERIES)-$(ASCIIDOC_CLI_TYPE)/pdf/$$book/Pacemaker-1.1{-$(ASCIIDOC_CLI_TYPE),}-$$book-$$lang.pdf;	\
- 		done;											\
--		rsync $(RSYNC_OPTS) $$book/publish/* "$(RSYNC_DEST)/doc/";				\
-+		rsync $(RSYNC_OPTS) $$book/publish/* "$(RSYNC_DEST)/$(PACKAGE)/doc/";				\
- 		sed -i.sed 's@version:.*@version: $(PACKAGE_SERIES)@' $$book/publican.cfg;		\
- 	done
- endif
-diff --git a/doc/Pacemaker_Explained/en-US/Ch-Intro.txt b/doc/Pacemaker_Explained/en-US/Ch-Intro.txt
-index e610651..dad0635 100644
---- a/doc/Pacemaker_Explained/en-US/Ch-Intro.txt
-+++ b/doc/Pacemaker_Explained/en-US/Ch-Intro.txt
-@@ -16,7 +16,9 @@ Additionally, this document is NOT a step-by-step how-to guide for
- configuring a specific clustering scenario.
- 
- Although such guides exist,
--footnote:[For example, see the http://www.clusterlabs.org/doc/[Clusters from Scratch] guide.]
-+footnote:[
-+For example, see https://www.clusterlabs.org/pacemaker/doc/[Clusters from Scratch]
-+]
- the purpose of this document is to provide an understanding of the building
- blocks that can be used to construct any type of Pacemaker cluster.
- 
--- 
-1.8.3.1
-
-
-From 3d7c882c22bcb4f68a549297c11288aacd54fad9 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 11 Jan 2018 12:45:33 -0600
-Subject: [PATCH 72/96] Build: www: get rid of ASCIIDOC_CLI_TYPE
-
-Only pcs has been supported for a long while, and it only ever applied to
-"Clusters from Scratch" anyway, while being applied to all books.
----
- doc/Makefile.am | 28 ++++++++--------------------
- 1 file changed, 8 insertions(+), 20 deletions(-)
-
-diff --git a/doc/Makefile.am b/doc/Makefile.am
-index 98ae680..a00b704 100644
---- a/doc/Makefile.am
-+++ b/doc/Makefile.am
-@@ -39,7 +39,6 @@ publican_docs   =
- generated_docs	=
- generated_mans	=
- 
--ASCIIDOC_CLI_TYPE := pcs
- 
- # What formats to build: pdf,html,html-single,html-desktop,epub
- DOCBOOK_FORMATS := html-desktop
-@@ -290,33 +289,22 @@ brand-rpm-install: brand-rpm-build
- 	find publican-clusterlabs -name "*.noarch.rpm" -exec sudo rpm -Uvh --force \{\} \;
- 
- pdf:
--	make DOCBOOK_FORMATS="pdf" ASCIIDOC_CLI_TYPE=$(ASCIIDOC_CLI_TYPE) all-local
-+	make DOCBOOK_FORMATS="pdf" all-local
- 
- www: clean-local $(generated_docs) $(ascii)
--	make www-cli
--	rsync $(RSYNC_OPTS) $(generated_docs) $(ascii) $(asciiman) "$(RSYNC_DEST)/$(PACKAGE)/doc/"
--
--www-pcs: www-cli
--
--www-cli:
--	for book in $(docbook); do 										\
--		sed -i.sed 's@brand:.*@brand: clusterlabs@' $$book/publican.cfg;				\
--		sed -i.sed 's@version:.*@version: $(PACKAGE_SERIES)-$(ASCIIDOC_CLI_TYPE)@' $$book/publican.cfg;	\
-+	for book in $(docbook); do 							\
-+		sed -i.sed 's@^brand:.*@brand: clusterlabs@' $$book/publican.cfg;	\
- 	done
--	make DOCBOOK_FORMATS="pdf,html,html-single,epub" DOCBOOK_LANGS="$(UPLOAD_LANGS)" ASCIIDOC_CLI_TYPE=$(ASCIIDOC_CLI_TYPE) all-local
--	echo Uploading current $(PACKAGE_SERIES)-$(ASCIIDOC_CLI_TYPE) documentation set to clusterlabs.org
-+	make DOCBOOK_FORMATS="pdf,html,html-single,epub" DOCBOOK_LANGS="$(UPLOAD_LANGS)" all-local
-+	echo Uploading current $(PACKAGE_SERIES) documentation set to clusterlabs.org
- if BUILD_DOCBOOK
- 	for book in $(docbook); do 									\
- 		echo Uploading $$book...;								\
--		echo "Generated on `date` from version: $(shell git log --pretty="format:%h %d" -n 1)" >> $$book/publish/build-$(PACKAGE_SERIES)-$(ASCIIDOC_CLI_TYPE).txt;	\
--		for lang in `ls -1 $$book/publish | grep [a-z][a-z]-[A-Z][A-Z]`; do							\
--			mv $$book/publish/$$lang/Pacemaker/$(PACKAGE_SERIES)-$(ASCIIDOC_CLI_TYPE)/epub/$$book/Pacemaker-1.1{-$(ASCIIDOC_CLI_TYPE),}-$$book-$$lang.epub;	\
--			mv $$book/publish/$$lang/Pacemaker/$(PACKAGE_SERIES)-$(ASCIIDOC_CLI_TYPE)/pdf/$$book/Pacemaker-1.1{-$(ASCIIDOC_CLI_TYPE),}-$$book-$$lang.pdf;	\
--		done;											\
--		rsync $(RSYNC_OPTS) $$book/publish/* "$(RSYNC_DEST)/$(PACKAGE)/doc/";				\
--		sed -i.sed 's@version:.*@version: $(PACKAGE_SERIES)@' $$book/publican.cfg;		\
-+		echo "Generated on `date` from version: $(shell git log --pretty="format:%h %d" -n 1)" >> $$book/publish/build-$(PACKAGE_SERIES).txt;	\
-+		rsync $(RSYNC_OPTS) $$book/publish/* "$(RSYNC_DEST)/$(PACKAGE)/doc/";			\
- 	done
- endif
-+	rsync $(RSYNC_OPTS) $(generated_docs) $(ascii) "$(RSYNC_DEST)/$(PACKAGE)/doc/"
- 
- clean-local:
- 	-rm -f $(PNGS_GENERATED)
--- 
-1.8.3.1
-
-
-From c4b5a54893334bc11a7ceec31b780f664d315629 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
-Date: Tue, 7 Aug 2018 18:10:42 +0200
-Subject: [PATCH 73/96] Build: Makefile.common: use determined symbolic
- reference for AsciiDoc
-
-Also fix a typo and drop attribute passing relevant to crm/pcs duality
-in the former documentation, something finally ditched in 81b00e6da
-that just missed this last reference behind.
----
- Makefile.common | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/Makefile.common b/Makefile.common
-index 469417f..feb68bd 100644
---- a/Makefile.common
-+++ b/Makefile.common
-@@ -52,11 +52,11 @@ endif
- # Build docbook from asciidoc because XML is a PITA to edit
- #
- # Build each chapter as a book (since the numbering isn't right for
--# articles and only books can have appendicies) and then strip out the
-+# articles and only books can have appendices) and then strip out the
- # bits we don't want/need
- #
- %.xml:  %.txt
--	$(AM_V_ASCII)asciidoc -b docbook -a cli_name=$(ASCIIDOC_CLI_TYPE) -a $(ASCIIDOC_CLI_TYPE)=true -d book -o $@ $<
-+	$(AM_V_ASCII)$(ASCIIDOC) -b docbook -d book -o $@ $<
- 	$(AM_V_at)sed -i 's///' $@
- 	$(AM_V_at)sed -i 's/
//' $@                 # Fix line endings
- 	$(AM_V_at)sed -i 's/\ lang="en"//' $@        # Never specify a language in the chapters
--- 
-1.8.3.1
-
-
-From 242bd026c7b5e815c8b5b135341837bb33a9a827 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
-Date: Mon, 20 Aug 2018 20:29:27 +0200
-Subject: [PATCH 74/96] Build: Makefile.common: avoid using verbatim control
- characters
-
-This is not a good practise, since it poses an imminent risk of
-"deceptive display (rendering)" at various places, especially
-tools that may be used for change reviews, incl. GitHub[1].
-
-When at it, arrange for periodical CI to capture undesired
-occurrences of such characters in the code base, and related
-to that, obtain pristine LGPLv2.1 license text anew using
-
-  curl  https://www.gnu.org/licenses/lgpl-2.1.txt \
-    | tr -d '\f' > licenses/LGPLv2.1
-
-so that embedded "form feed" characters are got rid of (beside
-that, also tabulators are changed into spaces, which is how this
-authoritative server currently carries it).
-
-[1] https://github.com/isaacs/github/issues/1329
----
- Makefile.common   |  5 ++---
- licenses/LGPLv2.1 | 32 +++++++++++++++-----------------
- 2 files changed, 17 insertions(+), 20 deletions(-)
-
-diff --git a/Makefile.common b/Makefile.common
-index feb68bd..e50441b 100644
---- a/Makefile.common
-+++ b/Makefile.common
-@@ -56,9 +56,8 @@ endif
- # bits we don't want/need
- #
- %.xml:  %.txt
--	$(AM_V_ASCII)$(ASCIIDOC) -b docbook -d book -o $@ $<
--	$(AM_V_at)sed -i 's///' $@
--	$(AM_V_at)sed -i 's/
//' $@                 # Fix line endings
-+	$(AM_V_ASCII)$(ASCIIDOC) -b docbook -d book -o $@-t $<
-+	$(AM_V_at)tr -d '\036\r' <$@-t >$@; rm "$@-t"# Fix line endings
- 	$(AM_V_at)sed -i 's/\ lang="en"//' $@        # Never specify a language in the chapters
- 	$(AM_V_at)sed -i 's/simpara/para/g' $@       # publican doesn't correctly render footnotes with simpara
- 	$(AM_V_at)sed -i 's/.*<date>.*//g' $@	       # Remove dangling tag
-diff --git a/licenses/LGPLv2.1 b/licenses/LGPLv2.1
-index 602bfc9..e5ab03e 100644
---- a/licenses/LGPLv2.1
-+++ b/licenses/LGPLv2.1
-@@ -1,5 +1,5 @@
--		  GNU LESSER GENERAL PUBLIC LICENSE
--		       Version 2.1, February 1999
-+                  GNU LESSER GENERAL PUBLIC LICENSE
-+                       Version 2.1, February 1999
- 
-  Copyright (C) 1991, 1999 Free Software Foundation, Inc.
-  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-@@ -10,7 +10,7 @@
-  as the successor of the GNU Library Public License, version 2, hence
-  the version number 2.1.]
- 
--			    Preamble
-+                            Preamble
- 
-   The licenses for most software are designed to take away your
- freedom to share and change it.  By contrast, the GNU General Public
-@@ -55,7 +55,7 @@ modified by someone else and passed on, the recipients should know
- that what they have is not the original version, so that the original
- author's reputation will not be affected by problems that might be
- introduced by others.
--
-+
-   Finally, software patents pose a constant threat to the existence of
- any free program.  We wish to make sure that a company cannot
- effectively restrict the users of a free program by obtaining a
-@@ -111,8 +111,8 @@ modification follow.  Pay close attention to the difference between a
- "work based on the library" and a "work that uses the library".  The
- former contains code derived from the library, whereas the latter must
- be combined with the library in order to run.
--
--		  GNU LESSER GENERAL PUBLIC LICENSE
-+
-+                  GNU LESSER GENERAL PUBLIC LICENSE
-    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
- 
-   0. This License Agreement applies to any software library or other
-@@ -158,7 +158,7 @@ Library.
-   You may charge a fee for the physical act of transferring a copy,
- and you may at your option offer warranty protection in exchange for a
- fee.
--
-+
-   2. You may modify your copy or copies of the Library or any portion
- of it, thus forming a work based on the Library, and copy and
- distribute such modifications or work under the terms of Section 1
-@@ -216,7 +216,7 @@ instead of to this License.  (If a newer version than version 2 of the
- ordinary GNU General Public License has appeared, then you can specify
- that version instead if you wish.)  Do not make any other change in
- these notices.
--
-+
-   Once this change is made in a given copy, it is irreversible for
- that copy, so the ordinary GNU General Public License applies to all
- subsequent copies and derivative works made from that copy.
-@@ -267,7 +267,7 @@ Library will still fall under Section 6.)
- distribute the object code for the work under the terms of Section 6.
- Any executables containing that work also fall under Section 6,
- whether or not they are linked directly with the Library itself.
--
-+
-   6. As an exception to the Sections above, you may also combine or
- link a "work that uses the Library" with the Library to produce a
- work containing portions of the Library, and distribute that work
-@@ -329,7 +329,7 @@ restrictions of other proprietary libraries that do not normally
- accompany the operating system.  Such a contradiction means you cannot
- use both them and the Library together in an executable that you
- distribute.
--
-+
-   7. You may place library facilities that are a work based on the
- Library side-by-side in a single library together with other library
- facilities not covered by this License, and distribute such a combined
-@@ -370,7 +370,7 @@ subject to these terms and conditions.  You may not impose any further
- restrictions on the recipients' exercise of the rights granted herein.
- You are not responsible for enforcing compliance by third parties with
- this License.
--
-+
-   11. If, as a consequence of a court judgment or allegation of patent
- infringement or for any other reason (not limited to patent issues),
- conditions are imposed on you (whether by court order, agreement or
-@@ -422,7 +422,7 @@ conditions either of that version or of any later version published by
- the Free Software Foundation.  If the Library does not specify a
- license version number, you may choose any version ever published by
- the Free Software Foundation.
--
-+
-   14. If you wish to incorporate parts of the Library into other free
- programs whose distribution conditions are incompatible with these,
- write to the author to ask for permission.  For software which is
-@@ -432,7 +432,7 @@ decision will be guided by the two goals of preserving the free status
- of all derivatives of our free software and of promoting the sharing
- and reuse of software generally.
- 
--			    NO WARRANTY
-+                            NO WARRANTY
- 
-   15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
- WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-@@ -455,8 +455,8 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
- SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- DAMAGES.
- 
--		     END OF TERMS AND CONDITIONS
--
-+                     END OF TERMS AND CONDITIONS
-+
-            How to Apply These Terms to Your New Libraries
- 
-   If you develop a new library, and you want it to be of the greatest
-@@ -500,5 +500,3 @@ necessary.  Here is a sample; alter the names:
-   Ty Coon, President of Vice
- 
- That's all there is to it!
--
--
--- 
-1.8.3.1
-
-
-From 73fa92b8d95b2f16cf8257504b5a7e5c8b6c5099 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
-Date: Tue, 7 Aug 2018 21:45:51 +0200
-Subject: [PATCH 75/96] Build: add support for AsciiDoc's successor,
- Asciidoctor
-
-Everything seems to be built just fine when Asciidoctor is present in
-the build environment and AsciiDoc is not (as it takes the precedence),
-except for Pacemake Explained that needs some more tweaking to be
-usable with Asciidoctor:
-
-> Ch-Options.xml:125: validity error : Element emphasis is not declared in literal list of possible children
-> Ch-Options.xml:419: validity error : Element xref is not declared in literal list of possible children
-> Ch-Options.xml:716: validity error : Element xref is not declared in literal list of possible children
-> Ch-Options.xml:824: validity error : Element emphasis is not declared in literal list of possible children
-> Ch-Options.xml:860: validity error : Element emphasis is not declared in literal list of possible children
-> Ch-Options.xml:896: validity error : Element emphasis is not declared in literal list of possible children
-> Ch-Resources.xml:608: validity error : Element xref is not declared in literal list of possible children
-> Ch-Constraints.xml:525: validity error : Element xref is not declared in literal list of possible children
-> Ch-Advanced-Options.xml:662: validity error : Element xref is not declared in literal list of possible children
-> Ch-Stonith.xml:153: validity error : Element emphasis is not declared in literal list of possible children
-> Ch-Stonith.xml:153: validity error : Element emphasis is not declared in literal list of possible children
-
-Also remove superfluous "inverse grep" conditionalizing amounting to
-a thinko how that's supposed to work.  Another logical problem was with
-"it's OK to generate the final product of the makefile's target early
-and adjust it in-place in the steps of the recipe to follow" broken
-assumption.
----
- INSTALL.md      |  2 +-
- Makefile.common | 31 ++++++++++++++++++++-----------
- configure.ac    |  7 ++++---
- doc/Makefile.am |  6 +++++-
- 4 files changed, 30 insertions(+), 16 deletions(-)
-
-diff --git a/INSTALL.md b/INSTALL.md
-index f02b589..8671ac2 100644
---- a/INSTALL.md
-+++ b/INSTALL.md
-@@ -29,7 +29,7 @@
- * libesmtp-devel (crm_mon --mail-to option)
- * lm_sensors-devel (crm_mon --snmp-traps option)
- * net-snmp-devel (crm_mon --snmp-traps option)
--* asciidoc (documentation)
-+* asciidoc or asciidoctor (documentation)
- * help2man (documentation)
- * publican (documentation)
- * inkscape (documentation)
-diff --git a/Makefile.common b/Makefile.common
-index e50441b..0b06ec4 100644
---- a/Makefile.common
-+++ b/Makefile.common
-@@ -55,17 +55,26 @@ endif
- # articles and only books can have appendices) and then strip out the
- # bits we don't want/need
- #
-+# XXX Sequence of tr/sed commands should be replaced with a single XSLT
-+#
- %.xml:  %.txt
--	$(AM_V_ASCII)$(ASCIIDOC) -b docbook -d book -o $@-t $<
--	$(AM_V_at)tr -d '\036\r' <$@-t >$@; rm "$@-t"# Fix line endings
--	$(AM_V_at)sed -i 's/\ lang="en"//' $@        # Never specify a language in the chapters
--	$(AM_V_at)sed -i 's/simpara/para/g' $@       # publican doesn't correctly render footnotes with simpara
--	$(AM_V_at)sed -i 's/.*<date>.*//g' $@	       # Remove dangling tag
--	$(AM_V_at)sed -i 's/.*preface>//g' $@        # Remove preface elements
--	$(AM_V_at)sed -i 's:<title></title>::g' $@   # Remove empty title
--	$(AM_V_at)sed -i 's/chapter/section/g' $@    # Chapters become sections, so that books can become chapters
--	$(AM_V_at)sed -i 's/<.*bookinfo.*>//g' $@    # Strip out bookinfo, we don't need it
--	-grep -qis "<appendix" $@ && sed -i 's/.*book>//' $@         # We just want the appendix tag
--	-grep -vqis "<appendix" $@ && sed -i 's/book>/chapter>/g' $@ # Rename to chapter
-+if IS_ASCIIDOC
-+	$(AM_V_ASCII)$(ASCIIDOC_CONV) -b docbook -d book -o $@-tt $<
-+else
-+	$(AM_V_ASCII)$(ASCIIDOC_CONV) -b docbook45 -d book -o $@-tt $<
-+endif
-+	$(AM_V_at)tr -d '\036\r' <$@-tt >$@-t; rm -f $@-tt  # Fix line endings
-+	$(AM_V_at)sed -i 's/\ lang="en"//' $@-t      # Never specify a language in the chapters
-+	$(AM_V_at)sed -i 's/simpara/para/g' $@-t     # publican doesn't correctly render footnotes with simpara
-+	$(AM_V_at)sed -i 's/.*<date>.*//g' $@-t      # Remove dangling tag
-+	$(AM_V_at)sed -i 's/.*preface>//g' $@-t      # Remove preface elements
-+	$(AM_V_at)sed -i 's:<title></title>::g' $@-t # Remove empty title
-+	$(AM_V_at)sed -i 's/chapter/section/g' $@-t  # Chapters become sections, so that books can become chapters
-+	$(AM_V_at)sed -i 's/<.*bookinfo.*>//g' $@-t  # Strip out bookinfo, we don't need it
-+	$(AM_V_at)! grep -q "<appendix" $@-t || sed -i \
-+	  's/.*book>//;tb;bf;:b;N;s/.*<title>.*<\/title>.*//;tb;/<appendix/{:i;n;/<\/appendix/{p;d};bi};bb;:f;p;d' \
-+	  $@-t  # We just want the appendix tag (asciidoctor adds non-empty book-level title)
-+	$(AM_V_at)sed -i 's/book>/chapter>/g' $@-t   # Rename to chapter (won't trigger if previous sed did)
-+	$(AM_V_GEN)mv $@-t $@
- 
- #	echo Rebuilt $@ from $<
-diff --git a/configure.ac b/configure.ac
-index a7084e2..c58b556 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -605,7 +605,7 @@ AC_CHECK_PROGS(MAKE, gmake make)
- AC_PATH_PROGS(HTML2TXT, lynx w3m)
- AC_PATH_PROGS(HELP2MAN, help2man)
- AC_PATH_PROGS(POD2MAN, pod2man, pod2man)
--AC_PATH_PROGS(ASCIIDOC, asciidoc)
-+AC_PATH_PROGS([ASCIIDOC_CONV], [asciidoc asciidoctor])
- AC_PATH_PROGS(PUBLICAN, publican)
- AC_PATH_PROGS(INKSCAPE, inkscape)
- AC_PATH_PROGS(XSLTPROC, xsltproc)
-@@ -667,8 +667,9 @@ if test x"${MANPAGE_XSLT}" != x""; then
-    PCMK_FEATURES="$PCMK_FEATURES agent-manpages"
- fi
- 
--AM_CONDITIONAL(BUILD_ASCIIDOC, test x"${ASCIIDOC}" != x"")
--if test x"${ASCIIDOC}" != x""; then
-+AM_CONDITIONAL([IS_ASCIIDOC], [echo "${ASCIIDOC_CONV}" | grep -Eq 'asciidoc$'])
-+AM_CONDITIONAL([BUILD_ASCIIDOC], [test "x${ASCIIDOC_CONV}" != x])
-+if test "x${ASCIIDOC_CONV}" != x; then
-    PCMK_FEATURES="$PCMK_FEATURES ascii-docs"
- fi
- 
-diff --git a/doc/Makefile.am b/doc/Makefile.am
-index a00b704..d59cdcd 100644
---- a/doc/Makefile.am
-+++ b/doc/Makefile.am
-@@ -103,7 +103,11 @@ endif
- EXTRA_DIST	= $(docbook:%=%.xml)
- 
- %.html: %.txt
--	$(AM_V_ASCII)$(ASCIIDOC) --unsafe --backend=xhtml11 $<
-+if IS_ASCIIDOC
-+	$(AM_V_ASCII)$(ASCIIDOC_CONV) --unsafe --backend=xhtml11 $<
-+else
-+	$(AM_V_ASCII)$(ASCIIDOC_CONV) --backend=html5 $<
-+endif
- 
- # publican-clusterlabs/xsl/{html,html-single,pdf}.xsl refer to URIs
- # requiring Internet access, hence we shadow that with a XML catalog-based
--- 
-1.8.3.1
-
-
-From 2032f3e990c8fd39c8618dd15e9f8738290ec30f Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Mon, 29 Jan 2018 14:01:01 -0600
-Subject: [PATCH 76/96] Doc: clear detritus from previous failed builds when
- building
-
----
- doc/Makefile.am | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/doc/Makefile.am b/doc/Makefile.am
-index d59cdcd..f1a3c63 100644
---- a/doc/Makefile.am
-+++ b/doc/Makefile.am
-@@ -152,7 +152,7 @@ endif
- # With '%' the test for 'newness' fails
- Clusters_from_Scratch.build: $(PNGS) $(wildcard Clusters_from_Scratch/en-US/*.xml) $(CFS_XML) $(CFS_SHARED_XML) $(PUBLICAN_INTREE_DEPS)
- 	$(PCMK_V) @echo Building $(@:%.build=%) because of $?
--	rm -rf $(@:%.build=%)/publish/*
-+	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
- if PUBLICAN_INTREE_BRAND
- 	$(AM_V_PUB)cd $(@:%.build=%) \
- 	&& RPM_BUILD_DIR="" XML_CATALOG_FILES="$(CURDIR)/publican-catalog" \
-@@ -175,7 +175,7 @@ PD_XML=$(PD_TXT:%.txt=%.xml)
- # With '%' the test for 'newness' fails
- Pacemaker_Development.build: $(wildcard Pacemaker_Development/en-US/*.xml) $(PD_XML) $(PUBLICAN_INTREE_DEPS)
- 	$(PCMK_V) @echo Building $(@:%.build=%) because of $?
--	rm -rf $(@:%.build=%)/publish/*
-+	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
- if PUBLICAN_INTREE_BRAND
- 	$(AM_V_PUB)cd $(@:%.build=%) \
- 	&& RPM_BUILD_DIR="" XML_CATALOG_FILES="$(CURDIR)/publican-catalog" \
-@@ -202,7 +202,7 @@ $(PE_XML): $(PE_SHARED_XML)
- # With '%' the test for 'newness' fails
- Pacemaker_Explained.build: $(PNGS) $(wildcard Pacemaker_Explained/en-US/*.xml) $(PE_XML) $(PE_SHARED_XML) $(PUBLICAN_INTREE_DEPS)
- 	$(PCMK_V) @echo Building $(@:%.build=%) because of $?
--	rm -rf $(@:%.build=%)/publish/*
-+	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
- if PUBLICAN_INTREE_BRAND
- 	$(AM_V_PUB)cd $(@:%.build=%) \
- 	&& RPM_BUILD_DIR="" XML_CATALOG_FILES="$(CURDIR)/publican-catalog" \
-@@ -225,7 +225,7 @@ PR_XML=$(PR_TXT:%.txt=%.xml)
- # With '%' the test for 'newness' fails
- Pacemaker_Remote.build: $(PNGS) $(wildcard Pacemaker_Remote/en-US/*.xml) $(PR_XML) $(PUBLICAN_INTREE_DEPS)
- 	$(PCMK_V) @echo Building $(@:%.build=%) because of $?
--	rm -rf $(@:%.build=%)/publish/*
-+	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
- if PUBLICAN_INTREE_BRAND
- 	$(AM_V_PUB)cd $(@:%.build=%) \
- 	&& RPM_BUILD_DIR="" XML_CATALOG_FILES="$(CURDIR)/publican-catalog" \
--- 
-1.8.3.1
-
-
-From 0e072d3debfc2c03751ff69add211a20c9db01cb Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
-Date: Thu, 9 May 2019 17:41:21 +0200
-Subject: [PATCH 77/96] Build: configure: let "make dist" tarballs be
- ustar/posix, not v7 format
-
-This avoids problem with "file name is too long (max 99); not dumped"
--- we don't suffer from this currently, but eventually could (see also
-the subsequent, related change in the set).  Not also that some git
-hosting sites (GitHub) will also offer tarballs (effectively our current
-official, blessed and authoritative redistributables) using *only* even
-newer format (pax), which may effectively cause portability issues(!).
----
- configure.ac | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/configure.ac b/configure.ac
-index c58b556..e21eb03 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -59,7 +59,8 @@ AC_ARG_WITH(pkg-name,
-     [ PACKAGE_NAME="$withval" ])
- 
- dnl Older distros may need: AM_INIT_AUTOMAKE($PACKAGE_NAME, $PACKAGE_VERSION)
--AM_INIT_AUTOMAKE([foreign])
-+dnl tar-ustar:      use (older) POSIX variant of generated tar rather than v7
-+AM_INIT_AUTOMAKE([foreign tar-ustar])
- AC_DEFINE_UNQUOTED(PACEMAKER_VERSION, "$PACKAGE_VERSION", Current pacemaker version)
- 
- dnl Versioned attributes implementation is not yet production-ready
--- 
-1.8.3.1
-
-
-From 9ddc343d609e3082ec8baead451456a7b7c959de Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
-Date: Thu, 9 May 2019 17:47:48 +0200
-Subject: [PATCH 78/96] Build: fix "make dist" in one go deficiency (and if,
- it's brokenness)
-
-Problem was with EXTRA_DIST variable that got rightfully assigned
-"$(docbook:%=%.xml)" in e99ccd1b0, but frightfully stayed unadjusted
-in 7382e6241 -- actually it sort of worked, but only as a byproduct
-of generating spurious empty <publication dir>.xml files, which
-moreover required multiple iteration over "make dist" for it to
-finish successfully -- in a limited sense of "successfully" since
-it didn't include the publications' sources at all.
-
-All this is now rectified.  Also note that preceding "Build: configure:
-let "make dist" tarballs be posix/pax, not v7 format" commit prepared
-the path for us, otherwise we'd be getting something like:
-
-pacemaker-<GITHASH>/doc/Pacemaker_Administration/en-US/Ch-Upgrading.txt:
-  file name is too long (max 99); not dumped
----
- doc/Makefile.am | 25 ++++++++++++++++++++-----
- 1 file changed, 20 insertions(+), 5 deletions(-)
-
-diff --git a/doc/Makefile.am b/doc/Makefile.am
-index f1a3c63..c981009 100644
---- a/doc/Makefile.am
-+++ b/doc/Makefile.am
-@@ -100,7 +100,12 @@ publican_docs	+= $(docbook)
- endif
- endif
- 
--EXTRA_DIST	= $(docbook:%=%.xml)
-+EXTRA_DIST	= $(ascii) $(SHARED_TXT) $(PNGS_ORIGINAL) $(SVGS)
-+EXTRA_DIST	+= $(CFS_TXT) $(CFS_XML_ONLY)
-+EXTRA_DIST	+= $(PA_TXT) $(PA_XML_ONLY)
-+EXTRA_DIST	+= $(PD_TXT) $(PD_XML_ONLY)
-+EXTRA_DIST	+= $(PE_TXT) $(PE_XML_ONLY)
-+EXTRA_DIST	+= $(PR_TXT) $(PR_XML_ONLY)
- 
- %.html: %.txt
- if IS_ASCIIDOC
-@@ -132,6 +137,8 @@ publican-catalog: publican-catalog-fallback
- 	&& echo '</catalog>'
- 	$(AM_V_GEN)mv $@-t $@
- 
-+COMMON_XML = Author_Group.xml Book_Info.xml Revision_History.xml
-+
- SHARED_TXT=$(wildcard shared/en-US/*.txt)
- SHARED_XML=$(SHARED_TXT:%.txt=%.xml)
- 
-@@ -140,6 +147,8 @@ CFS_SHARED_TXT=$(addprefix shared/en-US/,pacemaker-intro.txt)
- CFS_SHARED_XML=$(CFS_SHARED_TXT:%.txt=%.xml)
- CFS_TXT=$(wildcard Clusters_from_Scratch/en-US/*.txt)
- CFS_XML=$(CFS_TXT:%.txt=%.xml)
-+CFS_XML_ONLY=$(addprefix Clusters_from_Scratch/en-US/,$(COMMON_XML) \
-+  Clusters_from_Scratch.ent Clusters_from_Scratch.xml Preface.xml)
- 
- $(CFS_XML): $(CFS_SHARED_XML)
- 
-@@ -150,7 +159,7 @@ endif
- 
- # We have to hardcode the book name
- # With '%' the test for 'newness' fails
--Clusters_from_Scratch.build: $(PNGS) $(wildcard Clusters_from_Scratch/en-US/*.xml) $(CFS_XML) $(CFS_SHARED_XML) $(PUBLICAN_INTREE_DEPS)
-+Clusters_from_Scratch.build: $(PNGS)  $(CFS_XML_ONLY) $(CFS_XML) $(CFS_SHARED_XML) $(PUBLICAN_INTREE_DEPS)
- 	$(PCMK_V) @echo Building $(@:%.build=%) because of $?
- 	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
- if PUBLICAN_INTREE_BRAND
-@@ -170,10 +179,12 @@ endif
- 
- PD_TXT=$(wildcard Pacemaker_Development/en-US/*.txt)
- PD_XML=$(PD_TXT:%.txt=%.xml)
-+PD_XML_ONLY=$(addprefix Pacemaker_Development/en-US/,$(COMMON_XML) \
-+  Pacemaker_Development.ent Pacemaker_Development.xml)
- 
- # We have to hardcode the book name
- # With '%' the test for 'newness' fails
--Pacemaker_Development.build: $(wildcard Pacemaker_Development/en-US/*.xml) $(PD_XML) $(PUBLICAN_INTREE_DEPS)
-+Pacemaker_Development.build: $(PD_XML_ONLY) $(PD_XML) $(PUBLICAN_INTREE_DEPS)
- 	$(PCMK_V) @echo Building $(@:%.build=%) because of $?
- 	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
- if PUBLICAN_INTREE_BRAND
-@@ -195,12 +206,14 @@ PE_SHARED_TXT=$(addprefix shared/en-US/,pacemaker-intro.txt)
- PE_SHARED_XML=$(PE_SHARED_TXT:%.txt=%.xml)
- PE_TXT=$(wildcard Pacemaker_Explained/en-US/*.txt)
- PE_XML=$(PE_TXT:%.txt=%.xml)
-+PE_XML_ONLY=$(addprefix Pacemaker_Explained/en-US/,$(COMMON_XML) \
-+  Pacemaker_Explained.ent Pacemaker_Explained.xml Preface.xml)
- 
- $(PE_XML): $(PE_SHARED_XML)
- 
- # We have to hardcode the book name
- # With '%' the test for 'newness' fails
--Pacemaker_Explained.build: $(PNGS) $(wildcard Pacemaker_Explained/en-US/*.xml) $(PE_XML) $(PE_SHARED_XML) $(PUBLICAN_INTREE_DEPS)
-+Pacemaker_Explained.build: $(PNGS) $(PE_XML_ONLY) $(PE_XML) $(PE_SHARED_XML) $(PUBLICAN_INTREE_DEPS)
- 	$(PCMK_V) @echo Building $(@:%.build=%) because of $?
- 	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
- if PUBLICAN_INTREE_BRAND
-@@ -220,10 +233,12 @@ endif
- 
- PR_TXT=$(wildcard Pacemaker_Remote/en-US/*.txt)
- PR_XML=$(PR_TXT:%.txt=%.xml)
-+PR_XML_ONLY=$(addprefix Pacemaker_Remote/en-US/,$(COMMON_XML) \
-+  Pacemaker_Remote.ent Pacemaker_Remote.xml)
- 
- # We have to hardcode the book name
- # With '%' the test for 'newness' fails
--Pacemaker_Remote.build: $(PNGS) $(wildcard Pacemaker_Remote/en-US/*.xml) $(PR_XML) $(PUBLICAN_INTREE_DEPS)
-+Pacemaker_Remote.build: $(PNGS) $(PR_XML_ONLY) $(PR_XML) $(PUBLICAN_INTREE_DEPS)
- 	$(PCMK_V) @echo Building $(@:%.build=%) because of $?
- 	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
- if PUBLICAN_INTREE_BRAND
--- 
-1.8.3.1
-
-
-From 54b8f258f864d63596b71f38db49491873bddbdf Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
-Date: Tue, 5 Jun 2018 17:10:28 +0200
-Subject: [PATCH 79/96] Build: xml: *.rng: ship needed non-generated (& only
- such) RNG schemas
-
-Previously, "make dist" would omit those(!), and over-approximation
-of such files would get, undesirably, selected (since 0a7a4b4d7
-incl. cibtr-2.rng) in the respective source variable.
-Also fix some whitespace issues.
----
- xml/Makefile.am | 9 +++++----
- 1 file changed, 5 insertions(+), 4 deletions(-)
-
-diff --git a/xml/Makefile.am b/xml/Makefile.am
-index ffd09e3..1e5649f 100644
---- a/xml/Makefile.am
-+++ b/xml/Makefile.am
-@@ -58,14 +58,15 @@ RNG_version_pairs_last  = $(wordlist \
- 
- RNG_generated		= pacemaker.rng $(foreach base,$(RNG_versions),pacemaker-$(base).rng) versions.rng
- 
--RNG_cfg_base	 	= options nodes resources constraints fencing acls tags alerts
--RNG_base	 	= cib $(RNG_cfg_base) status score rule nvset
--RNG_files	 	= $(foreach base,$(RNG_base),$(wildcard $(base)*.rng))
-+RNG_cfg_base		= options nodes resources constraints fencing acls tags alerts
-+RNG_base		= cib $(RNG_cfg_base) status score rule nvset
-+RNG_files		= $(foreach base,$(RNG_base),$(wildcard $(base).rng $(base)-*.rng))
- 
- # List of non-Pacemaker RNGs
- RNG_extra		= crm_mon.rng
- 
--RNG_DATA		= $(RNG_files) $(RNG_generated) $(RNG_extra)
-+dist_RNG_DATA		= $(RNG_files) $(RNG_extra)
-+nodist_RNG_DATA		= $(RNG_generated)
- 
- EXTRA_DIST		= best-match.sh
- 
--- 
-1.8.3.1
-
-
-From 898accf5febfac5ddc4304ad4a0f92b8fc866964 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Mon, 5 Aug 2019 10:48:18 -0500
-Subject: [PATCH 80/96] Build: makefiles: make sure all files that should be
- distributed are
-
-... so the result of "make dist" has everything needed to build,
-and everything of interest to end users
----
- Makefile.am                 | 19 +++++++++++---
- Makefile.common             |  2 +-
- cts/Makefile.am             | 56 ++++++++++++++++++++--------------------
- cts/benchmark/Makefile.am   | 25 ++++--------------
- doc/Makefile.am             |  9 ++++---
- extra/Makefile.am           | 25 ++++++------------
- extra/alerts/Makefile.am    | 23 ++++++-----------
- extra/logrotate/Makefile.am | 21 +++++----------
- extra/resources/Makefile.am | 62 ++++++++++++++++++---------------------------
- fencing/Makefile.am         |  4 ++-
- lrmd/Makefile.am            |  2 +-
- mcp/Makefile.am             |  4 ++-
- pengine/Makefile.am         |  6 ++---
- tools/Makefile.am           | 11 ++++----
- xml/Makefile.am             | 14 ++++++----
- 15 files changed, 127 insertions(+), 156 deletions(-)
-
-diff --git a/Makefile.am b/Makefile.am
-index 874f6ed..3080445 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -18,7 +18,15 @@
- # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- #
- 
--EXTRA_DIST              = autogen.sh ConfigureMe README.in m4/gnulib-cache.m4
-+EXTRA_DIST		= CONTRIBUTING.md	\
-+			  GNUmakefile		\
-+			  INSTALL.md		\
-+			  README.markdown	\
-+			  autogen.sh		\
-+			  pacemaker.spec.in	\
-+			  rpmlintrc		\
-+			  m4/gnulib-cache.m4	\
-+			  m4/gnulib-tool.m4
- 
- MAINTAINERCLEANFILES    = Makefile.in aclocal.m4 configure DRF/config-h.in \
-                         DRF/stamp-h.in libtool.m4 ltdl.m4
-@@ -33,14 +41,17 @@ doc_DATA = README.markdown COPYING
- ACLOCAL_AMFLAGS  = -I m4
- 
- licensedir              = $(docdir)/licenses/
--license_DATA            = $(wildcard licenses/*)
-+dist_license_DATA	= $(wildcard licenses/*)
- 
- # Test components
- SUBDIRS	+= cts
- 
- testdir			= $(datadir)/$(PACKAGE)/tests/
--test_SCRIPTS		= coverage.sh BasicSanity.sh
--test_DATA		= valgrind-pcmk.suppressions
-+test_SCRIPTS		= coverage.sh
-+dist_test_SCRIPTS	= BasicSanity.sh
-+dist_test_DATA		= valgrind-pcmk.suppressions
-+
-+EXTRA_SCRIPTS		= abi-check bumplibs.sh
- 
- # Scratch file for ad-hoc testing
- noinst_PROGRAMS = scratch
-diff --git a/Makefile.common b/Makefile.common
-index 0b06ec4..a4842b7 100644
---- a/Makefile.common
-+++ b/Makefile.common
-@@ -33,7 +33,7 @@ AM_CPPFLAGS		= -I$(top_builddir)/include -I$(top_srcdir)/include   \
- 			  -I$(top_builddir)/libltdl -I$(top_srcdir)/libltdl
- 
- if BUILD_HELP
--man8_MANS		= $(sbin_PROGRAMS:%=%.8) $(sbin_SCRIPTS:%=%.8)
-+man8_MANS		= $(sbin_PROGRAMS:%=%.8) $(sbin_SCRIPTS:%=%.8) $(dist_sbin_SCRIPTS:%=%.8)
- endif
- 
- %.8:	% $(MAN8DEPS)
-diff --git a/cts/Makefile.am b/cts/Makefile.am
-index f3f169c..c0c5707 100644
---- a/cts/Makefile.am
-+++ b/cts/Makefile.am
-@@ -21,37 +21,37 @@ MAINTAINERCLEANFILES    = Makefile.in
- 
- CLEANFILES      = LSBDummy HBDummy
- 
--EXTRA_DIST      = $(cts_SCRIPTS) $(cts_DATA)
--noinst_SCRIPTS		= cluster_test		\
-+EXTRA_SCRIPTS		= cluster_test		\
- 			  OCFIPraTest.py
- 
--ctsdir		= $(datadir)/$(PACKAGE)/tests/cts
--ctslibdir	= $(pyexecdir)/cts
-+testdir		= $(datadir)/$(PACKAGE)/tests
- 
--ctslib_PYTHON	=	__init__.py		\
--			CTSvars.py		\
--			CM_lha.py		\
--			CM_ais.py		\
--			CTS.py			\
--			CTSaudits.py		\
--			CTStests.py		\
--			CTSscenarios.py		\
--			CIB.py			\
--			cib_xml.py		\
--			environment.py		\
--			logging.py		\
--			patterns.py		\
--			remote.py		\
--			watcher.py
-+ctslibdir		= $(pyexecdir)/cts
-+ctslib_PYTHON		= __init__.py		\
-+			  CIB.py		\
-+			  cib_xml.py		\
-+			  CM_lha.py		\
-+			  CM_ais.py		\
-+			  CTS.py		\
-+			  CTSaudits.py		\
-+			  CTSscenarios.py	\
-+			  CTStests.py		\
-+			  environment.py	\
-+			  logging.py		\
-+			  patterns.py		\
-+			  remote.py		\
-+			  watcher.py
-+nodist_ctslib_PYTHON	= CTSvars.py
- 
--cts_DATA	=	README.md cts.supp pacemaker-cts-dummyd.service
--
--cts_SCRIPTS	=	cts		\
--			CTSlab.py		\
--			lxc_autogen.sh	\
--			LSBDummy		\
--			HBDummy		\
--			pacemaker-cts-dummyd	\
--			$(top_srcdir)/fencing/fence_dummy
-+ctsdir		= 	$(testdir)/cts
-+cts_DATA	=	pacemaker-cts-dummyd.service
-+dist_cts_DATA	=	README.md cts.supp
-+dist_cts_SCRIPTS	= cts			\
-+			  CTSlab.py		\
-+			  $(top_srcdir)/fencing/fence_dummy
-+cts_SCRIPTS		= HBDummy		\
-+			  LSBDummy		\
-+			  lxc_autogen.sh	\
-+			  pacemaker-cts-dummyd
- 
- SUBDIRS	= benchmark
-diff --git a/cts/benchmark/Makefile.am b/cts/benchmark/Makefile.am
-index 8a50ac7..1fd6171 100644
---- a/cts/benchmark/Makefile.am
-+++ b/cts/benchmark/Makefile.am
-@@ -3,26 +3,11 @@
- #
- # Copyright (C) 2001 Michael Moerz
- #
--# This program is free software; you can redistribute it and/or
--# modify it under the terms of the GNU General Public License
--# as published by the Free Software Foundation; either version 2
--# of the License, or (at your option) any later version.
--# 
--# This program is distributed in the hope that it will be useful,
--# but WITHOUT ANY WARRANTY; without even the implied warranty of
--# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--# GNU General Public License for more details.
--# 
--# You should have received a copy of the GNU General Public License
--# along with this program; if not, write to the Free Software
--# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-+# This source code is licensed under the GNU General Public License version 2
-+# or later (GPLv2+) WITHOUT ANY WARRANTY.
- #
- MAINTAINERCLEANFILES    = Makefile.in
- 
--EXTRA_DIST      = $(bench_SCRIPTS) $(bench_DATA)
--
--benchdir		= $(datadir)/$(PACKAGE)/tests/cts/benchmark
--
--bench_DATA	=	README.benchmark control
--
--bench_SCRIPTS	=	clubench
-+benchdir	= $(datadir)/$(PACKAGE)/tests/cts/benchmark
-+dist_bench_DATA	= README.benchmark control
-+bench_SCRIPTS	= clubench
-diff --git a/doc/Makefile.am b/doc/Makefile.am
-index c981009..a929acb 100644
---- a/doc/Makefile.am
-+++ b/doc/Makefile.am
-@@ -56,11 +56,13 @@ UPLOAD_LANGS    = en-US
- 
- # Scheduler transition graphs
- # @TODO Add original XML, and generate DOTs via crm_simulate
--DOTS = $(wildcard shared/en-US/images/*.dot)
-+DOTS	= $(wildcard Clusters_from_Scratch/en-US/images/*.dot)	\
-+	  $(wildcard Pacemaker_Explained/en-US/images/*.dot)
- 
- # Vector sources for images
- # @TODO Generate transition SVGs from DOTs via dot
--SVGS =	$(wildcard shared/en-US/images/pcmk-*.svg)	\
-+SVGS =	$(wildcard Clusters_from_Scratch/en-US/images/pcmk-*.svg)	\
-+	$(wildcard Pacemaker_Explained/en-US/images/pcmk-*.svg)	\
- 	$(DOTS:%.dot=%.svg)
- 
- # Final images
-@@ -100,12 +102,13 @@ publican_docs	+= $(docbook)
- endif
- endif
- 
--EXTRA_DIST	= $(ascii) $(SHARED_TXT) $(PNGS_ORIGINAL) $(SVGS)
-+EXTRA_DIST	= $(ascii) $(SHARED_TXT) $(PNGS_ORIGINAL) $(DOTS) $(SVGS)
- EXTRA_DIST	+= $(CFS_TXT) $(CFS_XML_ONLY)
- EXTRA_DIST	+= $(PA_TXT) $(PA_XML_ONLY)
- EXTRA_DIST	+= $(PD_TXT) $(PD_XML_ONLY)
- EXTRA_DIST	+= $(PE_TXT) $(PE_XML_ONLY)
- EXTRA_DIST	+= $(PR_TXT) $(PR_XML_ONLY)
-+EXTRA_DIST	+= pcs-crmsh-quick-ref.md
- 
- %.html: %.txt
- if IS_ASCIIDOC
-diff --git a/extra/Makefile.am b/extra/Makefile.am
-index d742ae2..fb23caf 100644
---- a/extra/Makefile.am
-+++ b/extra/Makefile.am
-@@ -1,24 +1,15 @@
- #
--# Copyright (C) 2004-2009 Andrew Beekhof
-+# Copyright 2004-2019 the Pacemaker project contributors
- #
--# This program is free software; you can redistribute it and/or
--# modify it under the terms of the GNU General Public License
--# as published by the Free Software Foundation; either version 2
--# of the License, or (at your option) any later version.
--# 
--# This program is distributed in the hope that it will be useful,
--# but WITHOUT ANY WARRANTY; without even the implied warranty of
--# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--# GNU General Public License for more details.
--# 
--# You should have received a copy of the GNU General Public License
--# along with this program; if not, write to the Free Software
--# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-+# The version control history for this file may have further details.
-+#
-+# This source code is licensed under the GNU General Public License version 2
-+# or later (GPLv2+) WITHOUT ANY WARRANTY.
- #
- 
- MAINTAINERCLEANFILES    = Makefile.in
- 
--SUBDIRS                 =  alerts resources logrotate
-+SUBDIRS		= alerts resources logrotate
- 
--mibdir = $(datadir)/snmp/mibs
--mib_DATA = PCMK-MIB.txt
-+mibdir		= $(datadir)/snmp/mibs
-+dist_mib_DATA	= PCMK-MIB.txt
-diff --git a/extra/alerts/Makefile.am b/extra/alerts/Makefile.am
-index 2cd3bd6..e798ae9 100644
---- a/extra/alerts/Makefile.am
-+++ b/extra/alerts/Makefile.am
-@@ -1,22 +1,15 @@
- #
--# Copyright (C) 2016 Ken Gaillot <kgaillot@redhat.com>
-+# Copyright 2016-2019 the Pacemaker project contributors
- #
--# This program is free software; you can redistribute it and/or
--# modify it under the terms of the GNU General Public License
--# as published by the Free Software Foundation; either version 2
--# of the License, or (at your option) any later version.
-+# The version control history for this file may have further details.
- #
--# This program is distributed in the hope that it will be useful,
--# but WITHOUT ANY WARRANTY; without even the implied warranty of
--# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--# GNU General Public License for more details.
--#
--# You should have received a copy of the GNU General Public License
--# along with this program; if not, write to the Free Software
--# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-+# This source code is licensed under the GNU General Public License version 2
-+# or later (GPLv2+) WITHOUT ANY WARRANTY.
- #
- 
- MAINTAINERCLEANFILES    = Makefile.in
- 
--samplesdir = $(datadir)/$(PACKAGE)/alerts/
--samples_DATA = alert_file.sh.sample alert_smtp.sh.sample alert_snmp.sh.sample
-+samplesdir		= $(datadir)/$(PACKAGE)/alerts/
-+dist_samples_DATA	= alert_file.sh.sample	\
-+			  alert_smtp.sh.sample	\
-+			  alert_snmp.sh.sample
-diff --git a/extra/logrotate/Makefile.am b/extra/logrotate/Makefile.am
-index 55c669c..cafd0d5 100644
---- a/extra/logrotate/Makefile.am
-+++ b/extra/logrotate/Makefile.am
-@@ -1,22 +1,13 @@
- #
--# Copyright (C) 2014 Gao,Yan <ygao@suse.com>
-+# Copyright 2014-2019 the Pacemaker project contributors
- #
--# This program is free software; you can redistribute it and/or
--# modify it under the terms of the GNU General Public License
--# as published by the Free Software Foundation; either version 2
--# of the License, or (at your option) any later version.
-+# The version control history for this file may have further details.
- #
--# This program is distributed in the hope that it will be useful,
--# but WITHOUT ANY WARRANTY; without even the implied warranty of
--# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--# GNU General Public License for more details.
--#
--# You should have received a copy of the GNU General Public License
--# along with this program; if not, write to the Free Software
--# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-+# This source code is licensed under the GNU General Public License version 2
-+# or later (GPLv2+) WITHOUT ANY WARRANTY.
- #
- 
- MAINTAINERCLEANFILES    = Makefile.in
- 
--logrotatedir = $(sysconfdir)/logrotate.d
--logrotate_DATA = pacemaker
-+logrotatedir		= $(sysconfdir)/logrotate.d
-+logrotate_DATA		= pacemaker
-diff --git a/extra/resources/Makefile.am b/extra/resources/Makefile.am
-index c84dfdf..e4b54cc 100644
---- a/extra/resources/Makefile.am
-+++ b/extra/resources/Makefile.am
-@@ -1,22 +1,12 @@
--# Makefile.am for OCF RAs
- #
--# Author: Andrew Beekhof
--# Copyright (C) 2008 Andrew Beekhof
-+# Copyright 2008-2019 the Pacemaker project contributors
- #
--# This program is free software; you can redistribute it and/or
--# modify it under the terms of the GNU General Public License
--# as published by the Free Software Foundation; either version 2
--# of the License, or (at your option) any later version.
--# 
--# This program is distributed in the hope that it will be useful,
--# but WITHOUT ANY WARRANTY; without even the implied warranty of
--# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--# GNU General Public License for more details.
--# 
--# You should have received a copy of the GNU General Public License
--# along with this program; if not, write to the Free Software
--# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-+# The version control history for this file may have further details.
- #
-+# This source code is licensed under the GNU General Public License version 2
-+# or later (GPLv2+) WITHOUT ANY WARRANTY.
-+#
-+
- include $(top_srcdir)/Makefile.common
- 
- EXTRA_DIST		= $(ocf_SCRIPTS)
-@@ -24,28 +14,27 @@ EXTRA_DIST		= $(ocf_SCRIPTS)
- 
- isolationtechdir    = @OCF_RA_DIR@/.isolation
- 
--ocfdir		    = @OCF_RA_DIR@/pacemaker
--
--ocf_SCRIPTS	     =  ClusterMon 	\
--			controld	\
--			Dummy		\
--			HealthCPU	\
--			HealthSMART	\
--			ifspeed		\
--			o2cb		\
--			ping		\
--			pingd		\
--			Stateful	\
--			SysInfo		\
--			SystemHealth \
--			attribute	\
--			remote
--
--isolationtech_SCRIPTS	= docker-wrapper
-+ocfdir			= @OCF_RA_DIR@/pacemaker
-+dist_ocf_SCRIPTS	= attribute	\
-+			  ClusterMon	\
-+			  controld	\
-+			  Dummy		\
-+			  HealthCPU	\
-+			  HealthSMART	\
-+			  ifspeed	\
-+			  o2cb		\
-+			  ping		\
-+			  pingd		\
-+			  remote	\
-+			  Stateful	\
-+			  SysInfo	\
-+			  SystemHealth
-+
-+dist_isolationtech_SCRIPTS	= docker-wrapper
- 
- if BUILD_XML_HELP
- 
--man7_MANS = $(ocf_SCRIPTS:%=ocf_pacemaker_%.7)
-+man7_MANS = $(ocf_SCRIPTS:%=ocf_pacemaker_%.7) $(dist_ocf_SCRIPTS:%=ocf_pacemaker_%.7)
- DBOOK_OPTS = --stringparam command.prefix ocf_pacemaker_ --stringparam variable.prefix OCF_RESKEY_ --param man.vol 7
- 
- ocf_pacemaker_%.xml:  %
-@@ -54,5 +43,4 @@ ocf_pacemaker_%.xml:  %
- endif
- 
- clean-generic:
--	rm -f $(man7_MANS) $(ocf_SCRIPTS:%=%.xml) *~
--
-+	rm -f $(man7_MANS) $(ocf_SCRIPTS:%=%.xml) $(dist_ocf_SCRIPTS:%=%.xml) *~
-diff --git a/fencing/Makefile.am b/fencing/Makefile.am
-index cb7b551..6cda8ef 100644
---- a/fencing/Makefile.am
-+++ b/fencing/Makefile.am
-@@ -25,7 +25,7 @@ halibdir	= $(CRM_DAEMON_DIR)
- halib_PROGRAMS	= stonithd stonith-test
- 
- sbin_PROGRAMS	= stonith_admin
--sbin_SCRIPTS	= fence_legacy fence_pcmk
-+dist_sbin_SCRIPTS	= fence_legacy fence_pcmk
- 
- noinst_HEADERS	= internal.h standalone_config.h
- 
-@@ -33,6 +33,8 @@ if BUILD_XML_HELP
- man7_MANS	= stonithd.7
- endif
- 
-+EXTRA_DIST	= README.md
-+
- stonith_test_SOURCES	= test.c
- 
- stonith_test_LDADD	= $(top_builddir)/lib/common/libcrmcommon.la	\
-diff --git a/lrmd/Makefile.am b/lrmd/Makefile.am
-index 33611cb..7aa5414 100644
---- a/lrmd/Makefile.am
-+++ b/lrmd/Makefile.am
-@@ -26,7 +26,7 @@ testdir			= $(datadir)/$(PACKAGE)/tests/lrmd
- test_SCRIPTS		= regression.py
- 
- initdir			= $(INITDIR)
--init_SCRIPTS		= pacemaker_remote
-+dist_init_SCRIPTS	= pacemaker_remote
- sbin_PROGRAMS		= pacemaker_remoted
- 
- if BUILD_SYSTEMD
-diff --git a/mcp/Makefile.am b/mcp/Makefile.am
-index 074d251..5e1147d 100644
---- a/mcp/Makefile.am
-+++ b/mcp/Makefile.am
-@@ -20,13 +20,15 @@ include $(top_srcdir)/Makefile.common
- if BUILD_CS_SUPPORT
- 
- initdir			= $(INITDIR)
--init_SCRIPTS		= pacemaker
-+dist_init_SCRIPTS	= pacemaker
- sbin_PROGRAMS		= pacemakerd
- 
- if BUILD_SYSTEMD
- systemdunit_DATA	= pacemaker.service
- endif
- 
-+EXTRA_DIST		= pacemaker.sysconfig
-+
- ## SOURCES
- 
- noinst_HEADERS		= pacemaker.h
-diff --git a/pengine/Makefile.am b/pengine/Makefile.am
-index fdac3e3..c121ab5 100644
---- a/pengine/Makefile.am
-+++ b/pengine/Makefile.am
-@@ -24,11 +24,11 @@ halibdir	= $(CRM_DAEMON_DIR)
- PE_TESTS	= $(wildcard test10/*.scores)
- 
- testdir			= $(datadir)/$(PACKAGE)/tests/pengine
--test_SCRIPTS		= regression.sh
--test_DATA		= regression.core.sh
-+dist_test_SCRIPTS	= regression.sh
-+dist_test_DATA		= regression.core.sh
- 
- test10dir		= $(datadir)/$(PACKAGE)/tests/pengine/test10
--test10_DATA		= $(PE_TESTS) $(PE_TESTS:%.scores=%.xml) $(PE_TESTS:%.scores=%.exp) $(PE_TESTS:%.scores=%.dot) $(PE_TESTS:%.scores=%.summary) $(wildcard test10/*.stderr)
-+dist_test10_DATA	= $(PE_TESTS) $(PE_TESTS:%.scores=%.xml) $(PE_TESTS:%.scores=%.exp) $(PE_TESTS:%.scores=%.dot) $(PE_TESTS:%.scores=%.summary) $(wildcard test10/*.stderr)
- 
- beekhof:
- 	echo $(shell ls -1 test10/*.xml)
-diff --git a/tools/Makefile.am b/tools/Makefile.am
-index d8c3215..6960548 100644
---- a/tools/Makefile.am
-+++ b/tools/Makefile.am
-@@ -31,18 +31,20 @@ noinst_HEADERS		= crm_resource.h fake_transition.h
- pcmkdir			= $(datadir)/$(PACKAGE)
- pcmk_DATA		= report.common report.collector
- 
--sbin_SCRIPTS		= crm_report crm_standby crm_master crm_failcount
-+sbin_SCRIPTS		= crm_report
- if BUILD_CIBSECRETS
- sbin_SCRIPTS		+= cibsecret
- endif
--EXTRA_DIST		= $(sbin_SCRIPTS)
-+dist_sbin_SCRIPTS	= crm_standby crm_master crm_failcount
-+
-+EXTRA_DIST		= crm_mon.sysconfig
- 
- sbin_PROGRAMS		= crm_simulate crmadmin cibadmin crm_node crm_attribute crm_resource crm_verify \
- 			 crm_shadow attrd_updater crm_diff crm_mon iso8601 crm_ticket crm_error
- 
- testdir			= $(datadir)/$(PACKAGE)/tests/cli
--test_SCRIPTS		= regression.sh
--test_DATA		= regression.dates.exp		\
-+dist_test_SCRIPTS	= regression.sh
-+dist_test_DATA		= regression.dates.exp		\
- 			  regression.tools.exp		\
- 			  regression.acls.exp		\
- 			  regression.validity.exp	\
-@@ -102,7 +104,6 @@ crm_mon_LDADD		= $(top_builddir)/lib/pengine/libpe_status.la		\
- 			  $(top_builddir)/pengine/libpengine.la \
- 			  $(COMMONLIBS) $(SNMPLIBS) $(ESMTPLIBS)
- 
--# Arguments could be made that this should live in crm/pengine
- crm_verify_SOURCES	= crm_verify.c
- crm_verify_LDADD	= $(top_builddir)/lib/pengine/libpe_status.la 	\
- 			$(top_builddir)/pengine/libpengine.la		\
-diff --git a/xml/Makefile.am b/xml/Makefile.am
-index 1e5649f..c801842 100644
---- a/xml/Makefile.am
-+++ b/xml/Makefile.am
-@@ -18,12 +18,11 @@
- MAINTAINERCLEANFILES    = Makefile.in
- 
- dtddir			= $(CRM_DTD_DIRECTORY)
--dtd_DATA		= crm.dtd crm-transitional.dtd
-+dist_dtd_DATA		= crm.dtd crm-transitional.dtd
- 
- xsltdir			= $(dtddir)
--xslt_DATA		= $(top_srcdir)/xml/upgrade06.xsl $(top_srcdir)/xml/upgrade-*.xsl
--
--noinst_DATA		= context-of.xsl
-+dist_xslt_DATA		= $(top_srcdir)/xml/upgrade06.xsl \
-+			  $(top_srcdir)/xml/upgrade-*.xsl
- 
- RNGdir			= $(dtddir)
- 
-@@ -68,7 +67,12 @@ RNG_extra		= crm_mon.rng
- dist_RNG_DATA		= $(RNG_files) $(RNG_extra)
- nodist_RNG_DATA		= $(RNG_generated)
- 
--EXTRA_DIST		= best-match.sh
-+EXTRA_DIST		= Readme.md			\
-+			  best-match.sh			\
-+			  context-of.xsl		\
-+			  ocf-meta2man.xsl		\
-+			  regression.core.sh		\
-+			  regression.sh
- 
- versions:
- 	echo "Max: $(RNG_max)"
--- 
-1.8.3.1
-
-
-From 50825612a2d3922fbeabef390303ca2ac596e846 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Mon, 5 Aug 2019 17:38:42 -0500
-Subject: [PATCH 81/96] Build: GNUmakefile: allow all/clean to work without git
-
-e.g. in a distribution rather than a checkout
----
- GNUmakefile | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/GNUmakefile b/GNUmakefile
-index 352903f..d790865 100644
---- a/GNUmakefile
-+++ b/GNUmakefile
-@@ -45,12 +45,12 @@ ARCH    ?= $(shell test -e /etc/fedora-release && rpm --eval %{_arch})
- MOCK_CFG ?= $(shell test -e /etc/fedora-release && echo fedora-$(F)-$(ARCH))
- DISTRO  ?= $(shell test -e /etc/SuSE-release && echo suse; echo fedora)
- COMMIT  ?= HEAD
--TAG     ?= $(shell T=$$(git describe --all '$(COMMIT)' | sed -n 's|tags/\(.*\)|\1|p'); \
-+TAG     ?= $(shell T=$$(git describe --all '$(COMMIT)' 2>/dev/null | sed -n 's|tags/\(.*\)|\1|p'); \
- 	     test -n "$${T}" && echo "$${T}" \
--	       || git log --pretty=format:%H -n 1 '$(COMMIT)')
-+	       || git log --pretty=format:%H -n 1 '$(COMMIT)' 2>/dev/null || echo DIST)
- lparen = (
- rparen = )
--SHORTTAG ?= $(shell case $(TAG) in Pacemaker-*$(rparen) echo '$(TAG)' | cut -c11-;; \
-+SHORTTAG ?= $(shell case $(TAG) in Pacemaker-*|DIST$(rparen) echo '$(TAG)' | cut -c11-;; \
- 	      *$(rparen) git log --pretty=format:%h -n 1 '$(TAG)';; esac)
- SHORTTAG_ABBREV = $(shell printf %s '$(SHORTTAG)' | wc -c)
- WITH    ?= --without doc
--- 
-1.8.3.1
-
-
-From d545f94c95dbf9c205b458aee6bdff49fa9c3dd9 Mon Sep 17 00:00:00 2001
-From: Chris Lumens <clumens@redhat.com>
-Date: Thu, 28 Feb 2019 10:28:35 -0500
-Subject: [PATCH 82/96] Feature: xml: Add a schema for API results.
-
-This describes the layout of all the XML that will be emitted by the
-formatted output patches.  That output can be validated against the
-schema with xmllint.
-
-[small portion of commit backported to 1.1]
----
- xml/Makefile.am | 31 ++++++++++++++++++-------------
- 1 file changed, 18 insertions(+), 13 deletions(-)
-
-diff --git a/xml/Makefile.am b/xml/Makefile.am
-index c801842..09d3503 100644
---- a/xml/Makefile.am
-+++ b/xml/Makefile.am
-@@ -30,31 +30,36 @@ RNGdir			= $(dtddir)
- 
- # Sorted list of available numeric RNG versions,
- # extracted from filenames like NAME-MAJOR[.MINOR][.MINOR-MINOR].rng
--RNG_numeric_versions    = $(shell ls -1 $(top_srcdir)/xml/*.rng \
-+numeric_versions = $(shell ls -1 $(1) \
- 			  | sed -n -e 's/^.*-\([0-9][0-9.]*\).rng$$/\1/p' \
- 			  | sort -u -t. -k 1,1n -k 2,2n -k 3,3n)
- 
--# The highest numeric version
--RNG_max			?= $(lastword $(RNG_numeric_versions))
--
--# A sorted list of all RNG versions (numeric and "next")
--RNG_versions		= next $(RNG_numeric_versions)
--RNG_version_pairs	= $(join \
--			    ${RNG_numeric_versions},$(addprefix \
-+version_pairs = $(join \
-+			    $(1),$(addprefix \
- 			      -,$(wordlist \
--			        2,$(words ${RNG_numeric_versions}),${RNG_numeric_versions} \
-+			        2,$(words $(1)),$(1) \
- 			      ) next \
- 			    ) \
- 			  )
--RNG_version_pairs_cnt	= $(words ${RNG_version_pairs})
--RNG_version_pairs_last  = $(wordlist \
-+
-+version_pairs_last = $(wordlist \
- 			    $(words \
- 			      $(wordlist \
--			        2,${RNG_version_pairs_cnt},${RNG_version_pairs} \
-+			        2,$(1),$(2) \
- 			      ) \
--			    ),${RNG_version_pairs_cnt},${RNG_version_pairs} \
-+			    ),$(1),$(2) \
- 			  )
- 
-+RNG_numeric_versions = $(call numeric_versions,${RNG_files})
-+
-+# The highest numeric version
-+RNG_max			?= $(lastword $(RNG_numeric_versions))
-+
-+RNG_versions		= next $(RNG_numeric_versions)
-+RNG_version_pairs	= $(call version_pairs,${RNG_numeric_versions})
-+RNG_version_pairs_cnt	= $(words ${RNG_version_pairs})
-+RNG_version_pairs_last  = $(call version_pairs_last,${RNG_version_pairs_cnt},${RNG_version_pairs})
-+
- RNG_generated		= pacemaker.rng $(foreach base,$(RNG_versions),pacemaker-$(base).rng) versions.rng
- 
- RNG_cfg_base		= options nodes resources constraints fencing acls tags alerts
--- 
-1.8.3.1
-
-
-From fd3587f67b405c08473a636554f4822e72149495 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Fri, 2 Aug 2019 14:41:25 -0500
-Subject: [PATCH 83/96] Build: xml: remove broken and unneeded "make sync"
- target
-
----
- xml/Makefile.am | 4 ----
- 1 file changed, 4 deletions(-)
-
-diff --git a/xml/Makefile.am b/xml/Makefile.am
-index 09d3503..5734979 100644
---- a/xml/Makefile.am
-+++ b/xml/Makefile.am
-@@ -178,8 +178,4 @@ fulldiff: best-match.sh
- 	@echo "#  Comparing all changes across all the subsequent increments"
- 	$(call version_diff,${RNG_version_pairs})
- 
--sync:
--	git rm -f $(wildcard *-next.rng)
--	make pacemaker-next.rng
--
- CLEANFILES = $(RNG_generated)
--- 
-1.8.3.1
-
-
-From 2e8384cef56365c187c3b80719cd49f72d66b8e4 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Tue, 6 Aug 2019 14:52:20 -0500
-Subject: [PATCH 84/96] Build: xml: rearrange and comment Makefile for
- readability
-
-Similarly, rename some variables, and rename the versions target to
-cib-versions.
----
- xml/Makefile.am | 147 +++++++++++++++++++++++++++++---------------------------
- 1 file changed, 75 insertions(+), 72 deletions(-)
-
-diff --git a/xml/Makefile.am b/xml/Makefile.am
-index 5734979..8ff805b 100644
---- a/xml/Makefile.am
-+++ b/xml/Makefile.am
-@@ -1,35 +1,22 @@
- #
- # Copyright (C) 2004 Andrew Beekhof
- #
--# This program is free software; you can redistribute it and/or
--# modify it under the terms of the GNU General Public License
--# as published by the Free Software Foundation; either version 2
--# of the License, or (at your option) any later version.
--# 
--# This program is distributed in the hope that it will be useful,
--# but WITHOUT ANY WARRANTY; without even the implied warranty of
--# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--# GNU General Public License for more details.
--# 
--# You should have received a copy of the GNU General Public License
--# along with this program; if not, write to the Free Software
--# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-+# This source code is licensed under the GNU General Public License version 2
-+# or later (GPLv2+) WITHOUT ANY WARRANTY.
- #
- MAINTAINERCLEANFILES    = Makefile.in
- 
--dtddir			= $(CRM_DTD_DIRECTORY)
--dist_dtd_DATA		= crm.dtd crm-transitional.dtd
--
--xsltdir			= $(dtddir)
--dist_xslt_DATA		= $(top_srcdir)/xml/upgrade06.xsl \
--			  $(top_srcdir)/xml/upgrade-*.xsl
--
--RNGdir			= $(dtddir)
-+# Pacemaker 1.1 has 2 schemas: the CIB schema, and a schema for
-+# crm_mon --as-xml.
-+#
-+# See Readme.md for details on updating CIB schema files
- 
--# See Readme.md for details on updating schema files
-+# The CIB and crm_mon schemas are installed directly in CRM_DTD_DIRECTORY.
-+CIBdir	= $(CRM_DTD_DIRECTORY)
-+MONdir	= $(CRM_DTD_DIRECTORY)
- 
--# Sorted list of available numeric RNG versions,
--# extracted from filenames like NAME-MAJOR[.MINOR][.MINOR-MINOR].rng
-+# Extract a sorted list of available numeric schema versions
-+# from filenames like NAME-MAJOR[.MINOR][.MINOR-MINOR].rng
- numeric_versions = $(shell ls -1 $(1) \
- 			  | sed -n -e 's/^.*-\([0-9][0-9.]*\).rng$$/\1/p' \
- 			  | sort -u -t. -k 1,1n -k 2,2n -k 3,3n)
-@@ -50,27 +37,40 @@ version_pairs_last = $(wordlist \
- 			    ),$(1),$(2) \
- 			  )
- 
--RNG_numeric_versions = $(call numeric_versions,${RNG_files})
-+# Names of CIB schemas that form the choices for cib/configuration content
-+CIB_cfg_base		= options nodes resources constraints fencing acls tags alerts
-+
-+# Names of all schemas (including top level and those included by others)
-+CIB_base		= cib $(CIB_cfg_base) status score rule nvset
-+
-+# All static schema files
-+CIB_files		= $(foreach base,$(CIB_base),$(wildcard $(base).rng $(base)-*.rng))
-+MON_files		= crm_mon.rng
-+
-+# Sorted lists of all numeric schema versions
-+CIB_numeric_versions	= $(call numeric_versions,${CIB_files})
- 
--# The highest numeric version
--RNG_max			?= $(lastword $(RNG_numeric_versions))
-+# The highest numeric schema version
-+CIB_max			?= $(lastword $(CIB_numeric_versions))
- 
--RNG_versions		= next $(RNG_numeric_versions)
--RNG_version_pairs	= $(call version_pairs,${RNG_numeric_versions})
--RNG_version_pairs_cnt	= $(words ${RNG_version_pairs})
--RNG_version_pairs_last  = $(call version_pairs_last,${RNG_version_pairs_cnt},${RNG_version_pairs})
-+# Sorted lists of all schema versions (including "next")
-+CIB_versions		= next $(CIB_numeric_versions)
- 
--RNG_generated		= pacemaker.rng $(foreach base,$(RNG_versions),pacemaker-$(base).rng) versions.rng
-+# Dynamically generated schema files
-+CIB_generated		= pacemaker.rng $(foreach base,$(CIB_versions),pacemaker-$(base).rng) versions.rng
- 
--RNG_cfg_base		= options nodes resources constraints fencing acls tags alerts
--RNG_base		= cib $(RNG_cfg_base) status score rule nvset
--RNG_files		= $(foreach base,$(RNG_base),$(wildcard $(base).rng $(base)-*.rng))
-+CIB_version_pairs	= $(call version_pairs,${CIB_numeric_versions})
-+CIB_version_pairs_cnt	= $(words ${CIB_version_pairs})
-+CIB_version_pairs_last  = $(call version_pairs_last,${CIB_version_pairs_cnt},${CIB_version_pairs})
- 
--# List of non-Pacemaker RNGs
--RNG_extra		= crm_mon.rng
-+dist_CIB_DATA		= $(CIB_files)					\
-+			  upgrade06.xsl					\
-+			  upgrade-1.3.xsl				\
-+			  crm.dtd					\
-+			  crm-transitional.dtd
-+dist_MON_DATA		= $(MON_files)
- 
--dist_RNG_DATA		= $(RNG_files) $(RNG_extra)
--nodist_RNG_DATA		= $(RNG_generated)
-+nodist_CIB_DATA		= $(CIB_generated)
- 
- EXTRA_DIST		= Readme.md			\
- 			  best-match.sh			\
-@@ -79,10 +79,38 @@ EXTRA_DIST		= Readme.md			\
- 			  regression.core.sh		\
- 			  regression.sh
- 
--versions:
--	echo "Max: $(RNG_max)"
--	echo "Available: $(RNG_versions)"
-+cib-versions:
-+	@echo "Max: $(CIB_max)"
-+	@echo "Available: $(CIB_versions)"
- 
-+
-+# Dynamically generated top-level CIB schema
-+pacemaker.rng: pacemaker-$(CIB_max).rng
-+	echo "  RNG      $@"
-+	cp $(top_builddir)/xml/$< $@
-+
-+pacemaker-%.rng: $(CIB_files) best-match.sh Makefile.am
-+	echo "  RNG      $@"
-+	echo '<?xml version="1.0" encoding="UTF-8"?>' > $@
-+	echo '<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">' >> $@
-+	echo '  <start>' >> $@
-+	echo '    <element name="cib">' >> $@
-+	$(srcdir)/best-match.sh cib $(*) $(@) "      "
-+	echo '      <element name="configuration">' >> $@
-+	echo '        <interleave>' >> $@
-+	for rng in $(CIB_cfg_base); do $(srcdir)/best-match.sh $$rng $(*) $(@) "          " || :; done
-+	echo '        </interleave>' >> $@
-+	echo '      </element>' >> $@
-+	echo '      <optional>' >> $@
-+	echo '        <element name="status">' >> $@
-+	$(srcdir)/best-match.sh status $(*) $(@) "          "
-+	echo '        </element>' >> $@
-+	echo '      </optional>' >> $@
-+	echo '    </element>' >> $@
-+	echo '  </start>' >> $@
-+	echo '</grammar>' >> $@
-+
-+# Dynamically generated CIB schema listing all pacemaker versions
- versions.rng: Makefile.am
- 	echo "  RNG      $@"
- 	echo '<?xml version="1.0" encoding="UTF-8"?>' > $@
-@@ -97,7 +125,7 @@ versions.rng: Makefile.am
- 	echo '          <value>transitional-0.6</value>' >> $@
- 	echo '          <value>pacemaker-0.7</value>' >> $@
- 	echo '          <value>pacemaker-1.1</value>' >> $@
--	for rng in $(RNG_versions); do echo "          <value>pacemaker-$$rng</value>" >> $@; done
-+	for rng in $(CIB_versions); do echo "          <value>pacemaker-$$rng</value>" >> $@; done
- 	echo '        </choice>' >> $@
- 	echo '      </attribute>' >> $@
- 	echo '    </optional>' >> $@
-@@ -108,31 +136,6 @@ versions.rng: Makefile.am
- 	echo '  </start>' >> $@
- 	echo '</grammar>' >> $@
- 
--pacemaker.rng: pacemaker-$(RNG_max).rng
--	echo "  RNG      $@"
--	cp $(top_builddir)/xml/$< $@
--
--pacemaker-%.rng: $(RNG_files) best-match.sh Makefile.am
--	echo "  RNG      $@"
--	echo '<?xml version="1.0" encoding="UTF-8"?>' > $@
--	echo '<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">' >> $@
--	echo '  <start>' >> $@
--	echo '    <element name="cib">' >> $@
--	$(top_srcdir)/xml/best-match.sh cib $(*) $(@) "      "
--	echo '      <element name="configuration">' >> $@
--	echo '        <interleave>' >> $@
--	for rng in $(RNG_cfg_base); do $(top_srcdir)/xml/best-match.sh $$rng $(*) $(@) "          " || :; done
--	echo '        </interleave>' >> $@
--	echo '      </element>' >> $@
--	echo '      <optional>' >> $@
--	echo '        <element name="status">' >> $@
--	$(top_srcdir)/xml/best-match.sh status $(*) $(@) "          "
--	echo '        </element>' >> $@
--	echo '      </optional>' >> $@
--	echo '    </element>' >> $@
--	echo '  </start>' >> $@
--	echo '</grammar>' >> $@
--
- # diff fails with ec=2 if no predecessor is found;
- # this uses '=' GNU extension to sed, if that's not available,
- # one can use: hline=`echo "$${p}" | grep -Fn "$${hunk}" | cut -d: -f1`;
-@@ -171,11 +174,11 @@ version_diff = \
- 	done
- 
- diff: best-match.sh
--	@echo "#  Comparing changes in + since $(RNG_max)"
--	$(call version_diff,${RNG_version_pairs_last})
-+	@echo "#  Comparing changes in + since $(CIB_max)"
-+	$(call version_diff,${CIB_version_pairs_last})
- 
- fulldiff: best-match.sh
- 	@echo "#  Comparing all changes across all the subsequent increments"
--	$(call version_diff,${RNG_version_pairs})
-+	$(call version_diff,${CIB_version_pairs})
- 
--CLEANFILES = $(RNG_generated)
-+CLEANFILES = $(CIB_generated)
--- 
-1.8.3.1
-
-
-From da2dd7c8aef6b19fe7b45a0df6ec2d042a3d0049 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Mon, 29 Jul 2019 18:33:29 -0500
-Subject: [PATCH 85/96] Build: xml: make schema files work with VPATH builds
-
-a.k.a pristine builds, where the source and build directories are different
----
- xml/Makefile.am | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/xml/Makefile.am b/xml/Makefile.am
-index 8ff805b..972750f 100644
---- a/xml/Makefile.am
-+++ b/xml/Makefile.am
-@@ -44,7 +44,7 @@ CIB_cfg_base		= options nodes resources constraints fencing acls tags alerts
- CIB_base		= cib $(CIB_cfg_base) status score rule nvset
- 
- # All static schema files
--CIB_files		= $(foreach base,$(CIB_base),$(wildcard $(base).rng $(base)-*.rng))
-+CIB_files		= $(foreach base,$(CIB_base),$(wildcard $(srcdir)/$(base).rng $(srcdir)/$(base)-*.rng))
- MON_files		= crm_mon.rng
- 
- # Sorted lists of all numeric schema versions
--- 
-1.8.3.1
-
-
-From a08ebb7599992a783dadb7cf74f83e127c29f8cc Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Tue, 30 Jul 2019 12:27:06 -0500
-Subject: [PATCH 86/96] Build: doc: make HTML documents compatible with VPATH
- builds
-
----
- doc/Makefile.am | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
-diff --git a/doc/Makefile.am b/doc/Makefile.am
-index a929acb..6c2a3c7 100644
---- a/doc/Makefile.am
-+++ b/doc/Makefile.am
-@@ -110,13 +110,15 @@ EXTRA_DIST	+= $(PE_TXT) $(PE_XML_ONLY)
- EXTRA_DIST	+= $(PR_TXT) $(PR_XML_ONLY)
- EXTRA_DIST	+= pcs-crmsh-quick-ref.md
- 
--%.html: %.txt
- if IS_ASCIIDOC
--	$(AM_V_ASCII)$(ASCIIDOC_CONV) --unsafe --backend=xhtml11 $<
-+ASCIIDOC_HTML_ARGS	= --unsafe --backend=xhtml11
- else
--	$(AM_V_ASCII)$(ASCIIDOC_CONV) --backend=html5 $<
-+ASCIIDOC_HTML_ARGS	= --backend=html5
- endif
- 
-+%.html: %.txt
-+	$(AM_V_ASCII)$(ASCIIDOC_CONV) $(ASCIIDOC_HTML_ARGS) --out-file=$@ $<
-+
- # publican-clusterlabs/xsl/{html,html-single,pdf}.xsl refer to URIs
- # requiring Internet access, hence we shadow that with a XML catalog-based
- # redirect to local files brought with Publican installation;
--- 
-1.8.3.1
-
-
-From 736051ab087c97372891591b0aa907b5d7c1f2dc Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 1 Aug 2019 10:44:26 -0500
-Subject: [PATCH 87/96] Build: makefiles: simplify silent rules usage
-
-make output is terser with --enable-silent-rules at configure time or make V=0
-at make run-time. This simplifies our handling of such silent rules, mainly by
-using AM_V_at and AM_V_GEN appropriately.
-
-This gets rid of AM_V_IMG (which we never defined) and AM_V_ASCII and AM_V_XSL
-(which weren't particularly useful), and adds AM_V_SCHEMA (to replace the
-half-hearted attempt at RNG handling). Our PCMK_quiet now just silences stdout,
-not stderr.
----
- Makefile.common | 52 ++++++++++++++++++++--------------
- doc/Makefile.am | 18 ++++++------
- xml/Makefile.am | 88 ++++++++++++++++++++++++++++-----------------------------
- 3 files changed, 83 insertions(+), 75 deletions(-)
-
-diff --git a/Makefile.common b/Makefile.common
-index a4842b7..386d59d 100644
---- a/Makefile.common
-+++ b/Makefile.common
-@@ -1,27 +1,37 @@
--# Not all current distros support AM_V_P
-+#
-+# Copyright 2014-2019 the Pacemaker project contributors
-+#
-+# The version control history for this file may have further details.
-+#
-+# This source code is licensed under the GNU General Public License version 2
-+# or later (GPLv2+) WITHOUT ANY WARRANTY.
-+#
-+
-+#
-+# Some variables to help with silent rules
- # https://www.gnu.org/software/automake/manual/html_node/Automake-silent_002drules-Option.html
-+#
-+# We require a minimum automake version of 1.11, which includes AM_V_GEN and
-+# AM_V_at, but AM_V_P is not available until 1.13.
- 
- V ?= $(AM_DEFAULT_VERBOSITY)
- 
--PCMK_V = $(pcmk__v_$(V))
--pcmk__v_0 = :
--pcmk__v_1 =
--
-+# When a make command is prefixed with one of the AM_V_* macros, it may also be
-+# desirable to suffix the command with this, to silence stdout.
- PCMK_quiet = $(pcmk_quiet_$(V))
--pcmk_quiet_0 = >/dev/null 2>&1
-+pcmk_quiet_0 = >/dev/null
- pcmk_quiet_1 = 
- 
--AM_V_XSL = $(am__v_XSL_$(V))
--am__v_XSL_0 = @echo "  XSL     " $@;
--am__v_XSL_1 = 
--
-+# AM_V_GEN is intended to be used in custom pattern rules, and replaces echoing
-+# the command used with a more concise line with "GEN" and the name of the file
-+# being generated. Our AM_V_* macros are similar but more descriptive.
- AM_V_MAN = $(am__v_MAN_$(V))
--am__v_MAN_0 = @echo "  MAN     " $@;
-+am__v_MAN_0 = @echo "  MAN      $@";
- am__v_MAN_1 = 
- 
--AM_V_ASCII = $(am__v_ASCII_$(V))
--am__v_ASCII_0 = @echo "  ASCII   " $@;
--am__v_ASCII_1 = 
-+AM_V_SCHEMA = $(am__v_SCHEMA_$(V))
-+am__v_SCHEMA_0 = @echo "  SCHEMA   $@";
-+am__v_SCHEMA_1 = 
- 
- AM_V_PUB = $(am__v_PUB_$(V))
- am__v_PUB_0 = @echo "  PUB     $@: $(DOCBOOK_FORMATS)";
-@@ -37,18 +47,18 @@ man8_MANS		= $(sbin_PROGRAMS:%=%.8) $(sbin_SCRIPTS:%=%.8) $(dist_sbin_SCRIPTS:%=
- endif
- 
- %.8:	% $(MAN8DEPS)
--	chmod a+x $(abs_builddir)/$<
-+	$(AM_V_at)chmod a+x $(abs_builddir)/$<
- 	$(AM_V_MAN)PATH=$(abs_builddir):$$PATH $(HELP2MAN) --output $@ --no-info --section 8 --name "Part of the Pacemaker cluster resource manager" $(abs_builddir)/$<
- 
- %.xml:  %
--	$(AM_V_GEN)$(abs_builddir)/$< metadata > $@
-+	$(AM_V_at)$(abs_builddir)/$< metadata > $@
- 
- %.dbook: %.xml
--	$(AM_V_XSL)$(XSLTPROC) --nonet --novalid --stringparam man.name $* $(DBOOK_OPTS) $(top_srcdir)/xml/ocf-meta2man.xsl $(abs_builddir)/$< > $(abs_builddir)/$@
-+	$(AM_V_at)$(XSLTPROC) --nonet --novalid --stringparam man.name $* $(DBOOK_OPTS) $(top_srcdir)/xml/ocf-meta2man.xsl $(abs_builddir)/$< > $(abs_builddir)/$@
- 
- %.7:	%.dbook
--	$(AM_V_XSL)$(XSLTPROC) $(MANPAGE_XSLT) $(abs_builddir)/$< $(PCMK_quiet)
--
-+	$(AM_V_MAN)$(XSLTPROC) $(MANPAGE_XSLT) $(abs_builddir)/$< $(PCMK_quiet)
-+# 
- # Build docbook from asciidoc because XML is a PITA to edit
- #
- # Build each chapter as a book (since the numbering isn't right for
-@@ -59,9 +69,9 @@ endif
- #
- %.xml:  %.txt
- if IS_ASCIIDOC
--	$(AM_V_ASCII)$(ASCIIDOC_CONV) -b docbook -d book -o $@-tt $<
-+	$(AM_V_GEN)$(ASCIIDOC_CONV) -b docbook -d book -o $@-tt $<
- else
--	$(AM_V_ASCII)$(ASCIIDOC_CONV) -b docbook45 -d book -o $@-tt $<
-+	$(AM_V_GEN)$(ASCIIDOC_CONV) -b docbook45 -d book -o $@-tt $<
- endif
- 	$(AM_V_at)tr -d '\036\r' <$@-tt >$@-t; rm -f $@-tt  # Fix line endings
- 	$(AM_V_at)sed -i 's/\ lang="en"//' $@-t      # Never specify a language in the chapters
-diff --git a/doc/Makefile.am b/doc/Makefile.am
-index 6c2a3c7..a01423d 100644
---- a/doc/Makefile.am
-+++ b/doc/Makefile.am
-@@ -86,13 +86,13 @@ PNGS = $(PNGS_ORIGINAL) $(PNGS_GENERATED)
- graphics: $(PNGS)
- 
- %.png: %.svg
--	$(AM_V_IMG)$(INKSCAPE) --file=$< --export-dpi=90 -C --export-png=$@
-+	$(AM_V_GEN)$(INKSCAPE) --file=$< --export-dpi=90 -C --export-png=$@ $(PCMK_quiet)
- 
- %-small.png: %.svg
--	$(AM_V_IMG)$(INKSCAPE) --file=$< --export-dpi=45 -C --export-png=$@
-+	$(AM_V_GEN)$(INKSCAPE) --file=$< --export-dpi=45 -C --export-png=$@ $(PCMK_quiet)
- 
- %-large.png: %.svg
--	$(AM_V_IMG)$(INKSCAPE) --file=$< --export-dpi=180 -C --export-png=$@
-+	$(AM_V_GEN)$(INKSCAPE) --file=$< --export-dpi=180 -C --export-png=$@ $(PCMK_quiet)
- 
- if BUILD_ASCIIDOC
- generated_docs	+= $(ascii:%.txt=%.html)
-@@ -117,7 +117,7 @@ ASCIIDOC_HTML_ARGS	= --backend=html5
- endif
- 
- %.html: %.txt
--	$(AM_V_ASCII)$(ASCIIDOC_CONV) $(ASCIIDOC_HTML_ARGS) --out-file=$@ $<
-+	$(AM_V_GEN)$(ASCIIDOC_CONV) $(ASCIIDOC_HTML_ARGS) --out-file=$@ $< $(PCMK_quiet)
- 
- # publican-clusterlabs/xsl/{html,html-single,pdf}.xsl refer to URIs
- # requiring Internet access, hence we shadow that with a XML catalog-based
-@@ -164,8 +164,8 @@ endif
- 
- # We have to hardcode the book name
- # With '%' the test for 'newness' fails
--Clusters_from_Scratch.build: $(PNGS)  $(CFS_XML_ONLY) $(CFS_XML) $(CFS_SHARED_XML) $(PUBLICAN_INTREE_DEPS)
--	$(PCMK_V) @echo Building $(@:%.build=%) because of $?
-+Clusters_from_Scratch.build: $(PNGS) $(CFS_XML_ONLY) $(CFS_XML) $(CFS_SHARED_XML) $(PUBLICAN_INTREE_DEPS)
-+	@echo Building $(@:%.build=%) because of $?
- 	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
- if PUBLICAN_INTREE_BRAND
- 	$(AM_V_PUB)cd $(@:%.build=%) \
-@@ -190,7 +190,7 @@ PD_XML_ONLY=$(addprefix Pacemaker_Development/en-US/,$(COMMON_XML) \
- # We have to hardcode the book name
- # With '%' the test for 'newness' fails
- Pacemaker_Development.build: $(PD_XML_ONLY) $(PD_XML) $(PUBLICAN_INTREE_DEPS)
--	$(PCMK_V) @echo Building $(@:%.build=%) because of $?
-+	@echo Building $(@:%.build=%) because of $?
- 	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
- if PUBLICAN_INTREE_BRAND
- 	$(AM_V_PUB)cd $(@:%.build=%) \
-@@ -219,7 +219,7 @@ $(PE_XML): $(PE_SHARED_XML)
- # We have to hardcode the book name
- # With '%' the test for 'newness' fails
- Pacemaker_Explained.build: $(PNGS) $(PE_XML_ONLY) $(PE_XML) $(PE_SHARED_XML) $(PUBLICAN_INTREE_DEPS)
--	$(PCMK_V) @echo Building $(@:%.build=%) because of $?
-+	@echo Building $(@:%.build=%) because of $?
- 	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
- if PUBLICAN_INTREE_BRAND
- 	$(AM_V_PUB)cd $(@:%.build=%) \
-@@ -244,7 +244,7 @@ PR_XML_ONLY=$(addprefix Pacemaker_Remote/en-US/,$(COMMON_XML) \
- # We have to hardcode the book name
- # With '%' the test for 'newness' fails
- Pacemaker_Remote.build: $(PNGS) $(PR_XML_ONLY) $(PR_XML) $(PUBLICAN_INTREE_DEPS)
--	$(PCMK_V) @echo Building $(@:%.build=%) because of $?
-+	@echo Building $(@:%.build=%) because of $?
- 	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
- if PUBLICAN_INTREE_BRAND
- 	$(AM_V_PUB)cd $(@:%.build=%) \
-diff --git a/xml/Makefile.am b/xml/Makefile.am
-index 972750f..af53a6d 100644
---- a/xml/Makefile.am
-+++ b/xml/Makefile.am
-@@ -4,7 +4,8 @@
- # This source code is licensed under the GNU General Public License version 2
- # or later (GPLv2+) WITHOUT ANY WARRANTY.
- #
--MAINTAINERCLEANFILES    = Makefile.in
-+
-+include $(top_srcdir)/Makefile.common
- 
- # Pacemaker 1.1 has 2 schemas: the CIB schema, and a schema for
- # crm_mon --as-xml.
-@@ -86,55 +87,52 @@ cib-versions:
- 
- # Dynamically generated top-level CIB schema
- pacemaker.rng: pacemaker-$(CIB_max).rng
--	echo "  RNG      $@"
--	cp $(top_builddir)/xml/$< $@
-+	$(AM_V_SCHEMA)cp $(top_builddir)/xml/$< $@
- 
- pacemaker-%.rng: $(CIB_files) best-match.sh Makefile.am
--	echo "  RNG      $@"
--	echo '<?xml version="1.0" encoding="UTF-8"?>' > $@
--	echo '<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">' >> $@
--	echo '  <start>' >> $@
--	echo '    <element name="cib">' >> $@
--	$(srcdir)/best-match.sh cib $(*) $(@) "      "
--	echo '      <element name="configuration">' >> $@
--	echo '        <interleave>' >> $@
--	for rng in $(CIB_cfg_base); do $(srcdir)/best-match.sh $$rng $(*) $(@) "          " || :; done
--	echo '        </interleave>' >> $@
--	echo '      </element>' >> $@
--	echo '      <optional>' >> $@
--	echo '        <element name="status">' >> $@
--	$(srcdir)/best-match.sh status $(*) $(@) "          "
--	echo '        </element>' >> $@
--	echo '      </optional>' >> $@
--	echo '    </element>' >> $@
--	echo '  </start>' >> $@
--	echo '</grammar>' >> $@
-+	$(AM_V_at)echo '<?xml version="1.0" encoding="UTF-8"?>' > $@
-+	$(AM_V_at)echo '<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">' >> $@
-+	$(AM_V_at)echo '  <start>' >> $@
-+	$(AM_V_at)echo '    <element name="cib">' >> $@
-+	$(AM_V_at)$(srcdir)/best-match.sh cib $(*) $(@) "      "
-+	$(AM_V_at)echo '      <element name="configuration">' >> $@
-+	$(AM_V_at)echo '        <interleave>' >> $@
-+	$(AM_V_at)for rng in $(CIB_cfg_base); do $(srcdir)/best-match.sh $$rng $(*) $(@) "          " || :; done
-+	$(AM_V_at)echo '        </interleave>' >> $@
-+	$(AM_V_at)echo '      </element>' >> $@
-+	$(AM_V_at)echo '      <optional>' >> $@
-+	$(AM_V_at)echo '        <element name="status">' >> $@
-+	$(AM_V_at)$(srcdir)/best-match.sh status $(*) $(@) "          "
-+	$(AM_V_at)echo '        </element>' >> $@
-+	$(AM_V_at)echo '      </optional>' >> $@
-+	$(AM_V_at)echo '    </element>' >> $@
-+	$(AM_V_at)echo '  </start>' >> $@
-+	$(AM_V_SCHEMA)echo '</grammar>' >> $@
- 
- # Dynamically generated CIB schema listing all pacemaker versions
- versions.rng: Makefile.am
--	echo "  RNG      $@"
--	echo '<?xml version="1.0" encoding="UTF-8"?>' > $@
--	echo '<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">' >> $@
--	echo '  <start>' >> $@
--	echo '   <interleave>' >> $@
--	echo '    <optional>' >> $@
--	echo '      <attribute name="validate-with">' >> $@
--	echo '        <choice>' >> $@
--	echo '          <value>none</value>' >> $@
--	echo '          <value>pacemaker-0.6</value>' >> $@
--	echo '          <value>transitional-0.6</value>' >> $@
--	echo '          <value>pacemaker-0.7</value>' >> $@
--	echo '          <value>pacemaker-1.1</value>' >> $@
--	for rng in $(CIB_versions); do echo "          <value>pacemaker-$$rng</value>" >> $@; done
--	echo '        </choice>' >> $@
--	echo '      </attribute>' >> $@
--	echo '    </optional>' >> $@
--	echo '    <attribute name="admin_epoch"><data type="nonNegativeInteger"/></attribute>' >> $@
--	echo '    <attribute name="epoch"><data type="nonNegativeInteger"/></attribute>' >> $@
--	echo '    <attribute name="num_updates"><data type="nonNegativeInteger"/></attribute>' >> $@
--	echo '   </interleave>' >> $@
--	echo '  </start>' >> $@
--	echo '</grammar>' >> $@
-+	$(AM_V_at)echo '<?xml version="1.0" encoding="UTF-8"?>' > $@
-+	$(AM_V_at)echo '<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">' >> $@
-+	$(AM_V_at)echo '  <start>' >> $@
-+	$(AM_V_at)echo '   <interleave>' >> $@
-+	$(AM_V_at)echo '    <optional>' >> $@
-+	$(AM_V_at)echo '      <attribute name="validate-with">' >> $@
-+	$(AM_V_at)echo '        <choice>' >> $@
-+	$(AM_V_at)echo '          <value>none</value>' >> $@
-+	$(AM_V_at)echo '          <value>pacemaker-0.6</value>' >> $@
-+	$(AM_V_at)echo '          <value>transitional-0.6</value>' >> $@
-+	$(AM_V_at)echo '          <value>pacemaker-0.7</value>' >> $@
-+	$(AM_V_at)echo '          <value>pacemaker-1.1</value>' >> $@
-+	$(AM_V_at)for rng in $(CIB_versions); do echo "          <value>pacemaker-$$rng</value>" >> $@; done
-+	$(AM_V_at)echo '        </choice>' >> $@
-+	$(AM_V_at)echo '      </attribute>' >> $@
-+	$(AM_V_at)echo '    </optional>' >> $@
-+	$(AM_V_at)echo '    <attribute name="admin_epoch"><data type="nonNegativeInteger"/></attribute>' >> $@
-+	$(AM_V_at)echo '    <attribute name="epoch"><data type="nonNegativeInteger"/></attribute>' >> $@
-+	$(AM_V_at)echo '    <attribute name="num_updates"><data type="nonNegativeInteger"/></attribute>' >> $@
-+	$(AM_V_at)echo '   </interleave>' >> $@
-+	$(AM_V_at)echo '  </start>' >> $@
-+	$(AM_V_SCHEMA)echo '</grammar>' >> $@
- 
- # diff fails with ec=2 if no predecessor is found;
- # this uses '=' GNU extension to sed, if that's not available,
--- 
-1.8.3.1
-
-
-From d801c43b35b457170604f2e9d0c16c81cf2c0f98 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 1 Aug 2019 11:09:59 -0500
-Subject: [PATCH 88/96] Build: makefiles: don't echo echo
-
-echo should usually be used as @echo in makefiles; there's no point in seeing:
-
-  echo blah
-  blah
----
- GNUmakefile     | 16 ++++++++--------
- Makefile.am     | 15 ++++++++++++---
- doc/Makefile.am | 14 +++++++-------
- 3 files changed, 27 insertions(+), 18 deletions(-)
-
-diff --git a/GNUmakefile b/GNUmakefile
-index d790865..3dd1055 100644
---- a/GNUmakefile
-+++ b/GNUmakefile
-@@ -207,7 +207,7 @@ srpm-%:	export $(PACKAGE)-%.spec
- 	$(call rpmbuild-with,$(WITH),-bs --define "dist .$*" $(RPM_OPTS),$(PACKAGE).spec)
- 
- chroot: mock-$(MOCK_CFG) mock-install-$(MOCK_CFG) mock-sh-$(MOCK_CFG)
--	echo "Done"
-+	@echo "Done"
- 
- mock-next:
- 	make F=$(shell expr 1 + $(F)) mock
-@@ -216,19 +216,19 @@ mock-rawhide:
- 	make F=rawhide mock
- 
- mock-install-%:
--	echo "Installing packages"
-+	@echo "Installing packages"
- 	mock --root=$* $(MOCK_OPTIONS) --install $(RPM_ROOT)/mock/*.rpm vi sudo valgrind lcov gdb fence-agents psmisc
- 
- mock-install: mock-install-$(MOCK_CFG)
--	echo "Done"
-+	@echo "Done"
- 
- mock-sh: mock-sh-$(MOCK_CFG)
--	echo "Done"
-+	@echo "Done"
- 
- mock-sh-%:
--	echo "Connecting"
-+	@echo "Connecting"
- 	mock --root=$* $(MOCK_OPTIONS) --shell
--	echo "Done"
-+	@echo "Done"
- 
- # eg. WITH="--with cman" make rpm
- mock-%:
-@@ -238,10 +238,10 @@ mock-%:
- 	mock --root=$* --no-cleanup-after --rebuild $(WITH) $(MOCK_OPTIONS) $(RPM_ROOT)/*.src.rpm
- 
- srpm:	srpm-$(DISTRO)
--	echo "Done"
-+	@echo "Done"
- 
- mock:   mock-$(MOCK_CFG)
--	echo "Done"
-+	@echo "Done"
- 
- rpm-dep: $(PACKAGE)-$(DISTRO).spec
- 	if [ x != x`which yum-builddep 2>/dev/null` ]; then			\
-diff --git a/Makefile.am b/Makefile.am
-index 3080445..b47f488 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -63,15 +63,24 @@ scratch.c:
- 
- core:
- 	@echo "Building only core components: $(CORE)"
--	list='$(CORE)'; for subdir in $$list; do echo "Building $$subdir"; $(MAKE) -C $$subdir all || exit 1; done
-+	@for subdir in $(CORE); do \
-+		echo "Building $$subdir"; \
-+		$(MAKE) -C $$subdir all || exit 1; \
-+	done
- 
- core-install:
- 	@echo "Installing only core components: $(CORE)"
--	list='$(CORE)'; for subdir in $$list; do echo "Installing $$subdir"; $(MAKE) -C $$subdir install || exit 1; done
-+	@for subdir in $(CORE); do \
-+	    echo "Installing $$subdir"; \
-+	    $(MAKE) -C $$subdir install || exit 1; \
-+	done
- 
- core-clean:
- 	@echo "Cleaning only core components: $(CORE)"
--	list='$(CORE)'; for subdir in $$list; do echo "Cleaning $$subdir"; $(MAKE) -C $$subdir clean || exit 1; done
-+	@for subdir in $(CORE); do \
-+		echo "Cleaning $$subdir"; \
-+		$(MAKE) -C $$subdir clean || exit 1; \
-+	done
- 
- install-exec-local:
- 	$(INSTALL) -d $(DESTDIR)/$(LCRSODIR)
-diff --git a/doc/Makefile.am b/doc/Makefile.am
-index a01423d..8389054 100644
---- a/doc/Makefile.am
-+++ b/doc/Makefile.am
-@@ -262,14 +262,14 @@ endif
- 
- # Update the translation template
- pot:
--	for book in $(docbook); do 				      \
-+	@for book in $(docbook); do 				      \
- 		echo "Updating translation templates in: $$book";     \
- 		( cd $$book && RPM_BUILD_DIR="" $(PUBLICAN) update_pot ); \
- 	done
- 
- # Update the actual translations
- po: pot
--	for book in $(docbook); do 				      \
-+	@for book in $(docbook); do 				      \
- 		echo "Updating translations in: $$book";     \
- 		( cd $$book && RPM_BUILD_DIR="" $(PUBLICAN) update_po --langs=all );\
- 	done
-@@ -300,7 +300,7 @@ brand-build: $(BRAND_DEPS)
- 	cd publican-clusterlabs && publican build --formats=xml --langs=all --publish
- 
- brand: brand-build
--	echo "Installing..."
-+	@echo "Installing branded content..."
- 	cd publican-clusterlabs && sudo publican install_brand --path=$(datadir)/publican/Common_Content
- 
- brand-rpm-clean:
-@@ -315,14 +315,14 @@ brand-rpm-install: brand-rpm-build
- pdf:
- 	make DOCBOOK_FORMATS="pdf" all-local
- 
--www: clean-local $(generated_docs) $(ascii)
-+www: clean-local $(doc_DATA)
- 	for book in $(docbook); do 							\
- 		sed -i.sed 's@^brand:.*@brand: clusterlabs@' $$book/publican.cfg;	\
- 	done
--	make DOCBOOK_FORMATS="pdf,html,html-single,epub" DOCBOOK_LANGS="$(UPLOAD_LANGS)" all-local
--	echo Uploading current $(PACKAGE_SERIES) documentation set to clusterlabs.org
-+	$(MAKE) DOCBOOK_FORMATS="pdf,html,html-single,epub" DOCBOOK_LANGS="$(UPLOAD_LANGS)" all-local
-+	@echo Uploading current $(PACKAGE_SERIES) documentation set to clusterlabs.org
- if BUILD_DOCBOOK
--	for book in $(docbook); do 									\
-+	@for book in $(docbook); do 									\
- 		echo Uploading $$book...;								\
- 		echo "Generated on `date` from version: $(shell git log --pretty="format:%h %d" -n 1)" >> $$book/publish/build-$(PACKAGE_SERIES).txt;	\
- 		rsync $(RSYNC_OPTS) $$book/publish/* "$(RSYNC_DEST)/$(PACKAGE)/doc/";			\
--- 
-1.8.3.1
-
-
-From 1ac3f3ec7702e5aaff3c77e75da817370602eab7 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 1 Aug 2019 11:11:25 -0500
-Subject: [PATCH 89/96] Build: doc: reorganize and comment makefile
-
-for simplicity and readability
----
- doc/Makefile.am | 208 +++++++++++++++++++++++++-------------------------------
- 1 file changed, 94 insertions(+), 114 deletions(-)
-
-diff --git a/doc/Makefile.am b/doc/Makefile.am
-index 8389054..b1c9e06 100644
---- a/doc/Makefile.am
-+++ b/doc/Makefile.am
-@@ -19,14 +19,29 @@
- #
- include $(top_srcdir)/Makefile.common
- 
--helpdir		= $(datadir)/$(PACKAGE)
-+# Deprecated plaintext documents (also dynamically converted to HTML)
-+ascii		= acls.txt			\
-+		  crm_fencing.txt
-+generated_docs	=
-+if BUILD_ASCIIDOC
-+generated_docs	+= $(ascii:%.txt=%.html)
-+endif
-+
-+# Current Publican/docbook-based documentation
-+docbook		= Clusters_from_Scratch		\
-+		  Pacemaker_Development		\
-+		  Pacemaker_Explained		\
-+		  Pacemaker_Remote
-+docbook_build = $(docbook:%=%.build)
-+
-+doc_DATA		= $(ascii) $(generated_docs)
- 
--ascii		= crm_fencing.txt acls.txt
--docbook		=	Clusters_from_Scratch		\
--			Pacemaker_Development		\
--			Pacemaker_Explained		\
--			Pacemaker_Remote
--doc_DATA	= $(ascii) $(generated_docs)
-+EXTRA_DIST	= $(ascii) $(SHARED_TXT) $(PNGS_ORIGINAL) $(DOTS) $(SVGS)
-+EXTRA_DIST	+= $(CFS_TXT) $(CFS_XML_ONLY)
-+EXTRA_DIST	+= $(PD_TXT) $(PD_XML_ONLY)
-+EXTRA_DIST	+= $(PE_TXT) $(PE_XML_ONLY)
-+EXTRA_DIST	+= $(PR_TXT) $(PR_XML_ONLY)
-+EXTRA_DIST	+= pcs-crmsh-quick-ref.md
- 
- # toplevel rsync destination for www targets (without trailing slash)
- RSYNC_DEST      ?= root@www.clusterlabs.org:/var/www/html
-@@ -35,21 +50,13 @@ RSYNC_DEST      ?= root@www.clusterlabs.org:/var/www/html
- # don't cross filesystems, sparse, show progress
- RSYNC_OPTS      = -rlptvzxS --progress
- 
--publican_docs   =
--generated_docs	=
--generated_mans	=
--
--
--# What formats to build: pdf,html,html-single,html-desktop,epub
-+# What formats to build by default: pdf,html,html-single,html-desktop,epub
- DOCBOOK_FORMATS := html-desktop
- 
--# What languages to build
-+# What languages to build and upload to website by default
-+# (currently only en-US because translations are out of date)
- DOCBOOK_LANGS   := en-US
- 
--# What languages to build for uploading to website
--# (currently only en-US because translations aren't up-to-date)
--UPLOAD_LANGS    = en-US
--
- # @TODO We could simplify this (and .gitignore) by establishing a convention
- # that original image source begins with an uppercase letter and generated
- # files with lowercase.
-@@ -65,7 +72,7 @@ SVGS =	$(wildcard Clusters_from_Scratch/en-US/images/pcmk-*.svg)	\
- 	$(wildcard Pacemaker_Explained/en-US/images/pcmk-*.svg)	\
- 	$(DOTS:%.dot=%.svg)
- 
--# Final images
-+# Final images (some originally in PNG, others generated from SVG)
- PNGS_ORIGINAL =	Pacemaker_Remote/en-US/images/pcmk-ha-cluster-stack.png	\
- 		Pacemaker_Remote/en-US/images/pcmk-ha-remote-stack.png	\
- 		Clusters_from_Scratch/en-US/images/Console.png		\
-@@ -94,22 +101,6 @@ graphics: $(PNGS)
- %-large.png: %.svg
- 	$(AM_V_GEN)$(INKSCAPE) --file=$< --export-dpi=180 -C --export-png=$@ $(PCMK_quiet)
- 
--if BUILD_ASCIIDOC
--generated_docs	+= $(ascii:%.txt=%.html)
--
--if BUILD_DOCBOOK
--publican_docs	+= $(docbook)
--endif
--endif
--
--EXTRA_DIST	= $(ascii) $(SHARED_TXT) $(PNGS_ORIGINAL) $(DOTS) $(SVGS)
--EXTRA_DIST	+= $(CFS_TXT) $(CFS_XML_ONLY)
--EXTRA_DIST	+= $(PA_TXT) $(PA_XML_ONLY)
--EXTRA_DIST	+= $(PD_TXT) $(PD_XML_ONLY)
--EXTRA_DIST	+= $(PE_TXT) $(PE_XML_ONLY)
--EXTRA_DIST	+= $(PR_TXT) $(PR_XML_ONLY)
--EXTRA_DIST	+= pcs-crmsh-quick-ref.md
--
- if IS_ASCIIDOC
- ASCIIDOC_HTML_ARGS	= --unsafe --backend=xhtml11
- else
-@@ -147,119 +138,107 @@ COMMON_XML = Author_Group.xml Book_Info.xml Revision_History.xml
- SHARED_TXT=$(wildcard shared/en-US/*.txt)
- SHARED_XML=$(SHARED_TXT:%.txt=%.xml)
- 
-+if PUBLICAN_INTREE_BRAND
-+PUBLICAN_INTREE_DEPS	= publican-catalog
-+PUBLICAN_INTREE_ENV	= XML_CATALOG_FILES="$(CURDIR)/publican-catalog"
-+PUBLICAN_INTREE_OPT	= --brand_dir=../publican-clusterlabs 
-+else
-+PUBLICAN_INTREE_DEPS	=
-+PUBLICAN_INTREE_ENV	=
-+PUBLICAN_INTREE_OPT	=
-+endif
- 
--CFS_SHARED_TXT=$(addprefix shared/en-US/,pacemaker-intro.txt)
--CFS_SHARED_XML=$(CFS_SHARED_TXT:%.txt=%.xml)
--CFS_TXT=$(wildcard Clusters_from_Scratch/en-US/*.txt)
--CFS_XML=$(CFS_TXT:%.txt=%.xml)
--CFS_XML_ONLY=$(addprefix Clusters_from_Scratch/en-US/,$(COMMON_XML) \
--  Clusters_from_Scratch.ent Clusters_from_Scratch.xml Preface.xml)
- 
--$(CFS_XML): $(CFS_SHARED_XML)
-+# Clusters From Scratch
- 
--PUBLICAN_INTREE_DEPS =
--if PUBLICAN_INTREE_BRAND
--PUBLICAN_INTREE_DEPS += publican-catalog
--endif
-+CFS_SHARED_TXT	= $(addprefix shared/en-US/,pacemaker-intro.txt)
-+CFS_SHARED_XML	= $(CFS_SHARED_TXT:%.txt=%.xml)
-+CFS_TXT		= $(wildcard Clusters_from_Scratch/en-US/*.txt)
-+CFS_XML_GEN	= $(CFS_TXT:%.txt=%.xml)
-+CFS_XML_ONLY	= $(addprefix Clusters_from_Scratch/en-US/,$(COMMON_XML) \
-+		  Clusters_from_Scratch.ent \
-+		  Clusters_from_Scratch.xml \
-+		  Preface.xml)
-+CFS_DEPS	= $(PNGS) $(CFS_SHARED_XML) $(CFS_XML_ONLY) $(CFS_XML_GEN)
- 
- # We have to hardcode the book name
- # With '%' the test for 'newness' fails
--Clusters_from_Scratch.build: $(PNGS) $(CFS_XML_ONLY) $(CFS_XML) $(CFS_SHARED_XML) $(PUBLICAN_INTREE_DEPS)
-+Clusters_from_Scratch.build: $(CFS_DEPS) $(PUBLICAN_INTREE_DEPS)
- 	@echo Building $(@:%.build=%) because of $?
- 	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
--if PUBLICAN_INTREE_BRAND
--	$(AM_V_PUB)cd $(@:%.build=%) \
--	&& RPM_BUILD_DIR="" XML_CATALOG_FILES="$(CURDIR)/publican-catalog" \
--	   $(PUBLICAN) build --publish --langs=$(DOCBOOK_LANGS) --formats=$(DOCBOOK_FORMATS) --brand_dir=../publican-clusterlabs \
--	   $(PCMK_quiet)
--else
--	$(AM_V_PUB)cd $(@:%.build=%) \
--	&& RPM_BUILD_DIR="" \
--	   $(PUBLICAN) build --publish --langs=$(DOCBOOK_LANGS) --formats=$(DOCBOOK_FORMATS) \
--	   $(PCMK_quiet)
--endif
-+	$(AM_V_PUB)cd $(@:%.build=%) && RPM_BUILD_DIR="" $(PUBLICAN_INTREE_ENV)	\
-+	  $(PUBLICAN) build --publish --langs="$(DOCBOOK_LANGS)"		\
-+	    --formats="$(DOCBOOK_FORMATS)" $(PUBLICAN_INTREE_OPT) $(PCMK_quiet)
- 	rm -rf $(@:%.build=%)/tmp
- 	touch $@
- 
- 
--PD_TXT=$(wildcard Pacemaker_Development/en-US/*.txt)
--PD_XML=$(PD_TXT:%.txt=%.xml)
--PD_XML_ONLY=$(addprefix Pacemaker_Development/en-US/,$(COMMON_XML) \
--  Pacemaker_Development.ent Pacemaker_Development.xml)
-+# Pacemaker Development
-+
-+PD_TXT		= $(wildcard Pacemaker_Development/en-US/*.txt)
-+PD_XML_GEN	= $(PD_TXT:%.txt=%.xml)
-+PD_XML_ONLY	= $(addprefix Pacemaker_Development/en-US/,$(COMMON_XML) \
-+		  Pacemaker_Development.ent \
-+		  Pacemaker_Development.xml)
-+PD_DEPS		= $(PD_XML_ONLY) $(PD_XML_GEN)
- 
- # We have to hardcode the book name
- # With '%' the test for 'newness' fails
--Pacemaker_Development.build: $(PD_XML_ONLY) $(PD_XML) $(PUBLICAN_INTREE_DEPS)
-+Pacemaker_Development.build: $(PD_DEPS) $(PUBLICAN_INTREE_DEPS)
- 	@echo Building $(@:%.build=%) because of $?
- 	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
--if PUBLICAN_INTREE_BRAND
--	$(AM_V_PUB)cd $(@:%.build=%) \
--	&& RPM_BUILD_DIR="" XML_CATALOG_FILES="$(CURDIR)/publican-catalog" \
--	   $(PUBLICAN) build --publish --langs=$(DOCBOOK_LANGS) --formats=$(DOCBOOK_FORMATS) --brand_dir=../publican-clusterlabs \
--	   $(PCMK_quiet)
--else
--	$(AM_V_PUB)cd $(@:%.build=%) \
--	&& RPM_BUILD_DIR="" \
--	   $(PUBLICAN) build --publish --langs=$(DOCBOOK_LANGS) --formats=$(DOCBOOK_FORMATS) \
--	   $(PCMK_quiet)
--endif
-+	$(AM_V_PUB)cd $(@:%.build=%) && RPM_BUILD_DIR="" $(PUBLICAN_INTREE_ENV)	\
-+	  $(PUBLICAN) build --publish --langs="$(DOCBOOK_LANGS)"		\
-+	    --formats="$(DOCBOOK_FORMATS)" $(PUBLICAN_INTREE_OPT) $(PCMK_quiet)
- 	rm -rf $(@:%.build=%)/tmp
- 	touch $@
- 
- 
--PE_SHARED_TXT=$(addprefix shared/en-US/,pacemaker-intro.txt)
--PE_SHARED_XML=$(PE_SHARED_TXT:%.txt=%.xml)
--PE_TXT=$(wildcard Pacemaker_Explained/en-US/*.txt)
--PE_XML=$(PE_TXT:%.txt=%.xml)
--PE_XML_ONLY=$(addprefix Pacemaker_Explained/en-US/,$(COMMON_XML) \
--  Pacemaker_Explained.ent Pacemaker_Explained.xml Preface.xml)
-+# Pacemaker Explained
- 
--$(PE_XML): $(PE_SHARED_XML)
-+PE_SHARED_TXT	= $(addprefix shared/en-US/,pacemaker-intro.txt)
-+PE_SHARED_XML	= $(PE_SHARED_TXT:%.txt=%.xml)
-+PE_TXT		= $(wildcard Pacemaker_Explained/en-US/*.txt)
-+PE_XML_GEN	= $(PE_TXT:%.txt=%.xml)
-+PE_XML_ONLY	= $(addprefix Pacemaker_Explained/en-US/,$(COMMON_XML) \
-+		  Pacemaker_Explained.ent \
-+		  Pacemaker_Explained.xml \
-+		  Preface.xml)
-+PE_DEPS		= $(PNGS) $(PE_SHARED_XML) $(PE_XML_ONLY) $(PE_XML_GEN)
- 
- # We have to hardcode the book name
- # With '%' the test for 'newness' fails
--Pacemaker_Explained.build: $(PNGS) $(PE_XML_ONLY) $(PE_XML) $(PE_SHARED_XML) $(PUBLICAN_INTREE_DEPS)
-+Pacemaker_Explained.build: $(PE_DEPS) $(PUBLICAN_INTREE_DEPS)
- 	@echo Building $(@:%.build=%) because of $?
- 	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
--if PUBLICAN_INTREE_BRAND
--	$(AM_V_PUB)cd $(@:%.build=%) \
--	&& RPM_BUILD_DIR="" XML_CATALOG_FILES="$(CURDIR)/publican-catalog" \
--	   $(PUBLICAN) build --publish --langs=$(DOCBOOK_LANGS) --formats=$(DOCBOOK_FORMATS) --brand_dir=../publican-clusterlabs \
--	   $(PCMK_quiet)
--else
--	$(AM_V_PUB)cd $(@:%.build=%) \
--	&& RPM_BUILD_DIR="" \
--	   $(PUBLICAN) build --publish --langs=$(DOCBOOK_LANGS) --formats=$(DOCBOOK_FORMATS) \
--	   $(PCMK_quiet)
--endif
-+	$(AM_V_PUB)cd $(@:%.build=%) && RPM_BUILD_DIR="" $(PUBLICAN_INTREE_ENV)	\
-+	  $(PUBLICAN) build --publish --langs="$(DOCBOOK_LANGS)"		\
-+	    --formats="$(DOCBOOK_FORMATS)" $(PUBLICAN_INTREE_OPT) $(PCMK_quiet)
- 	rm -rf $(@:%.build=%)/tmp
- 	touch $@
- 
- 
--PR_TXT=$(wildcard Pacemaker_Remote/en-US/*.txt)
--PR_XML=$(PR_TXT:%.txt=%.xml)
--PR_XML_ONLY=$(addprefix Pacemaker_Remote/en-US/,$(COMMON_XML) \
--  Pacemaker_Remote.ent Pacemaker_Remote.xml)
-+# Pacemaker Remote
-+
-+PR_TXT		= $(wildcard Pacemaker_Remote/en-US/*.txt)
-+PR_XML_GEN	= $(PR_TXT:%.txt=%.xml)
-+PR_XML_ONLY	= $(addprefix Pacemaker_Remote/en-US/,$(COMMON_XML) \
-+		  Pacemaker_Remote.ent \
-+		  Pacemaker_Remote.xml)
-+PR_DEPS		= $(PR_XML_ONLY) $(PR_XML_GEN)
- 
- # We have to hardcode the book name
- # With '%' the test for 'newness' fails
--Pacemaker_Remote.build: $(PNGS) $(PR_XML_ONLY) $(PR_XML) $(PUBLICAN_INTREE_DEPS)
-+Pacemaker_Remote.build: $(PNGS) $(PR_DEPS) $(PUBLICAN_INTREE_DEPS)
- 	@echo Building $(@:%.build=%) because of $?
- 	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
--if PUBLICAN_INTREE_BRAND
--	$(AM_V_PUB)cd $(@:%.build=%) \
--	&& RPM_BUILD_DIR="" XML_CATALOG_FILES="$(CURDIR)/publican-catalog" \
--	   $(PUBLICAN) build --publish --langs=$(DOCBOOK_LANGS) --formats=$(DOCBOOK_FORMATS) --brand_dir=../publican-clusterlabs \
--	   $(PCMK_quiet)
--else
--	$(AM_V_PUB)cd $(@:%.build=%) \
--	&& RPM_BUILD_DIR="" \
--	   $(PUBLICAN) build --publish --langs=$(DOCBOOK_LANGS) --formats=$(DOCBOOK_FORMATS) \
--	   $(PCMK_quiet)
--endif
-+	$(AM_V_PUB)cd $(@:%.build=%) && RPM_BUILD_DIR="" $(PUBLICAN_INTREE_ENV)	\
-+	  $(PUBLICAN) build --publish --langs="$(DOCBOOK_LANGS)"		\
-+	    --formats="$(DOCBOOK_FORMATS)" $(PUBLICAN_INTREE_OPT) $(PCMK_quiet)
- 	rm -rf $(@:%.build=%)/tmp
- 	touch $@
- 
-+
- # Update the translation template
- pot:
- 	@for book in $(docbook); do 				      \
-@@ -275,8 +254,6 @@ po: pot
- 	done
- 
- if BUILD_DOCBOOK
--docbook_build = $(docbook:%=%.build)
--
- all-local: $(docbook_build) */publican.cfg
- 
- install-data-local: all-local
-@@ -316,10 +293,12 @@ pdf:
- 	make DOCBOOK_FORMATS="pdf" all-local
- 
- www: clean-local $(doc_DATA)
-+if BUILD_DOCBOOK
- 	for book in $(docbook); do 							\
- 		sed -i.sed 's@^brand:.*@brand: clusterlabs@' $$book/publican.cfg;	\
- 	done
--	$(MAKE) DOCBOOK_FORMATS="pdf,html,html-single,epub" DOCBOOK_LANGS="$(UPLOAD_LANGS)" all-local
-+endif
-+	$(MAKE) DOCBOOK_FORMATS="pdf,html,html-single,epub" DOCBOOK_LANGS="$(DOCBOOK_LANGS)" all-local
- 	@echo Uploading current $(PACKAGE_SERIES) documentation set to clusterlabs.org
- if BUILD_DOCBOOK
- 	@for book in $(docbook); do 									\
-@@ -328,11 +307,12 @@ if BUILD_DOCBOOK
- 		rsync $(RSYNC_OPTS) $$book/publish/* "$(RSYNC_DEST)/$(PACKAGE)/doc/";			\
- 	done
- endif
--	rsync $(RSYNC_OPTS) $(generated_docs) $(ascii) "$(RSYNC_DEST)/$(PACKAGE)/doc/"
-+	rsync $(RSYNC_OPTS) $(doc_DATA) "$(RSYNC_DEST)/$(PACKAGE)/doc/"
-+
- 
- clean-local:
- 	-rm -f $(PNGS_GENERATED)
- 	-rm -rf $(generated_docs) $(generated_mans) $(docbook_build)
--	-rm -rf $(SHARED_XML) $(CFS_XML) $(PE_XML) $(PR_XML)
-+	-rm -rf $(SHARED_XML) $(CFS_XML_GEN) $(PD_XML_GEN) $(PE_XML_GEN) $(PR_XML_GEN)
- 	-rm -rf  publican-catalog-fallback publican-catalog
- 	for book in $(docbook); do rm -rf $$book/tmp $$book/publish; done
--- 
-1.8.3.1
-
-
-From 00c927f263760bc3163f45fabc2744842f128d3f Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 1 Aug 2019 14:29:41 -0500
-Subject: [PATCH 90/96] Build: doc: properly clean all generated files
-
----
- doc/Makefile.am | 25 +++++++++++++++++--------
- 1 file changed, 17 insertions(+), 8 deletions(-)
-
-diff --git a/doc/Makefile.am b/doc/Makefile.am
-index b1c9e06..dfc6732 100644
---- a/doc/Makefile.am
-+++ b/doc/Makefile.am
-@@ -281,7 +281,7 @@ brand: brand-build
- 	cd publican-clusterlabs && sudo publican install_brand --path=$(datadir)/publican/Common_Content
- 
- brand-rpm-clean:
--	find publican-clusterlabs -name "*.noarch.rpm" -exec rm -f \{\} \;
-+	-find publican-clusterlabs -name "*.noarch.rpm" -exec rm -f \{\} \;
- 
- brand-rpm-build: brand-rpm-clean brand-build
- 	cd publican-clusterlabs && $(PUBLICAN) package --binary
-@@ -309,10 +309,19 @@ if BUILD_DOCBOOK
- endif
- 	rsync $(RSYNC_OPTS) $(doc_DATA) "$(RSYNC_DEST)/$(PACKAGE)/doc/"
- 
--
--clean-local:
--	-rm -f $(PNGS_GENERATED)
--	-rm -rf $(generated_docs) $(generated_mans) $(docbook_build)
--	-rm -rf $(SHARED_XML) $(CFS_XML_GEN) $(PD_XML_GEN) $(PE_XML_GEN) $(PR_XML_GEN)
--	-rm -rf  publican-catalog-fallback publican-catalog
--	for book in $(docbook); do rm -rf $$book/tmp $$book/publish; done
-+ALL_GEN	= $(generated_docs)		\
-+	  $(docbook_build)		\
-+	  $(PNGS_GENERATED)		\
-+	  $(SHARED_XML)			\
-+	  $(CFS_XML_GEN)		\
-+	  $(PD_XML_GEN)			\
-+	  $(PE_XML_GEN)			\
-+	  $(PR_XML_GEN)			\
-+	  publican-catalog-fallback	\
-+	  publican-catalog
-+
-+clean-local: brand-rpm-clean
-+	-rm -f $(ALL_GEN)
-+	-for book in $(docbook); do			\
-+		rm -rf $$book/tmp $$book/publish;	\
-+	done
--- 
-1.8.3.1
-
-
-From b022f4fe58424fe9149aebeef45f85c2abd6fcf9 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 1 Aug 2019 15:56:20 -0500
-Subject: [PATCH 91/96] Build: clean up Makefile.common
-
-Reorganize and comment for readability
----
- Makefile.common   | 43 ++++++++++++++++++++++++++++++++++++++-----
- tools/Makefile.am |  5 ++++-
- 2 files changed, 42 insertions(+), 6 deletions(-)
-
-diff --git a/Makefile.common b/Makefile.common
-index 386d59d..f7661c9 100644
---- a/Makefile.common
-+++ b/Makefile.common
-@@ -42,22 +42,57 @@ MAINTAINERCLEANFILES	= Makefile.in
- AM_CPPFLAGS		= -I$(top_builddir)/include -I$(top_srcdir)/include   \
- 			  -I$(top_builddir)/libltdl -I$(top_srcdir)/libltdl
- 
-+#
-+# Man page builders
-+#
-+# We have three types of man pages:
-+# - man pages for the tools
-+# - man pages for OCF agents
-+# - man pages for cluster properties used by daemons
-+#
-+# "BUILD_HELP" actually means "help2man is available", so it only controls the
-+# tool man pages, which are generated by help2man. The other man pages are
-+# generated via XSL transforms.
-+#
-+
- if BUILD_HELP
- man8_MANS		= $(sbin_PROGRAMS:%=%.8) $(sbin_SCRIPTS:%=%.8) $(dist_sbin_SCRIPTS:%=%.8)
--endif
- 
-+HELP2MAN_ARGS = -N --section 8 --name "Part of the Pacemaker cluster resource manager"
-+
-+# Some of our tools' help are just shell script invocations of another tool's
-+# help. Putting the real tool in MAN8DEPS helps detect when the wrapped help
-+# needs updating.
-+#
-+# If a ".inc" file exists, the tool has been converted to use glib for
-+# argument parsing, otherwise it still uses the libcrmcommon functions.
-+#
-+# @TODO Drop MAN8DEPS once we've converted all tools to libpacemaker API calls
-+#       and all wrappers to C code.
- %.8:	% $(MAN8DEPS)
- 	$(AM_V_at)chmod a+x $(abs_builddir)/$<
--	$(AM_V_MAN)PATH=$(abs_builddir):$$PATH $(HELP2MAN) --output $@ --no-info --section 8 --name "Part of the Pacemaker cluster resource manager" $(abs_builddir)/$<
-+	$(AM_V_MAN)PATH=$(abs_builddir):$$PATH $(HELP2MAN) --output $@		\
-+		$(HELP2MAN_ARGS) $(abs_builddir)/$<
-+endif
- 
-+# Save raw XML meta-data from daemon executables, for later conversion into man
-+# pages. (Note that more specific rules may override this for creating other
-+# types of XML files.)
- %.xml:  %
- 	$(AM_V_at)$(abs_builddir)/$< metadata > $@
- 
-+# Process the raw daemon and OCF agent meta-data output using our
-+# meta-data-to-docbook-XML tranform.
- %.dbook: %.xml
--	$(AM_V_at)$(XSLTPROC) --nonet --novalid --stringparam man.name $* $(DBOOK_OPTS) $(top_srcdir)/xml/ocf-meta2man.xsl $(abs_builddir)/$< > $(abs_builddir)/$@
-+	$(AM_V_at)$(XSLTPROC) --nonet --novalid --stringparam man.name $* \
-+		$(DBOOK_OPTS) $(top_srcdir)/xml/ocf-meta2man.xsl \
-+		$(abs_builddir)/$< > $(abs_builddir)/$@
- 
-+# Generate the actual man page for an OCF resource agent from the intermediate
-+# docbook XML.
- %.7:	%.dbook
- 	$(AM_V_MAN)$(XSLTPROC) $(MANPAGE_XSLT) $(abs_builddir)/$< $(PCMK_quiet)
-+
- # 
- # Build docbook from asciidoc because XML is a PITA to edit
- #
-@@ -86,5 +121,3 @@ endif
- 	  $@-t  # We just want the appendix tag (asciidoctor adds non-empty book-level title)
- 	$(AM_V_at)sed -i 's/book>/chapter>/g' $@-t   # Rename to chapter (won't trigger if previous sed did)
- 	$(AM_V_GEN)mv $@-t $@
--
--#	echo Rebuilt $@ from $<
-diff --git a/tools/Makefile.am b/tools/Makefile.am
-index 6960548..e403849 100644
---- a/tools/Makefile.am
-+++ b/tools/Makefile.am
-@@ -63,7 +63,10 @@ endif
- 
- ## SOURCES
- 
--MAN8DEPS		= crm_attribute crm_node
-+# A few tools are just thin wrappers around crm_attribute.
-+# This makes their help get updated when crm_attribute changes
-+# (see Makefile.common).
-+MAN8DEPS		= crm_attribute
- 
- crmadmin_SOURCES	= crmadmin.c
- crmadmin_LDADD		= $(top_builddir)/lib/pengine/libpe_status.la \
--- 
-1.8.3.1
-
-
-From 49e892641dce5870407dcd3bd5322e04893461da Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 1 Aug 2019 16:50:21 -0500
-Subject: [PATCH 92/96] Build: doc: move text-to-DocBook rule from common to
- doc
-
-... since it's only used there, and was a bit confusing next to the
-meta-data-to-DocBook rule in common.
----
- Makefile.common | 29 -----------------------------
- doc/Makefile.am | 26 ++++++++++++++++++++++++++
- 2 files changed, 26 insertions(+), 29 deletions(-)
-
-diff --git a/Makefile.common b/Makefile.common
-index f7661c9..2731922 100644
---- a/Makefile.common
-+++ b/Makefile.common
-@@ -92,32 +92,3 @@ endif
- # docbook XML.
- %.7:	%.dbook
- 	$(AM_V_MAN)$(XSLTPROC) $(MANPAGE_XSLT) $(abs_builddir)/$< $(PCMK_quiet)
--
--# 
--# Build docbook from asciidoc because XML is a PITA to edit
--#
--# Build each chapter as a book (since the numbering isn't right for
--# articles and only books can have appendices) and then strip out the
--# bits we don't want/need
--#
--# XXX Sequence of tr/sed commands should be replaced with a single XSLT
--#
--%.xml:  %.txt
--if IS_ASCIIDOC
--	$(AM_V_GEN)$(ASCIIDOC_CONV) -b docbook -d book -o $@-tt $<
--else
--	$(AM_V_GEN)$(ASCIIDOC_CONV) -b docbook45 -d book -o $@-tt $<
--endif
--	$(AM_V_at)tr -d '\036\r' <$@-tt >$@-t; rm -f $@-tt  # Fix line endings
--	$(AM_V_at)sed -i 's/\ lang="en"//' $@-t      # Never specify a language in the chapters
--	$(AM_V_at)sed -i 's/simpara/para/g' $@-t     # publican doesn't correctly render footnotes with simpara
--	$(AM_V_at)sed -i 's/.*<date>.*//g' $@-t      # Remove dangling tag
--	$(AM_V_at)sed -i 's/.*preface>//g' $@-t      # Remove preface elements
--	$(AM_V_at)sed -i 's:<title></title>::g' $@-t # Remove empty title
--	$(AM_V_at)sed -i 's/chapter/section/g' $@-t  # Chapters become sections, so that books can become chapters
--	$(AM_V_at)sed -i 's/<.*bookinfo.*>//g' $@-t  # Strip out bookinfo, we don't need it
--	$(AM_V_at)! grep -q "<appendix" $@-t || sed -i \
--	  's/.*book>//;tb;bf;:b;N;s/.*<title>.*<\/title>.*//;tb;/<appendix/{:i;n;/<\/appendix/{p;d};bi};bb;:f;p;d' \
--	  $@-t  # We just want the appendix tag (asciidoctor adds non-empty book-level title)
--	$(AM_V_at)sed -i 's/book>/chapter>/g' $@-t   # Rename to chapter (won't trigger if previous sed did)
--	$(AM_V_GEN)mv $@-t $@
-diff --git a/doc/Makefile.am b/doc/Makefile.am
-index dfc6732..5ff350c 100644
---- a/doc/Makefile.am
-+++ b/doc/Makefile.am
-@@ -103,13 +103,39 @@ graphics: $(PNGS)
- 
- if IS_ASCIIDOC
- ASCIIDOC_HTML_ARGS	= --unsafe --backend=xhtml11
-+ASCIIDOC_DBOOK_ARGS	= -b docbook -d book
- else
- ASCIIDOC_HTML_ARGS	= --backend=html5
-+ASCIIDOC_DBOOK_ARGS	= -b docbook45 -d book
- endif
- 
- %.html: %.txt
- 	$(AM_V_GEN)$(ASCIIDOC_CONV) $(ASCIIDOC_HTML_ARGS) --out-file=$@ $< $(PCMK_quiet)
- 
-+# 
-+# Generate DocBook XML from asciidoc text.
-+#
-+# Build each chapter as a book (since the numbering isn't right for
-+# articles and only books can have appendices) and then strip out the
-+# bits we don't want or need.
-+#
-+# XXX Sequence of tr/sed commands should be replaced with a single XSLT
-+#
-+%.xml:  %.txt
-+	$(AM_V_at)$(ASCIIDOC_CONV) $(ASCIIDOC_DBOOK_ARGS) -o - $< | tr -d '\036\r' >$@-t # Convert, fix line endings
-+	$(AM_V_at)sed -i 's/\ lang="en"//' $@-t      # Never specify a language in the chapters
-+	$(AM_V_at)sed -i 's/simpara/para/g' $@-t     # publican doesn't correctly render footnotes with simpara
-+	$(AM_V_at)sed -i 's/.*<date>.*//g' $@-t      # Remove dangling tag
-+	$(AM_V_at)sed -i 's/.*preface>//g' $@-t      # Remove preface elements
-+	$(AM_V_at)sed -i 's:<title></title>::g' $@-t # Remove empty title
-+	$(AM_V_at)sed -i 's/chapter/section/g' $@-t  # Chapters become sections, so that books can become chapters
-+	$(AM_V_at)sed -i 's/<.*bookinfo.*>//g' $@-t  # Strip out bookinfo, we don't need it
-+	$(AM_V_at)! grep -q "<appendix" $@-t || sed -i \
-+	  's/.*book>//;tb;bf;:b;N;s/.*<title>.*<\/title>.*//;tb;/<appendix/{:i;n;/<\/appendix/{p;d};bi};bb;:f;p;d' \
-+	  $@-t  # We just want the appendix tag (asciidoctor adds non-empty book-level title)
-+	$(AM_V_at)sed -i 's/book>/chapter>/g' $@-t   # Rename to chapter (won't trigger if previous sed did)
-+	$(AM_V_GEN)mv $@-t $@
-+
- # publican-clusterlabs/xsl/{html,html-single,pdf}.xsl refer to URIs
- # requiring Internet access, hence we shadow that with a XML catalog-based
- # redirect to local files brought with Publican installation;
--- 
-1.8.3.1
-
-
-From 2aa5764c84c7fac7c06ccebccee7295872ec8b40 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Thu, 1 Aug 2019 17:47:53 -0500
-Subject: [PATCH 93/96] Build: doc: skip publican documentation with "make
- distcheck"
-
-I got publican partly working with VPATH builds, but ran into an issue
-that wasn't worth spending more time on.
----
- Makefile.am     |  9 +++++++++
- doc/Makefile.am | 44 ++++++++++++++++++++++++++------------------
- 2 files changed, 35 insertions(+), 18 deletions(-)
-
-diff --git a/Makefile.am b/Makefile.am
-index b47f488..5db35c2 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -31,6 +31,15 @@ EXTRA_DIST		= CONTRIBUTING.md	\
- MAINTAINERCLEANFILES    = Makefile.in aclocal.m4 configure DRF/config-h.in \
-                         DRF/stamp-h.in libtool.m4 ltdl.m4
- 
-+# Disable building Publican documentation when doing "make distcheck", because
-+# some of our book sources are in the source directory, while others are
-+# dynamically generated in the build directory, and publican can't handle that.
-+#
-+# @TODO To support VPATH builds for Publican, we'd probably have to create
-+# a separate subtree of the build directory to use as Publican's source
-+# directory, and copy the static sources into it.
-+AM_DISTCHECK_CONFIGURE_FLAGS	= --with-brand=""
-+
- CORE	= replace include lib mcp attrd pengine cib crmd fencing lrmd tools xml
- SUBDIRS	= $(CORE) extra doc
- 
-diff --git a/doc/Makefile.am b/doc/Makefile.am
-index 5ff350c..3d4be7f 100644
---- a/doc/Makefile.am
-+++ b/doc/Makefile.am
-@@ -122,6 +122,7 @@ endif
- # XXX Sequence of tr/sed commands should be replaced with a single XSLT
- #
- %.xml:  %.txt
-+	$(AM_V_at)$(MKDIR_P) $(shell dirname $@)     # might not exist in VPATH build
- 	$(AM_V_at)$(ASCIIDOC_CONV) $(ASCIIDOC_DBOOK_ARGS) -o - $< | tr -d '\036\r' >$@-t # Convert, fix line endings
- 	$(AM_V_at)sed -i 's/\ lang="en"//' $@-t      # Never specify a language in the chapters
- 	$(AM_V_at)sed -i 's/simpara/para/g' $@-t     # publican doesn't correctly render footnotes with simpara
-@@ -167,7 +168,7 @@ SHARED_XML=$(SHARED_TXT:%.txt=%.xml)
- if PUBLICAN_INTREE_BRAND
- PUBLICAN_INTREE_DEPS	= publican-catalog
- PUBLICAN_INTREE_ENV	= XML_CATALOG_FILES="$(CURDIR)/publican-catalog"
--PUBLICAN_INTREE_OPT	= --brand_dir=../publican-clusterlabs 
-+PUBLICAN_INTREE_OPT	= --brand_dir="$(top_srcdir)/publican-clusterlabs"
- else
- PUBLICAN_INTREE_DEPS	=
- PUBLICAN_INTREE_ENV	=
-@@ -181,7 +182,7 @@ CFS_SHARED_TXT	= $(addprefix shared/en-US/,pacemaker-intro.txt)
- CFS_SHARED_XML	= $(CFS_SHARED_TXT:%.txt=%.xml)
- CFS_TXT		= $(wildcard Clusters_from_Scratch/en-US/*.txt)
- CFS_XML_GEN	= $(CFS_TXT:%.txt=%.xml)
--CFS_XML_ONLY	= $(addprefix Clusters_from_Scratch/en-US/,$(COMMON_XML) \
-+CFS_XML_ONLY	= $(addprefix $(srcdir)/Clusters_from_Scratch/en-US/,$(COMMON_XML) \
- 		  Clusters_from_Scratch.ent \
- 		  Clusters_from_Scratch.xml \
- 		  Preface.xml)
-@@ -193,8 +194,9 @@ Clusters_from_Scratch.build: $(CFS_DEPS) $(PUBLICAN_INTREE_DEPS)
- 	@echo Building $(@:%.build=%) because of $?
- 	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
- 	$(AM_V_PUB)cd $(@:%.build=%) && RPM_BUILD_DIR="" $(PUBLICAN_INTREE_ENV)	\
--	  $(PUBLICAN) build --publish --langs="$(DOCBOOK_LANGS)"		\
--	    --formats="$(DOCBOOK_FORMATS)" $(PUBLICAN_INTREE_OPT) $(PCMK_quiet)
-+	  $(PUBLICAN) build --src_dir="$(srcdir)" --publish 			\
-+	    --langs="$(DOCBOOK_LANGS)" --formats="$(DOCBOOK_FORMATS)"		\
-+	    $(PUBLICAN_INTREE_OPT) $(PCMK_quiet)
- 	rm -rf $(@:%.build=%)/tmp
- 	touch $@
- 
-@@ -203,7 +205,7 @@ Clusters_from_Scratch.build: $(CFS_DEPS) $(PUBLICAN_INTREE_DEPS)
- 
- PD_TXT		= $(wildcard Pacemaker_Development/en-US/*.txt)
- PD_XML_GEN	= $(PD_TXT:%.txt=%.xml)
--PD_XML_ONLY	= $(addprefix Pacemaker_Development/en-US/,$(COMMON_XML) \
-+PD_XML_ONLY	= $(addprefix $(srcdir)/Pacemaker_Development/en-US/,$(COMMON_XML) \
- 		  Pacemaker_Development.ent \
- 		  Pacemaker_Development.xml)
- PD_DEPS		= $(PD_XML_ONLY) $(PD_XML_GEN)
-@@ -226,7 +228,7 @@ PE_SHARED_TXT	= $(addprefix shared/en-US/,pacemaker-intro.txt)
- PE_SHARED_XML	= $(PE_SHARED_TXT:%.txt=%.xml)
- PE_TXT		= $(wildcard Pacemaker_Explained/en-US/*.txt)
- PE_XML_GEN	= $(PE_TXT:%.txt=%.xml)
--PE_XML_ONLY	= $(addprefix Pacemaker_Explained/en-US/,$(COMMON_XML) \
-+PE_XML_ONLY	= $(addprefix $(srcdir)/Pacemaker_Explained/en-US/,$(COMMON_XML) \
- 		  Pacemaker_Explained.ent \
- 		  Pacemaker_Explained.xml \
- 		  Preface.xml)
-@@ -238,8 +240,9 @@ Pacemaker_Explained.build: $(PE_DEPS) $(PUBLICAN_INTREE_DEPS)
- 	@echo Building $(@:%.build=%) because of $?
- 	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
- 	$(AM_V_PUB)cd $(@:%.build=%) && RPM_BUILD_DIR="" $(PUBLICAN_INTREE_ENV)	\
--	  $(PUBLICAN) build --publish --langs="$(DOCBOOK_LANGS)"		\
--	    --formats="$(DOCBOOK_FORMATS)" $(PUBLICAN_INTREE_OPT) $(PCMK_quiet)
-+	  $(PUBLICAN) build --src_dir="$(srcdir)" --publish 			\
-+	    --langs="$(DOCBOOK_LANGS)" --formats="$(DOCBOOK_FORMATS)"		\
-+	    $(PUBLICAN_INTREE_OPT) $(PCMK_quiet)
- 	rm -rf $(@:%.build=%)/tmp
- 	touch $@
- 
-@@ -248,7 +251,7 @@ Pacemaker_Explained.build: $(PE_DEPS) $(PUBLICAN_INTREE_DEPS)
- 
- PR_TXT		= $(wildcard Pacemaker_Remote/en-US/*.txt)
- PR_XML_GEN	= $(PR_TXT:%.txt=%.xml)
--PR_XML_ONLY	= $(addprefix Pacemaker_Remote/en-US/,$(COMMON_XML) \
-+PR_XML_ONLY	= $(addprefix $(srcdir)/Pacemaker_Remote/en-US/,$(COMMON_XML) \
- 		  Pacemaker_Remote.ent \
- 		  Pacemaker_Remote.xml)
- PR_DEPS		= $(PR_XML_ONLY) $(PR_XML_GEN)
-@@ -259,24 +262,28 @@ Pacemaker_Remote.build: $(PNGS) $(PR_DEPS) $(PUBLICAN_INTREE_DEPS)
- 	@echo Building $(@:%.build=%) because of $?
- 	rm -rf $(@:%.build=%)/publish/* $(@:%.build=%)/tmp
- 	$(AM_V_PUB)cd $(@:%.build=%) && RPM_BUILD_DIR="" $(PUBLICAN_INTREE_ENV)	\
--	  $(PUBLICAN) build --publish --langs="$(DOCBOOK_LANGS)"		\
--	    --formats="$(DOCBOOK_FORMATS)" $(PUBLICAN_INTREE_OPT) $(PCMK_quiet)
-+	  $(PUBLICAN) build --src_dir="$(srcdir)" --publish 			\
-+	    --langs="$(DOCBOOK_LANGS)" --formats="$(DOCBOOK_FORMATS)"		\
-+	    $(PUBLICAN_INTREE_OPT) $(PCMK_quiet)
- 	rm -rf $(@:%.build=%)/tmp
- 	touch $@
- 
- 
- # Update the translation template
- pot:
--	@for book in $(docbook); do 				      \
--		echo "Updating translation templates in: $$book";     \
--		( cd $$book && RPM_BUILD_DIR="" $(PUBLICAN) update_pot ); \
-+	@for book in $(docbook); do					\
-+		echo "Updating translation templates in: $$book";	\
-+		( cd $$book && RPM_BUILD_DIR=""				\
-+		  $(PUBLICAN) --src_dir="$(srcdir)" update_pot );	\
- 	done
- 
- # Update the actual translations
- po: pot
--	@for book in $(docbook); do 				      \
--		echo "Updating translations in: $$book";     \
--		( cd $$book && RPM_BUILD_DIR="" $(PUBLICAN) update_po --langs=all );\
-+	@for book in $(docbook); do					\
-+		echo "Updating translations in: $$book";		\
-+		( cd $$book && RPM_BUILD_DIR=""				\
-+		  $(PUBLICAN) --src_dir="$(srcdir)" update_po		\
-+		  --langs=all );					\
- 	done
- 
- if BUILD_DOCBOOK
-@@ -310,7 +317,8 @@ brand-rpm-clean:
- 	-find publican-clusterlabs -name "*.noarch.rpm" -exec rm -f \{\} \;
- 
- brand-rpm-build: brand-rpm-clean brand-build
--	cd publican-clusterlabs && $(PUBLICAN) package --binary
-+	cd publican-clusterlabs && \
-+		$(PUBLICAN) --src_dir="$(srcdir)" package --binary
- 
- brand-rpm-install: brand-rpm-build
- 	find publican-clusterlabs -name "*.noarch.rpm" -exec sudo rpm -Uvh --force \{\} \;
--- 
-1.8.3.1
-
-
-From bc0bd42b67c80102a4a838319bb8aa0a1310c76b Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Fri, 23 Aug 2019 17:28:49 -0500
-Subject: [PATCH 94/96] Fix: tools: correct crm_report argument parsing
-
-There were a few instances where crm_report's option names passed to getopt,
-option names listed in help, and option names checked for did not match.
-
-Where getopt and checks matched, I went with that, so that anything that
-worked before continues to work.
----
- tools/crm_report.in | 10 ++++++----
- 1 file changed, 6 insertions(+), 4 deletions(-)
-
-diff --git a/tools/crm_report.in b/tools/crm_report.in
-index 63c137c..947140f 100755
---- a/tools/crm_report.in
-+++ b/tools/crm_report.in
-@@ -20,7 +20,7 @@
- 
- TEMP=`getopt				\
-     -o hv?xl:f:t:n:T:L:p:c:dSACHu:D:MVse:	\
--    --long help,cts:,cts-log:,dest:,node:,nodes:,from:,to:,sos-mode,logfile:,as-directory,single-node,cluster:,user:,max-depth:,version,features,rsh:	\
-+    --long help,corosync,cts:,cts-log:,dest:,heartbeat,node:,nodes:,--openais,from:,to:,sos-mode,logfile:,as-directory,single-node,cluster:,user:,max-depth:,version,features,rsh:	\
-     -n 'crm_report' -- "$@"`
- # The quotes around $TEMP are essential
- eval set -- "$TEMP"
-@@ -54,6 +54,7 @@ Required option:
- 
- Options:
-   -V                    increase verbosity (may be specified multiple times)
-+  -h, --help            display this message
-   -v, --version         display software version
-   --features            display software features
-   -t, --to TIME         time at which all problems were resolved
-@@ -77,9 +78,10 @@ Options:
-   -H, --heartbeat       force the cluster type to be heartbeat
-   -u, --user USER       username to use when collecting data from other nodes
-                         (default root)
--  -D, --depth           search depth to use when attempting to locate files
-+  -D, --max-depth       search depth to use when attempting to locate files
-   -e, --rsh             command to use to run commands on other nodes
-                         (default ssh -T)
-+  -d, --as-directory    leave result as a directory tree instead of archiving
-   --sos-mode            use defaults suitable for being called by sosreport tool
-                         (behavior subject to change and not useful to end users)
-   DEST, --dest DEST     custom destination directory or file name
-@@ -119,13 +121,13 @@ while true; do
-     case "$1" in
- 	-x) set -x; shift;;
- 	-V) verbose=`expr $verbose + 1`; shift;;
--	-T|--cts-test) tests="$tests $2"; shift; shift;;
-+	-T|--cts) tests="$tests $2"; shift; shift;;
- 	   --cts-log) ctslog="$2"; shift; shift;;
- 	-f|--from) start_time=`get_time "$2"`; shift; shift;;
- 	-t|--to) end_time=`get_time "$2"`; shift; shift;;
- 	-n|--node|--nodes) nodes="$nodes $2"; shift; shift;;
- 	-S|--single-node) nodes="$host"; shift;;
--	-E|-l|--logfile) extra_logs="$extra_logs $2"; shift; shift;;
-+	-l|--logfile) extra_logs="$extra_logs $2"; shift; shift;;
- 	-p) sanitize_patterns="$sanitize_patterns $2"; shift; shift;;
- 	-L) log_patterns="$log_patterns `echo $2 | sed 's/ /\\\W/g'`"; shift; shift;;
- 	-d|--as-directory) compress=0; shift;;
--- 
-1.8.3.1
-
-
-From 49c3055b932b732e0904d91cf49d4f80b7aa0e7d Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Fri, 23 Aug 2019 17:39:45 -0500
-Subject: [PATCH 95/96] Fix: tools: don't ignore log if unrelated file is too
- large
-
-This fixes a regression in 1.1.12: since cb420a04, findln_by_time() would skip
-a log if any file in the current working directory (rather than the log itself)
-was larger than 1GB.
----
- tools/report.common.in | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/tools/report.common.in b/tools/report.common.in
-index ebdd8df..55b37da 100644
---- a/tools/report.common.in
-+++ b/tools/report.common.in
-@@ -535,7 +535,7 @@ findln_by_time() {
-     # Some logs can be massive (over 1,500,000,000 lines have been seen in the wild) 
-     # Even just 'wc -l' on these files can take 10+ minutes 
- 
--    local fileSize=`ls -lh | awk '{ print $5 }' | grep -ie G`
-+    local fileSize=`ls -lh "$logf" | awk '{ print $5 }' | grep -ie G`
-     if [ x$fileSize != x ]; then
-         warning "$logf is ${fileSize} in size and could take many hours to process. Skipping."
-         return
--- 
-1.8.3.1
-
-
-From 456668b5afd781c61576c9b2d2feaf058fe1cc22 Mon Sep 17 00:00:00 2001
-From: Ken Gaillot <kgaillot@redhat.com>
-Date: Fri, 23 Aug 2019 22:38:51 -0500
-Subject: [PATCH 96/96] Fix: tools: check for tar in crm_report
-
-crm_report requires tar, so check for its existence up front.
----
- tools/crm_report.in       |  4 ++++
- tools/report.collector.in |  2 ++
- tools/report.common.in    | 10 ++++++++++
- 3 files changed, 16 insertions(+)
-
-diff --git a/tools/crm_report.in b/tools/crm_report.in
-index 947140f..0ef4e6f 100755
---- a/tools/crm_report.in
-+++ b/tools/crm_report.in
-@@ -475,6 +475,10 @@ getnodes() {
-     fi
- }
- 
-+if [ $compress -eq 1 ]; then
-+    require_tar
-+fi
-+
- if [ "x$tests" != "x" ]; then
-     do_cts
- 
-diff --git a/tools/report.collector.in b/tools/report.collector.in
-index 48ee075..ab41df1 100644
---- a/tools/report.collector.in
-+++ b/tools/report.collector.in
-@@ -821,6 +821,8 @@ collect_logs() {
-     trap "" 0
- }
- 
-+require_tar
-+
- debug "Initializing $REPORT_TARGET subdir"
- if [ "$REPORT_MASTER" != "$REPORT_TARGET" ]; then
-   if [ -e $REPORT_HOME/$REPORT_TARGET ]; then
-diff --git a/tools/report.common.in b/tools/report.common.in
-index 55b37da..6d4f193 100644
---- a/tools/report.common.in
-+++ b/tools/report.common.in
-@@ -128,6 +128,13 @@ fatal() {
-     exit 1
- }
- 
-+require_tar() {
-+    which tar >/dev/null 2>&1
-+    if [ $? -ne 0 ]; then
-+        fatal "Required program 'tar' not found, please install and re-run"
-+    fi
-+}
-+
- is_running() {
-     ps -ef | egrep -qs $(echo "$1" | sed -e 's/^\(.\)/[\1]/')
- }
-@@ -522,6 +529,9 @@ shrink() {
- 
-     cd $dir  >/dev/null 2>&1
-     tar $tar_options $target $base >/dev/null 2>&1
-+    if [ $? -ne 0 ]; then
-+        fatal "Could not archive $base, please investigate and collect manually"
-+    fi
-     cd $olddir  >/dev/null 2>&1
- 
-     echo $target
--- 
-1.8.3.1
-
diff --git a/SOURCES/2.0-cleanup-behavior.patch b/SOURCES/2.0-cleanup-behavior.patch
index 039079e..d9e73bb 100644
--- a/SOURCES/2.0-cleanup-behavior.patch
+++ b/SOURCES/2.0-cleanup-behavior.patch
@@ -26,8 +26,8 @@ index 128d075..bbdba25 100644
          "refresh", no_argument, NULL, 'R',
 -#endif
          "\t\tDelete resource's history (including failures) so its current state is rechecked.\n"
-         "\t\t\t\tOptionally filtered by --resource and --node (otherwise all).\n"
-         "\t\t\t\tUnless --force is specified, resource's group or clone (if any) will also be refreshed."
+         "\t\t\t\tOptionally filtered by --resource and --node (otherwise all). If the named resource is\n"
+         "\t\t\t\tpart of a group, or one numbered instance of a clone or bundled resource, the clean-up\n"
 @@ -352,13 +349,11 @@ static struct crm_option long_options[] = {
      },
      {
diff --git a/SOURCES/shutdown-lock-01.patch b/SOURCES/shutdown-lock-01.patch
new file mode 100644
index 0000000..6b90362
--- /dev/null
+++ b/SOURCES/shutdown-lock-01.patch
@@ -0,0 +1,132 @@
+From c3e2a63e08046b25f1773504d8c1ab431d3abf78 Mon Sep 17 00:00:00 2001
+From: Ken Gaillot <kgaillot@redhat.com>
+Date: Thu, 21 Nov 2019 14:48:02 -0600
+Subject: [PATCH 01/10] Feature: scheduler: add shutdown lock cluster options
+
+This commit adds shutdown-lock and shutdown-lock-limit options (just the
+options, not the feature itself).
+
+shutdown-lock defaults to false, which preserves current behavior. The intended
+purpose of setting it to true is to *prevent* recovery of a node's resources
+elsewhere when the node is cleanly shut down, until the node rejoins. If
+shutdown-lock-limit is set to a nonzero time duration, the cluster will
+be allowed to recover the resources if the node has not rejoined within this
+time.
+
+The use case is when rebooting a node (such as for software updates) is done by
+cluster-unaware system administrators during scheduled maintenance windows,
+resources prefer specific nodes, and resource recovery time is high.
+---
+ include/crm/msg_xml.h        |  6 +++++-
+ include/crm/pengine/status.h |  2 ++
+ lib/pengine/common.c         | 26 ++++++++++++++++++++++++--
+ lib/pengine/unpack.c         | 10 ++++++++++
+ 4 files changed, 41 insertions(+), 3 deletions(-)
+
+diff --git a/include/crm/msg_xml.h b/include/crm/msg_xml.h
+index de99959..50fdf45 100644
+--- a/include/crm/msg_xml.h
++++ b/include/crm/msg_xml.h
+@@ -1,5 +1,7 @@
+ /*
+- * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
++ * Copyright 2004-2020 the Pacemaker project contributors
++ *
++ * The version control history for this file may have further details.
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Lesser General Public
+@@ -378,6 +380,8 @@
+ #  define XML_CONFIG_ATTR_FORCE_QUIT	"shutdown-escalation"
+ #  define XML_CONFIG_ATTR_RECHECK	"cluster-recheck-interval"
+ #  define XML_CONFIG_ATTR_FENCE_REACTION	"fence-reaction"
++#  define XML_CONFIG_ATTR_SHUTDOWN_LOCK         "shutdown-lock"
++#  define XML_CONFIG_ATTR_SHUTDOWN_LOCK_LIMIT   "shutdown-lock-limit"
+ 
+ #  define XML_ALERT_ATTR_PATH		"path"
+ #  define XML_ALERT_ATTR_TIMEOUT	"timeout"
+diff --git a/include/crm/pengine/status.h b/include/crm/pengine/status.h
+index 415f60e..c6d4bdb 100644
+--- a/include/crm/pengine/status.h
++++ b/include/crm/pengine/status.h
+@@ -83,6 +83,7 @@ enum pe_find {
+ #  define pe_flag_start_failure_fatal   0x00001000ULL
+ #  define pe_flag_remove_after_stop     0x00002000ULL
+ #  define pe_flag_startup_fencing       0x00004000ULL
++#  define pe_flag_shutdown_lock         0x00008000ULL
+ 
+ #  define pe_flag_startup_probes        0x00010000ULL
+ #  define pe_flag_have_status           0x00020000ULL
+@@ -148,6 +149,7 @@ typedef struct pe_working_set_s {
+     GList *param_check; // History entries that need to be checked
+     GList *stop_needed; // Containers that need stop actions
+     int ninstances;     // Total number of resource instances
++    guint shutdown_lock;// How long (seconds) to lock resources to shutdown node
+ } pe_working_set_t;
+ 
+ enum pe_check_parameters {
+diff --git a/lib/pengine/common.c b/lib/pengine/common.c
+index e82434a..fc976d3 100644
+--- a/lib/pengine/common.c
++++ b/lib/pengine/common.c
+@@ -1,5 +1,7 @@
+-/* 
+- * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
++/*
++ * Copyright 2004-2020 the Pacemaker project contributors
++ *
++ * The version control history for this file may have further details.
+  * 
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Lesser General Public
+@@ -101,6 +103,26 @@ pe_cluster_option pe_opts[] = {
+ 	  "When set to TRUE, the cluster will immediately ban a resource from a node if it fails to start there. When FALSE, the cluster will instead check the resource's fail count against its migration-threshold." },
+ 	{ "enable-startup-probes", NULL, "boolean", NULL, "true", &check_boolean,
+ 	  "Should the cluster check for active resources during startup", NULL },
++    {
++        XML_CONFIG_ATTR_SHUTDOWN_LOCK,
++        NULL, "boolean", NULL, "false", &check_boolean,
++        "Whether to lock resources to a cleanly shut down node",
++        "When true, resources active on a node when it is cleanly shut down "
++            "are kept \"locked\" to that node (not allowed to run elsewhere) "
++            "until they start again on that node after it rejoins (or for at "
++            "most shutdown-lock-limit, if set). Stonith resources and "
++            "Pacemaker Remote connections are never locked. Clone and bundle "
++            "instances and the master role of promotable clones are currently "
++            "never locked, though support could be added in a future release."
++    },
++    {
++        XML_CONFIG_ATTR_SHUTDOWN_LOCK_LIMIT,
++        NULL, "time", NULL, "0", &check_timer,
++        "Do not lock resources to a cleanly shut down node longer than this",
++        "If shutdown-lock is true and this is set to a nonzero time duration, "
++            "shutdown locks will expire after this much time has passed since "
++            "the shutdown was initiated, even if the node has not rejoined."
++    },
+ 
+ 	/* Stonith Options */
+ 	{ "stonith-enabled", "stonith_enabled", "boolean", NULL, "true", &check_boolean,
+diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c
+index 24e56f5..7b0d837 100644
+--- a/lib/pengine/unpack.c
++++ b/lib/pengine/unpack.c
+@@ -340,6 +340,16 @@ unpack_config(xmlNode * config, pe_working_set_t * data_set)
+     data_set->placement_strategy = pe_pref(data_set->config_hash, "placement-strategy");
+     crm_trace("Placement strategy: %s", data_set->placement_strategy);
+ 
++    set_config_flag(data_set, "shutdown-lock", pe_flag_shutdown_lock);
++    crm_trace("Resources will%s be locked to cleanly shut down nodes",
++              (is_set(data_set->flags, pe_flag_shutdown_lock)? "" : " not"));
++    if (is_set(data_set->flags, pe_flag_shutdown_lock)) {
++        value = pe_pref(data_set->config_hash,
++                        XML_CONFIG_ATTR_SHUTDOWN_LOCK_LIMIT);
++        data_set->shutdown_lock = crm_get_interval(value) / 1000;
++        crm_trace("Shutdown locks expire after %us", data_set->shutdown_lock);
++    }
++
+     return TRUE;
+ }
+ 
+-- 
+1.8.3.1
+
diff --git a/SOURCES/shutdown-lock-02.patch b/SOURCES/shutdown-lock-02.patch
new file mode 100644
index 0000000..6ed0900
--- /dev/null
+++ b/SOURCES/shutdown-lock-02.patch
@@ -0,0 +1,143 @@
+From 4e85d3012d61dcf534a51d4f82b91fce9aef8d0b Mon Sep 17 00:00:00 2001
+From: Ken Gaillot <kgaillot@redhat.com>
+Date: Fri, 6 Dec 2019 11:57:59 -0600
+Subject: [PATCH 02/10] Low: scheduler: respect shutdown locks when placing
+ active resources
+
+Use new pe_resource_t members to indicate that a resource is locked to a
+particular node.
+
+For active resources (i.e. in the transition where the node is scheduled for
+shutdown), these are connected by checking each lockable resource for whether
+it is running on a single clean node that is shutting down.
+
+When applying constraints, place -INFINITY location constraints for locked
+resources on all nodes other than the lock node.
+
+(Inactive resources -- i.e. in later transitions after the node is shut down --
+are not yet locked.)
+---
+ include/crm/pengine/status.h |  2 ++
+ pengine/allocate.c           | 86 ++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 88 insertions(+)
+
+diff --git a/include/crm/pengine/status.h b/include/crm/pengine/status.h
+index c6d4bdb..1e8d5bb 100644
+--- a/include/crm/pengine/status.h
++++ b/include/crm/pengine/status.h
+@@ -347,6 +347,8 @@ struct resource_s {
+     pe_working_set_t *cluster;
+ 
+     pe_node_t *pending_node;    // Node on which pending_task is happening
++    pe_node_t *lock_node;       // Resource is shutdown-locked to this node
++    time_t lock_time;           // When shutdown lock started
+ 
+ #if ENABLE_VERSIONED_ATTRS
+     xmlNode *versioned_parameters;
+diff --git a/pengine/allocate.c b/pengine/allocate.c
+index 30d29e1..09f9e51 100644
+--- a/pengine/allocate.c
++++ b/pengine/allocate.c
+@@ -1009,6 +1009,86 @@ rsc_discover_filter(resource_t *rsc, node_t *node)
+     }
+ }
+ 
++static time_t
++shutdown_time(pe_node_t *node, pe_working_set_t *data_set)
++{
++    const char *shutdown = pe_node_attribute_raw(node, XML_CIB_ATTR_SHUTDOWN);
++    time_t result = 0;
++
++    if (shutdown) {
++        errno = 0;
++        result = (time_t) crm_int_helper(shutdown, NULL);
++        if (errno != 0) {
++            result = 0;
++        }
++    }
++    return result? result : get_effective_time(data_set);
++}
++
++static void
++apply_shutdown_lock(pe_resource_t *rsc, pe_working_set_t *data_set)
++{
++    const char *class;
++
++    // Only primitives and (uncloned) groups may be locked
++    if (rsc->variant == pe_group) {
++        for (GList *item = rsc->children; item != NULL;
++             item = item->next) {
++            apply_shutdown_lock((pe_resource_t *) item->data, data_set);
++        }
++    } else if (rsc->variant != pe_native) {
++        return;
++    }
++
++    // Fence devices and remote connections can't be locked
++    class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
++    if ((class == NULL) || !strcmp(class, PCMK_RESOURCE_CLASS_STONITH)
++        || is_rsc_baremetal_remote_node(rsc, data_set)) {
++        return;
++    }
++
++    // Only a resource active on exactly one node can be locked
++    if (pcmk__list_of_1(rsc->running_on)) {
++        pe_node_t *node = rsc->running_on->data;
++
++        if (node->details->shutdown) {
++            if (node->details->unclean) {
++                pe_rsc_debug(rsc, "Not locking %s to unclean %s for shutdown",
++                             rsc->id, node->details->uname);
++            } else {
++                rsc->lock_node = node;
++                rsc->lock_time = shutdown_time(node, data_set);
++            }
++        }
++    }
++
++    if (rsc->lock_node == NULL) {
++        // No lock needed
++        return;
++    }
++
++    if (data_set->shutdown_lock > 0) {
++        time_t lock_expiration = rsc->lock_time + data_set->shutdown_lock;
++
++        pe_rsc_info(rsc, "Locking %s to %s due to shutdown (expires @%lld)",
++                    rsc->id, rsc->lock_node->details->uname,
++                    (long long) lock_expiration);
++    } else {
++        pe_rsc_info(rsc, "Locking %s to %s due to shutdown",
++                    rsc->id, rsc->lock_node->details->uname);
++    }
++
++    // If resource is locked to one node, ban it from all other nodes
++    for (GList *item = data_set->nodes; item != NULL; item = item->next) {
++        pe_node_t *node = item->data;
++
++        if (strcmp(node->details->uname, rsc->lock_node->details->uname)) {
++            resource_location(rsc, node, -INFINITY,
++                              XML_CONFIG_ATTR_SHUTDOWN_LOCK, data_set);
++        }
++    }
++}
++
+ /*
+  * \internal
+  * \brief Stage 2 of cluster status: apply node-specific criteria
+@@ -1020,6 +1100,12 @@ stage2(pe_working_set_t * data_set)
+ {
+     GListPtr gIter = NULL;
+ 
++    if (is_set(data_set->flags, pe_flag_shutdown_lock)) {
++        for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
++            apply_shutdown_lock((pe_resource_t *) gIter->data, data_set);
++        }
++    }
++
+     if (is_not_set(data_set->flags, pe_flag_no_compat)) {
+         // @COMPAT API backward compatibility
+         for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
+-- 
+1.8.3.1
+
diff --git a/SOURCES/shutdown-lock-03.patch b/SOURCES/shutdown-lock-03.patch
new file mode 100644
index 0000000..154de19
--- /dev/null
+++ b/SOURCES/shutdown-lock-03.patch
@@ -0,0 +1,204 @@
+From 749f6b256cb2864ce3e862442adc6d219eefeca3 Mon Sep 17 00:00:00 2001
+From: Ken Gaillot <kgaillot@redhat.com>
+Date: Fri, 6 Dec 2019 12:17:03 -0600
+Subject: [PATCH 03/10] Low: scheduler: respect shutdown locks when placing
+ inactive resources
+
+When shutdown-lock is enabled, and we're either scheduling a resource stop
+on a node that's cleanly shutting down or scheduling any action for a
+previously locked resource, add "shutdown-lock=<shutdown-timestamp>" to the
+graph action. The controller will be able to use this to know when to preserve
+the lock (by adding the lock time to the resource state entry).
+
+When the scheduler unpacks a resource state entry with a lock, it will remember
+the lock node and lock time, which will trigger existing code for applying
+shutdown locks.
+---
+ lib/pengine/unpack.c | 49 ++++++++++++++++++++++++++++++++++++++++++++-----
+ pengine/allocate.c   | 17 ++++++++++++++++-
+ pengine/graph.c      | 32 +++++++++++++++++++++++++++++++-
+ 3 files changed, 91 insertions(+), 7 deletions(-)
+
+diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c
+index 7b0d837..bb5efa4 100644
+--- a/lib/pengine/unpack.c
++++ b/lib/pengine/unpack.c
+@@ -18,6 +18,7 @@
+ #include <crm_internal.h>
+ 
+ #include <glib.h>
++#include <time.h>
+ 
+ #include <crm/crm.h>
+ #include <crm/services.h>
+@@ -1151,7 +1152,8 @@ unpack_node_loop(xmlNode * status, bool fence, pe_working_set_t * data_set)
+                 crm_trace("Checking node %s/%s/%s status %d/%d/%d", id, rsc->id, rsc->container->id, fence, rsc->role, RSC_ROLE_STARTED);
+ 
+             } else if (is_container_remote_node(this_node) == FALSE
+-                       && rsc->role == RSC_ROLE_STARTED) {
++                       && ((rsc->role == RSC_ROLE_STARTED)
++                           || is_set(data_set->flags, pe_flag_shutdown_lock))) {
+                 check = TRUE;
+                 crm_trace("Checking node %s/%s status %d/%d/%d", id, rsc->id, fence, rsc->role, RSC_ROLE_STARTED);
+             }
+@@ -1167,6 +1169,9 @@ unpack_node_loop(xmlNode * status, bool fence, pe_working_set_t * data_set)
+ 
+         } else if (fence) {
+             process = TRUE;
++
++        } else if (is_set(data_set->flags, pe_flag_shutdown_lock)) {
++            process = TRUE;
+         }
+ 
+         if(process) {
+@@ -2286,6 +2291,28 @@ calculate_active_ops(GListPtr sorted_op_list, int *start_index, int *stop_index)
+     }
+ }
+ 
++// If resource history entry has shutdown lock, remember lock node and time
++static void
++unpack_shutdown_lock(xmlNode *rsc_entry, pe_resource_t *rsc, pe_node_t *node,
++                     pe_working_set_t *data_set)
++{
++    time_t lock_time = 0;   // When lock started (i.e. node shutdown time)
++
++    if ((crm_element_value_epoch(rsc_entry, XML_CONFIG_ATTR_SHUTDOWN_LOCK,
++                                 &lock_time) == pcmk_ok) && (lock_time != 0)) {
++
++        if ((data_set->shutdown_lock > 0)
++            && (get_effective_time(data_set)
++                > (lock_time + data_set->shutdown_lock))) {
++            pe_rsc_info(rsc, "Shutdown lock for %s on %s expired",
++                        rsc->id, node->details->uname);
++        } else {
++            rsc->lock_node = node;
++            rsc->lock_time = lock_time;
++        }
++    }
++}
++
+ static resource_t *
+ unpack_lrm_rsc_state(node_t * node, xmlNode * rsc_entry, pe_working_set_t * data_set)
+ {
+@@ -2322,18 +2349,30 @@ unpack_lrm_rsc_state(node_t * node, xmlNode * rsc_entry, pe_working_set_t * data
+         }
+     }
+ 
+-    if (op_list == NULL) {
+-        /* if there are no operations, there is nothing to do */
+-        return NULL;
++    if (is_not_set(data_set->flags, pe_flag_shutdown_lock)) {
++        if (op_list == NULL) {
++            // If there are no operations, there is nothing to do
++            return NULL;
++        }
+     }
+ 
+     /* find the resource */
+     rsc = unpack_find_resource(data_set, node, rsc_id, rsc_entry);
+     if (rsc == NULL) {
+-        rsc = process_orphan_resource(rsc_entry, node, data_set);
++        if (op_list == NULL) {
++            // If there are no operations, there is nothing to do
++            return NULL;
++        } else {
++            rsc = process_orphan_resource(rsc_entry, node, data_set);
++        }
+     }
+     CRM_ASSERT(rsc != NULL);
+ 
++    // Check whether the resource is "shutdown-locked" to this node
++    if (is_set(data_set->flags, pe_flag_shutdown_lock)) {
++        unpack_shutdown_lock(rsc_entry, rsc, node, data_set);
++    }
++
+     /* process operations */
+     saved_role = rsc->role;
+     on_fail = action_fail_ignore;
+diff --git a/pengine/allocate.c b/pengine/allocate.c
+index 09f9e51..7366716 100644
+--- a/pengine/allocate.c
++++ b/pengine/allocate.c
+@@ -1047,8 +1047,23 @@ apply_shutdown_lock(pe_resource_t *rsc, pe_working_set_t *data_set)
+         return;
+     }
+ 
++    if (rsc->lock_node != NULL) {
++        // The lock was obtained from resource history
++
++        if (rsc->running_on != NULL) {
++            /* The resource was started elsewhere even though it is now
++             * considered locked. This shouldn't be possible, but as a
++             * failsafe, we don't want to disturb the resource now.
++             */
++            pe_rsc_info(rsc,
++                        "Cancelling shutdown lock because %s is already active",
++                        rsc->id);
++            rsc->lock_node = NULL;
++            rsc->lock_time = 0;
++        }
++
+     // Only a resource active on exactly one node can be locked
+-    if (pcmk__list_of_1(rsc->running_on)) {
++    } else if (pcmk__list_of_1(rsc->running_on)) {
+         pe_node_t *node = rsc->running_on->data;
+ 
+         if (node->details->shutdown) {
+diff --git a/pengine/graph.c b/pengine/graph.c
+index cba30d0..33168ca 100644
+--- a/pengine/graph.c
++++ b/pengine/graph.c
+@@ -1,5 +1,7 @@
+ /*
+- * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
++ * Copyright 2004-2020 the Pacemaker project contributors
++ *
++ * The version control history for this file may have further details.
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public
+@@ -998,6 +1000,26 @@ add_downed_nodes(xmlNode *xml, const action_t *action,
+     }
+ }
+ 
++static bool
++should_lock_action(pe_action_t *action)
++{
++    // Only actions taking place on resource's lock node are locked
++    if ((action->rsc->lock_node == NULL) || (action->node == NULL)
++        || (action->node->details != action->rsc->lock_node->details)) {
++        return false;
++    }
++
++    /* During shutdown, only stops are locked (otherwise, another action such as
++     * a demote would cause the controller to clear the lock)
++     */
++    if (action->node->details->shutdown && action->task
++        && strcmp(action->task, RSC_STOP)) {
++        return false;
++    }
++
++    return true;
++}
++
+ static xmlNode *
+ action2xml(action_t * action, gboolean as_input, pe_working_set_t *data_set)
+ {
+@@ -1104,6 +1126,14 @@ action2xml(action_t * action, gboolean as_input, pe_working_set_t *data_set)
+             XML_ATTR_TYPE
+         };
+ 
++        /* If a resource is locked to a node via shutdown-lock, mark its actions
++         * so the controller can preserve the lock when the action completes.
++         */
++        if (should_lock_action(action)) {
++            crm_xml_add_ll(action_xml, XML_CONFIG_ATTR_SHUTDOWN_LOCK,
++                           (long long) action->rsc->lock_time);
++        }
++
+         // List affected resource
+ 
+         rsc_xml = create_xml_node(action_xml,
+-- 
+1.8.3.1
+
diff --git a/SOURCES/shutdown-lock-04.patch b/SOURCES/shutdown-lock-04.patch
new file mode 100644
index 0000000..5993772
--- /dev/null
+++ b/SOURCES/shutdown-lock-04.patch
@@ -0,0 +1,286 @@
+From 538aeef2523017a9b5c1ba950c984ed16efdc9a0 Mon Sep 17 00:00:00 2001
+From: Ken Gaillot <kgaillot@redhat.com>
+Date: Fri, 22 Nov 2019 17:03:20 -0600
+Subject: [PATCH 04/10] Low: controller: mark shutdown-locked resources in
+ resource history
+
+When a graph action indicates that the resource should be shutdown-locked
+to its node, remember the shutdown lock time in active_op_t so we can remember
+that when the result comes back. When the result does come back, add
+"shutdown-lock" to its lrm_resource entry in the CIB status section -- as
+the timestamp if it's a successful stop or a probe finding the resource
+inactive, or as 0 to clear the lock for any other operation.
+---
+ crmd/control.c      |  9 ++++++-
+ crmd/crmd_lrm.h     |  1 +
+ crmd/crmd_utils.h   |  1 +
+ crmd/lrm.c          | 46 ++++++++++++++++++++++++++++++++----
+ crmd/te_callbacks.c | 68 +++++++++++++++++++++++++++++++++++++----------------
+ 5 files changed, 99 insertions(+), 26 deletions(-)
+
+diff --git a/crmd/control.c b/crmd/control.c
+index cd4223f..47dabf1 100644
+--- a/crmd/control.c
++++ b/crmd/control.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright 2004-2019 the Pacemaker project contributors
++ * Copyright 2004-2020 the Pacemaker project contributors
+  *
+  * The version control history for this file may have further details.
+  *
+@@ -51,6 +51,7 @@ gboolean fsa_has_quorum = FALSE;
+ crm_trigger_t *fsa_source = NULL;
+ crm_trigger_t *config_read = NULL;
+ bool no_quorum_suicide_escalation = FALSE;
++bool controld_shutdown_lock_enabled = false;
+ 
+ /*	 A_HA_CONNECT	*/
+ void
+@@ -971,7 +972,10 @@ pe_cluster_option crmd_opts[] = {
+         { "stonith-max-attempts",NULL,"integer",NULL,"10",&check_positive_number,
+           "How many times stonith can fail before it will no longer be attempted on a target"
+         },   
++
++    // Already documented in libpe_status (other values must be kept identical)
+ 	{ "no-quorum-policy", "no_quorum_policy", "enum", "stop, freeze, ignore, suicide", "stop", &check_quorum, NULL, NULL },
++    { XML_CONFIG_ATTR_SHUTDOWN_LOCK, NULL, "boolean", NULL, "false", &check_boolean, NULL, NULL },
+ 
+ #if SUPPORT_PLUGIN
+ 	{ XML_ATTR_EXPECTED_VOTES, NULL, "integer", NULL, "2", &check_number, "The number of nodes expected to be in the cluster", "Used to calculate quorum in openais based clusters." },
+@@ -1094,6 +1098,9 @@ config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void
+     value = crmd_pref(config_hash, "crmd-finalization-timeout");
+     finalization_timer->period_ms = crm_get_msec(value);
+ 
++    value = crmd_pref(config_hash, XML_CONFIG_ATTR_SHUTDOWN_LOCK);
++    controld_shutdown_lock_enabled = crm_is_true(value);
++
+ #if SUPPORT_COROSYNC
+     if (is_classic_ais_cluster()) {
+         value = crmd_pref(config_hash, XML_ATTR_EXPECTED_VOTES);
+diff --git a/crmd/crmd_lrm.h b/crmd/crmd_lrm.h
+index 7d35264..ecc2511 100644
+--- a/crmd/crmd_lrm.h
++++ b/crmd/crmd_lrm.h
+@@ -46,6 +46,7 @@ typedef struct active_op_s {
+     int interval;
+     uint32_t flags; // bitmask of active_op_e
+     unsigned int start_time;
++    time_t lock_time;
+     char *rsc_id;
+     char *op_type;
+     char *op_key;
+diff --git a/crmd/crmd_utils.h b/crmd/crmd_utils.h
+index eeaa8b7..9ecce88 100644
+--- a/crmd/crmd_utils.h
++++ b/crmd/crmd_utils.h
+@@ -63,6 +63,7 @@ fsa_cib_anon_update(const char *section, xmlNode *data) {
+ }
+ 
+ extern gboolean fsa_has_quorum;
++extern bool controld_shutdown_lock_enabled;
+ extern int last_peer_update;
+ extern int last_resource_update;
+ 
+diff --git a/crmd/lrm.c b/crmd/lrm.c
+index 27fdd8b..9156ab8 100644
+--- a/crmd/lrm.c
++++ b/crmd/lrm.c
+@@ -47,7 +47,8 @@ static void do_lrm_rsc_op(lrm_state_t *lrm_state, lrmd_rsc_info_t *rsc,
+ 
+ static gboolean lrm_state_verify_stopped(lrm_state_t * lrm_state, enum crmd_fsa_state cur_state,
+                                          int log_level);
+-static int do_update_resource(const char *node_name, lrmd_rsc_info_t * rsc, lrmd_event_data_t * op);
++static int do_update_resource(const char *node_name, lrmd_rsc_info_t *rsc,
++                              lrmd_event_data_t *op, time_t lock_time);
+ 
+ static void
+ lrm_connection_destroy(void)
+@@ -2168,7 +2169,7 @@ record_pending_op(const char *node_name, lrmd_rsc_info_t *rsc, lrmd_event_data_t
+     crm_debug("Recording pending op %s_%s_%d on %s in the CIB",
+               op->rsc_id, op->op_type, op->interval, node_name);
+ 
+-    do_update_resource(node_name, rsc, op);
++    do_update_resource(node_name, rsc, op, 0);
+ }
+ 
+ static void
+@@ -2309,7 +2310,11 @@ do_lrm_rsc_op(lrm_state_t *lrm_state, lrmd_rsc_info_t *rsc,
+         pending->op_key = strdup(op_id);
+         pending->rsc_id = strdup(rsc->id);
+         pending->start_time = time(NULL);
+-        pending->user_data = strdup(op->user_data);
++        pending->user_data = op->user_data? strdup(op->user_data) : NULL;
++        if (crm_element_value_epoch(msg, XML_CONFIG_ATTR_SHUTDOWN_LOCK,
++                                    &(pending->lock_time)) != pcmk_ok) {
++            pending->lock_time = 0;
++        }
+         g_hash_table_replace(lrm_state->pending_ops, call_id_s, pending);
+ 
+         if (op->interval > 0 && op->start_delay > START_DELAY_THRESHOLD) {
+@@ -2356,8 +2361,28 @@ cib_rsc_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *use
+     }
+ }
+ 
++/* Only successful stops, and probes that found the resource inactive, get locks
++ * recorded in the history. This ensures the resource stays locked to the node
++ * until it is active there again after the node comes back up.
++ */
++static bool
++should_preserve_lock(lrmd_event_data_t *op)
++{
++    if (!controld_shutdown_lock_enabled) {
++        return false;
++    }
++    if (!strcmp(op->op_type, RSC_STOP) && (op->rc == PCMK_OCF_OK)) {
++        return true;
++    }
++    if (!strcmp(op->op_type, RSC_STATUS) && (op->rc == PCMK_OCF_NOT_RUNNING)) {
++        return true;
++    }
++    return false;
++}
++
+ static int
+-do_update_resource(const char *node_name, lrmd_rsc_info_t * rsc, lrmd_event_data_t * op)
++do_update_resource(const char *node_name, lrmd_rsc_info_t *rsc,
++                   lrmd_event_data_t *op, time_t lock_time)
+ {
+ /*
+   <status>
+@@ -2412,6 +2437,16 @@ do_update_resource(const char *node_name, lrmd_rsc_info_t * rsc, lrmd_event_data
+         crm_xml_add(iter, XML_ATTR_TYPE, rsc->type);
+         crm_xml_add(iter, XML_AGENT_ATTR_CLASS, rsc->class);
+         crm_xml_add(iter, XML_AGENT_ATTR_PROVIDER, rsc->provider);
++        if (lock_time != 0) {
++            /* Actions on a locked resource should either preserve the lock by
++             * recording it with the action result, or clear it.
++             */
++            if (!should_preserve_lock(op)) {
++                lock_time = 0;
++            }
++            crm_xml_add_ll(iter, XML_CONFIG_ATTR_SHUTDOWN_LOCK,
++                           (long long) lock_time);
++        }
+ 
+         if (op->params) {
+             container = g_hash_table_lookup(op->params, CRM_META"_"XML_RSC_ATTR_CONTAINER);
+@@ -2600,7 +2635,8 @@ process_lrm_event(lrm_state_t *lrm_state, lrmd_event_data_t *op,
+         if (controld_action_is_recordable(op->op_type)) {
+             if (node_name && rsc) {
+                 // We should record the result, and happily, we can
+-                update_id = do_update_resource(node_name, rsc, op);
++                update_id = do_update_resource(node_name, rsc, op,
++                                               pending? pending->lock_time : 0);
+                 need_direct_ack = FALSE;
+ 
+             } else if (op->rsc_deleted) {
+diff --git a/crmd/te_callbacks.c b/crmd/te_callbacks.c
+index 9faf932..46a4393 100644
+--- a/crmd/te_callbacks.c
++++ b/crmd/te_callbacks.c
+@@ -1,5 +1,7 @@
+ /*
+- * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
++ * Copyright 2004-2020 the Pacemaker project contributors
++ *
++ * The version control history for this file may have further details.
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public
+@@ -52,6 +54,18 @@ update_stonith_max_attempts(const char* value)
+        stonith_max_attempts = crm_int_helper(value, NULL);
+     }
+ }
++
++// An explicit shutdown-lock of 0 means the lock has been cleared
++static bool
++shutdown_lock_cleared(xmlNode *lrm_resource)
++{
++    time_t shutdown_lock = 0;
++
++    return (crm_element_value_epoch(lrm_resource, XML_CONFIG_ATTR_SHUTDOWN_LOCK,
++                                    &shutdown_lock) == pcmk_ok)
++           && (shutdown_lock == 0);
++}
++
+ static void
+ te_update_diff_v1(const char *event, xmlNode *diff)
+ {
+@@ -130,33 +144,42 @@ te_update_diff_v1(const char *event, xmlNode *diff)
+     }
+     freeXpathObject(xpathObj);
+ 
++    // Check for lrm_resource entries
++    xpathObj = xpath_search(diff,
++                            "//" F_CIB_UPDATE_RESULT
++                            "//" XML_TAG_DIFF_ADDED
++                            "//" XML_LRM_TAG_RESOURCE);
++    max = numXpathResults(xpathObj);
++
+     /*
+-     * Updates by, or in response to, TE actions will never contain updates
+-     * for more than one resource at a time, so such updates indicate an
+-     * LRM refresh.
+-     *
+-     * In that case, start a new transition rather than check each result
+-     * individually, which can result in _huge_ speedups in large clusters.
++     * Updates by, or in response to, graph actions will never affect more than
++     * one resource at a time, so such updates indicate an LRM refresh. In that
++     * case, start a new transition rather than check each result individually,
++     * which can result in _huge_ speedups in large clusters.
+      *
+      * Unfortunately, we can only do so when there are no pending actions.
+      * Otherwise, we could mistakenly throw away those results here, and
+      * the cluster will stall waiting for them and time out the operation.
+      */
+-    if (transition_graph->pending == 0) {
+-        xpathObj = xpath_search(diff,
+-                                "//" F_CIB_UPDATE_RESULT
+-                                "//" XML_TAG_DIFF_ADDED
+-                                "//" XML_LRM_TAG_RESOURCE);
+-        max = numXpathResults(xpathObj);
+-        if (max > 1) {
+-            crm_debug("Ignoring resource operation updates due to LRM refresh of %d resources",
+-                      max);
+-            crm_log_xml_trace(diff, "lrm-refresh");
+-            abort_transition(INFINITY, tg_restart, "LRM Refresh", NULL);
+-            goto bail;
++    if ((transition_graph->pending == 0) && (max > 1)) {
++        crm_debug("Ignoring resource operation updates due to history refresh of %d resources",
++                  max);
++        crm_log_xml_trace(diff, "lrm-refresh");
++        abort_transition(INFINITY, tg_restart, "History refresh", NULL);
++        goto bail;
++    }
++
++    if (max == 1) {
++        xmlNode *lrm_resource = getXpathResult(xpathObj, 0);
++
++        if (shutdown_lock_cleared(lrm_resource)) {
++            // @TODO would be more efficient to abort once after transition done
++            abort_transition(INFINITY, tg_restart, "Shutdown lock cleared",
++                             lrm_resource);
++            // Still process results, so we stop timers and update failcounts
+         }
+-        freeXpathObject(xpathObj);
+     }
++    freeXpathObject(xpathObj);
+ 
+     /* Process operation updates */
+     xpathObj =
+@@ -229,6 +252,11 @@ process_lrm_resource_diff(xmlNode *lrm_resource, const char *node)
+          rsc_op = __xml_next(rsc_op)) {
+         process_graph_event(rsc_op, node);
+     }
++    if (shutdown_lock_cleared(lrm_resource)) {
++        // @TODO would be more efficient to abort once after transition done
++        abort_transition(INFINITY, tg_restart, "Shutdown lock cleared",
++                         lrm_resource);
++    }
+ }
+ 
+ static void
+-- 
+1.8.3.1
+
diff --git a/SOURCES/shutdown-lock-05.patch b/SOURCES/shutdown-lock-05.patch
new file mode 100644
index 0000000..14f1161
--- /dev/null
+++ b/SOURCES/shutdown-lock-05.patch
@@ -0,0 +1,159 @@
+From ba17007f04d2fdbd2147c14c7eedb0de137ff448 Mon Sep 17 00:00:00 2001
+From: Ken Gaillot <kgaillot@redhat.com>
+Date: Fri, 13 Dec 2019 11:38:49 -0600
+Subject: [PATCH 05/10] Low: controller: don't clear shutdown locks when node
+ rejoins
+
+Add new controld_delete_node_state() values for clearing resource history
+while preserving shutdown locks. This is accomplished by deleting all
+unlocked lrm_resource entries and all lrm_rsc_op entries, instead of the entire
+lrm subsection.
+---
+ crmd/cib.c            | 22 +++++++++++++++++++++-
+ crmd/crmd_utils.h     |  2 ++
+ crmd/join_dc.c        |  7 +++++--
+ crmd/remote_lrmd_ra.c | 18 +++++++++++-------
+ 4 files changed, 39 insertions(+), 10 deletions(-)
+
+diff --git a/crmd/cib.c b/crmd/cib.c
+index e8c6376..a9e4ed3 100644
+--- a/crmd/cib.c
++++ b/crmd/cib.c
+@@ -247,12 +247,21 @@ cib_delete_callback(xmlNode *msg, int call_id, int rc, xmlNode *output,
+ // Node's lrm section (name 1x)
+ #define XPATH_NODE_LRM          XPATH_NODE_STATE "/" XML_CIB_TAG_LRM
+ 
++// Node's lrm_rsc_op entries and lrm_resource entries without lock (name 2x)
++#define XPATH_NODE_LRM_UNLOCKED XPATH_NODE_STATE "//" XML_LRM_TAG_RSC_OP    \
++                                "|" XPATH_NODE_STATE                        \
++                                "//" XML_LRM_TAG_RESOURCE                   \
++                                "[not(@" XML_CONFIG_ATTR_SHUTDOWN_LOCK ")]"
++
+ // Node's transient_attributes section (name 1x)
+ #define XPATH_NODE_ATTRS        XPATH_NODE_STATE "/" XML_TAG_TRANSIENT_NODEATTRS
+ 
+ // Everything under node_state (name 1x)
+ #define XPATH_NODE_ALL          XPATH_NODE_STATE "/*"
+ 
++// Unlocked history + transient attributes (name 3x)
++#define XPATH_NODE_ALL_UNLOCKED XPATH_NODE_LRM_UNLOCKED "|" XPATH_NODE_ATTRS
++
+ /*!
+  * \internal
+  * \brief Delete subsection of a node's CIB node_state
+@@ -274,6 +283,11 @@ controld_delete_node_state(const char *uname, enum controld_section_e section,
+             xpath = crm_strdup_printf(XPATH_NODE_LRM, uname);
+             desc = crm_strdup_printf("resource history for node %s", uname);
+             break;
++        case controld_section_lrm_unlocked:
++            xpath = crm_strdup_printf(XPATH_NODE_LRM_UNLOCKED, uname, uname);
++            desc = crm_strdup_printf("resource history (other than shutdown "
++                                     "locks) for node %s", uname);
++            break;
+         case controld_section_attrs:
+             xpath = crm_strdup_printf(XPATH_NODE_ATTRS, uname);
+             desc = crm_strdup_printf("transient attributes for node %s", uname);
+@@ -282,6 +296,12 @@ controld_delete_node_state(const char *uname, enum controld_section_e section,
+             xpath = crm_strdup_printf(XPATH_NODE_ALL, uname);
+             desc = crm_strdup_printf("all state for node %s", uname);
+             break;
++        case controld_section_all_unlocked:
++            xpath = crm_strdup_printf(XPATH_NODE_ALL_UNLOCKED,
++                                      uname, uname, uname);
++            desc = crm_strdup_printf("all state (other than shutdown locks) "
++                                     "for node %s", uname);
++            break;
+     }
+ 
+     if (fsa_cib_conn == NULL) {
+@@ -290,7 +310,7 @@ controld_delete_node_state(const char *uname, enum controld_section_e section,
+     } else {
+         int call_id;
+ 
+-        options |= cib_quorum_override|cib_xpath;
++        options |= cib_quorum_override|cib_xpath|cib_multiple;
+         call_id = fsa_cib_conn->cmds->delete(fsa_cib_conn, xpath, NULL, options);
+         crm_info("Deleting %s (via CIB call %d) " CRM_XS " xpath=%s",
+                  desc, call_id, xpath);
+diff --git a/crmd/crmd_utils.h b/crmd/crmd_utils.h
+index 9ecce88..77dcfc2 100644
+--- a/crmd/crmd_utils.h
++++ b/crmd/crmd_utils.h
+@@ -120,8 +120,10 @@ bool controld_action_is_recordable(const char *action);
+ // Subsections of node_state
+ enum controld_section_e {
+     controld_section_lrm,
++    controld_section_lrm_unlocked,
+     controld_section_attrs,
+     controld_section_all,
++    controld_section_all_unlocked
+ };
+ 
+ void controld_delete_node_state(const char *uname,
+diff --git a/crmd/join_dc.c b/crmd/join_dc.c
+index 8284695..1553078 100644
+--- a/crmd/join_dc.c
++++ b/crmd/join_dc.c
+@@ -534,6 +534,7 @@ do_dc_join_ack(long long action,
+     int join_id = -1;
+     int call_id = 0;
+     ha_msg_input_t *join_ack = fsa_typed_data(fsa_dt_ha_msg);
++    enum controld_section_e section = controld_section_lrm;
+ 
+     const char *op = crm_element_value(join_ack->msg, F_CRM_TASK);
+     const char *join_from = crm_element_value(join_ack->msg, F_CRM_HOST_FROM);
+@@ -583,8 +584,10 @@ do_dc_join_ack(long long action,
+     /* Update CIB with node's current LRM state. A new transition will be
+      * triggered later, when the CIB notifies us of the change.
+      */
+-    controld_delete_node_state(join_from, controld_section_lrm,
+-                               cib_scope_local);
++    if (controld_shutdown_lock_enabled) {
++        section = controld_section_lrm_unlocked;
++    }
++    controld_delete_node_state(join_from, section, cib_scope_local);
+     if (safe_str_eq(join_from, fsa_our_uname)) {
+         xmlNode *now_dc_lrmd_state = controld_query_executor_state(fsa_our_uname);
+ 
+diff --git a/crmd/remote_lrmd_ra.c b/crmd/remote_lrmd_ra.c
+index c4f58d6..3870431 100644
+--- a/crmd/remote_lrmd_ra.c
++++ b/crmd/remote_lrmd_ra.c
+@@ -1,5 +1,5 @@
+-/* 
+- * Copyright 2013-2019 the Pacemaker project contributors
++/*
++ * Copyright 2013-2020 the Pacemaker project contributors
+  *
+  * The version control history for this file may have further details.
+  * 
+@@ -191,17 +191,21 @@ remote_node_up(const char *node_name)
+     int call_opt, call_id = 0;
+     xmlNode *update, *state;
+     crm_node_t *node;
++    enum controld_section_e section = controld_section_all;
+ 
+     CRM_CHECK(node_name != NULL, return);
+     crm_info("Announcing pacemaker_remote node %s", node_name);
+ 
+-    /* Clear node's entire state (resource history and transient attributes).
+-     * The transient attributes should and normally will be cleared when the
+-     * node leaves, but since remote node state has a number of corner cases,
+-     * clear them here as well, to be sure.
++    /* Clear node's entire state (resource history and transient attributes)
++     * other than shutdown locks. The transient attributes should and normally
++     * will be cleared when the node leaves, but since remote node state has a
++     * number of corner cases, clear them here as well, to be sure.
+      */
+     call_opt = crmd_cib_smart_opt();
+-    controld_delete_node_state(node_name, controld_section_all, call_opt);
++    if (controld_shutdown_lock_enabled) {
++        section = controld_section_all_unlocked;
++    }
++    controld_delete_node_state(node_name, section, call_opt);
+ 
+     /* Clear node's probed attribute */
+     update_attrd(node_name, CRM_OP_PROBED, NULL, NULL, TRUE);
+-- 
+1.8.3.1
+
diff --git a/SOURCES/shutdown-lock-06.patch b/SOURCES/shutdown-lock-06.patch
new file mode 100644
index 0000000..dca6b41
--- /dev/null
+++ b/SOURCES/shutdown-lock-06.patch
@@ -0,0 +1,39 @@
+From f629c2de1d011e8ed7a3f1d14811681672f424d5 Mon Sep 17 00:00:00 2001
+From: Ken Gaillot <kgaillot@redhat.com>
+Date: Thu, 16 Jan 2020 12:34:21 -0600
+Subject: [PATCH 06/10] Low: scheduler: display when a resource is
+ shutdown-locked to a node
+
+... so it shows up in logs and cluster status displays
+---
+ lib/pengine/native.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/lib/pengine/native.c b/lib/pengine/native.c
+index 3c9f8f5..c66cada 100644
+--- a/lib/pengine/native.c
++++ b/lib/pengine/native.c
+@@ -538,6 +538,9 @@ common_print(resource_t * rsc, const char *pre_text, const char *name, node_t *n
+         return;
+     }
+ 
++    if ((node == NULL) && (rsc->lock_node != NULL)) {
++        node = rsc->lock_node;
++    }
+     if ((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) {
+         node = NULL;
+     }
+@@ -593,6 +596,10 @@ common_print(resource_t * rsc, const char *pre_text, const char *name, node_t *n
+             flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
+                                    "%sUNCLEAN", comma_if(flagOffset));
+         }
++        if (node == rsc->lock_node) {
++            flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
++                                   "%sLOCKED", comma_if(flagOffset));
++        }
+     }
+ 
+     if (options & pe_print_pending) {
+-- 
+1.8.3.1
+
diff --git a/SOURCES/shutdown-lock-07.patch b/SOURCES/shutdown-lock-07.patch
new file mode 100644
index 0000000..11239fe
--- /dev/null
+++ b/SOURCES/shutdown-lock-07.patch
@@ -0,0 +1,29 @@
+From e487cd68049b1da2a9646bba2f0fb26cae4022d1 Mon Sep 17 00:00:00 2001
+From: Ken Gaillot <kgaillot@redhat.com>
+Date: Tue, 14 Jan 2020 16:01:16 -0600
+Subject: [PATCH 07/10] Low: tools: crm_resource resource checks should show
+ shutdown locks
+
+---
+ tools/crm_resource_runtime.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/tools/crm_resource_runtime.c b/tools/crm_resource_runtime.c
+index 9e70db8..9b93928 100644
+--- a/tools/crm_resource_runtime.c
++++ b/tools/crm_resource_runtime.c
+@@ -907,6 +907,11 @@ cli_resource_check(cib_t * cib_conn, resource_t *rsc)
+     }
+     free(managed);
+ 
++    if (rsc->lock_node) {
++        printf("%s  * '%s' is locked to node %s due to shutdown\n",
++               (printed? "" : "\n"), parent->id, rsc->lock_node->details->uname);
++    }
++
+     if (printed) {
+         printf("\n");
+     }
+-- 
+1.8.3.1
+
diff --git a/SOURCES/shutdown-lock-08.patch b/SOURCES/shutdown-lock-08.patch
new file mode 100644
index 0000000..57ebb49
--- /dev/null
+++ b/SOURCES/shutdown-lock-08.patch
@@ -0,0 +1,191 @@
+From 3f19b4333897a0392e8a5efc4742732b8e6f0efb Mon Sep 17 00:00:00 2001
+From: Ken Gaillot <kgaillot@redhat.com>
+Date: Tue, 14 Jan 2020 12:53:39 -0600
+Subject: [PATCH 08/10] Low: controller: allow CRM_OP_LRM_DELETE to clear CIB
+ only
+
+Normally, CRM_OP_LRM_DELETE is relayed to the affected node's controller, which
+clears the resource from the executor and CIB as well the its own bookkeeping.
+
+Now, we want to be able to use it to clear shutdown locks for nodes that are
+down. Let it take a new "mode" attribute, and if it is "cib", clear the
+resource from the CIB locally without relaying the operation or doing anything
+else.
+---
+ crmd/lrm.c             |  4 ++-
+ crmd/messages.c        | 97 ++++++++++++++++++++++++++++++++++++++++++++++++--
+ crmd/te_actions.c      |  7 ++++
+ include/crm_internal.h |  2 ++
+ 4 files changed, 106 insertions(+), 4 deletions(-)
+
+diff --git a/crmd/lrm.c b/crmd/lrm.c
+index 9156ab8..bdf7b94 100644
+--- a/crmd/lrm.c
++++ b/crmd/lrm.c
+@@ -1764,7 +1764,9 @@ do_lrm_invoke(long long action,
+     crm_trace("LRM %s command from %s", crm_op, from_sys);
+ 
+     if (safe_str_eq(crm_op, CRM_OP_LRM_DELETE)) {
+-        crm_rsc_delete = TRUE; // Only crm_resource uses this op
++        if (safe_str_neq(from_sys, CRM_SYSTEM_TENGINE)) {
++            crm_rsc_delete = TRUE; // from crm_resource
++        }
+         operation = CRMD_ACTION_DELETE;
+ 
+     } else if (safe_str_eq(crm_op, CRM_OP_LRM_FAIL)) {
+diff --git a/crmd/messages.c b/crmd/messages.c
+index f1599ab..8839d65 100644
+--- a/crmd/messages.c
++++ b/crmd/messages.c
+@@ -430,6 +430,14 @@ relay_message(xmlNode * msg, gboolean originated_locally)
+ 
+     } else if (safe_str_eq(fsa_our_uname, host_to)) {
+         is_local = 1;
++    } else if (is_for_crm && safe_str_eq(task, CRM_OP_LRM_DELETE)) {
++        xmlNode *msg_data = get_message_xml(msg, F_CRM_DATA);
++        const char *mode = crm_element_value(msg_data, PCMK__XA_MODE);
++
++        if (safe_str_eq(mode, XML_TAG_CIB)) {
++            // Local delete of an offline node's resource history
++            is_local = 1;
++        }
+     }
+ 
+     if (is_for_dc || is_for_dcib || is_for_te) {
+@@ -669,6 +677,86 @@ handle_failcount_op(xmlNode * stored_msg)
+     return I_NULL;
+ }
+ 
++static enum crmd_fsa_input
++handle_lrm_delete(xmlNode *stored_msg)
++{
++    const char *mode = NULL;
++    xmlNode *msg_data = get_message_xml(stored_msg, F_CRM_DATA);
++
++    CRM_CHECK(msg_data != NULL, return I_NULL);
++
++    /* CRM_OP_LRM_DELETE has two distinct modes. The default behavior is to
++     * relay the operation to the affected node, which will unregister the
++     * resource from the local executor, clear the resource's history from the
++     * CIB, and do some bookkeeping in the controller.
++     *
++     * However, if the affected node is offline, the client will specify
++     * mode="cib" which means the controller receiving the operation should
++     * clear the resource's history from the CIB and nothing else. This is used
++     * to clear shutdown locks.
++     */
++    mode = crm_element_value(msg_data, PCMK__XA_MODE);
++    if ((mode == NULL) || strcmp(mode, XML_TAG_CIB)) {
++        // Relay to affected node
++        crm_xml_add(stored_msg, F_CRM_SYS_TO, CRM_SYSTEM_LRMD);
++        return I_ROUTER;
++
++    } else {
++        // Delete CIB history locally (compare with do_lrm_delete())
++        const char *from_sys = NULL;
++        const char *user_name = NULL;
++        const char *rsc_id = NULL;
++        const char *node = NULL;
++        xmlNode *rsc_xml = NULL;
++        int rc = pcmk_rc_ok;
++
++        rsc_xml = first_named_child(msg_data, XML_CIB_TAG_RESOURCE);
++        CRM_CHECK(rsc_xml != NULL, return I_NULL);
++
++        rsc_id = ID(rsc_xml);
++        from_sys = crm_element_value(stored_msg, F_CRM_SYS_FROM);
++        node = crm_element_value(msg_data, XML_LRM_ATTR_TARGET);
++#if ENABLE_ACL
++        user_name = crm_acl_get_set_user(stored_msg, F_CRM_USER, NULL);
++#endif
++        crm_debug("Handling " CRM_OP_LRM_DELETE " for %s on %s locally%s%s "
++                  "(clearing CIB resource history only)", rsc_id, node,
++                  (user_name? " for user " : ""), (user_name? user_name : ""));
++#if ENABLE_ACL
++        rc = controld_delete_resource_history(rsc_id, node, user_name,
++                                              cib_dryrun|cib_sync_call);
++#endif
++        if (rc == pcmk_rc_ok) {
++            rc = controld_delete_resource_history(rsc_id, node, user_name,
++                                                  crmd_cib_smart_opt());
++        }
++
++        // Notify client if not from graph (compare with notify_deleted())
++        if (from_sys && strcmp(from_sys, CRM_SYSTEM_TENGINE)) {
++            lrmd_event_data_t *op = NULL;
++            const char *from_host = crm_element_value(stored_msg,
++                                                      F_CRM_HOST_FROM);
++            const char *transition = crm_element_value(msg_data,
++                                                       XML_ATTR_TRANSITION_KEY);
++
++            crm_info("Notifying %s on %s that %s was%s deleted",
++                     from_sys, (from_host? from_host : "local node"), rsc_id,
++                     ((rc == pcmk_rc_ok)? "" : " not"));
++            op = lrmd_new_event(rsc_id, CRMD_ACTION_DELETE, 0);
++            op->type = lrmd_event_exec_complete;
++            op->user_data = strdup(transition? transition : FAKE_TE_ID);
++            op->params = crm_str_table_new();
++            g_hash_table_insert(op->params, strdup(XML_ATTR_CRM_VERSION),
++                                strdup(CRM_FEATURE_SET));
++            controld_rc2event(op, rc);
++            controld_ack_event_directly(from_host, from_sys, NULL, op, rsc_id);
++            lrmd_free_event(op);
++            controld_trigger_delete_refresh(from_sys, rsc_id);
++        }
++        return I_NULL;
++    }
++}
++
+ /*!
+  * \brief Handle a CRM_OP_REMOTE_STATE message by updating remote peer cache
+  *
+@@ -902,9 +990,12 @@ handle_request(xmlNode * stored_msg, enum crmd_fsa_cause cause)
+         crm_debug("Raising I_JOIN_RESULT: join-%s", crm_element_value(stored_msg, F_CRM_JOIN_ID));
+         return I_JOIN_RESULT;
+ 
+-    } else if (strcmp(op, CRM_OP_LRM_DELETE) == 0
+-               || strcmp(op, CRM_OP_LRM_FAIL) == 0
+-               || strcmp(op, CRM_OP_LRM_REFRESH) == 0 || strcmp(op, CRM_OP_REPROBE) == 0) {
++    } else if (strcmp(op, CRM_OP_LRM_DELETE) == 0) {
++        return handle_lrm_delete(stored_msg);
++
++    } else if ((strcmp(op, CRM_OP_LRM_FAIL) == 0)
++               || (strcmp(op, CRM_OP_LRM_REFRESH) == 0)
++               || (strcmp(op, CRM_OP_REPROBE) == 0)) {
+ 
+         crm_xml_add(stored_msg, F_CRM_SYS_TO, CRM_SYSTEM_LRMD);
+         return I_ROUTER;
+diff --git a/crmd/te_actions.c b/crmd/te_actions.c
+index 19bb199..ec92df2 100644
+--- a/crmd/te_actions.c
++++ b/crmd/te_actions.c
+@@ -239,6 +239,13 @@ te_crm_command(crm_graph_t * graph, crm_action_t * action)
+ 
+     if (!router_node) {
+         router_node = on_node;
++        if (safe_str_eq(task, CRM_OP_LRM_DELETE)) {
++            const char *mode = crm_element_value(action->xml, PCMK__XA_MODE);
++
++            if (safe_str_eq(mode, XML_TAG_CIB)) {
++                router_node = fsa_our_uname;
++            }
++        }
+     }
+ 
+     CRM_CHECK(on_node != NULL && strlen(on_node) != 0,
+diff --git a/include/crm_internal.h b/include/crm_internal.h
+index 0adeb7b..7656bf5 100644
+--- a/include/crm_internal.h
++++ b/include/crm_internal.h
+@@ -260,6 +260,8 @@ long crm_read_pidfile(const char *filename);
+ #  define ATTRD_OP_SYNC_RESPONSE "sync-response"
+ #  define ATTRD_OP_CLEAR_FAILURE "clear-failure"
+ 
++#  define PCMK__XA_MODE             "mode"
++
+ #  define PCMK_ENV_PHYSICAL_HOST "physical_host"
+ 
+ 
+-- 
+1.8.3.1
+
diff --git a/SOURCES/shutdown-lock-09.patch b/SOURCES/shutdown-lock-09.patch
new file mode 100644
index 0000000..5af52c6
--- /dev/null
+++ b/SOURCES/shutdown-lock-09.patch
@@ -0,0 +1,56 @@
+From 8ab8d64976212207935bf165c26db32c1d79c344 Mon Sep 17 00:00:00 2001
+From: Ken Gaillot <kgaillot@redhat.com>
+Date: Tue, 14 Jan 2020 16:24:08 -0600
+Subject: [PATCH 09/10] Low: tools: for down nodes, crm_resource --refresh
+ should clear CIB only
+
+This provides a mechanism to manually clear shutdown locks.
+---
+ tools/crm_resource_runtime.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/tools/crm_resource_runtime.c b/tools/crm_resource_runtime.c
+index 9b93928..acb9dbe 100644
+--- a/tools/crm_resource_runtime.c
++++ b/tools/crm_resource_runtime.c
+@@ -458,6 +458,7 @@ send_lrm_rsc_op(crm_ipc_t * crmd_channel, const char *op,
+     const char *rsc_type = NULL;
+     xmlNode *params = NULL;
+     xmlNode *msg_data = NULL;
++    bool cib_only = false;
+     resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
+ 
+     if (rsc == NULL) {
+@@ -489,10 +490,14 @@ send_lrm_rsc_op(crm_ipc_t * crmd_channel, const char *op,
+         }
+ 
+         if (!(node->details->online)) {
+-            CMD_ERR("Node %s is not online", host_uname);
+-            return -ENOTCONN;
++            if (strcmp(op, CRM_OP_LRM_DELETE) == 0) {
++                cib_only = true;
++            } else {
++                CMD_ERR("Node %s is not online", host_uname);
++                return -ENOTCONN;
++            }
+         }
+-        if (node && is_remote_node(node)) {
++        if (!cib_only && node && is_remote_node(node)) {
+             node = pe__current_node(node->details->remote_rsc);
+             if (node == NULL) {
+                 CMD_ERR("No lrmd connection detected to remote node %s", host_uname);
+@@ -517,6 +522,11 @@ send_lrm_rsc_op(crm_ipc_t * crmd_channel, const char *op,
+         crm_xml_add(msg_data, XML_LRM_ATTR_ROUTER_NODE, router_node);
+     }
+ 
++    if (cib_only) {
++        // Indicate that only the CIB needs to be cleaned
++        crm_xml_add(msg_data, PCMK__XA_MODE, XML_TAG_CIB);
++    }
++
+     xml_rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE);
+     if (rsc->clone_name) {
+         crm_xml_add(xml_rsc, XML_ATTR_ID, rsc->clone_name);
+-- 
+1.8.3.1
+
diff --git a/SOURCES/shutdown-lock-10.patch b/SOURCES/shutdown-lock-10.patch
new file mode 100644
index 0000000..2d8afe6
--- /dev/null
+++ b/SOURCES/shutdown-lock-10.patch
@@ -0,0 +1,225 @@
+From abbfc0ba9afb6c2d1ce54fea2d0cf25ce1d9108a Mon Sep 17 00:00:00 2001
+From: Ken Gaillot <kgaillot@redhat.com>
+Date: Fri, 10 Jan 2020 18:18:07 -0600
+Subject: [PATCH 10/10] Low: scheduler: clear resource history when appropriate
+
+Tell the controller to clear resource history from the CIB when a resource has
+a shutdown lock that expired or was cancelled because the resource is already
+active elsewhere.
+---
+ include/crm/pengine/internal.h |  6 +++++-
+ include/crm/pengine/status.h   |  6 +++++-
+ lib/pengine/unpack.c           |  1 +
+ lib/pengine/utils.c            | 34 ++++++++++++++++++++++++++++++++--
+ pengine/allocate.c             |  1 +
+ pengine/graph.c                | 16 ++++++++++++++--
+ pengine/native.c               |  6 ++++++
+ 7 files changed, 64 insertions(+), 6 deletions(-)
+
+diff --git a/include/crm/pengine/internal.h b/include/crm/pengine/internal.h
+index fc908e8..64b9a50 100644
+--- a/include/crm/pengine/internal.h
++++ b/include/crm/pengine/internal.h
+@@ -1,5 +1,7 @@
+ /*
+- * Copyright 2004-2019 Andrew Beekhof <andrew@beekhof.net>
++ * Copyright 2004-2020 the Pacemaker project contributors
++ *
++ * The version control history for this file may have further details.
+  *
+  * This source code is licensed under the GNU Lesser General Public License
+  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
+@@ -366,4 +368,7 @@ void pe__free_param_checks(pe_working_set_t *data_set);
+ bool pe__shutdown_requested(pe_node_t *node);
+ bool pe__resource_is_disabled(pe_resource_t *rsc);
+ 
++pe_action_t *pe__clear_resource_history(pe_resource_t *rsc, pe_node_t *node,
++                                        pe_working_set_t *data_set);
++
+ #endif
+diff --git a/include/crm/pengine/status.h b/include/crm/pengine/status.h
+index 1e8d5bb..9f9fd3b 100644
+--- a/include/crm/pengine/status.h
++++ b/include/crm/pengine/status.h
+@@ -1,5 +1,7 @@
+ /*
+- * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
++ * Copyright 2004-2020 the Pacemaker project contributors
++ *
++ * The version control history for this file may have further details.
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Lesser General Public
+@@ -280,6 +282,8 @@ enum pe_action_flags {
+ 
+     pe_action_reschedule = 0x02000,
+     pe_action_tracking = 0x04000,
++
++    pe_action_dc = 0x10000,         //! Action may run on DC instead of target
+ };
+ /* *INDENT-ON* */
+ 
+diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c
+index bb5efa4..9deff67 100644
+--- a/lib/pengine/unpack.c
++++ b/lib/pengine/unpack.c
+@@ -2306,6 +2306,7 @@ unpack_shutdown_lock(xmlNode *rsc_entry, pe_resource_t *rsc, pe_node_t *node,
+                 > (lock_time + data_set->shutdown_lock))) {
+             pe_rsc_info(rsc, "Shutdown lock for %s on %s expired",
+                         rsc->id, node->details->uname);
++            pe__clear_resource_history(rsc, node, data_set);
+         } else {
+             rsc->lock_node = node;
+             rsc->lock_time = lock_time;
+diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c
+index c336e37..84d3399 100644
+--- a/lib/pengine/utils.c
++++ b/lib/pengine/utils.c
+@@ -490,6 +490,11 @@ custom_action(resource_t * rsc, char *key, const char *task,
+         }
+         action->uuid = strdup(key);
+ 
++        if (safe_str_eq(task, CRM_OP_LRM_DELETE)) {
++            // Resource history deletion for a node can be done on the DC
++            pe_set_action_bit(action, pe_action_dc);
++        }
++
+         pe_set_action_bit(action, pe_action_runnable);
+         if (optional) {
+             pe_rsc_trace(rsc, "Set optional on %s", action->uuid);
+@@ -570,7 +575,8 @@ custom_action(resource_t * rsc, char *key, const char *task,
+             pe_set_action_bit(action, pe_action_optional);
+ /*   			action->runnable = FALSE; */
+ 
+-        } else if (action->node->details->online == FALSE
++        } else if (is_not_set(action->flags, pe_action_dc)
++                   && !(action->node->details->online)
+                    && (!is_container_remote_node(action->node) || action->node->details->remote_requires_reset)) {
+             pe_clear_action_bit(action, pe_action_runnable);
+             do_crm_log(warn_level, "Action %s on %s is unrunnable (offline)",
+@@ -581,7 +587,8 @@ custom_action(resource_t * rsc, char *key, const char *task,
+                 pe_fence_node(data_set, action->node, "resource actions are unrunnable");
+             }
+ 
+-        } else if (action->node->details->pending) {
++        } else if (is_not_set(action->flags, pe_action_dc)
++                   && action->node->details->pending) {
+             pe_clear_action_bit(action, pe_action_runnable);
+             do_crm_log(warn_level, "Action %s on %s is unrunnable (pending)",
+                        action->uuid, action->node->details->uname);
+@@ -695,6 +702,8 @@ unpack_operation_on_fail(action_t * action)
+ 
+             value = on_fail;
+         }
++    } else if (safe_str_eq(action->task, CRM_OP_LRM_DELETE)) {
++        value = "ignore";
+     }
+ 
+     return value;
+@@ -2566,3 +2575,24 @@ pe__resource_is_disabled(pe_resource_t *rsc)
+     }
+     return false;
+ }
++
++/*!
++ * \internal
++ * \brief Create an action to clear a resource's history from CIB
++ *
++ * \param[in] rsc   Resource to clear
++ * \param[in] node  Node to clear history on
++ *
++ * \return New action to clear resource history
++ */
++pe_action_t *
++pe__clear_resource_history(pe_resource_t *rsc, pe_node_t *node,
++                           pe_working_set_t *data_set)
++{
++    char *key = NULL;
++
++    CRM_ASSERT(rsc && node);
++    key = generate_op_key(rsc->id, CRM_OP_LRM_DELETE, 0);
++    return custom_action(rsc, key, CRM_OP_LRM_DELETE, node, FALSE, TRUE,
++                         data_set);
++}
+diff --git a/pengine/allocate.c b/pengine/allocate.c
+index 7366716..946f063 100644
+--- a/pengine/allocate.c
++++ b/pengine/allocate.c
+@@ -1058,6 +1058,7 @@ apply_shutdown_lock(pe_resource_t *rsc, pe_working_set_t *data_set)
+             pe_rsc_info(rsc,
+                         "Cancelling shutdown lock because %s is already active",
+                         rsc->id);
++            pe__clear_resource_history(rsc, rsc->lock_node, data_set);
+             rsc->lock_node = NULL;
+             rsc->lock_time = 0;
+         }
+diff --git a/pengine/graph.c b/pengine/graph.c
+index 33168ca..a045549 100644
+--- a/pengine/graph.c
++++ b/pengine/graph.c
+@@ -596,10 +596,11 @@ update_action(action_t * then)
+ 
+             /* 'then' is required, so we must abandon 'first'
+              * (e.g. a required stop cancels any reload).
+-             * Only used with reload actions as 'first'.
+              */
+             set_bit(other->action->flags, pe_action_optional);
+-            clear_bit(first->rsc->flags, pe_rsc_reload);
++            if (!strcmp(first->task, CRMD_ACTION_RELOAD)) {
++                clear_bit(first->rsc->flags, pe_rsc_reload);
++            }
+         }
+ 
+         if (first->rsc && then->rsc && (first->rsc != then->rsc)
+@@ -1051,6 +1052,11 @@ action2xml(action_t * action, gboolean as_input, pe_working_set_t *data_set)
+     } else if (safe_str_eq(action->task, CRM_OP_LRM_REFRESH)) {
+         action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
+ 
++    } else if (safe_str_eq(action->task, CRM_OP_LRM_DELETE)) {
++        // CIB-only clean-up for shutdown locks
++        action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT);
++        crm_xml_add(action_xml, PCMK__XA_MODE, XML_TAG_CIB);
++
+ /* 	} else if(safe_str_eq(action->task, RSC_PROBED)) { */
+ /* 		action_xml = create_xml_node(NULL, XML_GRAPH_TAG_CRM_EVENT); */
+ 
+@@ -1063,6 +1069,7 @@ action2xml(action_t * action, gboolean as_input, pe_working_set_t *data_set)
+ 
+     } else {
+         action_xml = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
++
+ #if ENABLE_VERSIONED_ATTRS
+         rsc_details = pe_rsc_action_details(action);
+ #endif
+@@ -1404,6 +1411,11 @@ should_dump_action(action_t * action)
+         log_action(LOG_DEBUG, "Unallocated action", action, FALSE);
+         return FALSE;
+ 
++    } else if (is_set(action->flags, pe_action_dc)) {
++        crm_trace("Action %s (%d) should be dumped: "
++                  "can run on DC instead of %s",
++                  action->uuid, action->id, action->node->details->uname);
++
+     } else if(is_container_remote_node(action->node) && action->node->details->remote_requires_reset == FALSE) {
+         crm_trace("Assuming action %s for %s will be runnable", action->uuid, action->node->details->uname);
+ 
+diff --git a/pengine/native.c b/pengine/native.c
+index 1abaf29..b639fae 100644
+--- a/pengine/native.c
++++ b/pengine/native.c
+@@ -1439,6 +1439,12 @@ native_internal_constraints(resource_t * rsc, pe_working_set_t * data_set)
+                             pe_order_runnable_left, data_set);
+     }
+ 
++    // Don't clear resource history if probing on same node
++    custom_action_order(rsc, generate_op_key(rsc->id, CRM_OP_LRM_DELETE, 0),
++                        NULL, rsc, generate_op_key(rsc->id, RSC_STATUS, 0),
++                        NULL, pe_order_same_node|pe_order_then_cancels_first,
++                        data_set);
++
+     // Certain checks need allowed nodes
+     if (check_unfencing || check_utilization || rsc->container) {
+         allowed_nodes = allowed_nodes_as_list(rsc, data_set);
+-- 
+1.8.3.1
+
diff --git a/SOURCES/shutdown-lock-11.patch b/SOURCES/shutdown-lock-11.patch
new file mode 100644
index 0000000..1455cdf
--- /dev/null
+++ b/SOURCES/shutdown-lock-11.patch
@@ -0,0 +1,726 @@
+From 6fa96ab26752f03ef3d9f08b22e91dba0ca6085c Mon Sep 17 00:00:00 2001
+From: Ken Gaillot <kgaillot@redhat.com>
+Date: Thu, 16 Jan 2020 14:48:05 -0600
+Subject: [PATCH] Test: scheduler: add regression tests for shutdown locks
+
+---
+ pengine/regression.sh                           |   2 +
+ pengine/test10/shutdown-lock-expiration.dot     |  11 ++
+ pengine/test10/shutdown-lock-expiration.exp     |  68 +++++++++
+ pengine/test10/shutdown-lock-expiration.scores  |  17 +++
+ pengine/test10/shutdown-lock-expiration.summary |  31 ++++
+ pengine/test10/shutdown-lock-expiration.xml     | 186 ++++++++++++++++++++++++
+ pengine/test10/shutdown-lock.dot                |  11 ++
+ pengine/test10/shutdown-lock.exp                |  64 ++++++++
+ pengine/test10/shutdown-lock.scores             |  17 +++
+ pengine/test10/shutdown-lock.summary            |  31 ++++
+ pengine/test10/shutdown-lock.xml                | 185 +++++++++++++++++++++++
+ 11 files changed, 623 insertions(+)
+ create mode 100644 pengine/test10/shutdown-lock-expiration.dot
+ create mode 100644 pengine/test10/shutdown-lock-expiration.exp
+ create mode 100644 pengine/test10/shutdown-lock-expiration.scores
+ create mode 100644 pengine/test10/shutdown-lock-expiration.summary
+ create mode 100644 pengine/test10/shutdown-lock-expiration.xml
+ create mode 100644 pengine/test10/shutdown-lock.dot
+ create mode 100644 pengine/test10/shutdown-lock.exp
+ create mode 100644 pengine/test10/shutdown-lock.scores
+ create mode 100644 pengine/test10/shutdown-lock.summary
+ create mode 100644 pengine/test10/shutdown-lock.xml
+
+diff --git a/pengine/regression.sh b/pengine/regression.sh
+index f2226ed..abb9708 100755
+--- a/pengine/regression.sh
++++ b/pengine/regression.sh
+@@ -894,6 +894,8 @@ do_test remote-connection-unrecoverable  "Remote connection host must be fenced,
+ echo ""
+ do_test resource-discovery      "Exercises resource-discovery location constraint option."
+ do_test rsc-discovery-per-node  "Disable resource discovery per node"
++do_test shutdown-lock           "Ensure shutdown lock works properly"
++do_test shutdown-lock-expiration "Ensure shutdown lock expiration works properly"
+ 
+ echo ""
+ do_test isolation-start-all   "Start docker isolated resources."
+diff --git a/pengine/test10/shutdown-lock-expiration.dot b/pengine/test10/shutdown-lock-expiration.dot
+new file mode 100644
+index 0000000..cd1a4fd
+--- /dev/null
++++ b/pengine/test10/shutdown-lock-expiration.dot
+@@ -0,0 +1,11 @@
++digraph "g" {
++"Fencing_monitor_120000 node3" [ style=bold color="green" fontcolor="black"]
++"Fencing_start_0 node3" -> "Fencing_monitor_120000 node3" [ style = bold]
++"Fencing_start_0 node3" [ style=bold color="green" fontcolor="black"]
++"Fencing_stop_0 node3" -> "Fencing_start_0 node3" [ style = bold]
++"Fencing_stop_0 node3" [ style=bold color="green" fontcolor="black"]
++"rsc2_lrm_delete_0 node2" [ style=bold color="green" fontcolor="black"]
++"rsc2_monitor_10000 node4" [ style=bold color="green" fontcolor="black"]
++"rsc2_start_0 node4" -> "rsc2_monitor_10000 node4" [ style = bold]
++"rsc2_start_0 node4" [ style=bold color="green" fontcolor="black"]
++}
+diff --git a/pengine/test10/shutdown-lock-expiration.exp b/pengine/test10/shutdown-lock-expiration.exp
+new file mode 100644
+index 0000000..6f3d139
+--- /dev/null
++++ b/pengine/test10/shutdown-lock-expiration.exp
+@@ -0,0 +1,68 @@
++<transition_graph cluster-delay="60s" stonith-timeout="60s" failed-stop-offset="INFINITY" failed-start-offset="1"  transition_id="0">
++  <synapse id="0">
++    <action_set>
++      <rsc_op id="4" operation="stop" operation_key="Fencing_stop_0" on_node="node3" on_node_uuid="3">
++        <primitive id="Fencing" class="stonith" type="fence_xvm"/>
++        <attributes CRM_meta_name="stop" CRM_meta_on_node="node3" CRM_meta_on_node_uuid="3" CRM_meta_timeout="60000"  key_file="/etc/pacemaker/fence_xvm.key" multicast_address="239.255.100.100" pcmk_host_list="node1 node2 node3 node4 node5"/>
++      </rsc_op>
++    </action_set>
++    <inputs/>
++  </synapse>
++  <synapse id="1">
++    <action_set>
++      <rsc_op id="3" operation="start" operation_key="Fencing_start_0" on_node="node3" on_node_uuid="3">
++        <primitive id="Fencing" class="stonith" type="fence_xvm"/>
++        <attributes CRM_meta_name="start" CRM_meta_on_node="node3" CRM_meta_on_node_uuid="3" CRM_meta_timeout="60000"  key_file="/etc/pacemaker/fence_xvm.key" multicast_address="239.255.100.100" pcmk_host_list="node1 node2 node3 node4 node5"/>
++      </rsc_op>
++    </action_set>
++    <inputs>
++      <trigger>
++        <rsc_op id="4" operation="stop" operation_key="Fencing_stop_0" on_node="node3" on_node_uuid="3"/>
++      </trigger>
++    </inputs>
++  </synapse>
++  <synapse id="2">
++    <action_set>
++      <rsc_op id="2" operation="monitor" operation_key="Fencing_monitor_120000" on_node="node3" on_node_uuid="3">
++        <primitive id="Fencing" class="stonith" type="fence_xvm"/>
++        <attributes CRM_meta_interval="120000" CRM_meta_name="monitor" CRM_meta_on_node="node3" CRM_meta_on_node_uuid="3" CRM_meta_timeout="120000"  key_file="/etc/pacemaker/fence_xvm.key" multicast_address="239.255.100.100" pcmk_host_list="node1 node2 node3 node4 node5"/>
++      </rsc_op>
++    </action_set>
++    <inputs>
++      <trigger>
++        <rsc_op id="3" operation="start" operation_key="Fencing_start_0" on_node="node3" on_node_uuid="3"/>
++      </trigger>
++    </inputs>
++  </synapse>
++  <synapse id="3">
++    <action_set>
++      <rsc_op id="6" operation="monitor" operation_key="rsc2_monitor_10000" on_node="node4" on_node_uuid="4">
++        <primitive id="rsc2" class="ocf" provider="pacemaker" type="Dummy"/>
++        <attributes CRM_meta_interval="10000" CRM_meta_name="monitor" CRM_meta_on_node="node4" CRM_meta_on_node_uuid="4" CRM_meta_timeout="20000" />
++      </rsc_op>
++    </action_set>
++    <inputs>
++      <trigger>
++        <rsc_op id="5" operation="start" operation_key="rsc2_start_0" on_node="node4" on_node_uuid="4"/>
++      </trigger>
++    </inputs>
++  </synapse>
++  <synapse id="4">
++    <action_set>
++      <rsc_op id="5" operation="start" operation_key="rsc2_start_0" on_node="node4" on_node_uuid="4">
++        <primitive id="rsc2" class="ocf" provider="pacemaker" type="Dummy"/>
++        <attributes CRM_meta_name="start" CRM_meta_on_node="node4" CRM_meta_on_node_uuid="4" CRM_meta_timeout="20000" />
++      </rsc_op>
++    </action_set>
++    <inputs/>
++  </synapse>
++  <synapse id="5">
++    <action_set>
++      <crm_event mode="cib" id="1" operation="lrm_delete" operation_key="rsc2_lrm_delete_0" on_node="node2" on_node_uuid="2">
++        <primitive id="rsc2" class="ocf" provider="pacemaker" type="Dummy"/>
++        <attributes CRM_meta_on_node="node2" CRM_meta_on_node_uuid="2" CRM_meta_timeout="90000" />
++      </crm_event>
++    </action_set>
++    <inputs/>
++  </synapse>
++</transition_graph>
+diff --git a/pengine/test10/shutdown-lock-expiration.scores b/pengine/test10/shutdown-lock-expiration.scores
+new file mode 100644
+index 0000000..e5d435d
+--- /dev/null
++++ b/pengine/test10/shutdown-lock-expiration.scores
+@@ -0,0 +1,17 @@
++Allocation scores:
++Using the original execution date of: 2020-01-06 22:11:40Z
++pcmk__native_allocate: Fencing allocation score on node1: 0
++pcmk__native_allocate: Fencing allocation score on node2: 0
++pcmk__native_allocate: Fencing allocation score on node3: 0
++pcmk__native_allocate: Fencing allocation score on node4: 0
++pcmk__native_allocate: Fencing allocation score on node5: 0
++pcmk__native_allocate: rsc1 allocation score on node1: INFINITY
++pcmk__native_allocate: rsc1 allocation score on node2: -INFINITY
++pcmk__native_allocate: rsc1 allocation score on node3: -INFINITY
++pcmk__native_allocate: rsc1 allocation score on node4: -INFINITY
++pcmk__native_allocate: rsc1 allocation score on node5: -INFINITY
++pcmk__native_allocate: rsc2 allocation score on node1: 0
++pcmk__native_allocate: rsc2 allocation score on node2: INFINITY
++pcmk__native_allocate: rsc2 allocation score on node3: 0
++pcmk__native_allocate: rsc2 allocation score on node4: 0
++pcmk__native_allocate: rsc2 allocation score on node5: 0
+diff --git a/pengine/test10/shutdown-lock-expiration.summary b/pengine/test10/shutdown-lock-expiration.summary
+new file mode 100644
+index 0000000..08c93aa
+--- /dev/null
++++ b/pengine/test10/shutdown-lock-expiration.summary
+@@ -0,0 +1,31 @@
++Using the original execution date of: 2020-01-06 22:11:40Z
++
++Current cluster status:
++Online: [ node3 node4 node5 ]
++OFFLINE: [ node1 node2 ]
++
++ Fencing	(stonith:fence_xvm):	Started node3
++ rsc1	(ocf::pacemaker:Dummy):	Stopped node1 (LOCKED)
++ rsc2	(ocf::pacemaker:Dummy):	Stopped
++
++Transition Summary:
++ * Restart    Fencing     ( node3 )   due to resource definition change
++ * Start      rsc2        ( node4 )  
++
++Executing cluster transition:
++ * Resource action: Fencing         stop on node3
++ * Resource action: Fencing         start on node3
++ * Resource action: Fencing         monitor=120000 on node3
++ * Resource action: rsc2            start on node4
++ * Cluster action:  lrm_delete for rsc2 on node2
++ * Resource action: rsc2            monitor=10000 on node4
++Using the original execution date of: 2020-01-06 22:11:40Z
++
++Revised cluster status:
++Online: [ node3 node4 node5 ]
++OFFLINE: [ node1 node2 ]
++
++ Fencing	(stonith:fence_xvm):	Started node3
++ rsc1	(ocf::pacemaker:Dummy):	Stopped node1 (LOCKED)
++ rsc2	(ocf::pacemaker:Dummy):	Started node4
++
+diff --git a/pengine/test10/shutdown-lock-expiration.xml b/pengine/test10/shutdown-lock-expiration.xml
+new file mode 100644
+index 0000000..6caa7cf
+--- /dev/null
++++ b/pengine/test10/shutdown-lock-expiration.xml
+@@ -0,0 +1,186 @@
++<cib crm_feature_set="3.0.14" validate-with="pacemaker-2.10" epoch="155" num_updates="14" admin_epoch="0" cib-last-written="Mon Jan  6 16:05:00 2020" update-origin="node2" update-client="cibadmin" update-user="root" have-quorum="1" dc-uuid="3" execution-date="1578348700">
++  <configuration>
++    <crm_config>
++      <cluster_property_set id="cib-bootstrap-options">
++        <nvpair id="cts-stonith-enabled" name="stonith-enabled" value="1"/>
++        <nvpair id="cts-start-failure-is-fatal" name="start-failure-is-fatal" value="false"/>
++        <nvpair id="cts-pe-input-series-max" name="pe-input-series-max" value="5000"/>
++        <nvpair id="cts-shutdown-escalation" name="shutdown-escalation" value="5min"/>
++        <nvpair id="cts-batch-limit" name="batch-limit" value="10"/>
++        <nvpair id="cts-dc-deadtime" name="dc-deadtime" value="5s"/>
++        <nvpair id="cts-no-quorum-policy" name="no-quorum-policy" value="stop"/>
++        <nvpair id="cib-bootstrap-options-have-watchdog" name="have-watchdog" value="false"/>
++        <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"/>
++        <nvpair id="cib-bootstrap-options-cluster-name" name="cluster-name" value="mycluster"/>
++        <!-- This regression test ensures that shutdown lock expiration works properly, for both
++             non-expired locks (rsc1 on node1) and expired locks (rsc2 on node2). This will also
++             ensure that the next recheck time is calculated properly.
++          -->
++        <nvpair id="cib-bootstrap-options-shutdown-lock" name="shutdown-lock" value="true"/>
++        <nvpair id="cib-bootstrap-options-shutdown-lock-limit" name="shutdown-lock-limit" value="5m"/>
++      </cluster_property_set>
++    </crm_config>
++    <nodes>
++      <node id="1" uname="node1">
++        <instance_attributes id="nodes-1">
++          <nvpair id="nodes-1-standby" name="standby" value="off"/>
++        </instance_attributes>
++      </node>
++      <node id="2" uname="node2"/>
++      <node id="3" uname="node3">
++        <instance_attributes id="nodes-3">
++          <nvpair id="nodes-3-standby" name="standby" value="off"/>
++        </instance_attributes>
++      </node>
++      <node id="4" uname="node4">
++        <instance_attributes id="nodes-4">
++          <nvpair id="nodes-4-standby" name="standby" value="off"/>
++        </instance_attributes>
++      </node>
++      <node id="5" uname="node5"/>
++    </nodes>
++    <resources>
++      <primitive class="stonith" id="Fencing" type="fence_xvm">
++        <meta_attributes id="Fencing-meta">
++          <nvpair id="Fencing-migration-threshold" name="migration-threshold" value="5"/>
++        </meta_attributes>
++        <instance_attributes id="Fencing-params">
++          <nvpair id="Fencing-key_file" name="key_file" value="/etc/pacemaker/fence_xvm.key"/>
++          <nvpair id="Fencing-multicast_address" name="multicast_address" value="239.255.100.100"/>
++          <nvpair id="Fencing-pcmk_host_list" name="pcmk_host_list" value="node1 node2 node3 node4 node5"/>
++        </instance_attributes>
++        <operations>
++          <op id="Fencing-monitor-120s" interval="120s" name="monitor" timeout="120s"/>
++          <op id="Fencing-stop-0" interval="0" name="stop" timeout="60s"/>
++          <op id="Fencing-start-0" interval="0" name="start" timeout="60s"/>
++        </operations>
++      </primitive>
++      <primitive class="ocf" id="rsc1" provider="pacemaker" type="Dummy">
++        <operations>
++          <op id="rsc1-migrate_from-interval-0s" interval="0s" name="migrate_from" timeout="20s"/>
++          <op id="rsc1-migrate_to-interval-0s" interval="0s" name="migrate_to" timeout="20s"/>
++          <op id="rsc1-monitor-interval-10s" interval="10s" name="monitor" timeout="20s"/>
++          <op id="rsc1-reload-interval-0s" interval="0s" name="reload" timeout="20s"/>
++          <op id="rsc1-start-interval-0s" interval="0s" name="start" timeout="20s"/>
++          <op id="rsc1-stop-interval-0s" interval="0s" name="stop" timeout="20s"/>
++        </operations>
++      </primitive>
++      <primitive class="ocf" id="rsc2" provider="pacemaker" type="Dummy">
++        <operations>
++          <op id="rsc2-migrate_from-interval-0s" interval="0s" name="migrate_from" timeout="20s"/>
++          <op id="rsc2-migrate_to-interval-0s" interval="0s" name="migrate_to" timeout="20s"/>
++          <op id="rsc2-monitor-interval-10s" interval="10s" name="monitor" timeout="20s"/>
++          <op id="rsc2-reload-interval-0s" interval="0s" name="reload" timeout="20s"/>
++          <op id="rsc2-start-interval-0s" interval="0s" name="start" timeout="20s"/>
++          <op id="rsc2-stop-interval-0s" interval="0s" name="stop" timeout="20s"/>
++        </operations>
++      </primitive>
++    </resources>
++    <constraints>
++      <rsc_location id="location-rsc1-node1-INFINITY" node="node1" rsc="rsc1" score="INFINITY"/>
++      <rsc_location id="location-rsc2-node2-INFINITY" node="node2" rsc="rsc2" score="INFINITY"/>
++    </constraints>
++    <op_defaults>
++      <meta_attributes id="cts-op_defaults-meta">
++        <nvpair id="cts-op_defaults-timeout" name="timeout" value="90s"/>
++      </meta_attributes>
++    </op_defaults>
++    <alerts>
++      <alert id="alert-1" path="/var/lib/pacemaker/notify.sh">
++        <recipient id="alert-1-recipient-1" value="/run/crm/alert.log"/>
++      </alert>
++    </alerts>
++    <rsc_defaults>
++      <meta_attributes id="rsc_defaults-options"/>
++    </rsc_defaults>
++  </configuration>
++  <status>
++    <node_state id="2" uname="node2" in_ccm="false" crmd="offline" crm-debug-origin="post_cache_update" join="down" expected="down">
++      <lrm id="2">
++        <lrm_resources>
++          <lrm_resource id="rsc2" type="Dummy" class="ocf" provider="pacemaker" shutdown-lock="1578348332">
++            <lrm_rsc_op id="rsc2_last_0" operation_key="rsc2_stop_0" operation="stop" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="8:6:0:398bf005-bb15-4098-9a72-d8373456b457" transition-magic="0:0;8:6:0:398bf005-bb15-4098-9a72-d8373456b457" exit-reason="" on_node="node2" call-id="24" rc-code="0" op-status="0" interval="0" last-rc-change="1578348332" last-run="1578348332" exec-time="24" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++            <lrm_rsc_op id="rsc2_monitor_10000" operation_key="rsc2_monitor_10000" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="9:4:0:398bf005-bb15-4098-9a72-d8373456b457" transition-magic="0:0;9:4:0:398bf005-bb15-4098-9a72-d8373456b457" exit-reason="" on_node="node2" call-id="21" rc-code="0" op-status="0" interval="10000" last-rc-change="1578348257" exec-time="21" queue-time="0" op-digest="4811cef7f7f94e3a35a70be7916cb2fd" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++          <lrm_resource id="Fencing" type="fence_xvm" class="stonith">
++            <lrm_rsc_op id="Fencing_last_0" operation_key="Fencing_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="3:3:7:398bf005-bb15-4098-9a72-d8373456b457" transition-magic="0:7;3:3:7:398bf005-bb15-4098-9a72-d8373456b457" exit-reason="" on_node="node2" call-id="10" rc-code="7" op-status="0" interval="0" last-rc-change="1578348256" last-run="1578348256" exec-time="6" queue-time="0" op-digest="c7e1af5a2f7b98510353dc9f9edfef70"/>
++          </lrm_resource>
++          <lrm_resource id="rsc1" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc1_last_0" operation_key="rsc1_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="4:3:7:398bf005-bb15-4098-9a72-d8373456b457" transition-magic="0:7;4:3:7:398bf005-bb15-4098-9a72-d8373456b457" exit-reason="" on_node="node2" call-id="14" rc-code="7" op-status="0" interval="0" last-rc-change="1578348257" last-run="1578348257" exec-time="38" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++        </lrm_resources>
++      </lrm>
++    </node_state>
++    <node_state id="5" uname="node5" in_ccm="true" crmd="online" crm-debug-origin="post_cache_update" join="member" expected="member">
++      <transient_attributes id="5">
++        <instance_attributes id="status-5"/>
++      </transient_attributes>
++      <lrm id="5">
++        <lrm_resources>
++          <lrm_resource id="Fencing" type="fence_xvm" class="stonith">
++            <lrm_rsc_op id="Fencing_last_0" operation_key="Fencing_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="61:0:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;61:0:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node5" call-id="5" rc-code="7" op-status="0" interval="0" last-rc-change="1578347670" last-run="1578347670" exec-time="7" queue-time="0" op-digest="c7e1af5a2f7b98510353dc9f9edfef70"/>
++          </lrm_resource>
++          <lrm_resource id="rsc1" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc1_last_0" operation_key="rsc1_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="6:59:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;6:59:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node5" call-id="104" rc-code="7" op-status="0" interval="0" last-rc-change="1578347819" last-run="1578347819" exec-time="33" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++          <lrm_resource id="rsc2" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc2_last_0" operation_key="rsc2_stop_0" operation="stop" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="12:62:0:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:0;12:62:0:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node5" call-id="114" rc-code="0" op-status="0" interval="0" last-rc-change="1578347832" last-run="1578347832" exec-time="29" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++        </lrm_resources>
++      </lrm>
++    </node_state>
++    <node_state id="3" uname="node3" in_ccm="true" crmd="online" crm-debug-origin="post_cache_update" join="member" expected="member">
++      <transient_attributes id="3">
++        <instance_attributes id="status-3"/>
++      </transient_attributes>
++      <lrm id="3">
++        <lrm_resources>
++          <lrm_resource id="Fencing" type="fence_xvm" class="stonith">
++            <lrm_rsc_op id="Fencing_last_0" operation_key="Fencing_start_0" operation="start" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="4:68:0:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:0;4:68:0:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node3" call-id="115" rc-code="0" op-status="0" interval="0" last-rc-change="1578347951" last-run="1578347951" exec-time="41" queue-time="0" op-digest="c7e1af5a2f7b98510353dc9f9edfef70"/>
++            <lrm_rsc_op id="Fencing_monitor_120000" operation_key="Fencing_monitor_120000" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="5:68:0:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:0;5:68:0:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node3" call-id="117" rc-code="0" op-status="0" interval="120000" last-rc-change="1578347951" exec-time="32" queue-time="1" op-digest="cb34bc19df153021ce8f301baa293f35"/>
++          </lrm_resource>
++          <lrm_resource id="rsc1" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc1_last_0" operation_key="rsc1_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="4:59:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;4:59:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node3" call-id="105" rc-code="7" op-status="0" interval="0" last-rc-change="1578347819" last-run="1578347819" exec-time="30" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++          <lrm_resource id="rsc2" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc2_last_0" operation_key="rsc2_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="5:60:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;5:60:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node3" call-id="109" rc-code="7" op-status="0" interval="0" last-rc-change="1578347822" last-run="1578347822" exec-time="48" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++        </lrm_resources>
++      </lrm>
++    </node_state>
++    <node_state id="4" uname="node4" in_ccm="true" crmd="online" crm-debug-origin="post_cache_update" join="member" expected="member">
++      <transient_attributes id="4">
++        <instance_attributes id="status-4"/>
++      </transient_attributes>
++      <lrm id="4">
++        <lrm_resources>
++          <lrm_resource id="Fencing" type="fence_xvm" class="stonith">
++            <lrm_rsc_op id="Fencing_last_0" operation_key="Fencing_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="46:0:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;46:0:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node4" call-id="5" rc-code="7" op-status="0" interval="0" last-rc-change="1578347670" last-run="1578347670" exec-time="7" queue-time="0" op-digest="c7e1af5a2f7b98510353dc9f9edfef70"/>
++          </lrm_resource>
++          <lrm_resource id="rsc1" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc1_last_0" operation_key="rsc1_stop_0" operation="stop" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="10:61:0:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:0;10:61:0:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node4" call-id="121" rc-code="0" op-status="0" interval="0" last-rc-change="1578347828" last-run="1578347828" exec-time="25" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++          <lrm_resource id="rsc2" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc2_last_0" operation_key="rsc2_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="6:60:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;6:60:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node4" call-id="119" rc-code="7" op-status="0" interval="0" last-rc-change="1578347822" last-run="1578347822" exec-time="29" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++        </lrm_resources>
++      </lrm>
++    </node_state>
++    <node_state id="1" uname="node1" in_ccm="false" crmd="offline" crm-debug-origin="post_cache_update" join="down" expected="down">
++      <lrm id="1">
++        <lrm_resources>
++          <lrm_resource id="rsc1" type="Dummy" class="ocf" provider="pacemaker" shutdown-lock="1578348439">
++            <lrm_rsc_op id="rsc1_last_0" operation_key="rsc1_stop_0" operation="stop" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="5:7:0:398bf005-bb15-4098-9a72-d8373456b457" transition-magic="0:0;5:7:0:398bf005-bb15-4098-9a72-d8373456b457" exit-reason="" on_node="node1" call-id="25" rc-code="0" op-status="0" interval="0" last-rc-change="1578348439" last-run="1578348439" exec-time="22" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++            <lrm_rsc_op id="rsc1_monitor_10000" operation_key="rsc1_monitor_10000" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="6:2:0:398bf005-bb15-4098-9a72-d8373456b457" transition-magic="0:0;6:2:0:398bf005-bb15-4098-9a72-d8373456b457" exit-reason="" on_node="node1" call-id="21" rc-code="0" op-status="0" interval="10000" last-rc-change="1578348254" exec-time="16" queue-time="0" op-digest="4811cef7f7f94e3a35a70be7916cb2fd" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++          <lrm_resource id="Fencing" type="fence_xvm" class="stonith">
++            <lrm_rsc_op id="Fencing_last_0" operation_key="Fencing_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="2:1:7:398bf005-bb15-4098-9a72-d8373456b457" transition-magic="0:7;2:1:7:398bf005-bb15-4098-9a72-d8373456b457" exit-reason="" on_node="node1" call-id="10" rc-code="7" op-status="0" interval="0" last-rc-change="1578348254" last-run="1578348254" exec-time="4" queue-time="0" op-digest="c7e1af5a2f7b98510353dc9f9edfef70"/>
++          </lrm_resource>
++          <lrm_resource id="rsc2" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc2_last_0" operation_key="rsc2_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="4:1:7:398bf005-bb15-4098-9a72-d8373456b457" transition-magic="0:7;4:1:7:398bf005-bb15-4098-9a72-d8373456b457" exit-reason="" on_node="node1" call-id="18" rc-code="7" op-status="0" interval="0" last-rc-change="1578348254" last-run="1578348254" exec-time="35" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++        </lrm_resources>
++      </lrm>
++    </node_state>
++  </status>
++</cib>
+diff --git a/pengine/test10/shutdown-lock.dot b/pengine/test10/shutdown-lock.dot
+new file mode 100644
+index 0000000..532329d
+--- /dev/null
++++ b/pengine/test10/shutdown-lock.dot
+@@ -0,0 +1,11 @@
++digraph "g" {
++"Fencing_monitor_120000 node3" [ style=bold color="green" fontcolor="black"]
++"Fencing_start_0 node3" -> "Fencing_monitor_120000 node3" [ style = bold]
++"Fencing_start_0 node3" [ style=bold color="green" fontcolor="black"]
++"Fencing_stop_0 node1" -> "Fencing_start_0 node3" [ style = bold]
++"Fencing_stop_0 node1" -> "do_shutdown node1" [ style = bold]
++"Fencing_stop_0 node1" [ style=bold color="green" fontcolor="black"]
++"do_shutdown node1" [ style=bold color="green" fontcolor="black"]
++"rsc1_stop_0 node1" -> "do_shutdown node1" [ style = bold]
++"rsc1_stop_0 node1" [ style=bold color="green" fontcolor="black"]
++}
+diff --git a/pengine/test10/shutdown-lock.exp b/pengine/test10/shutdown-lock.exp
+new file mode 100644
+index 0000000..e8bf9d8
+--- /dev/null
++++ b/pengine/test10/shutdown-lock.exp
+@@ -0,0 +1,64 @@
++<transition_graph cluster-delay="60s" stonith-timeout="60s" failed-stop-offset="INFINITY" failed-start-offset="INFINITY"  transition_id="0">
++  <synapse id="0">
++    <action_set>
++      <rsc_op id="5" operation="monitor" operation_key="Fencing_monitor_120000" on_node="node3" on_node_uuid="3">
++        <primitive id="Fencing" class="stonith" type="fence_xvm"/>
++        <attributes CRM_meta_interval="120000" CRM_meta_name="monitor" CRM_meta_on_node="node3" CRM_meta_on_node_uuid="3" CRM_meta_timeout="120000"  key_file="/etc/pacemaker/fence_xvm.key" multicast_address="239.255.100.100" pcmk_host_list="node1 node2 node3 node4 node5"/>
++      </rsc_op>
++    </action_set>
++    <inputs>
++      <trigger>
++        <rsc_op id="4" operation="start" operation_key="Fencing_start_0" on_node="node3" on_node_uuid="3"/>
++      </trigger>
++    </inputs>
++  </synapse>
++  <synapse id="1">
++    <action_set>
++      <rsc_op id="4" operation="start" operation_key="Fencing_start_0" on_node="node3" on_node_uuid="3">
++        <primitive id="Fencing" class="stonith" type="fence_xvm"/>
++        <attributes CRM_meta_name="start" CRM_meta_on_node="node3" CRM_meta_on_node_uuid="3" CRM_meta_timeout="60000"  key_file="/etc/pacemaker/fence_xvm.key" multicast_address="239.255.100.100" pcmk_host_list="node1 node2 node3 node4 node5"/>
++      </rsc_op>
++    </action_set>
++    <inputs>
++      <trigger>
++        <rsc_op id="3" operation="stop" operation_key="Fencing_stop_0" on_node="node1" on_node_uuid="1"/>
++      </trigger>
++    </inputs>
++  </synapse>
++  <synapse id="2">
++    <action_set>
++      <rsc_op id="3" operation="stop" operation_key="Fencing_stop_0" on_node="node1" on_node_uuid="1">
++        <primitive id="Fencing" class="stonith" type="fence_xvm"/>
++        <attributes CRM_meta_name="stop" CRM_meta_on_node="node1" CRM_meta_on_node_uuid="1" CRM_meta_timeout="60000"  key_file="/etc/pacemaker/fence_xvm.key" multicast_address="239.255.100.100" pcmk_host_list="node1 node2 node3 node4 node5"/>
++      </rsc_op>
++    </action_set>
++    <inputs/>
++  </synapse>
++  <synapse id="3">
++    <action_set>
++      <rsc_op id="6" operation="stop" operation_key="rsc1_stop_0" on_node="node1" on_node_uuid="1" shutdown-lock="1578347951">
++        <primitive id="rsc1" class="ocf" provider="pacemaker" type="Dummy"/>
++        <attributes CRM_meta_name="stop" CRM_meta_on_node="node1" CRM_meta_on_node_uuid="1" CRM_meta_timeout="20000" />
++      </rsc_op>
++    </action_set>
++    <inputs/>
++  </synapse>
++  <synapse id="4">
++    <action_set>
++      <crm_event id="7" operation="do_shutdown" operation_key="do_shutdown-node1" on_node="node1" on_node_uuid="1">
++        <attributes CRM_meta_on_node="node1" CRM_meta_on_node_uuid="1" CRM_meta_op_no_wait="true" />
++        <downed>
++          <node id="1"/>
++        </downed>
++      </crm_event>
++    </action_set>
++    <inputs>
++      <trigger>
++        <rsc_op id="3" operation="stop" operation_key="Fencing_stop_0" on_node="node1" on_node_uuid="1"/>
++      </trigger>
++      <trigger>
++        <rsc_op id="6" operation="stop" operation_key="rsc1_stop_0" on_node="node1" on_node_uuid="1"/>
++      </trigger>
++    </inputs>
++  </synapse>
++</transition_graph>
+diff --git a/pengine/test10/shutdown-lock.scores b/pengine/test10/shutdown-lock.scores
+new file mode 100644
+index 0000000..e09ebfb
+--- /dev/null
++++ b/pengine/test10/shutdown-lock.scores
+@@ -0,0 +1,17 @@
++Allocation scores:
++Using the original execution date of: 2020-01-06 21:59:11Z
++pcmk__native_allocate: Fencing allocation score on node1: 0
++pcmk__native_allocate: Fencing allocation score on node2: 0
++pcmk__native_allocate: Fencing allocation score on node3: 0
++pcmk__native_allocate: Fencing allocation score on node4: 0
++pcmk__native_allocate: Fencing allocation score on node5: 0
++pcmk__native_allocate: rsc1 allocation score on node1: INFINITY
++pcmk__native_allocate: rsc1 allocation score on node2: -INFINITY
++pcmk__native_allocate: rsc1 allocation score on node3: -INFINITY
++pcmk__native_allocate: rsc1 allocation score on node4: -INFINITY
++pcmk__native_allocate: rsc1 allocation score on node5: -INFINITY
++pcmk__native_allocate: rsc2 allocation score on node1: -INFINITY
++pcmk__native_allocate: rsc2 allocation score on node2: INFINITY
++pcmk__native_allocate: rsc2 allocation score on node3: -INFINITY
++pcmk__native_allocate: rsc2 allocation score on node4: -INFINITY
++pcmk__native_allocate: rsc2 allocation score on node5: -INFINITY
+diff --git a/pengine/test10/shutdown-lock.summary b/pengine/test10/shutdown-lock.summary
+new file mode 100644
+index 0000000..6ed56d1
+--- /dev/null
++++ b/pengine/test10/shutdown-lock.summary
+@@ -0,0 +1,31 @@
++Using the original execution date of: 2020-01-06 21:59:11Z
++
++Current cluster status:
++Online: [ node1 node3 node4 node5 ]
++OFFLINE: [ node2 ]
++
++ Fencing	(stonith:fence_xvm):	Started node1
++ rsc1	(ocf::pacemaker:Dummy):	Started node1
++ rsc2	(ocf::pacemaker:Dummy):	Stopped node2 (LOCKED)
++
++Transition Summary:
++ * Shutdown node1
++ * Move       Fencing     ( node1 -> node3 )  
++ * Stop       rsc1        (          node1 )   due to node availability
++
++Executing cluster transition:
++ * Resource action: Fencing         stop on node1
++ * Resource action: rsc1            stop on node1
++ * Cluster action:  do_shutdown on node1
++ * Resource action: Fencing         start on node3
++ * Resource action: Fencing         monitor=120000 on node3
++Using the original execution date of: 2020-01-06 21:59:11Z
++
++Revised cluster status:
++Online: [ node1 node3 node4 node5 ]
++OFFLINE: [ node2 ]
++
++ Fencing	(stonith:fence_xvm):	Started node3
++ rsc1	(ocf::pacemaker:Dummy):	Stopped
++ rsc2	(ocf::pacemaker:Dummy):	Stopped node2 (LOCKED)
++
+diff --git a/pengine/test10/shutdown-lock.xml b/pengine/test10/shutdown-lock.xml
+new file mode 100644
+index 0000000..40b807d
+--- /dev/null
++++ b/pengine/test10/shutdown-lock.xml
+@@ -0,0 +1,185 @@
++<cib crm_feature_set="3.0.14" validate-with="pacemaker-2.10" epoch="154" num_updates="21" admin_epoch="0" cib-last-written="Mon Jan  6 15:58:11 2020" update-origin="node1" update-client="cibadmin" update-user="root" have-quorum="1" dc-uuid="1" execution-date="1578347951">
++  <configuration>
++    <crm_config>
++      <cluster_property_set id="cib-bootstrap-options">
++        <nvpair id="cts-stonith-enabled" name="stonith-enabled" value="1"/>
++        <nvpair id="cib-bootstrap-options-have-watchdog" name="have-watchdog" value="false"/>
++        <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"/>
++        <nvpair id="cib-bootstrap-options-cluster-name" name="cluster-name" value="mycluster"/>
++        <!-- This regression test ensures that resources are properly locked to a node when shutdown-lock
++             is true, both when active on a node that is shutting down (rsc1 on node1), and when
++             inactive on a node already shut down (rsc2 on node2). It also ensures that stonith-class
++             resources are not locked.
++          -->
++        <nvpair id="cib-bootstrap-options-shutdown-lock" name="shutdown-lock" value="true"/>
++      </cluster_property_set>
++    </crm_config>
++    <nodes>
++      <node id="1" uname="node1">
++        <instance_attributes id="nodes-1">
++          <nvpair id="nodes-1-standby" name="standby" value="off"/>
++        </instance_attributes>
++      </node>
++      <node id="2" uname="node2"/>
++      <node id="3" uname="node3">
++        <instance_attributes id="nodes-3">
++          <nvpair id="nodes-3-standby" name="standby" value="off"/>
++        </instance_attributes>
++      </node>
++      <node id="4" uname="node4">
++        <instance_attributes id="nodes-4">
++          <nvpair id="nodes-4-standby" name="standby" value="off"/>
++        </instance_attributes>
++      </node>
++      <node id="5" uname="node5"/>
++    </nodes>
++    <resources>
++      <primitive class="stonith" id="Fencing" type="fence_xvm">
++        <meta_attributes id="Fencing-meta">
++          <nvpair id="Fencing-migration-threshold" name="migration-threshold" value="5"/>
++        </meta_attributes>
++        <instance_attributes id="Fencing-params">
++          <nvpair id="Fencing-key_file" name="key_file" value="/etc/pacemaker/fence_xvm.key"/>
++          <nvpair id="Fencing-multicast_address" name="multicast_address" value="239.255.100.100"/>
++          <nvpair id="Fencing-pcmk_host_list" name="pcmk_host_list" value="node1 node2 node3 node4 node5"/>
++        </instance_attributes>
++        <operations>
++          <op id="Fencing-monitor-120s" interval="120s" name="monitor" timeout="120s"/>
++          <op id="Fencing-stop-0" interval="0" name="stop" timeout="60s"/>
++          <op id="Fencing-start-0" interval="0" name="start" timeout="60s"/>
++        </operations>
++      </primitive>
++      <primitive class="ocf" id="rsc1" provider="pacemaker" type="Dummy">
++        <operations>
++          <op id="rsc1-migrate_from-interval-0s" interval="0s" name="migrate_from" timeout="20s"/>
++          <op id="rsc1-migrate_to-interval-0s" interval="0s" name="migrate_to" timeout="20s"/>
++          <op id="rsc1-monitor-interval-10s" interval="10s" name="monitor" timeout="20s"/>
++          <op id="rsc1-reload-interval-0s" interval="0s" name="reload" timeout="20s"/>
++          <op id="rsc1-start-interval-0s" interval="0s" name="start" timeout="20s"/>
++          <op id="rsc1-stop-interval-0s" interval="0s" name="stop" timeout="20s"/>
++        </operations>
++      </primitive>
++      <primitive class="ocf" id="rsc2" provider="pacemaker" type="Dummy">
++        <operations>
++          <op id="rsc2-migrate_from-interval-0s" interval="0s" name="migrate_from" timeout="20s"/>
++          <op id="rsc2-migrate_to-interval-0s" interval="0s" name="migrate_to" timeout="20s"/>
++          <op id="rsc2-monitor-interval-10s" interval="10s" name="monitor" timeout="20s"/>
++          <op id="rsc2-reload-interval-0s" interval="0s" name="reload" timeout="20s"/>
++          <op id="rsc2-start-interval-0s" interval="0s" name="start" timeout="20s"/>
++          <op id="rsc2-stop-interval-0s" interval="0s" name="stop" timeout="20s"/>
++        </operations>
++      </primitive>
++    </resources>
++    <constraints>
++      <rsc_location id="location-rsc1-node1-INFINITY" node="node1" rsc="rsc1" score="INFINITY"/>
++      <rsc_location id="location-rsc2-node2-INFINITY" node="node2" rsc="rsc2" score="INFINITY"/>
++    </constraints>
++    <op_defaults>
++      <meta_attributes id="cts-op_defaults-meta">
++        <nvpair id="cts-op_defaults-timeout" name="timeout" value="90s"/>
++      </meta_attributes>
++    </op_defaults>
++    <alerts>
++      <alert id="alert-1" path="/var/lib/pacemaker/notify.sh">
++        <recipient id="alert-1-recipient-1" value="/run/crm/alert.log"/>
++      </alert>
++    </alerts>
++    <rsc_defaults>
++      <meta_attributes id="rsc_defaults-options"/>
++    </rsc_defaults>
++  </configuration>
++  <status>
++    <node_state id="2" uname="node2" in_ccm="false" crmd="offline" crm-debug-origin="post_cache_update" join="down" expected="down">
++      <lrm id="2">
++        <lrm_resources>
++          <lrm_resource id="Fencing" type="fence_xvm" class="stonith">
++            <lrm_rsc_op id="Fencing_last_0" operation_key="Fencing_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="16:0:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;16:0:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node2" call-id="5" rc-code="7" op-status="0" interval="0" last-rc-change="1578347670" last-run="1578347670" exec-time="6" queue-time="0" op-digest="c7e1af5a2f7b98510353dc9f9edfef70"/>
++          </lrm_resource>
++          <lrm_resource id="rsc1" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc1_last_0" operation_key="rsc1_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="3:59:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;3:59:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node2" call-id="141" rc-code="7" op-status="0" interval="0" last-rc-change="1578347819" last-run="1578347819" exec-time="44" queue-time="1" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++          <lrm_resource id="rsc2" type="Dummy" class="ocf" provider="pacemaker" shutdown-lock="1578347927">
++            <lrm_rsc_op id="rsc2_last_0" operation_key="rsc2_stop_0" operation="stop" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="8:67:0:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:0;8:67:0:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node2" call-id="155" rc-code="0" op-status="0" interval="0" last-rc-change="1578347927" last-run="1578347927" exec-time="28" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++            <lrm_rsc_op id="rsc2_monitor_10000" operation_key="rsc2_monitor_10000" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="14:62:0:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:0;14:62:0:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node2" call-id="148" rc-code="0" op-status="0" interval="10000" last-rc-change="1578347832" exec-time="18" queue-time="0" op-digest="4811cef7f7f94e3a35a70be7916cb2fd" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++        </lrm_resources>
++      </lrm>
++    </node_state>
++    <node_state id="5" uname="node5" in_ccm="true" crmd="online" crm-debug-origin="post_cache_update" join="member" expected="member">
++      <transient_attributes id="5">
++        <instance_attributes id="status-5"/>
++      </transient_attributes>
++      <lrm id="5">
++        <lrm_resources>
++          <lrm_resource id="Fencing" type="fence_xvm" class="stonith">
++            <lrm_rsc_op id="Fencing_last_0" operation_key="Fencing_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="61:0:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;61:0:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node5" call-id="5" rc-code="7" op-status="0" interval="0" last-rc-change="1578347670" last-run="1578347670" exec-time="7" queue-time="0" op-digest="c7e1af5a2f7b98510353dc9f9edfef70"/>
++          </lrm_resource>
++          <lrm_resource id="rsc1" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc1_last_0" operation_key="rsc1_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="6:59:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;6:59:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node5" call-id="104" rc-code="7" op-status="0" interval="0" last-rc-change="1578347819" last-run="1578347819" exec-time="33" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++          <lrm_resource id="rsc2" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc2_last_0" operation_key="rsc2_stop_0" operation="stop" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="12:62:0:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:0;12:62:0:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node5" call-id="114" rc-code="0" op-status="0" interval="0" last-rc-change="1578347832" last-run="1578347832" exec-time="29" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++        </lrm_resources>
++      </lrm>
++    </node_state>
++    <node_state id="3" uname="node3" in_ccm="true" crmd="online" crm-debug-origin="post_cache_update" join="member" expected="member">
++      <transient_attributes id="3">
++        <instance_attributes id="status-3"/>
++      </transient_attributes>
++      <lrm id="3">
++        <lrm_resources>
++          <lrm_resource id="Fencing" type="fence_xvm" class="stonith">
++            <lrm_rsc_op id="Fencing_last_0" operation_key="Fencing_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="31:0:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;31:0:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node3" call-id="5" rc-code="7" op-status="0" interval="0" last-rc-change="1578347670" last-run="1578347670" exec-time="4" queue-time="0" op-digest="c7e1af5a2f7b98510353dc9f9edfef70"/>
++          </lrm_resource>
++          <lrm_resource id="rsc1" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc1_last_0" operation_key="rsc1_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="4:59:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;4:59:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node3" call-id="105" rc-code="7" op-status="0" interval="0" last-rc-change="1578347819" last-run="1578347819" exec-time="30" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++          <lrm_resource id="rsc2" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc2_last_0" operation_key="rsc2_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="5:60:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;5:60:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node3" call-id="109" rc-code="7" op-status="0" interval="0" last-rc-change="1578347822" last-run="1578347822" exec-time="48" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++        </lrm_resources>
++      </lrm>
++    </node_state>
++    <node_state id="4" uname="node4" in_ccm="true" crmd="online" crm-debug-origin="post_cache_update" join="member" expected="member">
++      <transient_attributes id="4">
++        <instance_attributes id="status-4"/>
++      </transient_attributes>
++      <lrm id="4">
++        <lrm_resources>
++          <lrm_resource id="Fencing" type="fence_xvm" class="stonith">
++            <lrm_rsc_op id="Fencing_last_0" operation_key="Fencing_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="46:0:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;46:0:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node4" call-id="5" rc-code="7" op-status="0" interval="0" last-rc-change="1578347670" last-run="1578347670" exec-time="7" queue-time="0" op-digest="c7e1af5a2f7b98510353dc9f9edfef70"/>
++          </lrm_resource>
++          <lrm_resource id="rsc1" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc1_last_0" operation_key="rsc1_stop_0" operation="stop" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="10:61:0:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:0;10:61:0:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node4" call-id="121" rc-code="0" op-status="0" interval="0" last-rc-change="1578347828" last-run="1578347828" exec-time="25" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++          <lrm_resource id="rsc2" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc2_last_0" operation_key="rsc2_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="6:60:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;6:60:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node4" call-id="119" rc-code="7" op-status="0" interval="0" last-rc-change="1578347822" last-run="1578347822" exec-time="29" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++        </lrm_resources>
++      </lrm>
++    </node_state>
++    <node_state id="1" uname="node1" in_ccm="true" crmd="online" crm-debug-origin="post_cache_update" join="member" expected="member">
++      <transient_attributes id="1">
++        <instance_attributes id="status-1">
++          <nvpair id="status-1-shutdown" name="shutdown" value="1578347951"/>
++        </instance_attributes>
++      </transient_attributes>
++      <lrm id="1">
++        <lrm_resources>
++          <lrm_resource id="Fencing" type="fence_xvm" class="stonith">
++            <lrm_rsc_op id="Fencing_last_0" operation_key="Fencing_start_0" operation="start" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="76:0:0:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:0;76:0:0:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node1" call-id="10" rc-code="0" op-status="0" interval="0" last-rc-change="1578347670" last-run="1578347670" exec-time="121" queue-time="0" op-digest="c7e1af5a2f7b98510353dc9f9edfef70"/>
++            <lrm_rsc_op id="Fencing_monitor_120000" operation_key="Fencing_monitor_120000" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="77:0:0:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:0;77:0:0:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node1" call-id="12" rc-code="0" op-status="0" interval="120000" last-rc-change="1578347670" exec-time="92" queue-time="0" op-digest="cb34bc19df153021ce8f301baa293f35"/>
++          </lrm_resource>
++          <lrm_resource id="rsc1" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc1_last_0" operation_key="rsc1_start_0" operation="start" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="11:61:0:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:0;11:61:0:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node1" call-id="112" rc-code="0" op-status="0" interval="0" last-rc-change="1578347828" last-run="1578347828" exec-time="22" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++            <lrm_rsc_op id="rsc1_monitor_10000" operation_key="rsc1_monitor_10000" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="12:61:0:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:0;12:61:0:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node1" call-id="114" rc-code="0" op-status="0" interval="10000" last-rc-change="1578347828" exec-time="21" queue-time="0" op-digest="4811cef7f7f94e3a35a70be7916cb2fd" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++          <lrm_resource id="rsc2" type="Dummy" class="ocf" provider="pacemaker">
++            <lrm_rsc_op id="rsc2_last_0" operation_key="rsc2_monitor_0" operation="monitor" crm-debug-origin="build_active_RAs" crm_feature_set="3.3.0" transition-key="3:60:7:4502288b-71ea-43d2-a481-d2c360266103" transition-magic="0:7;3:60:7:4502288b-71ea-43d2-a481-d2c360266103" exit-reason="" on_node="node1" call-id="111" rc-code="7" op-status="0" interval="0" last-rc-change="1578347822" last-run="1578347822" exec-time="47" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-force-restart=" envfile  op_sleep  passwd  state " op-restart-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8" op-secure-params=" passwd " op-secure-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
++          </lrm_resource>
++        </lrm_resources>
++      </lrm>
++    </node_state>
++  </status>
++</cib>
+-- 
+1.8.3.1
+
diff --git a/SPECS/pacemaker.spec b/SPECS/pacemaker.spec
index 1bd6ace..bb2a1c5 100644
--- a/SPECS/pacemaker.spec
+++ b/SPECS/pacemaker.spec
@@ -5,7 +5,11 @@
 %global gname haclient
 
 ## Where to install Pacemaker documentation
+%if 0%{?suse_version} > 0
+%global pcmk_docdir %{_docdir}/%{name}-%{version}
+%else
 %global pcmk_docdir %{_docdir}/%{name}
+%endif
 
 ## GitHub entity that distributes source (for ease of using a fork)
 %global github_owner ClusterLabs
@@ -13,12 +17,12 @@
 ## Upstream pacemaker version, and its package version (specversion
 ## can be incremented to build packages reliably considered "newer"
 ## than previously built packages with the same pcmkversion)
-%global pcmkversion 1.1.21
-%global specversion 2
+%global pcmkversion 1.1.22
+%global specversion 1
 
 ## Upstream commit (or git tag, such as "Pacemaker-" plus the
 ## {pcmkversion} macro for an official release) to use for this package
-%global commit f14e36fd4336874705b34266c7cddbe12119106c
+%global commit 63d2d79005005f42bd1538f7b8fd211aca225073
 ## Since git v2.11, the extent of abbreviation is autoscaled by default
 ## (used to be constant of 7), so we need to convey it for non-tags, too.
 %global commit_abbrev 7
@@ -80,6 +84,43 @@
   } || %{?__transaction_systemd_inhibit:1}%{!?__transaction_systemd_inhibit:0}%{nil \
   } || %(test -f /usr/lib/os-release; test $? -ne 0; echo $?))
 
+%if 0%{?fedora} > 20 || 0%{?rhel} > 7
+%global gnutls_priorities @SYSTEM
+%endif
+
+%if !%{defined _rundir}
+%if 0%{?fedora} >= 15 || 0%{?rhel} >= 7 || 0%{?suse_version} >= 1200
+%define _rundir /run
+%else
+%define _rundir /var/run
+%endif
+%endif
+
+## Different distros name certain packages differently
+## (note: corosync libraries also differ, but all provide corosync-devel)
+%if 0%{?suse_version} > 0
+%global pkgname_bzip2_devel libbz2-devel
+%global pkgname_docbook_xsl docbook-xsl-stylesheets
+%global pkgname_gnutls_devel libgnutls-devel
+%global pkgname_shadow_utils shadow
+%global pkgname_procps procps
+%global pkgname_glue_libs libglue
+%global pkgname_pcmk_libs lib%{name}3
+%global hacluster_id 90
+%else
+%global pkgname_libtool_devel libtool-ltdl-devel
+%global pkgname_libtool_devel_arch libtool-ltdl-devel%{?_isa}
+%global pkgname_bzip2_devel bzip2-devel
+%global pkgname_docbook_xsl docbook-style-xsl
+%global pkgname_gnutls_devel gnutls-devel
+%global pkgname_shadow_utils shadow-utils
+%global pkgname_procps procps-ng
+%global pkgname_publican publican
+%global pkgname_glue_libs cluster-glue-libs
+%global pkgname_pcmk_libs %{name}-libs
+%global hacluster_id 189
+%endif
+
 # RHEL: harden the default GnuTLS cipher list
 %global gnutls_priorities NORMAL:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1:-MD5:-3DES-CBC:-ARCFOUR-128:-ARCFOUR-40
 
@@ -179,17 +220,28 @@ Source0:       https://github.com/%{github_owner}/%{name}/archive/%{commit}/%{na
 Source1:       nagios-agents-metadata-%{nagios_hash}.tar.gz
 
 # upstream commits
-Patch1:        01-rollup.patch
+#Patch1:        01-rollup.patch
 
 # patches that aren't from upstream
 Patch100:      lrmd-protocol-version.patch
 Patch101:      2.0-record-pending-behavior.patch
 Patch102:      2.0-cleanup-behavior.patch
+Patch103:      shutdown-lock-01.patch
+Patch104:      shutdown-lock-02.patch
+Patch105:      shutdown-lock-03.patch
+Patch106:      shutdown-lock-04.patch
+Patch107:      shutdown-lock-05.patch
+Patch108:      shutdown-lock-06.patch
+Patch109:      shutdown-lock-07.patch
+Patch110:      shutdown-lock-08.patch
+Patch111:      shutdown-lock-09.patch
+Patch112:      shutdown-lock-10.patch
+Patch113:      shutdown-lock-11.patch
 
 BuildRoot:     %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
 AutoReqProv:   on
 Requires:      resource-agents
-Requires:      %{name}-libs%{?_isa} = %{version}-%{release}
+Requires:      %{pkgname_pcmk_libs}%{?_isa} = %{version}-%{release}
 Requires:      %{name}-cluster-libs%{?_isa} = %{version}-%{release}
 Requires:      %{name}-cli = %{version}-%{release}
 Obsoletes:     rgmanager < 3.2.0
@@ -212,11 +264,11 @@ BuildRequires: libqb-devel > 0.17.0
 BuildRequires: coreutils findutils grep sed
 
 # Required for core functionality
-BuildRequires: automake autoconf libtool pkgconfig libtool-ltdl-devel
+BuildRequires: automake autoconf gcc libtool pkgconfig %{?pkgname_libtool_devel}
 ## version lower bound for: G_GNUC_INTERNAL
 BuildRequires: pkgconfig(glib-2.0) >= 2.6
 BuildRequires: libxml2-devel libxslt-devel libuuid-devel
-BuildRequires: bzip2-devel pam-devel
+BuildRequires: %{pkgname_bzip2_devel}
 
 # Required for agent_config.h which specifies the correct scratch directory
 BuildRequires: resource-agents
@@ -225,8 +277,8 @@ BuildRequires: resource-agents
 BuildRequires: git
 
 # Enables optional functionality
-BuildRequires: ncurses-devel docbook-style-xsl
-BuildRequires: bison byacc flex help2man gnutls-devel pkgconfig(dbus-1)
+BuildRequires: ncurses-devel %{pkgname_docbook_xsl}
+BuildRequires: bison byacc flex help2man %{pkgname_gnutls_devel} pam-devel pkgconfig(dbus-1)
 
 %if %{systemd_native}
 BuildRequires: pkgconfig(systemd)
@@ -240,16 +292,16 @@ Requires:      cman
 %endif
 
 Requires:      corosync
-BuildRequires: corosynclib-devel
+BuildRequires: corosync-devel
 
 %if %{with stonithd}
-BuildRequires: cluster-glue-libs-devel
+BuildRequires: %{pkgname_glue_libs}-devel
 %endif
 
 ## (note no avoiding effect when building through non-customized mock)
 %if !%{bleeding}
 %if %{with doc}
-BuildRequires: inkscape asciidoc publican
+BuildRequires: inkscape asciidoc %{?pkgname_publican}
 %endif
 %endif
 
@@ -271,7 +323,7 @@ Available rpmbuild rebuild options:
 License:       GPLv2+ and LGPLv2+
 Summary:       Command line tools for controlling Pacemaker clusters
 Group:         System Environment/Daemons
-Requires:      %{name}-libs%{?_isa} = %{version}-%{release}
+Requires:      %{pkgname_pcmk_libs}%{?_isa} = %{version}-%{release}
 Requires:      perl-TimeDate
 
 %description cli
@@ -282,26 +334,26 @@ The %{name}-cli package contains command line tools that can be used
 to query and control the cluster from machines that may, or may not,
 be part of the cluster.
 
-%package -n %{name}-libs
+%package -n %{pkgname_pcmk_libs}
 License:       GPLv2+ and LGPLv2+
 Summary:       Core Pacemaker libraries
 Group:         System Environment/Daemons
-Requires(pre): shadow-utils
+Requires(pre): %{pkgname_shadow_utils}
 # sbd 1.4.0+ supports the libpe_status API for pe_working_set_t
 Conflicts:     sbd < 1.4.0
 
-%description -n %{name}-libs
+%description -n %{pkgname_pcmk_libs}
 Pacemaker is an advanced, scalable High-Availability cluster resource
 manager for Corosync, CMAN and/or Linux-HA.
 
-The %{name}-libs package contains shared libraries needed for cluster
+The %{pkgname_pcmk_libs} package contains shared libraries needed for cluster
 nodes and those just running the CLI tools.
 
 %package -n %{name}-cluster-libs
 License:       GPLv2+ and LGPLv2+
 Summary:       Cluster Libraries used by Pacemaker
 Group:         System Environment/Daemons
-Requires:      %{name}-libs%{?_isa} = %{version}-%{release}
+Requires:      %{pkgname_pcmk_libs}%{?_isa} = %{version}-%{release}
 
 %description -n %{name}-cluster-libs
 Pacemaker is an advanced, scalable High-Availability cluster resource
@@ -319,7 +371,7 @@ License:       GPLv2+ and LGPLv2+ and BSD
 %endif
 Summary:       Pacemaker remote daemon for non-cluster nodes
 Group:         System Environment/Daemons
-Requires:      %{name}-libs%{?_isa} = %{version}-%{release}
+Requires:      %{pkgname_pcmk_libs}%{?_isa} = %{version}-%{release}
 Requires:      %{name}-cli = %{version}-%{release}
 Requires:      resource-agents
 Provides:      pcmk-cluster-manager
@@ -335,22 +387,24 @@ The %{name}-remote package contains the Pacemaker Remote daemon
 which is capable of extending pacemaker functionality to remote
 nodes not running the full corosync/cluster stack.
 
-%package -n %{name}-libs-devel
+%package -n %{pkgname_pcmk_libs}-devel
 License:       GPLv2+ and LGPLv2+
 Summary:       Pacemaker development package
 Group:         Development/Libraries
 Requires:      %{name}-cts = %{version}-%{release}
-Requires:      %{name}-libs = %{version}-%{release}
-Requires:      %{name}-cluster-libs = %{version}-%{release}
-Requires:      libtool-ltdl-devel libqb-devel libuuid-devel
-Requires:      libxml2-devel libxslt-devel bzip2-devel glib2-devel
-Requires:      corosynclib-devel
+Requires:      %{pkgname_pcmk_libs}%{?_isa} = %{version}-%{release}
+Requires:      %{name}-cluster-libs%{?_isa} = %{version}-%{release}
+Requires:      libuuid-devel%{?_isa} %{?pkgname_libtool_devel_arch}
+Requires:      libxml2-devel%{?_isa} libxslt-devel%{?_isa}
+Requires:      %{pkgname_bzip2_devel}%{?_isa} glib2-devel%{?_isa}
+Requires:      libqb-devel%{?_isa}
+Requires:      corosync-devel
 
-%description -n %{name}-libs-devel
+%description -n %{pkgname_pcmk_libs}-devel
 Pacemaker is an advanced, scalable High-Availability cluster resource
 manager for Corosync, CMAN and/or Linux-HA.
 
-The %{name}-libs-devel package contains headers and shared libraries
+The %{pkgname_pcmk_libs}-devel package contains headers and shared libraries
 for developing tools for Pacemaker.
 
 # NOTE: can be noarch if lrmd_test is moved to another subpackage
@@ -359,7 +413,7 @@ License:       GPLv2+ and LGPLv2+
 Summary:       Test framework for cluster-related technologies like Pacemaker
 Group:         System Environment/Daemons
 Requires:      python >= 2.6
-Requires:      %{name}-libs = %{version}-%{release}
+Requires:      %{pkgname_pcmk_libs} = %{version}-%{release}
 
 # systemd python bindings are separate package in some distros
 %if %{defined systemd_requires}
@@ -427,7 +481,7 @@ find . -exec touch \{\} \;
 # Early versions of autotools (e.g. RHEL <= 5) do not support --docdir
 export docdir=%{pcmk_docdir}
 
-export systemdunitdir=%{?_unitdir}%{!?_unitdir:no}
+export systemdsystemunitdir=%{?_unitdir}%{!?_unitdir:no}
 
 # RHEL: enable notification-agent/notification-recipient,
 # and change concurrent-fencing default to true
@@ -458,6 +512,7 @@ export LDFLAGS_HARDENED_LIB="%{?_hardening_ldflags}"
         %{!?with_hardening:  --disable-hardening}  \
         %{?gnutls_priorities: --with-gnutls-priorities="%{gnutls_priorities}"} \
         --with-initdir=%{_initrddir}               \
+        --with-runstatedir=%{_rundir}                                           \
         --localstatedir=%{_var}                    \
         --with-bug-url=https://bugzilla.redhat.com/                               \
         --with-nagios                                                             \
@@ -647,15 +702,14 @@ fi
 %systemd_postun_with_restart crm_mon.service
 %endif
 
-%pre -n %{name}-libs
-
-getent group %{gname} >/dev/null || groupadd -r %{gname} -g 189
-getent passwd %{uname} >/dev/null || useradd -r -g %{gname} -u 189 -s /sbin/nologin -c "cluster user" %{uname}
+%pre -n %{pkgname_pcmk_libs}
+getent group %{gname} >/dev/null || groupadd -r %{gname} -g %{hacluster_id}
+getent passwd %{uname} >/dev/null || useradd -r -g %{gname} -u %{hacluster_id} -s /sbin/nologin -c "cluster user" %{uname}
 exit 0
 
-%post -n %{name}-libs -p /sbin/ldconfig
+%post -n %{pkgname_pcmk_libs} -p /sbin/ldconfig
 
-%postun -n %{name}-libs -p /sbin/ldconfig
+%postun -n %{pkgname_pcmk_libs} -p /sbin/ldconfig
 
 %post -n %{name}-cluster-libs -p /sbin/ldconfig
 
@@ -792,7 +846,7 @@ exit 0
 %dir %attr (750, %{uname}, %{gname}) %{_var}/lib/pacemaker/blackbox
 %dir %attr (750, %{uname}, %{gname}) %{_var}/lib/pacemaker/cores
 
-%files -n %{name}-libs
+%files -n %{pkgname_pcmk_libs}
 %defattr(-,root,root)
 
 %{_libdir}/libcib.so.*
@@ -849,7 +903,7 @@ exit 0
 %doc COPYING
 %doc ChangeLog
 
-%files -n %{name}-libs-devel
+%files -n %{pkgname_pcmk_libs}-devel
 %defattr(-,root,root)
 %exclude %{_datadir}/pacemaker/tests/cts
 %{_datadir}/pacemaker/tests
@@ -869,6 +923,28 @@ exit 0
 %attr(0644,root,root) %{_datadir}/pacemaker/nagios/plugins-metadata/*
 
 %changelog
+* Mon Mar 30 2020 Ken Gaillot <kgaillot@redhat.com> - 1.1.22-1
+- Show correct disabled resource count in status display
+- Run-time option for Pacemaker Remote bind address
+- Avoid restart loop when migration is left dangling
+- Improve help for clean-up option
+- Do not overweight group colocation scores
+- Rebase on upstream 1.1.22+63d2d79
+- Resolves: rhbz#1458953
+- Resolves: rhbz#1743373
+- Resolves: rhbz#1757951
+- Resolves: rhbz#1758969
+- Resolves: rhbz#1760669
+- Resolves: rhbz#1792492
+
+* Thu Jan 16 2020 Ken Gaillot <kgaillot@redhat.com> - 1.1.21-4
+- Implement shutdown-lock feature
+- Resolves: rhbz#1781820
+
+* Thu Nov 7 2019 Ken Gaillot <kgaillot@redhat.com> - 1.1.21-3
+- Avoid invalid transition when guest node's host is unclean but can't be fenced
+- Resolves: rhbz#1755659
+
 * Tue Aug 27 2019 Ken Gaillot <kgaillot@redhat.com> - 1.1.21-2
 - Add latest upstream bug fixes to rebase roll-up patch
 - Resolves: rhbz#1731189