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?= -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 -+#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_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 -+""; -+#else -+""\ -+" "\ -+" "\ -+" "\ -+" "\ -+" "\ -+" "\ -+" "\ -+""; -+#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 /* size_t */ -+#include /* bool */ -+ -+#include /* 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?= -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 /* 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), -+"\n" -+" \n" -+" \n" -+" \n" -+" \n" -+" \n" -+" \n" -+" \n" -+" \n" -+" \n" -+" \n" -+" \n" -+" \n" -+"\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?= -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?= -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?= -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; - ]> - -- -- -- -- -- -+ -+ -+ -+ -+ -+ - - -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 @@ - - - -+ -+ 1-2 -+ Fri 17 May 2019 -+ -+ JanPokorný -+ poki@redhat.com -+ -+ -+ Start capturing hacking howto -+ for advanced contributors -+ -+ -+ - - - --- -1.8.3.1 - - -From 96244e2c9bb4f32dc38bd4fa1c091c9f0d5bbf57 Mon Sep 17 00:00:00 2001 -From: "Gao,Yan" -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: -``` - - - - - - - -``` - -, if we'd like to change it to: -``` - - - - - - - -``` - -, the generated XML diff would be like: -``` - - - - - - -``` - -Previously after applying the XML diff, the resulting XML would be a mess: -``` - - - - - - - -``` -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" -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" -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 -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 -+ * 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 -@@ -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" -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: ... */ - #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 -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 -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 -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 -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 -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 -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 @@ - - - -- -- -- -- -- -- - - - -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 @@ - - - -- -- -- -- -- -+ - - - -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 @@ - - - -- -- -- - - - -@@ -64,9 +61,6 @@ - - - -- -- -- - - - -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 @@ - - - -- -- -- - - - -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 @@ - - - -- -- -- - - - -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -+ * 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 -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 -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 -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 @@ - - - -+ - - - -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 @@ - - - -+ - - - -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 @@ - - - -+ - - - -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 @@ - - - -+ - - - -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 @@ - - - -+ - - - -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 @@ - - - -+ - - - -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 @@ - - - -+ - - - -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 @@ - - - -+ - - - -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 @@ - - - -+ - - - --- -1.8.3.1 - - -From 7c3bc762a9cede20a0193f64ca1a36f507aeeeb3 Mon Sep 17 00:00:00 2001 -From: Ken Gaillot -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 -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 -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 -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" -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" -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 @@ - - - -- -+ -+ -+ -+ -+ - - -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 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ -+ - - - -@@ -339,6 +348,18 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - - - -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 @@ - - - -+ -+ -+ - - - -@@ -246,6 +249,12 @@ - - - -+ -+ -+ -+ -+ -+ - - - -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 @@ - - - -+ -+ -+ - - - -@@ -202,6 +205,12 @@ - - - -+ -+ -+ -+ -+ -+ - - - -@@ -367,6 +376,9 @@ - - - -+ -+ -+ - - - -@@ -417,6 +429,12 @@ - - - -+ -+ -+ -+ -+ -+ - - - -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 @@ - - - -+ -+ -+ - - - -@@ -169,6 +172,12 @@ - - - -+ -+ -+ -+ -+ -+ - - - -@@ -340,6 +349,9 @@ - - - -+ -+ -+ - - - -@@ -381,6 +393,12 @@ - - - -+ -+ -+ -+ -+ -+ - - - -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 @@ - - - -- -+ -+ -+ -+ -+ - - - -@@ -117,7 +121,11 @@ - - - -- -+ -+ -+ -+ -+ - - - -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 @@ - - - -+ -+ -+ - - - --- -1.8.3.1 - - -From 95791c21987c82dd5c821569a7f029e876f9bed1 Mon Sep 17 00:00:00 2001 -From: Ken Gaillot -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 -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 -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 -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 --# include --#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 : "", 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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -+ * 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 -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) : "") -+ - 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 -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 scaffolding with id="" 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 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=): 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 with id="cib-bootstrap-options-stonith-enabled" - =#=#=#= Current cib after: niceguy: Set stonith-enabled =#=#=#= - - -@@ -377,7 +378,7 @@ Error setting enable-acl=false (section=crm_config, set=): 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 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 scaffolding with id="dummy-meta_attributes" is implicitly allowed -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of 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 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 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 with id="observer-read-1" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="observer-write-1" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="observer-write-2" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="admin-read-1" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="admin-write-1" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="l33t-haxor" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="auto-l33t-haxor" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="auto-l33t-haxor" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="crook-nothing" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="niceguy" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="observer" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="bob" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="admin" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="badidea" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="auto-badidea" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="auto-badidea" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="badidea-resources" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="betteridea" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="auto-betteridea" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="auto-betteridea" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="betteridea-nothing" -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of with id="betteridea-resources" - =#=#=#= Current cib after: root: Upgrade to pacemaker-2.0 =#=#=#= - - -@@ -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 scaffolding with id="" 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 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=): 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 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 scaffolding with id="dummy-meta_attributes" is implicitly allowed -+( acl.c:NNN ) trace: pcmk__post_process_acl: ACLs allow creation of 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 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 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 -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) : "") - -+/*! -+ * \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 -+ * 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 -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 -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 -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 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -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 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -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 =#=#=#= - -@@ -3174,3 +3174,66 @@ Migration will take effect until: - - =#=#=#= End test: Remove expired constraints - OK (0) =#=#=#= - * Passed: crm_resource - Remove expired constraints -+=#=#=#= Begin test: Create an XML patchset =#=#=#= -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+=#=#=#= 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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -+ * 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 -- * -- * 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 -@@ -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 -+ * 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 -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 -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 -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 -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 -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?= -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?= -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/.*.*//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?= -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/.*.*//g' $@ # Remove dangling tag -- $(AM_V_at)sed -i 's/.*preface>//g' $@ # Remove preface elements -- $(AM_V_at)sed -i 's:::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 "//' $@ # We just want the appendix tag -- -grep -vqis "/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/.*.*//g' $@-t # Remove dangling tag -+ $(AM_V_at)sed -i 's/.*preface>//g' $@-t # Remove preface elements -+ $(AM_V_at)sed -i 's:::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 "//;tb;bf;:b;N;s/.*.*<\/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>::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 "//;tb;bf;:b;N;s/.*.*<\/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>::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 "//;tb;bf;:b;N;s/.*.*<\/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