diff --git a/SOURCES/bz1471182-crypt-1-new-ra.patch b/SOURCES/bz1471182-crypt-1-new-ra.patch new file mode 100644 index 0000000..7ed08b5 --- /dev/null +++ b/SOURCES/bz1471182-crypt-1-new-ra.patch @@ -0,0 +1,415 @@ +From 019c3108feff48d8ad496cd0759349c46170dc2d Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 6 Apr 2020 10:23:51 +0200 +Subject: [PATCH 1/2] crypt: new resource agent + +--- + doc/man/Makefile.am | 1 + + heartbeat/Makefile.am | 1 + + heartbeat/crypt | 337 ++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 339 insertions(+) + create mode 100755 heartbeat/crypt + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index 478fbe4f8..53c9975ec 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -105,6 +105,7 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_azure-lb.7 \ + ocf_heartbeat_clvm.7 \ + ocf_heartbeat_conntrackd.7 \ ++ ocf_heartbeat_crypt.7 \ + ocf_heartbeat_db2.7 \ + ocf_heartbeat_dhcpd.7 \ + ocf_heartbeat_docker.7 \ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index 893115810..bbc9590ac 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -101,6 +101,7 @@ ocf_SCRIPTS = AoEtarget \ + azure-lb \ + clvm \ + conntrackd \ ++ crypt \ + db2 \ + dhcpd \ + dnsupdate \ +diff --git a/heartbeat/crypt b/heartbeat/crypt +new file mode 100755 +index 000000000..6bffdff89 +--- /dev/null ++++ b/heartbeat/crypt +@@ -0,0 +1,337 @@ ++#!/bin/sh ++# ++# crypt/LUKS OCF RA. Manages cryptsetup devices. ++# ++# Copyright (c) 2020 Red Hat GmbH, Heinz Mauelshagen ++# All Rights Reserved. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of version 2 of the GNU General Public License as ++# published by the Free Software Foundation. ++# ++# This program is distributed in the hope that it would be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++# ++# Further, this software is distributed without any warranty that it is ++# free of the rightful claim of any third person regarding infringement ++# or the like. Any license provided herein, whether implied or ++# otherwise, applies only to this software file. Patent licenses, if ++# any, provided herein do not apply to combinations of this program with ++# other software, or any other product whatsoever. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write the Free Software Foundation, ++# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++# ++ ++####################################################################### ++# Initialization: ++ ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++ ++# Parameter defaults ++OCF_RESKEY_encrypted_dev_default="" ++OCF_RESKEY_crypt_dev_default="" ++OCF_RESKEY_key_file_default="" ++OCF_RESKEY_crypt_type_default="" ++OCF_RESKEY_force_stop_default="false" ++ ++: ${OCF_RESKEY_encrypted_dev=${OCF_RESKEY_encrypted_dev_default}} ++: ${OCF_RESKEY_crypt_dev=${OCF_RESKEY_crypt_dev_default}} ++: ${OCF_RESKEY_key_file=${OCF_RESKEY_key_file_default}} ++: ${OCF_RESKEY_crypt_type=${OCF_RESKEY_crypt_type_default}} ++: ${OCF_RESKEY_force_stop=${OCF_RESKEY_force_stop_default}} ++ ++####################################################################### ++ ++meta_data() { ++ cat < ++ ++ ++1.0 ++ ++ ++This is a LUKS/crypt Resource Agent managing encrypted devices via cryptsetup(8). ++The agent imposes limitations on device types supported: luks, luks[1..N]. ++ ++LUKS/crypt resource agent ++ ++ ++ ++ ++ ++Encrypted backing device, which should be defined by UUID, ++36 characters including '-'s as reported by blkid(8). ++ ++Although it can be defined as a block device path (e.g. /dev/sdh), ++the UUID should be preferred over the block device path to allow for the ++unique discovery of the crypt backing device given the volatile nature of ++/dev entries (e.g. /dev/sdh on one node may be /dev/sdg on another). ++ ++Only define as block device path if you know what you are doing. ++ ++Encrypted device ++ ++ ++ ++ ++ ++Encrypted device name, no path. I.e. the one given in "cryptsetup open name ...". ++The resulting block device path is /dev/mapper/name. ++ ++Encrypted device ++ ++ ++ ++ ++ ++Key file path containing the encryption passphrase ++(aka key; see cryptsetup(8)). For LUKS, the passphrase as of the key_file ++parameter is used to decrypt a randomly selected key when the device was created. ++ ++Key file ++ ++ ++ ++ ++ ++Encryption (device) type (e.g. "luks" or "luks2"). ++ ++This parameter affirms the encryption format as of the crypt metadata ++thus allowing for safety measures when starting the encrypted resource. ++ ++Encryption type ++ ++ ++ ++ ++ ++If processes or kernel threads are using the crypt device, it cannot ++be stopped. We will try to stop processes, first by sending TERM and ++then, if that doesn't help in $PROC_CLEANUP_TIME seconds, using KILL. ++The lsof(8) program is required to get the list of array users. ++Of course, the kernel threads cannot be stopped this way. ++If the processes are critical for data integrity, then set this ++parameter to false. Note that in that case the stop operation ++will fail and the node will be fenced. ++ ++force stop processes using the crpyt device ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++# Disable cryptsetup auto-recovery if cloned. ++disable_locks="" ++ocf_is_clone && disable_locks="--disable-locks" ++ ++crypt_usage() { ++ cat </dev/null ++ if [ $? -eq 0 ] && [ -z "$crypt_dev" ]; then ++ ocf_exit_reason "Crypt device \"$crypt_dev\" name has to at least 1 character long and without path" ++ return $OCF_ERR_ARGS ++ fi ++ if [ ! -r "$key_file" ]; then ++ ocf_exit_reason "Hash key file $key_file not accessible" ++ return $OCF_ERR_ARGS ++ fi ++ if ! ocf_is_true "$force_stop" && "$force_stop" != "false" ]]; then ++ ocf_exit_reason "Bogus force_stop=\"$force_stop\" attribute" ++ return $OCF_ERR_CONFIGURED ++ fi ++ if "$force_stop" = "true" && ! have_binary lsof; then ++ ocf_exit_reason "Force stop requested, please install lsof(8)" ++ return $OCF_ERR_INSTALLED ++ fi ++ cryptsetup isLuks $encrypted_dev 2>/dev/null ++ if [ $? -ne 0 ]; then ++ ocf_exit_reason "$encrypted_dev is not a Luks formatted device" ++ return $OCF_ERR_CONFIGURED ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++get_users_pids() { ++ ocf_log debug "running lsof to list \"$crypt_dev\" users..." ++ ocf_run -warn 'lsof $crypt_dev_path | tail -n +2 | awk "{print $2}" | sort -u' ++} ++ ++stop_crypt_users() { ++ local pids=`get_users_pids` ++ ++ if [ -z "$pids" ]; then ++ ocf_log warn "lsof reported no users holding arrays" ++ return 2 ++ fi ++ ++ ocf_stop_processes TERM $PROC_CLEANUP_TIME $pids ++} ++ ++show_users() { ++ local dm_dev ++ ++ ocf_log info "running lsof to list \"$crypt_dev\" users..." ++ ocf_run -warn lsof $crypt_dev_path ++ ++ dm_dev=$(basename $(realpath $crypt_dev_path)) ++ if [ -d /sys/block/$dm_dev/holders ]; then ++ ocf_log debug "ls -l /sys/block/$dm_dev/holders" ++ ocf_run -warn ls -l /sys/block/$dm_dev/holders ++ fi ++} ++ ++crypt_stop_one() { ++ cryptsetup close $crypt_dev $disable_locks ++} ++ ++####################################################################### ++# ++# Action: START an encrypted resource ++# ++crypt_start() { ++ local rc ++ ++ cryptsetup open $encrypted_dev $crypt_dev --type $crypt_type $disable_locks --key-file=$key_file ++ rc=$? ++ if [ $rc -eq 0 ];then ++ crypt_monitor ++ rc=$? ++ else ++ rc=$OCF_ERR_GERNERIC ++ fi ++ [ $rc -ne $OCF_SUCCESS ] ocf_exit_reason "Failed to start encrypted device \"$crypt_dev\"" ++ ++ return $rc ++} ++ ++# ++# Action: STOP an encrypted resource ++# ++crypt_stop() { ++ local rc ++ ++ crypt_monitor ++ rc=$? ++ if [ $rc -ne $OCF_NOT_RUNNING ]; then ++ crypt_stop_one ++ crypt_monitor ++ rc=$? ++ fi ++ if [ $rc -ne $OCF_NOT_RUNNING ] && ocf_is_true $FORCESTOP; then ++ stop_crypt_users ++ case $? in ++ 2) rc=$OCF_SUCCESS;; ++ *) crypt_stop_one ++ crypt_monitor ++ rc=$?;; ++ esac ++ fi ++ if [ $rc -ne $OCF_NOT_RUNNING ]; then ++ ocf_log warn "Couldn't stop crypt device \"$crypt_dev\" (rc=$rc)" ++ show_users ++ ocf_exit_reason "Failed to stop crypt device \"$crypt_dev\"!" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++# ++# Action: MONITOR an encrypted resource ++# ++crypt_monitor() { ++ cryptsetup status $crypt_dev $disable_locks &>/dev/null ++ if [ $? -eq 0 ]; then ++ [ -L $crypt_dev_path ] && return $OCF_SUCCESS ++ return $OCF_ERR_GENERIC ++ fi ++ ++ [ "$__OCF_ACTION" = "monitor" ] && ! ocf_is_probe && ocf_exit_reason "Crypt resource not running" ++ return $OCF_NOT_RUNNING ++} ++ ++# Check for stange argument count. ++if [ $# -ne 1 ]; then ++ usage ++ exit $OCF_ERR_ARGS ++fi ++ ++case "$__OCF_ACTION" in ++meta-data) meta_data ++ exit $OCF_SUCCESS;; ++usage|help) crypt_usage ++ exit $OCF_SUCCESS;; ++esac ++ ++# XME: remove once pacemaker is fixed and calls this action ++crypt_validate_all ++rc=$? ++[ $rc -ne $OCF_SUCCESS ] && exit $rc ++ ++case "$__OCF_ACTION" in ++start) crypt_start; rc=$?;; ++stop) crypt_stop; rc=$?;; ++monitor) crypt_monitor; rc=$?;; ++validate-all) rc=$OCF_SUCCESS;; # crypt_validate_all would have errored out above already. ++*) crypt_usage ++ exit $OCF_ERR_UNIMPLEMENTED;; ++esac ++ ++ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc" ++exit $rc + +From 5e0d35f8db967419ea9f1234ab621b88babcf3ea Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 7 Apr 2020 12:39:24 +0200 +Subject: [PATCH 2/2] crypt: force_stop check fixes + +--- + heartbeat/crypt | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/heartbeat/crypt b/heartbeat/crypt +index 6bffdff89..8bfa1094d 100755 +--- a/heartbeat/crypt ++++ b/heartbeat/crypt +@@ -190,11 +190,7 @@ crypt_validate_all() { + ocf_exit_reason "Hash key file $key_file not accessible" + return $OCF_ERR_ARGS + fi +- if ! ocf_is_true "$force_stop" && "$force_stop" != "false" ]]; then +- ocf_exit_reason "Bogus force_stop=\"$force_stop\" attribute" +- return $OCF_ERR_CONFIGURED +- fi +- if "$force_stop" = "true" && ! have_binary lsof; then ++ if ocf_is_true "$force_stop" && ! have_binary lsof; then + ocf_exit_reason "Force stop requested, please install lsof(8)" + return $OCF_ERR_INSTALLED + fi +@@ -273,7 +269,7 @@ crypt_stop() { + crypt_monitor + rc=$? + fi +- if [ $rc -ne $OCF_NOT_RUNNING ] && ocf_is_true $FORCESTOP; then ++ if [ $rc -ne $OCF_NOT_RUNNING ] && ocf_is_true $force_stop; then + stop_crypt_users + case $? in + 2) rc=$OCF_SUCCESS;; diff --git a/SOURCES/bz1471182-crypt-2-fix-bashism.patch b/SOURCES/bz1471182-crypt-2-fix-bashism.patch new file mode 100644 index 0000000..dace36f --- /dev/null +++ b/SOURCES/bz1471182-crypt-2-fix-bashism.patch @@ -0,0 +1,22 @@ +From 2915fa336e95b609d3d738d335799f015022c493 Mon Sep 17 00:00:00 2001 +From: Valentin Vidic +Date: Sat, 13 Jun 2020 08:47:36 +0200 +Subject: [PATCH] crypt: fix bashism + +--- + heartbeat/crypt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/crypt b/heartbeat/crypt +index 8bfa1094d..2727b5b23 100755 +--- a/heartbeat/crypt ++++ b/heartbeat/crypt +@@ -292,7 +292,7 @@ crypt_stop() { + # Action: MONITOR an encrypted resource + # + crypt_monitor() { +- cryptsetup status $crypt_dev $disable_locks &>/dev/null ++ cryptsetup status $crypt_dev $disable_locks >/dev/null 2>&1 + if [ $? -eq 0 ]; then + [ -L $crypt_dev_path ] && return $OCF_SUCCESS + return $OCF_ERR_GENERIC diff --git a/SOURCES/bz1471182-crypt-3-fix-missing-and.patch b/SOURCES/bz1471182-crypt-3-fix-missing-and.patch new file mode 100644 index 0000000..8a0deaf --- /dev/null +++ b/SOURCES/bz1471182-crypt-3-fix-missing-and.patch @@ -0,0 +1,22 @@ +From 635c344fb85ef225b8a0c094687d2838b0b0cd2c Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 26 Oct 2020 16:36:06 +0100 +Subject: [PATCH] crypt: fix missing && to set exit_reason + +--- + heartbeat/crypt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/crypt b/heartbeat/crypt +index 2727b5b23..0e49b6c2d 100755 +--- a/heartbeat/crypt ++++ b/heartbeat/crypt +@@ -251,7 +251,7 @@ crypt_start() { + else + rc=$OCF_ERR_GERNERIC + fi +- [ $rc -ne $OCF_SUCCESS ] ocf_exit_reason "Failed to start encrypted device \"$crypt_dev\"" ++ [ $rc -ne $OCF_SUCCESS ] && ocf_exit_reason "Failed to start encrypted device \"$crypt_dev\"" + + return $rc + } diff --git a/SOURCES/bz1640587-pgsql-ignore-masters-re-promote.patch b/SOURCES/bz1640587-pgsql-ignore-masters-re-promote.patch new file mode 100644 index 0000000..b371857 --- /dev/null +++ b/SOURCES/bz1640587-pgsql-ignore-masters-re-promote.patch @@ -0,0 +1,40 @@ +From 355cd29f2dee828bfe0a4ab64f425827aba7dd3b Mon Sep 17 00:00:00 2001 +From: Hideo Yamauchi +Date: Wed, 17 Oct 2018 09:54:37 +0900 +Subject: [PATCH] Mid: pgsql: Fix to ignore Master's re-promote. + +--- + heartbeat/pgsql | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/heartbeat/pgsql b/heartbeat/pgsql +index 380866da1..38f6ceeb7 100755 +--- a/heartbeat/pgsql ++++ b/heartbeat/pgsql +@@ -680,6 +680,7 @@ pgsql_start() { + + #pgsql_promote: Promote PostgreSQL + pgsql_promote() { ++ local output + local target + local rc + +@@ -687,6 +688,18 @@ pgsql_promote() { + ocf_exit_reason "Not in a replication mode." + return $OCF_ERR_CONFIGURED + fi ++ ++ output=`exec_sql "${CHECK_MS_SQL}"` ++ if [ $? -ne 0 ]; then ++ report_psql_error $rc $loglevel "Can't get PostgreSQL recovery status on promote." ++ return $OCF_ERR_GENERIC ++ fi ++ ++ if [ "$output" = "f" ]; then ++ ocf_log info "PostgreSQL is alredy Master. Don't execute promote." ++ return $OCF_SUCCESS ++ fi ++ + rm -f ${XLOG_NOTE_FILE}.* + + for target in $NODE_LIST; do diff --git a/SOURCES/bz1763249-manpages-fix-pcs-syntax.patch b/SOURCES/bz1763249-manpages-fix-pcs-syntax.patch new file mode 100644 index 0000000..eff376b --- /dev/null +++ b/SOURCES/bz1763249-manpages-fix-pcs-syntax.patch @@ -0,0 +1,53 @@ +From 0903a60930238238d5caa6c3b42b28d7bc4cccf4 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 26 Oct 2020 13:11:05 +0100 +Subject: [PATCH 1/2] man: use promotable keyword in manpage examples + +--- + doc/man/ra2refentry.xsl | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/doc/man/ra2refentry.xsl b/doc/man/ra2refentry.xsl +index d0535fd36..f3cdcdbb2 100644 +--- a/doc/man/ra2refentry.xsl ++++ b/doc/man/ra2refentry.xsl +@@ -556,7 +556,7 @@ + + +- --master ++ promotable + + + + +From bfcd5796ae12e6a43a245d0c785f183342943393 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 26 Oct 2020 16:56:00 +0100 +Subject: [PATCH 2/2] man: use OCF_CHECK_LEVEL for depth parameters in pcs + examples + +--- + doc/man/ra2refentry.xsl | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/doc/man/ra2refentry.xsl b/doc/man/ra2refentry.xsl +index f3cdcdbb2..f8e12321f 100644 +--- a/doc/man/ra2refentry.xsl ++++ b/doc/man/ra2refentry.xsl +@@ -612,7 +612,14 @@ + + + +- ++ ++ ++ ++ ++ ++ OCF_CHECK_LEVEL ++ ++ + =" + + " diff --git a/SOURCES/bz1795535-pgsql-1-add-postgresql-12-support.patch b/SOURCES/bz1795535-pgsql-1-add-postgresql-12-support.patch new file mode 100644 index 0000000..3c05aba --- /dev/null +++ b/SOURCES/bz1795535-pgsql-1-add-postgresql-12-support.patch @@ -0,0 +1,105 @@ +From a43075be72683e1d4ddab700ec16d667164d359c Mon Sep 17 00:00:00 2001 +From: Kazutomo Nakahira +Date: Mon, 25 Nov 2019 17:40:33 +0900 +Subject: [PATCH 1/2] High: pgsql: Support for PostgreSQL 12 + +--- + heartbeat/pgsql | 32 +++++++++++++++++++++++++++++++- + 1 file changed, 31 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/pgsql b/heartbeat/pgsql +index b1c070ead..5bc76cc4c 100755 +--- a/heartbeat/pgsql ++++ b/heartbeat/pgsql +@@ -1612,12 +1612,24 @@ make_recovery_conf() { + fi + + cat > $RECOVERY_CONF <> $RECOVERY_CONF <> $RECOVERY_CONF + ocf_log debug "Created recovery.conf. host=${OCF_RESKEY_master_ip}, user=${OCF_RESKEY_repuser}" + return 0 +@@ -1835,6 +1847,7 @@ pgsql_validate_all() { + local version + local check_config_rc + local rep_mode_string ++ local recovery_conf_string + local socket_directories + local rc + +@@ -1898,6 +1911,22 @@ pgsql_validate_all() { + ocf_exit_reason "Replication mode needs PostgreSQL 9.1 or higher." + return $OCF_ERR_INSTALLED + fi ++ ocf_version_cmp "$version" "12" ++ rc=$? ++ if [ $rc -eq 1 ]||[ $rc -eq 2 ]; then ++ # change the standby method for PosrgreSQL 12 or later. ++ USE_STANDBY_SIGNAL=true ++ # change the path to recovery.conf because it cause PostgreSQL start error. ++ RECOVERY_CONF=${OCF_RESKEY_tmpdir}/recovery.conf ++ if [ $check_config_rc -eq 0 ]; then ++ # adding recovery parameters to postgresql.conf. ++ recovery_conf_string="include '$RECOVERY_CONF' # added by pgsql RA" ++ if ! grep -q "^[[:space:]]*$recovery_conf_string" $OCF_RESKEY_config; then ++ ocf_log info "adding include directive $recovery_conf_string into $OCF_RESKEY_config" ++ echo "$recovery_conf_string" >> $OCF_RESKEY_config ++ fi ++ fi ++ fi + if [ ! -n "$OCF_RESKEY_master_ip" ]; then + ocf_exit_reason "master_ip can't be empty." + return $OCF_ERR_CONFIGURED +@@ -2107,6 +2136,7 @@ RESOURCE_NAME=`echo $OCF_RESOURCE_INSTANCE | cut -d ":" -f 1` + PGSQL_WAL_RECEIVER_STATUS_ATTR="${RESOURCE_NAME}-receiver-status" + RECOVERY_CONF=${OCF_RESKEY_pgdata}/recovery.conf + NODENAME=$(ocf_local_nodename | tr '[A-Z]' '[a-z]') ++USE_STANDBY_SIGNAL=false + + case "$1" in + methods) pgsql_methods + +From 5ab3339e8cb236583d375f5577f5a4dc129d5b27 Mon Sep 17 00:00:00 2001 +From: munenari +Date: Thu, 16 Jan 2020 09:27:59 +0900 +Subject: [PATCH 2/2] Remove standby.signal when promote with restart + +--- + heartbeat/pgsql | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/pgsql b/heartbeat/pgsql +index 5bc76cc4c..d5baa7b35 100755 +--- a/heartbeat/pgsql ++++ b/heartbeat/pgsql +@@ -720,7 +720,11 @@ pgsql_promote() { + ocf_log info "Restarting PostgreSQL instead of promote." + #stop : this function returns $OCF_SUCCESS only. + pgsql_real_stop slave +- rm -f $RECOVERY_CONF ++ if "${USE_STANDBY_SIGNAL}"; then ++ rm -f ${OCF_RESKEY_pgdata}/standby.signal ++ else ++ rm -f $RECOVERY_CONF ++ fi + pgsql_real_start + rc=$? + if [ $rc -ne $OCF_RUNNING_MASTER ]; then diff --git a/SOURCES/bz1795535-pgsql-2-fix-uppercase-hostname-support.patch b/SOURCES/bz1795535-pgsql-2-fix-uppercase-hostname-support.patch new file mode 100644 index 0000000..06c9aef --- /dev/null +++ b/SOURCES/bz1795535-pgsql-2-fix-uppercase-hostname-support.patch @@ -0,0 +1,48 @@ +From e56d0e1727bf84d0664db544a129a0237a1757c0 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 11 Sep 2020 10:12:21 +0200 +Subject: [PATCH 1/2] pgsql: lower-case application_name to avoid issues with + upper-case hostnames + +--- + heartbeat/pgsql | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/pgsql b/heartbeat/pgsql +index 99e074287..de9f750c5 100755 +--- a/heartbeat/pgsql ++++ b/heartbeat/pgsql +@@ -1960,7 +1960,7 @@ pgsql_validate_all() { + else + CHECK_XLOG_LOC_SQL="select pg_last_xlog_replay_location(),pg_last_xlog_receive_location()" + fi +- CHECK_REPLICATION_STATE_SQL="select application_name,upper(state),upper(sync_state) from pg_stat_replication" ++ CHECK_REPLICATION_STATE_SQL="select lower(application_name),upper(state),upper(sync_state) from pg_stat_replication" + + PGSQL_STATUS_ATTR="${RESOURCE_NAME}-status" + PGSQL_DATA_STATUS_ATTR="${RESOURCE_NAME}-data-status" + +From 5aee799878180bb8daca82aebc2290c2735045eb Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 11 Sep 2020 10:13:47 +0200 +Subject: [PATCH 2/2] pgsql: set exit-reason when failing due to remaining + PGSQL.lock + +--- + heartbeat/pgsql | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/heartbeat/pgsql b/heartbeat/pgsql +index de9f750c5..5a0628b7a 100755 +--- a/heartbeat/pgsql ++++ b/heartbeat/pgsql +@@ -966,6 +966,9 @@ pgsql_real_monitor() { + if ! pgsql_status + then + ocf_log info "PostgreSQL is down" ++ if [ "$__OCF_ACTION" = "monitor" ] && ! ocf_is_probe && [ -f $PGSQL_LOCK ]; then ++ ocf_exit_reason "My data may be inconsistent. You have to remove $PGSQL_LOCK file to force start." ++ fi + return $OCF_NOT_RUNNING + fi + diff --git a/SOURCES/bz1815013-redis-parse-password-correctly-based-on-version.patch b/SOURCES/bz1815013-redis-parse-password-correctly-based-on-version.patch new file mode 100644 index 0000000..c61a306 --- /dev/null +++ b/SOURCES/bz1815013-redis-parse-password-correctly-based-on-version.patch @@ -0,0 +1,169 @@ +From 2270c5d6aaf8b3b6d663d413a8e7193a493cfdc5 Mon Sep 17 00:00:00 2001 +From: Konstantin Pokotilenko +Date: Tue, 24 Sep 2019 17:26:11 +0300 +Subject: [PATCH 1/2] Consider redis-cli features to choose optimal password + passing method and warning filtering workaround + +--- + heartbeat/redis.in | 60 +++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 57 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/redis.in b/heartbeat/redis.in +index ec7186d8b..409961d0b 100644 +--- a/heartbeat/redis.in ++++ b/heartbeat/redis.in +@@ -237,6 +237,51 @@ CRM_ATTR_REPL_INFO="${HA_SBIN_DIR}/crm_attribute --type crm_config --name ${INST + MASTER_HOST="" + MASTER_ACTIVE_CACHED="" + MASTER_ACTIVE="" ++CLI_HAVE_AUTH_WARNING=0 ++CLI_HAVE_ARG_NO_AUTH_WARNING=0 ++CLI_HAVE_ENV_AUTH=0 ++ ++cmp_redis_version() ++{ ++ ++ if [ "$1" == "$2" ]; then ++ return 1 ++ elif [ $(echo -e "$1\n$2" | sort -V | head -1) == "$1" ]; then ++ return 0 ++ else ++ return 2 ++ fi ++} ++ ++redis_cli_features() ++{ ++ ++ CLI_VER=$(redis-cli --version | tr " " "\n" | tail -1) ++ # Starting with 4.0.10 there is a warning on stderr when using a pass ++ # Starting with 5.0.0 there is an argument to silence the warning: --no-auth-warning ++ # Starting with 5.0.3 there is an option to use REDISCLI_AUTH evironment variable for password, no warning in this case ++ ++ cmp_redis_version $CLI_VER 5.0.3 ++ res=$? ++ echo 5.0.3: $res ++ if [[ res -ge 1 ]]; then ++ CLI_HAVE_ENV_AUTH=1 ++ fi ++ ++ cmp_redis_version $CLI_VER 5.0.0 ++ res=$? ++ echo 5.0.0: $res ++ if [[ res -ge 1 ]]; then ++ CLI_HAVE_ARG_NO_AUTH_WARNING=1 ++ fi ++ ++ cmp_redis_version $CLI_VER 4.0.10 ++ res=$? ++ echo 4.0.10: $res ++ if [[ res -ge 1 ]]; then ++ CLI_HAVE_AUTH_WARNING=1 ++ fi ++} + + master_is_active() + { +@@ -315,9 +360,16 @@ set_score() + redis_client() { + ocf_log debug "redis_client: '$REDIS_CLIENT' -s '$REDIS_SOCKET' $*" + if [ -n "$clientpasswd" ]; then +- # Starting with 4.0.10 there is a warning on stderr when using a pass +- # Once we stop supporting versions < 5.0.0 we can add --no-auth-warning here +- ("$REDIS_CLIENT" -s "$REDIS_SOCKET" -a "$clientpasswd" "$@" 2>&1 >&3 3>&- | grep -v "Using a password" >&2 3>&-) 3>&1 | sed 's/\r//' ++ # Consider redis-cli features to choose optimal password passing method and warning filtering workaround ++ if [[ CLI_HAVE_ENV_AUTH -eq 1 ]]; then ++ REDISCLI_AUTH=$clientpasswd "$REDIS_CLIENT" -s "$REDIS_SOCKET" "$@" | sed 's/\r//' ++ elif [[ CLI_HAVE_ARG_NO_AUTH_WARNING -eq 1 ]]; then ++ "$REDIS_CLIENT" -s "$REDIS_SOCKET" -a "$clientpasswd" "$@" --no-auth-warning | sed 's/\r//' ++ elif [[ CLI_HAVE_AUTH_WARNING -eq 1 ]]; then ++ ("$REDIS_CLIENT" -s "$REDIS_SOCKET" -a "$clientpasswd" "$@" 2>&1 >&3 3>&- | grep -v "Using a password" >&2 3>&-) 3>&1 | sed 's/\r//' ++ else ++ "$REDIS_CLIENT" -s "$REDIS_SOCKET" -a "$clientpasswd" "$@" | sed 's/\r//' ++ fi + else + "$REDIS_CLIENT" -s "$REDIS_SOCKET" "$@" | sed 's/\r//' + fi +@@ -686,6 +738,8 @@ if [ -r "$REDIS_CONFIG" ]; then + clientpasswd="$(sed -n -e 's/^\s*requirepass\s*\(.*\)\s*$/\1/p' < $REDIS_CONFIG | tail -n 1)" + fi + ++redis_cli_features ++ + ocf_log debug "action=${1:-$__OCF_ACTION} notify_type=${OCF_RESKEY_CRM_meta_notify_type} notify_operation=${OCF_RESKEY_CRM_meta_notify_operation} master_host=${OCF_RESKEY_CRM_meta_notify_master_uname} slave_host=${OCF_RESKEY_CRM_meta_notify_slave_uname} promote_host=${OCF_RESKEY_CRM_meta_notify_promote_uname} demote_host=${OCF_RESKEY_CRM_meta_notify_demote_uname}; params: bin=${OCF_RESKEY_bin} client_bin=${OCF_RESKEY_client_bin} config=${OCF_RESKEY_config} user=${OCF_RESKEY_user} rundir=${OCF_RESKEY_rundir} port=${OCF_RESKEY_port}" + + case "${1:-$__OCF_ACTION}" in + +From 0b9f942a88bfc3ad04938aa5135fad8f8bece69c Mon Sep 17 00:00:00 2001 +From: Konstantin Pokotilenko +Date: Tue, 24 Sep 2019 18:35:59 +0300 +Subject: [PATCH 2/2] use ocf_version_cmp instead of own implementation use + same method of getting redis-cli version as already used before in file, this + also uses redis client from variable instead of hardcoded remove debug output + fix --no-auth-warning argument position + +--- + heartbeat/redis.in | 25 +++++-------------------- + 1 file changed, 5 insertions(+), 20 deletions(-) + +diff --git a/heartbeat/redis.in b/heartbeat/redis.in +index 409961d0b..d722fb12c 100644 +--- a/heartbeat/redis.in ++++ b/heartbeat/redis.in +@@ -241,43 +241,28 @@ CLI_HAVE_AUTH_WARNING=0 + CLI_HAVE_ARG_NO_AUTH_WARNING=0 + CLI_HAVE_ENV_AUTH=0 + +-cmp_redis_version() +-{ +- +- if [ "$1" == "$2" ]; then +- return 1 +- elif [ $(echo -e "$1\n$2" | sort -V | head -1) == "$1" ]; then +- return 0 +- else +- return 2 +- fi +-} +- + redis_cli_features() + { + +- CLI_VER=$(redis-cli --version | tr " " "\n" | tail -1) ++ CLI_VER=$("$REDIS_CLIENT" -v | awk '{print $NF}') + # Starting with 4.0.10 there is a warning on stderr when using a pass + # Starting with 5.0.0 there is an argument to silence the warning: --no-auth-warning + # Starting with 5.0.3 there is an option to use REDISCLI_AUTH evironment variable for password, no warning in this case + +- cmp_redis_version $CLI_VER 5.0.3 ++ ocf_version_cmp $CLI_VER 5.0.3 + res=$? +- echo 5.0.3: $res + if [[ res -ge 1 ]]; then + CLI_HAVE_ENV_AUTH=1 + fi + +- cmp_redis_version $CLI_VER 5.0.0 ++ ocf_version_cmp $CLI_VER 5.0.0 + res=$? +- echo 5.0.0: $res + if [[ res -ge 1 ]]; then + CLI_HAVE_ARG_NO_AUTH_WARNING=1 + fi + +- cmp_redis_version $CLI_VER 4.0.10 ++ ocf_version_cmp $CLI_VER 4.0.10 + res=$? +- echo 4.0.10: $res + if [[ res -ge 1 ]]; then + CLI_HAVE_AUTH_WARNING=1 + fi +@@ -364,7 +349,7 @@ redis_client() { + if [[ CLI_HAVE_ENV_AUTH -eq 1 ]]; then + REDISCLI_AUTH=$clientpasswd "$REDIS_CLIENT" -s "$REDIS_SOCKET" "$@" | sed 's/\r//' + elif [[ CLI_HAVE_ARG_NO_AUTH_WARNING -eq 1 ]]; then +- "$REDIS_CLIENT" -s "$REDIS_SOCKET" -a "$clientpasswd" "$@" --no-auth-warning | sed 's/\r//' ++ "$REDIS_CLIENT" -s "$REDIS_SOCKET" --no-auth-warning -a "$clientpasswd" "$@" | sed 's/\r//' + elif [[ CLI_HAVE_AUTH_WARNING -eq 1 ]]; then + ("$REDIS_CLIENT" -s "$REDIS_SOCKET" -a "$clientpasswd" "$@" 2>&1 >&3 3>&- | grep -v "Using a password" >&2 3>&-) 3>&1 | sed 's/\r//' + else diff --git a/SOURCES/bz1818997-3-nfsserver-nfsnotify-fix-selinux-label-issue.patch b/SOURCES/bz1818997-3-nfsserver-nfsnotify-fix-selinux-label-issue.patch new file mode 100644 index 0000000..e470d50 --- /dev/null +++ b/SOURCES/bz1818997-3-nfsserver-nfsnotify-fix-selinux-label-issue.patch @@ -0,0 +1,48 @@ +From dbd45cb5fcce0a3378f6ecd0c14b578e6f843e3d Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 24 Jul 2020 16:03:20 +0200 +Subject: [PATCH 1/2] nfsserver: fix SELinux issue due to newer ls versions + giving additional output. + +This patch has been tested on RHEL6, 7 and 8. +--- + heartbeat/nfsserver | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/nfsserver b/heartbeat/nfsserver +index 0dbc173f3..80d20676b 100755 +--- a/heartbeat/nfsserver ++++ b/heartbeat/nfsserver +@@ -192,7 +192,7 @@ fi + which restorecon > /dev/null 2>&1 && selinuxenabled + SELINUX_ENABLED=$? + if [ $SELINUX_ENABLED -eq 0 ]; then +- export SELINUX_LABEL="$(ls -ldZ $STATD_PATH | cut -f4 -d' ')" ++ export SELINUX_LABEL="$(ls -dZ $STATD_PATH | grep -o '\S\+:\S\+:\S\+')" + fi + + ## + +From 81118dbb25fe2cfc7d5fc803178cd7c3b445915e Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 27 Jul 2020 10:33:44 +0200 +Subject: [PATCH 2/2] nfsnotify: fix SELinux issue due to newer ls versions + giving additional output. + +--- + heartbeat/nfsnotify.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/nfsnotify.in b/heartbeat/nfsnotify.in +index 7f710bca7..851f6ad6b 100644 +--- a/heartbeat/nfsnotify.in ++++ b/heartbeat/nfsnotify.in +@@ -305,7 +305,7 @@ esac + which restorecon > /dev/null 2>&1 && selinuxenabled + SELINUX_ENABLED=$? + if [ $SELINUX_ENABLED -eq 0 ]; then +- export SELINUX_LABEL="$(ls -ldZ $STATD_PATH | cut -f4 -d' ')" ++ export SELINUX_LABEL="$(ls -dZ $STATD_PATH | grep -o '\S\+:\S\+:\S\+')" + fi + + case $__OCF_ACTION in diff --git a/SOURCES/bz1818997-nfsserver-1-fix-nfsv4-only-support.patch b/SOURCES/bz1818997-nfsserver-1-fix-nfsv4-only-support.patch new file mode 100644 index 0000000..b3efdce --- /dev/null +++ b/SOURCES/bz1818997-nfsserver-1-fix-nfsv4-only-support.patch @@ -0,0 +1,43 @@ +From 47dd1d16f08de06d512f9e04c3966c35f0ac4d3f Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 27 May 2020 13:05:57 +0200 +Subject: [PATCH] nfsserver: fix NFSv4-only support + +When disabling NFSv2 and NFSv3 mountd doesnt register with rpcbind, but +it's still running. This patch checks that mountd is running instead of +basing its status on it being registered w/rpcbind. +--- + heartbeat/nfsserver | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/nfsserver b/heartbeat/nfsserver +index acef0147a..9e6e1fcb1 100755 +--- a/heartbeat/nfsserver ++++ b/heartbeat/nfsserver +@@ -316,7 +316,7 @@ nfsserver_systemd_monitor() + fi + + ocf_log debug "Status: nfs-mountd" +- rpcinfo -t localhost 100005 > /dev/null 2>&1 ++ ps axww | grep -q "[r]pc.mountd" + rc=$? + if [ "$rc" -ne "0" ]; then + ocf_exit_reason "nfs-mountd is not running" +@@ -683,7 +683,7 @@ nfsserver_start () + local i=1 + while : ; do + ocf_log info "Start: nfs-mountd i: $i" +- rpcinfo -t localhost 100005 > /dev/null 2>&1 ++ ps axww | grep -q "[r]pc.mountd" + rc=$? + if [ "$rc" -eq "0" ]; then + break; +@@ -800,7 +800,7 @@ nfsserver_stop () + + nfs_exec stop nfs-mountd > /dev/null 2>&1 + ocf_log info "Stop: nfs-mountd" +- rpcinfo -t localhost 100005 > /dev/null 2>&1 ++ ps axww | grep -q "[r]pc.mountd" + rc=$? + if [ "$rc" -eq "0" ]; then + ocf_exit_reason "Failed to stop nfs-mountd" diff --git a/SOURCES/bz1818997-nfsserver-2-stop-nfsdcld-if-present.patch b/SOURCES/bz1818997-nfsserver-2-stop-nfsdcld-if-present.patch new file mode 100644 index 0000000..085a39a --- /dev/null +++ b/SOURCES/bz1818997-nfsserver-2-stop-nfsdcld-if-present.patch @@ -0,0 +1,34 @@ +From 290741f43ff414630f558ee3432e830e39d1599d Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 22 Jul 2020 11:56:32 +0200 +Subject: [PATCH] nfsserver: stop nfsdcld if present during stop-action + +--- + heartbeat/nfsserver | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/heartbeat/nfsserver b/heartbeat/nfsserver +index 9e6e1fcb1..0dbc173f3 100755 +--- a/heartbeat/nfsserver ++++ b/heartbeat/nfsserver +@@ -806,6 +806,20 @@ nfsserver_stop () + ocf_exit_reason "Failed to stop nfs-mountd" + return $OCF_ERR_GENERIC + fi ++ ++ if systemctl --no-legend list-unit-files "nfsdcld*" | grep -q nfsdcld; then ++ nfs_exec stop nfsdcld > /dev/null 2>&1 ++ ocf_log info "Stop: nfsdcld" ++ fn=`mktemp` ++ nfs_exec status nfsdcld > $fn 2>&1 ++ rc=$? ++ ocf_log debug "$(cat $fn)" ++ rm -f $fn ++ if [ "$rc" -eq "0" ]; then ++ ocf_exit_reason "Failed to stop nfsdcld" ++ return $OCF_ERR_GENERIC ++ fi ++ fi + esac + + diff --git a/SOURCES/bz1818997-nfsserver-fix-nfsv4-only-support.patch b/SOURCES/bz1818997-nfsserver-fix-nfsv4-only-support.patch deleted file mode 100644 index b3efdce..0000000 --- a/SOURCES/bz1818997-nfsserver-fix-nfsv4-only-support.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 47dd1d16f08de06d512f9e04c3966c35f0ac4d3f Mon Sep 17 00:00:00 2001 -From: Oyvind Albrigtsen -Date: Wed, 27 May 2020 13:05:57 +0200 -Subject: [PATCH] nfsserver: fix NFSv4-only support - -When disabling NFSv2 and NFSv3 mountd doesnt register with rpcbind, but -it's still running. This patch checks that mountd is running instead of -basing its status on it being registered w/rpcbind. ---- - heartbeat/nfsserver | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/heartbeat/nfsserver b/heartbeat/nfsserver -index acef0147a..9e6e1fcb1 100755 ---- a/heartbeat/nfsserver -+++ b/heartbeat/nfsserver -@@ -316,7 +316,7 @@ nfsserver_systemd_monitor() - fi - - ocf_log debug "Status: nfs-mountd" -- rpcinfo -t localhost 100005 > /dev/null 2>&1 -+ ps axww | grep -q "[r]pc.mountd" - rc=$? - if [ "$rc" -ne "0" ]; then - ocf_exit_reason "nfs-mountd is not running" -@@ -683,7 +683,7 @@ nfsserver_start () - local i=1 - while : ; do - ocf_log info "Start: nfs-mountd i: $i" -- rpcinfo -t localhost 100005 > /dev/null 2>&1 -+ ps axww | grep -q "[r]pc.mountd" - rc=$? - if [ "$rc" -eq "0" ]; then - break; -@@ -800,7 +800,7 @@ nfsserver_stop () - - nfs_exec stop nfs-mountd > /dev/null 2>&1 - ocf_log info "Stop: nfs-mountd" -- rpcinfo -t localhost 100005 > /dev/null 2>&1 -+ ps axww | grep -q "[r]pc.mountd" - rc=$? - if [ "$rc" -eq "0" ]; then - ocf_exit_reason "Failed to stop nfs-mountd" diff --git a/SOURCES/bz1819965-3-azure-events-decode-when-type-not-str.patch b/SOURCES/bz1819965-3-azure-events-decode-when-type-not-str.patch new file mode 100644 index 0000000..3c62631 --- /dev/null +++ b/SOURCES/bz1819965-3-azure-events-decode-when-type-not-str.patch @@ -0,0 +1,59 @@ +From 57424bd1f158f1ff597034e09ca90da864925a16 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 16 Jul 2020 09:58:55 +0200 +Subject: [PATCH] azure-events: only decode() when exec() output not of type + str + +--- + heartbeat/azure-events.in | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/heartbeat/azure-events.in b/heartbeat/azure-events.in +index a48a86309..d4a166d9f 100644 +--- a/heartbeat/azure-events.in ++++ b/heartbeat/azure-events.in +@@ -179,6 +179,8 @@ class clusterHelper: + ocf.logger.debug("_exec: cmd = %s" % " ".join(command)) + try: + ret = subprocess.check_output(command) ++ if type(ret) != str: ++ ret = ret.decode() + ocf.logger.debug("_exec: return = %s" % ret) + return ret.rstrip() + except Exception as err: +@@ -232,7 +234,7 @@ class clusterHelper: + + nodes = [] + nodeList = clusterHelper._exec("crm_node", "--list") +- for n in nodeList.decode().split("\n"): ++ for n in nodeList.split("\n"): + nodes.append(n.split()[1]) + ocf.logger.debug("getAllNodes: finished; return %s" % str(nodes)) + +@@ -303,7 +305,7 @@ class clusterHelper: + ocf.logger.warning("transitionSummary: received unexpected transition summary: %s" % summary) + return False + summary = summary.split("Transition Summary:")[1] +- ret = summary.decode().split("\n").pop(0) ++ ret = summary.split("\n").pop(0) + + ocf.logger.debug("transitionSummary: finished; return = %s" % str(ret)) + return ret +@@ -324,7 +326,7 @@ class clusterHelper: + if len(resources) == 0: + ret = [] + else: +- ret = resources.decode().split("\n") ++ ret = resources.split("\n") + + ocf.logger.debug("listOperationsOnNode: finished; return = %s" % str(ret)) + return ret +@@ -470,7 +472,7 @@ class Node: + + eventIDStr = clusterHelper.getAttr(attr_pendingEventIDs, node=node) + if eventIDStr: +- eventIDs = eventIDStr.decode().split(",") ++ eventIDs = eventIDStr.split(",") + else: + eventIDs = None + diff --git a/SOURCES/bz1845574-azure-events-1-handle-exceptions-in-urlopen.patch b/SOURCES/bz1845574-azure-events-1-handle-exceptions-in-urlopen.patch new file mode 100644 index 0000000..fa194c9 --- /dev/null +++ b/SOURCES/bz1845574-azure-events-1-handle-exceptions-in-urlopen.patch @@ -0,0 +1,70 @@ +From 194909ff08cfe75cd5da9f704d8ed4cc9ab40341 Mon Sep 17 00:00:00 2001 +From: Gustavo Figueira +Date: Tue, 19 May 2020 10:58:34 +0200 +Subject: [PATCH 1/2] azure-events: handle exceptions in urlopen The locking in + azure-events does not correctly handle some failures. + +If the metadata server is not recheable or has an error +handling the request, attr_globalPullState will never go +back to IDLE unless the administrator manually changes it. + +> azure-events: ERROR: [Errno 104] Connection reset by peer +> lrmd[2734]: notice: rsc_azure-events_monitor_10000:113088:stderr [ ocf-exit-reason:[Errno 104] Connection reset by peer ] +--- + heartbeat/azure-events.in | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/azure-events.in b/heartbeat/azure-events.in +index 8709d97e3..bd812f4b2 100644 +--- a/heartbeat/azure-events.in ++++ b/heartbeat/azure-events.in +@@ -82,9 +82,19 @@ class azHelper: + req = urllib2.Request(url, postData) + req.add_header("Metadata", "true") + req.add_header("User-Agent", USER_AGENT) +- resp = urllib2.urlopen(req) +- data = resp.read() +- ocf.logger.debug("_sendMetadataRequest: response = %s" % data) ++ try: ++ resp = urllib2.urlopen(req) ++ except URLError as e: ++ if hasattr(e, 'reason'): ++ print('We failed to reach a server. Reason: '), e.reason ++ clusterHelper.setAttr(attr_globalPullState, "IDLE") ++ elif hasattr(e, 'code'): ++ print('The server couldn\'t fulfill the request. Error code: '), e.code ++ clusterHelper.setAttr(attr_globalPullState, "IDLE") ++ else: ++ data = resp.read() ++ ocf.logger.debug("_sendMetadataRequest: response = %s" % data) ++ + if data: + data = json.loads(data) + + +From c4071ec4a82fcb831f170f341e0790633e4b904f Mon Sep 17 00:00:00 2001 +From: Gustavo Figueira +Date: Tue, 19 May 2020 12:53:22 +0200 +Subject: [PATCH 2/2] azure-events: use ocf.logger.warning instead of print + +--- + heartbeat/azure-events.in | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/azure-events.in b/heartbeat/azure-events.in +index bd812f4b2..a48a86309 100644 +--- a/heartbeat/azure-events.in ++++ b/heartbeat/azure-events.in +@@ -86,10 +86,10 @@ class azHelper: + resp = urllib2.urlopen(req) + except URLError as e: + if hasattr(e, 'reason'): +- print('We failed to reach a server. Reason: '), e.reason ++ ocf.logger.warning("Failed to reach the server: %s" % e.reason) + clusterHelper.setAttr(attr_globalPullState, "IDLE") + elif hasattr(e, 'code'): +- print('The server couldn\'t fulfill the request. Error code: '), e.code ++ ocf.logger.warning("The server couldn\'t fulfill the request. Error code: %s" % e.code) + clusterHelper.setAttr(attr_globalPullState, "IDLE") + else: + data = resp.read() diff --git a/SOURCES/bz1845574-azure-events-2-import-urlerror-encode-postdata.patch b/SOURCES/bz1845574-azure-events-2-import-urlerror-encode-postdata.patch new file mode 100644 index 0000000..7795e78 --- /dev/null +++ b/SOURCES/bz1845574-azure-events-2-import-urlerror-encode-postdata.patch @@ -0,0 +1,68 @@ +From f2bf1d8a07ea810099b03469883cb7f485ab9ac1 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 27 Jul 2020 10:09:43 +0200 +Subject: [PATCH 1/2] azure-events: import URLError and encode postData when + necessary + +--- + heartbeat/azure-events.in | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/heartbeat/azure-events.in b/heartbeat/azure-events.in +index d4a166d9f..a7f359468 100644 +--- a/heartbeat/azure-events.in ++++ b/heartbeat/azure-events.in +@@ -13,8 +13,10 @@ import subprocess + import json + try: + import urllib2 ++ from urllib2 import URLError + except ImportError: + import urllib.request as urllib2 ++ from urllib.error import URLError + import socket + from collections import defaultdict + +@@ -76,9 +78,13 @@ class azHelper: + Send a request to Azure's Azure Metadata Service API + """ + url = "%s/%s?api-version=%s" % (azHelper.metadata_host, endpoint, azHelper.api_version) ++ data = "" + ocf.logger.debug("_sendMetadataRequest: begin; endpoint = %s, postData = %s" % (endpoint, postData)) + ocf.logger.debug("_sendMetadataRequest: url = %s" % url) + ++ if postData and type(postData) != bytes: ++ postData = postData.encode() ++ + req = urllib2.Request(url, postData) + req.add_header("Metadata", "true") + req.add_header("User-Agent", USER_AGENT) + +From 1ab5d71bff95eb271f1e1bbc401961dc313219d9 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 29 Jul 2020 21:25:43 +0200 +Subject: [PATCH 2/2] azure-events: report error if jsondata not received + +--- + heartbeat/azure-events.in | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/azure-events.in b/heartbeat/azure-events.in +index a7f359468..3a24d6358 100644 +--- a/heartbeat/azure-events.in ++++ b/heartbeat/azure-events.in +@@ -117,8 +117,12 @@ class azHelper: + jsondata = azHelper._sendMetadataRequest(azHelper.instance_api) + ocf.logger.debug("getInstanceInfo: json = %s" % jsondata) + +- ocf.logger.debug("getInstanceInfo: finished, returning {}".format(jsondata["compute"])) +- return attrDict(jsondata["compute"]) ++ if jsondata: ++ ocf.logger.debug("getInstanceInfo: finished, returning {}".format(jsondata["compute"])) ++ return attrDict(jsondata["compute"]) ++ else: ++ ocf.ocf_exit_reason("getInstanceInfo: Unable to get instance info") ++ sys.exit(ocf.OCF_ERR_GENERIC) + + @staticmethod + def pullScheduledEvents(): diff --git a/SOURCES/bz1845574-azure-events-handle-exceptions-in-urlopen.patch b/SOURCES/bz1845574-azure-events-handle-exceptions-in-urlopen.patch deleted file mode 100644 index fa194c9..0000000 --- a/SOURCES/bz1845574-azure-events-handle-exceptions-in-urlopen.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 194909ff08cfe75cd5da9f704d8ed4cc9ab40341 Mon Sep 17 00:00:00 2001 -From: Gustavo Figueira -Date: Tue, 19 May 2020 10:58:34 +0200 -Subject: [PATCH 1/2] azure-events: handle exceptions in urlopen The locking in - azure-events does not correctly handle some failures. - -If the metadata server is not recheable or has an error -handling the request, attr_globalPullState will never go -back to IDLE unless the administrator manually changes it. - -> azure-events: ERROR: [Errno 104] Connection reset by peer -> lrmd[2734]: notice: rsc_azure-events_monitor_10000:113088:stderr [ ocf-exit-reason:[Errno 104] Connection reset by peer ] ---- - heartbeat/azure-events.in | 16 +++++++++++++--- - 1 file changed, 13 insertions(+), 3 deletions(-) - -diff --git a/heartbeat/azure-events.in b/heartbeat/azure-events.in -index 8709d97e3..bd812f4b2 100644 ---- a/heartbeat/azure-events.in -+++ b/heartbeat/azure-events.in -@@ -82,9 +82,19 @@ class azHelper: - req = urllib2.Request(url, postData) - req.add_header("Metadata", "true") - req.add_header("User-Agent", USER_AGENT) -- resp = urllib2.urlopen(req) -- data = resp.read() -- ocf.logger.debug("_sendMetadataRequest: response = %s" % data) -+ try: -+ resp = urllib2.urlopen(req) -+ except URLError as e: -+ if hasattr(e, 'reason'): -+ print('We failed to reach a server. Reason: '), e.reason -+ clusterHelper.setAttr(attr_globalPullState, "IDLE") -+ elif hasattr(e, 'code'): -+ print('The server couldn\'t fulfill the request. Error code: '), e.code -+ clusterHelper.setAttr(attr_globalPullState, "IDLE") -+ else: -+ data = resp.read() -+ ocf.logger.debug("_sendMetadataRequest: response = %s" % data) -+ - if data: - data = json.loads(data) - - -From c4071ec4a82fcb831f170f341e0790633e4b904f Mon Sep 17 00:00:00 2001 -From: Gustavo Figueira -Date: Tue, 19 May 2020 12:53:22 +0200 -Subject: [PATCH 2/2] azure-events: use ocf.logger.warning instead of print - ---- - heartbeat/azure-events.in | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/heartbeat/azure-events.in b/heartbeat/azure-events.in -index bd812f4b2..a48a86309 100644 ---- a/heartbeat/azure-events.in -+++ b/heartbeat/azure-events.in -@@ -86,10 +86,10 @@ class azHelper: - resp = urllib2.urlopen(req) - except URLError as e: - if hasattr(e, 'reason'): -- print('We failed to reach a server. Reason: '), e.reason -+ ocf.logger.warning("Failed to reach the server: %s" % e.reason) - clusterHelper.setAttr(attr_globalPullState, "IDLE") - elif hasattr(e, 'code'): -- print('The server couldn\'t fulfill the request. Error code: '), e.code -+ ocf.logger.warning("The server couldn\'t fulfill the request. Error code: %s" % e.code) - clusterHelper.setAttr(attr_globalPullState, "IDLE") - else: - data = resp.read() diff --git a/SOURCES/bz1846733-gcp-vpc-move-vip-1-support-multiple-alias-ips.patch b/SOURCES/bz1846733-gcp-vpc-move-vip-1-support-multiple-alias-ips.patch new file mode 100644 index 0000000..13401c2 --- /dev/null +++ b/SOURCES/bz1846733-gcp-vpc-move-vip-1-support-multiple-alias-ips.patch @@ -0,0 +1,317 @@ +--- a/heartbeat/gcp-vpc-move-vip.in 2020-08-17 10:33:22.132531259 +0200 ++++ b/heartbeat/gcp-vpc-move-vip.in 2020-08-17 10:34:54.050633259 +0200 +@@ -22,7 +22,8 @@ + import sys + import time + +-OCF_FUNCTIONS_DIR="%s/lib/heartbeat" % os.environ.get("OCF_ROOT") ++OCF_FUNCTIONS_DIR = os.environ.get("OCF_FUNCTIONS_DIR", "%s/lib/heartbeat" ++ % os.environ.get("OCF_ROOT")) + sys.path.append(OCF_FUNCTIONS_DIR) + + from ocf import * +@@ -43,6 +44,10 @@ + import urllib2 as urlrequest + + ++# Constants for alias add/remove modes ++ADD = 0 ++REMOVE = 1 ++ + CONN = None + THIS_VM = None + ALIAS = None +@@ -53,27 +58,27 @@ + + + 1.0 +- Floating IP Address on Google Cloud Platform - Using Alias IP address functionality to attach a secondary IP address to a running instance +- Floating IP Address on Google Cloud Platform ++ Floating IP Address or Range on Google Cloud Platform - Using Alias IP address functionality to attach a secondary IP range to a running instance ++ Floating IP Address or Range on Google Cloud Platform + + +- IP Address to be added including CIDR. E.g 192.168.0.1/32 +- IP Address to be added including CIDR. E.g 192.168.0.1/32 ++ IP range to be added including CIDR netmask (e.g., 192.168.0.1/32) ++ IP range to be added including CIDR netmask (e.g., 192.168.0.1/32) + + +- ++ + Subnet name for the Alias IP + Subnet name for the Alias IP + + +- +- List of hosts in the cluster ++ ++ List of hosts in the cluster, separated by spaces + Host list + + + +- If enabled (set to true), IP failover logs will be posted to stackdriver logging. Using stackdriver logging requires additional libraries (google-cloud-logging). +- Stackdriver-logging support. Requires additional libraries (google-cloud-logging). ++ If enabled (set to true), IP failover logs will be posted to stackdriver logging ++ Stackdriver-logging support + + + +@@ -107,7 +112,8 @@ + url = '%s?%s' % (metadata_url, params) + request = urlrequest.Request(url, headers=METADATA_HEADERS) + request_opener = urlrequest.build_opener(urlrequest.ProxyHandler({})) +- return request_opener.open(request, timeout=timeout * 1.1).read().decode("utf-8") ++ return request_opener.open( ++ request, timeout=timeout * 1.1).read().decode("utf-8") + + + def get_instance(project, zone, instance): +@@ -134,17 +140,21 @@ + time.sleep(1) + + +-def set_alias(project, zone, instance, alias, alias_range_name=None): +- fingerprint = get_network_ifaces(project, zone, instance)[0]['fingerprint'] ++def set_aliases(project, zone, instance, aliases, fingerprint): ++ """Sets the alias IP ranges for an instance. ++ ++ Args: ++ project: string, the project in which the instance resides. ++ zone: string, the zone in which the instance resides. ++ instance: string, the name of the instance. ++ aliases: list, the list of dictionaries containing alias IP ranges ++ to be added to or removed from the instance. ++ fingerprint: string, the fingerprint of the network interface. ++ """ + body = { +- 'aliasIpRanges': [], +- 'fingerprint': fingerprint ++ 'aliasIpRanges': aliases, ++ 'fingerprint': fingerprint + } +- if alias: +- obj = {'ipCidrRange': alias} +- if alias_range_name: +- obj['subnetworkRangeName'] = alias_range_name +- body['aliasIpRanges'].append(obj) + + request = CONN.instances().updateNetworkInterface( + instance=instance, networkInterface='nic0', project=project, zone=zone, +@@ -153,21 +163,75 @@ + wait_for_operation(project, zone, operation) + + +-def get_alias(project, zone, instance): +- iface = get_network_ifaces(project, zone, instance) ++def add_rm_alias(mode, project, zone, instance, alias, alias_range_name=None): ++ """Adds or removes an alias IP range for a GCE instance. ++ ++ Args: ++ mode: int, a constant (ADD (0) or REMOVE (1)) indicating the ++ operation type. ++ project: string, the project in which the instance resides. ++ zone: string, the zone in which the instance resides. ++ instance: string, the name of the instance. ++ alias: string, the alias IP range to be added to or removed from ++ the instance. ++ alias_range_name: string, the subnet name for the alias IP range. ++ ++ Returns: ++ True if the existing list of alias IP ranges was modified, or False ++ otherwise. ++ """ ++ ifaces = get_network_ifaces(project, zone, instance) ++ fingerprint = ifaces[0]['fingerprint'] ++ ++ try: ++ old_aliases = ifaces[0]['aliasIpRanges'] ++ except KeyError: ++ old_aliases = [] ++ ++ new_aliases = [a for a in old_aliases if a['ipCidrRange'] != alias] ++ ++ if alias: ++ if mode == ADD: ++ obj = {'ipCidrRange': alias} ++ if alias_range_name: ++ obj['subnetworkRangeName'] = alias_range_name ++ new_aliases.append(obj) ++ elif mode == REMOVE: ++ pass # already removed during new_aliases build ++ else: ++ raise ValueError('Invalid value for mode: {}'.format(mode)) ++ ++ if (sorted(new_aliases) != sorted(old_aliases)): ++ set_aliases(project, zone, instance, new_aliases, fingerprint) ++ return True ++ else: ++ return False ++ ++ ++def add_alias(project, zone, instance, alias, alias_range_name=None): ++ return add_rm_alias(ADD, project, zone, instance, alias, alias_range_name) ++ ++ ++def remove_alias(project, zone, instance, alias): ++ return add_rm_alias(REMOVE, project, zone, instance, alias) ++ ++ ++def get_aliases(project, zone, instance): ++ ifaces = get_network_ifaces(project, zone, instance) + try: +- return iface[0]['aliasIpRanges'][0]['ipCidrRange'] ++ aliases = ifaces[0]['aliasIpRanges'] ++ return [a['ipCidrRange'] for a in aliases] + except KeyError: +- return '' ++ return [] + + +-def get_localhost_alias(): ++def get_localhost_aliases(): + net_iface = get_metadata('instance/network-interfaces', {'recursive': True}) + net_iface = json.loads(net_iface) + try: +- return net_iface[0]['ipAliases'][0] ++ return net_iface[0]['ipAliases'] + except (KeyError, IndexError): +- return '' ++ return [] + + + def get_zone(project, instance): +@@ -201,21 +265,17 @@ + + + def gcp_alias_start(alias): +- my_alias = get_localhost_alias() ++ my_aliases = get_localhost_aliases() + my_zone = get_metadata('instance/zone').split('/')[-1] + project = get_metadata('project/project-id') + +- # If I already have the IP, exit. If it has an alias IP that isn't the VIP, +- # then remove it +- if my_alias == alias: ++ if alias in my_aliases: ++ # TODO: Do we need to check alias_range_name? + logger.info( + '%s already has %s attached. No action required' % (THIS_VM, alias)) + sys.exit(OCF_SUCCESS) +- elif my_alias: +- logger.info('Removing %s from %s' % (my_alias, THIS_VM)) +- set_alias(project, my_zone, THIS_VM, '') + +- # Loops through all hosts & remove the alias IP from the host that has it ++ # If the alias is currently attached to another host, detach it. + hostlist = os.environ.get('OCF_RESKEY_hostlist', '') + if hostlist: + hostlist = hostlist.replace(THIS_VM, '').split() +@@ -223,47 +283,53 @@ + hostlist = get_instances_list(project, THIS_VM) + for host in hostlist: + host_zone = get_zone(project, host) +- host_alias = get_alias(project, host_zone, host) +- if alias == host_alias: ++ host_aliases = get_aliases(project, host_zone, host) ++ if alias in host_aliases: + logger.info( +- '%s is attached to %s - Removing all alias IP addresses from %s' % +- (alias, host, host)) +- set_alias(project, host_zone, host, '') ++ '%s is attached to %s - Removing %s from %s' % ++ (alias, host, alias, host)) ++ remove_alias(project, host_zone, host, alias) + break + +- # add alias IP to localhost +- set_alias( ++ # Add alias IP range to localhost ++ add_alias( + project, my_zone, THIS_VM, alias, + os.environ.get('OCF_RESKEY_alias_range_name')) + +- # Check the IP has been added +- my_alias = get_localhost_alias() +- if alias == my_alias: ++ # Verify that the IP range has been added ++ my_aliases = get_localhost_aliases() ++ if alias in my_aliases: + logger.info('Finished adding %s to %s' % (alias, THIS_VM)) +- elif my_alias: +- logger.error( +- 'Failed to add IP. %s has an IP attached but it isn\'t %s' % +- (THIS_VM, alias)) +- sys.exit(OCF_ERR_GENERIC) + else: +- logger.error('Failed to add IP address %s to %s' % (alias, THIS_VM)) ++ if my_aliases: ++ logger.error( ++ 'Failed to add alias IP range %s. %s has alias IP ranges attached but' ++ + ' they don\'t include %s' % (alias, THIS_VM, alias)) ++ else: ++ logger.error( ++ 'Failed to add IP range %s. %s has no alias IP ranges attached' ++ % (alias, THIS_VM)) + sys.exit(OCF_ERR_GENERIC) + + + def gcp_alias_stop(alias): +- my_alias = get_localhost_alias() ++ my_aliases = get_localhost_aliases() + my_zone = get_metadata('instance/zone').split('/')[-1] + project = get_metadata('project/project-id') + +- if my_alias == alias: +- logger.info('Removing %s from %s' % (my_alias, THIS_VM)) +- set_alias(project, my_zone, THIS_VM, '') ++ if alias in my_aliases: ++ logger.info('Removing %s from %s' % (alias, THIS_VM)) ++ remove_alias(project, my_zone, THIS_VM, alias) ++ else: ++ logger.info( ++ '%s is not attached to %s. No action required' ++ % (alias, THIS_VM)) + + + def gcp_alias_status(alias): +- my_alias = get_localhost_alias() +- if alias == my_alias: +- logger.info('%s has the correct IP address attached' % THIS_VM) ++ my_aliases = get_localhost_aliases() ++ if alias in my_aliases: ++ logger.info('%s has the correct IP range attached' % THIS_VM) + else: + sys.exit(OCF_NOT_RUNNING) + +@@ -275,7 +341,8 @@ + + # Populate global vars + try: +- CONN = googleapiclient.discovery.build('compute', 'v1') ++ CONN = googleapiclient.discovery.build('compute', 'v1', ++ cache_discovery=False) + except Exception as e: + logger.error('Couldn\'t connect with google api: ' + str(e)) + sys.exit(OCF_ERR_CONFIGURED) +@@ -283,7 +350,8 @@ + try: + THIS_VM = get_metadata('instance/name') + except Exception as e: +- logger.error('Couldn\'t get instance name, is this running inside GCE?: ' + str(e)) ++ logger.error('Couldn\'t get instance name, is this running inside GCE?: ' ++ + str(e)) + sys.exit(OCF_ERR_CONFIGURED) + + ALIAS = os.environ.get('OCF_RESKEY_alias_ip') +@@ -309,7 +377,8 @@ + formatter = logging.Formatter('gcp:alias "%(message)s"') + handler.setFormatter(formatter) + log.addHandler(handler) +- logger = logging.LoggerAdapter(log, {'OCF_RESOURCE_INSTANCE': OCF_RESOURCE_INSTANCE}) ++ logger = logging.LoggerAdapter(log, {'OCF_RESOURCE_INSTANCE': ++ OCF_RESOURCE_INSTANCE}) + except ImportError: + logger.error('Couldn\'t import google.cloud.logging, ' + 'disabling Stackdriver-logging support') diff --git a/SOURCES/bz1846733-gcp-vpc-move-vip-2-fix-list-sort.patch b/SOURCES/bz1846733-gcp-vpc-move-vip-2-fix-list-sort.patch new file mode 100644 index 0000000..887fc99 --- /dev/null +++ b/SOURCES/bz1846733-gcp-vpc-move-vip-2-fix-list-sort.patch @@ -0,0 +1,32 @@ +From 2b22a14a128b87214bfb1ece221274aac78ba81b Mon Sep 17 00:00:00 2001 +From: Reid Wahl +Date: Tue, 18 Aug 2020 18:43:13 -0700 +Subject: [PATCH] gcp-vpc-move-vip: Fix sort for list of dicts in python3 + +python2 sorts a list of dicts of `{'ipCidrRange': }` correctly by +default. python3 fails with a TypeError: + +`TypeError: '<' not supported between instances of 'dict' and 'dict'` + +Fix this by using the key parameter of sorted(). python2 also supports +this. + +Signed-off-by: Reid Wahl +--- + heartbeat/gcp-vpc-move-vip.in | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/gcp-vpc-move-vip.in b/heartbeat/gcp-vpc-move-vip.in +index 85d59f6bb..01d91a59d 100755 +--- a/heartbeat/gcp-vpc-move-vip.in ++++ b/heartbeat/gcp-vpc-move-vip.in +@@ -200,7 +200,8 @@ def add_rm_alias(mode, project, zone, instance, alias, alias_range_name=None): + else: + raise ValueError('Invalid value for mode: {}'.format(mode)) + +- if (sorted(new_aliases) != sorted(old_aliases)): ++ if (sorted(new_aliases, key=lambda item: item.get('ipCidrRange')) ++ != sorted(old_aliases, key=lambda item: item.get('ipCidrRange'))): + set_aliases(project, zone, instance, new_aliases, fingerprint) + return True + else: diff --git a/SOURCES/bz1848025-sybaseASE-run-verify-for-start-action-only.patch b/SOURCES/bz1848025-sybaseASE-run-verify-for-start-action-only.patch new file mode 100644 index 0000000..402bbd6 --- /dev/null +++ b/SOURCES/bz1848025-sybaseASE-run-verify-for-start-action-only.patch @@ -0,0 +1,41 @@ +From 953f689cb2a37606b6d4b2250ebec23f129f5095 Mon Sep 17 00:00:00 2001 +From: Reid wahl +Date: Thu, 9 Jul 2020 23:32:22 -0700 +Subject: [PATCH] sybaseASE: Run verify_all() for start operation only + +The `sybaseASE` resource agent runs the `verify_all()` function at the +beginning of start, stop, and monitor operations. + +When `verify_all()` is run for a probe (monitor) operation and +`sybase_home` resides on a cluster-managed filesystem, the probe often +fails with `$OCF_ERR_GENERIC` because the filesystem isn't mounted yet. +This prevents the resource from starting on that node. + +For the stop operation, there's simply no reason to run `verify_all()`. + +This patch removes `verify_all()` for the stop and monitor operations. +It is now only run for the start operation. + +Resolves: RHBZ#1848673 +Resolves: RHBZ#1848025 +--- + heartbeat/sybaseASE.in | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/heartbeat/sybaseASE.in b/heartbeat/sybaseASE.in +index 9ddd429be..7ff30bd31 100755 +--- a/heartbeat/sybaseASE.in ++++ b/heartbeat/sybaseASE.in +@@ -864,12 +864,10 @@ case $__OCF_ACTION in + exit $? + ;; + stop) +- verify_all || exit $OCF_ERR_GENERIC + ase_stop + exit $? + ;; + status | monitor) +- verify_all || exit $OCF_ERR_GENERIC + ase_status $OCF_CHECK_LEVEL + exit $? + ;; diff --git a/SOURCES/bz1850778-azure-lb-fix-redirect-issue.patch b/SOURCES/bz1850778-azure-lb-fix-redirect-issue.patch new file mode 100644 index 0000000..b171613 --- /dev/null +++ b/SOURCES/bz1850778-azure-lb-fix-redirect-issue.patch @@ -0,0 +1,54 @@ +From d22700fc5d5098c683b465ea0fede43803fd4d6b Mon Sep 17 00:00:00 2001 +From: Reid wahl +Date: Tue, 7 Jul 2020 02:18:09 -0700 +Subject: [PATCH] azure-lb: Don't redirect nc listener output to pidfile + +The `lb_start()` function spawns an `nc` listener background process +and echoes the resulting pid to `$pidfile`. Due to a bug in the +redirection, all future data received by the `nc` process is also +appended to `$pidfile`. + +If binary data is received later and appended to `$pidfile`, the +monitor operation fails when `grep` searches the now-binary file. + +``` +line 97: kill: Binary: arguments must be process or job IDs ] +line 97: kill: file: arguments must be process or job IDs ] +line 97: kill: /var/run/nc_PF2_02.pid: arguments must be process or job + IDs ] +line 97: kill: matches: arguments must be process or job IDs ] +``` + +Then the start operation fails during recovery. `lb_start()` spawns a +new `nc` process, but the old process is still running and using the +configured port. + +``` +nc_PF2_02_start_0:777:stderr [ Ncat: bind to :::62502: Address + already in use. QUITTING. ] +``` + +This patch fixes the issue by removing the `nc &` command from the +section whose output gets redirected to `$pidfile`. Now, only the `nc` +PID is echoed to `$pidfile`. + +Resolves: RHBZ#1850778 +Resolves: RHBZ#1850779 +--- + heartbeat/azure-lb | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/azure-lb b/heartbeat/azure-lb +index 05c134514..05755d778 100755 +--- a/heartbeat/azure-lb ++++ b/heartbeat/azure-lb +@@ -113,7 +113,8 @@ lb_start() { + if ! lb_monitor; then + ocf_log debug "Starting $process: $cmd" + # Execute the command as created above +- eval "$cmd & echo \$!" > $pidfile ++ $cmd & ++ echo $! > $pidfile + if lb_monitor; then + ocf_log debug "$process: $cmd started successfully, calling monitor" + lb_monitor diff --git a/SOURCES/bz1858752-Filesystem-support-whitespace-device-dir.patch b/SOURCES/bz1858752-Filesystem-support-whitespace-device-dir.patch new file mode 100644 index 0000000..15fb71f --- /dev/null +++ b/SOURCES/bz1858752-Filesystem-support-whitespace-device-dir.patch @@ -0,0 +1,566 @@ +From a8051cf9e21d231ce3c445f09631266157ffc2e0 Mon Sep 17 00:00:00 2001 +From: Reid wahl +Date: Fri, 10 Jul 2020 03:44:18 -0700 +Subject: [PATCH 1/3] Filesystem: Support whitespace in device or directory + name + +Whitespace in a device name (e.g., a CIFS share) or a directory name +breaks resource operations. + +One issue is that many of the variable occurrences aren't quoted, so a +string containing whitespace is split into multiple tokens. This is a +problem when the string meant to be passed as a single argument to a +function (e.g., `list_submounts()`). + +Another issue involves the parsing of `list_mounts()` output. +`list_mounts()` can pull data from `/proc/mounts`, `/etc/mtab`, or the +`mount` command. `/proc/mounts` and `/etc/mtab` represent spaces within +a field as octal `\040` strings, while `mount` represents them as +literal space characters. + +`list_mounts()` had to be modified to output the mount list as three +distinct fields ((`device`, `mountpoint`, `fstype`), separated by tab +characters) regardless of the data source. Parsers of `list_mounts()` +were modified to use tabs as field delimiters. + +The for loop in `Filesystem_stop()` also had to become a while loop to +read line-by-line irrespective of spaces. A for loop splits on spaces. + +Resolves: RHBZ#1624591 +--- + heartbeat/Filesystem | 106 +++++++++++++++++++++++++------------------ + 1 file changed, 61 insertions(+), 45 deletions(-) + +diff --git a/heartbeat/Filesystem b/heartbeat/Filesystem +index 2f07a90ad..9a52aa712 100755 +--- a/heartbeat/Filesystem ++++ b/heartbeat/Filesystem +@@ -91,6 +91,7 @@ fi + + # Variables used by multiple methods + HOSTOS=`uname` ++TAB=' ' + + # The status file is going to an extra directory, by default + # +@@ -100,7 +101,7 @@ suffix="${OCF_RESOURCE_INSTANCE}" + [ "$OCF_RESKEY_CRM_meta_clone" ] && + suffix="${suffix}_$OCF_RESKEY_CRM_meta_clone" + suffix="${suffix}_`uname -n`" +-STATUSFILE=${OCF_RESKEY_directory}/$prefix$suffix ++STATUSFILE="${OCF_RESKEY_directory}/$prefix$suffix" + + ####################################################################### + +@@ -283,6 +284,7 @@ flushbufs() { + is_bind_mount() { + echo "$options" | grep -w bind >/dev/null 2>&1 + } ++ + list_mounts() { + local inpf="" + local mount_list="" +@@ -296,15 +298,23 @@ list_mounts() { + + # Make sure that the mount list has not been changed while reading. + while [ "$mount_list" != "$check_list" ]; do +- check_list=$mount_list ++ check_list="$mount_list" + if [ "$inpf" ]; then +- mount_list=$(cut -d' ' -f1,2,3 < $inpf) ++ # ... ++ # Spaces in device or mountpoint are octal \040 in $inpf ++ # Convert literal spaces (field separators) to tabs ++ mount_list=$(cut -d' ' -f1,2,3 < $inpf | tr ' ' "$TAB") + else +- mount_list=$($MOUNT | cut -d' ' -f1,3,5) ++ # on type ... ++ # Use tabs as field separators ++ match_string='\(.*\) on \(.*\) type \([^[:space:]]\)' ++ replace_string="\\1${TAB}\\3${TAB}\\5" ++ mount_list=$($MOUNT | sed "s/$match_string/$replace_string/g") + fi + done + +- echo "$mount_list" ++ # Convert octal \040 to space characters ++ printf "$mount_list" + } + + determine_blockdevice() { +@@ -318,7 +328,8 @@ determine_blockdevice() { + nfs4|nfs|smbfs|cifs|glusterfs|ceph|tmpfs|overlay|overlayfs|rozofs|zfs|cvfs|none|lustre) + : ;; + *) +- DEVICE=`list_mounts | grep " $CANONICALIZED_MOUNTPOINT " | cut -d' ' -f1` ++ match_string="${TAB}${CANONICALIZED_MOUNTPOINT}${TAB}" ++ DEVICE=`list_mounts | grep "$match_string" | cut -d"$TAB" -f1` + if [ -b "$DEVICE" ]; then + blockdevice=yes + fi +@@ -329,7 +340,7 @@ determine_blockdevice() { + # Lists all filesystems potentially mounted under a given path, + # excluding the path itself. + list_submounts() { +- list_mounts | grep " $1/" | cut -d' ' -f2 | sort -r ++ list_mounts | grep "${TAB}${1}/" | cut -d"$TAB" -f2 | sort -r + } + + # kernels < 2.6.26 can't handle bind remounts +@@ -358,15 +369,15 @@ bind_mount() { + if is_bind_mount && [ "$options" != "-o bind" ] + then + bind_kernel_check +- bind_opts=`echo $options | sed 's/bind/remount/'` +- $MOUNT $bind_opts $MOUNTPOINT ++ bind_opts=`echo "$options" | sed 's/bind/remount/'` ++ $MOUNT $bind_opts "$MOUNTPOINT" + else + true # make sure to return OK + fi + } + + is_option() { +- echo $OCF_RESKEY_options | grep -w "$1" >/dev/null 2>&1 ++ echo "$OCF_RESKEY_options" | grep -w "$1" >/dev/null 2>&1 + } + + is_fsck_needed() { +@@ -374,7 +385,7 @@ is_fsck_needed() { + force) true;; + no) false;; + ""|auto) +- case $FSTYPE in ++ case "$FSTYPE" in + ext4|ext4dev|ext3|reiserfs|reiser4|nss|xfs|jfs|vfat|fat|nfs4|nfs|cifs|smbfs|ocfs2|gfs2|none|lustre|glusterfs|ceph|tmpfs|overlay|overlayfs|rozofs|zfs|cvfs) + false;; + *) +@@ -403,7 +414,7 @@ fstype_supported() + fi + + # support fuse-filesystems (e.g. GlusterFS) +- case $FSTYPE in ++ case "$FSTYPE" in + fuse.*|glusterfs|rozofs) support="fuse";; + esac + +@@ -486,7 +497,8 @@ trigger_udev_rules_if_needed() + Filesystem_start() + { + # Check if there are any mounts mounted under the mountpoint +- if list_mounts | grep -q -E " $CANONICALIZED_MOUNTPOINT/\w+" >/dev/null 2>&1; then ++ match_string="${TAB}${CANONICALIZED_MOUNTPOINT}" ++ if list_mounts | grep -q -E "$match_string/\w+" >/dev/null 2>&1; then + ocf_log err "There is one or more mounts mounted under $MOUNTPOINT." + return $OCF_ERR_CONFIGURED + fi +@@ -514,9 +526,9 @@ Filesystem_start() + if is_fsck_needed; then + ocf_log info "Starting filesystem check on $DEVICE" + if [ -z "$FSTYPE" ]; then +- $FSCK -p $DEVICE ++ $FSCK -p "$DEVICE" + else +- $FSCK -t $FSTYPE -p $DEVICE ++ $FSCK -t "$FSTYPE" -p "$DEVICE" + fi + + # NOTE: if any errors at all are detected, it returns non-zero +@@ -529,20 +541,20 @@ Filesystem_start() + fi + + [ -d "$MOUNTPOINT" ] || +- ocf_run mkdir -p $MOUNTPOINT ++ ocf_run mkdir -p "$MOUNTPOINT" + if [ ! -d "$MOUNTPOINT" ] ; then + ocf_exit_reason "Couldn't find directory [$MOUNTPOINT] to use as a mount point" + exit $OCF_ERR_INSTALLED + fi + +- flushbufs $DEVICE ++ flushbufs "$DEVICE" + # Mount the filesystem. + case "$FSTYPE" in +- none) $MOUNT $options $DEVICE $MOUNTPOINT && ++ none) $MOUNT $options "$DEVICE" "$MOUNTPOINT" && + bind_mount + ;; +- "") $MOUNT $options $DEVICE $MOUNTPOINT ;; +- *) $MOUNT -t $FSTYPE $options $DEVICE $MOUNTPOINT ;; ++ "") $MOUNT $options "$DEVICE" "$MOUNTPOINT" ;; ++ *) $MOUNT -t "$FSTYPE" $options "$DEVICE" "$MOUNTPOINT" ;; + esac + + if [ $? -ne 0 ]; then +@@ -595,23 +607,23 @@ signal_processes() { + done + } + try_umount() { +- local SUB=$1 +- $UMOUNT $umount_force $SUB +- list_mounts | grep -q " $SUB " >/dev/null 2>&1 || { ++ local SUB="$1" ++ $UMOUNT $umount_force "$SUB" ++ list_mounts | grep -q "${TAB}${SUB}${TAB}" >/dev/null 2>&1 || { + ocf_log info "unmounted $SUB successfully" + return $OCF_SUCCESS + } + return $OCF_ERR_GENERIC + } + fs_stop() { +- local SUB=$1 timeout=$2 sig cnt ++ local SUB="$1" timeout=$2 sig cnt + for sig in TERM KILL; do + cnt=$((timeout/2)) # try half time with TERM + while [ $cnt -gt 0 ]; do +- try_umount $SUB && ++ try_umount "$SUB" && + return $OCF_SUCCESS + ocf_exit_reason "Couldn't unmount $SUB; trying cleanup with $sig" +- signal_processes $SUB $sig ++ signal_processes "$SUB" $sig + cnt=$((cnt-1)) + sleep 1 + done +@@ -633,7 +645,7 @@ Filesystem_stop() + # Wipe the status file, but continue with a warning if + # removal fails -- the file system might be read only + if [ $OCF_CHECK_LEVEL -eq 20 ]; then +- rm -f ${STATUSFILE} ++ rm -f "${STATUSFILE}" + if [ $? -ne 0 ]; then + ocf_log warn "Failed to remove status file ${STATUSFILE}." + fi +@@ -650,7 +662,7 @@ Filesystem_stop() + + # Umount all sub-filesystems mounted under $MOUNTPOINT/ too. + local timeout +- for SUB in `list_submounts $MOUNTPOINT` $MOUNTPOINT; do ++ while read SUB; do + ocf_log info "Trying to unmount $SUB" + if ocf_is_true "$FAST_STOP"; then + timeout=6 +@@ -658,15 +670,18 @@ Filesystem_stop() + timeout=${OCF_RESKEY_CRM_meta_timeout:="20000"} + timeout=$((timeout/1000)) + fi +- fs_stop $SUB $timeout ++ fs_stop "$SUB" $timeout + rc=$? + if [ $rc -ne $OCF_SUCCESS ]; then + ocf_exit_reason "Couldn't unmount $SUB, giving up!" + fi +- done ++ done <<-EOF ++ $(list_submounts "$CANONICALIZED_MOUNTPOINT"; \ ++ echo $CANONICALIZED_MOUNTPOINT) ++ EOF + fi + +- flushbufs $DEVICE ++ flushbufs "$DEVICE" + + return $rc + } +@@ -677,7 +692,8 @@ Filesystem_stop() + # + Filesystem_status() + { +- if list_mounts | grep -q " $CANONICALIZED_MOUNTPOINT " >/dev/null 2>&1; then ++ match_string="${TAB}${CANONICALIZED_MOUNTPOINT}${TAB}" ++ if list_mounts | grep -q "$match_string" >/dev/null 2>&1; then + rc=$OCF_SUCCESS + msg="$MOUNTPOINT is mounted (running)" + else +@@ -712,7 +728,7 @@ Filesystem_monitor_10() + return $OCF_SUCCESS + fi + dd_opts="iflag=direct bs=4k count=1" +- err_output=`dd if=$DEVICE $dd_opts 2>&1 >/dev/null` ++ err_output=`dd if="$DEVICE" $dd_opts 2>&1 >/dev/null` + if [ $? -ne 0 ]; then + ocf_exit_reason "Failed to read device $DEVICE" + ocf_log err "dd said: $err_output" +@@ -733,20 +749,20 @@ Filesystem_monitor_20() + # to bypass caches. + dd_opts="oflag=direct,sync bs=4k conv=fsync,sync" + fi +- status_dir=`dirname $STATUSFILE` ++ status_dir=$(dirname "$STATUSFILE") + [ -d "$status_dir" ] || mkdir -p "$status_dir" +- err_output=`echo "${OCF_RESOURCE_INSTANCE}" | dd of=${STATUSFILE} $dd_opts 2>&1` ++ err_output=`echo "${OCF_RESOURCE_INSTANCE}" | dd of="${STATUSFILE}" $dd_opts 2>&1` + if [ $? -ne 0 ]; then + ocf_exit_reason "Failed to write status file ${STATUSFILE}" + ocf_log err "dd said: $err_output" + return $OCF_ERR_GENERIC + fi +- test -f ${STATUSFILE} ++ test -f "${STATUSFILE}" + if [ $? -ne 0 ]; then + ocf_exit_reason "Cannot stat the status file ${STATUSFILE}" + return $OCF_ERR_GENERIC + fi +- cat ${STATUSFILE} > /dev/null ++ cat "${STATUSFILE}" > /dev/null + if [ $? -ne 0 ]; then + ocf_exit_reason "Cannot read the status file ${STATUSFILE}" + return $OCF_ERR_GENERIC +@@ -791,9 +807,9 @@ Filesystem_validate_all() + # NOTE: Without inserting the $FSTYPE module, this step may be imprecise + # TODO: This is Linux specific crap. + if [ ! -z "$FSTYPE" -a "$FSTYPE" != none ]; then +- cut -f2 /proc/filesystems |grep -q ^$FSTYPE$ ++ cut -f2 /proc/filesystems |grep -q "^${FSTYPE}$" + if [ $? -ne 0 ]; then +- modpath=/lib/modules/`uname -r` ++ modpath=/lib/modules/`uname -r` + moddep=$modpath/modules.dep + # Do we have $FSTYPE in modules.dep? + cut -d' ' -f1 $moddep |grep -q "^$modpath.*$FSTYPE\.k\?o:$" +@@ -826,7 +842,7 @@ set_blockdevice_var() { + blockdevice=no + + # these are definitely not block devices +- case $FSTYPE in ++ case "$FSTYPE" in + nfs4|nfs|smbfs|cifs|none|glusterfs|ceph|tmpfs|overlay|overlayfs|rozofs|zfs|cvfs) return;; + esac + +@@ -834,7 +850,7 @@ set_blockdevice_var() { + return + fi + +- case $DEVICE in ++ case "$DEVICE" in + -*) # Oh... An option to mount instead... Typically -U or -L + ;; + /dev/null) # Special case for BSC +@@ -863,7 +879,7 @@ if [ -n "${OCF_RESKEY_force_unmount}" ]; then + FORCE_UNMOUNT=$OCF_RESKEY_force_unmount + fi + +-DEVICE=$OCF_RESKEY_device ++DEVICE="$OCF_RESKEY_device" + FSTYPE=$OCF_RESKEY_fstype + if [ ! -z "$OCF_RESKEY_options" ]; then + options="-o $OCF_RESKEY_options" +@@ -899,10 +915,10 @@ if [ -z "$OCF_RESKEY_directory" ]; then + exit $OCF_ERR_CONFIGURED + fi + else +- MOUNTPOINT=$(echo $OCF_RESKEY_directory | sed 's/\/*$//') ++ MOUNTPOINT="$(echo "$OCF_RESKEY_directory" | sed 's/\/*$//')" + : ${MOUNTPOINT:=/} + if [ -e "$MOUNTPOINT" ] ; then +- CANONICALIZED_MOUNTPOINT=$(readlink -f "$MOUNTPOINT") ++ CANONICALIZED_MOUNTPOINT="$(readlink -f "$MOUNTPOINT")" + if [ $? -ne 0 ]; then + ocf_exit_reason "Could not canonicalize $MOUNTPOINT because readlink failed" + exit $OCF_ERR_GENERIC +@@ -947,7 +963,7 @@ CLUSTERSAFE=0 + is_option "ro" && + CLUSTERSAFE=2 + +-case $FSTYPE in ++case "$FSTYPE" in + nfs4|nfs|smbfs|cifs|none|gfs2|glusterfs|ceph|ocfs2|overlay|overlayfs|tmpfs|cvfs) + CLUSTERSAFE=1 # this is kind of safe too + ;; + +From eca9a96ad3356df3636bfa3187afe1b1954693b2 Mon Sep 17 00:00:00 2001 +From: Reid wahl +Date: Fri, 10 Jul 2020 16:38:04 -0700 +Subject: [PATCH 2/3] Filesystem: POSIX-compliant syntax for portability + +Updated to use POSIX `$()` instead of Bourne-shell backticks, and to +use `grep ... >/dev/null 2>&1` instead of `grep -q`. (Note: `grep -q` +only suppresses `stdout` anyway. `grep -q -s` would be required to +suppress both `stdout` and `stderr`.) +--- + heartbeat/Filesystem | 33 +++++++++++++++++---------------- + 1 file changed, 17 insertions(+), 16 deletions(-) + +diff --git a/heartbeat/Filesystem b/heartbeat/Filesystem +index 9a52aa712..34ade20d7 100755 +--- a/heartbeat/Filesystem ++++ b/heartbeat/Filesystem +@@ -90,7 +90,7 @@ fi + : ${OCF_RESKEY_force_unmount=${OCF_RESKEY_force_unmount_default}} + + # Variables used by multiple methods +-HOSTOS=`uname` ++HOSTOS=$(uname) + TAB=' ' + + # The status file is going to an extra directory, by default +@@ -100,7 +100,7 @@ prefix=${OCF_RESKEY_statusfile_prefix} + suffix="${OCF_RESOURCE_INSTANCE}" + [ "$OCF_RESKEY_CRM_meta_clone" ] && + suffix="${suffix}_$OCF_RESKEY_CRM_meta_clone" +-suffix="${suffix}_`uname -n`" ++suffix="${suffix}_$(uname -n)" + STATUSFILE="${OCF_RESKEY_directory}/$prefix$suffix" + + ####################################################################### +@@ -329,7 +329,7 @@ determine_blockdevice() { + : ;; + *) + match_string="${TAB}${CANONICALIZED_MOUNTPOINT}${TAB}" +- DEVICE=`list_mounts | grep "$match_string" | cut -d"$TAB" -f1` ++ DEVICE=$(list_mounts | grep "$match_string" | cut -d"$TAB" -f1) + if [ -b "$DEVICE" ]; then + blockdevice=yes + fi +@@ -354,7 +354,7 @@ bind_kernel_check() { + exit(1); + }' + [ $? -ne 0 ] && +- ocf_log warn "kernel `uname -r` cannot handle read only bind mounts" ++ ocf_log warn "kernel $(uname -r) cannot handle read only bind mounts" + } + + bind_root_mount_check() { +@@ -369,7 +369,7 @@ bind_mount() { + if is_bind_mount && [ "$options" != "-o bind" ] + then + bind_kernel_check +- bind_opts=`echo "$options" | sed 's/bind/remount/'` ++ bind_opts=$(echo "$options" | sed 's/bind/remount/') + $MOUNT $bind_opts "$MOUNTPOINT" + else + true # make sure to return OK +@@ -469,7 +469,7 @@ trigger_udev_rules_if_needed() + refresh_flag="yes" + fi + else +- tmp="`echo $DEVICE|awk '{$1=""; print substr($0,2)}'`" ++ tmp="$(echo $DEVICE|awk '{$1=""; print substr($0,2)}')" + case "$DEVICE" in + -U*|--uuid*) + tmp="/dev/disk/by-uuid/$tmp" +@@ -498,7 +498,7 @@ Filesystem_start() + { + # Check if there are any mounts mounted under the mountpoint + match_string="${TAB}${CANONICALIZED_MOUNTPOINT}" +- if list_mounts | grep -q -E "$match_string/\w+" >/dev/null 2>&1; then ++ if list_mounts | grep -E "$match_string/\w+" >/dev/null 2>&1; then + ocf_log err "There is one or more mounts mounted under $MOUNTPOINT." + return $OCF_ERR_CONFIGURED + fi +@@ -602,14 +602,14 @@ signal_processes() { + return + fi + for pid in $pids; do +- ocf_log info "sending signal $sig to: `ps -f $pid | tail -1`" ++ ocf_log info "sending signal $sig to: $(ps -f $pid | tail -1)" + kill -s $sig $pid + done + } + try_umount() { + local SUB="$1" + $UMOUNT $umount_force "$SUB" +- list_mounts | grep -q "${TAB}${SUB}${TAB}" >/dev/null 2>&1 || { ++ list_mounts | grep "${TAB}${SUB}${TAB}" >/dev/null 2>&1 || { + ocf_log info "unmounted $SUB successfully" + return $OCF_SUCCESS + } +@@ -693,7 +693,7 @@ Filesystem_stop() + Filesystem_status() + { + match_string="${TAB}${CANONICALIZED_MOUNTPOINT}${TAB}" +- if list_mounts | grep -q "$match_string" >/dev/null 2>&1; then ++ if list_mounts | grep "$match_string" >/dev/null 2>&1; then + rc=$OCF_SUCCESS + msg="$MOUNTPOINT is mounted (running)" + else +@@ -728,7 +728,7 @@ Filesystem_monitor_10() + return $OCF_SUCCESS + fi + dd_opts="iflag=direct bs=4k count=1" +- err_output=`dd if="$DEVICE" $dd_opts 2>&1 >/dev/null` ++ err_output=$(dd if="$DEVICE" $dd_opts 2>&1 >/dev/null) + if [ $? -ne 0 ]; then + ocf_exit_reason "Failed to read device $DEVICE" + ocf_log err "dd said: $err_output" +@@ -751,7 +751,7 @@ Filesystem_monitor_20() + fi + status_dir=$(dirname "$STATUSFILE") + [ -d "$status_dir" ] || mkdir -p "$status_dir" +- err_output=`echo "${OCF_RESOURCE_INSTANCE}" | dd of="${STATUSFILE}" $dd_opts 2>&1` ++ err_output=$(echo "${OCF_RESOURCE_INSTANCE}" | dd of="${STATUSFILE}" $dd_opts 2>&1) + if [ $? -ne 0 ]; then + ocf_exit_reason "Failed to write status file ${STATUSFILE}" + ocf_log err "dd said: $err_output" +@@ -807,12 +807,13 @@ Filesystem_validate_all() + # NOTE: Without inserting the $FSTYPE module, this step may be imprecise + # TODO: This is Linux specific crap. + if [ ! -z "$FSTYPE" -a "$FSTYPE" != none ]; then +- cut -f2 /proc/filesystems |grep -q "^${FSTYPE}$" ++ cut -f2 /proc/filesystems | grep "^${FSTYPE}$" >/dev/null 2>&1 + if [ $? -ne 0 ]; then +- modpath=/lib/modules/`uname -r` ++ modpath=/lib/modules/$(uname -r) + moddep=$modpath/modules.dep + # Do we have $FSTYPE in modules.dep? +- cut -d' ' -f1 $moddep |grep -q "^$modpath.*$FSTYPE\.k\?o:$" ++ cut -d' ' -f1 $moddep \ ++ | grep "^${modpath}.*${FSTYPE}\.k\?o:$" >/dev/null 2>&1 + if [ $? -ne 0 ]; then + ocf_log info "It seems we do not have $FSTYPE support" + fi +@@ -846,7 +847,7 @@ set_blockdevice_var() { + nfs4|nfs|smbfs|cifs|none|glusterfs|ceph|tmpfs|overlay|overlayfs|rozofs|zfs|cvfs|lustre) return;; + esac + +- if `is_option "loop"`; then ++ if $(is_option "loop"); then + return + fi + + +From 5517712f4bb6e90b23cde6310c03509c9061cb36 Mon Sep 17 00:00:00 2001 +From: Reid wahl +Date: Fri, 10 Jul 2020 16:44:17 -0700 +Subject: [PATCH 3/3] Filesystem: Convert leading space characters to tabs + +A few lines started with spaces instead of tabs. Tabs are the +convention in this file. +--- + heartbeat/Filesystem | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/heartbeat/Filesystem b/heartbeat/Filesystem +index 34ade20d7..501e5a0d0 100755 +--- a/heartbeat/Filesystem ++++ b/heartbeat/Filesystem +@@ -359,10 +359,10 @@ bind_kernel_check() { + + bind_root_mount_check() { + if [ "$(df -P "$1" | awk 'END{print $6}')" = "/" ]; then +- return 1 +- else +- return 0 +- fi ++ return 1 ++ else ++ return 0 ++ fi + } + + bind_mount() { +@@ -571,10 +571,10 @@ get_pids() + local procs + local mmap_procs + +- if is_bind_mount && ocf_is_true "$FORCE_UNMOUNT" && ! bind_root_mount_check "$DEVICE"; then +- ocf_log debug "Change force_umount from '$FORCE_UNMOUNT' to 'safe'" +- FORCE_UNMOUNT=safe +- fi ++ if is_bind_mount && ocf_is_true "$FORCE_UNMOUNT" && ! bind_root_mount_check "$DEVICE"; then ++ ocf_log debug "Change force_umount from '$FORCE_UNMOUNT' to 'safe'" ++ FORCE_UNMOUNT=safe ++ fi + + if ocf_is_true "$FORCE_UNMOUNT"; then + if [ "X${HOSTOS}" = "XOpenBSD" ];then diff --git a/SOURCES/bz1861001-sybaseASE-add-logfile-parameter.patch b/SOURCES/bz1861001-sybaseASE-add-logfile-parameter.patch new file mode 100644 index 0000000..b294584 --- /dev/null +++ b/SOURCES/bz1861001-sybaseASE-add-logfile-parameter.patch @@ -0,0 +1,53 @@ +From d62d8776df8aaa1da32e8452b3816505d1ea1f7f Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 28 Oct 2020 15:06:47 +0100 +Subject: [PATCH] sybaseASE: add logfile parameter + +--- + heartbeat/sybaseASE.in | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/sybaseASE.in b/heartbeat/sybaseASE.in +index 7ff30bd31..fef76474e 100755 +--- a/heartbeat/sybaseASE.in ++++ b/heartbeat/sybaseASE.in +@@ -115,6 +115,13 @@ fi + interfaces_file_default="${OCF_RESKEY_sybase_home}/interfaces" + : ${OCF_RESKEY_interfaces_file=${interfaces_file_default}} + ++if [ $__OCF_ACTION != "meta-data" ]; then ++ logfile_default="$OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ase/install/$OCF_RESKEY_server_name.log" ++else ++ logfile_default="detect" ++fi ++: ${OCF_RESKEY_logfile=${logfile_default}} ++ + export LD_POINTER_GUARD=0 + + ####################################################################################### +@@ -122,7 +129,7 @@ export LD_POINTER_GUARD=0 + ####################################################################################### + declare login_string="" + declare RUNSERVER_SCRIPT=$OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ase/install/RUN_$OCF_RESKEY_server_name +-declare CONSOLE_LOG=$OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ase/install/$OCF_RESKEY_server_name.log ++declare CONSOLE_LOG="$OCF_RESKEY_logfile" + + ################################################################################################## + # This function will be called by Pacemaker to get the meta data of resource agent "sybaseASE". # +@@ -223,6 +230,16 @@ meta_data() + + + ++ ++ ++ Logfile ++ ++ ++ Logfile ++ ++ ++ ++ + + + diff --git a/SOURCES/bz1872999-aws-vpc-move-ip-add-region-parameter.patch b/SOURCES/bz1872999-aws-vpc-move-ip-add-region-parameter.patch new file mode 100644 index 0000000..4fef3d5 --- /dev/null +++ b/SOURCES/bz1872999-aws-vpc-move-ip-add-region-parameter.patch @@ -0,0 +1,81 @@ +--- ClusterLabs-resource-agents-e711383f/heartbeat/aws-vpc-move-ip 2020-09-23 11:57:38.855067216 +0200 ++++ aws-vpc-move-ip.tmp 2020-09-23 11:57:17.993045991 +0200 +@@ -37,13 +37,17 @@ + # Defaults + OCF_RESKEY_awscli_default="/usr/bin/aws" + OCF_RESKEY_profile_default="default" ++OCF_RESKEY_region_default="" + OCF_RESKEY_routing_table_role_default="" + OCF_RESKEY_monapi_default="false" + + : ${OCF_RESKEY_awscli=${OCF_RESKEY_awscli_default}} + : ${OCF_RESKEY_profile=${OCF_RESKEY_profile_default}} ++: ${OCF_RESKEY_region=${OCF_RESKEY_region_default}} + : ${OCF_RESKEY_routing_table_role=${OCF_RESKEY_routing_table_role_default}} + : ${OCF_RESKEY_monapi=${OCF_RESKEY_monapi_default}} ++ ++[ -n "$OCF_RESKEY_region" ] && region_opt="--region $OCF_RESKEY_region" + ####################################################################### + + +@@ -87,6 +91,14 @@ + + + ++ ++ ++Valid AWS region name (e.g., 'us-west-2') ++ ++region name ++ ++ ++ + + + VPC private IP address +@@ -151,7 +163,7 @@ + execute_cmd_as_role(){ + cmd=$1 + role=$2 +- output="$($OCF_RESKEY_awscli sts assume-role --role-arn $role --role-session-name AWSCLI-RouteTableUpdate --profile $OCF_RESKEY_profile --output=text)" ++ output="$($OCF_RESKEY_awscli sts assume-role --role-arn $role --role-session-name AWSCLI-RouteTableUpdate --profile $OCF_RESKEY_profile $region_opt --output=text)" + export AWS_ACCESS_KEY_ID="$(echo $output | awk -F" " '$4=="CREDENTIALS" {print $5}')" + export AWS_SECRET_ACCESS_KEY="$(echo $output | awk -F" " '$4=="CREDENTIALS" {print $7}')" + export AWS_SESSION_TOKEN="$(echo $output | awk -F" " '$4=="CREDENTIALS" {print $8}')" +@@ -198,11 +210,11 @@ + for rtb in $(echo $OCF_RESKEY_routing_table | sed -e 's/,/ /g'); do + ocf_log info "monitor: check routing table (API call) - $rtb" + if [[ -z "${OCF_RESKEY_routing_table_role}" ]]; then +- cmd="$OCF_RESKEY_awscli --profile $OCF_RESKEY_profile --output text ec2 describe-route-tables --route-table-ids $rtb --query RouteTables[*].Routes[?DestinationCidrBlock=='$OCF_RESKEY_ip/32'].InstanceId" ++ cmd="$OCF_RESKEY_awscli --profile $OCF_RESKEY_profile $region_opt --output text ec2 describe-route-tables --route-table-ids $rtb --query RouteTables[*].Routes[?DestinationCidrBlock=='$OCF_RESKEY_ip/32'].InstanceId" + ocf_log debug "executing command: $cmd" + ROUTE_TO_INSTANCE="$($cmd)" + else +- cmd="$OCF_RESKEY_awscli --output text ec2 describe-route-tables --route-table-ids $rtb --query RouteTables[*].Routes[?DestinationCidrBlock=='$OCF_RESKEY_ip/32'].InstanceId" ++ cmd="$OCF_RESKEY_awscli $region_opt --output text ec2 describe-route-tables --route-table-ids $rtb --query RouteTables[*].Routes[?DestinationCidrBlock=='$OCF_RESKEY_ip/32'].InstanceId" + ROUTE_TO_INSTANCE="$(execute_cmd_as_role "$cmd" $OCF_RESKEY_routing_table_role)" + fi + ocf_log debug "Overlay IP is currently routed to ${ROUTE_TO_INSTANCE}" +@@ -283,11 +295,11 @@ + + for rtb in $(echo $OCF_RESKEY_routing_table | sed -e 's/,/ /g'); do + if [[ -z "${OCF_RESKEY_routing_table_role}" ]]; then +- cmd="$OCF_RESKEY_awscli --profile $OCF_RESKEY_profile --output text ec2 replace-route --route-table-id $rtb --destination-cidr-block ${OCF_RESKEY_ip}/32 --network-interface-id $EC2_NETWORK_INTERFACE_ID" ++ cmd="$OCF_RESKEY_awscli --profile $OCF_RESKEY_profile $region_opt --output text ec2 replace-route --route-table-id $rtb --destination-cidr-block ${OCF_RESKEY_ip}/32 --network-interface-id $EC2_NETWORK_INTERFACE_ID" + ocf_log debug "executing command: $cmd" + $cmd + else +- cmd="$OCF_RESKEY_awscli --output text ec2 replace-route --route-table-id $rtb --destination-cidr-block ${OCF_RESKEY_ip}/32 --network-interface-id $EC2_NETWORK_INTERFACE_ID" ++ cmd="$OCF_RESKEY_awscli $region_opt --output text ec2 replace-route --route-table-id $rtb --destination-cidr-block ${OCF_RESKEY_ip}/32 --network-interface-id $EC2_NETWORK_INTERFACE_ID" + update_response="$(execute_cmd_as_role "$cmd" $OCF_RESKEY_routing_table_role)" + fi + rc=$? +@@ -397,7 +409,7 @@ + ec2ip_monitor;; + validate-all) + exit $?;; +- *) ++ *) + echo $USAGE + exit $OCF_ERR_UNIMPLEMENTED + ;; diff --git a/SOURCES/bz1881114-galera-recover-joining-non-existing-cluster.patch b/SOURCES/bz1881114-galera-recover-joining-non-existing-cluster.patch new file mode 100644 index 0000000..17b823a --- /dev/null +++ b/SOURCES/bz1881114-galera-recover-joining-non-existing-cluster.patch @@ -0,0 +1,51 @@ +From 028bd6aab181104fe68166c8ec9c0485e12f9376 Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Fri, 18 Sep 2020 18:34:22 +0200 +Subject: [PATCH] galera: recover from joining a non existing cluster + +galera being a M/S resource, the resource agent decides +when and how to promote a resource based on the current +state of the galera cluster. If there's no cluster, +a resource is promoted as the bootstrap node. Otherwise +it is promoted as a joiner node. + +There can be some time between the moment when a node is +promoted and when the promote operation effectively +takes place. So if a node is promoted for joining a cluster, +all the running galera nodes are stopped before the promote +operation start, the joining node won't be able to join the +cluster, and it can't bootstrap a new one either because it +doesn't have the most recent copy of the DB. + +In that case, do not make the promotion fail, and force +a demotion instead. This ensures that a normal bootstrap +election will take place eventually, without blocking +the joining node due to a failed promotion. +--- + heartbeat/galera | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/galera b/heartbeat/galera +index 74f11d8c5..d2f4faa86 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -727,9 +727,16 @@ galera_promote() + ocf_log info "Node <${NODENAME}> is bootstrapping the cluster" + extra_opts="--wsrep-cluster-address=gcomm://" + else +- ocf_exit_reason "Failure, Attempted to promote Master instance of $OCF_RESOURCE_INSTANCE before bootstrap node has been detected." +- clear_last_commit +- return $OCF_ERR_GENERIC ++ # We are being promoted without having the bootstrap ++ # attribute in the CIB, which means we are supposed to ++ # join a cluster; however if we end up here, there is no ++ # Master remaining right now, which means there is no ++ # cluster to join anymore. So force a demotion, and and ++ # let the RA decide later which node should be the next ++ # bootstrap node. ++ ocf_log warn "There is no running cluster to join, demoting ourself" ++ clear_master_score ++ return $OCF_SUCCESS + fi + fi + diff --git a/SOURCES/bz1886262-podman-recover-from-killed-conmon.patch b/SOURCES/bz1886262-podman-recover-from-killed-conmon.patch new file mode 100644 index 0000000..3fa5934 --- /dev/null +++ b/SOURCES/bz1886262-podman-recover-from-killed-conmon.patch @@ -0,0 +1,63 @@ +From 3aa0dda4e0c2a3b801d65aeacc4fdfd713a604f2 Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Tue, 27 Oct 2020 18:01:36 +0100 +Subject: [PATCH] podman: recover from killed conmon side process + +When podman containers are created by the resource-agent, the podman +runtime spawns a side process (conmon) to monitor the container and +record the exit status. + +If the conmon process dies unexpectedly (e.g. kill -9), the podman +container can still be stopped, even if the cli returns a generic +error. + +Try to distinguish this specific failure condition and make the stop +operation resilient; when it happens, just log a warning and finish +the usual stop actions. +--- + heartbeat/podman | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/podman b/heartbeat/podman +index 81b00ee6f..9f8c2a091 100755 +--- a/heartbeat/podman ++++ b/heartbeat/podman +@@ -419,6 +419,7 @@ podman_start() + podman_stop() + { + local timeout=60 ++ local rc + podman_simple_status + if [ $? -eq $OCF_NOT_RUNNING ]; then + remove_container +@@ -434,16 +435,27 @@ podman_stop() + + if ocf_is_true "$OCF_RESKEY_force_kill"; then + ocf_run podman kill $CONTAINER ++ rc=$? + else + ocf_log debug "waiting $timeout second[s] before killing container" + ocf_run podman stop -t=$timeout $CONTAINER ++ rc=$? + # on stop, systemd will automatically delete any transient + # drop-in conf that has been created earlier + fi + +- if [ $? -ne 0 ]; then +- ocf_exit_reason "Failed to stop container, ${CONTAINER}, based on image, ${OCF_RESKEY_image}." +- return $OCF_ERR_GENERIC ++ if [ $rc -ne 0 ]; then ++ # If the stop failed, it could be because the controlling conmon ++ # process died unexpectedly. If so, a generic error code is returned ++ # but the associated container exit code is -1. If that's the case, ++ # assume there's no failure and continue with the rm as usual. ++ if [ $rc -eq 125 ] && \ ++ podman inspect --format '{{.State.Status}}:{{.State.ExitCode}}' $CONTAINER | grep -wq "stopped:-1"; then ++ ocf_log warn "Container ${CONTAINER} had an unexpected stop outcome. Trying to remove it anyway." ++ else ++ ocf_exit_reason "Failed to stop container, ${CONTAINER}, based on image, ${OCF_RESKEY_image}." ++ return $OCF_ERR_GENERIC ++ fi + fi + + remove_container diff --git a/SOURCES/bz1890068-gcp-pd-move-fix-partially-matched-disk_name.patch b/SOURCES/bz1890068-gcp-pd-move-fix-partially-matched-disk_name.patch new file mode 100644 index 0000000..83aef93 --- /dev/null +++ b/SOURCES/bz1890068-gcp-pd-move-fix-partially-matched-disk_name.patch @@ -0,0 +1,58 @@ +From 2927279ba1677e9dda202121176a8245a7ef76ca Mon Sep 17 00:00:00 2001 +From: tositaka77 <45960626+tositaka77@users.noreply.github.com> +Date: Wed, 14 Oct 2020 22:22:56 +0900 +Subject: [PATCH] fixes and improvements + +- Fixed "regional" PD functionality in attach_disk() +- Improve to exact match disk_name with disks.source in detach_disk() +--- + heartbeat/gcp-pd-move.in | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/gcp-pd-move.in b/heartbeat/gcp-pd-move.in +index f82bd25e5..e99cc71f8 100644 +--- a/heartbeat/gcp-pd-move.in ++++ b/heartbeat/gcp-pd-move.in +@@ -49,6 +49,7 @@ else: + CONN = None + PROJECT = None + ZONE = None ++REGION = None + LIST_DISK_ATTACHED_INSTANCES = None + INSTANCE_NAME = None + +@@ -148,6 +149,7 @@ def populate_vars(): + global INSTANCE_NAME + global PROJECT + global ZONE ++ global REGION + global LIST_DISK_ATTACHED_INSTANCES + + # Populate global vars +@@ -175,6 +177,7 @@ def populate_vars(): + PROJECT = get_metadata('project/project-id') + if PARAMETERS['disk_scope'] in ['detect', 'regional']: + ZONE = get_metadata('instance/zone').split('/')[-1] ++ REGION = ZONE[:-2] + else: + ZONE = PARAMETERS['disk_scope'] + LIST_DISK_ATTACHED_INSTANCES = get_disk_attached_instances( +@@ -255,7 +258,7 @@ def detach_disk(instance, disk_name): + + device_name = None + for disk in response['disks']: +- if disk_name in disk['source']: ++ if disk_name == re.sub('.*disks/',"",disk['source']): + device_name = disk['deviceName'] + break + +@@ -273,6 +276,9 @@ def detach_disk(instance, disk_name): + + def attach_disk(instance, disk_name): + location = 'zones/%s' % ZONE ++ if PARAMETERS['disk_scope'] == 'regional': ++ location = 'regions/%s' % REGION ++ + prefix = 'https://www.googleapis.com/compute/v1' + body = { + 'source': '%(prefix)s/projects/%(project)s/%(location)s/disks/%(disk)s' % { diff --git a/SOURCES/bz1891835-galera-set-bootstrap-attribute-before-promote.patch b/SOURCES/bz1891835-galera-set-bootstrap-attribute-before-promote.patch new file mode 100644 index 0000000..7dfdc48 --- /dev/null +++ b/SOURCES/bz1891835-galera-set-bootstrap-attribute-before-promote.patch @@ -0,0 +1,36 @@ +From ac213f158ff851422d78ae8f56b022e8e30751bc Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Mon, 26 Oct 2020 14:54:05 +0100 +Subject: [PATCH] galera: set bootstrap attribute before promote + +When the master detection takes place, the node chosen for +becoming the master is given two attributes in the CIB: +a master score and a bootstrap flag. The master score makes +pacemaker schedule a promote operation, and the bootstrap flag +drives how the galera server is started. + +The order in which we set the attributes is racy; it may happen +that a promote operation is started before the current master +detection function has set the bootstrap flag, in which case +the promotion will fail. + +Reverse the order in which we set the attributes on a bootstrap +node to close the race. +--- + heartbeat/galera | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/galera b/heartbeat/galera +index d2f4faa86..b4d7e187d 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -587,8 +587,8 @@ detect_first_master() + fi + + ocf_log info "Promoting $best_node to be our bootstrap node" +- set_master_score $best_node + set_bootstrap_node $best_node ++ set_master_score $best_node + } + + detect_safe_to_bootstrap() diff --git a/SOURCES/bz1891855-galera-recover-2-node-cluster.patch b/SOURCES/bz1891855-galera-recover-2-node-cluster.patch new file mode 100644 index 0000000..22ab885 --- /dev/null +++ b/SOURCES/bz1891855-galera-recover-2-node-cluster.patch @@ -0,0 +1,80 @@ +--- a/heartbeat/galera 2020-10-28 16:28:48.125700714 +0100 ++++ b/heartbeat/galera 2020-10-28 16:31:14.932820752 +0100 +@@ -81,6 +81,11 @@ + . /etc/default/clustercheck + fi + ++# Parameter defaults ++ ++OCF_RESKEY_two_node_mode_default="false" ++: ${OCF_RESKEY_two_node_mode=${OCF_RESKEY_two_node_mode_default}} ++ + ####################################################################### + + usage() { +@@ -249,6 +254,16 @@ + + + ++ ++ ++If running in a 2-node pacemaker cluster, rely on pacemaker quorum ++to allow automatic recovery even when the other node is unreachable. ++Use it with caution! (and fencing) ++ ++Special recovery when running on a 2-node cluster ++ ++ ++ + + + +@@ -400,6 +415,27 @@ + return 0 + } + ++is_two_node_mode_active() ++{ ++ # crm_node or corosync-quorumtool cannot access various corosync ++ # flags when running inside a bundle, so only count the cluster ++ # members ++ ocf_is_true "$OCF_RESKEY_two_node_mode" && ${HA_SBIN_DIR}/crm_mon -1X | xmllint --xpath "count(//nodes/node[@type='member'])" - | grep -q -w 2 ++} ++ ++is_last_node_in_quorate_partition() ++{ ++ # when a network split occurs in a 2-node cluster, pacemaker ++ # fences the other node and try to retain quorum. So until ++ # the fencing is resolved (and the status of the peer node ++ # is clean), we shouldn't consider ourself quorate. ++ local partition_members=$(${HA_SBIN_DIR}/crm_node -p | wc -w) ++ local quorate=$(${HA_SBIN_DIR}/crm_node -q) ++ local clean_members=$(${HA_SBIN_DIR}/crm_mon -1X | xmllint --xpath 'count(//nodes/node[@type="member" and @unclean="false"])' -) ++ ++ [ "$partition_members" = 1 ] && [ "$quorate" = 1 ] && [ "$clean_members" = 2 ] ++} ++ + master_exists() + { + if [ "$__OCF_ACTION" = "demote" ]; then +@@ -518,8 +554,20 @@ + done + + for node in $nodes_recovered $nodes; do ++ # On clean shutdown, galera sets the last stopped node as 'safe to bootstrap', ++ # so use this hint when we can + safe_to_bootstrap=$(get_safe_to_bootstrap $node) + ++ # Special case for 2-node clusters: during a network split, rely on ++ # pacemaker's quorum to check whether we can restart galera ++ if [ "$safe_to_bootstrap" != "1" ] && [ "$node" = "$NODENAME" ] && is_two_node_mode_active; then ++ is_last_node_in_quorate_partition ++ if [ $? -eq 0 ]; then ++ ocf_log warn "Survived a split in a 2-node cluster, considering ourselves safe to bootstrap" ++ safe_to_bootstrap=1 ++ fi ++ fi ++ + if [ "$safe_to_bootstrap" = "1" ]; then + # Galera marked the node as safe to boostrap during shutdown. Let's just + # pick it as our bootstrap node. diff --git a/SOURCES/bz1895811-aws-vpc-move-ip-dont-warn-for-expected-scenarios.patch b/SOURCES/bz1895811-aws-vpc-move-ip-dont-warn-for-expected-scenarios.patch new file mode 100644 index 0000000..385e034 --- /dev/null +++ b/SOURCES/bz1895811-aws-vpc-move-ip-dont-warn-for-expected-scenarios.patch @@ -0,0 +1,84 @@ +From 8d459216c9718269303b9caf227a971d73ec4df9 Mon Sep 17 00:00:00 2001 +From: Reid Wahl +Date: Thu, 27 Aug 2020 01:34:01 -0700 +Subject: [PATCH] aws-vpc-move-ip: Don't warn for expected scenarios + +Make log levels more appropriate to the situation. Before this patch, a +normal start looked like this: + +Operation start for aws-vip (ocf:heartbeat:aws-vpc-move-ip) returned: 'ok' (0) + > stderr: Nov 09 02:38:20 INFO: EC2: Moving IP address 10.0.1.65 to this host by adjusting routing table rtb-01b4ea1ae0ec0a4d9 + > stderr: Nov 09 02:38:20 INFO: monitor: check routing table (API call) - rtb-01b4ea1ae0ec0a4d9 + > stderr: Nov 09 02:38:22 WARNING: IP 10.0.1.65 not assigned to running interface + > stderr: Nov 09 02:38:22 INFO: EC2: Adjusting routing table and locally configuring IP address + > stderr: RTNETLINK answers: Cannot assign requested address + > stderr: Nov 09 02:38:24 WARNING: command failed, rc 2 + > stderr: Nov 09 02:38:24 INFO: monitor: check routing table (API call) - rtb-01b4ea1ae0ec0a4d9 + +Now it looks like this: + +Operation start for aws-vip (ocf:heartbeat:aws-vpc-move-ip) returned: 'ok' (0) + > stderr: Nov 09 02:40:43 INFO: EC2: Moving IP address 10.0.1.65 to this host by adjusting routing table rtb-01b4ea1ae0ec0a4d9 + > stderr: Nov 09 02:40:43 INFO: monitor: check routing table (API call) - rtb-01b4ea1ae0ec0a4d9 + > stderr: Nov 09 02:40:44 INFO: IP 10.0.1.65 not assigned to running interface + > stderr: Nov 09 02:40:44 INFO: EC2: Adjusting routing table and locally configuring IP address + > stderr: Nov 09 02:40:46 INFO: monitor: check routing table (API call) - rtb-01b4ea1ae0ec0a4d9 + +Under normal circumstances, the call to `ec2ip_drop()` within +`ec2ip_get_and_configure` should not be required at all. The drop +function deletes the address before the get_and_configure function +immediately re-adds the address. This call could probably be removed +altogether. Instead, I left the call and silenced its output just in +case of unexpected edge cases. + +Resolves: RHBZ#1895811 + +Signed-off-by: Reid Wahl +--- + heartbeat/aws-vpc-move-ip | 23 ++++++++++++++++++++--- + 1 file changed, 20 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/aws-vpc-move-ip b/heartbeat/aws-vpc-move-ip +index a5b28ad92..72a89ecb1 100755 +--- a/heartbeat/aws-vpc-move-ip ++++ b/heartbeat/aws-vpc-move-ip +@@ -270,7 +270,13 @@ ec2ip_monitor() { + ocf_log debug "executing command: $cmd" + RESULT=$($cmd | grep "$OCF_RESKEY_ip") + if [ -z "$RESULT" ]; then +- ocf_log warn "IP $OCF_RESKEY_ip not assigned to running interface" ++ if [ "$__OCF_ACTION" = "monitor" ] && ! ocf_is_probe; then ++ level="error" ++ else ++ level="info" ++ fi ++ ++ ocf_log "$level" "IP $OCF_RESKEY_ip not assigned to running interface" + return $OCF_NOT_RUNNING + fi + +@@ -282,11 +288,22 @@ ec2ip_monitor() { + ec2ip_drop() { + cmd="ip addr delete ${OCF_RESKEY_ip}/32 dev $OCF_RESKEY_interface" + ocf_log debug "executing command: $cmd" +- $cmd ++ output=$($cmd 2>&1) + rc=$? ++ + if [ "$rc" -gt 0 ]; then +- ocf_log warn "command failed, rc $rc" ++ if [ "$__OCF_ACTION" = "start" ]; then ++ # expected to fail during start ++ level="debug" ++ else ++ level="warn" ++ fi ++ ++ ocf_log "$level" "command failed, rc $rc" ++ ocf_log "$level" "output/error: $output" + return $OCF_ERR_GENERIC ++ else ++ ocf_log debug "output/error: $output" + fi + + # delete remaining route-entries if any diff --git a/SOURCES/bz1897570-aws-add-imdsv2-support.patch b/SOURCES/bz1897570-aws-add-imdsv2-support.patch new file mode 100644 index 0000000..09772cc --- /dev/null +++ b/SOURCES/bz1897570-aws-add-imdsv2-support.patch @@ -0,0 +1,97 @@ +From 8f10d0eb1e33d38ab6e89015a903620c54edd7c1 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 13 Nov 2020 16:36:20 +0100 +Subject: [PATCH] AWS agents: add support for IMDSv2 + +--- + heartbeat/aws-vpc-move-ip | 5 +++-- + heartbeat/aws-vpc-route53.in | 3 ++- + heartbeat/awseip | 9 +++++---- + heartbeat/awsvip | 7 ++++--- + 4 files changed, 14 insertions(+), 10 deletions(-) + +diff --git a/heartbeat/aws-vpc-move-ip b/heartbeat/aws-vpc-move-ip +index 72a89ecb1..cbb629b00 100755 +--- a/heartbeat/aws-vpc-move-ip ++++ b/heartbeat/aws-vpc-move-ip +@@ -215,7 +215,8 @@ ec2ip_validate() { + return $OCF_ERR_CONFIGURED + fi + +- EC2_INSTANCE_ID="$(curl -s http://169.254.169.254/latest/meta-data/instance-id)" ++ TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") ++ EC2_INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id -H "X-aws-ec2-metadata-token: $TOKEN") + + if [ -z "${EC2_INSTANCE_ID}" ]; then + ocf_exit_reason "Instance ID not found. Is this a EC2 instance?" +@@ -329,7 +330,7 @@ ec2ip_get_instance_eni() { + fi + ocf_log debug "MAC address associated with interface ${OCF_RESKEY_interface}: ${MAC_ADDR}" + +- cmd="curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC_ADDR}/interface-id" ++ cmd="curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC_ADDR}/interface-id -H \"X-aws-ec2-metadata-token: $TOKEN\"" + ocf_log debug "executing command: $cmd" + EC2_NETWORK_INTERFACE_ID="$(eval $cmd)" + rc=$? +diff --git a/heartbeat/aws-vpc-route53.in b/heartbeat/aws-vpc-route53.in +index b06b93726..4fb17019b 100644 +--- a/heartbeat/aws-vpc-route53.in ++++ b/heartbeat/aws-vpc-route53.in +@@ -347,7 +347,8 @@ r53_monitor() { + _get_ip() { + case $OCF_RESKEY_ip in + local|public) +- IPADDRESS="$(curl -s http://169.254.169.254/latest/meta-data/${OCF_RESKEY_ip}-ipv4)";; ++ TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") ++ IPADDRESS=$(curl -s http://169.254.169.254/latest/meta-data/${OCF_RESKEY_ip}-ipv4 -H "X-aws-ec2-metadata-token: $TOKEN");; + *.*.*.*) + IPADDRESS="${OCF_RESKEY_ip}";; + esac +diff --git a/heartbeat/awseip b/heartbeat/awseip +index 445a03666..de1967774 100755 +--- a/heartbeat/awseip ++++ b/heartbeat/awseip +@@ -149,12 +149,12 @@ awseip_start() { + awseip_monitor && return $OCF_SUCCESS + + if [ -n "${PRIVATE_IP_ADDRESS}" ]; then +- NETWORK_INTERFACES_MACS="$(curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/)" ++ NETWORK_INTERFACES_MACS=$(curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/ -H "X-aws-ec2-metadata-token: $TOKEN") + for MAC in ${NETWORK_INTERFACES_MACS}; do +- curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC}/local-ipv4s | ++ curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC}/local-ipv4s -H "X-aws-ec2-metadata-token: $TOKEN" | + grep -q "^${PRIVATE_IP_ADDRESS}$" + if [ $? -eq 0 ]; then +- NETWORK_ID="$(curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC}/interface-id)" ++ NETWORK_ID=$(curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC}/interface-id -H "X-aws-ec2-metadata-token: $TOKEN") + fi + done + $AWSCLI --profile $OCF_RESKEY_profile ec2 associate-address \ +@@ -244,7 +244,8 @@ AWSCLI="${OCF_RESKEY_awscli}" + ELASTIC_IP="${OCF_RESKEY_elastic_ip}" + ALLOCATION_ID="${OCF_RESKEY_allocation_id}" + PRIVATE_IP_ADDRESS="${OCF_RESKEY_private_ip_address}" +-INSTANCE_ID="$(curl -s http://169.254.169.254/latest/meta-data/instance-id)" ++TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") ++INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id -H "X-aws-ec2-metadata-token: $TOKEN") + + case $__OCF_ACTION in + start) +diff --git a/heartbeat/awsvip b/heartbeat/awsvip +index 3eb31e6ae..8050107e8 100755 +--- a/heartbeat/awsvip ++++ b/heartbeat/awsvip +@@ -206,9 +206,10 @@ esac + + AWSCLI="${OCF_RESKEY_awscli}" + SECONDARY_PRIVATE_IP="${OCF_RESKEY_secondary_private_ip}" +-INSTANCE_ID="$(curl -s http://169.254.169.254/latest/meta-data/instance-id)" +-MAC_ADDRESS="$(curl -s http://169.254.169.254/latest/meta-data/mac)" +-NETWORK_ID="$(curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC_ADDRESS}/interface-id)" ++TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") ++INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id -H "X-aws-ec2-metadata-token: $TOKEN") ++MAC_ADDRESS=$(curl -s http://169.254.169.254/latest/meta-data/mac -H "X-aws-ec2-metadata-token: $TOKEN") ++NETWORK_ID=$(curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC_ADDRESS}/interface-id -H "X-aws-ec2-metadata-token: $TOKEN") + + case $__OCF_ACTION in + start) diff --git a/SOURCES/bz1898690-crypt-make-key_file-crypt_type_not-unique.patch b/SOURCES/bz1898690-crypt-make-key_file-crypt_type_not-unique.patch new file mode 100644 index 0000000..8cecc16 --- /dev/null +++ b/SOURCES/bz1898690-crypt-make-key_file-crypt_type_not-unique.patch @@ -0,0 +1,31 @@ +From 16236f76d086187f6ae6202153519c1eb2fe4f87 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 24 Nov 2020 10:49:14 +0100 +Subject: [PATCH] crypt: make key_file and crypt_type parameters not unique + +--- + heartbeat/crypt | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/crypt b/heartbeat/crypt +index 0e49b6c2d..7d0a5607c 100755 +--- a/heartbeat/crypt ++++ b/heartbeat/crypt +@@ -86,7 +86,7 @@ The resulting block device path is /dev/mapper/name. + + + +- ++ + + Key file path containing the encryption passphrase + (aka key; see cryptsetup(8)). For LUKS, the passphrase as of the key_file +@@ -96,7 +96,7 @@ parameter is used to decrypt a randomly selected key when the device was created + + + +- ++ + + Encryption (device) type (e.g. "luks" or "luks2"). + diff --git a/SOURCES/bz1899551-NovaEvacuate-fix-delay_evacuate-unset.patch b/SOURCES/bz1899551-NovaEvacuate-fix-delay_evacuate-unset.patch new file mode 100644 index 0000000..7af35cc --- /dev/null +++ b/SOURCES/bz1899551-NovaEvacuate-fix-delay_evacuate-unset.patch @@ -0,0 +1,33 @@ +From 11ac2db8f55aa3e6858d6c1b2ab29ee36b612f03 Mon Sep 17 00:00:00 2001 +From: Michele Baldessari +Date: Tue, 17 Nov 2020 15:16:29 +0100 +Subject: [PATCH] Fix delay_evacuate being unset + +In Ie2fe784202d754eda38092479b1ab3ff4d02136a we added an additional +parameter to allow for setting a delay on the evacuation. +While it was tested with a specific delay, the case with a delay +being unset was missed. +Since OCF does not set the defaults from the metadata specification +for a parameter, we need to manually set it ourselves. + +This fixes the following error: +Nov 17 13:00:21 database-1.foo.local pacemaker-execd [185805] (log_op_output) notice: nova-evacuate_monitor_10000[1038417] error output [ /usr/lib/ocf/resource.d/openstack/NovaEvacuate: line 228: [: !=: unary operator expected ] + +Change-Id: I0b7aacd67b77bc44c67fe7da4c494807abbbb4f3 +--- + +diff --git a/heartbeat/NovaEvacuate b/heartbeat/NovaEvacuate +index 596f520..8aa778c 100644 +--- a/heartbeat/NovaEvacuate ++++ b/heartbeat/NovaEvacuate +@@ -359,6 +359,10 @@ + fence_options="${fence_options} -e ${OCF_RESKEY_endpoint_type}" + fi + ++ if [ -z "${OCF_RESKEY_evacuate_delay}" ]; then ++ OCF_RESKEY_evacuate_delay=0 ++ fi ++ + if [ $rc != $OCF_SUCCESS ]; then + exit $rc + fi diff --git a/SOURCES/bz1900015-podman-recover-from-storage-out-of-sync.patch b/SOURCES/bz1900015-podman-recover-from-storage-out-of-sync.patch new file mode 100644 index 0000000..e022612 --- /dev/null +++ b/SOURCES/bz1900015-podman-recover-from-storage-out-of-sync.patch @@ -0,0 +1,64 @@ +From 52d09b57a499ed7b3757e0e2954c2783198d5b23 Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Mon, 9 Nov 2020 20:42:19 +0100 +Subject: [PATCH] podman: recover from podman's storage being out of sync + +If a system crash while podman is stopping a container (e.g. a fencing action +took place), it might happen that on reboot, podman is not able to recreate +a container as requested by the resource agent. + +When such a start operation fails, it might be because the internal storage +layer still references an old container with the same name, even though podman +itself thinks there is no such container. If so, purge the storage layer to try +to clean the corruption and try recreating the container. +--- + heartbeat/podman | 29 +++++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/podman b/heartbeat/podman +index 81b00ee6f..d4d608ca3 100755 +--- a/heartbeat/podman ++++ b/heartbeat/podman +@@ -345,6 +345,32 @@ create_transient_drop_in_dependency() + } + + ++run_new_container() ++{ ++ local opts=$1 ++ local image=$2 ++ local cmd=$3 ++ local rc ++ ++ ocf_log info "running container $CONTAINER for the first time" ++ ocf_run podman run $opts $image $cmd ++ rc=$? ++ if [ $rc -eq 125 ]; then ++ # If an internal podman error occurred, it might be because ++ # the internal storage layer still references an old container ++ # with the same name, even though podman itself thinks there ++ # is no such container. If so, purge the storage layer to try ++ # to clean the corruption and try again. ++ ocf_log warn "Internal podman error while creating new container $CONTAINER. Retrying." ++ ocf_run podman rm --storage $CONTAINER ++ ocf_run podman run $opts $image $cmd ++ rc=$? ++ fi ++ ++ return $rc ++} ++ ++ + podman_start() + { + local cid +@@ -378,8 +404,7 @@ podman_start() + # make sure any previous container matching our container name is cleaned up first. + # we already know at this point it wouldn't be running + remove_container +- ocf_log info "running container $CONTAINER for the first time" +- ocf_run podman run $run_opts $OCF_RESKEY_image $OCF_RESKEY_run_cmd ++ run_new_container "$run_opts" $OCF_RESKEY_image "$OCF_RESKEY_run_cmd" + fi + rc=$? + diff --git a/SOURCES/bz1901357-crypt-1-support-symlink-devices.patch b/SOURCES/bz1901357-crypt-1-support-symlink-devices.patch new file mode 100644 index 0000000..6b4f385 --- /dev/null +++ b/SOURCES/bz1901357-crypt-1-support-symlink-devices.patch @@ -0,0 +1,23 @@ +From 4ded33d34505af19ddf19bfa125b5e6c243ebd94 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 26 Nov 2020 12:56:03 +0100 +Subject: [PATCH] crypt: allow encrypted_dev to be symlink to support using + devices in /dev/disk/... or UUID + +--- + heartbeat/crypt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/crypt b/heartbeat/crypt +index 7d0a5607c..3ca28b92d 100755 +--- a/heartbeat/crypt ++++ b/heartbeat/crypt +@@ -177,7 +177,7 @@ crypt_validate_all() { + esac + esac + fi +- if [ ! -b "$encrypted_dev" ]; then ++ if [ ! -b "$encrypted_dev" ] && [ ! -L "$encrypted_dev" ]; then + ocf_exit_reason "Encrypted device $encrypted_dev not accessible" + return $OCF_ERR_ARGS + fi diff --git a/SOURCES/bz1901357-crypt-2-dont-sanity-check-during-probe.patch b/SOURCES/bz1901357-crypt-2-dont-sanity-check-during-probe.patch new file mode 100644 index 0000000..4e259d4 --- /dev/null +++ b/SOURCES/bz1901357-crypt-2-dont-sanity-check-during-probe.patch @@ -0,0 +1,44 @@ +From 6a45c28cd074e14a7bc2e2531b15595b9985965c Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 1 Dec 2020 10:11:52 +0100 +Subject: [PATCH] crypt: avoid failing for LVM exclusive by not running full + sanity check during probes + +--- + heartbeat/crypt | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/crypt b/heartbeat/crypt +index 3ca28b92d..05bded7c5 100755 +--- a/heartbeat/crypt ++++ b/heartbeat/crypt +@@ -177,6 +177,13 @@ crypt_validate_all() { + esac + esac + fi ++ ++ # return early for probes where device might not be available yet ++ # e.g. LVM exclusive volumes ++ if ocf_is_probe; then ++ return $OCF_SUCCESS ++ fi ++ + if [ ! -b "$encrypted_dev" ] && [ ! -L "$encrypted_dev" ]; then + ocf_exit_reason "Encrypted device $encrypted_dev not accessible" + return $OCF_ERR_ARGS +@@ -294,11 +301,13 @@ crypt_stop() { + crypt_monitor() { + cryptsetup status $crypt_dev $disable_locks >/dev/null 2>&1 + if [ $? -eq 0 ]; then +- [ -L $crypt_dev_path ] && return $OCF_SUCCESS ++ if [ -b "$encrypted_dev" ] || [ -L $crypt_dev_path ]; then ++ return $OCF_SUCCESS ++ fi + return $OCF_ERR_GENERIC + fi + +- [ "$__OCF_ACTION" = "monitor" ] && ! ocf_is_probe && ocf_exit_reason "Crypt resource not running" ++ [ "$__OCF_ACTION" = "monitor" ] && ! ocf_is_probe && ocf_exit_reason "Crypt resource not running" + return $OCF_NOT_RUNNING + } + diff --git a/SOURCES/bz1902208-LVM-activate-stop-before-storage-service.patch b/SOURCES/bz1902208-LVM-activate-stop-before-storage-service.patch new file mode 100644 index 0000000..1486b29 --- /dev/null +++ b/SOURCES/bz1902208-LVM-activate-stop-before-storage-service.patch @@ -0,0 +1,60 @@ +From 79fb4b2d3d862f4e83b1df72107b6322b420ea34 Mon Sep 17 00:00:00 2001 +From: Reid Wahl +Date: Sat, 28 Nov 2020 18:10:03 -0800 +Subject: [PATCH] LVM-activate: Stop before blk-availability.service + +If storage services (e.g., iscsi-shutdown.service) stop before an +LVM-activate resource stops, the managed VG may become unavailable. Then +the LVM-activate resource may fail to deactivate the volume group and +thus fail its stop operation. + +This commit adds a systemd drop-in "After=blk-availability.service" +directive for resource-agents-deps.target during the LVM-activate start +op. blk-availability includes "After=" directives for other storage +services and thus serves as a convenient wrapper. + +blk-availability is not enabled by default, and a "Wants=" drop-in +that's created after Pacemaker starts would not be able to start +blk-availability automatically. So here we also start blk-availability +during LVM_start(). + +Resolves RHBZ#1902208 + +Signed-off-by: Reid Wahl +--- + heartbeat/LVM-activate | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/heartbeat/LVM-activate b/heartbeat/LVM-activate +index 94f9e5813..b8abd7579 100755 +--- a/heartbeat/LVM-activate ++++ b/heartbeat/LVM-activate +@@ -830,6 +830,28 @@ lvm_start() { + local rc + local vol + ++ if systemd_is_running ; then ++ # Create drop-in to deactivate VG before stopping ++ # storage services during shutdown/reboot. ++ after=$(systemctl show resource-agents-deps.target.d \ ++ --property=After | cut -d'=' -f2) ++ ++ case "$after" in ++ *" blk-availability.service "*) ++ ;; ++ *) ++ systemd_drop_in "99-LVM-activate" "After" \ ++ "blk-availability.service" ++ ;; ++ esac ++ ++ # If blk-availability isn't started, the "After=" ++ # directive has no effect. ++ if ! systemctl is-active blk-availability.service ; then ++ systemctl start blk-availability.service ++ fi ++ fi ++ + if lvm_status ; then + ocf_log info "${vol}: is already active." + return $OCF_SUCCESS diff --git a/SOURCES/bz1903677-ocf-shellfuncs-fix-traceback-redirection-bash5.patch b/SOURCES/bz1903677-ocf-shellfuncs-fix-traceback-redirection-bash5.patch new file mode 100644 index 0000000..8472065 --- /dev/null +++ b/SOURCES/bz1903677-ocf-shellfuncs-fix-traceback-redirection-bash5.patch @@ -0,0 +1,45 @@ +From 908431d416076e3ceb70cc95871957d15265a949 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 2 Dec 2020 16:48:32 +0100 +Subject: [PATCH] ocf-shellfuncs: make ocf_is_bash4() detect Bash v4 or greater + (which it was supposed to according to the comments) + +--- + heartbeat/ocf-shellfuncs.in | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index b8d47e3d5..ac75dfc87 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -907,13 +907,18 @@ ocf_unique_rundir() + # NB: FD 9 may be used for tracing with bash >= v4 in case + # OCF_TRACE_FILE is set to a path. + # +-ocf_is_bash4() { ++ocf_bash_has_xtracefd() { + echo "$SHELL" | grep bash > /dev/null && +- [ ${BASH_VERSINFO[0]} = "4" ] ++ [ ${BASH_VERSINFO[0]} -ge 4 ] ++} ++# for backwards compatibility ++ocf_is_bash4() { ++ ocf_bash_has_xtracefd ++ return $? + } + ocf_trace_redirect_to_file() { + local dest=$1 +- if ocf_is_bash4; then ++ if ocf_bash_has_xtracefd; then + exec 9>$dest + BASH_XTRACEFD=9 + else +@@ -922,7 +927,7 @@ ocf_trace_redirect_to_file() { + } + ocf_trace_redirect_to_fd() { + local fd=$1 +- if ocf_is_bash4; then ++ if ocf_bash_has_xtracefd; then + BASH_XTRACEFD=$fd + else + exec 2>&$fd diff --git a/SOURCES/bz1913932-1-gcp-vpc-move-add-project-parameter.patch b/SOURCES/bz1913932-1-gcp-vpc-move-add-project-parameter.patch new file mode 100644 index 0000000..16cfb10 --- /dev/null +++ b/SOURCES/bz1913932-1-gcp-vpc-move-add-project-parameter.patch @@ -0,0 +1,86 @@ +From 560683500b3f9d5d8e183a569daea27422ae5268 Mon Sep 17 00:00:00 2001 +From: Reid Wahl +Date: Thu, 7 Jan 2021 12:25:04 -0800 +Subject: [PATCH] gcp-vpc-move-route, gcp-vpc-move-vip: Parameterize project ID + +Resolves: RHBZ#1913932 +Resolves: RHBZ#1913936 + +Signed-off-by: Reid Wahl +--- + heartbeat/gcp-vpc-move-route.in | 13 ++++++++++++- + heartbeat/gcp-vpc-move-vip.in | 16 ++++++++++++++-- + 2 files changed, 26 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/gcp-vpc-move-route.in b/heartbeat/gcp-vpc-move-route.in +index d8e8ea8dd..179eba15a 100644 +--- a/heartbeat/gcp-vpc-move-route.in ++++ b/heartbeat/gcp-vpc-move-route.in +@@ -106,6 +106,16 @@ Name of the VPC network + + + ++ ++ ++Project ID of the instance. It can be useful to set this attribute if ++the instance is in a shared service project. Otherwise, the agent should ++be able to determine the project ID automatically. ++ ++Project ID ++ ++ ++ + + + Name of the network interface +@@ -215,7 +225,8 @@ def validate(ctx): + try: + ctx.instance = get_metadata('instance/name') + ctx.zone = get_metadata('instance/zone').split('/')[-1] +- ctx.project = get_metadata('project/project-id') ++ ctx.project = os.environ.get( ++ 'OCF_RESKEY_project', get_metadata('project/project-id')) + except Exception as e: + logger.error( + 'Instance information not found. Is this a GCE instance ?: %s', str(e)) +diff --git a/heartbeat/gcp-vpc-move-vip.in b/heartbeat/gcp-vpc-move-vip.in +index 01d91a59d..e792f71d5 100755 +--- a/heartbeat/gcp-vpc-move-vip.in ++++ b/heartbeat/gcp-vpc-move-vip.in +@@ -75,6 +75,16 @@ METADATA = \ + Host list + + ++ ++ ++ Project ID of the instance. It can be useful to set this ++ attribute if the instance is in a shared service project. ++ Otherwise, the agent should be able to determine the project ID ++ automatically. ++ ++ Project ID ++ ++ + + If enabled (set to true), IP failover logs will be posted to stackdriver logging + Stackdriver-logging support +@@ -267,7 +277,8 @@ def get_instances_list(project, exclude): + def gcp_alias_start(alias): + my_aliases = get_localhost_aliases() + my_zone = get_metadata('instance/zone').split('/')[-1] +- project = get_metadata('project/project-id') ++ project = os.environ.get( ++ 'OCF_RESKEY_project', get_metadata('project/project-id')) + + if alias in my_aliases: + # TODO: Do we need to check alias_range_name? +@@ -315,7 +326,8 @@ def gcp_alias_start(alias): + def gcp_alias_stop(alias): + my_aliases = get_localhost_aliases() + my_zone = get_metadata('instance/zone').split('/')[-1] +- project = get_metadata('project/project-id') ++ project = os.environ.get( ++ 'OCF_RESKEY_project', get_metadata('project/project-id')) + + if alias in my_aliases: + logger.info('Removing %s from %s' % (alias, THIS_VM)) diff --git a/SOURCES/bz1913932-2-gcp-vpc-move-route-fixes.patch b/SOURCES/bz1913932-2-gcp-vpc-move-route-fixes.patch new file mode 100644 index 0000000..a94f0ee --- /dev/null +++ b/SOURCES/bz1913932-2-gcp-vpc-move-route-fixes.patch @@ -0,0 +1,106 @@ +From 523c4cee64b3b8ee9f603a940d83a6628531078d Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 19 Jan 2021 10:56:47 +0100 +Subject: [PATCH 1/2] gcp-vpc-move-route: fix stop-action when route stopped, + and fix check_conflicting_routes() + +--- + heartbeat/gcp-vpc-move-route.in | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +diff --git a/heartbeat/gcp-vpc-move-route.in b/heartbeat/gcp-vpc-move-route.in +index 179eba15a..9fe985832 100644 +--- a/heartbeat/gcp-vpc-move-route.in ++++ b/heartbeat/gcp-vpc-move-route.in +@@ -252,8 +252,19 @@ def validate(ctx): + def check_conflicting_routes(ctx): + fl = '(destRange = "%s*") AND (network = "%s") AND (name != "%s")' % ( + ctx.ip, ctx.vpc_network_url, ctx.route_name) +- request = ctx.conn.routes().list(project=ctx.project, filter=fl) +- response = request.execute() ++ try: ++ request = ctx.conn.routes().list(project=ctx.project, filter=fl) ++ response = request.execute() ++ except googleapiclient.errors.HttpError as e: ++ if e.resp.status == 404: ++ logger.error('VPC network not found') ++ if 'stop' in sys.argv[1]: ++ sys.exit(OCF_SUCCESS) ++ else: ++ sys.exit(OCF_ERR_CONFIGURED) ++ else: ++ raise ++ + route_list = response.get('items', None) + if route_list: + logger.error( +@@ -353,16 +364,16 @@ def route_monitor(ctx): + logger.info('GCP route monitor: checking route table') + + # Ensure that there is no route that we are not aware of that is also handling our IP +- check_conflicting_routes ++ check_conflicting_routes(ctx) + + try: + request = ctx.conn.routes().get(project=ctx.project, route=ctx.route_name) + response = request.execute() + except googleapiclient.errors.HttpError as e: +- if 'Insufficient Permission' in e.content: +- return OCF_ERR_PERM +- elif e.resp.status == 404: ++ if e.resp.status == 404: + return OCF_NOT_RUNNING ++ elif 'Insufficient Permission' in e.content: ++ return OCF_ERR_PERM + else: + raise + + +From 50dbfc3230e87b8d29163c235e6866d15fd6fc1b Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 19 Jan 2021 11:50:22 +0100 +Subject: [PATCH 2/2] gcp-vpc-move-vip: correctly return error when no + instances are returned + +--- + heartbeat/gcp-vpc-move-vip.in | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/heartbeat/gcp-vpc-move-vip.in b/heartbeat/gcp-vpc-move-vip.in +index e792f71d5..bbbd87b7a 100755 +--- a/heartbeat/gcp-vpc-move-vip.in ++++ b/heartbeat/gcp-vpc-move-vip.in +@@ -263,8 +263,14 @@ def get_instances_list(project, exclude): + hostlist = [] + request = CONN.instances().aggregatedList(project=project) + while request is not None: +- response = request.execute() +- zones = response.get('items', {}) ++ try: ++ response = request.execute() ++ zones = response.get('items', {}) ++ except googleapiclient.errors.HttpError as e: ++ if e.resp.status == 404: ++ logger.debug('get_instances_list(): no instances found') ++ return '' ++ + for zone in zones.values(): + for inst in zone.get('instances', []): + if inst['name'] != exclude: +@@ -303,9 +309,13 @@ def gcp_alias_start(alias): + break + + # Add alias IP range to localhost +- add_alias( +- project, my_zone, THIS_VM, alias, +- os.environ.get('OCF_RESKEY_alias_range_name')) ++ try: ++ add_alias( ++ project, my_zone, THIS_VM, alias, ++ os.environ.get('OCF_RESKEY_alias_range_name')) ++ except googleapiclient.errors.HttpError as e: ++ if e.resp.status == 404: ++ sys.exit(OCF_ERR_CONFIGURED) + + # Verify that the IP range has been added + my_aliases = get_localhost_aliases() diff --git a/SPECS/resource-agents.spec b/SPECS/resource-agents.spec index 8738405..089ec99 100644 --- a/SPECS/resource-agents.spec +++ b/SPECS/resource-agents.spec @@ -70,7 +70,7 @@ Name: resource-agents Summary: Open Source HA Reusable Cluster Resource Scripts Version: 4.1.1 -Release: 60%{?rcver:%{rcver}}%{?numcomm:.%{numcomm}}%{?alphatag:.%{alphatag}}%{?dirty:.%{dirty}}%{?dist} +Release: 86%{?rcver:%{rcver}}%{?numcomm:.%{numcomm}}%{?alphatag:.%{alphatag}}%{?dirty:.%{dirty}}%{?dist} License: GPLv2+ and LGPLv2+ URL: https://github.com/ClusterLabs/resource-agents %if 0%{?fedora} || 0%{?centos_version} || 0%{?rhel} @@ -215,7 +215,7 @@ Patch123: bz1744190-pgsql-1-set-primary-standby-initial-score.patch Patch124: bz1744190-pgsql-2-improve-start-checks.patch Patch125: bz1820523-exportfs-1-add-symlink-support.patch Patch126: bz1832321-rabbitmq-cluster-increase-wait-timeout.patch -Patch127: bz1818997-nfsserver-fix-nfsv4-only-support.patch +Patch127: bz1818997-nfsserver-1-fix-nfsv4-only-support.patch Patch128: bz1830716-NovaEvacuate-suppress-expected-error.patch Patch129: bz1836945-db2-hadr-promote-standby-node.patch Patch130: bz1633251-gcp-pd-move-4-fixes-and-improvements.patch @@ -223,12 +223,47 @@ Patch131: bz1633251-gcp-pd-move-5-bundle.patch Patch132: bz1839721-podman-force-rm-container-if-rm-fails.patch Patch133: bz1820523-exportfs-2-fix-monitor-action.patch Patch134: bz1843999-aliyun-vpc-move-ip-log-output-when-failing.patch -Patch135: bz1845574-azure-events-handle-exceptions-in-urlopen.patch +Patch135: bz1845574-azure-events-1-handle-exceptions-in-urlopen.patch Patch136: bz1845581-nfsserver-dont-log-error-message-file-doesnt-exist.patch Patch137: bz1845583-exportfs-1-describe-clientspec-format-in-metadata.patch Patch138: bz1845583-exportfs-2-fix-typo.patch Patch139: bz1814896-Filesystem-fast_stop-default-to-no-for-GFS2.patch Patch140: bz1836186-pgsql-support-Pacemaker-v2.03-output.patch +Patch141: bz1819965-3-azure-events-decode-when-type-not-str.patch +Patch142: bz1818997-nfsserver-2-stop-nfsdcld-if-present.patch +Patch143: bz1818997-3-nfsserver-nfsnotify-fix-selinux-label-issue.patch +Patch144: bz1845574-azure-events-2-import-urlerror-encode-postdata.patch +Patch145: bz1846733-gcp-vpc-move-vip-1-support-multiple-alias-ips.patch +Patch146: bz1846733-gcp-vpc-move-vip-2-fix-list-sort.patch +Patch147: bz1850778-azure-lb-fix-redirect-issue.patch +Patch148: bz1640587-pgsql-ignore-masters-re-promote.patch +Patch149: bz1795535-pgsql-1-add-postgresql-12-support.patch +Patch150: bz1795535-pgsql-2-fix-uppercase-hostname-support.patch +Patch151: bz1858752-Filesystem-support-whitespace-device-dir.patch +Patch152: bz1872999-aws-vpc-move-ip-add-region-parameter.patch +Patch153: bz1881114-galera-recover-joining-non-existing-cluster.patch +Patch154: bz1815013-redis-parse-password-correctly-based-on-version.patch +Patch155: bz1763249-manpages-fix-pcs-syntax.patch +Patch156: bz1890068-gcp-pd-move-fix-partially-matched-disk_name.patch +Patch157: bz1848025-sybaseASE-run-verify-for-start-action-only.patch +Patch158: bz1861001-sybaseASE-add-logfile-parameter.patch +Patch159: bz1891835-galera-set-bootstrap-attribute-before-promote.patch +Patch160: bz1891855-galera-recover-2-node-cluster.patch +Patch161: bz1471182-crypt-1-new-ra.patch +Patch162: bz1471182-crypt-2-fix-bashism.patch +Patch163: bz1471182-crypt-3-fix-missing-and.patch +Patch164: bz1895811-aws-vpc-move-ip-dont-warn-for-expected-scenarios.patch +Patch165: bz1897570-aws-add-imdsv2-support.patch +Patch166: bz1886262-podman-recover-from-killed-conmon.patch +Patch167: bz1900015-podman-recover-from-storage-out-of-sync.patch +Patch168: bz1898690-crypt-make-key_file-crypt_type_not-unique.patch +Patch169: bz1899551-NovaEvacuate-fix-delay_evacuate-unset.patch +Patch170: bz1901357-crypt-1-support-symlink-devices.patch +Patch171: bz1902208-LVM-activate-stop-before-storage-service.patch +Patch172: bz1901357-crypt-2-dont-sanity-check-during-probe.patch +Patch173: bz1903677-ocf-shellfuncs-fix-traceback-redirection-bash5.patch +Patch174: bz1913932-1-gcp-vpc-move-add-project-parameter.patch +Patch175: bz1913932-2-gcp-vpc-move-route-fixes.patch # bundle patches Patch1000: 7-gcp-bundled.patch @@ -268,7 +303,14 @@ Requires: /usr/sbin/fuser /bin/mount Requires: /sbin/fsck Requires: /usr/sbin/fsck.ext2 /usr/sbin/fsck.ext3 /usr/sbin/fsck.ext4 Requires: /usr/sbin/fsck.xfs -Requires: /sbin/mount.nfs /sbin/mount.nfs4 /usr/sbin/mount.cifs +Requires: /sbin/mount.nfs /sbin/mount.nfs4 +%if 0%{?fedora} < 33 || (0%{?rhel} && 0%{?rhel} < 9) || (0%{?centos} && 0%{?centos} < 9) || 0%{?suse_version} +%if (0%{?rhel} && 0%{?rhel} < 8) || (0%{?centos} && 0%{?centos} < 8) +Requires: /usr/sbin/mount.cifs +%else +Recommends: /usr/sbin/mount.cifs +%endif +%endif # IPaddr2 Requires: /sbin/ip @@ -518,6 +560,41 @@ exit 1 %patch138 -p1 %patch139 -p1 %patch140 -p1 +%patch141 -p1 +%patch142 -p1 +%patch143 -p1 +%patch144 -p1 +%patch145 -p1 +%patch146 -p1 +%patch147 -p1 +%patch148 -p1 +%patch149 -p1 +%patch150 -p1 +%patch151 -p1 -F1 +%patch152 -p1 +%patch153 -p1 +%patch154 -p1 -F1 +%patch155 -p1 +%patch156 -p1 +%patch157 -p1 +%patch158 -p1 +%patch159 -p1 +%patch160 -p1 +%patch161 -p1 +%patch162 -p1 +%patch163 -p1 +%patch164 -p1 +%patch165 -p1 +%patch166 -p1 +%patch167 -p1 +%patch168 -p1 +%patch169 -p1 -F2 +%patch170 -p1 +%patch171 -p1 +%patch172 -p1 +%patch173 -p1 +%patch174 -p1 +%patch175 -p1 chmod 755 heartbeat/nova-compute-wait chmod 755 heartbeat/NovaEvacuate @@ -1081,6 +1158,116 @@ ccs_update_schema > /dev/null 2>&1 ||: %endif %changelog +* Tue Jan 19 2021 Oyvind Albrigtsen - 4.1.1-86 +- gcp-vpc-move-route, gcp-vpc-move-vip: add project parameter + + Resolves: rhbz#1913932 + +* Thu Dec 3 2020 Oyvind Albrigtsen - 4.1.1-81 +- ocf-shellfuncs: fix traceback redirection for Bash 5+ + + Resolves: rhbz#1903677 + +* Tue Dec 1 2020 Oyvind Albrigtsen - 4.1.1-80 +- crypt: support symlink devices, and dont run sanity checks for probes + + Resolves: rhbz#1901357 + +* Mon Nov 30 2020 Oyvind Albrigtsen - 4.1.1-79 +- LVM-activate: add drop-in during start-action to avoid getting + fenced during reboot + + Resolves: rhbz#1902208 + +* Wed Nov 25 2020 Oyvind Albrigtsen - 4.1.1-77 +- NovaEvacuate: set delay_evacuate to 0 when it's not set + + Resolves: rhbz#1899551 + +* Tue Nov 24 2020 Oyvind Albrigtsen - 4.1.1-76 +- podman: recover from killed conmon process +- podman: recover from podman's storage being out of sync +- crypt: make key_file and crypt_type parameters not unique + + Resolves: rhbz#1886262 + Resolves: rhbz#1900015 + Resolves: rhbz#1898690 + +* Fri Nov 13 2020 Oyvind Albrigtsen - 4.1.1-75 +- AWS agents: add support for IMDSv2 + + Resolves: rhbz#1897570 + +* Wed Nov 11 2020 Oyvind Albrigtsen - 4.1.1-74 +- aws-vpc-move-ip: don't warn for expected scenarios + + Resolves: rhbz#1895811 + +* Mon Nov 2 2020 Oyvind Albrigtsen - 4.1.1-73 +- crypt: new resource agent + + Resolves: rhbz#1471182 + +* Wed Oct 28 2020 Oyvind Albrigtsen - 4.1.1-72 +- sybaseASE: Run verify_all() for start operation only +- sybaseASE: add logfile parameter +- galera: set bootstrap attribute before promote +- galera: recover after network split in a 2-node cluster + + Resolves: rhbz#1848025 + Resolves: rhbz#1861001 + Resolves: rhbz#1891835 + Resolves: rhbz#1891855 + +* Tue Oct 27 2020 Oyvind Albrigtsen - 4.1.1-71 +- redis: parse password correctly based on version +- all agents: fix pcs syntax in manpage for pcs 0.10+ +- gcp-pd-move: dont stop partially matched "disk_name" + + Resolves: rhbz#1815013 + Resolves: rhbz#1763249 + Resolves: rhbz#1890068 + +* Wed Oct 7 2020 Oyvind Albrigtsen - 4.1.1-70 +- galera: recover from joining a non existing cluster + + Resolves: rhbz#1881114 + +* Wed Sep 23 2020 Oyvind Albrigtsen - 4.1.1-69 +- pgsql: ignore masters re-promote +- pgsql: add PostgreSQL 12 support +- Make Samba/CIFS dependency weak +- Filesystem: Support whitespace in device or directory name +- aws-vpc-move-ip: add region parameter + + Resolves: rhbz#1640587 + Resolves: rhbz#1795535 + Resolves: rhbz#1828600 + Resolves: rhbz#1858752 + Resolves: rhbz#1872999 + +* Thu Aug 20 2020 Oyvind Albrigtsen - 4.1.1-68 +- azure-lb: fix redirect issue + + Resolves: rhbz#1850778 + +* Wed Aug 19 2020 Oyvind Albrigtsen - 4.1.1-67 +- gcp-vpc-move-vip: add support for multiple alias IPs + + Resolves: rhbz#1846733 + +* Thu Jul 30 2020 Oyvind Albrigtsen - 4.1.1-65 +- azure-events: handle exceptions in urlopen + + Resolves: rhbz#1845574 + +* Mon Jul 27 2020 Oyvind Albrigtsen - 4.1.1-64 +- nfsserver: fix NFSv4-only support +- azure-events: new resource agent for Azure + + Resolves: rhbz#1818997 + Resolves: rhbz#1819965 + * Thu Jun 25 2020 Oyvind Albrigtsen - 4.1.1-60 - Upgrade bundled python-httplib2 to fix CVE-2020-11078 @@ -1097,11 +1284,9 @@ ccs_update_schema > /dev/null 2>&1 ||: Resolves: rhbz#1814896 * Wed Jun 10 2020 Oyvind Albrigtsen - 4.1.1-55 -- azure-events: handle exceptions in urlopen - nfsserver: dont log error message when /etc/sysconfig/nfs does not exist - exportfs: describe clientspec format in metadata - Resolves: rhbz#1845574 Resolves: rhbz#1845581 Resolves: rhbz#1845583 @@ -1123,11 +1308,9 @@ ccs_update_schema > /dev/null 2>&1 ||: Resolves: rhbz#1633251 * Wed May 27 2020 Oyvind Albrigtsen - 4.1.1-51 -- nfsserver: fix NFSv4-only support - NovaEvacuate: suppress expected initial error message - db2 (HADR): promote standby node when master node disappears - Resolves: rhbz#1818997 Resolves: rhbz#1830716 Resolves: rhbz#1836945 @@ -1144,12 +1327,6 @@ ccs_update_schema > /dev/null 2>&1 ||: Resolves: rhbz#1759115 Resolves: rhbz#1744190 -* Thu Apr 16 2020 Oyvind Albrigtsen - 4.1.1-48 -- azure-events: new resource agent for Azure - - Resolves: rhbz#1633251 - Resolves: rhbz#1819965 - * Mon Apr 6 2020 Oyvind Albrigtsen - 4.1.1-47 - aws-vpc-move-ip: delete remaining route entries