From b65744112241762f41d5b364f7e32d317a4a2d07 Mon Sep 17 00:00:00 2001 From: Klaus Wenninger Date: Mon, 8 Nov 2021 21:40:35 +0100 Subject: [PATCH] * Mon Nov 8 2021 Klaus Wenninger - 2.1.2-0.1.rc1 - Update for new upstream tarball for release candidate: Pacemaker-2.1.2-rc1, for full details, see included ChangeLog file or https://github.com/ClusterLabs/pacemaker/releases/tag/Pacemaker-2.1.2-rc1 --- ...-fencing-allow-restriction-to-certai.patch | 1119 ----------------- ...cing-Silence-warning-without-node-re.patch | 25 - ...og-fix-version-output-needed-for-hel.patch | 24 - ...ckage-fence_watchdog-in-base-package.patch | 32 - ...tchdog-fix-malformed-xml-in-metadata.patch | 25 - ...-cts-fencing-Add-a-test-for-metadata.patch | 38 - ...-check-metadata-from-fence_dummy-wat.patch | 45 - ...-fencing-add-a-few-options-for-tests.patch | 121 -- pacemaker.spec | 29 +- sources | 2 +- 10 files changed, 13 insertions(+), 1447 deletions(-) delete mode 100644 0001-feature-watchdog-fencing-allow-restriction-to-certai.patch delete mode 100644 0002-Fix-watchdog-fencing-Silence-warning-without-node-re.patch delete mode 100644 0003-Fix-fence_watchdog-fix-version-output-needed-for-hel.patch delete mode 100644 0004-Build-rpm-package-fence_watchdog-in-base-package.patch delete mode 100644 0005-Fix-fence_watchdog-fix-malformed-xml-in-metadata.patch delete mode 100644 0006-Test-cts-fencing-Add-a-test-for-metadata.patch delete mode 100644 0007-Test-cts-fencing-check-metadata-from-fence_dummy-wat.patch delete mode 100644 0008-Test-cts-fencing-add-a-few-options-for-tests.patch diff --git a/0001-feature-watchdog-fencing-allow-restriction-to-certai.patch b/0001-feature-watchdog-fencing-allow-restriction-to-certai.patch deleted file mode 100644 index 97e6071..0000000 --- a/0001-feature-watchdog-fencing-allow-restriction-to-certai.patch +++ /dev/null @@ -1,1119 +0,0 @@ -From 5dd1e4459335764e0adf5fa78d81c875ae2332e9 Mon Sep 17 00:00:00 2001 -From: Klaus Wenninger -Date: Fri, 30 Jul 2021 18:15:10 +0200 -Subject: [PATCH] feature: watchdog-fencing: allow restriction to certain nodes - -Bump CRM_FEATURE_SET to 3.11.0 to encourage cluster being -fully upgraded to a version that supports the feature -before explicitly adding a watchdog-fence-device. ---- - configure.ac | 1 + - daemons/controld/controld_control.c | 2 +- - daemons/controld/controld_fencing.c | 14 ++ - daemons/controld/controld_fencing.h | 1 + - daemons/fenced/Makefile.am | 2 +- - daemons/fenced/fence_watchdog.in | 283 ++++++++++++++++++++++++++++++++++++ - daemons/fenced/fenced_commands.c | 141 ++++++++++++++---- - daemons/fenced/fenced_remote.c | 71 ++++++--- - daemons/fenced/pacemaker-fenced.c | 131 ++++++++++++----- - daemons/fenced/pacemaker-fenced.h | 5 +- - include/crm/crm.h | 2 +- - include/crm/fencing/internal.h | 8 +- - lib/fencing/st_client.c | 61 ++++++++ - lib/lrmd/lrmd_client.c | 6 +- - rpm/pacemaker.spec.in | 3 + - 16 files changed, 635 insertions(+), 97 deletions(-) - create mode 100755 daemons/fenced/fence_watchdog.in - -diff --git a/configure.ac b/configure.ac -index 436100c..013562e 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1972,6 +1972,7 @@ CONFIG_FILES_EXEC([cts/cts-cli], - [cts/support/fence_dummy], - [cts/support/pacemaker-cts-dummyd], - [daemons/fenced/fence_legacy], -+ [daemons/fenced/fence_watchdog], - [doc/abi-check], - [extra/resources/ClusterMon], - [extra/resources/HealthSMART], -diff --git a/daemons/controld/controld_control.c b/daemons/controld/controld_control.c -index 45a70bb..b5da6a4 100644 ---- a/daemons/controld/controld_control.c -+++ b/daemons/controld/controld_control.c -@@ -615,7 +615,7 @@ static pcmk__cluster_option_t crmd_opts[] = { - }, - { - "stonith-watchdog-timeout", NULL, "time", NULL, -- "0", pcmk__valid_sbd_timeout, -+ "0", controld_verify_stonith_watchdog_timeout, - "How long to wait before we can assume nodes are safely down " - "when watchdog-based self-fencing via SBD is in use", - "If nonzero, along with `have-watchdog=true` automatically set by the " -diff --git a/daemons/controld/controld_fencing.c b/daemons/controld/controld_fencing.c -index 0fba661..6c2a6c5 100644 ---- a/daemons/controld/controld_fencing.c -+++ b/daemons/controld/controld_fencing.c -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - #include - - #include -@@ -886,6 +887,19 @@ te_fence_node(crm_graph_t *graph, crm_action_t *action) - return TRUE; - } - -+bool -+controld_verify_stonith_watchdog_timeout(const char *value) -+{ -+ gboolean rv = TRUE; -+ -+ if (stonith_api && (stonith_api->state != stonith_disconnected) && -+ stonith__watchdog_fencing_enabled_for_node_api(stonith_api, -+ fsa_our_uname)) { -+ rv = pcmk__valid_sbd_timeout(value); -+ } -+ return rv; -+} -+ - /* end stonith API client functions */ - - -diff --git a/daemons/controld/controld_fencing.h b/daemons/controld/controld_fencing.h -index d0ecc82..ef68a0c 100644 ---- a/daemons/controld/controld_fencing.h -+++ b/daemons/controld/controld_fencing.h -@@ -24,6 +24,7 @@ void update_stonith_max_attempts(const char* value); - void controld_trigger_fencer_connect(void); - void controld_disconnect_fencer(bool destroy); - gboolean te_fence_node(crm_graph_t *graph, crm_action_t *action); -+bool controld_verify_stonith_watchdog_timeout(const char *value); - - // stonith cleanup list - void add_stonith_cleanup(const char *target); -diff --git a/daemons/fenced/Makefile.am b/daemons/fenced/Makefile.am -index 43413e1..2923d7c 100644 ---- a/daemons/fenced/Makefile.am -+++ b/daemons/fenced/Makefile.am -@@ -15,7 +15,7 @@ halibdir = $(CRM_DAEMON_DIR) - - halib_PROGRAMS = pacemaker-fenced cts-fence-helper - --sbin_SCRIPTS = fence_legacy -+sbin_SCRIPTS = fence_legacy fence_watchdog - - noinst_HEADERS = pacemaker-fenced.h - -diff --git a/daemons/fenced/fence_watchdog.in b/daemons/fenced/fence_watchdog.in -new file mode 100755 -index 0000000..c83304f ---- /dev/null -+++ b/daemons/fenced/fence_watchdog.in -@@ -0,0 +1,283 @@ -+#!@PYTHON@ -+"""Dummy watchdog fence agent for providing meta-data for the pacemaker internal agent -+""" -+ -+__copyright__ = "Copyright 2012-2021 the Pacemaker project contributors" -+__license__ = "GNU General Public License version 2 or later (GPLv2+) WITHOUT ANY WARRANTY" -+ -+import io -+import os -+import re -+import sys -+import atexit -+import getopt -+ -+SHORT_DESC = "Dummy watchdog fence agent" -+LONG_DESC = """fence_watchdog just provides -+meta-data - actual fencing is done by the pacemaker internal watchdog agent.""" -+ -+ALL_OPT = { -+ "version" : { -+ "getopt" : "V", -+ "longopt" : "version", -+ "help" : "-V, --version Display version information and exit", -+ "required" : "0", -+ "shortdesc" : "Display version information and exit", -+ "order" : 53 -+ }, -+ "help" : { -+ "getopt" : "h", -+ "longopt" : "help", -+ "help" : "-h, --help Display this help and exit", -+ "required" : "0", -+ "shortdesc" : "Display help and exit", -+ "order" : 54 -+ }, -+ "action" : { -+ "getopt" : "o:", -+ "longopt" : "action", -+ "help" : "-o, --action=[action] Action: metadata", -+ "required" : "1", -+ "shortdesc" : "Fencing Action", -+ "default" : "metadata", -+ "order" : 1 -+ }, -+ "nodename" : { -+ "getopt" : "N:", -+ "longopt" : "nodename", -+ "help" : "-N, --nodename Node name of fence victim (ignored)", -+ "required" : "0", -+ "shortdesc" : "Ignored", -+ "order" : 2 -+ }, -+ "plug" : { -+ "getopt" : "n:", -+ "longopt" : "plug", -+ "help" : "-n, --plug=[id] Physical plug number on device (ignored)", -+ "required" : "1", -+ "shortdesc" : "Ignored", -+ "order" : 4 -+ } -+} -+ -+ -+def agent(): -+ """ Return name this file was run as. """ -+ -+ return os.path.basename(sys.argv[0]) -+ -+ -+def fail_usage(message): -+ """ Print a usage message and exit. """ -+ -+ sys.exit("%s\nPlease use '-h' for usage" % message) -+ -+ -+def show_docs(options): -+ """ Handle informational options (display info and exit). """ -+ -+ device_opt = options["device_opt"] -+ -+ if "-h" in options: -+ usage(device_opt) -+ sys.exit(0) -+ -+ if "-o" in options and options["-o"].lower() == "metadata": -+ metadata(device_opt, options) -+ sys.exit(0) -+ -+ if "-V" in options: -+ print(AGENT_VERSION) -+ sys.exit(0) -+ -+ -+def sorted_options(avail_opt): -+ """ Return a list of all options, in their internally specified order. """ -+ -+ sorted_list = [(key, ALL_OPT[key]) for key in avail_opt] -+ sorted_list.sort(key=lambda x: x[1]["order"]) -+ return sorted_list -+ -+ -+def usage(avail_opt): -+ """ Print a usage message. """ -+ print(LONG_DESC) -+ print() -+ print("Usage:") -+ print("\t" + agent() + " [options]") -+ print("Options:") -+ -+ for dummy, value in sorted_options(avail_opt): -+ if len(value["help"]) != 0: -+ print(" " + value["help"]) -+ -+ -+def metadata(avail_opt, options): -+ """ Print agent metadata. """ -+ -+ print(""" -+ -+%s -+""" % (agent(), SHORT_DESC, LONG_DESC)) -+ -+ for option, dummy in sorted_options(avail_opt): -+ if "shortdesc" in ALL_OPT[option]: -+ print(' ') -+ -+ default = "" -+ default_name_arg = "-" + ALL_OPT[option]["getopt"][:-1] -+ default_name_no_arg = "-" + ALL_OPT[option]["getopt"] -+ -+ if "default" in ALL_OPT[option]: -+ default = 'default="%s"' % str(ALL_OPT[option]["default"]) -+ elif default_name_arg in options: -+ if options[default_name_arg]: -+ try: -+ default = 'default="%s"' % options[default_name_arg] -+ except TypeError: -+ ## @todo/@note: Currently there is no clean way how to handle lists -+ ## we can create a string from it but we can't set it on command line -+ default = 'default="%s"' % str(options[default_name_arg]) -+ elif default_name_no_arg in options: -+ default = 'default="true"' -+ -+ mixed = ALL_OPT[option]["help"] -+ ## split it between option and help text -+ res = re.compile(r"^(.*--\S+)\s+", re.IGNORECASE | re.S).search(mixed) -+ if None != res: -+ mixed = res.group(1) -+ mixed = mixed.replace("<", "<").replace(">", ">") -+ print(' ') -+ -+ if ALL_OPT[option]["getopt"].count(":") > 0: -+ print(' ') -+ else: -+ print(' ') -+ -+ print(' ' + ALL_OPT[option]["shortdesc"] + '') -+ print(' ') -+ -+ print(' \n ') -+ print(' ') -+ print(' ') -+ print(' ') -+ print(' ') -+ print(' ') -+ print(' ') -+ print(' ') -+ print('') -+ -+ -+def option_longopt(option): -+ """ Return the getopt-compatible long-option name of the given option. """ -+ -+ if ALL_OPT[option]["getopt"].endswith(":"): -+ return ALL_OPT[option]["longopt"] + "=" -+ else: -+ return ALL_OPT[option]["longopt"] -+ -+ -+def opts_from_command_line(argv, avail_opt): -+ """ Read options from command-line arguments. """ -+ -+ # Prepare list of options for getopt -+ getopt_string = "" -+ longopt_list = [] -+ for k in avail_opt: -+ if k in ALL_OPT: -+ getopt_string += ALL_OPT[k]["getopt"] -+ else: -+ fail_usage("Parse error: unknown option '" + k + "'") -+ -+ if k in ALL_OPT and "longopt" in ALL_OPT[k]: -+ longopt_list.append(option_longopt(k)) -+ -+ try: -+ opt, dummy = getopt.gnu_getopt(argv, getopt_string, longopt_list) -+ except getopt.GetoptError as error: -+ fail_usage("Parse error: " + error.msg) -+ -+ # Transform longopt to short one which are used in fencing agents -+ old_opt = opt -+ opt = {} -+ for old_option in dict(old_opt).keys(): -+ if old_option.startswith("--"): -+ for option in ALL_OPT.keys(): -+ if "longopt" in ALL_OPT[option] and "--" + ALL_OPT[option]["longopt"] == old_option: -+ opt["-" + ALL_OPT[option]["getopt"].rstrip(":")] = dict(old_opt)[old_option] -+ else: -+ opt[old_option] = dict(old_opt)[old_option] -+ -+ return opt -+ -+ -+def opts_from_stdin(avail_opt): -+ """ Read options from standard input. """ -+ -+ opt = {} -+ name = "" -+ for line in sys.stdin.readlines(): -+ line = line.strip() -+ if line.startswith("#") or (len(line) == 0): -+ continue -+ -+ (name, value) = (line + "=").split("=", 1) -+ value = value[:-1] -+ -+ if name not in avail_opt: -+ print("Parse error: Ignoring unknown option '%s'" % line, -+ file=sys.stderr) -+ continue -+ -+ if ALL_OPT[name]["getopt"].endswith(":"): -+ opt["-"+ALL_OPT[name]["getopt"].rstrip(":")] = value -+ elif value.lower() in ["1", "yes", "on", "true"]: -+ opt["-"+ALL_OPT[name]["getopt"]] = "1" -+ -+ return opt -+ -+ -+def process_input(avail_opt): -+ """ Set standard environment variables, and parse all options. """ -+ -+ # Set standard environment -+ os.putenv("LANG", "C") -+ os.putenv("LC_ALL", "C") -+ -+ # Read options from command line or standard input -+ if len(sys.argv) > 1: -+ return opts_from_command_line(sys.argv[1:], avail_opt) -+ else: -+ return opts_from_stdin(avail_opt) -+ -+ -+def atexit_handler(): -+ """ Close stdout on exit. """ -+ -+ try: -+ sys.stdout.close() -+ os.close(1) -+ except IOError: -+ sys.exit("%s failed to close standard output" % agent()) -+ -+ -+def main(): -+ """ Make it so! """ -+ -+ device_opt = ALL_OPT.keys() -+ -+ ## Defaults for fence agent -+ atexit.register(atexit_handler) -+ options = process_input(device_opt) -+ options["device_opt"] = device_opt -+ show_docs(options) -+ -+ print("Watchdog fencing may be initiated only by the cluster, not this agent.", -+ file=sys.stderr) -+ -+ sys.exit(1) -+ -+ -+if __name__ == "__main__": -+ main() -diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c -index cd9968f..9470ea2 100644 ---- a/daemons/fenced/fenced_commands.c -+++ b/daemons/fenced/fenced_commands.c -@@ -397,15 +397,13 @@ stonith_device_execute(stonith_device_t * device) - return TRUE; - } - -- if(pcmk__str_eq(device->agent, STONITH_WATCHDOG_AGENT, pcmk__str_casei)) { -- if(pcmk__str_eq(cmd->action, "reboot", pcmk__str_casei)) { -- pcmk__panic(__func__); -- goto done; -- -- } else if(pcmk__str_eq(cmd->action, "off", pcmk__str_casei)) { -- pcmk__panic(__func__); -- goto done; -- -+ if (pcmk__str_any_of(device->agent, STONITH_WATCHDOG_AGENT, -+ STONITH_WATCHDOG_AGENT_INTERNAL, NULL)) { -+ if (pcmk__strcase_any_of(cmd->action, "reboot", "off", NULL)) { -+ if (node_does_watchdog_fencing(stonith_our_uname)) { -+ pcmk__panic(__func__); -+ goto done; -+ } - } else { - crm_info("Faking success for %s watchdog operation", cmd->action); - cmd->done_cb(0, 0, NULL, cmd); -@@ -716,7 +714,7 @@ get_agent_metadata(const char *agent, xmlNode ** metadata) - return EINVAL; - } - *metadata = NULL; -- if (pcmk__str_eq(agent, STONITH_WATCHDOG_AGENT, pcmk__str_none)) { -+ if (pcmk__str_eq(agent, STONITH_WATCHDOG_AGENT_INTERNAL, pcmk__str_none)) { - return pcmk_rc_ok; - } - init_metadata_cache(); -@@ -1050,24 +1048,6 @@ schedule_internal_command(const char *origin, - schedule_stonith_command(cmd, device); - } - --gboolean --string_in_list(GList *list, const char *item) --{ -- int lpc = 0; -- int max = g_list_length(list); -- -- for (lpc = 0; lpc < max; lpc++) { -- const char *value = g_list_nth_data(list, lpc); -- -- if (pcmk__str_eq(item, value, pcmk__str_casei)) { -- return TRUE; -- } else { -- crm_trace("%d: '%s' != '%s'", lpc, item, value); -- } -- } -- return FALSE; --} -- - static void - status_search_cb(GPid pid, int rc, const char *output, gpointer user_data) - { -@@ -1144,7 +1124,7 @@ dynamic_list_search_cb(GPid pid, int rc, const char *output, gpointer user_data) - if (!alias) { - alias = search->host; - } -- if (string_in_list(dev->targets, alias)) { -+ if (pcmk__str_in_list(dev->targets, alias, pcmk__str_casei)) { - can_fence = TRUE; - } - } -@@ -1215,9 +1195,62 @@ stonith_device_register(xmlNode * msg, const char **desc, gboolean from_cib) - stonith_device_t *dup = NULL; - stonith_device_t *device = build_device_from_xml(msg); - guint ndevices = 0; -+ int rv = pcmk_ok; - - CRM_CHECK(device != NULL, return -ENOMEM); - -+ /* do we have a watchdog-device? */ -+ if (pcmk__str_eq(device->id, STONITH_WATCHDOG_ID, pcmk__str_none) || -+ pcmk__str_any_of(device->agent, STONITH_WATCHDOG_AGENT, -+ STONITH_WATCHDOG_AGENT_INTERNAL, NULL)) do { -+ if (stonith_watchdog_timeout_ms <= 0) { -+ crm_err("Ignoring watchdog fence device without " -+ "stonith-watchdog-timeout set."); -+ rv = -ENODEV; -+ /* fall through to cleanup & return */ -+ } else if (!pcmk__str_any_of(device->agent, STONITH_WATCHDOG_AGENT, -+ STONITH_WATCHDOG_AGENT_INTERNAL, NULL)) { -+ crm_err("Ignoring watchdog fence device with unknown " -+ "agent '%s' unequal '" STONITH_WATCHDOG_AGENT "'.", -+ device->agent?device->agent:""); -+ rv = -ENODEV; -+ /* fall through to cleanup & return */ -+ } else if (!pcmk__str_eq(device->id, STONITH_WATCHDOG_ID, -+ pcmk__str_none)) { -+ crm_err("Ignoring watchdog fence device " -+ "named %s !='"STONITH_WATCHDOG_ID"'.", -+ device->id?device->id:""); -+ rv = -ENODEV; -+ /* fall through to cleanup & return */ -+ } else { -+ if (pcmk__str_eq(device->agent, STONITH_WATCHDOG_AGENT, -+ pcmk__str_none)) { -+ /* this either has an empty list or the targets -+ configured for watchdog-fencing -+ */ -+ g_list_free_full(stonith_watchdog_targets, free); -+ stonith_watchdog_targets = device->targets; -+ device->targets = NULL; -+ } -+ if (node_does_watchdog_fencing(stonith_our_uname)) { -+ g_list_free_full(device->targets, free); -+ device->targets = stonith__parse_targets(stonith_our_uname); -+ g_hash_table_replace(device->params, -+ strdup(PCMK_STONITH_HOST_LIST), -+ strdup(stonith_our_uname)); -+ /* proceed as with any other stonith-device */ -+ break; -+ } -+ -+ crm_debug("Skip registration of watchdog fence device on node not in host-list."); -+ /* cleanup and fall through to more cleanup and return */ -+ device->targets = NULL; -+ stonith_device_remove(device->id, from_cib); -+ } -+ free_device(device); -+ return rv; -+ } while (0); -+ - dup = device_has_duplicate(device); - if (dup) { - ndevices = g_hash_table_size(device_list); -@@ -1598,6 +1631,39 @@ stonith_level_remove(xmlNode *msg, char **desc) - * (CIB registration is not sufficient), because monitor should not be - * possible unless the device is "started" (API registered). - */ -+ -+static char * -+list_to_string(GList *list, const char *delim, gboolean terminate_with_delim) -+{ -+ int max = g_list_length(list); -+ size_t delim_len = delim?strlen(delim):0; -+ size_t alloc_size = 1 + (max?((max-1+(terminate_with_delim?1:0))*delim_len):0); -+ char *rv; -+ GList *gIter; -+ -+ for (gIter = list; gIter != NULL; gIter = gIter->next) { -+ const char *value = (const char *) gIter->data; -+ -+ alloc_size += strlen(value); -+ } -+ rv = calloc(alloc_size, sizeof(char)); -+ if (rv) { -+ char *pos = rv; -+ const char *lead_delim = ""; -+ -+ for (gIter = list; gIter != NULL; gIter = gIter->next) { -+ const char *value = (const char *) gIter->data; -+ -+ pos = &pos[sprintf(pos, "%s%s", lead_delim, value)]; -+ lead_delim = delim; -+ } -+ if (max && terminate_with_delim) { -+ sprintf(pos, "%s", delim); -+ } -+ } -+ return rv; -+} -+ - static int - stonith_device_action(xmlNode * msg, char **output) - { -@@ -1615,6 +1681,19 @@ stonith_device_action(xmlNode * msg, char **output) - return -EPROTO; - } - -+ if (pcmk__str_eq(id, STONITH_WATCHDOG_ID, pcmk__str_none)) { -+ if (stonith_watchdog_timeout_ms <= 0) { -+ return -ENODEV; -+ } else { -+ if (pcmk__str_eq(action, "list", pcmk__str_casei)) { -+ *output = list_to_string(stonith_watchdog_targets, "\n", TRUE); -+ return pcmk_ok; -+ } else if (pcmk__str_eq(action, "monitor", pcmk__str_casei)) { -+ return pcmk_ok; -+ } -+ } -+ } -+ - device = g_hash_table_lookup(device_list, id); - if ((device == NULL) - || (!device->api_registered && !strcmp(action, "monitor"))) { -@@ -1742,7 +1821,7 @@ can_fence_host_with_device(stonith_device_t * dev, struct device_search_s *searc - * Only use if all hosts on which the device can be active can always fence all listed hosts - */ - -- if (string_in_list(dev->targets, host)) { -+ if (pcmk__str_in_list(dev->targets, host, pcmk__str_casei)) { - can = TRUE; - } else if (g_hash_table_lookup(dev->params, PCMK_STONITH_HOST_MAP) - && g_hash_table_lookup(dev->aliases, host)) { -@@ -1763,7 +1842,7 @@ can_fence_host_with_device(stonith_device_t * dev, struct device_search_s *searc - return; - } - -- if (string_in_list(dev->targets, alias)) { -+ if (pcmk__str_in_list(dev->targets, alias, pcmk__str_casei)) { - can = TRUE; - } - -diff --git a/daemons/fenced/fenced_remote.c b/daemons/fenced/fenced_remote.c -index cf91aca..224f2ba 100644 ---- a/daemons/fenced/fenced_remote.c -+++ b/daemons/fenced/fenced_remote.c -@@ -1522,6 +1522,25 @@ advance_topology_device_in_level(remote_fencing_op_t *op, const char *device, - } - } - -+static gboolean -+check_watchdog_fencing_and_wait(remote_fencing_op_t * op) -+{ -+ if (node_does_watchdog_fencing(op->target)) { -+ -+ crm_notice("Waiting %lds for %s to self-fence (%s) for " -+ "client %s " CRM_XS " id=%.8s", -+ (stonith_watchdog_timeout_ms / 1000), -+ op->target, op->action, op->client_name, op->id); -+ op->op_timer_one = g_timeout_add(stonith_watchdog_timeout_ms, -+ remote_op_watchdog_done, op); -+ return TRUE; -+ } else { -+ crm_debug("Skipping fallback to watchdog-fencing as %s is " -+ "not in host-list", op->target); -+ } -+ return FALSE; -+} -+ - void - call_remote_stonith(remote_fencing_op_t * op, st_query_result_t * peer, int rc) - { -@@ -1592,26 +1611,33 @@ call_remote_stonith(remote_fencing_op_t * op, st_query_result_t * peer, int rc) - g_source_remove(op->op_timer_one); - } - -- if(stonith_watchdog_timeout_ms > 0 && device && pcmk__str_eq(device, "watchdog", pcmk__str_casei)) { -- crm_notice("Waiting %lds for %s to self-fence (%s) for client %s " -- CRM_XS " id=%.8s", (stonith_watchdog_timeout_ms / 1000), -- op->target, op->action, op->client_name, op->id); -- op->op_timer_one = g_timeout_add(stonith_watchdog_timeout_ms, remote_op_watchdog_done, op); -- -- /* TODO check devices to verify watchdog will be in use */ -- } else if(stonith_watchdog_timeout_ms > 0 -- && pcmk__str_eq(peer->host, op->target, pcmk__str_casei) -- && !pcmk__str_eq(op->action, "on", pcmk__str_casei)) { -- crm_notice("Waiting %lds for %s to self-fence (%s) for client %s " -- CRM_XS " id=%.8s", (stonith_watchdog_timeout_ms / 1000), -- op->target, op->action, op->client_name, op->id); -- op->op_timer_one = g_timeout_add(stonith_watchdog_timeout_ms, remote_op_watchdog_done, op); -- -- } else { -+ if (!(stonith_watchdog_timeout_ms > 0 && ( -+ (pcmk__str_eq(device, STONITH_WATCHDOG_ID, -+ pcmk__str_none)) || -+ (pcmk__str_eq(peer->host, op->target, pcmk__str_casei) -+ && !pcmk__str_eq(op->action, "on", pcmk__str_casei))) && -+ check_watchdog_fencing_and_wait(op))) { -+ -+ /* Some thoughts about self-fencing cases reaching this point: -+ - Actually check in check_watchdog_fencing_and_wait -+ shouldn't fail if STONITH_WATCHDOG_ID is -+ chosen as fencing-device and it being present implies -+ watchdog-fencing is enabled anyway -+ - If watchdog-fencing is disabled either in general or for -+ a specific target - detected in check_watchdog_fencing_and_wait - -+ for some other kind of self-fencing we can't expect -+ a success answer but timeout is fine if the node doesn't -+ come back in between -+ - Delicate might be the case where we have watchdog-fencing -+ enabled for a node but the watchdog-fencing-device isn't -+ explicitly chosen for suicide. Local pe-execution in sbd -+ may detect the node as unclean and lead to timely suicide. -+ Otherwise the selection of stonith-watchdog-timeout at -+ least is questionable. -+ */ - op->op_timer_one = g_timeout_add((1000 * timeout_one), remote_op_timeout_one, op); - } - -- - send_cluster_message(crm_get_peer(0, peer->host), crm_msg_stonith_ng, remote_op, FALSE); - peer->tried = TRUE; - free_xml(remote_op); -@@ -1645,12 +1671,11 @@ call_remote_stonith(remote_fencing_op_t * op, st_query_result_t * peer, int rc) - * but we have all the expected replies, then no devices - * are available to execute the fencing operation. */ - -- if(stonith_watchdog_timeout_ms && pcmk__str_eq(device, "watchdog", pcmk__str_null_matches | pcmk__str_casei)) { -- crm_notice("Waiting %lds for %s to self-fence (%s) for client %s " -- CRM_XS " id=%.8s", (stonith_watchdog_timeout_ms / 1000), -- op->target, op->action, op->client_name, op->id); -- op->op_timer_one = g_timeout_add(stonith_watchdog_timeout_ms, remote_op_watchdog_done, op); -- return; -+ if(stonith_watchdog_timeout_ms > 0 && pcmk__str_eq(device, -+ STONITH_WATCHDOG_ID, pcmk__str_null_matches)) { -+ if (check_watchdog_fencing_and_wait(op)) { -+ return; -+ } - } - - if (op->state == st_query) { -diff --git a/daemons/fenced/pacemaker-fenced.c b/daemons/fenced/pacemaker-fenced.c -index 39738d8..7f8b427 100644 ---- a/daemons/fenced/pacemaker-fenced.c -+++ b/daemons/fenced/pacemaker-fenced.c -@@ -42,6 +42,7 @@ - - char *stonith_our_uname = NULL; - long stonith_watchdog_timeout_ms = 0; -+GList *stonith_watchdog_targets = NULL; - - static GMainLoop *mainloop = NULL; - -@@ -578,7 +579,44 @@ our_node_allowed_for(pe_resource_t *rsc) - } - - static void --watchdog_device_update(xmlNode *cib) -+watchdog_device_update(void) -+{ -+ if (stonith_watchdog_timeout_ms > 0) { -+ if (!g_hash_table_lookup(device_list, STONITH_WATCHDOG_ID) && -+ !stonith_watchdog_targets) { -+ /* getting here watchdog-fencing enabled, no device there yet -+ and reason isn't stonith_watchdog_targets preventing that -+ */ -+ int rc; -+ xmlNode *xml; -+ -+ xml = create_device_registration_xml( -+ STONITH_WATCHDOG_ID, -+ st_namespace_internal, -+ STONITH_WATCHDOG_AGENT, -+ NULL, /* stonith_device_register will add our -+ own name as PCMK_STONITH_HOST_LIST param -+ so we can skip that here -+ */ -+ NULL); -+ rc = stonith_device_register(xml, NULL, TRUE); -+ free_xml(xml); -+ if (rc != pcmk_ok) { -+ crm_crit("Cannot register watchdog pseudo fence agent"); -+ crm_exit(CRM_EX_FATAL); -+ } -+ } -+ -+ } else { -+ /* be silent if no device - todo parameter to stonith_device_remove */ -+ if (g_hash_table_lookup(device_list, STONITH_WATCHDOG_ID)) { -+ stonith_device_remove(STONITH_WATCHDOG_ID, TRUE); -+ } -+ } -+} -+ -+static void -+update_stonith_watchdog_timeout_ms(xmlNode *cib) - { - xmlNode *stonith_enabled_xml = NULL; - const char *stonith_enabled_s = NULL; -@@ -608,33 +646,7 @@ watchdog_device_update(xmlNode *cib) - } - } - -- if (timeout_ms != stonith_watchdog_timeout_ms) { -- crm_notice("New watchdog timeout %lds (was %lds)", timeout_ms/1000, stonith_watchdog_timeout_ms/1000); -- stonith_watchdog_timeout_ms = timeout_ms; -- -- if (stonith_watchdog_timeout_ms > 0) { -- int rc; -- xmlNode *xml; -- stonith_key_value_t *params = NULL; -- -- params = stonith_key_value_add(params, PCMK_STONITH_HOST_LIST, -- stonith_our_uname); -- -- xml = create_device_registration_xml("watchdog", st_namespace_internal, -- STONITH_WATCHDOG_AGENT, params, -- NULL); -- stonith_key_value_freeall(params, 1, 1); -- rc = stonith_device_register(xml, NULL, FALSE); -- free_xml(xml); -- if (rc != pcmk_ok) { -- crm_crit("Cannot register watchdog pseudo fence agent"); -- crm_exit(CRM_EX_FATAL); -- } -- -- } else { -- stonith_device_remove("watchdog", FALSE); -- } -- } -+ stonith_watchdog_timeout_ms = timeout_ms; - } - - /*! -@@ -677,6 +689,16 @@ static void cib_device_update(pe_resource_t *rsc, pe_working_set_t *data_set) - return; - } - -+ /* if watchdog-fencing is disabled handle any watchdog-fence -+ resource as if it was disabled -+ */ -+ if ((stonith_watchdog_timeout_ms <= 0) && -+ pcmk__str_eq(rsc->id, STONITH_WATCHDOG_ID, pcmk__str_none)) { -+ crm_info("Watchdog-fencing disabled thus handling " -+ "device %s as disabled", rsc->id); -+ return; -+ } -+ - /* Check whether our node is allowed for this resource (and its parent if in a group) */ - node = our_node_allowed_for(rsc); - if (rsc->parent && (rsc->parent->variant == pe_group)) { -@@ -772,6 +794,12 @@ cib_devices_update(void) - } - } - -+ /* have list repopulated if cib has a watchdog-fencing-resource -+ TODO: keep a cached list for queries happening while we are refreshing -+ */ -+ g_list_free_full(stonith_watchdog_targets, free); -+ stonith_watchdog_targets = NULL; -+ - for (gIter = fenced_data_set->resources; gIter != NULL; gIter = gIter->next) { - cib_device_update(gIter->data, fenced_data_set); - } -@@ -825,6 +853,8 @@ update_cib_stonith_devices_v2(const char *event, xmlNode * msg) - if (search != NULL) { - *search = 0; - stonith_device_remove(rsc_id, TRUE); -+ /* watchdog_device_update called afterwards -+ to fall back to implicit definition if needed */ - } else { - crm_warn("Ignoring malformed CIB update (resource deletion)"); - } -@@ -968,6 +998,24 @@ node_has_attr(const char *node, const char *name, const char *value) - return (match != NULL); - } - -+/*! -+ * \internal -+ * \brief Check whether a node does watchdog-fencing -+ * -+ * \param[in] node Name of node to check -+ * -+ * \return TRUE if node found in stonith_watchdog_targets -+ * or stonith_watchdog_targets is empty indicating -+ * all nodes are doing watchdog-fencing -+ */ -+gboolean -+node_does_watchdog_fencing(const char *node) -+{ -+ return ((stonith_watchdog_targets == NULL) || -+ pcmk__str_in_list(stonith_watchdog_targets, node, pcmk__str_casei)); -+} -+ -+ - static void - update_fencing_topology(const char *event, xmlNode * msg) - { -@@ -1073,6 +1121,8 @@ update_cib_cache_cb(const char *event, xmlNode * msg) - xmlNode *stonith_enabled_xml = NULL; - const char *stonith_enabled_s = NULL; - static gboolean stonith_enabled_saved = TRUE; -+ long timeout_ms_saved = stonith_watchdog_timeout_ms; -+ gboolean need_full_refresh = FALSE; - - if(!have_cib_devices) { - crm_trace("Skipping updates until we get a full dump"); -@@ -1127,6 +1177,7 @@ update_cib_cache_cb(const char *event, xmlNode * msg) - } - - pcmk__refresh_node_caches_from_cib(local_cib); -+ update_stonith_watchdog_timeout_ms(local_cib); - - stonith_enabled_xml = get_xpath_object("//nvpair[@name='stonith-enabled']", - local_cib, LOG_NEVER); -@@ -1134,23 +1185,30 @@ update_cib_cache_cb(const char *event, xmlNode * msg) - stonith_enabled_s = crm_element_value(stonith_enabled_xml, XML_NVPAIR_ATTR_VALUE); - } - -- watchdog_device_update(local_cib); -- - if (stonith_enabled_s && crm_is_true(stonith_enabled_s) == FALSE) { - crm_trace("Ignoring CIB updates while fencing is disabled"); - stonith_enabled_saved = FALSE; -- return; - - } else if (stonith_enabled_saved == FALSE) { - crm_info("Updating fencing device and topology lists " - "now that fencing is enabled"); - stonith_enabled_saved = TRUE; -- fencing_topology_init(); -- cib_devices_update(); -+ need_full_refresh = TRUE; - - } else { -- update_fencing_topology(event, msg); -- update_cib_stonith_devices(event, msg); -+ if (timeout_ms_saved != stonith_watchdog_timeout_ms) { -+ need_full_refresh = TRUE; -+ } else { -+ update_fencing_topology(event, msg); -+ update_cib_stonith_devices(event, msg); -+ watchdog_device_update(); -+ } -+ } -+ -+ if (need_full_refresh) { -+ fencing_topology_init(); -+ cib_devices_update(); -+ watchdog_device_update(); - } - } - -@@ -1162,10 +1220,11 @@ init_cib_cache_cb(xmlNode * msg, int call_id, int rc, xmlNode * output, void *us - local_cib = copy_xml(output); - - pcmk__refresh_node_caches_from_cib(local_cib); -+ update_stonith_watchdog_timeout_ms(local_cib); - - fencing_topology_init(); -- watchdog_device_update(local_cib); - cib_devices_update(); -+ watchdog_device_update(); - } - - static void -diff --git a/daemons/fenced/pacemaker-fenced.h b/daemons/fenced/pacemaker-fenced.h -index d330fda..14e085e 100644 ---- a/daemons/fenced/pacemaker-fenced.h -+++ b/daemons/fenced/pacemaker-fenced.h -@@ -260,14 +260,15 @@ bool fencing_peer_active(crm_node_t *peer); - - int stonith_manual_ack(xmlNode * msg, remote_fencing_op_t * op); - --gboolean string_in_list(GList *list, const char *item); -- - gboolean node_has_attr(const char *node, const char *name, const char *value); - -+gboolean node_does_watchdog_fencing(const char *node); -+ - extern char *stonith_our_uname; - extern gboolean stand_alone; - extern GHashTable *device_list; - extern GHashTable *topology; - extern long stonith_watchdog_timeout_ms; -+extern GList *stonith_watchdog_targets; - - extern GHashTable *stonith_remote_op_list; -diff --git a/include/crm/crm.h b/include/crm/crm.h -index ee52c36..7861c16 100644 ---- a/include/crm/crm.h -+++ b/include/crm/crm.h -@@ -66,7 +66,7 @@ extern "C" { - * >=3.0.13: Fail counts include operation name and interval - * >=3.2.0: DC supports PCMK_LRM_OP_INVALID and PCMK_LRM_OP_NOT_CONNECTED - */ --# define CRM_FEATURE_SET "3.10.2" -+# define CRM_FEATURE_SET "3.11.0" - - /* Pacemaker's CPG protocols use fixed-width binary fields for the sender and - * recipient of a CPG message. This imposes an arbitrary limit on cluster node -diff --git a/include/crm/fencing/internal.h b/include/crm/fencing/internal.h -index 8bcb544..f222edb 100644 ---- a/include/crm/fencing/internal.h -+++ b/include/crm/fencing/internal.h -@@ -164,7 +164,10 @@ void stonith__device_parameter_flags(uint32_t *device_flags, - # define STONITH_OP_LEVEL_ADD "st_level_add" - # define STONITH_OP_LEVEL_DEL "st_level_remove" - --# define STONITH_WATCHDOG_AGENT "#watchdog" -+# define STONITH_WATCHDOG_AGENT "fence_watchdog" -+/* Don't change 2 below as it would break rolling upgrade */ -+# define STONITH_WATCHDOG_AGENT_INTERNAL "#watchdog" -+# define STONITH_WATCHDOG_ID "watchdog" - - # ifdef HAVE_STONITH_STONITH_H - // utilities from st_lha.c -@@ -211,4 +214,7 @@ stonith__op_state_pending(enum op_state state) - return state != st_failed && state != st_done; - } - -+gboolean stonith__watchdog_fencing_enabled_for_node(const char *node); -+gboolean stonith__watchdog_fencing_enabled_for_node_api(stonith_t *st, const char *node); -+ - #endif -diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c -index e285f51..0ff9815 100644 ---- a/lib/fencing/st_client.c -+++ b/lib/fencing/st_client.c -@@ -195,6 +195,67 @@ stonith_get_namespace(const char *agent, const char *namespace_s) - return st_namespace_invalid; - } - -+gboolean -+stonith__watchdog_fencing_enabled_for_node_api(stonith_t *st, const char *node) -+{ -+ gboolean rv = FALSE; -+ stonith_t *stonith_api = st?st:stonith_api_new(); -+ char *list = NULL; -+ -+ if(stonith_api) { -+ if (stonith_api->state == stonith_disconnected) { -+ int rc = stonith_api->cmds->connect(stonith_api, "stonith-api", NULL); -+ -+ if (rc != pcmk_ok) { -+ crm_err("Failed connecting to Stonith-API for watchdog-fencing-query."); -+ } -+ } -+ -+ if (stonith_api->state != stonith_disconnected) { -+ /* caveat!!! -+ * this might fail when when stonithd is just updating the device-list -+ * probably something we should fix as well for other api-calls */ -+ int rc = stonith_api->cmds->list(stonith_api, st_opt_sync_call, STONITH_WATCHDOG_ID, &list, 0); -+ if ((rc != pcmk_ok) || (list == NULL)) { -+ /* due to the race described above it can happen that -+ * we drop in here - so as not to make remote nodes -+ * panic on that answer -+ */ -+ crm_warn("watchdog-fencing-query failed"); -+ } else if (list[0] == '\0') { -+ crm_warn("watchdog-fencing-query returned an empty list - any node"); -+ rv = TRUE; -+ } else { -+ GList *targets = stonith__parse_targets(list); -+ rv = pcmk__str_in_list(targets, node, pcmk__str_casei); -+ g_list_free_full(targets, free); -+ } -+ free(list); -+ if (!st) { -+ /* if we're provided the api we still might have done the -+ * connection - but let's assume the caller won't bother -+ */ -+ stonith_api->cmds->disconnect(stonith_api); -+ } -+ } -+ -+ if (!st) { -+ stonith_api_delete(stonith_api); -+ } -+ } else { -+ crm_err("Stonith-API for watchdog-fencing-query couldn't be created."); -+ } -+ crm_trace("Pacemaker assumes node %s %sto do watchdog-fencing.", -+ node, rv?"":"not "); -+ return rv; -+} -+ -+gboolean -+stonith__watchdog_fencing_enabled_for_node(const char *node) -+{ -+ return stonith__watchdog_fencing_enabled_for_node_api(NULL, node); -+} -+ - static void - log_action(stonith_action_t *action, pid_t pid) - { -diff --git a/lib/lrmd/lrmd_client.c b/lib/lrmd/lrmd_client.c -index 87d050e..bf4bceb 100644 ---- a/lib/lrmd/lrmd_client.c -+++ b/lib/lrmd/lrmd_client.c -@@ -34,6 +34,7 @@ - #include - - #include -+#include - - #ifdef HAVE_GNUTLS_GNUTLS_H - # undef KEYFILE -@@ -934,7 +935,10 @@ lrmd__validate_remote_settings(lrmd_t *lrmd, GHashTable *hash) - crm_xml_add(data, F_LRMD_ORIGIN, __func__); - - value = g_hash_table_lookup(hash, "stonith-watchdog-timeout"); -- crm_xml_add(data, F_LRMD_WATCHDOG, value); -+ if ((value) && -+ (stonith__watchdog_fencing_enabled_for_node(native->remote_nodename))) { -+ crm_xml_add(data, F_LRMD_WATCHDOG, value); -+ } - - rc = lrmd_send_command(lrmd, LRMD_OP_CHECK, data, NULL, 0, 0, - (native->type == pcmk__client_ipc)); -diff --git a/rpm/pacemaker.spec.in b/rpm/pacemaker.spec.in -index 79e78ed..f58357a 100644 ---- a/rpm/pacemaker.spec.in -+++ b/rpm/pacemaker.spec.in -@@ -744,6 +744,7 @@ exit 0 - %doc %{_mandir}/man8/crm_attribute.* - %doc %{_mandir}/man8/crm_master.* - %doc %{_mandir}/man8/fence_legacy.* -+%doc %{_mandir}/man8/fence_watchdog.* - %doc %{_mandir}/man8/pacemakerd.* - - %doc %{_datadir}/pacemaker/alerts -@@ -796,6 +797,7 @@ exit 0 - %{_sbindir}/crm_simulate - %{_sbindir}/crm_report - %{_sbindir}/crm_ticket -+%{_sbindir}/fence_watchdog - %{_sbindir}/stonith_admin - # "dirname" is owned by -schemas, which is a prerequisite - %{_datadir}/pacemaker/report.collector -@@ -822,6 +824,7 @@ exit 0 - %exclude %{_mandir}/man8/crm_attribute.* - %exclude %{_mandir}/man8/crm_master.* - %exclude %{_mandir}/man8/fence_legacy.* -+%exclude %{_mandir}/man8/fence_watchdog.* - %exclude %{_mandir}/man8/pacemakerd.* - %exclude %{_mandir}/man8/pacemaker-remoted.* - --- -1.8.3.1 - diff --git a/0002-Fix-watchdog-fencing-Silence-warning-without-node-re.patch b/0002-Fix-watchdog-fencing-Silence-warning-without-node-re.patch deleted file mode 100644 index ccfbccc..0000000 --- a/0002-Fix-watchdog-fencing-Silence-warning-without-node-re.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 53dd360f096e5f005e3221e8d44d82d3654b5172 Mon Sep 17 00:00:00 2001 -From: Klaus Wenninger -Date: Wed, 4 Aug 2021 15:57:23 +0200 -Subject: [PATCH] Fix: watchdog-fencing: Silence warning without node - restriction - ---- - lib/fencing/st_client.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c -index 0ff9815..14fa7b2 100644 ---- a/lib/fencing/st_client.c -+++ b/lib/fencing/st_client.c -@@ -223,7 +223,6 @@ stonith__watchdog_fencing_enabled_for_node_api(stonith_t *st, const char *node) - */ - crm_warn("watchdog-fencing-query failed"); - } else if (list[0] == '\0') { -- crm_warn("watchdog-fencing-query returned an empty list - any node"); - rv = TRUE; - } else { - GList *targets = stonith__parse_targets(list); --- -1.8.3.1 - diff --git a/0003-Fix-fence_watchdog-fix-version-output-needed-for-hel.patch b/0003-Fix-fence_watchdog-fix-version-output-needed-for-hel.patch deleted file mode 100644 index 8245e4f..0000000 --- a/0003-Fix-fence_watchdog-fix-version-output-needed-for-hel.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 88e75d5b98df197fa731e7642434951a24a67095 Mon Sep 17 00:00:00 2001 -From: Klaus Wenninger -Date: Tue, 10 Aug 2021 09:10:23 +0200 -Subject: [PATCH] Fix: fence_watchdog: fix version output needed for help2man - ---- - daemons/fenced/fence_watchdog.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/daemons/fenced/fence_watchdog.in b/daemons/fenced/fence_watchdog.in -index c83304f..700065e 100755 ---- a/daemons/fenced/fence_watchdog.in -+++ b/daemons/fenced/fence_watchdog.in -@@ -12,6 +12,7 @@ import sys - import atexit - import getopt - -+AGENT_VERSION = "1.0.0" - SHORT_DESC = "Dummy watchdog fence agent" - LONG_DESC = """fence_watchdog just provides - meta-data - actual fencing is done by the pacemaker internal watchdog agent.""" --- -1.8.3.1 - diff --git a/0004-Build-rpm-package-fence_watchdog-in-base-package.patch b/0004-Build-rpm-package-fence_watchdog-in-base-package.patch deleted file mode 100644 index d112c40..0000000 --- a/0004-Build-rpm-package-fence_watchdog-in-base-package.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 61eb9c240004d1dbd0b5973e2fecda3686bb4c53 Mon Sep 17 00:00:00 2001 -From: Klaus Wenninger -Date: Tue, 10 Aug 2021 09:06:55 +0200 -Subject: [PATCH] Build: rpm: package fence_watchdog in base-package - ---- - rpm/pacemaker.spec.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/rpm/pacemaker.spec.in b/rpm/pacemaker.spec.in -index f58357a..0c569b9 100644 ---- a/rpm/pacemaker.spec.in -+++ b/rpm/pacemaker.spec.in -@@ -734,6 +734,7 @@ exit 0 - %{_sbindir}/crm_attribute - %{_sbindir}/crm_master - %{_sbindir}/fence_legacy -+%{_sbindir}/fence_watchdog - - %doc %{_mandir}/man7/pacemaker-controld.* - %doc %{_mandir}/man7/pacemaker-schedulerd.* -@@ -797,7 +798,6 @@ exit 0 - %{_sbindir}/crm_simulate - %{_sbindir}/crm_report - %{_sbindir}/crm_ticket --%{_sbindir}/fence_watchdog - %{_sbindir}/stonith_admin - # "dirname" is owned by -schemas, which is a prerequisite - %{_datadir}/pacemaker/report.collector --- -1.8.3.1 - diff --git a/0005-Fix-fence_watchdog-fix-malformed-xml-in-metadata.patch b/0005-Fix-fence_watchdog-fix-malformed-xml-in-metadata.patch deleted file mode 100644 index 0d2c32e..0000000 --- a/0005-Fix-fence_watchdog-fix-malformed-xml-in-metadata.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 46dd1118cae948649e000b2159e8e92623520ad9 Mon Sep 17 00:00:00 2001 -From: Klaus Wenninger -Date: Thu, 19 Aug 2021 09:28:54 +0200 -Subject: [PATCH] Fix: fence_watchdog: fix malformed xml in metadata - ---- - daemons/fenced/fence_watchdog.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/daemons/fenced/fence_watchdog.in b/daemons/fenced/fence_watchdog.in -index 700065e..eefa739 100755 ---- a/daemons/fenced/fence_watchdog.in -+++ b/daemons/fenced/fence_watchdog.in -@@ -124,7 +124,7 @@ def metadata(avail_opt, options): - for option, dummy in sorted_options(avail_opt): - if "shortdesc" in ALL_OPT[option]: - print(' ') -+ '" required="' + ALL_OPT[option]["required"] + '">') - - default = "" - default_name_arg = "-" + ALL_OPT[option]["getopt"][:-1] --- -1.8.3.1 - diff --git a/0006-Test-cts-fencing-Add-a-test-for-metadata.patch b/0006-Test-cts-fencing-Add-a-test-for-metadata.patch deleted file mode 100644 index 1c92251..0000000 --- a/0006-Test-cts-fencing-Add-a-test-for-metadata.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 18b4c8170efaa4e17fcbfcd2873722de45fb9d25 Mon Sep 17 00:00:00 2001 -From: Grace Chin -Date: Wed, 18 Aug 2021 09:42:57 -0400 -Subject: [PATCH] Test: cts-fencing: Add a test for --metadata - ---- - cts/cts-fencing.in | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/cts/cts-fencing.in b/cts/cts-fencing.in -index 8dc5ec8..c4697ee 100644 ---- a/cts/cts-fencing.in -+++ b/cts/cts-fencing.in -@@ -1423,6 +1423,13 @@ class Tests(object): - test.add_stonith_log_pattern("perform 'reboot' action targeting node_fake using true2") - test.add_stonith_neg_log_pattern("node_fake with true3") - -+ def build_query_tests(self): -+ """ run stonith_admin --metadata for the fence_dummy agent and check command output """ -+ -+ test = self.new_test("get_metadata", -+ "Run stonith_admin --metadata for the fence_dummy agent", 1) -+ test.add_cmd_check_stdout("stonith_admin", "--output-as=xml -a fence_dummy --metadata", ' -Date: Thu, 19 Aug 2021 17:02:16 +0200 -Subject: [PATCH] Test: cts-fencing: check metadata from fence_dummy/watchdog - -xml gotten via stonith_admin has actual metadata just embedded -and thus is always valid xml even if metadata itself isn't. ---- - cts/cts-fencing.in | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/cts/cts-fencing.in b/cts/cts-fencing.in -index 942e607..0bedd9a 100644 ---- a/cts/cts-fencing.in -+++ b/cts/cts-fencing.in -@@ -1442,6 +1442,18 @@ class Tests(object): - "Run stonith_admin --metadata for the fence_dummy agent", 1) - test.add_cmd_check_stdout("stonith_admin", "--output-as=xml -a fence_dummy --metadata", ' -Date: Thu, 19 Aug 2021 16:51:49 +0200 -Subject: [PATCH] Test: cts-fencing: add a few options for tests - -allow pure xml validity-check without checking against rng-file -allow discarding stdout for checks -add exception-handler for xmllint errors ---- - cts/cts-fencing.in | 30 +++++++++++++++++++++--------- - 1 file changed, 21 insertions(+), 9 deletions(-) - -diff --git a/cts/cts-fencing.in b/cts/cts-fencing.in -index c4697ee..942e607 100644 ---- a/cts/cts-fencing.in -+++ b/cts/cts-fencing.in -@@ -109,7 +109,10 @@ def update_path(): - - def find_validator(rng_file): - if os.access("/usr/bin/xmllint", os.X_OK): -- return ["xmllint", "--relaxng", rng_file, "-"] -+ if rng_file == None: -+ return ["xmllint", "-"] -+ else: -+ return ["xmllint", "--relaxng", rng_file, "-"] - else: - return None - -@@ -123,7 +126,7 @@ def rng_directory(): - return SCHEMA_DIR - - --def pipe_communicate(pipes, stderr=False, stdin=None): -+def pipe_communicate(pipes, check_stderr=False, stdin=None): - """ Get text output from pipes """ - - if stdin is not None: -@@ -132,7 +135,7 @@ def pipe_communicate(pipes, stderr=False, stdin=None): - pipe_outputs = pipes.communicate() - - output = pipe_outputs[0].decode(sys.stdout.encoding) -- if stderr: -+ if check_stderr: - output = output + pipe_outputs[1].decode(sys.stderr.encoding) - return output - -@@ -240,7 +243,7 @@ class Test(object): - - self.executed = 0 - -- def __new_cmd(self, cmd, args, exitcode, stdout_match="", no_wait=0, stdout_negative_match="", kill=None, validate=True): -+ def __new_cmd(self, cmd, args, exitcode, stdout_match="", no_wait=0, stdout_negative_match="", kill=None, validate=True, check_rng=True, check_stderr=True): - """ Add a command to be executed as part of this test """ - - self.cmds.append( -@@ -253,6 +256,8 @@ class Test(object): - "stdout_negative_match" : stdout_negative_match, - "no_wait" : no_wait, - "validate" : validate, -+ "check_rng" : check_rng, -+ "check_stderr" : check_stderr, - } - ) - -@@ -347,10 +352,10 @@ class Test(object): - - self.negative_stonith_patterns.append(pattern) - -- def add_cmd(self, cmd, args, validate=True): -+ def add_cmd(self, cmd, args, validate=True, check_rng=True, check_stderr=True): - """ Add a simple command to be executed as part of this test """ - -- self.__new_cmd(cmd, args, CrmExit.OK, "", validate=validate) -+ self.__new_cmd(cmd, args, CrmExit.OK, "", validate=validate, check_rng=check_rng, check_stderr=check_stderr) - - def add_cmd_no_wait(self, cmd, args): - """ Add a simple command to be executed (without waiting) as part of this test """ -@@ -397,7 +402,7 @@ class Test(object): - else: - return CrmExit.OK - -- output = pipe_communicate(test, stderr=True) -+ output = pipe_communicate(test, check_stderr=args['check_stderr']) - if self.verbose: - print(output) - -@@ -413,7 +418,10 @@ class Test(object): - raise OutputFoundError(output) - - if args['validate']: -- rng_file = rng_directory() + "/api/api-result.rng" -+ if args['check_rng']: -+ rng_file = rng_directory() + "/api/api-result.rng" -+ else: -+ rng_file = None - - cmd = find_validator(rng_file) - if not cmd: -@@ -423,7 +431,7 @@ class Test(object): - print("\nRunning: "+" ".join(cmd)) - - validator = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) -- output = pipe_communicate(validator, stderr=True, stdin=output) -+ output = pipe_communicate(validator, check_stderr=True, stdin=output) - - if self.verbose: - print(output) -@@ -508,6 +516,10 @@ class Test(object): - print("Step %d FAILED - '%s' was found in command output: %s" % (i, cmd['stdout_negative_match'], e)) - self.set_error(i, cmd); - break -+ except XmlValidationError as e: -+ print("Step %d FAILED - xmllint failed: %s" % (i, e)) -+ self.set_error(i, cmd); -+ break - if self.verbose: - print("Step %d SUCCESS" % (i)) - i = i + 1 --- -1.8.3.1 - diff --git a/pacemaker.spec b/pacemaker.spec index 07f72df..3ca2e42 100644 --- a/pacemaker.spec +++ b/pacemaker.spec @@ -31,11 +31,11 @@ ## 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 2.1.1 -%global specversion 9 +%global pcmkversion 2.1.2 +%global specversion 0.1.rc1 ## Upstream commit (full commit ID, abbreviated commit ID, or tag) to build -%global commit 77db57872790c73e44ee7f49005d3ee1dded652e +%global commit 62c36e2b1ebe3dd0e970dabab6a44f9fc50bdfa2 ## 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. @@ -215,14 +215,6 @@ Url: https://www.clusterlabs.org/ # You can use "spectool -s 0 pacemaker.spec" (rpmdevtools) to show final URL. Source0: https://codeload.github.com/%{github_owner}/%{name}/tar.gz/%{archive_github_url} Source1: https://codeload.github.com/%{github_owner}/%{nagios_name}/tar.gz/%{nagios_archive_github_url} -Patch0: 0001-feature-watchdog-fencing-allow-restriction-to-certai.patch -Patch1: 0002-Fix-watchdog-fencing-Silence-warning-without-node-re.patch -Patch2: 0003-Fix-fence_watchdog-fix-version-output-needed-for-hel.patch -Patch3: 0004-Build-rpm-package-fence_watchdog-in-base-package.patch -Patch6: 0005-Fix-fence_watchdog-fix-malformed-xml-in-metadata.patch -Patch7: 0006-Test-cts-fencing-Add-a-test-for-metadata.patch -Patch8: 0007-Test-cts-fencing-check-metadata-from-fence_dummy-wat.patch -Patch9: 0008-Test-cts-fencing-add-a-few-options-for-tests.patch # upstream commits @@ -277,6 +269,9 @@ BuildRequires: help2man BuildRequires: ncurses-devel BuildRequires: pam-devel +# Required for "make check" +BuildRequires: libcmocka-devel + BuildRequires: pkgconfig(systemd) # RH patches are created by git, so we need git to apply them @@ -301,7 +296,7 @@ Provides: pcmk-cluster-manager%{?_isa} = %{version}-%{release} # Bundled bits ## Pacemaker uses the crypto/md5-buffer module from gnulib %if 0%{?fedora} || 0%{?rhel} -Provides: bundled(gnulib) +Provides: bundled(gnulib) = 20200404 %endif %description @@ -559,10 +554,6 @@ rm -f %{buildroot}/%{_mandir}/man8/fence_legacy.* rm -f %{buildroot}/%{_sbindir}/notifyServicelogEvent rm -f %{buildroot}/%{_sbindir}/ipmiservicelogd -# Don't ship init scripts for systemd based platforms -rm -f %{buildroot}/%{_initrddir}/pacemaker -rm -f %{buildroot}/%{_initrddir}/pacemaker_remote - # Byte-compile Python sources where suitable and the distro procedures known %if %{defined py_byte_compile} %{py_byte_compile %{python_path} %{buildroot}%{_datadir}/pacemaker/tests} @@ -743,7 +734,6 @@ exit 0 %doc %{_mandir}/man8/* %exclude %{_mandir}/man8/crm_attribute.* %exclude %{_mandir}/man8/crm_master.* -%exclude %{_mandir}/man8/fence_legacy.* %exclude %{_mandir}/man8/fence_watchdog.* %exclude %{_mandir}/man8/pacemakerd.* %exclude %{_mandir}/man8/pacemaker-remoted.* @@ -833,6 +823,11 @@ exit 0 %license %{nagios_name}-%{nagios_hash}/COPYING %changelog +* Mon Nov 8 2021 Klaus Wenninger - 2.1.2-0.1.rc1 +- Update for new upstream tarball for release candidate: Pacemaker-2.1.2-rc1, + for full details, see included ChangeLog file or + https://github.com/ClusterLabs/pacemaker/releases/tag/Pacemaker-2.1.2-rc1 + * Wed Sep 15 2021 Klaus Wenninger - 2.1.1-9 - allow xml-testing without rng in cts-fencing - merged in upstream spec-changes diff --git a/sources b/sources index a109919..978774b 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ SHA512 (nagios-agents-metadata-105ab8a7b2c16b9a29cf1c1596b80136eeef332b.tar.gz) = 11ddeb48a4929e7642b6dfa9c7962aa1d7a1af1c569830f55ed6cd6773abac13377317327bc1db8411c8077884f83f81cc54d746c834b63a99fa6dc219b5caad -SHA512 (pacemaker-77db57872.tar.gz) = 37fc0eafd8d3a0342e42b5a3a8eb2b32c24324a859adeed86c997884f667bf8e8bb2d231891c5be3268e78c0d950e9127e7a209fbec6a212c54420fab0c247a2 +SHA512 (pacemaker-62c36e2b1.tar.gz) = 0cffa538a31ed6c74215c8d3dafa7c67df4efc611579e3d09b49c1eba54fd0c4665603eb77b74bea861e2e163830d309683c6d3e320ac29ce0c6707545116950